Skip to content

Commit

Permalink
vm: include vm context in the embedded snapshot
Browse files Browse the repository at this point in the history
Include a minimally initialized contextify context in the embedded
snapshot. This paves the way for user-land vm context snapshots.

PR-URL: #44252
Refs: #44014
Refs: #37476
Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
  • Loading branch information
joyeecheung committed Aug 23, 2022
1 parent cfd25e0 commit ec91776
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 11 deletions.
3 changes: 2 additions & 1 deletion src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
33 changes: 24 additions & 9 deletions src/node_contextify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -118,14 +119,17 @@ 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()
? microtask_queue().get()
: 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.
Expand Down Expand Up @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions src/node_contextify.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
19 changes: 18 additions & 1 deletion src/node_snapshotable.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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});
Expand Down

0 comments on commit ec91776

Please sign in to comment.