src: move internal loaders out of bootstrap_node.js
- Moves the creation of `process.binding()`, `process._linkedBinding()` `internalBinding()` and `NativeModule` into a separate file `lib/internal/bootstrap_loaders.js`, and documents them there. This file will be compiled and run before `bootstrap_node.js`, which means we now bootstrap the internal module & binding system before actually bootstrapping Node.js. - Rename the special ID that can be used to require `NativeModule` as `internal/bootstrap_loaders` since it is setup there. Also put `internalBinding` in the object exported by `NativeModule.require` instead of putting it inside the `NativeModule.wrapper` - Use the original `getBinding()` to get the source code of native modules instead of getting it from `process.binding('native')` so that users cannot fake native modules by modifying the binding object. - Names the bootstrapping functions so their names show up in the stack trace. PR-URL: https://github.com/nodejs/node/pull/19112 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gus Caplan <me@gus.host>
This commit is contained in:
Родитель
1a5ec837ca
Коммит
2a9eb316a1
|
@ -244,7 +244,6 @@ module.exports = {
|
|||
DTRACE_HTTP_SERVER_REQUEST: false,
|
||||
DTRACE_HTTP_SERVER_RESPONSE: false,
|
||||
DTRACE_NET_SERVER_CONNECTION: false,
|
||||
DTRACE_NET_STREAM_END: false,
|
||||
internalBinding: false,
|
||||
DTRACE_NET_STREAM_END: false
|
||||
},
|
||||
};
|
||||
|
|
|
@ -36,7 +36,7 @@ const { openSync, closeSync, readSync } = require('fs');
|
|||
const { parseExpressionAt } = require('internal/deps/acorn/dist/acorn');
|
||||
const { inspect } = require('util');
|
||||
const { EOL } = require('os');
|
||||
const nativeModule = require('native_module');
|
||||
const { NativeModule } = require('internal/bootstrap_loaders');
|
||||
|
||||
// Escape control characters but not \n and \t to keep the line breaks and
|
||||
// indentation intact.
|
||||
|
@ -163,7 +163,7 @@ function getErrMessage(call) {
|
|||
}
|
||||
|
||||
// Skip Node.js modules!
|
||||
if (filename.endsWith('.js') && nativeModule.exists(filename.slice(0, -3))) {
|
||||
if (filename.endsWith('.js') && NativeModule.exists(filename.slice(0, -3))) {
|
||||
errorCache.set(identifier, undefined);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ const {
|
|||
// that test/parallel/test-buffer-bindingobj-no-zerofill.js is written.
|
||||
let isAnyArrayBuffer;
|
||||
try {
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
isAnyArrayBuffer = internalBinding('types').isAnyArrayBuffer;
|
||||
} catch (e) {
|
||||
isAnyArrayBuffer = require('util').types.isAnyArrayBuffer;
|
||||
|
|
|
@ -34,6 +34,7 @@ const {
|
|||
ERR_UNHANDLED_ERROR
|
||||
} = require('internal/errors').codes;
|
||||
const { createHook } = require('async_hooks');
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
|
||||
// overwrite process.domain with a getter/setter that will allow for more
|
||||
// effective optimizations
|
||||
|
|
|
@ -0,0 +1,229 @@
|
|||
// This file creates the internal module & binding loaders used by built-in
|
||||
// modules. In contrast, user land modules are loaded using
|
||||
// lib/module.js (CommonJS Modules) or lib/internal/loader/* (ES Modules).
|
||||
//
|
||||
// This file is compiled and run by node.cc before bootstrap_node.js
|
||||
// was called, therefore the loaders are bootstraped before we start to
|
||||
// actually bootstrap Node.js. It creates the following objects:
|
||||
//
|
||||
// C++ binding loaders:
|
||||
// - process.binding(): the legacy C++ binding loader, accessible from user land
|
||||
// because it is an object attached to the global process object.
|
||||
// These C++ bindings are created using NODE_BUILTIN_MODULE_CONTEXT_AWARE()
|
||||
// and have their nm_flags set to NM_F_BUILTIN. We do not make any guarantees
|
||||
// about the stability of these bindings, but still have to take care of
|
||||
// compatibility issues caused by them from time to time.
|
||||
// - process._linkedBinding(): intended to be used by embedders to add
|
||||
// additional C++ bindings in their applications. These C++ bindings
|
||||
// can be created using NODE_MODULE_CONTEXT_AWARE_CPP() with the flag
|
||||
// NM_F_LINKED.
|
||||
// - internalBinding(): the private internal C++ binding loader, inaccessible
|
||||
// from user land because they are only available from NativeModule.require()
|
||||
// These C++ bindings are created using NODE_MODULE_CONTEXT_AWARE_INTERNAL()
|
||||
// and have their nm_flags set to NM_F_INTERNAL.
|
||||
//
|
||||
// Internal JavaScript module loader:
|
||||
// - NativeModule: a minimal module system used to load the JavaScript core
|
||||
// modules found in lib/**/*.js and deps/**/*.js. All core modules are
|
||||
// compiled into the node binary via node_javascript.cc generated by js2c.py,
|
||||
// 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
|
||||
// CommonJS style.
|
||||
//
|
||||
// Other objects:
|
||||
// - process.moduleLoadList: an array recording the bindings and the modules
|
||||
// loaded in the process and the order in which they are loaded.
|
||||
|
||||
'use strict';
|
||||
|
||||
(function bootstrapInternalLoaders(process, getBinding, getLinkedBinding,
|
||||
getInternalBinding) {
|
||||
|
||||
// Set up process.moduleLoadList
|
||||
const moduleLoadList = [];
|
||||
Object.defineProperty(process, 'moduleLoadList', {
|
||||
value: moduleLoadList,
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: false
|
||||
});
|
||||
|
||||
// Set up process.binding() and process._linkedBinding()
|
||||
{
|
||||
const bindingObj = Object.create(null);
|
||||
|
||||
process.binding = function binding(module) {
|
||||
module = String(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 = Object.create(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;
|
||||
};
|
||||
}
|
||||
|
||||
// Minimal sandbox helper
|
||||
const ContextifyScript = process.binding('contextify').ContextifyScript;
|
||||
function runInThisContext(code, options) {
|
||||
const script = new ContextifyScript(code, options);
|
||||
return script.runInThisContext();
|
||||
}
|
||||
|
||||
// Set up NativeModule
|
||||
function NativeModule(id) {
|
||||
this.filename = `${id}.js`;
|
||||
this.id = id;
|
||||
this.exports = {};
|
||||
this.loaded = false;
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
NativeModule._source = getBinding('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
|
||||
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.requireForDeps = function(id) {
|
||||
if (!NativeModule.exists(id) ||
|
||||
// TODO(TimothyGu): remove when DEP0084 reaches end of life.
|
||||
id.startsWith('node-inspect/') ||
|
||||
id.startsWith('v8/')) {
|
||||
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/');
|
||||
};
|
||||
}
|
||||
|
||||
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) {',
|
||||
'\n});'
|
||||
];
|
||||
|
||||
NativeModule.prototype.compile = function() {
|
||||
let source = NativeModule.getSource(this.id);
|
||||
source = NativeModule.wrap(source);
|
||||
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
const fn = runInThisContext(source, {
|
||||
filename: this.filename,
|
||||
lineOffset: 0,
|
||||
displayErrors: true
|
||||
});
|
||||
const requireFn = this.id.startsWith('internal/deps/') ?
|
||||
NativeModule.requireForDeps :
|
||||
NativeModule.require;
|
||||
fn(this.exports, requireFn, this, process);
|
||||
|
||||
this.loaded = true;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
NativeModule.prototype.cache = function() {
|
||||
NativeModule._cache[this.id] = this;
|
||||
};
|
||||
|
||||
// This will be passed to the bootstrapNodeJSCore function in
|
||||
// bootstrap_node.js.
|
||||
return loaderExports;
|
||||
});
|
|
@ -4,11 +4,16 @@
|
|||
// responsible for bootstrapping the node.js core. As special caution is given
|
||||
// to the performance of the startup process, many dependencies are invoked
|
||||
// lazily.
|
||||
//
|
||||
// Before this file is run, lib/internal/bootstrap_loaders.js gets run first
|
||||
// to bootstrap the internal binding and module loaders, including
|
||||
// process.binding(), process._linkedBinding(), internalBinding() and
|
||||
// NativeModule. And then { internalBinding, NativeModule } will be passed
|
||||
// into this bootstrapper to bootstrap Node.js core.
|
||||
|
||||
'use strict';
|
||||
|
||||
(function(process) {
|
||||
let internalBinding;
|
||||
(function bootstrapNodeJSCore(process, { internalBinding, NativeModule }) {
|
||||
const exceptionHandlerState = { captureFn: null };
|
||||
|
||||
function startup() {
|
||||
|
@ -270,54 +275,6 @@
|
|||
perf.markMilestone(NODE_PERFORMANCE_MILESTONE_BOOTSTRAP_COMPLETE);
|
||||
}
|
||||
|
||||
const moduleLoadList = [];
|
||||
Object.defineProperty(process, 'moduleLoadList', {
|
||||
value: moduleLoadList,
|
||||
configurable: true,
|
||||
enumerable: true,
|
||||
writable: false
|
||||
});
|
||||
|
||||
{
|
||||
const bindingObj = Object.create(null);
|
||||
|
||||
const getBinding = process.binding;
|
||||
process.binding = function binding(module) {
|
||||
module = String(module);
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object') {
|
||||
mod = bindingObj[module] = getBinding(module);
|
||||
moduleLoadList.push(`Binding ${module}`);
|
||||
}
|
||||
return mod;
|
||||
};
|
||||
|
||||
const getLinkedBinding = process._linkedBinding;
|
||||
process._linkedBinding = function _linkedBinding(module) {
|
||||
module = String(module);
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object')
|
||||
mod = bindingObj[module] = getLinkedBinding(module);
|
||||
return mod;
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
const bindingObj = Object.create(null);
|
||||
|
||||
const getInternalBinding = process._internalBinding;
|
||||
delete process._internalBinding;
|
||||
|
||||
internalBinding = function internalBinding(module) {
|
||||
let mod = bindingObj[module];
|
||||
if (typeof mod !== 'object') {
|
||||
mod = bindingObj[module] = getInternalBinding(module);
|
||||
moduleLoadList.push(`Internal Binding ${module}`);
|
||||
}
|
||||
return mod;
|
||||
};
|
||||
}
|
||||
|
||||
function setupProcessObject() {
|
||||
process._setupProcessObject(pushValueToArray);
|
||||
|
||||
|
@ -602,133 +559,5 @@
|
|||
new vm.Script(source, { displayErrors: true, filename });
|
||||
}
|
||||
|
||||
// Below you find a minimal module system, which is used to load the node
|
||||
// core modules found in lib/*.js. All core modules are compiled into the
|
||||
// node binary, so they can be loaded faster.
|
||||
|
||||
const ContextifyScript = process.binding('contextify').ContextifyScript;
|
||||
function runInThisContext(code, options) {
|
||||
const script = new ContextifyScript(code, options);
|
||||
return script.runInThisContext();
|
||||
}
|
||||
|
||||
function NativeModule(id) {
|
||||
this.filename = `${id}.js`;
|
||||
this.id = id;
|
||||
this.exports = {};
|
||||
this.loaded = false;
|
||||
this.loading = false;
|
||||
}
|
||||
|
||||
NativeModule._source = process.binding('natives');
|
||||
NativeModule._cache = {};
|
||||
|
||||
const config = process.binding('config');
|
||||
|
||||
NativeModule.require = function(id) {
|
||||
if (id === 'native_module') {
|
||||
return NativeModule;
|
||||
}
|
||||
|
||||
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
|
||||
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.requireForDeps = function(id) {
|
||||
if (!NativeModule.exists(id) ||
|
||||
// TODO(TimothyGu): remove when DEP0084 reaches end of life.
|
||||
id.startsWith('node-inspect/') ||
|
||||
id.startsWith('v8/')) {
|
||||
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 = NativeModule.exists;
|
||||
|
||||
NativeModule.isInternal = function(id) {
|
||||
return false;
|
||||
};
|
||||
} else {
|
||||
NativeModule.nonInternalExists = function(id) {
|
||||
return NativeModule.exists(id) && !NativeModule.isInternal(id);
|
||||
};
|
||||
|
||||
NativeModule.isInternal = function(id) {
|
||||
return id.startsWith('internal/');
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
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, internalBinding, process) {',
|
||||
'\n});'
|
||||
];
|
||||
|
||||
NativeModule.prototype.compile = function() {
|
||||
let source = NativeModule.getSource(this.id);
|
||||
source = NativeModule.wrap(source);
|
||||
|
||||
this.loading = true;
|
||||
|
||||
try {
|
||||
const fn = runInThisContext(source, {
|
||||
filename: this.filename,
|
||||
lineOffset: 0,
|
||||
displayErrors: true
|
||||
});
|
||||
const requireFn = this.id.startsWith('internal/deps/') ?
|
||||
NativeModule.requireForDeps :
|
||||
NativeModule.require;
|
||||
fn(this.exports, requireFn, this, internalBinding, process);
|
||||
|
||||
this.loaded = true;
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
};
|
||||
|
||||
NativeModule.prototype.cache = function() {
|
||||
NativeModule._cache[this.id] = this;
|
||||
};
|
||||
|
||||
startup();
|
||||
});
|
||||
|
|
|
@ -17,6 +17,7 @@ const {
|
|||
|
||||
const { isArrayBufferView } = require('internal/util/types');
|
||||
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
const {
|
||||
isArrayBuffer
|
||||
} = internalBinding('types');
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
const { ModuleWrap } = internalBinding('module_wrap');
|
||||
const debug = require('util').debuglog('esm');
|
||||
const ArrayJoin = Function.call.bind(Array.prototype.join);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
const { URL } = require('url');
|
||||
const CJSmodule = require('module');
|
||||
const internalFS = require('internal/fs');
|
||||
const NativeModule = require('native_module');
|
||||
const { NativeModule, internalBinding } = require('internal/bootstrap_loaders');
|
||||
const { extname } = require('path');
|
||||
const { realpathSync } = require('fs');
|
||||
const preserveSymlinks = !!process.binding('config').preserveSymlinks;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
const { ModuleWrap } = internalBinding('module_wrap');
|
||||
const { SafeSet, SafePromise } = require('internal/safe_globals');
|
||||
const { decorateErrorStack } = require('internal/util');
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const { NativeModule, internalBinding } = require('internal/bootstrap_loaders');
|
||||
const { ModuleWrap } = internalBinding('module_wrap');
|
||||
const NativeModule = require('native_module');
|
||||
const internalCJSModule = require('internal/module');
|
||||
const CJSModule = require('module');
|
||||
const internalURLModule = require('internal/url');
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
const {
|
||||
setImportModuleDynamicallyCallback,
|
||||
setInitializeImportMetaObjectCallback
|
||||
|
|
|
@ -8,6 +8,7 @@ process.emitWarning(
|
|||
// These exports should be scoped as specifically as possible
|
||||
// to avoid exposing APIs because even with that warning and
|
||||
// this file being internal people will still try to abuse it.
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
module.exports = {
|
||||
ModuleWrap: internalBinding('module_wrap').ModuleWrap,
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
const { compare } = process.binding('buffer');
|
||||
const { isArrayBufferView } = require('internal/util/types');
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
const { isDate, isMap, isRegExp, isSet } = internalBinding('types');
|
||||
|
||||
function objectToString(o) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
const { emitExperimentalWarning } = require('internal/util');
|
||||
const { URL } = require('internal/url');
|
||||
const { kParsingContext, isContext } = process.binding('contextify');
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
const NativeModule = require('native_module');
|
||||
const { NativeModule } = require('internal/bootstrap_loaders');
|
||||
const util = require('util');
|
||||
const { decorateErrorStack } = require('internal/util');
|
||||
const { getURLFromFilePath } = require('internal/url');
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
'use strict';
|
||||
|
||||
const { Buffer } = require('buffer');
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
const {
|
||||
kIncompleteCharactersStart,
|
||||
kIncompleteCharactersEnd,
|
||||
|
|
|
@ -39,6 +39,7 @@ const {
|
|||
kRejected,
|
||||
} = process.binding('util');
|
||||
|
||||
const { internalBinding } = require('internal/bootstrap_loaders');
|
||||
const types = internalBinding('types');
|
||||
Object.assign(types, require('internal/util/types'));
|
||||
const {
|
||||
|
|
1
node.gyp
1
node.gyp
|
@ -24,6 +24,7 @@
|
|||
'node_lib_target_name%': 'node_lib',
|
||||
'node_intermediate_lib_type%': 'static_library',
|
||||
'library_files': [
|
||||
'lib/internal/bootstrap_loaders.js',
|
||||
'lib/internal/bootstrap_node.js',
|
||||
'lib/async_hooks.js',
|
||||
'lib/assert.js',
|
||||
|
|
129
src/node.cc
129
src/node.cc
|
@ -2525,7 +2525,7 @@ static void ThrowIfNoSuchModule(Environment* env, const char* module_v) {
|
|||
env->ThrowError(errmsg);
|
||||
}
|
||||
|
||||
static void Binding(const FunctionCallbackInfo<Value>& args) {
|
||||
static void GetBinding(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
CHECK(args[0]->IsString());
|
||||
|
@ -2552,7 +2552,7 @@ static void Binding(const FunctionCallbackInfo<Value>& args) {
|
|||
args.GetReturnValue().Set(exports);
|
||||
}
|
||||
|
||||
static void InternalBinding(const FunctionCallbackInfo<Value>& args) {
|
||||
static void GetInternalBinding(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
|
||||
CHECK(args[0]->IsString());
|
||||
|
@ -2567,7 +2567,7 @@ static void InternalBinding(const FunctionCallbackInfo<Value>& args) {
|
|||
args.GetReturnValue().Set(exports);
|
||||
}
|
||||
|
||||
static void LinkedBinding(const FunctionCallbackInfo<Value>& args) {
|
||||
static void GetLinkedBinding(const FunctionCallbackInfo<Value>& args) {
|
||||
Environment* env = Environment::GetCurrent(args.GetIsolate());
|
||||
|
||||
CHECK(args[0]->IsString());
|
||||
|
@ -3265,10 +3265,6 @@ void SetupProcessObject(Environment* env,
|
|||
env->SetMethod(process, "uptime", Uptime);
|
||||
env->SetMethod(process, "memoryUsage", MemoryUsage);
|
||||
|
||||
env->SetMethod(process, "binding", Binding);
|
||||
env->SetMethod(process, "_linkedBinding", LinkedBinding);
|
||||
env->SetMethod(process, "_internalBinding", InternalBinding);
|
||||
|
||||
env->SetMethod(process, "_setupProcessObject", SetupProcessObject);
|
||||
env->SetMethod(process, "_setupNextTick", SetupNextTick);
|
||||
env->SetMethod(process, "_setupPromises", SetupPromises);
|
||||
|
@ -3306,8 +3302,10 @@ static void RawDebug(const FunctionCallbackInfo<Value>& args) {
|
|||
fflush(stderr);
|
||||
}
|
||||
|
||||
void LoadEnvironment(Environment* env) {
|
||||
HandleScope handle_scope(env->isolate());
|
||||
|
||||
static Local<Function> GetBootstrapper(Environment* env, Local<String> source,
|
||||
Local<String> script_name) {
|
||||
EscapableHandleScope scope(env->isolate());
|
||||
|
||||
TryCatch try_catch(env->isolate());
|
||||
|
||||
|
@ -3316,20 +3314,59 @@ void LoadEnvironment(Environment* env) {
|
|||
// are not safe to ignore.
|
||||
try_catch.SetVerbose(false);
|
||||
|
||||
// Execute the lib/internal/bootstrap_node.js file which was included as a
|
||||
// static C string in node_natives.h by node_js2c.
|
||||
// 'internal_bootstrap_node_native' is the string containing that source code.
|
||||
Local<String> script_name = FIXED_ONE_BYTE_STRING(env->isolate(),
|
||||
"bootstrap_node.js");
|
||||
Local<Value> f_value = ExecuteString(env, MainSource(env), script_name);
|
||||
// Execute the factory javascript file
|
||||
Local<Value> factory_v = ExecuteString(env, source, script_name);
|
||||
if (try_catch.HasCaught()) {
|
||||
ReportException(env, try_catch);
|
||||
exit(10);
|
||||
}
|
||||
// The bootstrap_node.js file returns a function 'f'
|
||||
CHECK(f_value->IsFunction());
|
||||
|
||||
Local<Function> f = Local<Function>::Cast(f_value);
|
||||
CHECK(factory_v->IsFunction());
|
||||
Local<Function> factory = Local<Function>::Cast(factory_v);
|
||||
|
||||
return scope.Escape(factory);
|
||||
}
|
||||
|
||||
static bool ExecuteBootstrapper(Environment* env, Local<Function> factory,
|
||||
int argc, Local<Value> argv[],
|
||||
Local<Value>* out) {
|
||||
bool ret = factory->Call(
|
||||
env->context(), Null(env->isolate()), argc, argv).ToLocal(out);
|
||||
|
||||
// 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
|
||||
// exceeded). Either way, clear the stack so that the AsyncCallbackScope
|
||||
// destructor doesn't fail on the id check.
|
||||
// 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) {
|
||||
env->async_hooks()->clear_async_id_stack();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void LoadEnvironment(Environment* env) {
|
||||
HandleScope handle_scope(env->isolate());
|
||||
|
||||
TryCatch try_catch(env->isolate());
|
||||
// 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 factory scripts are lib/internal/bootstrap_loaders.js and
|
||||
// lib/internal/bootstrap_node.js, each included as a static C string
|
||||
// defined in node_javascript.h, generated in node_javascript.cc by
|
||||
// node_js2c.
|
||||
Local<Function> loaders_bootstrapper =
|
||||
GetBootstrapper(env, LoadersBootstrapperSource(env),
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "bootstrap_loaders.js"));
|
||||
Local<Function> node_bootstrapper =
|
||||
GetBootstrapper(env, NodeBootstrapperSource(env),
|
||||
FIXED_ONE_BYTE_STRING(env->isolate(), "bootstrap_node.js"));
|
||||
|
||||
// Add a reference to the global object
|
||||
Local<Object> global = env->context()->Global();
|
||||
|
@ -3356,25 +3393,47 @@ void LoadEnvironment(Environment* env) {
|
|||
// (Allows you to set stuff on `global` from anywhere in JavaScript.)
|
||||
global->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "global"), global);
|
||||
|
||||
// Now we call 'f' with the 'process' variable that we've built up with
|
||||
// all our bindings. Inside bootstrap_node.js and internal/process we'll
|
||||
// take care of assigning things to their places.
|
||||
// Create binding loaders
|
||||
v8::Local<v8::Function> get_binding_fn =
|
||||
env->NewFunctionTemplate(GetBinding)->GetFunction(env->context())
|
||||
.ToLocalChecked();
|
||||
|
||||
// We start the process this way in order to be more modular. Developers
|
||||
// who do not like how bootstrap_node.js sets up the module system but do
|
||||
// like Node's I/O bindings may want to replace 'f' with their own function.
|
||||
Local<Value> arg = env->process_object();
|
||||
v8::Local<v8::Function> get_linked_binding_fn =
|
||||
env->NewFunctionTemplate(GetLinkedBinding)->GetFunction(env->context())
|
||||
.ToLocalChecked();
|
||||
|
||||
auto ret = f->Call(env->context(), Null(env->isolate()), 1, &arg);
|
||||
// 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
|
||||
// exceeded). Either way, clear the stack so that the AsyncCallbackScope
|
||||
// destructor doesn't fail on the id check.
|
||||
// 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.IsEmpty())
|
||||
env->async_hooks()->clear_async_id_stack();
|
||||
v8::Local<v8::Function> get_internal_binding_fn =
|
||||
env->NewFunctionTemplate(GetInternalBinding)->GetFunction(env->context())
|
||||
.ToLocalChecked();
|
||||
|
||||
Local<Value> loaders_bootstrapper_args[] = {
|
||||
env->process_object(),
|
||||
get_binding_fn,
|
||||
get_linked_binding_fn,
|
||||
get_internal_binding_fn
|
||||
};
|
||||
|
||||
// Bootstrap internal loaders
|
||||
Local<Value> bootstrapped_loaders;
|
||||
if (!ExecuteBootstrapper(env, loaders_bootstrapper,
|
||||
arraysize(loaders_bootstrapper_args),
|
||||
loaders_bootstrapper_args,
|
||||
&bootstrapped_loaders)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bootstrap Node.js
|
||||
Local<Value> bootstrapped_node;
|
||||
Local<Value> node_bootstrapper_args[] = {
|
||||
env->process_object(),
|
||||
bootstrapped_loaders
|
||||
};
|
||||
if (!ExecuteBootstrapper(env, node_bootstrapper,
|
||||
arraysize(node_bootstrapper_args),
|
||||
node_bootstrapper_args,
|
||||
&bootstrapped_node)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintHelp() {
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
namespace node {
|
||||
|
||||
void DefineJavaScript(Environment* env, v8::Local<v8::Object> target);
|
||||
v8::Local<v8::String> MainSource(Environment* env);
|
||||
v8::Local<v8::String> LoadersBootstrapperSource(Environment* env);
|
||||
v8::Local<v8::String> NodeBootstrapperSource(Environment* env);
|
||||
|
||||
} // namespace node
|
||||
|
||||
|
|
|
@ -12,4 +12,4 @@ AssertionError [ERR_ASSERTION]: 1 strictEqual 2
|
|||
at Function.Module._load (module.js:*:*)
|
||||
at Function.Module.runMain (module.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
|
|
|
@ -10,7 +10,7 @@ SyntaxError: Strict mode code may not include a with statement
|
|||
at Module._compile (module.js:*:*)
|
||||
at evalScript (bootstrap_node.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
42
|
||||
42
|
||||
[eval]:1
|
||||
|
@ -25,7 +25,7 @@ Error: hello
|
|||
at Module._compile (module.js:*:*)
|
||||
at evalScript (bootstrap_node.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
|
||||
[eval]:1
|
||||
throw new Error("hello")
|
||||
|
@ -39,7 +39,7 @@ Error: hello
|
|||
at Module._compile (module.js:*:*)
|
||||
at evalScript (bootstrap_node.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
100
|
||||
[eval]:1
|
||||
var x = 100; y = x;
|
||||
|
@ -53,7 +53,7 @@ ReferenceError: y is not defined
|
|||
at Module._compile (module.js:*:*)
|
||||
at evalScript (bootstrap_node.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
|
||||
[eval]:1
|
||||
var ______________________________________________; throw 10
|
||||
|
|
|
@ -19,4 +19,4 @@ Emitted 'error' event at:
|
|||
at Module._compile (module.js:*:*)
|
||||
[... lines matching original stack trace ...]
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
|
|
|
@ -11,10 +11,10 @@ Error
|
|||
at Function.Module._load (module.js:*:*)
|
||||
at Function.Module.runMain (module.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
Emitted 'error' event at:
|
||||
at process.nextTick (*events_unhandled_error_nexttick.js:*:*)
|
||||
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||
at Function.Module.runMain (module.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
|
|
|
@ -11,9 +11,9 @@ Error
|
|||
at Function.Module._load (module.js:*:*)
|
||||
at Function.Module.runMain (module.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
Emitted 'error' event at:
|
||||
at Object.<anonymous> (*events_unhandled_error_sameline.js:*:*)
|
||||
at Module._compile (module.js:*:*)
|
||||
[... lines matching original stack trace ...]
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
|
|
|
@ -7,4 +7,4 @@ ReferenceError: undefined_reference_error_maker is not defined
|
|||
at process._tickCallback (internal/process/next_tick.js:*:*)
|
||||
at Function.Module.runMain (module.js:*:*)
|
||||
at startup (bootstrap_node.js:*:*)
|
||||
at bootstrap_node.js:*:*
|
||||
at bootstrapNodeJSCore (bootstrap_node.js:*:*)
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// Flags: --expose-internals
|
||||
|
||||
'use strict';
|
||||
|
||||
const common = require('../common');
|
||||
|
||||
common.expectsError(
|
||||
() => {
|
||||
require('internal/bootstrap_loaders');
|
||||
}, {
|
||||
code: 'MODULE_NOT_FOUND',
|
||||
message: 'Cannot find module \'internal/bootstrap_loaders\''
|
||||
}
|
||||
);
|
||||
|
||||
common.expectsError(
|
||||
() => {
|
||||
const source = 'module.exports = require("internal/bootstrap_loaders")';
|
||||
process.binding('natives').owo = source;
|
||||
require('owo');
|
||||
}, {
|
||||
code: 'MODULE_NOT_FOUND',
|
||||
message: 'Cannot find module \'owo\''
|
||||
}
|
||||
);
|
|
@ -185,7 +185,11 @@ namespace node {{
|
|||
|
||||
{definitions}
|
||||
|
||||
v8::Local<v8::String> MainSource(Environment* env) {{
|
||||
v8::Local<v8::String> LoadersBootstrapperSource(Environment* env) {{
|
||||
return internal_bootstrap_loaders_value.ToStringChecked(env->isolate());
|
||||
}}
|
||||
|
||||
v8::Local<v8::String> NodeBootstrapperSource(Environment* env) {{
|
||||
return internal_bootstrap_node_value.ToStringChecked(env->isolate());
|
||||
}}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче