From e7d101fbd4930afb1d3a91f70ebbeed8d4f75b93 Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 28 Jul 2022 14:58:00 +0800 Subject: [PATCH] bootstrap: support more builtins in the embedded code cache This patch: - Make NativeModuleLoader::LookupAndCompile() detect parameters based on module IDs. This allows us to compile more builtins when generating the embedded bootstrap, including - internal/per_context/* - internal/bootstrap/* - internal/main/* - Move pre_execution.js to lib/internal/process as it needs to be compiled as a regular built-in module, unlike other scripts in lib/internal/bootstrap - Move markBootstrapComplete() to the performance binding instead of making it a function-wrapper-based global to reduce number of special cases. PR-URL: https://github.com/nodejs/node/pull/44018 Reviewed-By: Chengzhong Wu Reviewed-By: Anna Henningsen --- lib/internal/bootstrap/loaders.js | 2 + lib/internal/bootstrap/node.js | 4 +- lib/internal/main/.eslintrc.yaml | 2 - lib/internal/main/check_syntax.js | 5 +- .../{bootstrap => main}/environment.js | 6 +- lib/internal/main/eval_stdin.js | 5 +- lib/internal/main/eval_string.js | 5 +- lib/internal/main/inspect.js | 5 +- lib/internal/main/mksnapshot.js | 2 +- lib/internal/main/print_help.js | 5 +- lib/internal/main/prof_process.js | 5 +- lib/internal/main/repl.js | 5 +- lib/internal/main/run_main_module.js | 5 +- lib/internal/main/test_runner.js | 3 +- lib/internal/main/worker_thread.js | 5 +- .../{bootstrap => process}/pre_execution.js | 7 +- lib/internal/v8/startup_snapshot.js | 6 +- lib/internal/wasm_web_api.js | 2 +- src/api/environment.cc | 15 ++- src/node.cc | 68 ++++---------- src/node_internals.h | 1 - src/node_native_module.cc | 91 +++++++++++++------ src/node_native_module.h | 8 +- src/node_perf.cc | 8 ++ src/node_snapshotable.cc | 5 +- test/parallel/test-bootstrap-modules.js | 2 +- test/parallel/test-code-cache.js | 16 +--- 27 files changed, 156 insertions(+), 137 deletions(-) delete mode 100644 lib/internal/main/.eslintrc.yaml rename lib/internal/{bootstrap => main}/environment.js (69%) rename lib/internal/{bootstrap => process}/pre_execution.js (99%) diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index 41162fabcbc589..4c7a9acef2e539 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -326,6 +326,8 @@ class NativeModule { requireWithFallbackInDeps : nativeModuleRequire; const fn = compileFunction(id); + // Arguments must match the parameters specified in + // NativeModuleLoader::LookupAndCompile(). fn(this.exports, requireFn, this, process, internalBinding, primordials); this.loaded = true; diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index df2afb84b5a6ca..14eb4bbcca472d 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -6,7 +6,7 @@ // // This file is expected not to perform any asynchronous operations itself // when being executed - those should be done in either -// `lib/internal/bootstrap/pre_execution.js` or in main scripts. The majority +// `lib/internal/process/pre_execution.js` or in main scripts. The majority // of the code here focuses on setting up the global proxy and the process // object in a synchronous manner. // As special caution is given to the performance of the startup process, @@ -28,7 +28,7 @@ // Then, depending on how the Node.js instance is launched, one of the main // scripts in `lib/internal/main` will be selected by C++ to start the actual // execution. They may run additional setups exported by -// `lib/internal/bootstrap/pre_execution.js` depending on the runtime states. +// `lib/internal/process/pre_execution.js` depending on the runtime states. 'use strict'; diff --git a/lib/internal/main/.eslintrc.yaml b/lib/internal/main/.eslintrc.yaml deleted file mode 100644 index dfb75077782301..00000000000000 --- a/lib/internal/main/.eslintrc.yaml +++ /dev/null @@ -1,2 +0,0 @@ -globals: - markBootstrapComplete: true diff --git a/lib/internal/main/check_syntax.js b/lib/internal/main/check_syntax.js index 010bef045e4fc8..4aa0d217c28c11 100644 --- a/lib/internal/main/check_syntax.js +++ b/lib/internal/main/check_syntax.js @@ -4,8 +4,9 @@ // instead of actually running the file. const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); const { readStdin diff --git a/lib/internal/bootstrap/environment.js b/lib/internal/main/environment.js similarity index 69% rename from lib/internal/bootstrap/environment.js rename to lib/internal/main/environment.js index 79a67dae378202..0be982bfb6d25d 100644 --- a/lib/internal/bootstrap/environment.js +++ b/lib/internal/main/environment.js @@ -4,10 +4,10 @@ // that depends on run time states. // It is currently only intended for preparing contexts for embedders. -/* global markBootstrapComplete */ const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); prepareMainThreadExecution(); markBootstrapComplete(); diff --git a/lib/internal/main/eval_stdin.js b/lib/internal/main/eval_stdin.js index d97dbece8f0f56..422e05c837a830 100644 --- a/lib/internal/main/eval_stdin.js +++ b/lib/internal/main/eval_stdin.js @@ -3,8 +3,9 @@ // Stdin is not a TTY, we will read it and execute it. const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); const { getOptionValue } = require('internal/options'); diff --git a/lib/internal/main/eval_string.js b/lib/internal/main/eval_string.js index 2784204f6002e9..d4787e151a07f3 100644 --- a/lib/internal/main/eval_string.js +++ b/lib/internal/main/eval_string.js @@ -8,8 +8,9 @@ const { } = primordials; const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); const { evalModule, evalScript } = require('internal/process/execution'); const { addBuiltinLibsToObject } = require('internal/modules/cjs/helpers'); diff --git a/lib/internal/main/inspect.js b/lib/internal/main/inspect.js index b3b26ecaa960f1..6c4cc7cc36bcda 100644 --- a/lib/internal/main/inspect.js +++ b/lib/internal/main/inspect.js @@ -3,8 +3,9 @@ // `node inspect ...` or `node debug ...` const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); prepareMainThreadExecution(); diff --git a/lib/internal/main/mksnapshot.js b/lib/internal/main/mksnapshot.js index 616a436e0a9483..fdf0e021204858 100644 --- a/lib/internal/main/mksnapshot.js +++ b/lib/internal/main/mksnapshot.js @@ -114,7 +114,7 @@ function requireForUserSnapshot(id) { function main() { const { prepareMainThreadExecution - } = require('internal/bootstrap/pre_execution'); + } = require('internal/process/pre_execution'); prepareMainThreadExecution(true, false); diff --git a/lib/internal/main/print_help.js b/lib/internal/main/print_help.js index f8fc5a6075f104..bfef215ace8db5 100644 --- a/lib/internal/main/print_help.js +++ b/lib/internal/main/print_help.js @@ -20,8 +20,9 @@ const { types } = internalBinding('options'); const hasCrypto = Boolean(process.versions.openssl); const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); const typeLookup = []; for (const key of ObjectKeys(types)) diff --git a/lib/internal/main/prof_process.js b/lib/internal/main/prof_process.js index bd835bfe630fa4..3d56e3ec57fa46 100644 --- a/lib/internal/main/prof_process.js +++ b/lib/internal/main/prof_process.js @@ -1,8 +1,9 @@ 'use strict'; const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); prepareMainThreadExecution(); markBootstrapComplete(); diff --git a/lib/internal/main/repl.js b/lib/internal/main/repl.js index a8356687ccedf5..7da68dc05e84b4 100644 --- a/lib/internal/main/repl.js +++ b/lib/internal/main/repl.js @@ -4,8 +4,9 @@ // the main module is not specified and stdin is a TTY. const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); const esmLoader = require('internal/process/esm_loader'); const { diff --git a/lib/internal/main/run_main_module.js b/lib/internal/main/run_main_module.js index ca5d1122c59d94..1c2d421fc08996 100644 --- a/lib/internal/main/run_main_module.js +++ b/lib/internal/main/run_main_module.js @@ -1,8 +1,9 @@ 'use strict'; const { - prepareMainThreadExecution -} = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete +} = require('internal/process/pre_execution'); prepareMainThreadExecution(true); diff --git a/lib/internal/main/test_runner.js b/lib/internal/main/test_runner.js index c1066cfca35323..d28311f3ab5dcd 100644 --- a/lib/internal/main/test_runner.js +++ b/lib/internal/main/test_runner.js @@ -12,7 +12,8 @@ const { } = primordials; const { prepareMainThreadExecution, -} = require('internal/bootstrap/pre_execution'); + markBootstrapComplete +} = require('internal/process/pre_execution'); const { spawn } = require('child_process'); const { readdirSync, statSync } = require('fs'); const console = require('internal/console/global'); diff --git a/lib/internal/main/worker_thread.js b/lib/internal/main/worker_thread.js index 8d5bc45edd50f3..01f711aab25ccd 100644 --- a/lib/internal/main/worker_thread.js +++ b/lib/internal/main/worker_thread.js @@ -30,8 +30,9 @@ const { initializeReport, initializeSourceMapsHandlers, loadPreloadModules, - setupTraceCategoryState -} = require('internal/bootstrap/pre_execution'); + setupTraceCategoryState, + markBootstrapComplete +} = require('internal/process/pre_execution'); const { threadId, diff --git a/lib/internal/bootstrap/pre_execution.js b/lib/internal/process/pre_execution.js similarity index 99% rename from lib/internal/bootstrap/pre_execution.js rename to lib/internal/process/pre_execution.js index 823f2515f4f704..3d5657a77e512e 100644 --- a/lib/internal/bootstrap/pre_execution.js +++ b/lib/internal/process/pre_execution.js @@ -572,6 +572,10 @@ function loadPreloadModules() { } } +function markBootstrapComplete() { + internalBinding('performance').markBootstrapComplete(); +} + module.exports = { refreshRuntimeOptions, patchProcessObject, @@ -592,5 +596,6 @@ module.exports = { setupInspectorHooks, initializeReport, initializeCJSLoader, - initializeWASI + initializeWASI, + markBootstrapComplete }; diff --git a/lib/internal/v8/startup_snapshot.js b/lib/internal/v8/startup_snapshot.js index 6a6a6c47e85708..86bee8749566d7 100644 --- a/lib/internal/v8/startup_snapshot.js +++ b/lib/internal/v8/startup_snapshot.js @@ -12,7 +12,6 @@ const { setSerializeCallback, setDeserializeCallback, setDeserializeMainFunction: _setDeserializeMainFunction, - markBootstrapComplete } = internalBinding('mksnapshot'); function isBuildingSnapshot() { @@ -87,8 +86,9 @@ function setDeserializeMainFunction(callback, data) { _setDeserializeMainFunction(function deserializeMain() { const { - prepareMainThreadExecution - } = require('internal/bootstrap/pre_execution'); + prepareMainThreadExecution, + markBootstrapComplete + } = require('internal/process/pre_execution'); // This should be in sync with run_main_module.js until we make that // a built-in main function. diff --git a/lib/internal/wasm_web_api.js b/lib/internal/wasm_web_api.js index 084a223806334f..8b28b5e1fb4574 100644 --- a/lib/internal/wasm_web_api.js +++ b/lib/internal/wasm_web_api.js @@ -15,7 +15,7 @@ function lazyUndici() { // This is essentially an implementation of a v8::WasmStreamingCallback, except // that it is implemented in JavaScript because the fetch() implementation is -// difficult to use from C++. See lib/internal/bootstrap/pre_execution.js and +// difficult to use from C++. See lib/internal/process/pre_execution.js and // src/node_wasm_web_api.cc that interact with this function. function wasmStreamingCallback(streamState, source) { (async () => { diff --git a/src/api/environment.cc b/src/api/environment.cc index c0b5f539451696..b09d6736722d4e 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -445,13 +445,12 @@ MaybeLocal LoadEnvironment( native_module::NativeModuleLoader::Add( name.c_str(), UnionBytes(**main_utf16, main_utf16->length())); env->set_main_utf16(std::move(main_utf16)); - std::vector> params = { - env->process_string(), - env->require_string()}; + // Arguments must match the parameters specified in + // NativeModuleLoader::LookupAndCompile(). std::vector> args = { env->process_object(), env->native_module_require()}; - return ExecuteBootstrapper(env, name.c_str(), ¶ms, &args); + return ExecuteBootstrapper(env, name.c_str(), &args); }); } @@ -676,8 +675,6 @@ Maybe InitializePrimordials(Local context) { Local primordials_string = FIXED_ONE_BYTE_STRING(isolate, "primordials"); - Local global_string = FIXED_ONE_BYTE_STRING(isolate, "global"); - Local exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports"); // Create primordials first and make it available to per-context scripts. Local primordials = Object::New(isolate); @@ -693,12 +690,12 @@ Maybe InitializePrimordials(Local context) { nullptr}; for (const char** module = context_files; *module != nullptr; module++) { - std::vector> parameters = { - global_string, exports_string, primordials_string}; + // Arguments must match the parameters specified in + // NativeModuleLoader::LookupAndCompile(). Local arguments[] = {context->Global(), exports, primordials}; MaybeLocal maybe_fn = native_module::NativeModuleLoader::LookupAndCompile( - context, *module, ¶meters, nullptr); + context, *module, nullptr); Local fn; if (!maybe_fn.ToLocal(&fn)) { return Nothing(); diff --git a/src/node.cc b/src/node.cc index 5cbe48abd184e9..9b8b7f9f0bd49e 100644 --- a/src/node.cc +++ b/src/node.cc @@ -129,7 +129,6 @@ using native_module::NativeModuleLoader; using v8::EscapableHandleScope; using v8::Function; -using v8::FunctionCallbackInfo; using v8::Isolate; using v8::Local; using v8::MaybeLocal; @@ -174,11 +173,10 @@ void SignalExit(int signo, siginfo_t* info, void* ucontext) { MaybeLocal ExecuteBootstrapper(Environment* env, const char* id, - std::vector>* parameters, std::vector>* arguments) { EscapableHandleScope scope(env->isolate()); MaybeLocal maybe_fn = - NativeModuleLoader::LookupAndCompile(env->context(), id, parameters, env); + NativeModuleLoader::LookupAndCompile(env->context(), id, env); Local fn; if (!maybe_fn.ToLocal(&fn)) { @@ -301,12 +299,8 @@ void Environment::InitializeDiagnostics() { MaybeLocal Environment::BootstrapInternalLoaders() { EscapableHandleScope scope(isolate_); - // Create binding loaders - std::vector> loaders_params = { - process_string(), - FIXED_ONE_BYTE_STRING(isolate_, "getLinkedBinding"), - FIXED_ONE_BYTE_STRING(isolate_, "getInternalBinding"), - primordials_string()}; + // Arguments must match the parameters specified in + // NativeModuleLoader::LookupAndCompile(). std::vector> loaders_args = { process_object(), NewFunctionTemplate(isolate_, binding::GetLinkedBinding) @@ -319,8 +313,7 @@ MaybeLocal Environment::BootstrapInternalLoaders() { // Bootstrap internal loaders Local loader_exports; - if (!ExecuteBootstrapper( - this, "internal/bootstrap/loaders", &loaders_params, &loaders_args) + if (!ExecuteBootstrapper(this, "internal/bootstrap/loaders", &loaders_args) .ToLocal(&loader_exports)) { return MaybeLocal(); } @@ -342,28 +335,25 @@ MaybeLocal Environment::BootstrapInternalLoaders() { MaybeLocal Environment::BootstrapNode() { EscapableHandleScope scope(isolate_); + // Arguments must match the parameters specified in + // NativeModuleLoader::LookupAndCompile(). // process, require, internalBinding, primordials - std::vector> node_params = { - process_string(), - require_string(), - internal_binding_string(), - primordials_string()}; std::vector> node_args = { process_object(), native_module_require(), internal_binding_loader(), primordials()}; - MaybeLocal result = ExecuteBootstrapper( - this, "internal/bootstrap/node", &node_params, &node_args); + MaybeLocal result = + ExecuteBootstrapper(this, "internal/bootstrap/node", &node_args); if (result.IsEmpty()) { return MaybeLocal(); } if (!no_browser_globals()) { - result = ExecuteBootstrapper( - this, "internal/bootstrap/browser", &node_params, &node_args); + result = + ExecuteBootstrapper(this, "internal/bootstrap/browser", &node_args); if (result.IsEmpty()) { return MaybeLocal(); @@ -374,8 +364,7 @@ MaybeLocal Environment::BootstrapNode() { auto thread_switch_id = is_main_thread() ? "internal/bootstrap/switches/is_main_thread" : "internal/bootstrap/switches/is_not_main_thread"; - result = - ExecuteBootstrapper(this, thread_switch_id, &node_params, &node_args); + result = ExecuteBootstrapper(this, thread_switch_id, &node_args); if (result.IsEmpty()) { return MaybeLocal(); @@ -385,8 +374,7 @@ MaybeLocal Environment::BootstrapNode() { owns_process_state() ? "internal/bootstrap/switches/does_own_process_state" : "internal/bootstrap/switches/does_not_own_process_state"; - result = ExecuteBootstrapper( - this, process_state_switch_id, &node_params, &node_args); + result = ExecuteBootstrapper(this, process_state_switch_id, &node_args); if (result.IsEmpty()) { return MaybeLocal(); @@ -428,35 +416,20 @@ MaybeLocal Environment::RunBootstrapping() { return scope.Escape(result); } -void MarkBootstrapComplete(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); - env->performance_state()->Mark( - performance::NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE); -} - static MaybeLocal StartExecution(Environment* env, const char* main_script_id) { EscapableHandleScope scope(env->isolate()); CHECK_NOT_NULL(main_script_id); - std::vector> parameters = { - env->process_string(), - env->require_string(), - env->internal_binding_string(), - env->primordials_string(), - FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")}; - - std::vector> arguments = { - env->process_object(), - env->native_module_require(), - env->internal_binding_loader(), - env->primordials(), - NewFunctionTemplate(env->isolate(), MarkBootstrapComplete) - ->GetFunction(env->context()) - .ToLocalChecked()}; + // Arguments must match the parameters specified in + // NativeModuleLoader::LookupAndCompile(). + std::vector> arguments = {env->process_object(), + env->native_module_require(), + env->internal_binding_loader(), + env->primordials()}; return scope.EscapeMaybe( - ExecuteBootstrapper(env, main_script_id, ¶meters, &arguments)); + ExecuteBootstrapper(env, main_script_id, &arguments)); } MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) { @@ -469,8 +442,7 @@ MaybeLocal StartExecution(Environment* env, StartExecutionCallback cb) { if (cb != nullptr) { EscapableHandleScope scope(env->isolate()); - if (StartExecution(env, "internal/bootstrap/environment").IsEmpty()) - return {}; + if (StartExecution(env, "internal/main/environment").IsEmpty()) return {}; StartExecutionCallbackInfo info = { env->process_object(), diff --git a/src/node_internals.h b/src/node_internals.h index 464b6685de1fe6..1401cb33293e61 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -308,7 +308,6 @@ v8::MaybeLocal GetPerContextExports(v8::Local context); v8::MaybeLocal ExecuteBootstrapper( Environment* env, const char* id, - std::vector>* parameters, std::vector>* arguments); void MarkBootstrapComplete(const v8::FunctionCallbackInfo& args); diff --git a/src/node_native_module.cc b/src/node_native_module.cc index 7a515cc1efaeb2..ffd406625db5c1 100644 --- a/src/node_native_module.cc +++ b/src/node_native_module.cc @@ -184,21 +184,6 @@ ScriptCompiler::CachedData* NativeModuleLoader::GetCodeCache( return it->second.get(); } -MaybeLocal NativeModuleLoader::CompileAsModule( - Local context, - const char* id, - NativeModuleLoader::Result* result) { - Isolate* isolate = context->GetIsolate(); - std::vector> parameters = { - FIXED_ONE_BYTE_STRING(isolate, "exports"), - FIXED_ONE_BYTE_STRING(isolate, "require"), - FIXED_ONE_BYTE_STRING(isolate, "module"), - FIXED_ONE_BYTE_STRING(isolate, "process"), - FIXED_ONE_BYTE_STRING(isolate, "internalBinding"), - FIXED_ONE_BYTE_STRING(isolate, "primordials")}; - return LookupAndCompileInternal(context, id, ¶meters, result); -} - #ifdef NODE_BUILTIN_MODULES_PATH static std::string OnDiskFileName(const char* id) { std::string filename = NODE_BUILTIN_MODULES_PATH; @@ -360,29 +345,84 @@ MaybeLocal NativeModuleLoader::LookupAndCompileInternal( MaybeLocal NativeModuleLoader::LookupAndCompile( Local context, const char* id, - std::vector>* parameters, Environment* optional_env) { Result result; - MaybeLocal maybe = - GetInstance()->LookupAndCompileInternal(context, id, parameters, &result); + std::vector> parameters; + Isolate* isolate = context->GetIsolate(); + // Detects parameters of the scripts based on module ids. + // internal/bootstrap/loaders: process, getLinkedBinding, + // getInternalBinding, primordials + if (strcmp(id, "internal/bootstrap/loaders") == 0) { + parameters = { + FIXED_ONE_BYTE_STRING(isolate, "process"), + FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"), + FIXED_ONE_BYTE_STRING(isolate, "getInternalBinding"), + FIXED_ONE_BYTE_STRING(isolate, "primordials"), + }; + } else if (strncmp(id, + "internal/per_context/", + strlen("internal/per_context/")) == 0) { + // internal/per_context/*: global, exports, primordials + parameters = { + FIXED_ONE_BYTE_STRING(isolate, "global"), + 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 + 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 if (strncmp(id, "embedder_main_", strlen("embedder_main_")) == 0) { + // Synthetic embedder main scripts from LoadEnvironment(): process, require + parameters = { + 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 = { + FIXED_ONE_BYTE_STRING(isolate, "exports"), + FIXED_ONE_BYTE_STRING(isolate, "require"), + FIXED_ONE_BYTE_STRING(isolate, "module"), + FIXED_ONE_BYTE_STRING(isolate, "process"), + FIXED_ONE_BYTE_STRING(isolate, "internalBinding"), + FIXED_ONE_BYTE_STRING(isolate, "primordials"), + }; + } + + MaybeLocal maybe = GetInstance()->LookupAndCompileInternal( + context, id, ¶meters, &result); if (optional_env != nullptr) { RecordResult(id, result, optional_env); } return maybe; } -bool NativeModuleLoader::CompileAllModules(Local context) { +bool NativeModuleLoader::CompileAllBuiltins(Local context) { NativeModuleLoader* loader = GetInstance(); std::vector ids = loader->GetModuleIds(); bool all_succeeded = true; + std::string v8_tools_prefix = "internal/deps/v8/tools/"; for (const auto& id : ids) { - // TODO(joyeecheung): compile non-module scripts here too. - if (!loader->CanBeRequired(id.c_str())) { + if (id.compare(0, v8_tools_prefix.size(), v8_tools_prefix) == 0) { continue; } v8::TryCatch bootstrapCatch(context->GetIsolate()); - Result result; - USE(loader->CompileAsModule(context, id.c_str(), &result)); + USE(loader->LookupAndCompile(context, id.c_str(), nullptr)); if (bootstrapCatch.HasCaught()) { per_process::Debug(DebugCategory::CODE_CACHE, "Failed to compile code cache for %s\n", @@ -538,16 +578,15 @@ void NativeModuleLoader::RecordResult(const char* id, env->native_modules_without_cache.insert(id); } } + void NativeModuleLoader::CompileFunction( const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); CHECK(args[0]->IsString()); node::Utf8Value id_v(env->isolate(), args[0].As()); const char* id = *id_v; - NativeModuleLoader::Result result; MaybeLocal maybe = - GetInstance()->CompileAsModule(env->context(), id, &result); - RecordResult(id, result, env); + GetInstance()->LookupAndCompile(env->context(), id, env); Local fn; if (maybe.ToLocal(&fn)) { args.GetReturnValue().Set(fn); diff --git a/src/node_native_module.h b/src/node_native_module.h index 3c797a5d35b17e..5357a1272d3214 100644 --- a/src/node_native_module.h +++ b/src/node_native_module.h @@ -45,10 +45,11 @@ class NODE_EXTERN_PRIVATE NativeModuleLoader { v8::Local context, void* priv); + // The parameters used to compile the scripts are detected based on + // the pattern of the id. static v8::MaybeLocal LookupAndCompile( v8::Local context, const char* id, - std::vector>* parameters, Environment* optional_env); static v8::Local GetSourceObject(v8::Local context); @@ -57,7 +58,7 @@ class NODE_EXTERN_PRIVATE NativeModuleLoader { static bool Exists(const char* id); static bool Add(const char* id, const UnionBytes& source); - static bool CompileAllModules(v8::Local context); + static bool CompileAllBuiltins(v8::Local context); static void RefreshCodeCache(const std::vector& in); static void CopyCodeCache(std::vector* out); @@ -100,9 +101,6 @@ class NODE_EXTERN_PRIVATE NativeModuleLoader { const char* id, std::vector>* parameters, Result* result); - v8::MaybeLocal CompileAsModule(v8::Local context, - const char* id, - Result* result); static void RecordResult(const char* id, NativeModuleLoader::Result result, diff --git a/src/node_perf.cc b/src/node_perf.cc index 15f45cba78c1e0..f08237f03c405e 100644 --- a/src/node_perf.cc +++ b/src/node_perf.cc @@ -265,6 +265,12 @@ void GetTimeOriginTimeStamp(const FunctionCallbackInfo& args) { Number::New(args.GetIsolate(), timeOriginTimestamp / MICROS_PER_MILLIS)); } +void MarkBootstrapComplete(const FunctionCallbackInfo& args) { + Environment* env = Environment::GetCurrent(args); + env->performance_state()->Mark( + performance::NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE); +} + void Initialize(Local target, Local unused, Local context, @@ -304,6 +310,7 @@ void Initialize(Local target, SetMethod(context, target, "getTimeOrigin", GetTimeOrigin); SetMethod(context, target, "getTimeOriginTimestamp", GetTimeOriginTimeStamp); SetMethod(context, target, "createELDHistogram", CreateELDHistogram); + SetMethod(context, target, "markBootstrapComplete", MarkBootstrapComplete); Local constants = Object::New(isolate); @@ -358,6 +365,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(GetTimeOrigin); registry->Register(GetTimeOriginTimeStamp); registry->Register(CreateELDHistogram); + registry->Register(MarkBootstrapComplete); HistogramBase::RegisterExternalReferences(registry); IntervalHistogram::RegisterExternalReferences(registry); } diff --git a/src/node_snapshotable.cc b/src/node_snapshotable.cc index a7551bf1af14c0..880c50663f9aa1 100644 --- a/src/node_snapshotable.cc +++ b/src/node_snapshotable.cc @@ -285,7 +285,8 @@ int SnapshotBuilder::Generate(SnapshotData* out, #ifdef NODE_USE_NODE_CODE_CACHE // Regenerate all the code cache. - if (!native_module::NativeModuleLoader::CompileAllModules(main_context)) { + if (!native_module::NativeModuleLoader::CompileAllBuiltins( + main_context)) { return UNCAUGHT_EXCEPTION_ERROR; } native_module::NativeModuleLoader::CopyCodeCache(&(out->code_cache)); @@ -521,7 +522,6 @@ void Initialize(Local target, Local context, void* priv) { SetMethod(context, target, "compileSerializeMain", CompileSerializeMain); - SetMethod(context, target, "markBootstrapComplete", MarkBootstrapComplete); SetMethod(context, target, "setSerializeCallback", SetSerializeCallback); SetMethod(context, target, "setDeserializeCallback", SetDeserializeCallback); SetMethod(context, @@ -532,7 +532,6 @@ void Initialize(Local target, void RegisterExternalReferences(ExternalReferenceRegistry* registry) { registry->Register(CompileSerializeMain); - registry->Register(MarkBootstrapComplete); registry->Register(SetSerializeCallback); registry->Register(SetDeserializeCallback); registry->Register(SetDeserializeMainFunction); diff --git a/test/parallel/test-bootstrap-modules.js b/test/parallel/test-bootstrap-modules.js index 87c9dc1b92523c..63ef4336123640 100644 --- a/test/parallel/test-bootstrap-modules.js +++ b/test/parallel/test-bootstrap-modules.js @@ -52,7 +52,6 @@ const expectedModules = new Set([ 'NativeModule internal/assert', 'NativeModule internal/async_hooks', 'NativeModule internal/blocklist', - 'NativeModule internal/bootstrap/pre_execution', 'NativeModule internal/buffer', 'NativeModule internal/console/constructor', 'NativeModule internal/console/global', @@ -106,6 +105,7 @@ const expectedModules = new Set([ 'NativeModule internal/process/esm_loader', 'NativeModule internal/process/execution', 'NativeModule internal/process/per_thread', + 'NativeModule internal/process/pre_execution', 'NativeModule internal/process/promises', 'NativeModule internal/process/report', 'NativeModule internal/process/signal', diff --git a/test/parallel/test-code-cache.js b/test/parallel/test-code-cache.js index 00deafd6d49465..44fe98238ad069 100644 --- a/test/parallel/test-code-cache.js +++ b/test/parallel/test-code-cache.js @@ -12,7 +12,7 @@ const { } = require('internal/test/binding'); const { getCacheUsage, - moduleCategories: { canBeRequired, cannotBeRequired } + moduleCategories: { canBeRequired } } = internalBinding('native_module'); for (const key of canBeRequired) { @@ -54,20 +54,12 @@ if (!process.features.cached_builtins) { } else { // Native compiled assert(process.config.variables.node_use_node_code_cache); - if (!isMainThread) { - for (const key of [ 'internal/bootstrap/pre_execution' ]) { - canBeRequired.add(key); - cannotBeRequired.delete(key); - } - } - const wrong = []; for (const key of loadedModules) { - if (cannotBeRequired.has(key) && !compiledWithoutCache.has(key)) { - wrong.push(`"${key}" should've been compiled **without** code cache`); + if (key.startsWith('internal/deps/v8/tools')) { + continue; } - if (canBeRequired.has(key) && - !compiledWithCache.has(key) && + if (!compiledWithCache.has(key) && compiledInSnapshot.indexOf(key) === -1) { wrong.push(`"${key}" should've been compiled **with** code cache`); }