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:
parent
fa19ce9233
commit
edcb950090
@ -39,335 +39,336 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
(function bootstrapInternalLoaders(process, getBinding, getLinkedBinding,
|
||||
getInternalBinding, debugBreak) {
|
||||
if (debugBreak)
|
||||
debugger; // eslint-disable-line no-debugger
|
||||
// This file is compiled as if it's wrapped in a function with arguments
|
||||
// passed by node::LoadEnvironment()
|
||||
/* global process, getBinding, getLinkedBinding, getInternalBinding */
|
||||
/* global debugBreak */
|
||||
|
||||
const {
|
||||
apply: ReflectApply,
|
||||
deleteProperty: ReflectDeleteProperty,
|
||||
get: ReflectGet,
|
||||
getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor,
|
||||
has: ReflectHas,
|
||||
set: ReflectSet,
|
||||
} = Reflect;
|
||||
const {
|
||||
prototype: {
|
||||
hasOwnProperty: ObjectHasOwnProperty,
|
||||
if (debugBreak)
|
||||
debugger; // eslint-disable-line no-debugger
|
||||
|
||||
const {
|
||||
apply: ReflectApply,
|
||||
deleteProperty: ReflectDeleteProperty,
|
||||
get: ReflectGet,
|
||||
getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor,
|
||||
has: ReflectHas,
|
||||
set: ReflectSet,
|
||||
} = Reflect;
|
||||
const {
|
||||
prototype: {
|
||||
hasOwnProperty: ObjectHasOwnProperty,
|
||||
},
|
||||
create: ObjectCreate,
|
||||
defineProperty: ObjectDefineProperty,
|
||||
keys: ObjectKeys,
|
||||
} = Object;
|
||||
|
||||
// Set up process.moduleLoadList.
|
||||
const moduleLoadList = [];
|
||||
ObjectDefineProperty(process, 'moduleLoadList', {
|
||||
value: moduleLoadList,
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: false
|
||||
});
|
||||
|
||||
// internalBindingWhitelist contains the name of internalBinding modules
|
||||
// that are whitelisted for access via process.binding()... This is used
|
||||
// to provide a transition path for modules that are being moved over to
|
||||
// internalBinding.
|
||||
const internalBindingWhitelist = [
|
||||
'async_wrap',
|
||||
'buffer',
|
||||
'cares_wrap',
|
||||
'constants',
|
||||
'contextify',
|
||||
'crypto',
|
||||
'fs',
|
||||
'fs_event_wrap',
|
||||
'http_parser',
|
||||
'icu',
|
||||
'js_stream',
|
||||
'natives',
|
||||
'pipe_wrap',
|
||||
'process_wrap',
|
||||
'signal_wrap',
|
||||
'spawn_sync',
|
||||
'stream_wrap',
|
||||
'tcp_wrap',
|
||||
'tls_wrap',
|
||||
'tty_wrap',
|
||||
'udp_wrap',
|
||||
'url',
|
||||
'util',
|
||||
'uv',
|
||||
'v8',
|
||||
'zlib'
|
||||
];
|
||||
// We will use a lazy loaded SafeSet in internalBindingWhitelistHas
|
||||
// for checking existence in this list.
|
||||
let internalBindingWhitelistSet;
|
||||
|
||||
// Set up process.binding() and process._linkedBinding().
|
||||
{
|
||||
const bindingObj = ObjectCreate(null);
|
||||
|
||||
process.binding = function binding(module) {
|
||||
module = String(module);
|
||||
// Deprecated specific process.binding() modules, but not all, allow
|
||||
// selective fallback to internalBinding for the deprecated ones.
|
||||
if (internalBindingWhitelistHas(module)) {
|
||||
return internalBinding(module);
|
||||
}
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object') {
|
||||
mod = bindingObj[module] = getBinding(module);
|
||||
moduleLoadList.push(`Binding ${module}`);
|
||||
}
|
||||
return mod;
|
||||
};
|
||||
|
||||
process._linkedBinding = function _linkedBinding(module) {
|
||||
module = String(module);
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object')
|
||||
mod = bindingObj[module] = getLinkedBinding(module);
|
||||
return mod;
|
||||
};
|
||||
}
|
||||
|
||||
// Set up internalBinding() in the closure.
|
||||
let internalBinding;
|
||||
{
|
||||
const bindingObj = ObjectCreate(null);
|
||||
internalBinding = function internalBinding(module) {
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object') {
|
||||
mod = bindingObj[module] = getInternalBinding(module);
|
||||
moduleLoadList.push(`Internal Binding ${module}`);
|
||||
}
|
||||
return mod;
|
||||
};
|
||||
}
|
||||
|
||||
// Create this WeakMap in js-land because V8 has no C++ API for WeakMap.
|
||||
internalBinding('module_wrap').callbackMap = new WeakMap();
|
||||
|
||||
// Set up NativeModule.
|
||||
function NativeModule(id) {
|
||||
this.filename = `${id}.js`;
|
||||
this.id = id;
|
||||
this.exports = {};
|
||||
this.reflect = undefined;
|
||||
this.exportKeys = undefined;
|
||||
this.loaded = false;
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
NativeModule._source = getInternalBinding('natives');
|
||||
NativeModule._cache = {};
|
||||
|
||||
const config = getBinding('config');
|
||||
|
||||
// Think of this as module.exports in this file even though it is not
|
||||
// written in CommonJS style.
|
||||
const loaderExports = { internalBinding, NativeModule };
|
||||
const loaderId = 'internal/bootstrap/loaders';
|
||||
|
||||
NativeModule.require = function(id) {
|
||||
if (id === loaderId) {
|
||||
return loaderExports;
|
||||
}
|
||||
|
||||
const cached = NativeModule.getCached(id);
|
||||
if (cached && (cached.loaded || cached.loading)) {
|
||||
return cached.exports;
|
||||
}
|
||||
|
||||
if (!NativeModule.exists(id)) {
|
||||
// Model the error off the internal/errors.js model, but
|
||||
// do not use that module given that it could actually be
|
||||
// the one causing the error if there's a bug in Node.js.
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
const err = new Error(`No such built-in module: ${id}`);
|
||||
err.code = 'ERR_UNKNOWN_BUILTIN_MODULE';
|
||||
err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]';
|
||||
throw err;
|
||||
}
|
||||
|
||||
moduleLoadList.push(`NativeModule ${id}`);
|
||||
|
||||
const nativeModule = new NativeModule(id);
|
||||
|
||||
nativeModule.cache();
|
||||
nativeModule.compile();
|
||||
|
||||
return nativeModule.exports;
|
||||
};
|
||||
|
||||
NativeModule.isDepsModule = function(id) {
|
||||
return id.startsWith('node-inspect/') || id.startsWith('v8/');
|
||||
};
|
||||
|
||||
NativeModule.requireForDeps = function(id) {
|
||||
if (!NativeModule.exists(id) ||
|
||||
// TODO(TimothyGu): remove when DEP0084 reaches end of life.
|
||||
NativeModule.isDepsModule(id)) {
|
||||
id = `internal/deps/${id}`;
|
||||
}
|
||||
return NativeModule.require(id);
|
||||
};
|
||||
|
||||
NativeModule.getCached = function(id) {
|
||||
return NativeModule._cache[id];
|
||||
};
|
||||
|
||||
NativeModule.exists = function(id) {
|
||||
return NativeModule._source.hasOwnProperty(id);
|
||||
};
|
||||
|
||||
if (config.exposeInternals) {
|
||||
NativeModule.nonInternalExists = function(id) {
|
||||
// Do not expose this to user land even with --expose-internals.
|
||||
if (id === loaderId) {
|
||||
return false;
|
||||
}
|
||||
return NativeModule.exists(id);
|
||||
};
|
||||
|
||||
NativeModule.isInternal = function(id) {
|
||||
// Do not expose this to user land even with --expose-internals.
|
||||
return id === loaderId;
|
||||
};
|
||||
} else {
|
||||
NativeModule.nonInternalExists = function(id) {
|
||||
return NativeModule.exists(id) && !NativeModule.isInternal(id);
|
||||
};
|
||||
|
||||
NativeModule.isInternal = function(id) {
|
||||
return id.startsWith('internal/') ||
|
||||
(id === 'worker_threads' && !config.experimentalWorker);
|
||||
};
|
||||
}
|
||||
|
||||
NativeModule.getSource = function(id) {
|
||||
return NativeModule._source[id];
|
||||
};
|
||||
|
||||
NativeModule.wrap = function(script) {
|
||||
return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
|
||||
};
|
||||
|
||||
NativeModule.wrapper = [
|
||||
'(function (exports, require, module, process, internalBinding) {',
|
||||
'\n});'
|
||||
];
|
||||
|
||||
const getOwn = (target, property, receiver) => {
|
||||
return ReflectApply(ObjectHasOwnProperty, target, [property]) ?
|
||||
ReflectGet(target, property, receiver) :
|
||||
undefined;
|
||||
};
|
||||
|
||||
// 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
|
||||
// as the entire namespace (module.exports) and wrapped in a proxy such
|
||||
// that APMs and other behavior are still left intact.
|
||||
NativeModule.prototype.proxifyExports = function() {
|
||||
this.exportKeys = ObjectKeys(this.exports);
|
||||
|
||||
const update = (property, value) => {
|
||||
if (this.reflect !== undefined &&
|
||||
ReflectApply(ObjectHasOwnProperty,
|
||||
this.reflect.exports, [property]))
|
||||
this.reflect.exports[property].set(value);
|
||||
};
|
||||
|
||||
const handler = {
|
||||
__proto__: null,
|
||||
defineProperty: (target, prop, descriptor) => {
|
||||
// Use `Object.defineProperty` instead of `Reflect.defineProperty`
|
||||
// to throw the appropriate error if something goes wrong.
|
||||
ObjectDefineProperty(target, prop, descriptor);
|
||||
if (typeof descriptor.get === 'function' &&
|
||||
!ReflectHas(handler, 'get')) {
|
||||
handler.get = (target, prop, receiver) => {
|
||||
const value = ReflectGet(target, prop, receiver);
|
||||
if (ReflectApply(ObjectHasOwnProperty, target, [prop]))
|
||||
update(prop, value);
|
||||
return value;
|
||||
};
|
||||
}
|
||||
update(prop, getOwn(target, prop));
|
||||
return true;
|
||||
},
|
||||
create: ObjectCreate,
|
||||
defineProperty: ObjectDefineProperty,
|
||||
keys: ObjectKeys,
|
||||
} = Object;
|
||||
|
||||
// Set up process.moduleLoadList.
|
||||
const moduleLoadList = [];
|
||||
ObjectDefineProperty(process, 'moduleLoadList', {
|
||||
value: moduleLoadList,
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: false
|
||||
});
|
||||
|
||||
// internalBindingWhitelist contains the name of internalBinding modules
|
||||
// that are whitelisted for access via process.binding()... This is used
|
||||
// to provide a transition path for modules that are being moved over to
|
||||
// internalBinding.
|
||||
const internalBindingWhitelist = [
|
||||
'async_wrap',
|
||||
'buffer',
|
||||
'cares_wrap',
|
||||
'constants',
|
||||
'contextify',
|
||||
'crypto',
|
||||
'fs',
|
||||
'fs_event_wrap',
|
||||
'http_parser',
|
||||
'icu',
|
||||
'js_stream',
|
||||
'natives',
|
||||
'pipe_wrap',
|
||||
'process_wrap',
|
||||
'signal_wrap',
|
||||
'spawn_sync',
|
||||
'stream_wrap',
|
||||
'tcp_wrap',
|
||||
'tls_wrap',
|
||||
'tty_wrap',
|
||||
'udp_wrap',
|
||||
'url',
|
||||
'util',
|
||||
'uv',
|
||||
'v8',
|
||||
'zlib'
|
||||
];
|
||||
// We will use a lazy loaded SafeSet in internalBindingWhitelistHas
|
||||
// for checking existence in this list.
|
||||
let internalBindingWhitelistSet;
|
||||
|
||||
// Set up process.binding() and process._linkedBinding().
|
||||
{
|
||||
const bindingObj = ObjectCreate(null);
|
||||
|
||||
process.binding = function binding(module) {
|
||||
module = String(module);
|
||||
// Deprecated specific process.binding() modules, but not all, allow
|
||||
// selective fallback to internalBinding for the deprecated ones.
|
||||
if (internalBindingWhitelistHas(module)) {
|
||||
return internalBinding(module);
|
||||
deleteProperty: (target, prop) => {
|
||||
if (ReflectDeleteProperty(target, prop)) {
|
||||
update(prop, undefined);
|
||||
return true;
|
||||
}
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object') {
|
||||
mod = bindingObj[module] = getBinding(module);
|
||||
moduleLoadList.push(`Binding ${module}`);
|
||||
return false;
|
||||
},
|
||||
set: (target, prop, value, receiver) => {
|
||||
const descriptor = ReflectGetOwnPropertyDescriptor(target, prop);
|
||||
if (ReflectSet(target, prop, value, receiver)) {
|
||||
if (descriptor && typeof descriptor.set === 'function') {
|
||||
for (const key of this.exportKeys) {
|
||||
update(key, getOwn(target, key, receiver));
|
||||
}
|
||||
} else {
|
||||
update(prop, getOwn(target, prop, receiver));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return mod;
|
||||
};
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
process._linkedBinding = function _linkedBinding(module) {
|
||||
module = String(module);
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object')
|
||||
mod = bindingObj[module] = getLinkedBinding(module);
|
||||
return mod;
|
||||
};
|
||||
}
|
||||
this.exports = new Proxy(this.exports, handler);
|
||||
};
|
||||
|
||||
// Set up internalBinding() in the closure.
|
||||
let internalBinding;
|
||||
{
|
||||
const bindingObj = ObjectCreate(null);
|
||||
internalBinding = function internalBinding(module) {
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object') {
|
||||
mod = bindingObj[module] = getInternalBinding(module);
|
||||
moduleLoadList.push(`Internal Binding ${module}`);
|
||||
}
|
||||
return mod;
|
||||
};
|
||||
}
|
||||
const { compileFunction } = getInternalBinding('native_module');
|
||||
NativeModule.prototype.compile = function() {
|
||||
const id = this.id;
|
||||
|
||||
// Create this WeakMap in js-land because V8 has no C++ API for WeakMap.
|
||||
internalBinding('module_wrap').callbackMap = new WeakMap();
|
||||
this.loading = true;
|
||||
|
||||
// Set up NativeModule.
|
||||
function NativeModule(id) {
|
||||
this.filename = `${id}.js`;
|
||||
this.id = id;
|
||||
this.exports = {};
|
||||
this.reflect = undefined;
|
||||
this.exportKeys = undefined;
|
||||
this.loaded = false;
|
||||
try {
|
||||
const requireFn = this.id.startsWith('internal/deps/') ?
|
||||
NativeModule.requireForDeps :
|
||||
NativeModule.require;
|
||||
|
||||
const fn = compileFunction(id);
|
||||
fn(this.exports, requireFn, this, process, internalBinding);
|
||||
|
||||
if (config.experimentalModules && !NativeModule.isInternal(this.id)) {
|
||||
this.proxifyExports();
|
||||
}
|
||||
|
||||
this.loaded = true;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
NativeModule._source = getInternalBinding('natives');
|
||||
NativeModule._cache = {};
|
||||
NativeModule.prototype.cache = function() {
|
||||
NativeModule._cache[this.id] = this;
|
||||
};
|
||||
|
||||
const config = getBinding('config');
|
||||
// Coverage must be turned on early, so that we can collect
|
||||
// it for Node.js' own internal libraries.
|
||||
if (process.env.NODE_V8_COVERAGE) {
|
||||
NativeModule.require('internal/process/coverage').setup();
|
||||
}
|
||||
|
||||
// Think of this as module.exports in this file even though it is not
|
||||
// written in CommonJS style.
|
||||
const loaderExports = { internalBinding, NativeModule };
|
||||
const loaderId = 'internal/bootstrap/loaders';
|
||||
|
||||
NativeModule.require = function(id) {
|
||||
if (id === loaderId) {
|
||||
return loaderExports;
|
||||
}
|
||||
|
||||
const cached = NativeModule.getCached(id);
|
||||
if (cached && (cached.loaded || cached.loading)) {
|
||||
return cached.exports;
|
||||
}
|
||||
|
||||
if (!NativeModule.exists(id)) {
|
||||
// Model the error off the internal/errors.js model, but
|
||||
// do not use that module given that it could actually be
|
||||
// the one causing the error if there's a bug in Node.js.
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
const err = new Error(`No such built-in module: ${id}`);
|
||||
err.code = 'ERR_UNKNOWN_BUILTIN_MODULE';
|
||||
err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]';
|
||||
throw err;
|
||||
}
|
||||
|
||||
moduleLoadList.push(`NativeModule ${id}`);
|
||||
|
||||
const nativeModule = new NativeModule(id);
|
||||
|
||||
nativeModule.cache();
|
||||
nativeModule.compile();
|
||||
|
||||
return nativeModule.exports;
|
||||
};
|
||||
|
||||
NativeModule.isDepsModule = function(id) {
|
||||
return id.startsWith('node-inspect/') || id.startsWith('v8/');
|
||||
};
|
||||
|
||||
NativeModule.requireForDeps = function(id) {
|
||||
if (!NativeModule.exists(id) ||
|
||||
// TODO(TimothyGu): remove when DEP0084 reaches end of life.
|
||||
NativeModule.isDepsModule(id)) {
|
||||
id = `internal/deps/${id}`;
|
||||
}
|
||||
return NativeModule.require(id);
|
||||
};
|
||||
|
||||
NativeModule.getCached = function(id) {
|
||||
return NativeModule._cache[id];
|
||||
};
|
||||
|
||||
NativeModule.exists = function(id) {
|
||||
return NativeModule._source.hasOwnProperty(id);
|
||||
};
|
||||
|
||||
if (config.exposeInternals) {
|
||||
NativeModule.nonInternalExists = function(id) {
|
||||
// Do not expose this to user land even with --expose-internals.
|
||||
if (id === loaderId) {
|
||||
return false;
|
||||
}
|
||||
return NativeModule.exists(id);
|
||||
};
|
||||
|
||||
NativeModule.isInternal = function(id) {
|
||||
// Do not expose this to user land even with --expose-internals.
|
||||
return id === loaderId;
|
||||
};
|
||||
} else {
|
||||
NativeModule.nonInternalExists = function(id) {
|
||||
return NativeModule.exists(id) && !NativeModule.isInternal(id);
|
||||
};
|
||||
|
||||
NativeModule.isInternal = function(id) {
|
||||
return id.startsWith('internal/') ||
|
||||
(id === 'worker_threads' && !config.experimentalWorker);
|
||||
};
|
||||
function internalBindingWhitelistHas(name) {
|
||||
if (!internalBindingWhitelistSet) {
|
||||
const { SafeSet } = NativeModule.require('internal/safe_globals');
|
||||
internalBindingWhitelistSet = new SafeSet(internalBindingWhitelist);
|
||||
}
|
||||
return internalBindingWhitelistSet.has(name);
|
||||
}
|
||||
|
||||
NativeModule.getSource = function(id) {
|
||||
return NativeModule._source[id];
|
||||
};
|
||||
|
||||
NativeModule.wrap = function(script) {
|
||||
return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
|
||||
};
|
||||
|
||||
NativeModule.wrapper = [
|
||||
'(function (exports, require, module, process, internalBinding) {',
|
||||
'\n});'
|
||||
];
|
||||
|
||||
const getOwn = (target, property, receiver) => {
|
||||
return ReflectApply(ObjectHasOwnProperty, target, [property]) ?
|
||||
ReflectGet(target, property, receiver) :
|
||||
undefined;
|
||||
};
|
||||
|
||||
// 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
|
||||
// as the entire namespace (module.exports) and wrapped in a proxy such
|
||||
// that APMs and other behavior are still left intact.
|
||||
NativeModule.prototype.proxifyExports = function() {
|
||||
this.exportKeys = ObjectKeys(this.exports);
|
||||
|
||||
const update = (property, value) => {
|
||||
if (this.reflect !== undefined &&
|
||||
ReflectApply(ObjectHasOwnProperty,
|
||||
this.reflect.exports, [property]))
|
||||
this.reflect.exports[property].set(value);
|
||||
};
|
||||
|
||||
const handler = {
|
||||
__proto__: null,
|
||||
defineProperty: (target, prop, descriptor) => {
|
||||
// Use `Object.defineProperty` instead of `Reflect.defineProperty`
|
||||
// to throw the appropriate error if something goes wrong.
|
||||
ObjectDefineProperty(target, prop, descriptor);
|
||||
if (typeof descriptor.get === 'function' &&
|
||||
!ReflectHas(handler, 'get')) {
|
||||
handler.get = (target, prop, receiver) => {
|
||||
const value = ReflectGet(target, prop, receiver);
|
||||
if (ReflectApply(ObjectHasOwnProperty, target, [prop]))
|
||||
update(prop, value);
|
||||
return value;
|
||||
};
|
||||
}
|
||||
update(prop, getOwn(target, prop));
|
||||
return true;
|
||||
},
|
||||
deleteProperty: (target, prop) => {
|
||||
if (ReflectDeleteProperty(target, prop)) {
|
||||
update(prop, undefined);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
set: (target, prop, value, receiver) => {
|
||||
const descriptor = ReflectGetOwnPropertyDescriptor(target, prop);
|
||||
if (ReflectSet(target, prop, value, receiver)) {
|
||||
if (descriptor && typeof descriptor.set === 'function') {
|
||||
for (const key of this.exportKeys) {
|
||||
update(key, getOwn(target, key, receiver));
|
||||
}
|
||||
} else {
|
||||
update(prop, getOwn(target, prop, receiver));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
this.exports = new Proxy(this.exports, handler);
|
||||
};
|
||||
|
||||
const { compileFunction } = getInternalBinding('native_module');
|
||||
NativeModule.prototype.compile = function() {
|
||||
const id = this.id;
|
||||
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
const requireFn = this.id.startsWith('internal/deps/') ?
|
||||
NativeModule.requireForDeps :
|
||||
NativeModule.require;
|
||||
|
||||
const fn = compileFunction(id);
|
||||
fn(this.exports, requireFn, this, process, internalBinding);
|
||||
|
||||
if (config.experimentalModules && !NativeModule.isInternal(this.id)) {
|
||||
this.proxifyExports();
|
||||
}
|
||||
|
||||
this.loaded = true;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
NativeModule.prototype.cache = function() {
|
||||
NativeModule._cache[this.id] = this;
|
||||
};
|
||||
|
||||
// Coverage must be turned on early, so that we can collect
|
||||
// it for Node.js' own internal libraries.
|
||||
if (process.env.NODE_V8_COVERAGE) {
|
||||
NativeModule.require('internal/process/coverage').setup();
|
||||
}
|
||||
|
||||
function internalBindingWhitelistHas(name) {
|
||||
if (!internalBindingWhitelistSet) {
|
||||
const { SafeSet } = NativeModule.require('internal/safe_globals');
|
||||
internalBindingWhitelistSet = new SafeSet(internalBindingWhitelist);
|
||||
}
|
||||
return internalBindingWhitelistSet.has(name);
|
||||
}
|
||||
|
||||
// This will be passed to the bootstrapNodeJSCore function in
|
||||
// bootstrap/node.js.
|
||||
return loaderExports;
|
||||
});
|
||||
// This will be passed to internal/bootstrap/node.js.
|
||||
return loaderExports;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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';
|
||||
|
||||
// node::NewContext calls this script
|
||||
|
||||
// https://github.com/nodejs/node/issues/14909
|
||||
if (global.Intl) delete global.Intl.v8BreakIterator;
|
||||
|
||||
|
210
src/node.cc
210
src/node.cc
@ -116,7 +116,6 @@ typedef int mode_t;
|
||||
|
||||
namespace node {
|
||||
|
||||
using errors::TryCatchScope;
|
||||
using native_module::NativeModuleLoader;
|
||||
using options_parser::kAllowedInEnvironment;
|
||||
using options_parser::kDisallowedInEnvironment;
|
||||
@ -144,7 +143,6 @@ using v8::NamedPropertyHandlerConfiguration;
|
||||
using v8::NewStringType;
|
||||
using v8::None;
|
||||
using v8::Nothing;
|
||||
using v8::Null;
|
||||
using v8::Object;
|
||||
using v8::ObjectTemplate;
|
||||
using v8::PropertyAttribute;
|
||||
@ -741,41 +739,6 @@ Local<Value> MakeCallback(Isolate* isolate,
|
||||
.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) {
|
||||
#if HAVE_INSPECTOR
|
||||
if (env->inspector_agent()->IsActive()) {
|
||||
@ -1334,39 +1297,13 @@ void SignalExit(int signo) {
|
||||
raise(signo);
|
||||
}
|
||||
|
||||
|
||||
static MaybeLocal<Function> GetBootstrapper(
|
||||
static MaybeLocal<Value> ExecuteBootstrapper(
|
||||
Environment* env,
|
||||
Local<String> source,
|
||||
Local<String> script_name) {
|
||||
EscapableHandleScope 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);
|
||||
|
||||
// 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);
|
||||
const char* id,
|
||||
std::vector<Local<String>>* parameters,
|
||||
std::vector<Local<Value>>* arguments) {
|
||||
MaybeLocal<Value> ret = per_process_loader.CompileAndCall(
|
||||
env->context(), id, parameters, arguments, env);
|
||||
|
||||
// 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
|
||||
@ -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
|
||||
// called MakeCallback or 2) user awaited during bootstrap, which triggered
|
||||
// _tickCallback().
|
||||
if (!ret) {
|
||||
if (ret.IsEmpty()) {
|
||||
env->async_hooks()->clear_async_id_stack();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void LoadEnvironment(Environment* env) {
|
||||
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();
|
||||
Local<String> loaders_name =
|
||||
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;
|
||||
}
|
||||
Local<Context> context = env->context();
|
||||
|
||||
// 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
|
||||
InitDTrace(env, global);
|
||||
#endif
|
||||
|
||||
// Enable handling of uncaught exceptions
|
||||
// (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);
|
||||
Local<Object> process = env->process_object();
|
||||
|
||||
// Setting global properties for the bootstrappers to use:
|
||||
// - global
|
||||
// - process._rawDebug
|
||||
// Expose the global object as a property on itself
|
||||
// (Allows you to set stuff on `global` from anywhere in JavaScript.)
|
||||
global->Set(env->context(),
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "global"),
|
||||
global).FromJust();
|
||||
global->Set(context, FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global)
|
||||
.FromJust();
|
||||
env->SetMethod(process, "_rawDebug", RawDebug);
|
||||
|
||||
// Create binding loaders
|
||||
Local<Function> get_binding_fn = env->NewFunctionTemplate(binding::GetBinding)
|
||||
->GetFunction(env->context())
|
||||
.ToLocalChecked();
|
||||
|
||||
Local<Function> get_linked_binding_fn =
|
||||
std::vector<Local<String>> loaders_params = {
|
||||
env->process_string(),
|
||||
FIXED_ONE_BYTE_STRING(isolate, "getBinding"),
|
||||
FIXED_ONE_BYTE_STRING(isolate, "getLinkedBinding"),
|
||||
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)
|
||||
->GetFunction(env->context())
|
||||
.ToLocalChecked();
|
||||
|
||||
Local<Function> get_internal_binding_fn =
|
||||
->GetFunction(context)
|
||||
.ToLocalChecked(),
|
||||
env->NewFunctionTemplate(binding::GetInternalBinding)
|
||||
->GetFunction(env->context())
|
||||
.ToLocalChecked();
|
||||
|
||||
Local<Value> loaders_bootstrapper_args[] = {
|
||||
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)
|
||||
};
|
||||
->GetFunction(context)
|
||||
.ToLocalChecked(),
|
||||
Boolean::New(isolate,
|
||||
env->options()->debug_options->break_node_first_line)};
|
||||
|
||||
MaybeLocal<Value> loader_exports;
|
||||
// Bootstrap internal loaders
|
||||
Local<Value> bootstrapped_loaders;
|
||||
if (!ExecuteBootstrapper(env, loaders_bootstrapper.ToLocalChecked(),
|
||||
arraysize(loaders_bootstrapper_args),
|
||||
loaders_bootstrapper_args,
|
||||
&bootstrapped_loaders)) {
|
||||
loader_exports = ExecuteBootstrapper(
|
||||
env, "internal/bootstrap/loaders", &loaders_params, &loaders_args);
|
||||
if (loader_exports.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Local<Function> trigger_fatal_exception =
|
||||
env->NewFunctionTemplate(FatalException)->GetFunction(env->context())
|
||||
.ToLocalChecked();
|
||||
|
||||
// Bootstrap Node.js
|
||||
Local<Object> bootstrapper = Object::New(env->isolate());
|
||||
SetupBootstrapObject(env, bootstrapper);
|
||||
Local<Value> bootstrapped_node;
|
||||
Local<Value> node_bootstrapper_args[] = {
|
||||
env->process_object(),
|
||||
bootstrapper,
|
||||
bootstrapped_loaders,
|
||||
trigger_fatal_exception,
|
||||
};
|
||||
if (!ExecuteBootstrapper(env, node_bootstrapper.ToLocalChecked(),
|
||||
arraysize(node_bootstrapper_args),
|
||||
node_bootstrapper_args,
|
||||
&bootstrapped_node)) {
|
||||
|
||||
// process, bootstrappers, loaderExports, triggerFatalException
|
||||
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,
|
||||
loader_exports.ToLocalChecked(),
|
||||
env->NewFunctionTemplate(FatalException)
|
||||
->GetFunction(context)
|
||||
.ToLocalChecked()};
|
||||
|
||||
if (ExecuteBootstrapper(
|
||||
env, "internal/bootstrap/node", &node_params, &node_args)
|
||||
.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ SyntaxError: Strict mode code may not include a with statement
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startExecution (internal/bootstrap/node.js:*:*)
|
||||
at startup (internal/bootstrap/node.js:*:*)
|
||||
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)
|
||||
at internal/bootstrap/node.js:*:*
|
||||
42
|
||||
42
|
||||
[eval]:1
|
||||
@ -29,7 +29,7 @@ Error: hello
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startExecution (internal/bootstrap/node.js:*:*)
|
||||
at startup (internal/bootstrap/node.js:*:*)
|
||||
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)
|
||||
at internal/bootstrap/node.js:*:*
|
||||
|
||||
[eval]:1
|
||||
throw new Error("hello")
|
||||
@ -45,7 +45,7 @@ Error: hello
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startExecution (internal/bootstrap/node.js:*:*)
|
||||
at startup (internal/bootstrap/node.js:*:*)
|
||||
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)
|
||||
at internal/bootstrap/node.js:*:*
|
||||
100
|
||||
[eval]:1
|
||||
var x = 100; y = x;
|
||||
@ -61,7 +61,7 @@ ReferenceError: y is not defined
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startExecution (internal/bootstrap/node.js:*:*)
|
||||
at startup (internal/bootstrap/node.js:*:*)
|
||||
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)
|
||||
at internal/bootstrap/node.js:*:*
|
||||
|
||||
[eval]:1
|
||||
var ______________________________________________; throw 10
|
||||
|
@ -21,4 +21,4 @@ Emitted 'error' event at:
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startExecution (internal/bootstrap/node.js:*:*)
|
||||
at startup (internal/bootstrap/node.js:*:*)
|
||||
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)
|
||||
at internal/bootstrap/node.js:*:*
|
||||
|
@ -10,4 +10,4 @@ ReferenceError: undefined_reference_error_maker is not defined
|
||||
at executeUserCode (internal/bootstrap/node.js:*:*)
|
||||
at startExecution (internal/bootstrap/node.js:*:*)
|
||||
at startup (internal/bootstrap/node.js:*:*)
|
||||
at bootstrapNodeJSCore (internal/bootstrap/node.js:*:*)
|
||||
at internal/bootstrap/node.js:*:*
|
||||
|
Loading…
x
Reference in New Issue
Block a user