diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 648efc2da80870..40cfdfbc4eacf2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -89,7 +89,7 @@ /doc/api/module.md @nodejs/modules @nodejs/loaders /doc/api/modules.md @nodejs/modules @nodejs/loaders /doc/api/packages.md @nodejs/modules @nodejs/loaders -/lib/internal/bootstrap/loaders.js @nodejs/modules @nodejs/loaders +/lib/internal/bootstrap/realm.js @nodejs/modules @nodejs/loaders /lib/internal/modules/* @nodejs/modules @nodejs/loaders /lib/internal/process/esm_loader.js @nodejs/modules @nodejs/loaders /lib/internal/process/execution.js @nodejs/modules @nodejs/loaders diff --git a/lib/assert.js b/lib/assert.js index 04c2dd3bfcfdfb..c73e750e337fcb 100644 --- a/lib/assert.js +++ b/lib/assert.js @@ -65,7 +65,7 @@ const { openSync, closeSync, readSync } = require('fs'); const { inspect } = require('internal/util/inspect'); const { isPromise, isRegExp } = require('internal/util/types'); const { EOL } = require('internal/constants'); -const { BuiltinModule } = require('internal/bootstrap/loaders'); +const { BuiltinModule } = require('internal/bootstrap/realm'); const { isError } = require('internal/util'); const errorCache = new SafeMap(); diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index 93009b5beccbba..161f75284d33dc 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -1,6 +1,6 @@ // Hello, and welcome to hacking node.js! // -// This file is invoked by `Realm::BootstrapNode()` in `src/node_realm.cc`, +// This file is invoked by `Realm::BootstrapRealm()` in `src/node_realm.cc`, // and is responsible for setting up Node.js core before main scripts // under `lib/internal/main/` are executed. // @@ -32,9 +32,10 @@ // `DOMException` class. // - `lib/internal/per_context/messageport.js`: JS-side components of the // `MessagePort` implementation. -// - `lib/internal/bootstrap/loaders.js`: this sets up internal binding and +// - `lib/internal/bootstrap/realm.js`: this sets up internal binding and // module loaders, including `process.binding()`, `process._linkedBinding()`, -// `internalBinding()` and `BuiltinModule`. +// `internalBinding()` and `BuiltinModule`, and per-realm internal states +// and bindings, including `prepare_stack_trace_callback`. // // The initialization done in this script is included in both the main thread // and the worker threads. After this, further initialization is done based @@ -52,8 +53,6 @@ // passed by `BuiltinLoader::CompileAndCall()`. /* global process, require, internalBinding, primordials */ -setupPrepareStackTrace(); - const { FunctionPrototypeCall, JSONParse, @@ -364,25 +363,6 @@ process.emitWarning = emitWarning; // Note: only after this point are the timers effective } -function setupPrepareStackTrace() { - const { - setEnhanceStackForFatalException, - setPrepareStackTraceCallback, - } = internalBinding('errors'); - const { - prepareStackTrace, - fatalExceptionStackEnhancers: { - beforeInspector, - afterInspector, - }, - } = require('internal/errors'); - // Tell our PrepareStackTraceCallback passed to the V8 API - // to call prepareStackTrace(). - setPrepareStackTraceCallback(prepareStackTrace); - // Set the function used to enhance the error stack for printing - setEnhanceStackForFatalException(beforeInspector, afterInspector); -} - function setupProcessObject() { const EventEmitter = require('events'); const origProcProto = ObjectGetPrototypeOf(process); diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/realm.js similarity index 91% rename from lib/internal/bootstrap/loaders.js rename to lib/internal/bootstrap/realm.js index 0db70f1cc85687..221b1de5424d45 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/realm.js @@ -1,3 +1,8 @@ +// This file is executed in every realm that is created by Node.js, including +// the context of main thread, worker threads, and ShadowRealms. +// Only per-realm internal states and bindings should be bootstrapped in this +// file and no globals should be exposed to the user code. +// // This file creates the internal module & binding loaders used by built-in // modules. In contrast, user land modules are loaded using // lib/internal/modules/cjs/loader.js (CommonJS Modules) or @@ -30,7 +35,7 @@ // so they can be loaded faster without the cost of I/O. This class makes the // lib/internal/*, deps/internal/* modules and internalBinding() available by // default to core modules, and lets the core modules require itself via -// require('internal/bootstrap/loaders') even when this file is not written in +// require('internal/bootstrap/realm') even when this file is not written in // CommonJS style. // // Other objects: @@ -181,7 +186,7 @@ let internalBinding; }; } -const loaderId = 'internal/bootstrap/loaders'; +const selfId = 'internal/bootstrap/realm'; const { builtinIds, compileFunction, @@ -238,7 +243,7 @@ class BuiltinModule { static exposeInternals() { for (const { 0: id, 1: mod } of BuiltinModule.map) { // Do not expose this to user land even with --expose-internals. - if (id !== loaderId) { + if (id !== selfId) { mod.canBeRequiredByUsers = true; } } @@ -357,7 +362,7 @@ const loaderExports = { }; function requireBuiltin(id) { - if (id === loaderId) { + if (id === selfId) { return loaderExports; } @@ -379,5 +384,27 @@ function requireWithFallbackInDeps(request) { return requireBuiltin(request); } +function setupPrepareStackTrace() { + const { + setEnhanceStackForFatalException, + setPrepareStackTraceCallback, + } = internalBinding('errors'); + const { + prepareStackTrace, + fatalExceptionStackEnhancers: { + beforeInspector, + afterInspector, + }, + } = requireBuiltin('internal/errors'); + // Tell our PrepareStackTraceCallback passed to the V8 API + // to call prepareStackTrace(). + setPrepareStackTraceCallback(prepareStackTrace); + // Set the function used to enhance the error stack for printing + setEnhanceStackForFatalException(beforeInspector, afterInspector); +} + // Store the internal loaders in C++. setInternalLoaders(internalBinding, requireBuiltin); + +// Setup per-realm bindings. +setupPrepareStackTrace(); diff --git a/lib/internal/main/mksnapshot.js b/lib/internal/main/mksnapshot.js index 6dee4334fbaa4f..ec4e01da051754 100644 --- a/lib/internal/main/mksnapshot.js +++ b/lib/internal/main/mksnapshot.js @@ -12,7 +12,7 @@ const { } = primordials; const binding = internalBinding('mksnapshot'); -const { BuiltinModule } = require('internal/bootstrap/loaders'); +const { BuiltinModule } = require('internal/bootstrap/realm'); const { compileSerializeMain, } = binding; diff --git a/lib/internal/modules/cjs/loader.js b/lib/internal/modules/cjs/loader.js index c037d169585198..7b18f241f4b006 100644 --- a/lib/internal/modules/cjs/loader.js +++ b/lib/internal/modules/cjs/loader.js @@ -76,7 +76,7 @@ module.exports = { initializeCJS, }; -const { BuiltinModule } = require('internal/bootstrap/loaders'); +const { BuiltinModule } = require('internal/bootstrap/realm'); const { maybeCacheSourceMap, } = require('internal/source_map/source_map_cache'); diff --git a/lib/internal/modules/esm/hooks.js b/lib/internal/modules/esm/hooks.js index 64bfbe7fef9342..803e60c23bc9ff 100644 --- a/lib/internal/modules/esm/hooks.js +++ b/lib/internal/modules/esm/hooks.js @@ -190,7 +190,7 @@ class Hooks { filename: '', }, ); - const { BuiltinModule } = require('internal/bootstrap/loaders'); + const { BuiltinModule } = require('internal/bootstrap/realm'); // We only allow replacing the importMetaInitializer during preload; // after preload is finished, we disable the ability to replace it. // diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index 0dc8711643c6f0..448782cf96afac 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -24,7 +24,7 @@ const { StringPrototypeStartsWith, } = primordials; const internalFS = require('internal/fs/utils'); -const { BuiltinModule } = require('internal/bootstrap/loaders'); +const { BuiltinModule } = require('internal/bootstrap/realm'); const { realpathSync, statSync, diff --git a/lib/internal/modules/helpers.js b/lib/internal/modules/helpers.js index 05619d3ad54f24..1eafceee205623 100644 --- a/lib/internal/modules/helpers.js +++ b/lib/internal/modules/helpers.js @@ -18,7 +18,7 @@ const { ERR_MANIFEST_DEPENDENCY_MISSING, ERR_UNKNOWN_BUILTIN_MODULE, } = require('internal/errors').codes; -const { BuiltinModule } = require('internal/bootstrap/loaders'); +const { BuiltinModule } = require('internal/bootstrap/realm'); const { validateString } = require('internal/validators'); const path = require('path'); diff --git a/lib/internal/process/pre_execution.js b/lib/internal/process/pre_execution.js index 1e5de6ed3e947b..0a467e7c461610 100644 --- a/lib/internal/process/pre_execution.js +++ b/lib/internal/process/pre_execution.js @@ -339,7 +339,7 @@ function initializeReport() { function setupDebugEnv() { require('internal/util/debuglog').initializeDebugEnv(process.env.NODE_DEBUG); if (getOptionValue('--expose-internals')) { - require('internal/bootstrap/loaders').BuiltinModule.exposeInternals(); + require('internal/bootstrap/realm').BuiltinModule.exposeInternals(); } } diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index bc5ea4b31a2ad5..760498f22f2080 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -151,7 +151,7 @@ const { const assert = require('internal/assert'); -const { BuiltinModule } = require('internal/bootstrap/loaders'); +const { BuiltinModule } = require('internal/bootstrap/realm'); const { validateObject, validateString, diff --git a/lib/repl.js b/lib/repl.js index 94ce92c2d045ba..ce055541034d88 100644 --- a/lib/repl.js +++ b/lib/repl.js @@ -97,7 +97,7 @@ const { globalThis, } = primordials; -const { BuiltinModule } = require('internal/bootstrap/loaders'); +const { BuiltinModule } = require('internal/bootstrap/realm'); const { makeRequireFunction, addBuiltinLibsToObject, diff --git a/src/api/environment.cc b/src/api/environment.cc index 404c5dd0a2faa8..51cd46d0fb1c02 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -65,7 +65,18 @@ MaybeLocal PrepareStackTraceCallback(Local context, if (env == nullptr) { return exception->ToString(context).FromMaybe(Local()); } - Local prepare = env->prepare_stack_trace_callback(); + Realm* realm = Realm::GetCurrent(context); + Local prepare; + if (realm != nullptr) { + // If we are in a Realm, call the realm specific prepareStackTrace callback + // to avoid passing the JS objects (the exception and trace) across the + // realm boundary with the `Error.prepareStackTrace` override. + prepare = realm->prepare_stack_trace_callback(); + } else { + // The context is created with ContextifyContext, call the principal + // realm's prepareStackTrace callback. + prepare = env->principal_realm()->prepare_stack_trace_callback(); + } if (prepare.IsEmpty()) { return exception->ToString(context).FromMaybe(Local()); } diff --git a/src/node_builtins.cc b/src/node_builtins.cc index 663a693bb4696f..f4379dbdbfd6c9 100644 --- a/src/node_builtins.cc +++ b/src/node_builtins.cc @@ -363,9 +363,9 @@ MaybeLocal BuiltinLoader::LookupAndCompile(Local context, 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) { + // internal/bootstrap/realm: process, getLinkedBinding, + // getInternalBinding, primordials + if (strcmp(id, "internal/bootstrap/realm") == 0) { parameters = { FIXED_ONE_BYTE_STRING(isolate, "process"), FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"), @@ -427,9 +427,9 @@ MaybeLocal BuiltinLoader::CompileAndCall(Local context, // BuiltinLoader::LookupAndCompile(). std::vector> arguments; // Detects parameters of the scripts based on module ids. - // internal/bootstrap/loaders: process, getLinkedBinding, - // getInternalBinding, primordials - if (strcmp(id, "internal/bootstrap/loaders") == 0) { + // internal/bootstrap/realm: process, getLinkedBinding, + // getInternalBinding, primordials + if (strcmp(id, "internal/bootstrap/realm") == 0) { Local get_linked_binding; Local get_internal_binding; if (!NewFunctionTemplate(isolate, binding::GetLinkedBinding) diff --git a/src/node_errors.cc b/src/node_errors.cc index e58e45be7bbb64..11bf2cc8b43916 100644 --- a/src/node_errors.cc +++ b/src/node_errors.cc @@ -954,9 +954,9 @@ void PerIsolateMessageListener(Local message, Local error) { } void SetPrepareStackTraceCallback(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + Realm* realm = Realm::GetCurrent(args); CHECK(args[0]->IsFunction()); - env->set_prepare_stack_trace_callback(args[0].As()); + realm->set_prepare_stack_trace_callback(args[0].As()); } static void SetSourceMapsEnabled(const FunctionCallbackInfo& args) { @@ -981,11 +981,11 @@ static void SetMaybeCacheGeneratedSourceMap( static void SetEnhanceStackForFatalException( const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + Realm* realm = Realm::GetCurrent(args); CHECK(args[0]->IsFunction()); CHECK(args[1]->IsFunction()); - env->set_enhance_fatal_stack_before_inspector(args[0].As()); - env->set_enhance_fatal_stack_after_inspector(args[1].As()); + realm->set_enhance_fatal_stack_before_inspector(args[0].As()); + realm->set_enhance_fatal_stack_after_inspector(args[1].As()); } // Side effect-free stringification that will never throw exceptions. diff --git a/src/node_realm.cc b/src/node_realm.cc index 1903c65f179b54..7e58b2aa2d59d6 100644 --- a/src/node_realm.cc +++ b/src/node_realm.cc @@ -183,18 +183,14 @@ MaybeLocal Realm::ExecuteBootstrapper(const char* id) { } MaybeLocal Realm::BootstrapNode() { - EscapableHandleScope scope(isolate_); - - MaybeLocal result = ExecuteBootstrapper("internal/bootstrap/node"); + HandleScope scope(isolate_); - if (result.IsEmpty()) { + if (ExecuteBootstrapper("internal/bootstrap/node").IsEmpty()) { return MaybeLocal(); } if (!env_->no_browser_globals()) { - result = ExecuteBootstrapper("internal/bootstrap/browser"); - - if (result.IsEmpty()) { + if (ExecuteBootstrapper("internal/bootstrap/browser").IsEmpty()) { return MaybeLocal(); } } @@ -203,9 +199,7 @@ MaybeLocal 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); - - if (result.IsEmpty()) { + if (ExecuteBootstrapper(thread_switch_id).IsEmpty()) { return MaybeLocal(); } @@ -213,9 +207,7 @@ MaybeLocal 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); - - if (result.IsEmpty()) { + if (ExecuteBootstrapper(process_state_switch_id).IsEmpty()) { return MaybeLocal(); } @@ -227,7 +219,7 @@ MaybeLocal Realm::BootstrapNode() { return MaybeLocal(); } - return scope.EscapeMaybe(result); + return v8::True(isolate_); } MaybeLocal Realm::RunBootstrapping() { @@ -236,7 +228,7 @@ MaybeLocal Realm::RunBootstrapping() { CHECK(!has_run_bootstrapping_code()); Local result; - if (!ExecuteBootstrapper("internal/bootstrap/loaders").ToLocal(&result)) { + if (!ExecuteBootstrapper("internal/bootstrap/realm").ToLocal(&result)) { return MaybeLocal(); } diff --git a/test/es-module/test-loaders-hidden-from-users.js b/test/es-module/test-loaders-hidden-from-users.js index 96d1c44154883e..59e910ad751dbe 100644 --- a/test/es-module/test-loaders-hidden-from-users.js +++ b/test/es-module/test-loaders-hidden-from-users.js @@ -7,16 +7,16 @@ const assert = require('assert'); assert.throws( () => { - require('internal/bootstrap/loaders'); + require('internal/bootstrap/realm'); }, { code: 'MODULE_NOT_FOUND', - message: /Cannot find module 'internal\/bootstrap\/loaders'/ + message: /Cannot find module 'internal\/bootstrap\/realm'/ } ); assert.throws( () => { - const source = 'module.exports = require("internal/bootstrap/loaders")'; + const source = 'module.exports = require("internal/bootstrap/realm")'; const { internalBinding } = require('internal/test/binding'); internalBinding('natives').owo = source; require('owo'); diff --git a/test/parallel/test-inspector-inspect-brk-node.js b/test/parallel/test-inspector-inspect-brk-node.js index 0f4795ed7b87e4..04bac6dc7cf0df 100644 --- a/test/parallel/test-inspector-inspect-brk-node.js +++ b/test/parallel/test-inspector-inspect-brk-node.js @@ -16,7 +16,7 @@ async function runTest() { await session.waitForNotification((notification) => { // The main assertion here is that we do hit the loader script first. return notification.method === 'Debugger.scriptParsed' && - notification.params.url === 'node:internal/bootstrap/loaders'; + notification.params.url === 'node:internal/bootstrap/realm'; }); await session.waitForNotification('Debugger.paused');