src: use NativeModuleLoader to compile all the bootstrappers

This patch moves all the bootstrapper compilation to use
NativeModuleLoader::CompileAndCall(). With this we no longer
need to mess with the error decoration and handling any more -
there is no point in handling the JS error occurred during bootstrapping
by ourselves, we should just crash or let the VM handle it.

PR-URL: https://github.com/nodejs/node/pull/24775
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
This commit is contained in:
Joyee Cheung 2018-11-27 01:50:41 +08:00
parent fa19ce9233
commit edcb950090
No known key found for this signature in database
GPG Key ID: 92B78A53C8303B8D
7 changed files with 1032 additions and 1131 deletions

View File

@ -39,42 +39,45 @@
'use strict'; 'use strict';
(function bootstrapInternalLoaders(process, getBinding, getLinkedBinding, // This file is compiled as if it's wrapped in a function with arguments
getInternalBinding, debugBreak) { // passed by node::LoadEnvironment()
if (debugBreak) /* global process, getBinding, getLinkedBinding, getInternalBinding */
/* global debugBreak */
if (debugBreak)
debugger; // eslint-disable-line no-debugger debugger; // eslint-disable-line no-debugger
const { const {
apply: ReflectApply, apply: ReflectApply,
deleteProperty: ReflectDeleteProperty, deleteProperty: ReflectDeleteProperty,
get: ReflectGet, get: ReflectGet,
getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor, getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor,
has: ReflectHas, has: ReflectHas,
set: ReflectSet, set: ReflectSet,
} = Reflect; } = Reflect;
const { const {
prototype: { prototype: {
hasOwnProperty: ObjectHasOwnProperty, hasOwnProperty: ObjectHasOwnProperty,
}, },
create: ObjectCreate, create: ObjectCreate,
defineProperty: ObjectDefineProperty, defineProperty: ObjectDefineProperty,
keys: ObjectKeys, keys: ObjectKeys,
} = Object; } = Object;
// Set up process.moduleLoadList. // Set up process.moduleLoadList.
const moduleLoadList = []; const moduleLoadList = [];
ObjectDefineProperty(process, 'moduleLoadList', { ObjectDefineProperty(process, 'moduleLoadList', {
value: moduleLoadList, value: moduleLoadList,
configurable: true, configurable: true,
enumerable: true, enumerable: true,
writable: false writable: false
}); });
// internalBindingWhitelist contains the name of internalBinding modules // internalBindingWhitelist contains the name of internalBinding modules
// that are whitelisted for access via process.binding()... This is used // that are whitelisted for access via process.binding()... This is used
// to provide a transition path for modules that are being moved over to // to provide a transition path for modules that are being moved over to
// internalBinding. // internalBinding.
const internalBindingWhitelist = [ const internalBindingWhitelist = [
'async_wrap', 'async_wrap',
'buffer', 'buffer',
'cares_wrap', 'cares_wrap',
@ -101,13 +104,13 @@
'uv', 'uv',
'v8', 'v8',
'zlib' 'zlib'
]; ];
// We will use a lazy loaded SafeSet in internalBindingWhitelistHas // We will use a lazy loaded SafeSet in internalBindingWhitelistHas
// for checking existence in this list. // for checking existence in this list.
let internalBindingWhitelistSet; let internalBindingWhitelistSet;
// Set up process.binding() and process._linkedBinding(). // Set up process.binding() and process._linkedBinding().
{ {
const bindingObj = ObjectCreate(null); const bindingObj = ObjectCreate(null);
process.binding = function binding(module) { process.binding = function binding(module) {
@ -132,11 +135,11 @@
mod = bindingObj[module] = getLinkedBinding(module); mod = bindingObj[module] = getLinkedBinding(module);
return mod; return mod;
}; };
} }
// Set up internalBinding() in the closure. // Set up internalBinding() in the closure.
let internalBinding; let internalBinding;
{ {
const bindingObj = ObjectCreate(null); const bindingObj = ObjectCreate(null);
internalBinding = function internalBinding(module) { internalBinding = function internalBinding(module) {
let mod = bindingObj[module]; let mod = bindingObj[module];
@ -146,13 +149,13 @@
} }
return mod; return mod;
}; };
} }
// Create this WeakMap in js-land because V8 has no C++ API for WeakMap. // Create this WeakMap in js-land because V8 has no C++ API for WeakMap.
internalBinding('module_wrap').callbackMap = new WeakMap(); internalBinding('module_wrap').callbackMap = new WeakMap();
// Set up NativeModule. // Set up NativeModule.
function NativeModule(id) { function NativeModule(id) {
this.filename = `${id}.js`; this.filename = `${id}.js`;
this.id = id; this.id = id;
this.exports = {}; this.exports = {};
@ -160,19 +163,19 @@
this.exportKeys = undefined; this.exportKeys = undefined;
this.loaded = false; this.loaded = false;
this.loading = false; this.loading = false;
} }
NativeModule._source = getInternalBinding('natives'); NativeModule._source = getInternalBinding('natives');
NativeModule._cache = {}; NativeModule._cache = {};
const config = getBinding('config'); const config = getBinding('config');
// Think of this as module.exports in this file even though it is not // Think of this as module.exports in this file even though it is not
// written in CommonJS style. // written in CommonJS style.
const loaderExports = { internalBinding, NativeModule }; const loaderExports = { internalBinding, NativeModule };
const loaderId = 'internal/bootstrap/loaders'; const loaderId = 'internal/bootstrap/loaders';
NativeModule.require = function(id) { NativeModule.require = function(id) {
if (id === loaderId) { if (id === loaderId) {
return loaderExports; return loaderExports;
} }
@ -201,30 +204,30 @@
nativeModule.compile(); nativeModule.compile();
return nativeModule.exports; return nativeModule.exports;
}; };
NativeModule.isDepsModule = function(id) { NativeModule.isDepsModule = function(id) {
return id.startsWith('node-inspect/') || id.startsWith('v8/'); return id.startsWith('node-inspect/') || id.startsWith('v8/');
}; };
NativeModule.requireForDeps = function(id) { NativeModule.requireForDeps = function(id) {
if (!NativeModule.exists(id) || if (!NativeModule.exists(id) ||
// TODO(TimothyGu): remove when DEP0084 reaches end of life. // TODO(TimothyGu): remove when DEP0084 reaches end of life.
NativeModule.isDepsModule(id)) { NativeModule.isDepsModule(id)) {
id = `internal/deps/${id}`; id = `internal/deps/${id}`;
} }
return NativeModule.require(id); return NativeModule.require(id);
}; };
NativeModule.getCached = function(id) { NativeModule.getCached = function(id) {
return NativeModule._cache[id]; return NativeModule._cache[id];
}; };
NativeModule.exists = function(id) { NativeModule.exists = function(id) {
return NativeModule._source.hasOwnProperty(id); return NativeModule._source.hasOwnProperty(id);
}; };
if (config.exposeInternals) { if (config.exposeInternals) {
NativeModule.nonInternalExists = function(id) { NativeModule.nonInternalExists = function(id) {
// Do not expose this to user land even with --expose-internals. // Do not expose this to user land even with --expose-internals.
if (id === loaderId) { if (id === loaderId) {
@ -237,7 +240,7 @@
// Do not expose this to user land even with --expose-internals. // Do not expose this to user land even with --expose-internals.
return id === loaderId; return id === loaderId;
}; };
} else { } else {
NativeModule.nonInternalExists = function(id) { NativeModule.nonInternalExists = function(id) {
return NativeModule.exists(id) && !NativeModule.isInternal(id); return NativeModule.exists(id) && !NativeModule.isInternal(id);
}; };
@ -246,32 +249,32 @@
return id.startsWith('internal/') || return id.startsWith('internal/') ||
(id === 'worker_threads' && !config.experimentalWorker); (id === 'worker_threads' && !config.experimentalWorker);
}; };
} }
NativeModule.getSource = function(id) { NativeModule.getSource = function(id) {
return NativeModule._source[id]; return NativeModule._source[id];
}; };
NativeModule.wrap = function(script) { NativeModule.wrap = function(script) {
return NativeModule.wrapper[0] + script + NativeModule.wrapper[1]; return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
}; };
NativeModule.wrapper = [ NativeModule.wrapper = [
'(function (exports, require, module, process, internalBinding) {', '(function (exports, require, module, process, internalBinding) {',
'\n});' '\n});'
]; ];
const getOwn = (target, property, receiver) => { const getOwn = (target, property, receiver) => {
return ReflectApply(ObjectHasOwnProperty, target, [property]) ? return ReflectApply(ObjectHasOwnProperty, target, [property]) ?
ReflectGet(target, property, receiver) : ReflectGet(target, property, receiver) :
undefined; undefined;
}; };
// Provide named exports for all builtin libraries so that the libraries // Provide named exports for all builtin libraries so that the libraries
// may be imported in a nicer way for ESM users. The default export is left // may be imported in a nicer way for ESM users. The default export is left
// as the entire namespace (module.exports) and wrapped in a proxy such // as the entire namespace (module.exports) and wrapped in a proxy such
// that APMs and other behavior are still left intact. // that APMs and other behavior are still left intact.
NativeModule.prototype.proxifyExports = function() { NativeModule.prototype.proxifyExports = function() {
this.exportKeys = ObjectKeys(this.exports); this.exportKeys = ObjectKeys(this.exports);
const update = (property, value) => { const update = (property, value) => {
@ -323,10 +326,10 @@
}; };
this.exports = new Proxy(this.exports, handler); this.exports = new Proxy(this.exports, handler);
}; };
const { compileFunction } = getInternalBinding('native_module'); const { compileFunction } = getInternalBinding('native_module');
NativeModule.prototype.compile = function() { NativeModule.prototype.compile = function() {
const id = this.id; const id = this.id;
this.loading = true; this.loading = true;
@ -347,27 +350,25 @@
} finally { } finally {
this.loading = false; this.loading = false;
} }
}; };
NativeModule.prototype.cache = function() { NativeModule.prototype.cache = function() {
NativeModule._cache[this.id] = this; NativeModule._cache[this.id] = this;
}; };
// Coverage must be turned on early, so that we can collect // Coverage must be turned on early, so that we can collect
// it for Node.js' own internal libraries. // it for Node.js' own internal libraries.
if (process.env.NODE_V8_COVERAGE) { if (process.env.NODE_V8_COVERAGE) {
NativeModule.require('internal/process/coverage').setup(); NativeModule.require('internal/process/coverage').setup();
} }
function internalBindingWhitelistHas(name) { function internalBindingWhitelistHas(name) {
if (!internalBindingWhitelistSet) { if (!internalBindingWhitelistSet) {
const { SafeSet } = NativeModule.require('internal/safe_globals'); const { SafeSet } = NativeModule.require('internal/safe_globals');
internalBindingWhitelistSet = new SafeSet(internalBindingWhitelist); internalBindingWhitelistSet = new SafeSet(internalBindingWhitelist);
} }
return internalBindingWhitelistSet.has(name); return internalBindingWhitelistSet.has(name);
} }
// This will be passed to the bootstrapNodeJSCore function in // This will be passed to internal/bootstrap/node.js.
// bootstrap/node.js. return loaderExports;
return loaderExports;
});

View File

@ -12,24 +12,25 @@
// into this bootstrapper to bootstrap Node.js core. // into this bootstrapper to bootstrap Node.js core.
'use strict'; 'use strict';
(function bootstrapNodeJSCore(process, // This file is compiled as if it's wrapped in a function with arguments
// bootstrapper properties... destructured to // passed by node::LoadEnvironment()
// avoid retaining a reference to the bootstrap /* global process, bootstrappers, loaderExports, triggerFatalException */
// object. const {
{ _setupTraceCategoryState, _setupTraceCategoryState,
_setupNextTick, _setupNextTick,
_setupPromises, _chdir, _cpuUsage, _setupPromises, _chdir, _cpuUsage,
_hrtime, _hrtimeBigInt, _hrtime, _hrtimeBigInt,
_memoryUsage, _rawDebug, _memoryUsage, _rawDebug,
_umask, _initgroups, _setegid, _seteuid, _umask, _initgroups, _setegid, _seteuid,
_setgid, _setuid, _setgroups, _setgid, _setuid, _setgroups,
_shouldAbortOnUncaughtToggle }, _shouldAbortOnUncaughtToggle
{ internalBinding, NativeModule }, } = bootstrappers;
triggerFatalException) { const { internalBinding, NativeModule } = loaderExports;
const exceptionHandlerState = { captureFn: null };
const isMainThread = internalBinding('worker').threadId === 0;
function startup() { const exceptionHandlerState = { captureFn: null };
const isMainThread = internalBinding('worker').threadId === 0;
function startup() {
setupTraceCategoryState(); setupTraceCategoryState();
setupProcessObject(); setupProcessObject();
@ -224,13 +225,13 @@
perThreadSetup.setupAllowedFlags(); perThreadSetup.setupAllowedFlags();
startExecution(); startExecution();
} }
// There are various modes that Node can run in. The most common two // There are various modes that Node can run in. The most common two
// are running from a script and running the REPL - but there are a few // are running from a script and running the REPL - but there are a few
// others like the debugger or running --eval arguments. Here we decide // others like the debugger or running --eval arguments. Here we decide
// which mode we run in. // which mode we run in.
function startExecution() { function startExecution() {
// This means we are in a Worker context, and any script execution // This means we are in a Worker context, and any script execution
// will be directed by the worker module. // will be directed by the worker module.
if (internalBinding('worker').getEnvMessagePort() !== undefined) { if (internalBinding('worker').getEnvMessagePort() !== undefined) {
@ -273,9 +274,9 @@
// There is user code to be run. // There is user code to be run.
prepareUserCodeExecution(); prepareUserCodeExecution();
executeUserCode(); executeUserCode();
} }
function prepareUserCodeExecution() { function prepareUserCodeExecution() {
// If this is a worker in cluster mode, start up the communication // If this is a worker in cluster mode, start up the communication
// channel. This needs to be done before any user code gets executed // channel. This needs to be done before any user code gets executed
// (including preload modules). // (including preload modules).
@ -295,9 +296,9 @@
} = NativeModule.require('internal/modules/cjs/loader'); } = NativeModule.require('internal/modules/cjs/loader');
_preloadModules(process._preload_modules); _preloadModules(process._preload_modules);
} }
} }
function executeUserCode() { function executeUserCode() {
// User passed `-e` or `--eval` arguments to Node without `-i` or // User passed `-e` or `--eval` arguments to Node without `-i` or
// `--interactive`. // `--interactive`.
// Note that the name `forceRepl` is merely an alias of `interactive` // Note that the name `forceRepl` is merely an alias of `interactive`
@ -372,9 +373,9 @@
// Stdin is not a TTY, we will read it and execute it. // Stdin is not a TTY, we will read it and execute it.
readAndExecuteStdin(); readAndExecuteStdin();
} }
function readAndExecuteStdin() { function readAndExecuteStdin() {
process.stdin.setEncoding('utf8'); process.stdin.setEncoding('utf8');
let code = ''; let code = '';
@ -390,9 +391,9 @@
evalScript('[stdin]', wrapForBreakOnFirstLine(process._eval)); evalScript('[stdin]', wrapForBreakOnFirstLine(process._eval));
} }
}); });
} }
function setupTraceCategoryState() { function setupTraceCategoryState() {
const { traceCategoryState } = internalBinding('trace_events'); const { traceCategoryState } = internalBinding('trace_events');
const kCategoryAsyncHooks = 0; const kCategoryAsyncHooks = 0;
let traceEventsAsyncHook; let traceEventsAsyncHook;
@ -416,16 +417,16 @@
toggleTraceCategoryState(); toggleTraceCategoryState();
_setupTraceCategoryState(toggleTraceCategoryState); _setupTraceCategoryState(toggleTraceCategoryState);
} }
function setupProcessObject() { function setupProcessObject() {
const EventEmitter = NativeModule.require('events'); const EventEmitter = NativeModule.require('events');
const origProcProto = Object.getPrototypeOf(process); const origProcProto = Object.getPrototypeOf(process);
Object.setPrototypeOf(origProcProto, EventEmitter.prototype); Object.setPrototypeOf(origProcProto, EventEmitter.prototype);
EventEmitter.call(process); EventEmitter.call(process);
} }
function setupGlobalVariables() { function setupGlobalVariables() {
Object.defineProperty(global, Symbol.toStringTag, { Object.defineProperty(global, Symbol.toStringTag, {
value: 'global', value: 'global',
writable: false, writable: false,
@ -472,9 +473,9 @@
global.Buffer = NativeModule.require('buffer').Buffer; global.Buffer = NativeModule.require('buffer').Buffer;
process.domain = null; process.domain = null;
process._exiting = false; process._exiting = false;
} }
function setupGlobalTimeouts() { function setupGlobalTimeouts() {
const timers = NativeModule.require('timers'); const timers = NativeModule.require('timers');
global.clearImmediate = timers.clearImmediate; global.clearImmediate = timers.clearImmediate;
global.clearInterval = timers.clearInterval; global.clearInterval = timers.clearInterval;
@ -482,9 +483,9 @@
global.setImmediate = timers.setImmediate; global.setImmediate = timers.setImmediate;
global.setInterval = timers.setInterval; global.setInterval = timers.setInterval;
global.setTimeout = timers.setTimeout; global.setTimeout = timers.setTimeout;
} }
function setupGlobalConsole() { function setupGlobalConsole() {
const consoleFromVM = global.console; const consoleFromVM = global.console;
const consoleFromNode = const consoleFromNode =
NativeModule.require('internal/console/global'); NativeModule.require('internal/console/global');
@ -504,9 +505,9 @@
// This will be exposed by `require('inspector').console` later. // This will be exposed by `require('inspector').console` later.
inspector.consoleFromVM = consoleFromVM; inspector.consoleFromVM = consoleFromVM;
} }
} }
function setupGlobalURL() { function setupGlobalURL() {
const { URL, URLSearchParams } = NativeModule.require('internal/url'); const { URL, URLSearchParams } = NativeModule.require('internal/url');
Object.defineProperties(global, { Object.defineProperties(global, {
URL: { URL: {
@ -522,9 +523,9 @@
enumerable: false enumerable: false
} }
}); });
} }
function setupGlobalEncoding() { function setupGlobalEncoding() {
const { TextEncoder, TextDecoder } = NativeModule.require('util'); const { TextEncoder, TextDecoder } = NativeModule.require('util');
Object.defineProperties(global, { Object.defineProperties(global, {
TextEncoder: { TextEncoder: {
@ -540,9 +541,9 @@
enumerable: false enumerable: false
} }
}); });
} }
function setupQueueMicrotask() { function setupQueueMicrotask() {
Object.defineProperty(global, 'queueMicrotask', { Object.defineProperty(global, 'queueMicrotask', {
get: () => { get: () => {
process.emitWarning('queueMicrotask() is experimental.', process.emitWarning('queueMicrotask() is experimental.',
@ -569,18 +570,18 @@
enumerable: false, enumerable: false,
configurable: true, configurable: true,
}); });
} }
function setupDOMException() { function setupDOMException() {
// Registers the constructor with C++. // Registers the constructor with C++.
const DOMException = NativeModule.require('internal/domexception'); const DOMException = NativeModule.require('internal/domexception');
const { registerDOMException } = internalBinding('messaging'); const { registerDOMException } = internalBinding('messaging');
registerDOMException(DOMException); registerDOMException(DOMException);
} }
function noop() {} function noop() {}
function setupProcessFatal() { function setupProcessFatal() {
const { const {
executionAsyncId, executionAsyncId,
clearDefaultTriggerAsyncId, clearDefaultTriggerAsyncId,
@ -635,9 +636,9 @@
return true; return true;
}; };
} }
function setupProcessICUVersions() { function setupProcessICUVersions() {
const icu = process.binding('config').hasIntl ? const icu = process.binding('config').hasIntl ?
internalBinding('icu') : undefined; internalBinding('icu') : undefined;
if (!icu) return; // no Intl/ICU: nothing to add here. if (!icu) return; // no Intl/ICU: nothing to add here.
@ -654,16 +655,16 @@
value: version value: version
}); });
} }
} }
function wrapForBreakOnFirstLine(source) { function wrapForBreakOnFirstLine(source) {
if (!process._breakFirstLine) if (!process._breakFirstLine)
return source; return source;
const fn = `function() {\n\n${source};\n\n}`; const fn = `function() {\n\n${source};\n\n}`;
return `process.binding('inspector').callAndPauseOnStart(${fn}, {})`; return `process.binding('inspector').callAndPauseOnStart(${fn}, {})`;
} }
function evalScript(name, body) { function evalScript(name, body) {
const CJSModule = NativeModule.require('internal/modules/cjs/loader'); const CJSModule = NativeModule.require('internal/modules/cjs/loader');
const path = NativeModule.require('path'); const path = NativeModule.require('path');
const { tryGetCwd } = NativeModule.require('internal/util'); const { tryGetCwd } = NativeModule.require('internal/util');
@ -684,9 +685,9 @@
if (process._print_eval) console.log(result); if (process._print_eval) console.log(result);
// Handle any nextTicks added in the first tick of the program. // Handle any nextTicks added in the first tick of the program.
process._tickCallback(); process._tickCallback();
} }
function checkScriptSyntax(source, filename) { function checkScriptSyntax(source, filename) {
const CJSModule = NativeModule.require('internal/modules/cjs/loader'); const CJSModule = NativeModule.require('internal/modules/cjs/loader');
const vm = NativeModule.require('vm'); const vm = NativeModule.require('vm');
const { const {
@ -701,7 +702,6 @@
source = CJSModule.wrap(source); source = CJSModule.wrap(source);
// Compile the script, this will throw if it fails. // Compile the script, this will throw if it fails.
new vm.Script(source, { displayErrors: true, filename }); new vm.Script(source, { displayErrors: true, filename });
} }
startup(); startup();
});

View File

@ -1,9 +1,9 @@
// arguments: global // This file is compiled as if it's wrapped in a function with arguments
// passed by node::NewContext()
/* global global */
'use strict'; 'use strict';
// node::NewContext calls this script
// https://github.com/nodejs/node/issues/14909 // https://github.com/nodejs/node/issues/14909
if (global.Intl) delete global.Intl.v8BreakIterator; if (global.Intl) delete global.Intl.v8BreakIterator;

View File

@ -116,7 +116,6 @@ typedef int mode_t;
namespace node { namespace node {
using errors::TryCatchScope;
using native_module::NativeModuleLoader; using native_module::NativeModuleLoader;
using options_parser::kAllowedInEnvironment; using options_parser::kAllowedInEnvironment;
using options_parser::kDisallowedInEnvironment; using options_parser::kDisallowedInEnvironment;
@ -144,7 +143,6 @@ using v8::NamedPropertyHandlerConfiguration;
using v8::NewStringType; using v8::NewStringType;
using v8::None; using v8::None;
using v8::Nothing; using v8::Nothing;
using v8::Null;
using v8::Object; using v8::Object;
using v8::ObjectTemplate; using v8::ObjectTemplate;
using v8::PropertyAttribute; using v8::PropertyAttribute;
@ -741,41 +739,6 @@ Local<Value> MakeCallback(Isolate* isolate,
.FromMaybe(Local<Value>())); .FromMaybe(Local<Value>()));
} }
// Executes a str within the current v8 context.
static MaybeLocal<Value> ExecuteString(Environment* env,
Local<String> source,
Local<String> filename) {
EscapableHandleScope scope(env->isolate());
TryCatchScope try_catch(env);
// try_catch must be nonverbose to disable FatalException() handler,
// we will handle exceptions ourself.
try_catch.SetVerbose(false);
ScriptOrigin origin(filename);
MaybeLocal<Script> script =
Script::Compile(env->context(), source, &origin);
if (script.IsEmpty()) {
ReportException(env, try_catch);
env->Exit(3);
return MaybeLocal<Value>();
}
MaybeLocal<Value> result = script.ToLocalChecked()->Run(env->context());
if (result.IsEmpty()) {
if (try_catch.HasTerminated()) {
env->isolate()->CancelTerminateExecution();
return MaybeLocal<Value>();
}
ReportException(env, try_catch);
env->Exit(4);
return MaybeLocal<Value>();
}
return scope.Escape(result.ToLocalChecked());
}
static void WaitForInspectorDisconnect(Environment* env) { static void WaitForInspectorDisconnect(Environment* env) {
#if HAVE_INSPECTOR #if HAVE_INSPECTOR
if (env->inspector_agent()->IsActive()) { if (env->inspector_agent()->IsActive()) {
@ -1334,39 +1297,13 @@ void SignalExit(int signo) {
raise(signo); raise(signo);
} }
static MaybeLocal<Value> ExecuteBootstrapper(
static MaybeLocal<Function> GetBootstrapper(
Environment* env, Environment* env,
Local<String> source, const char* id,
Local<String> script_name) { std::vector<Local<String>>* parameters,
EscapableHandleScope scope(env->isolate()); std::vector<Local<Value>>* arguments) {
MaybeLocal<Value> ret = per_process_loader.CompileAndCall(
TryCatchScope try_catch(env); env->context(), id, parameters, arguments, env);
// Disable verbose mode to stop FatalException() handler from trying
// to handle the exception. Errors this early in the start-up phase
// are not safe to ignore.
try_catch.SetVerbose(false);
// Execute the bootstrapper javascript file
MaybeLocal<Value> bootstrapper_v = ExecuteString(env, source, script_name);
if (bootstrapper_v.IsEmpty()) // This happens when execution was interrupted.
return MaybeLocal<Function>();
if (try_catch.HasCaught()) {
ReportException(env, try_catch);
exit(10);
}
CHECK(bootstrapper_v.ToLocalChecked()->IsFunction());
return scope.Escape(bootstrapper_v.ToLocalChecked().As<Function>());
}
static bool ExecuteBootstrapper(Environment* env, Local<Function> bootstrapper,
int argc, Local<Value> argv[],
Local<Value>* out) {
bool ret = bootstrapper->Call(
env->context(), Null(env->isolate()), argc, argv).ToLocal(out);
// If there was an error during bootstrap then it was either handled by the // If there was an error during bootstrap then it was either handled by the
// FatalException handler or it's unrecoverable (e.g. max call stack // FatalException handler or it's unrecoverable (e.g. max call stack
@ -1375,123 +1312,86 @@ static bool ExecuteBootstrapper(Environment* env, Local<Function> bootstrapper,
// There are only two ways to have a stack size > 1: 1) the user manually // There are only two ways to have a stack size > 1: 1) the user manually
// called MakeCallback or 2) user awaited during bootstrap, which triggered // called MakeCallback or 2) user awaited during bootstrap, which triggered
// _tickCallback(). // _tickCallback().
if (!ret) { if (ret.IsEmpty()) {
env->async_hooks()->clear_async_id_stack(); env->async_hooks()->clear_async_id_stack();
} }
return ret; return ret;
} }
void LoadEnvironment(Environment* env) { void LoadEnvironment(Environment* env) {
HandleScope handle_scope(env->isolate()); HandleScope handle_scope(env->isolate());
TryCatchScope try_catch(env);
// Disable verbose mode to stop FatalException() handler from trying
// to handle the exception. Errors this early in the start-up phase
// are not safe to ignore.
try_catch.SetVerbose(false);
// The bootstrapper scripts are lib/internal/bootstrap/loaders.js and
// lib/internal/bootstrap/node.js, each included as a static C string
// generated in node_javascript.cc by node_js2c.
// TODO(joyeecheung): use NativeModuleLoader::Compile
// We duplicate the string literals here since once we refactor the bootstrap
// compilation out to NativeModuleLoader none of this is going to matter
Isolate* isolate = env->isolate(); Isolate* isolate = env->isolate();
Local<String> loaders_name = Local<Context> context = env->context();
FIXED_ONE_BYTE_STRING(isolate, "internal/bootstrap/loaders.js");
Local<String> loaders_source =
per_process_loader.GetSource(isolate, "internal/bootstrap/loaders");
MaybeLocal<Function> loaders_bootstrapper =
GetBootstrapper(env, loaders_source, loaders_name);
Local<String> node_name =
FIXED_ONE_BYTE_STRING(isolate, "internal/bootstrap/node.js");
Local<String> node_source =
per_process_loader.GetSource(isolate, "internal/bootstrap/node");
MaybeLocal<Function> node_bootstrapper =
GetBootstrapper(env, node_source, node_name);
if (loaders_bootstrapper.IsEmpty() || node_bootstrapper.IsEmpty()) {
// Execution was interrupted.
return;
}
// Add a reference to the global object // Add a reference to the global object
Local<Object> global = env->context()->Global(); Local<Object> global = context->Global();
#if defined HAVE_DTRACE || defined HAVE_ETW #if defined HAVE_DTRACE || defined HAVE_ETW
InitDTrace(env, global); InitDTrace(env, global);
#endif #endif
// Enable handling of uncaught exceptions Local<Object> process = env->process_object();
// (FatalException(), break on uncaught exception in debugger)
//
// This is not strictly necessary since it's almost impossible
// to attach the debugger fast enough to break on exception
// thrown during process startup.
try_catch.SetVerbose(true);
env->SetMethod(env->process_object(), "_rawDebug", RawDebug);
// Setting global properties for the bootstrappers to use:
// - global
// - process._rawDebug
// Expose the global object as a property on itself // Expose the global object as a property on itself
// (Allows you to set stuff on `global` from anywhere in JavaScript.) // (Allows you to set stuff on `global` from anywhere in JavaScript.)
global->Set(env->context(), global->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global)
FIXED_ONE_BYTE_STRING(env->isolate(), "global"), .FromJust();
global).FromJust(); env->SetMethod(process, "_rawDebug", RawDebug);
// Create binding loaders // Create binding loaders
Local<Function> get_binding_fn = env->NewFunctionTemplate(binding::GetBinding) std::vector<Local<String>> loaders_params = {
->GetFunction(env->context()) env->process_string(),
.ToLocalChecked(); FIXED_ONE_BYTE_STRING(isolate, "getBinding"),
FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
Local<Function> get_linked_binding_fn = FIXED_ONE_BYTE_STRING(isolate, "getInternalBinding"),
FIXED_ONE_BYTE_STRING(isolate, "debugBreak")};
std::vector<Local<Value>> loaders_args = {
process,
env->NewFunctionTemplate(binding::GetBinding)
->GetFunction(context)
.ToLocalChecked(),
env->NewFunctionTemplate(binding::GetLinkedBinding) env->NewFunctionTemplate(binding::GetLinkedBinding)
->GetFunction(env->context()) ->GetFunction(context)
.ToLocalChecked(); .ToLocalChecked(),
Local<Function> get_internal_binding_fn =
env->NewFunctionTemplate(binding::GetInternalBinding) env->NewFunctionTemplate(binding::GetInternalBinding)
->GetFunction(env->context()) ->GetFunction(context)
.ToLocalChecked(); .ToLocalChecked(),
Boolean::New(isolate,
Local<Value> loaders_bootstrapper_args[] = { env->options()->debug_options->break_node_first_line)};
env->process_object(),
get_binding_fn,
get_linked_binding_fn,
get_internal_binding_fn,
Boolean::New(env->isolate(),
env->options()->debug_options->break_node_first_line)
};
MaybeLocal<Value> loader_exports;
// Bootstrap internal loaders // Bootstrap internal loaders
Local<Value> bootstrapped_loaders; loader_exports = ExecuteBootstrapper(
if (!ExecuteBootstrapper(env, loaders_bootstrapper.ToLocalChecked(), env, "internal/bootstrap/loaders", &loaders_params, &loaders_args);
arraysize(loaders_bootstrapper_args), if (loader_exports.IsEmpty()) {
loaders_bootstrapper_args,
&bootstrapped_loaders)) {
return; return;
} }
Local<Function> trigger_fatal_exception =
env->NewFunctionTemplate(FatalException)->GetFunction(env->context())
.ToLocalChecked();
// Bootstrap Node.js // Bootstrap Node.js
Local<Object> bootstrapper = Object::New(env->isolate()); Local<Object> bootstrapper = Object::New(env->isolate());
SetupBootstrapObject(env, bootstrapper); SetupBootstrapObject(env, bootstrapper);
Local<Value> bootstrapped_node;
Local<Value> node_bootstrapper_args[] = { // process, bootstrappers, loaderExports, triggerFatalException
env->process_object(), std::vector<Local<String>> node_params = {
env->process_string(),
FIXED_ONE_BYTE_STRING(isolate, "bootstrappers"),
FIXED_ONE_BYTE_STRING(isolate, "loaderExports"),
FIXED_ONE_BYTE_STRING(isolate, "triggerFatalException")};
std::vector<Local<Value>> node_args = {
process,
bootstrapper, bootstrapper,
bootstrapped_loaders, loader_exports.ToLocalChecked(),
trigger_fatal_exception, env->NewFunctionTemplate(FatalException)
}; ->GetFunction(context)
if (!ExecuteBootstrapper(env, node_bootstrapper.ToLocalChecked(), .ToLocalChecked()};
arraysize(node_bootstrapper_args),
node_bootstrapper_args, if (ExecuteBootstrapper(
&bootstrapped_node)) { env, "internal/bootstrap/node", &node_params, &node_args)
.IsEmpty()) {
return; return;
} }
} }

View File

@ -12,7 +12,7 @@ SyntaxError: Strict mode code may not include a with statement
at executeUserCode (internal/bootstrap/node.js:*:*) at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) at internal/bootstrap/node.js:*:*
42 42
42 42
[eval]:1 [eval]:1
@ -29,7 +29,7 @@ Error: hello
at executeUserCode (internal/bootstrap/node.js:*:*) at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) at internal/bootstrap/node.js:*:*
[eval]:1 [eval]:1
throw new Error("hello") throw new Error("hello")
@ -45,7 +45,7 @@ Error: hello
at executeUserCode (internal/bootstrap/node.js:*:*) at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) at internal/bootstrap/node.js:*:*
100 100
[eval]:1 [eval]:1
var x = 100; y = x; var x = 100; y = x;
@ -61,7 +61,7 @@ ReferenceError: y is not defined
at executeUserCode (internal/bootstrap/node.js:*:*) at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) at internal/bootstrap/node.js:*:*
[eval]:1 [eval]:1
var ______________________________________________; throw 10 var ______________________________________________; throw 10

View File

@ -21,4 +21,4 @@ Emitted 'error' event at:
at executeUserCode (internal/bootstrap/node.js:*:*) at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) at internal/bootstrap/node.js:*:*

View File

@ -10,4 +10,4 @@ ReferenceError: undefined_reference_error_maker is not defined
at executeUserCode (internal/bootstrap/node.js:*:*) at executeUserCode (internal/bootstrap/node.js:*:*)
at startExecution (internal/bootstrap/node.js:*:*) at startExecution (internal/bootstrap/node.js:*:*)
at startup (internal/bootstrap/node.js:*:*) at startup (internal/bootstrap/node.js:*:*)
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*) at internal/bootstrap/node.js:*:*