diff --git a/src/api/environment.cc b/src/api/environment.cc index 3b94d860de1e..459830a2af80 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -225,7 +225,8 @@ void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) { #endif } -void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) { +static void SetIsolateErrorHandlers(v8::Isolate* isolate, + const IsolateSettings& s) { if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL) isolate->AddMessageListenerWithErrorLevel( errors::PerIsolateMessageListener, @@ -350,16 +351,7 @@ Isolate* NewIsolate(Isolate::CreateParams* params, SetIsolateCreateParamsForNode(params); Isolate::Initialize(isolate, *params); - - Isolate::Scope isolate_scope(isolate); - - if (snapshot_data == nullptr) { - // If in deserialize mode, delay until after the deserialization is - // complete. - SetIsolateUpForNode(isolate, settings); - } else { - SetIsolateMiscHandlers(isolate, settings); - } + SetIsolateUpForNode(isolate, settings); return isolate; } @@ -469,7 +461,6 @@ Environment* CreateEnvironment( FreeEnvironment(env); return nullptr; } - SetIsolateErrorHandlers(isolate, {}); } Context::Scope context_scope(context); diff --git a/src/node_internals.h b/src/node_internals.h index 631a8d7ccdd9..17e23ce61d64 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -380,7 +380,6 @@ class InitializationResultImpl final : public InitializationResult { MultiIsolatePlatform* platform_ = nullptr; }; -void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s); void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s); void SetIsolateCreateParamsForNode(v8::Isolate::CreateParams* params); diff --git a/src/node_worker.cc b/src/node_worker.cc index edc21e7e5561..a290f778d488 100644 --- a/src/node_worker.cc +++ b/src/node_worker.cc @@ -190,8 +190,6 @@ class WorkerThreadData { return; } - SetIsolateUpForNode(isolate); - // Be sure it's called before Environment::InitializeDiagnostics() // so that this callback stays when the callback of // --heapsnapshot-near-heap-limit gets is popped. diff --git a/test/embedding/embedtest.cc b/test/embedding/embedtest.cc index 982eed74f954..3fbbd13c36bb 100644 --- a/test/embedding/embedtest.cc +++ b/test/embedding/embedtest.cc @@ -19,6 +19,7 @@ using node::MultiIsolatePlatform; using v8::Context; using v8::HandleScope; using v8::Isolate; +using v8::Local; using v8::Locker; using v8::MaybeLocal; using v8::V8; @@ -27,6 +28,11 @@ using v8::Value; static int RunNodeInstance(MultiIsolatePlatform* platform, const std::vector& args, const std::vector& exec_args); +static int RunSnapshotWithIsolateSettings( + MultiIsolatePlatform* platform, + const node::EmbedderSnapshotData* snapshot, + const std::vector& args, + const std::vector& exec_args); NODE_MAIN(int argc, node::argv_type raw_argv[]) { char** argv = nullptr; @@ -84,6 +90,7 @@ int RunNodeInstance(MultiIsolatePlatform* platform, // Running snapshot: // embedtest --embedder-snapshot-blob blob-path // [--embedder-snapshot-as-file] + // [--embedder-isolate-settings] // arg1 arg2... // No snapshot: // embedtest arg1 arg2... @@ -93,6 +100,7 @@ int RunNodeInstance(MultiIsolatePlatform* platform, std::vector filtered_args; bool is_building_snapshot = false; bool snapshot_as_file = false; + bool with_isolate_settings = false; std::optional snapshot_config; std::string snapshot_blob_path; for (size_t i = 0; i < args.size(); ++i) { @@ -101,6 +109,8 @@ int RunNodeInstance(MultiIsolatePlatform* platform, is_building_snapshot = true; } else if (arg == "--embedder-snapshot-as-file") { snapshot_as_file = true; + } else if (arg == "--embedder-isolate-settings") { + with_isolate_settings = true; } else if (arg == "--without-code-cache") { if (!snapshot_config.has_value()) { snapshot_config = node::SnapshotConfig{}; @@ -150,6 +160,11 @@ int RunNodeInstance(MultiIsolatePlatform* platform, node::GetAnonymousMainPath()); } + if (snapshot && with_isolate_settings) { + return RunSnapshotWithIsolateSettings( + platform, snapshot.get(), filtered_args, exec_args); + } + std::vector errors; std::unique_ptr setup; @@ -233,3 +248,67 @@ int RunNodeInstance(MultiIsolatePlatform* platform, return exit_code; } + +// CommonEnvironmentSetup does not take IsolateSettings, so this goes through +// NewIsolate()/CreateIsolateData()/CreateEnvironment() directly. +static int RunSnapshotWithIsolateSettings( + MultiIsolatePlatform* platform, + const node::EmbedderSnapshotData* snapshot, + const std::vector& args, + const std::vector& exec_args) { + uv_loop_t loop; + int ret = uv_loop_init(&loop); + assert(ret == 0); + + std::shared_ptr allocator = + node::ArrayBufferAllocator::Create(); + node::IsolateSettings settings; + settings.prepare_stack_trace_callback = [](Local context, + Local exception, + Local trace) { + return MaybeLocal(v8::String::NewFromUtf8Literal( + v8::Isolate::GetCurrent(), "stack trace prepared by the embedder")); + }; + Isolate* isolate = + node::NewIsolate(allocator, &loop, platform, snapshot, settings); + assert(isolate != nullptr); + + int exit_code = 1; + { + Locker locker(isolate); + Isolate::Scope isolate_scope(isolate); + HandleScope handle_scope(isolate); + + std::unique_ptr + isolate_data(node::CreateIsolateData( + isolate, &loop, platform, allocator.get(), snapshot), + node::FreeIsolateData); + std::unique_ptr env( + node::CreateEnvironment( + isolate_data.get(), Local(), args, exec_args), + node::FreeEnvironment); + assert(env); + + Context::Scope context_scope(node::GetMainContext(env.get())); + if (!node::LoadEnvironment(env.get(), node::StartExecutionCallback{}) + .IsEmpty()) { + exit_code = node::SpinEventLoop(env.get()).FromMaybe(1); + } + node::Stop(env.get()); + } + + bool platform_finished = false; + platform->AddIsolateFinishedCallback( + isolate, + [](void* data) { + bool* finished = static_cast(data); + *finished = true; + }, + &platform_finished); + platform->DisposeIsolate(isolate); + while (!platform_finished) uv_run(&loop, UV_RUN_ONCE); + ret = uv_loop_close(&loop); + assert(ret == 0); + + return exit_code; +} diff --git a/test/embedding/test-embedding-snapshot-isolate-settings.js b/test/embedding/test-embedding-snapshot-isolate-settings.js new file mode 100644 index 000000000000..67444da1e4cf --- /dev/null +++ b/test/embedding/test-embedding-snapshot-isolate-settings.js @@ -0,0 +1,38 @@ +'use strict'; + +// IsolateSettings passed to NewIsolate() with a snapshot must survive +// CreateEnvironment(); see RunSnapshotWithIsolateSettings() in embedtest.cc. + +const common = require('../common'); +const tmpdir = require('../common/tmpdir'); + +const { + spawnSyncAndAssert, + spawnSyncAndExitWithoutError, +} = require('../common/child_process'); + +const embedtest = common.resolveBuiltBinary('embedtest'); +const snapshotBlobArgs = [ + '--embedder-snapshot-blob', tmpdir.resolve('embedder-snapshot.blob'), +]; +const buildSnapshotScript = ` + require('v8').startupSnapshot.setDeserializeMainFunction(() => { + console.log(new Error('from the snapshot main function').stack); + }); +`; + +tmpdir.refresh(); + +spawnSyncAndExitWithoutError( + embedtest, + ['--', buildSnapshotScript, ...snapshotBlobArgs, '--embedder-snapshot-create'], + { cwd: tmpdir.path }); + +spawnSyncAndAssert( + embedtest, + ['--', ...snapshotBlobArgs, '--embedder-isolate-settings'], + { cwd: tmpdir.path }, + { + trim: true, + stdout: 'stack trace prepared by the embedder', + });