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 <legendecas@gmail.com>
This commit is contained in:
Joyee Cheung
2022-08-16 23:44:01 +08:00
parent cfd25e0c74
commit ec91776ee0
4 changed files with 45 additions and 11 deletions

View File

@@ -1002,7 +1002,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;

View File

@@ -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<Context> 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<ObjectTemplate> ContextifyContext::CreateGlobalTemplate(
MaybeLocal<Context> ContextifyContext::CreateV8Context(
Isolate* isolate,
Local<ObjectTemplate> object_template,
const SnapshotData* snapshot_data,
MicrotaskQueue* queue) {
EscapableHandleScope scope(isolate);
Local<Context> ctx = Context::New(isolate,
nullptr, // extensions
object_template,
{}, // global object
{}, // deserialization callback
queue);
if (ctx.IsEmpty()) return MaybeLocal<Context>();
Local<Context> ctx;
if (snapshot_data == nullptr) {
ctx = Context::New(isolate,
nullptr, // extensions
object_template,
{}, // global object
{}, // deserialization callback
queue);
if (ctx.IsEmpty()) return MaybeLocal<Context>();
} else if (!Context::FromSnapshot(isolate,
SnapshotData::kNodeVMContextIndex,
{}, // deserialization callback
nullptr, // extensions
{}, // global object
queue)
.ToLocal(&ctx)) {
return MaybeLocal<Context>();
}
return scope.Escape(ctx);
}

View File

@@ -52,6 +52,7 @@ class ContextifyContext {
static v8::MaybeLocal<v8::Context> CreateV8Context(
v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> object_template,
const SnapshotData* snapshot_data,
v8::MicrotaskQueue* queue);
bool InitializeContext(v8::Local<v8::Context> ctx,
Environment* env,

View File

@@ -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"
@@ -32,6 +33,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;
@@ -1031,6 +1033,19 @@ int SnapshotBuilder::Generate(SnapshotData* out,
// The default context with only things created by V8.
Local<Context> default_context = Context::New(isolate);
// The context used by the vm module.
Local<Context> vm_context;
{
Local<ObjectTemplate> 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.
@@ -1112,7 +1127,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});