From 736a04aa1311fd8f0a9e4eac0ea4e39288b321dc Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Tue, 16 Aug 2022 23:44:01 +0800 Subject: [PATCH] vm: include vm context in the embedded snapshot Include a minimally initialized contextify context in the embedded snapshot. This paves the way for user-land vm context snapshots. PR-URL: https://github.com/nodejs/node/pull/44252 Refs: https://github.com/nodejs/node/issues/44014 Refs: https://github.com/nodejs/node/issues/37476 Reviewed-By: Chengzhong Wu --- src/env.h | 3 ++- src/node_contextify.cc | 33 ++++++++++++++++++++++++--------- src/node_contextify.h | 1 + src/node_snapshotable.cc | 19 ++++++++++++++++++- 4 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/env.h b/src/env.h index e3def607553cee..6e909092f7a16c 100644 --- a/src/env.h +++ b/src/env.h @@ -989,7 +989,8 @@ struct SnapshotData { enum class DataOwnership { kOwned, kNotOwned }; static const uint32_t kMagic = 0x143da19; - static const SnapshotIndex kNodeBaseContextIndex = 0; + static const SnapshotIndex kNodeVMContextIndex = 0; + static const SnapshotIndex kNodeBaseContextIndex = kNodeVMContextIndex + 1; static const SnapshotIndex kNodeMainContextIndex = kNodeBaseContextIndex + 1; DataOwnership data_ownership = DataOwnership::kOwned; diff --git a/src/node_contextify.cc b/src/node_contextify.cc index 9f166f20e3c11c..0e24b32404846a 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -28,6 +28,7 @@ #include "node_errors.h" #include "node_external_reference.h" #include "node_internals.h" +#include "node_snapshot_builder.h" #include "node_watchdog.h" #include "util-inl.h" @@ -118,6 +119,9 @@ ContextifyContext::ContextifyContext( object_template = CreateGlobalTemplate(env->isolate()); env->set_contextify_global_template(object_template); } + bool use_node_snapshot = per_process::cli_options->node_snapshot; + const SnapshotData* snapshot_data = + use_node_snapshot ? SnapshotBuilder::GetEmbeddedSnapshotData() : nullptr; MicrotaskQueue* queue = microtask_queue() @@ -125,7 +129,7 @@ ContextifyContext::ContextifyContext( : env->isolate()->GetCurrentContext()->GetMicrotaskQueue(); Local v8_context; - if (!(CreateV8Context(env->isolate(), object_template, queue) + if (!(CreateV8Context(env->isolate(), object_template, snapshot_data, queue) .ToLocal(&v8_context)) || !InitializeContext(v8_context, env, sandbox_obj, options)) { // Allocation failure, maximum call stack size reached, termination, etc. @@ -190,17 +194,28 @@ Local ContextifyContext::CreateGlobalTemplate( MaybeLocal ContextifyContext::CreateV8Context( Isolate* isolate, Local object_template, + const SnapshotData* snapshot_data, MicrotaskQueue* queue) { EscapableHandleScope scope(isolate); - Local ctx = Context::New(isolate, - nullptr, // extensions - object_template, - {}, // global object - {}, // deserialization callback - queue); - if (ctx.IsEmpty()) return MaybeLocal(); - + Local ctx; + if (snapshot_data == nullptr) { + ctx = Context::New(isolate, + nullptr, // extensions + object_template, + {}, // global object + {}, // deserialization callback + queue); + if (ctx.IsEmpty()) return MaybeLocal(); + } else if (!Context::FromSnapshot(isolate, + SnapshotData::kNodeVMContextIndex, + {}, // deserialization callback + nullptr, // extensions + {}, // global object + queue) + .ToLocal(&ctx)) { + return MaybeLocal(); + } return scope.Escape(ctx); } diff --git a/src/node_contextify.h b/src/node_contextify.h index 088b5c5a56192c..a424c56d7e8f26 100644 --- a/src/node_contextify.h +++ b/src/node_contextify.h @@ -52,6 +52,7 @@ class ContextifyContext { static v8::MaybeLocal CreateV8Context( v8::Isolate* isolate, v8::Local object_template, + const SnapshotData* snapshot_data, v8::MicrotaskQueue* queue); bool InitializeContext(v8::Local ctx, Environment* env, diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index e48b4797803baa..8ed7ec2895a056 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -7,6 +7,7 @@ #include "env-inl.h" #include "node_blob.h" #include "node_builtins.h" +#include "node_contextify.h" #include "node_errors.h" #include "node_external_reference.h" #include "node_file.h" @@ -31,6 +32,7 @@ using v8::HandleScope; using v8::Isolate; using v8::Local; using v8::Object; +using v8::ObjectTemplate; using v8::ScriptCompiler; using v8::ScriptOrigin; using v8::SnapshotCreator; @@ -922,6 +924,19 @@ int SnapshotBuilder::Generate(SnapshotData* out, // The default context with only things created by V8. Local default_context = Context::New(isolate); + // The context used by the vm module. + Local vm_context; + { + Local global_template = + main_instance->isolate_data()->contextify_global_template(); + CHECK(!global_template.IsEmpty()); + if (!contextify::ContextifyContext::CreateV8Context( + isolate, global_template, nullptr, nullptr) + .ToLocal(&vm_context)) { + return SNAPSHOT_ERROR; + } + } + // The Node.js-specific context with primodials, can be used by workers // TODO(joyeecheung): investigate if this can be used by vm contexts // without breaking compatibility. @@ -1003,7 +1018,9 @@ int SnapshotBuilder::Generate(SnapshotData* out, // blob is created. So initialize all the contexts before adding them. // TODO(joyeecheung): figure out how to remove this restriction. creator.SetDefaultContext(default_context); - size_t index = creator.AddContext(base_context); + size_t index = creator.AddContext(vm_context); + CHECK_EQ(index, SnapshotData::kNodeVMContextIndex); + index = creator.AddContext(base_context); CHECK_EQ(index, SnapshotData::kNodeBaseContextIndex); index = creator.AddContext(main_context, {SerializeNodeContextInternalFields, env});