Skip to content

Commit beb5737

Browse files
committed
bootstrap: lazy load non-essential modules
It turns out that even with startup snapshots, there is a non-trivial overhead for loading internal modules. This patch makes the loading of the non-essential modules lazy again. Caveat: we have to make some of the globals lazily-loaded too, so the WPT runner is updated to test what the state of the global scope is after the globals are accessed (and replaced with the loaded value). PR-URL: nodejs/node#45659 Backport-PR-URL: nodejs/node#46425 Reviewed-By: Matteo Collina <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: Daeyeon Jeong <[email protected]> Reviewed-By: Jacob Smith <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Rafael Gonzaga <[email protected]> Reviewed-By: Antoine du Hamel <[email protected]> Reviewed-By: Minwoo Jung <[email protected]> Reviewed-By: Tierney Cyren <[email protected]>
1 parent e1f5317 commit beb5737

25 files changed

+314
-330
lines changed

graal-nodejs/lib/buffer.js

+12-12
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ const {
8686
lazyDOMException,
8787
normalizeEncoding,
8888
kIsEncodingSymbol,
89+
defineLazyProperties,
8990
} = require('internal/util');
9091
const {
9192
isAnyArrayBuffer,
@@ -129,15 +130,6 @@ const {
129130
createUnsafeBuffer,
130131
} = require('internal/buffer');
131132

132-
const {
133-
Blob,
134-
resolveObjectURL,
135-
} = require('internal/blob');
136-
137-
const {
138-
File,
139-
} = require('internal/file');
140-
141133
FastBuffer.prototype.constructor = Buffer;
142134
Buffer.prototype = FastBuffer.prototype;
143135
addBufferPrototypeMethods(Buffer.prototype);
@@ -1385,9 +1377,6 @@ function isAscii(input) {
13851377
}
13861378

13871379
module.exports = {
1388-
Blob,
1389-
File,
1390-
resolveObjectURL,
13911380
Buffer,
13921381
SlowBuffer,
13931382
transcode,
@@ -1416,3 +1405,14 @@ ObjectDefineProperties(module.exports, {
14161405
set(val) { INSPECT_MAX_BYTES = val; },
14171406
},
14181407
});
1408+
1409+
defineLazyProperties(
1410+
module.exports,
1411+
'internal/blob',
1412+
['Blob', 'resolveObjectURL'],
1413+
);
1414+
defineLazyProperties(
1415+
module.exports,
1416+
'internal/file',
1417+
['File'],
1418+
);

graal-nodejs/lib/fs.js

+12-14
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ const {
8787
custom: kCustomPromisifiedSymbol,
8888
},
8989
SideEffectFreeRegExpPrototypeExec,
90+
defineLazyProperties,
9091
} = require('internal/util');
9192
const {
9293
constants: {
@@ -125,11 +126,6 @@ const {
125126
validatePrimitiveStringAfterArrayBufferView,
126127
warnOnNonPortableTemplate,
127128
} = require('internal/fs/utils');
128-
const {
129-
Dir,
130-
opendir,
131-
opendirSync,
132-
} = require('internal/fs/dir');
133129
const {
134130
CHAR_FORWARD_SLASH,
135131
CHAR_BACKWARD_SLASH,
@@ -146,9 +142,6 @@ const {
146142
validateString,
147143
} = require('internal/validators');
148144

149-
const watchers = require('internal/fs/watchers');
150-
const ReadFileContext = require('internal/fs/read_file_context');
151-
152145
let truncateWarn = true;
153146
let fs;
154147

@@ -392,6 +385,7 @@ function checkAborted(signal, callback) {
392385
function readFile(path, options, callback) {
393386
callback = maybeCallback(callback || options);
394387
options = getOptions(options, { flag: 'r' });
388+
const ReadFileContext = require('internal/fs/read_file_context');
395389
const context = new ReadFileContext(callback, options.encoding);
396390
context.isUserFd = isFd(path); // File descriptor ownership
397391

@@ -2422,12 +2416,13 @@ function watch(filename, options, listener) {
24222416
if (options.recursive === undefined) options.recursive = false;
24232417
if (options.recursive && !(isOSX || isWindows))
24242418
throw new ERR_FEATURE_UNAVAILABLE_ON_PLATFORM('watch recursively');
2419+
2420+
const watchers = require('internal/fs/watchers');
24252421
const watcher = new watchers.FSWatcher();
24262422
watcher[watchers.kFSWatchStart](filename,
24272423
options.persistent,
24282424
options.recursive,
24292425
options.encoding);
2430-
24312426
if (listener) {
24322427
watcher.addListener('change', listener);
24332428
}
@@ -2486,7 +2481,7 @@ function watchFile(filename, options, listener) {
24862481
validateFunction(listener, 'listener');
24872482

24882483
stat = statWatchers.get(filename);
2489-
2484+
const watchers = require('internal/fs/watchers');
24902485
if (stat === undefined) {
24912486
stat = new watchers.StatWatcher(options.bigint);
24922487
stat[watchers.kFSStatWatcherStart](filename,
@@ -2512,7 +2507,7 @@ function unwatchFile(filename, listener) {
25122507
const stat = statWatchers.get(filename);
25132508

25142509
if (stat === undefined) return;
2515-
2510+
const watchers = require('internal/fs/watchers');
25162511
if (typeof listener === 'function') {
25172512
const beforeListenerCount = stat.listenerCount('change');
25182513
stat.removeListener('change', listener);
@@ -3116,8 +3111,6 @@ module.exports = fs = {
31163111
mkdtempSync,
31173112
open,
31183113
openSync,
3119-
opendir,
3120-
opendirSync,
31213114
readdir,
31223115
readdirSync,
31233116
read,
@@ -3157,7 +3150,6 @@ module.exports = fs = {
31573150
writeSync,
31583151
writev,
31593152
writevSync,
3160-
Dir,
31613153
Dirent,
31623154
Stats,
31633155

@@ -3203,6 +3195,12 @@ module.exports = fs = {
32033195
_toUnixTimestamp: toUnixTimestamp,
32043196
};
32053197

3198+
defineLazyProperties(
3199+
fs,
3200+
'internal/fs/dir',
3201+
['Dir', 'opendir', 'opendirSync'],
3202+
);
3203+
32063204
ObjectDefineProperties(fs, {
32073205
F_OK: { __proto__: null, enumerable: true, value: F_OK || 0 },
32083206
R_OK: { __proto__: null, enumerable: true, value: R_OK || 0 },

graal-nodejs/lib/internal/async_hooks.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ const {
88
Symbol,
99
} = primordials;
1010

11-
const promiseHooks = require('internal/promise_hooks');
12-
1311
const async_wrap = internalBinding('async_wrap');
1412
const { setCallbackTrampoline } = async_wrap;
1513
/* async_hook_fields is a Uint32Array wrapping the uint32_t array of
@@ -382,6 +380,7 @@ function updatePromiseHookMode() {
382380
initHook = destroyTracking;
383381
}
384382
if (stopPromiseHook) stopPromiseHook();
383+
const promiseHooks = require('internal/promise_hooks');
385384
stopPromiseHook = promiseHooks.createHook({
386385
init: initHook,
387386
before: promiseBeforeHook,

graal-nodejs/lib/internal/bootstrap/browser.js

+62-100
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ const {
99
defineOperation,
1010
exposeInterface,
1111
lazyDOMExceptionClass,
12+
defineLazyProperties,
13+
defineReplaceableLazyAttribute,
14+
exposeLazyInterfaces,
1215
} = require('internal/util');
1316
const config = internalBinding('config');
1417

@@ -28,56 +31,39 @@ exposeGetterAndSetter(globalThis,
2831
exposeInterface(globalThis, 'DOMException', value);
2932
});
3033

31-
const {
32-
TextEncoder,
33-
TextDecoder,
34-
} = require('internal/encoding');
35-
// https://encoding.spec.whatwg.org/#textencoder
36-
exposeInterface(globalThis, 'TextEncoder', TextEncoder);
37-
// https://encoding.spec.whatwg.org/#textdecoder
38-
exposeInterface(globalThis, 'TextDecoder', TextDecoder);
39-
40-
const {
41-
AbortController,
42-
AbortSignal,
43-
} = require('internal/abort_controller');
44-
exposeInterface(globalThis, 'AbortController', AbortController);
45-
exposeInterface(globalThis, 'AbortSignal', AbortSignal);
46-
47-
const {
48-
EventTarget,
49-
Event,
50-
} = require('internal/event_target');
51-
exposeInterface(globalThis, 'EventTarget', EventTarget);
52-
exposeInterface(globalThis, 'Event', Event);
53-
const {
54-
MessageChannel,
55-
MessagePort,
56-
MessageEvent,
57-
} = require('internal/worker/io');
58-
exposeInterface(globalThis, 'MessageChannel', MessageChannel);
59-
exposeInterface(globalThis, 'MessagePort', MessagePort);
60-
exposeInterface(globalThis, 'MessageEvent', MessageEvent);
61-
6234
// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope
6335
const timers = require('timers');
6436
defineOperation(globalThis, 'clearInterval', timers.clearInterval);
6537
defineOperation(globalThis, 'clearTimeout', timers.clearTimeout);
6638
defineOperation(globalThis, 'setInterval', timers.setInterval);
6739
defineOperation(globalThis, 'setTimeout', timers.setTimeout);
6840

69-
const buffer = require('buffer');
70-
defineOperation(globalThis, 'atob', buffer.atob);
71-
defineOperation(globalThis, 'btoa', buffer.btoa);
72-
41+
// Lazy ones.
42+
exposeLazyInterfaces(globalThis, 'internal/abort_controller', [
43+
'AbortController', 'AbortSignal',
44+
]);
45+
exposeLazyInterfaces(globalThis, 'internal/event_target', [
46+
'EventTarget', 'Event',
47+
]);
48+
exposeLazyInterfaces(globalThis, 'internal/worker/io', [
49+
'MessageChannel', 'MessagePort', 'MessageEvent',
50+
]);
51+
defineLazyProperties(globalThis, 'buffer', ['atob', 'btoa']);
7352
// https://www.w3.org/TR/FileAPI/#dfn-Blob
74-
exposeInterface(globalThis, 'Blob', buffer.Blob);
75-
53+
exposeLazyInterfaces(globalThis, 'internal/blob', ['Blob']);
7654
// https://www.w3.org/TR/hr-time-2/#the-performance-attribute
77-
const perf_hooks = require('perf_hooks');
78-
exposeInterface(globalThis, 'Performance', perf_hooks.Performance);
79-
defineReplacableAttribute(globalThis, 'performance',
80-
perf_hooks.performance);
55+
56+
exposeLazyInterfaces(globalThis, 'perf_hooks', [
57+
'Performance',
58+
]);
59+
60+
defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']);
61+
62+
// https://encoding.spec.whatwg.org/#textencoder
63+
// https://encoding.spec.whatwg.org/#textdecoder
64+
exposeLazyInterfaces(globalThis,
65+
'internal/encoding',
66+
['TextEncoder', 'TextDecoder']);
8167

8268
function createGlobalConsole() {
8369
const consoleFromNode =
@@ -115,67 +101,43 @@ function exposeGetterAndSetter(target, name, getter, setter = undefined) {
115101
});
116102
}
117103

118-
// https://heycam.github.io/webidl/#Replaceable
119-
function defineReplacableAttribute(target, name, value) {
120-
ObjectDefineProperty(target, name, {
121-
__proto__: null,
122-
writable: true,
123-
enumerable: true,
124-
configurable: true,
125-
value,
126-
});
127-
}
128-
129104
// Web Streams API
130-
const {
131-
TransformStream,
132-
TransformStreamDefaultController,
133-
} = require('internal/webstreams/transformstream');
134-
135-
const {
136-
WritableStream,
137-
WritableStreamDefaultController,
138-
WritableStreamDefaultWriter,
139-
} = require('internal/webstreams/writablestream');
105+
exposeLazyInterfaces(
106+
globalThis,
107+
'internal/webstreams/transformstream',
108+
['TransformStream', 'TransformStreamDefaultController']);
140109

141-
const {
142-
ReadableStream,
143-
ReadableStreamDefaultReader,
144-
ReadableStreamBYOBReader,
145-
ReadableStreamBYOBRequest,
146-
ReadableByteStreamController,
147-
ReadableStreamDefaultController,
148-
} = require('internal/webstreams/readablestream');
110+
exposeLazyInterfaces(
111+
globalThis,
112+
'internal/webstreams/writablestream',
113+
['WritableStream', 'WritableStreamDefaultController', 'WritableStreamDefaultWriter']);
149114

150-
const {
151-
ByteLengthQueuingStrategy,
152-
CountQueuingStrategy,
153-
} = require('internal/webstreams/queuingstrategies');
115+
exposeLazyInterfaces(
116+
globalThis,
117+
'internal/webstreams/readablestream',
118+
[
119+
'ReadableStream', 'ReadableStreamDefaultReader',
120+
'ReadableStreamBYOBReader', 'ReadableStreamBYOBRequest',
121+
'ReadableByteStreamController', 'ReadableStreamDefaultController',
122+
]);
123+
124+
exposeLazyInterfaces(
125+
globalThis,
126+
'internal/webstreams/queuingstrategies',
127+
[
128+
'ByteLengthQueuingStrategy', 'CountQueuingStrategy',
129+
]);
154130

155-
const {
156-
TextEncoderStream,
157-
TextDecoderStream,
158-
} = require('internal/webstreams/encoding');
131+
exposeLazyInterfaces(
132+
globalThis,
133+
'internal/webstreams/encoding',
134+
[
135+
'TextEncoderStream', 'TextDecoderStream',
136+
]);
159137

160-
const {
161-
CompressionStream,
162-
DecompressionStream,
163-
} = require('internal/webstreams/compression');
164-
165-
exposeInterface(globalThis, 'ReadableStream', ReadableStream);
166-
exposeInterface(globalThis, 'ReadableStreamDefaultReader', ReadableStreamDefaultReader);
167-
exposeInterface(globalThis, 'ReadableStreamBYOBReader', ReadableStreamBYOBReader);
168-
exposeInterface(globalThis, 'ReadableStreamBYOBRequest', ReadableStreamBYOBRequest);
169-
exposeInterface(globalThis, 'ReadableByteStreamController', ReadableByteStreamController);
170-
exposeInterface(globalThis, 'ReadableStreamDefaultController', ReadableStreamDefaultController);
171-
exposeInterface(globalThis, 'TransformStream', TransformStream);
172-
exposeInterface(globalThis, 'TransformStreamDefaultController', TransformStreamDefaultController);
173-
exposeInterface(globalThis, 'WritableStream', WritableStream);
174-
exposeInterface(globalThis, 'WritableStreamDefaultWriter', WritableStreamDefaultWriter);
175-
exposeInterface(globalThis, 'WritableStreamDefaultController', WritableStreamDefaultController);
176-
exposeInterface(globalThis, 'ByteLengthQueuingStrategy', ByteLengthQueuingStrategy);
177-
exposeInterface(globalThis, 'CountQueuingStrategy', CountQueuingStrategy);
178-
exposeInterface(globalThis, 'TextEncoderStream', TextEncoderStream);
179-
exposeInterface(globalThis, 'TextDecoderStream', TextDecoderStream);
180-
exposeInterface(globalThis, 'CompressionStream', CompressionStream);
181-
exposeInterface(globalThis, 'DecompressionStream', DecompressionStream);
138+
exposeLazyInterfaces(
139+
globalThis,
140+
'internal/webstreams/compression',
141+
[
142+
'CompressionStream', 'DecompressionStream',
143+
]);

0 commit comments

Comments
 (0)