Skip to content

Commit 02de66a

Browse files
joyeecheungtargos
authored andcommitted
vm: lazily initialize primordials for vm contexts
Lazily initialize primordials when cross-context support for builtins is needed to fix the performance regression in context creation. PR-URL: #31738 Fixes: #29842 Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: David Carlier <[email protected]>
1 parent 8a044cb commit 02de66a

File tree

3 files changed

+49
-43
lines changed

3 files changed

+49
-43
lines changed

src/api/environment.cc

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
382382
return handle_scope.Escape(existing_value.As<Object>());
383383

384384
Local<Object> exports = Object::New(isolate);
385-
if (context->Global()->SetPrivate(context, key, exports).IsNothing())
385+
if (context->Global()->SetPrivate(context, key, exports).IsNothing() ||
386+
!InitializePrimordials(context))
386387
return MaybeLocal<Object>();
387388
return handle_scope.Escape(exports);
388389
}
@@ -438,49 +439,50 @@ bool InitializeContextForSnapshot(Local<Context> context) {
438439

439440
context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
440441
True(isolate));
442+
return InitializePrimordials(context);
443+
}
444+
445+
bool InitializePrimordials(Local<Context> context) {
446+
// Run per-context JS files.
447+
Isolate* isolate = context->GetIsolate();
448+
Context::Scope context_scope(context);
449+
Local<Object> exports;
450+
451+
Local<String> primordials_string =
452+
FIXED_ONE_BYTE_STRING(isolate, "primordials");
453+
Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
454+
Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
455+
456+
// Create primordials first and make it available to per-context scripts.
457+
Local<Object> primordials = Object::New(isolate);
458+
if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
459+
!GetPerContextExports(context).ToLocal(&exports) ||
460+
!exports->Set(context, primordials_string, primordials).FromJust()) {
461+
return false;
462+
}
441463

442-
{
443-
// Run per-context JS files.
444-
Context::Scope context_scope(context);
445-
Local<Object> exports;
446-
447-
Local<String> primordials_string =
448-
FIXED_ONE_BYTE_STRING(isolate, "primordials");
449-
Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
450-
Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
451-
452-
// Create primordials first and make it available to per-context scripts.
453-
Local<Object> primordials = Object::New(isolate);
454-
if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
455-
!GetPerContextExports(context).ToLocal(&exports) ||
456-
!exports->Set(context, primordials_string, primordials).FromJust()) {
464+
static const char* context_files[] = {"internal/per_context/primordials",
465+
"internal/per_context/domexception",
466+
"internal/per_context/messageport",
467+
nullptr};
468+
469+
for (const char** module = context_files; *module != nullptr; module++) {
470+
std::vector<Local<String>> parameters = {
471+
global_string, exports_string, primordials_string};
472+
Local<Value> arguments[] = {context->Global(), exports, primordials};
473+
MaybeLocal<Function> maybe_fn =
474+
native_module::NativeModuleEnv::LookupAndCompile(
475+
context, *module, &parameters, nullptr);
476+
if (maybe_fn.IsEmpty()) {
457477
return false;
458478
}
459-
460-
static const char* context_files[] = {"internal/per_context/primordials",
461-
"internal/per_context/domexception",
462-
"internal/per_context/messageport",
463-
nullptr};
464-
465-
for (const char** module = context_files; *module != nullptr; module++) {
466-
std::vector<Local<String>> parameters = {
467-
global_string, exports_string, primordials_string};
468-
Local<Value> arguments[] = {context->Global(), exports, primordials};
469-
MaybeLocal<Function> maybe_fn =
470-
native_module::NativeModuleEnv::LookupAndCompile(
471-
context, *module, &parameters, nullptr);
472-
if (maybe_fn.IsEmpty()) {
473-
return false;
474-
}
475-
Local<Function> fn = maybe_fn.ToLocalChecked();
476-
MaybeLocal<Value> result =
477-
fn->Call(context, Undefined(isolate),
478-
arraysize(arguments), arguments);
479-
// Execution failed during context creation.
480-
// TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
481-
if (result.IsEmpty()) {
482-
return false;
483-
}
479+
Local<Function> fn = maybe_fn.ToLocalChecked();
480+
MaybeLocal<Value> result =
481+
fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
482+
// Execution failed during context creation.
483+
// TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
484+
if (result.IsEmpty()) {
485+
return false;
484486
}
485487
}
486488

src/node_contextify.cc

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,8 +185,11 @@ MaybeLocal<Context> ContextifyContext::CreateV8Context(
185185

186186
object_template->SetHandler(config);
187187
object_template->SetHandler(indexed_config);
188-
189-
Local<Context> ctx = NewContext(env->isolate(), object_template);
188+
Local<Context> ctx = Context::New(env->isolate(), nullptr, object_template);
189+
if (ctx.IsEmpty()) return MaybeLocal<Context>();
190+
// Only partially initialize the context - the primordials are left out
191+
// and only initialized when necessary.
192+
InitializeContextRuntime(ctx);
190193

191194
if (ctx.IsEmpty()) {
192195
return MaybeLocal<Context>();

src/node_internals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ std::string GetProcessTitle(const char* default_title);
102102
std::string GetHumanReadableProcessName();
103103

104104
void InitializeContextRuntime(v8::Local<v8::Context>);
105+
bool InitializePrimordials(v8::Local<v8::Context> context);
105106

106107
namespace task_queue {
107108
void PromiseRejectCallback(v8::PromiseRejectMessage message);

0 commit comments

Comments
 (0)