Skip to content

Commit 61ca3ba

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 dd5662e commit 61ca3ba

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
@@ -227,7 +227,8 @@ void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
227227
#endif
228228
}
229229

230-
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
230+
static void SetIsolateErrorHandlers(v8::Isolate* isolate,
231+
const IsolateSettings& s) {
231232
if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL)
232233
isolate->AddMessageListenerWithErrorLevel(
233234
errors::PerIsolateMessageListener,
@@ -352,16 +353,7 @@ Isolate* NewIsolate(Isolate::CreateParams* params,
352353

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

366358
return isolate;
367359
}
@@ -489,7 +481,6 @@ Environment* CreateEnvironment(
489481
FreeEnvironment(env);
490482
return nullptr;
491483
}
492-
SetIsolateErrorHandlers(isolate, {});
493484
}
494485

495486
Context::Scope context_scope(context);

‎src/node_internals.h‎

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

390-
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s);
391390
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s);
392391
void SetIsolateCreateParamsForNode(v8::Isolate::CreateParams* params);
393392

‎src/node_worker.cc‎

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

195-
SetIsolateUpForNode(isolate);
196-
197195
// Be sure it's called before Environment::InitializeDiagnostics()
198196
// so that this callback stays when the callback of
199197
// --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)