@@ -93,15 +93,42 @@ to as `node::Environment`. Each `node::Environment` is associated with:
9393 that `node::IsolateData` is shared only among `node::Environment`s that
9494 use the same `v8::Isolate`, Node.js does not perform this check.
9595
96- `node::Environment`s that share a `node::IsolateData` also share its
97- `uv_loop_t`. `node::FreeEnvironment()` runs that loop until the handles of the
98- `node::Environment` being freed have closed, and JavaScript execution is
99- disallowed on the whole `v8::Isolate` while it does, so pending timers, I/O
100- callbacks and thread pool completions that belong to other `node::Environment`s
101- on the same loop can run inside that call without being able to call into
102- JavaScript. `node::Environment`s that are freed independently of one another
103- should each use their own `uv_loop_t` and `node::IsolateData`, or the embedder
104- should make sure the others have no pending work when one of them is freed.
96+ Several `node::Environment`s can share one `v8::Isolate`, one `uv_loop_t` and
97+ one thread, for example when Node.js is embedded into a process that already
98+ runs a JavaScript engine and each of its contexts should get Node.js APIs. In
99+ that configuration:
100+
101+ * The embedder may create the `v8::Isolate` itself instead of calling
102+ `node::NewIsolate()`: allocate it with `v8::Isolate::Allocate()`, register it
103+ with the `MultiIsolatePlatform` (if one is used) before
104+ `v8::Isolate::Initialize()`, optionally pass its own `v8::CppHeap` in the
105+ `v8::Isolate::CreateParams`, and call `node::SetIsolateUpForNode()` with the
106+ `IsolateSettings` it wants. Node.js uses the isolate's existing `CppHeap`.
107+ * Each `node::Environment` gets its own main `v8::Context`, which the embedder
108+ may create itself and prepare with `node::InitializeContext()`.
109+ * The `node::Environment`s can share one `node::IsolateData` or use one each;
110+ a `node::IsolateData` must outlive every `node::Environment` created from
111+ it, and all of them must be freed before the `v8::Isolate` is disposed.
112+ * At most one `node::Environment` per isolate should register the ESM loader
113+ hooks (pass `EnvironmentFlags::kNoRegisterESMLoader` to the others), and
114+ `EnvironmentFlags::kNoBrowserGlobals` keeps Node.js from installing timers
115+ and other Web globals the host already provides. Every `node::Environment`
116+ created without `EnvironmentFlags::kNoCreateInspector` has its own
117+ inspector agent; the others throw `ERR_INSPECTOR_NOT_AVAILABLE` from
118+ `node:inspector`. Creating `Worker`s requires a `MultiIsolatePlatform` in
119+ the `node::IsolateData`.
120+ * `node::Stop()` terminates JavaScript on the whole isolate unless
121+ `StopFlags::kDoNotTerminateIsolate` is passed, so use that flag while other
122+ `node::Environment`s on the isolate are still running.
123+ * `node::FreeEnvironment()` runs the shared loop until the handles of the
124+ `node::Environment` being freed have closed. Timers, I/O callbacks and
125+ thread pool completions of the other `node::Environment`s that become due
126+ in those loop iterations run normally, including their JavaScript; only the
127+ `node::Environment` being freed can no longer call into JavaScript.
128+ * `process.on('beforeExit')` and `process.on('exit')` are per
129+ `node::Environment` and only run when the embedder calls
130+ `node::EmitProcessBeforeExit()` / `node::EmitProcessExit()` (or
131+ `node::SpinEventLoop()`) for that `node::Environment`.
105132
106133In order to set up a `v8::Isolate`, an `v8::ArrayBuffer::Allocator` needs
107134to be provided. One possible choice is the default Node.js allocator, which
0 commit comments