Skip to content

Commit a2548a0

Browse files
codebytereaduh95
authored andcommitted
src: apply IsolateSettings when using a snapshot
`NewIsolate()` deferred `SetIsolateErrorHandlers()` when snapshot data was passed, and `CreateEnvironment()` later installed the handlers with default `IsolateSettings` after deserializing the main context. An embedder's `fatal_error_callback`, `oom_error_callback`, `should_abort_on_uncaught_exception_callback` and `prepare_stack_trace_callback` were therefore dropped whenever a snapshot was used, and the per-isolate message listener was added even if `MESSAGE_LISTENER_WITH_ERROR_LEVEL` had been cleared. The only way to keep custom handlers was to call `SetIsolateUpForNode()` again after `CreateEnvironment()`. Install all handlers in `NewIsolate()` regardless of snapshot data, as its documentation already describes, and stop touching isolate handlers in `CreateEnvironment()`. The deferral dates from the initial isolate snapshot work; every handler already copes with a missing `Environment`, since without a snapshot they are installed before any context exists, and workers have been calling `SetIsolateUpForNode()` right after a snapshot `NewIsolate()` anyway. Refs: #27321 Refs: #45888 Signed-off-by: Shelley Vohr <shelley.vohr@gmail.com> PR-URL: #65407 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
1 parent e46f5e1 commit a2548a0

5 files changed

Lines changed: 120 additions & 15 deletions

File tree

src/api/environment.cc

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
225225
#endif
226226
}
227227

228-
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
228+
static void SetIsolateErrorHandlers(v8::Isolate* isolate,
229+
const IsolateSettings& s) {
229230
if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL)
230231
isolate->AddMessageListenerWithErrorLevel(
231232
errors::PerIsolateMessageListener,
@@ -350,16 +351,7 @@ Isolate* NewIsolate(Isolate::CreateParams* params,
350351

351352
SetIsolateCreateParamsForNode(params);
352353
Isolate::Initialize(isolate, *params);
353-
354-
Isolate::Scope isolate_scope(isolate);
355-
356-
if (snapshot_data == nullptr) {
357-
// If in deserialize mode, delay until after the deserialization is
358-
// complete.
359-
SetIsolateUpForNode(isolate, settings);
360-
} else {
361-
SetIsolateMiscHandlers(isolate, settings);
362-
}
354+
SetIsolateUpForNode(isolate, settings);
363355

364356
return isolate;
365357
}
@@ -487,7 +479,6 @@ Environment* CreateEnvironment(
487479
FreeEnvironment(env);
488480
return nullptr;
489481
}
490-
SetIsolateErrorHandlers(isolate, {});
491482
}
492483

493484
Context::Scope context_scope(context);

src/node_internals.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,6 @@ class InitializationResultImpl final : public InitializationResult {
380380
MultiIsolatePlatform* platform_ = nullptr;
381381
};
382382

383-
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s);
384383
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s);
385384
void SetIsolateCreateParamsForNode(v8::Isolate::CreateParams* params);
386385

src/node_worker.cc

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,6 @@ class WorkerThreadData {
190190
return;
191191
}
192192

193-
SetIsolateUpForNode(isolate);
194-
195193
// Be sure it's called before Environment::InitializeDiagnostics()
196194
// so that this callback stays when the callback of
197195
// --heapsnapshot-near-heap-limit gets is popped.

test/embedding/embedtest.cc

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ using node::MultiIsolatePlatform;
1919
using v8::Context;
2020
using v8::HandleScope;
2121
using v8::Isolate;
22+
using v8::Local;
2223
using v8::Locker;
2324
using v8::MaybeLocal;
2425
using v8::V8;
@@ -27,6 +28,11 @@ using v8::Value;
2728
static int RunNodeInstance(MultiIsolatePlatform* platform,
2829
const std::vector<std::string>& args,
2930
const std::vector<std::string>& exec_args);
31+
static int RunSnapshotWithIsolateSettings(
32+
MultiIsolatePlatform* platform,
33+
const node::EmbedderSnapshotData* snapshot,
34+
const std::vector<std::string>& args,
35+
const std::vector<std::string>& exec_args);
3036

3137
NODE_MAIN(int argc, node::argv_type raw_argv[]) {
3238
char** argv = nullptr;
@@ -84,6 +90,7 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
8490
// Running snapshot:
8591
// embedtest --embedder-snapshot-blob blob-path
8692
// [--embedder-snapshot-as-file]
93+
// [--embedder-isolate-settings]
8794
// arg1 arg2...
8895
// No snapshot:
8996
// embedtest arg1 arg2...
@@ -93,6 +100,7 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
93100
std::vector<std::string> filtered_args;
94101
bool is_building_snapshot = false;
95102
bool snapshot_as_file = false;
103+
bool with_isolate_settings = false;
96104
std::optional<node::SnapshotConfig> snapshot_config;
97105
std::string snapshot_blob_path;
98106
for (size_t i = 0; i < args.size(); ++i) {
@@ -101,6 +109,8 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
101109
is_building_snapshot = true;
102110
} else if (arg == "--embedder-snapshot-as-file") {
103111
snapshot_as_file = true;
112+
} else if (arg == "--embedder-isolate-settings") {
113+
with_isolate_settings = true;
104114
} else if (arg == "--without-code-cache") {
105115
if (!snapshot_config.has_value()) {
106116
snapshot_config = node::SnapshotConfig{};
@@ -150,6 +160,11 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
150160
node::GetAnonymousMainPath());
151161
}
152162

163+
if (snapshot && with_isolate_settings) {
164+
return RunSnapshotWithIsolateSettings(
165+
platform, snapshot.get(), filtered_args, exec_args);
166+
}
167+
153168
std::vector<std::string> errors;
154169
std::unique_ptr<CommonEnvironmentSetup> setup;
155170

@@ -233,3 +248,67 @@ int RunNodeInstance(MultiIsolatePlatform* platform,
233248

234249
return exit_code;
235250
}
251+
252+
// CommonEnvironmentSetup does not take IsolateSettings, so this goes through
253+
// NewIsolate()/CreateIsolateData()/CreateEnvironment() directly.
254+
static int RunSnapshotWithIsolateSettings(
255+
MultiIsolatePlatform* platform,
256+
const node::EmbedderSnapshotData* snapshot,
257+
const std::vector<std::string>& args,
258+
const std::vector<std::string>& exec_args) {
259+
uv_loop_t loop;
260+
int ret = uv_loop_init(&loop);
261+
assert(ret == 0);
262+
263+
std::shared_ptr<node::ArrayBufferAllocator> allocator =
264+
node::ArrayBufferAllocator::Create();
265+
node::IsolateSettings settings;
266+
settings.prepare_stack_trace_callback = [](Local<Context> context,
267+
Local<Value> exception,
268+
Local<v8::Array> trace) {
269+
return MaybeLocal<Value>(v8::String::NewFromUtf8Literal(
270+
v8::Isolate::GetCurrent(), "stack trace prepared by the embedder"));
271+
};
272+
Isolate* isolate =
273+
node::NewIsolate(allocator, &loop, platform, snapshot, settings);
274+
assert(isolate != nullptr);
275+
276+
int exit_code = 1;
277+
{
278+
Locker locker(isolate);
279+
Isolate::Scope isolate_scope(isolate);
280+
HandleScope handle_scope(isolate);
281+
282+
std::unique_ptr<node::IsolateData, decltype(&node::FreeIsolateData)>
283+
isolate_data(node::CreateIsolateData(
284+
isolate, &loop, platform, allocator.get(), snapshot),
285+
node::FreeIsolateData);
286+
std::unique_ptr<Environment, decltype(&node::FreeEnvironment)> env(
287+
node::CreateEnvironment(
288+
isolate_data.get(), Local<Context>(), args, exec_args),
289+
node::FreeEnvironment);
290+
assert(env);
291+
292+
Context::Scope context_scope(node::GetMainContext(env.get()));
293+
if (!node::LoadEnvironment(env.get(), node::StartExecutionCallback{})
294+
.IsEmpty()) {
295+
exit_code = node::SpinEventLoop(env.get()).FromMaybe(1);
296+
}
297+
node::Stop(env.get());
298+
}
299+
300+
bool platform_finished = false;
301+
platform->AddIsolateFinishedCallback(
302+
isolate,
303+
[](void* data) {
304+
bool* finished = static_cast<bool*>(data);
305+
*finished = true;
306+
},
307+
&platform_finished);
308+
platform->DisposeIsolate(isolate);
309+
while (!platform_finished) uv_run(&loop, UV_RUN_ONCE);
310+
ret = uv_loop_close(&loop);
311+
assert(ret == 0);
312+
313+
return exit_code;
314+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
'use strict';
2+
3+
// IsolateSettings passed to NewIsolate() with a snapshot must survive
4+
// CreateEnvironment(); see RunSnapshotWithIsolateSettings() in embedtest.cc.
5+
6+
const common = require('../common');
7+
const tmpdir = require('../common/tmpdir');
8+
9+
const {
10+
spawnSyncAndAssert,
11+
spawnSyncAndExitWithoutError,
12+
} = require('../common/child_process');
13+
14+
const embedtest = common.resolveBuiltBinary('embedtest');
15+
const snapshotBlobArgs = [
16+
'--embedder-snapshot-blob', tmpdir.resolve('embedder-snapshot.blob'),
17+
];
18+
const buildSnapshotScript = `
19+
require('v8').startupSnapshot.setDeserializeMainFunction(() => {
20+
console.log(new Error('from the snapshot main function').stack);
21+
});
22+
`;
23+
24+
tmpdir.refresh();
25+
26+
spawnSyncAndExitWithoutError(
27+
embedtest,
28+
['--', buildSnapshotScript, ...snapshotBlobArgs, '--embedder-snapshot-create'],
29+
{ cwd: tmpdir.path });
30+
31+
spawnSyncAndAssert(
32+
embedtest,
33+
['--', ...snapshotBlobArgs, '--embedder-isolate-settings'],
34+
{ cwd: tmpdir.path },
35+
{
36+
trim: true,
37+
stdout: 'stack trace prepared by the embedder',
38+
});

0 commit comments

Comments
 (0)