summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.eslintrc.js3
-rw-r--r--lib/assert.js4
-rw-r--r--lib/buffer.js1
-rw-r--r--lib/domain.js1
-rw-r--r--lib/internal/bootstrap_loaders.js229
-rw-r--r--lib/internal/bootstrap_node.js185
-rw-r--r--lib/internal/encoding.js1
-rw-r--r--lib/internal/loader/CreateDynamicModule.js1
-rw-r--r--lib/internal/loader/DefaultResolve.js2
-rw-r--r--lib/internal/loader/ModuleJob.js1
-rw-r--r--lib/internal/loader/Translators.js2
-rw-r--r--lib/internal/process/modules.js1
-rw-r--r--lib/internal/test/binding.js1
-rw-r--r--lib/internal/util/comparisons.js1
-rw-r--r--lib/internal/vm/Module.js1
-rw-r--r--lib/module.js2
-rw-r--r--lib/string_decoder.js1
-rw-r--r--lib/util.js1
-rw-r--r--node.gyp1
-rw-r--r--src/node.cc129
-rw-r--r--src/node_javascript.h3
-rw-r--r--test/message/error_exit.out2
-rw-r--r--test/message/eval_messages.out8
-rw-r--r--test/message/events_unhandled_error_common_trace.out2
-rw-r--r--test/message/events_unhandled_error_nexttick.out4
-rw-r--r--test/message/events_unhandled_error_sameline.out4
-rw-r--r--test/message/nexttick_throw.out2
-rw-r--r--test/parallel/test-loaders-hidden-from-users.js25
-rwxr-xr-xtools/js2c.py6
29 files changed, 391 insertions, 233 deletions
diff --git a/.eslintrc.js b/.eslintrc.js
index 2836173ca3..6a378f659c 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -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
},
};
diff --git a/lib/assert.js b/lib/assert.js
index 7d894518b1..f8eeba7222 100644
--- a/lib/assert.js
+++ b/lib/assert.js
@@ -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;
}
diff --git a/lib/buffer.js b/lib/buffer.js
index fc42f771c2..7703d2a129 100644
--- a/lib/buffer.js
+++ b/lib/buffer.js
@@ -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;
diff --git a/lib/domain.js b/lib/domain.js
index 360896d16a..e2cc38a1f9 100644
--- a/lib/domain.js
+++ b/lib/domain.js
@@ -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
diff --git a/lib/internal/bootstrap_loaders.js b/lib/internal/bootstrap_loaders.js
new file mode 100644
index 0000000000..e409438dfc
--- /dev/null
+++ b/lib/internal/bootstrap_loaders.js
@@ -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;
+});
diff --git a/lib/internal/bootstrap_node.js b/lib/internal/bootstrap_node.js
index 97b6db03ce..6cdbebc0c1 100644
--- a/lib/internal/bootstrap_node.js
+++ b/lib/internal/bootstrap_node.js
@@ -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();
});
diff --git a/lib/internal/encoding.js b/lib/internal/encoding.js
index f80bdcdf2b..fc8ac555fc 100644
--- a/lib/internal/encoding.js
+++ b/lib/internal/encoding.js
@@ -17,6 +17,7 @@ const {
const { isArrayBufferView } = require('internal/util/types');
+const { internalBinding } = require('internal/bootstrap_loaders');
const {
isArrayBuffer
} = internalBinding('types');
diff --git a/lib/internal/loader/CreateDynamicModule.js b/lib/internal/loader/CreateDynamicModule.js
index f2596de04b..8c28917138 100644
--- a/lib/internal/loader/CreateDynamicModule.js
+++ b/lib/internal/loader/CreateDynamicModule.js
@@ -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);
diff --git a/lib/internal/loader/DefaultResolve.js b/lib/internal/loader/DefaultResolve.js
index d815be87dd..e92f528721 100644
--- a/lib/internal/loader/DefaultResolve.js
+++ b/lib/internal/loader/DefaultResolve.js
@@ -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;
diff --git a/lib/internal/loader/ModuleJob.js b/lib/internal/loader/ModuleJob.js
index b3553fc723..162b0504d3 100644
--- a/lib/internal/loader/ModuleJob.js
+++ b/lib/internal/loader/ModuleJob.js
@@ -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');
diff --git a/lib/internal/loader/Translators.js b/lib/internal/loader/Translators.js
index 18b1b12fd1..74dd435827 100644
--- a/lib/internal/loader/Translators.js
+++ b/lib/internal/loader/Translators.js
@@ -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');
diff --git a/lib/internal/process/modules.js b/lib/internal/process/modules.js
index f89278ddaa..1592761f54 100644
--- a/lib/internal/process/modules.js
+++ b/lib/internal/process/modules.js
@@ -1,5 +1,6 @@
'use strict';
+const { internalBinding } = require('internal/bootstrap_loaders');
const {
setImportModuleDynamicallyCallback,
setInitializeImportMetaObjectCallback
diff --git a/lib/internal/test/binding.js b/lib/internal/test/binding.js
index 7b9e1a089d..aae89ce7a0 100644
--- a/lib/internal/test/binding.js
+++ b/lib/internal/test/binding.js
@@ -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,
};
diff --git a/lib/internal/util/comparisons.js b/lib/internal/util/comparisons.js
index 23d8488fbd..c1c4d7a712 100644
--- a/lib/internal/util/comparisons.js
+++ b/lib/internal/util/comparisons.js
@@ -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) {
diff --git a/lib/internal/vm/Module.js b/lib/internal/vm/Module.js
index a8fb7303ae..e954babf1d 100644
--- a/lib/internal/vm/Module.js
+++ b/lib/internal/vm/Module.js
@@ -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');
diff --git a/lib/module.js b/lib/module.js
index 8d1002a383..468619f2bf 100644
--- a/lib/module.js
+++ b/lib/module.js
@@ -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');
diff --git a/lib/string_decoder.js b/lib/string_decoder.js
index a2b7cf7de2..4cb50ca97b 100644
--- a/lib/string_decoder.js
+++ b/lib/string_decoder.js
@@ -22,6 +22,7 @@
'use strict';
const { Buffer } = require('buffer');
+const { internalBinding } = require('internal/bootstrap_loaders');
const {
kIncompleteCharactersStart,
kIncompleteCharactersEnd,
diff --git a/lib/util.js b/lib/util.js
index 70a76ccdcf..95bf17519b 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -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 {
diff --git a/node.gyp b/node.gyp
index 977cef33ff..3d5fd72958 100644
--- a/node.gyp
+++ b/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',
diff --git a/src/node.cc b/src/node.cc
index 20c5da46d6..682052aadf 100644
--- a/src/node.cc
+++ b/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() {
diff --git a/src/node_javascript.h b/src/node_javascript.h
index 664778091f..d1ad9a2574 100644
--- a/src/node_javascript.h
+++ b/src/node_javascript.h
@@ -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
diff --git a/test/message/error_exit.out b/test/message/error_exit.out
index 1a3c17bf58..eab43959b6 100644
--- a/test/message/error_exit.out
+++ b/test/message/error_exit.out
@@ -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:*:*)
diff --git a/test/message/eval_messages.out b/test/message/eval_messages.out
index 6c725cb1cc..7dbf9e950c 100644
--- a/test/message/eval_messages.out
+++ b/test/message/eval_messages.out
@@ -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
diff --git a/test/message/events_unhandled_error_common_trace.out b/test/message/events_unhandled_error_common_trace.out
index d39a95cb77..1535573470 100644
--- a/test/message/events_unhandled_error_common_trace.out
+++ b/test/message/events_unhandled_error_common_trace.out
@@ -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:*:*)
diff --git a/test/message/events_unhandled_error_nexttick.out b/test/message/events_unhandled_error_nexttick.out
index f0591610ff..c578f55f90 100644
--- a/test/message/events_unhandled_error_nexttick.out
+++ b/test/message/events_unhandled_error_nexttick.out
@@ -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:*:*)
diff --git a/test/message/events_unhandled_error_sameline.out b/test/message/events_unhandled_error_sameline.out
index 100c294276..d8441c44d4 100644
--- a/test/message/events_unhandled_error_sameline.out
+++ b/test/message/events_unhandled_error_sameline.out
@@ -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:*:*)
diff --git a/test/message/nexttick_throw.out b/test/message/nexttick_throw.out
index 1c9eca8405..41412b95f6 100644
--- a/test/message/nexttick_throw.out
+++ b/test/message/nexttick_throw.out
@@ -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:*:*)
diff --git a/test/parallel/test-loaders-hidden-from-users.js b/test/parallel/test-loaders-hidden-from-users.js
new file mode 100644
index 0000000000..b3e6622c8c
--- /dev/null
+++ b/test/parallel/test-loaders-hidden-from-users.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\''
+ }
+);
diff --git a/tools/js2c.py b/tools/js2c.py
index 75c74f22ce..213a9fefdc 100755
--- a/tools/js2c.py
+++ b/tools/js2c.py
@@ -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());
}}