Skip to content

vm: allow sharing a microtask queue across contexts - #66461

Open
agape1225 wants to merge 2 commits into
nodejs:mainfrom
agape1225:vm-shared-microtask-queue
Open

agape1225 wants to merge 2 commits into
nodejs:mainfrom
agape1225:vm-shared-microtask-queue

Conversation

@agape1225

@agape1225 agape1225 commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Extends the existing microtaskMode option (no new option) so multiple
vm contexts can share one explicitly-drained microtask queue:

const queue = vm.createMicrotaskQueue();
const window = vm.createContext(windowSandbox, { microtaskMode: { type: 'manual', queue } });
const iframe = vm.createContext(iframeSandbox, { microtaskMode: { type: 'manual', queue } });

vm.runInContext('...', window); // not drained automatically
queue.runMicrotasks();          // drained explicitly, once, by the embedder

Today, 'afterEvaluate' gives each context its own private, auto-drained
queue — there's no way for two contexts to share one and have it drained
together, in scheduling order, as the HTML spec requires for same-agent
realms (e.g. a Window and a same-origin iframe).

Design

  • microtaskMode now accepts either the existing string 'afterEvaluate'
    or an object { type: 'manual', queue }, where queue is created via
    the one new export, vm.createMicrotaskQueue(). These are two values
    of the same option, so a context is either auto-drained with a private
    queue or shared-and-manual — never both, by construction, with nothing
    to validate for that combination at runtime.
  • The native binding's argument list and MakeContext() signature are
    unchanged; the manual-mode queue is passed through the same slot that
    used to only take a boolean.
  • The queue handle (ContextifyMicrotaskQueue) is a plain BaseObject:
    the underlying v8::MicrotaskQueue is kept alive via std::shared_ptr,
    shared between the JS handle and every ContextifyContext using it, so
    the handle itself doesn't need cppgc tracking.
  • Passing anything other than a real vm.MicrotaskQueue (a spoofed
    object, a Proxy, etc.) is rejected with ERR_INVALID_ARG_TYPE,
    checked via FunctionTemplate::HasInstance() rather than a JS-level
    instanceof.

Testing

New tests in test/parallel/test-vm-shared-microtask-queue*.js cover
the issue's Window/iframe scenario, queue-spoofing rejection, GC of the
JS handle, and module evaluation. make -j12 and the full
test/parallel/test-vm-*.js suite pass (104/104).

Refs: #65555
Refs: #65582

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs involving general changes in the lib/ or src/ directories. needs-ci PRs that need a full CI run. labels Oct 2, 2026
agape1225 and others added 2 commits October 2, 2026 22:35
Add `vm.createMicrotaskQueue()` and extend the `microtaskMode` option
to accept `{ type: 'manual', queue }`, so multiple vm contexts can
share a single, explicitly-drained microtask queue instead of each
having its own privately auto-drained one. This lets embedders (e.g.
implementing a Window/iframe pair) reproduce the spec's
same-microtask-queue ordering guarantees, which was not previously
possible from the public API.

`'afterEvaluate'` and `{ type: 'manual', queue }` are mutually
exclusive by construction, since they are two different values of the
same option.

Refs: nodejs#65555
Signed-off-by: agape1225 <49804691+agape1225@users.noreply.github.com>
Parse microtaskMode only in createContext() so convenience APIs do not
read type and queue getters repeatedly.

Add regression tests for getter access, invalid options, and shared
manual queues during module evaluation. Clarify that the queue
constructor is not exported and fix the C++ macro line length.

Refs: nodejs#65555

Signed-off-by: leah-1ee <selee3196@gmail.com>
@agape1225
agape1225 force-pushed the vm-shared-microtask-queue branch from ea0e9df to eb20179 Compare October 2, 2026 13:38
@codecov

codecov Bot commented Oct 2, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.06931% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.41%. Comparing base (a18fd89) to head (eb20179).
⚠️ Report is 179 commits behind head on main.

Files with missing lines Patch % Lines
src/node_contextify.cc 91.11% 0 Missing and 4 partials ⚠️
src/node_contextify.h 40.00% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #66461      +/-   ##
==========================================
+ Coverage   90.33%   90.41%   +0.08%     
==========================================
  Files         790      791       +1     
  Lines      273834   275693    +1859     
  Branches    52361    52861     +500     
==========================================
+ Hits       247378   249280    +1902     
+ Misses      16924    16817     -107     
- Partials     9532     9596      +64     
Files with missing lines Coverage Δ
lib/vm.js 99.35% <100.00%> (+0.06%) ⬆️
src/node_contextify.h 63.63% <40.00%> (-6.96%) ⬇️
src/node_contextify.cc 81.99% <91.11%> (+0.18%) ⬆️

... and 143 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. lib / src Issues and PRs involving general changes in the lib/ or src/ directories. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants