Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2a9eb31

Browse filesBrowse files
committed
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: #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>
1 parent 1a5ec83 commit 2a9eb31
Copy full SHA for 2a9eb31
Expand file treeCollapse file tree

29 files changed

+391
-233
lines changed
Open diff view settings
Collapse file

‎.eslintrc.js‎

Copy file name to clipboardExpand all lines: .eslintrc.js
+1-2Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,6 @@ module.exports = {
244244
DTRACE_HTTP_SERVER_REQUEST: false,
245245
DTRACE_HTTP_SERVER_RESPONSE: false,
246246
DTRACE_NET_SERVER_CONNECTION: false,
247-
DTRACE_NET_STREAM_END: false,
248-
internalBinding: false,
247+
DTRACE_NET_STREAM_END: false
249248
},
250249
};
Collapse file

‎lib/assert.js‎

Copy file name to clipboardExpand all lines: lib/assert.js
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const { openSync, closeSync, readSync } = require('fs');
3636
const { parseExpressionAt } = require('internal/deps/acorn/dist/acorn');
3737
const { inspect } = require('util');
3838
const { EOL } = require('os');
39-
const nativeModule = require('native_module');
39+
const { NativeModule } = require('internal/bootstrap_loaders');
4040

4141
// Escape control characters but not \n and \t to keep the line breaks and
4242
// indentation intact.
@@ -163,7 +163,7 @@ function getErrMessage(call) {
163163
}
164164

165165
// Skip Node.js modules!
166-
if (filename.endsWith('.js') && nativeModule.exists(filename.slice(0, -3))) {
166+
if (filename.endsWith('.js') && NativeModule.exists(filename.slice(0, -3))) {
167167
errorCache.set(identifier, undefined);
168168
return;
169169
}
Collapse file

‎lib/buffer.js‎

Copy file name to clipboardExpand all lines: lib/buffer.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const {
4141
// that test/parallel/test-buffer-bindingobj-no-zerofill.js is written.
4242
let isAnyArrayBuffer;
4343
try {
44+
const { internalBinding } = require('internal/bootstrap_loaders');
4445
isAnyArrayBuffer = internalBinding('types').isAnyArrayBuffer;
4546
} catch (e) {
4647
isAnyArrayBuffer = require('util').types.isAnyArrayBuffer;
Collapse file

‎lib/domain.js‎

Copy file name to clipboardExpand all lines: lib/domain.js
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ const {
3434
ERR_UNHANDLED_ERROR
3535
} = require('internal/errors').codes;
3636
const { createHook } = require('async_hooks');
37+
const { internalBinding } = require('internal/bootstrap_loaders');
3738

3839
// overwrite process.domain with a getter/setter that will allow for more
3940
// effective optimizations
Collapse file

‎lib/internal/bootstrap_loaders.js‎

Copy file name to clipboard
+229Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
// This file creates the internal module & binding loaders used by built-in
2+
// modules. In contrast, user land modules are loaded using
3+
// lib/module.js (CommonJS Modules) or lib/internal/loader/* (ES Modules).
4+
//
5+
// This file is compiled and run by node.cc before bootstrap_node.js
6+
// was called, therefore the loaders are bootstraped before we start to
7+
// actually bootstrap Node.js. It creates the following objects:
8+
//
9+
// C++ binding loaders:
10+
// - process.binding(): the legacy C++ binding loader, accessible from user land
11+
// because it is an object attached to the global process object.
12+
// These C++ bindings are created using NODE_BUILTIN_MODULE_CONTEXT_AWARE()
13+
// and have their nm_flags set to NM_F_BUILTIN. We do not make any guarantees
14+
// about the stability of these bindings, but still have to take care of
15+
// compatibility issues caused by them from time to time.
16+
// - process._linkedBinding(): intended to be used by embedders to add
17+
// additional C++ bindings in their applications. These C++ bindings
18+
// can be created using NODE_MODULE_CONTEXT_AWARE_CPP() with the flag
19+
// NM_F_LINKED.
20+
// - internalBinding(): the private internal C++ binding loader, inaccessible
21+
// from user land because they are only available from NativeModule.require()
22+
// These C++ bindings are created using NODE_MODULE_CONTEXT_AWARE_INTERNAL()
23+
// and have their nm_flags set to NM_F_INTERNAL.
24+
//
25+
// Internal JavaScript module loader:
26+
// - NativeModule: a minimal module system used to load the JavaScript core
27+
// modules found in lib/**/*.js and deps/**/*.js. All core modules are
28+
// compiled into the node binary via node_javascript.cc generated by js2c.py,
29+
// so they can be loaded faster without the cost of I/O. This class makes the
30+
// lib/internal/*, deps/internal/* modules and internalBinding() available by
31+
// default to core modules, and lets the core modules require itself via
32+
// require('internal/bootstrap_loaders') even when this file is not written in
33+
// CommonJS style.
34+
//
35+
// Other objects:
36+
// - process.moduleLoadList: an array recording the bindings and the modules
37+
// loaded in the process and the order in which they are loaded.
38+
39+
'use strict';
40+
41+
(function bootstrapInternalLoaders(process, getBinding, getLinkedBinding,
42+
getInternalBinding) {
43+
44+
// Set up process.moduleLoadList
45+
const moduleLoadList = [];
46+
Object.defineProperty(process, 'moduleLoadList', {
47+
value: moduleLoadList,
48+
configurable: true,
49+
enumerable: true,
50+
writable: false
51+
});
52+
53+
// Set up process.binding() and process._linkedBinding()
54+
{
55+
const bindingObj = Object.create(null);
56+
57+
process.binding = function binding(module) {
58+
module = String(module);
59+
let mod = bindingObj[module];
60+
if (typeof mod !== 'object') {
61+
mod = bindingObj[module] = getBinding(module);
62+
moduleLoadList.push(`Binding ${module}`);
63+
}
64+
return mod;
65+
};
66+
67+
process._linkedBinding = function _linkedBinding(module) {
68+
module = String(module);
69+
let mod = bindingObj[module];
70+
if (typeof mod !== 'object')
71+
mod = bindingObj[module] = getLinkedBinding(module);
72+
return mod;
73+
};
74+
}
75+
76+
// Set up internalBinding() in the closure
77+
let internalBinding;
78+
{
79+
const bindingObj = Object.create(null);
80+
internalBinding = function internalBinding(module) {
81+
let mod = bindingObj[module];
82+
if (typeof mod !== 'object') {
83+
mod = bindingObj[module] = getInternalBinding(module);
84+
moduleLoadList.push(`Internal Binding ${module}`);
85+
}
86+
return mod;
87+
};
88+
}
89+
90+
// Minimal sandbox helper
91+
const ContextifyScript = process.binding('contextify').ContextifyScript;
92+
function runInThisContext(code, options) {
93+
const script = new ContextifyScript(code, options);
94+
return script.runInThisContext();
95+
}
96+
97+
// Set up NativeModule
98+
function NativeModule(id) {
99+
this.filename = `${id}.js`;
100+
this.id = id;
101+
this.exports = {};
102+
this.loaded = false;
103+
this.loading = false;
104+
}
105+
106+
NativeModule._source = getBinding('natives');
107+
NativeModule._cache = {};
108+
109+
const config = getBinding('config');
110+
111+
// Think of this as module.exports in this file even though it is not
112+
// written in CommonJS style.
113+
const loaderExports = { internalBinding, NativeModule };
114+
const loaderId = 'internal/bootstrap_loaders';
115+
NativeModule.require = function(id) {
116+
if (id === loaderId) {
117+
return loaderExports;
118+
}
119+
120+
const cached = NativeModule.getCached(id);
121+
if (cached && (cached.loaded || cached.loading)) {
122+
return cached.exports;
123+
}
124+
125+
if (!NativeModule.exists(id)) {
126+
// Model the error off the internal/errors.js model, but
127+
// do not use that module given that it could actually be
128+
// the one causing the error if there's a bug in Node.js
129+
const err = new Error(`No such built-in module: ${id}`);
130+
err.code = 'ERR_UNKNOWN_BUILTIN_MODULE';
131+
err.name = 'Error [ERR_UNKNOWN_BUILTIN_MODULE]';
132+
throw err;
133+
}
134+
135+
moduleLoadList.push(`NativeModule ${id}`);
136+
137+
const nativeModule = new NativeModule(id);
138+
139+
nativeModule.cache();
140+
nativeModule.compile();
141+
142+
return nativeModule.exports;
143+
};
144+
145+
NativeModule.requireForDeps = function(id) {
146+
if (!NativeModule.exists(id) ||
147+
// TODO(TimothyGu): remove when DEP0084 reaches end of life.
148+
id.startsWith('node-inspect/') ||
149+
id.startsWith('v8/')) {
150+
id = `internal/deps/${id}`;
151+
}
152+
return NativeModule.require(id);
153+
};
154+
155+
NativeModule.getCached = function(id) {
156+
return NativeModule._cache[id];
157+
};
158+
159+
NativeModule.exists = function(id) {
160+
return NativeModule._source.hasOwnProperty(id);
161+
};
162+
163+
if (config.exposeInternals) {
164+
NativeModule.nonInternalExists = function(id) {
165+
// Do not expose this to user land even with --expose-internals
166+
if (id === loaderId) {
167+
return false;
168+
}
169+
return NativeModule.exists(id);
170+
};
171+
172+
NativeModule.isInternal = function(id) {
173+
// Do not expose this to user land even with --expose-internals
174+
return id === loaderId;
175+
};
176+
} else {
177+
NativeModule.nonInternalExists = function(id) {
178+
return NativeModule.exists(id) && !NativeModule.isInternal(id);
179+
};
180+
181+
NativeModule.isInternal = function(id) {
182+
return id.startsWith('internal/');
183+
};
184+
}
185+
186+
NativeModule.getSource = function(id) {
187+
return NativeModule._source[id];
188+
};
189+
190+
NativeModule.wrap = function(script) {
191+
return NativeModule.wrapper[0] + script + NativeModule.wrapper[1];
192+
};
193+
194+
NativeModule.wrapper = [
195+
'(function (exports, require, module, process) {',
196+
'\n});'
197+
];
198+
199+
NativeModule.prototype.compile = function() {
200+
let source = NativeModule.getSource(this.id);
201+
source = NativeModule.wrap(source);
202+
203+
this.loading = true;
204+
205+
try {
206+
const fn = runInThisContext(source, {
207+
filename: this.filename,
208+
lineOffset: 0,
209+
displayErrors: true
210+
});
211+
const requireFn = this.id.startsWith('internal/deps/') ?
212+
NativeModule.requireForDeps :
213+
NativeModule.require;
214+
fn(this.exports, requireFn, this, process);
215+
216+
this.loaded = true;
217+
} finally {
218+
this.loading = false;
219+
}
220+
};
221+
222+
NativeModule.prototype.cache = function() {
223+
NativeModule._cache[this.id] = this;
224+
};
225+
226+
// This will be passed to the bootstrapNodeJSCore function in
227+
// bootstrap_node.js.
228+
return loaderExports;
229+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.