Skip to content

Commit

Permalink
bootstrap: generate bootstrapper arguments in BuiltinLoader
Browse files Browse the repository at this point in the history
PR-URL: nodejs/node#44488
Reviewed-By: Chengzhong Wu <[email protected]>
  • Loading branch information
sercher committed Apr 24, 2024
1 parent 90b7c8d commit 4e51651
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 79 deletions.
22 changes: 5 additions & 17 deletions graal-nodejs/src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -495,11 +495,7 @@ MaybeLocal<Value> LoadEnvironment(
builtins::BuiltinLoader::Add(name.c_str(), main_script_source_utf8);
Realm* realm = env->principal_realm();

// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
std::vector<Local<Value>> args = {realm->process_object(),
realm->builtin_module_require()};
return realm->ExecuteBootstrapper(name.c_str(), &args);
return realm->ExecuteBootstrapper(name.c_str());
});
}

Expand Down Expand Up @@ -737,19 +733,11 @@ Maybe<bool> InitializePrimordials(Local<Context> context) {
nullptr};

for (const char** module = context_files; *module != nullptr; module++) {
// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
Local<Value> arguments[] = {exports, primordials};
MaybeLocal<Function> maybe_fn =
builtins::BuiltinLoader::LookupAndCompile(context, *module, nullptr);
Local<Function> fn;
if (!maybe_fn.ToLocal(&fn)) {
return Nothing<bool>();
}
MaybeLocal<Value> result =
fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
// Execution failed during context creation.
if (result.IsEmpty()) {
if (builtins::BuiltinLoader::CompileAndCall(
context, *module, arraysize(arguments), arguments, nullptr)
.IsEmpty()) {
// Execution failed during context creation.
return Nothing<bool>();
}
}
Expand Down
10 changes: 1 addition & 9 deletions graal-nodejs/src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -275,15 +275,7 @@ MaybeLocal<Value> StartExecution(Environment* env, const char* main_script_id) {
CHECK_NOT_NULL(main_script_id);
Realm* realm = env->principal_realm();

// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
std::vector<Local<Value>> arguments = {env->process_object(),
env->builtin_module_require(),
env->internal_binding_loader(),
env->primordials()};

return scope.EscapeMaybe(
realm->ExecuteBootstrapper(main_script_id, &arguments));
return scope.EscapeMaybe(realm->ExecuteBootstrapper(main_script_id));
}

MaybeLocal<Value> StartExecution(Environment* env, StartExecutionCallback cb) {
Expand Down
89 changes: 77 additions & 12 deletions graal-nodejs/src/node_builtins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ using v8::ScriptOrigin;
using v8::Set;
using v8::SideEffectType;
using v8::String;
using v8::Undefined;
using v8::Value;

BuiltinLoader BuiltinLoader::instance_;
Expand Down Expand Up @@ -390,8 +391,12 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(
FIXED_ONE_BYTE_STRING(isolate, "exports"),
FIXED_ONE_BYTE_STRING(isolate, "primordials"),
};
} else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0) {
// internal/main/*: process, require, internalBinding, primordials
} else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0 ||
strncmp(id,
"internal/bootstrap/",
strlen("internal/bootstrap/")) == 0) {
// internal/main/*, internal/bootstrap/*: process, require,
// internalBinding, primordials
parameters = {
FIXED_ONE_BYTE_STRING(isolate, "process"),
FIXED_ONE_BYTE_STRING(isolate, "require"),
Expand All @@ -404,16 +409,6 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(
FIXED_ONE_BYTE_STRING(isolate, "process"),
FIXED_ONE_BYTE_STRING(isolate, "require"),
};
} else if (strncmp(id,
"internal/bootstrap/",
strlen("internal/bootstrap/")) == 0) {
// internal/bootstrap/*: process, require, internalBinding, primordials
parameters = {
FIXED_ONE_BYTE_STRING(isolate, "process"),
FIXED_ONE_BYTE_STRING(isolate, "require"),
FIXED_ONE_BYTE_STRING(isolate, "internalBinding"),
FIXED_ONE_BYTE_STRING(isolate, "primordials"),
};
} else {
// others: exports, require, module, process, internalBinding, primordials
parameters = {
Expand All @@ -434,6 +429,76 @@ MaybeLocal<Function> BuiltinLoader::LookupAndCompile(
return maybe;
}

MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context,
const char* id,
Realm* realm) {
Isolate* isolate = context->GetIsolate();
// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
std::vector<Local<Value>> arguments;
// Detects parameters of the scripts based on module ids.
// internal/bootstrap/loaders: process, getLinkedBinding,
// getInternalBinding, primordials
if (strcmp(id, "internal/bootstrap/loaders") == 0) {
Local<Value> get_linked_binding;
Local<Value> get_internal_binding;
if (!NewFunctionTemplate(isolate, binding::GetLinkedBinding)
->GetFunction(context)
.ToLocal(&get_linked_binding) ||
!NewFunctionTemplate(isolate, binding::GetInternalBinding)
->GetFunction(context)
.ToLocal(&get_internal_binding)) {
return MaybeLocal<Value>();
}
arguments = {realm->process_object(),
get_linked_binding,
get_internal_binding,
realm->primordials()};
} else if (strncmp(id, "internal/main/", strlen("internal/main/")) == 0 ||
strncmp(id,
"internal/bootstrap/",
strlen("internal/bootstrap/")) == 0) {
// internal/main/*, internal/bootstrap/*: process, require,
// internalBinding, primordials
arguments = {realm->process_object(),
realm->builtin_module_require(),
realm->internal_binding_loader(),
realm->primordials()};
} else if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) {
// Synthetic embedder main scripts from LoadEnvironment(): process, require
arguments = {
realm->process_object(),
realm->builtin_module_require(),
};
} else {
// This should be invoked with the other CompileAndCall() methods, as
// we are unable to generate the arguments.
// Currently there are two cases:
// internal/per_context/*: the arguments are generated in
// InitializePrimordials()
// all the other cases: the arguments are generated in the JS-land loader.
UNREACHABLE();
}
return CompileAndCall(
context, id, arguments.size(), arguments.data(), realm->env());
}

MaybeLocal<Value> BuiltinLoader::CompileAndCall(Local<Context> context,
const char* id,
int argc,
Local<Value> argv[],
Environment* optional_env) {
// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
MaybeLocal<Function> maybe_fn = LookupAndCompile(context, id, optional_env);
Local<Function> fn;
if (!maybe_fn.ToLocal(&fn)) {
return MaybeLocal<Value>();
}
Local<Value> undefined = Undefined(context->GetIsolate());
return fn->Call(context, undefined, argc, argv);
}

bool BuiltinLoader::CompileAllBuiltins(Local<Context> context) {
BuiltinLoader* loader = GetInstance();
std::vector<std::string> ids = loader->GetBuiltinIds();
Expand Down
12 changes: 12 additions & 0 deletions graal-nodejs/src/node_builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class PerProcessTest;
namespace node {
class SnapshotBuilder;
class ExternalReferenceRegistry;
class Realm;

namespace builtins {

using BuiltinSourceMap = std::map<std::string, UnionBytes>;
Expand Down Expand Up @@ -51,6 +53,16 @@ class NODE_EXTERN_PRIVATE BuiltinLoader {
const char* id,
Environment* optional_env);

static v8::MaybeLocal<v8::Value> CompileAndCall(
v8::Local<v8::Context> context,
const char* id,
int argc,
v8::Local<v8::Value> argv[],
Environment* optional_env);

static v8::MaybeLocal<v8::Value> CompileAndCall(
v8::Local<v8::Context> context, const char* id, Realm* realm);

static v8::Local<v8::Object> GetSourceObject(v8::Local<v8::Context> context);
// Returns config.gypi as a JSON string
static v8::Local<v8::String> GetConfigString(v8::Isolate* isolate);
Expand Down
46 changes: 7 additions & 39 deletions graal-nodejs/src/node_realm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ using v8::MaybeLocal;
using v8::Object;
using v8::SnapshotCreator;
using v8::String;
using v8::Undefined;
using v8::Value;

Realm::Realm(Environment* env,
Expand Down Expand Up @@ -157,20 +156,10 @@ void Realm::DeserializeProperties(const RealmSerializeInfo* info) {
DoneBootstrapping();
}

MaybeLocal<Value> Realm::ExecuteBootstrapper(
const char* id, std::vector<Local<Value>>* arguments) {
MaybeLocal<Value> Realm::ExecuteBootstrapper(const char* id) {
EscapableHandleScope scope(isolate());
Local<Context> ctx = context();
MaybeLocal<Function> maybe_fn =
BuiltinLoader::LookupAndCompile(ctx, id, env());

Local<Function> fn;
if (!maybe_fn.ToLocal(&fn)) {
return MaybeLocal<Value>();
}

MaybeLocal<Value> result =
fn->Call(ctx, Undefined(isolate()), arguments->size(), arguments->data());
MaybeLocal<Value> result = BuiltinLoader::CompileAndCall(ctx, id, this);

// If there was an error during bootstrap, it must be unrecoverable
// (e.g. max call stack exceeded). Clear the stack so that the
Expand All @@ -188,21 +177,9 @@ MaybeLocal<Value> Realm::ExecuteBootstrapper(
MaybeLocal<Value> Realm::BootstrapInternalLoaders() {
EscapableHandleScope scope(isolate_);

// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
std::vector<Local<Value>> loaders_args = {
process_object(),
NewFunctionTemplate(isolate_, binding::GetLinkedBinding)
->GetFunction(context())
.ToLocalChecked(),
NewFunctionTemplate(isolate_, binding::GetInternalBinding)
->GetFunction(context())
.ToLocalChecked(),
primordials()};

// Bootstrap internal loaders
Local<Value> loader_exports;
if (!ExecuteBootstrapper("internal/bootstrap/loaders", &loaders_args)
if (!ExecuteBootstrapper("internal/bootstrap/loaders")
.ToLocal(&loader_exports)) {
return MaybeLocal<Value>();
}
Expand All @@ -225,23 +202,14 @@ MaybeLocal<Value> Realm::BootstrapInternalLoaders() {
MaybeLocal<Value> Realm::BootstrapNode() {
EscapableHandleScope scope(isolate_);

// Arguments must match the parameters specified in
// BuiltinLoader::LookupAndCompile().
// process, require, internalBinding, primordials
std::vector<Local<Value>> node_args = {process_object(),
builtin_module_require(),
internal_binding_loader(),
primordials()};

MaybeLocal<Value> result =
ExecuteBootstrapper("internal/bootstrap/node", &node_args);
MaybeLocal<Value> result = ExecuteBootstrapper("internal/bootstrap/node");

if (result.IsEmpty()) {
return MaybeLocal<Value>();
}

if (!env_->no_browser_globals()) {
result = ExecuteBootstrapper("internal/bootstrap/browser", &node_args);
result = ExecuteBootstrapper("internal/bootstrap/browser");

if (result.IsEmpty()) {
return MaybeLocal<Value>();
Expand All @@ -252,7 +220,7 @@ MaybeLocal<Value> Realm::BootstrapNode() {
auto thread_switch_id =
env_->is_main_thread() ? "internal/bootstrap/switches/is_main_thread"
: "internal/bootstrap/switches/is_not_main_thread";
result = ExecuteBootstrapper(thread_switch_id, &node_args);
result = ExecuteBootstrapper(thread_switch_id);

if (result.IsEmpty()) {
return MaybeLocal<Value>();
Expand All @@ -262,7 +230,7 @@ MaybeLocal<Value> Realm::BootstrapNode() {
env_->owns_process_state()
? "internal/bootstrap/switches/does_own_process_state"
: "internal/bootstrap/switches/does_not_own_process_state";
result = ExecuteBootstrapper(process_state_switch_id, &node_args);
result = ExecuteBootstrapper(process_state_switch_id);

if (result.IsEmpty()) {
return MaybeLocal<Value>();
Expand Down
3 changes: 1 addition & 2 deletions graal-nodejs/src/node_realm.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,7 @@ class Realm : public MemoryRetainer {
RealmSerializeInfo Serialize(v8::SnapshotCreator* creator);
void DeserializeProperties(const RealmSerializeInfo* info);

v8::MaybeLocal<v8::Value> ExecuteBootstrapper(
const char* id, std::vector<v8::Local<v8::Value>>* arguments);
v8::MaybeLocal<v8::Value> ExecuteBootstrapper(const char* id);
v8::MaybeLocal<v8::Value> BootstrapInternalLoaders();
v8::MaybeLocal<v8::Value> BootstrapNode();
v8::MaybeLocal<v8::Value> RunBootstrapping();
Expand Down

0 comments on commit 4e51651

Please sign in to comment.