Skip to content

Commit e2caf7c

Browse files
joyeecheungtargos
authored andcommitted
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: #45659 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 75dbce9 commit e2caf7c

26 files changed

+321
-367
lines changed

lib/buffer.js

+13-13
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ const {
7878
isInsideNodeModules,
7979
lazyDOMException,
8080
normalizeEncoding,
81-
kIsEncodingSymbol
81+
kIsEncodingSymbol,
82+
defineLazyProperties,
8283
} = require('internal/util');
8384
const {
8485
isAnyArrayBuffer,
@@ -121,15 +122,6 @@ const {
121122
createUnsafeBuffer
122123
} = require('internal/buffer');
123124

124-
const {
125-
Blob,
126-
resolveObjectURL,
127-
} = require('internal/blob');
128-
129-
const {
130-
File,
131-
} = require('internal/file');
132-
133125
FastBuffer.prototype.constructor = Buffer;
134126
Buffer.prototype = FastBuffer.prototype;
135127
addBufferPrototypeMethods(Buffer.prototype);
@@ -1323,9 +1315,6 @@ function atob(input) {
13231315
}
13241316

13251317
module.exports = {
1326-
Blob,
1327-
File,
1328-
resolveObjectURL,
13291318
Buffer,
13301319
SlowBuffer,
13311320
transcode,
@@ -1352,3 +1341,14 @@ ObjectDefineProperties(module.exports, {
13521341
set(val) { INSPECT_MAX_BYTES = val; }
13531342
}
13541343
});
1344+
1345+
defineLazyProperties(
1346+
module.exports,
1347+
'internal/blob',
1348+
['Blob', 'resolveObjectURL']
1349+
);
1350+
defineLazyProperties(
1351+
module.exports,
1352+
'internal/file',
1353+
['File']
1354+
);

lib/fs.js

+12-15
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ const {
5757

5858
const pathModule = require('path');
5959
const { isArrayBufferView } = require('internal/util/types');
60-
const nonNativeWatcher = require('internal/fs/recursive_watch');
6160

6261
// We need to get the statValues from the binding at the callsite since
6362
// it's re-initialized after deserialization.
@@ -84,6 +83,7 @@ const {
8483
custom: kCustomPromisifiedSymbol,
8584
},
8685
SideEffectFreeRegExpPrototypeExec,
86+
defineLazyProperties,
8787
} = require('internal/util');
8888
const {
8989
constants: {
@@ -119,11 +119,6 @@ const {
119119
validateStringAfterArrayBufferView,
120120
warnOnNonPortableTemplate
121121
} = require('internal/fs/utils');
122-
const {
123-
Dir,
124-
opendir,
125-
opendirSync
126-
} = require('internal/fs/dir');
127122
const {
128123
CHAR_FORWARD_SLASH,
129124
CHAR_BACKWARD_SLASH,
@@ -140,9 +135,6 @@ const {
140135
validateString,
141136
} = require('internal/validators');
142137

143-
const watchers = require('internal/fs/watchers');
144-
const ReadFileContext = require('internal/fs/read_file_context');
145-
146138
let truncateWarn = true;
147139
let fs;
148140

@@ -379,6 +371,7 @@ function checkAborted(signal, callback) {
379371
function readFile(path, options, callback) {
380372
callback = maybeCallback(callback || options);
381373
options = getOptions(options, { flag: 'r' });
374+
const ReadFileContext = require('internal/fs/read_file_context');
382375
const context = new ReadFileContext(callback, options.encoding);
383376
context.isUserFd = isFd(path); // File descriptor ownership
384377

@@ -2298,11 +2291,12 @@ function watch(filename, options, listener) {
22982291
if (options.recursive === undefined) options.recursive = false;
22992292

23002293
let watcher;
2301-
2294+
const watchers = require('internal/fs/watchers');
23022295
// TODO(anonrig): Remove non-native watcher when/if libuv supports recursive.
23032296
// As of November 2022, libuv does not support recursive file watch on all platforms,
23042297
// e.g. Linux due to the limitations of inotify.
23052298
if (options.recursive && !isOSX && !isWindows) {
2299+
const nonNativeWatcher = require('internal/fs/recursive_watch');
23062300
watcher = new nonNativeWatcher.FSWatcher(options);
23072301
watcher[watchers.kFSWatchStart](filename);
23082302
} else {
@@ -2370,7 +2364,7 @@ function watchFile(filename, options, listener) {
23702364
validateFunction(listener, 'listener');
23712365

23722366
stat = statWatchers.get(filename);
2373-
2367+
const watchers = require('internal/fs/watchers');
23742368
if (stat === undefined) {
23752369
stat = new watchers.StatWatcher(options.bigint);
23762370
stat[watchers.kFSStatWatcherStart](filename,
@@ -2396,7 +2390,7 @@ function unwatchFile(filename, listener) {
23962390
const stat = statWatchers.get(filename);
23972391

23982392
if (stat === undefined) return;
2399-
2393+
const watchers = require('internal/fs/watchers');
24002394
if (typeof listener === 'function') {
24012395
const beforeListenerCount = stat.listenerCount('change');
24022396
stat.removeListener('change', listener);
@@ -3000,8 +2994,6 @@ module.exports = fs = {
30002994
mkdtempSync,
30012995
open,
30022996
openSync,
3003-
opendir,
3004-
opendirSync,
30052997
readdir,
30062998
readdirSync,
30072999
read,
@@ -3039,7 +3031,6 @@ module.exports = fs = {
30393031
writeSync,
30403032
writev,
30413033
writevSync,
3042-
Dir,
30433034
Dirent,
30443035
Stats,
30453036

@@ -3085,6 +3076,12 @@ module.exports = fs = {
30853076
_toUnixTimestamp: toUnixTimestamp
30863077
};
30873078

3079+
defineLazyProperties(
3080+
fs,
3081+
'internal/fs/dir',
3082+
['Dir', 'opendir', 'opendirSync']
3083+
);
3084+
30883085
ObjectDefineProperties(fs, {
30893086
F_OK: { __proto__: null, enumerable: true, value: F_OK || 0 },
30903087
R_OK: { __proto__: null, enumerable: true, value: R_OK || 0 },

lib/internal/async_hooks.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ const {
1010

1111
const { exitCodes: { kGenericUserError } } = internalBinding('errors');
1212

13-
const promiseHooks = require('internal/promise_hooks');
14-
1513
const async_wrap = internalBinding('async_wrap');
1614
const { setCallbackTrampoline } = async_wrap;
1715
/* async_hook_fields is a Uint32Array wrapping the uint32_t array of
@@ -384,6 +382,7 @@ function updatePromiseHookMode() {
384382
initHook = destroyTracking;
385383
}
386384
if (stopPromiseHook) stopPromiseHook();
385+
const promiseHooks = require('internal/promise_hooks');
387386
stopPromiseHook = promiseHooks.createHook({
388387
init: initHook,
389388
before: promiseBeforeHook,

lib/internal/bootstrap/browser.js

+62-124
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,61 +31,39 @@ exposeGetterAndSetter(globalThis,
2831
exposeInterface(globalThis, 'DOMException', value);
2932
});
3033

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

68-
const buffer = require('buffer');
69-
defineOperation(globalThis, 'atob', buffer.atob);
70-
defineOperation(globalThis, 'btoa', buffer.btoa);
71-
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']);
7252
// https://www.w3.org/TR/FileAPI/#dfn-Blob
73-
exposeInterface(globalThis, 'Blob', buffer.Blob);
74-
53+
exposeLazyInterfaces(globalThis, 'internal/blob', ['Blob']);
7554
// https://www.w3.org/TR/hr-time-2/#the-performance-attribute
76-
const perf_hooks = require('perf_hooks');
77-
exposeInterface(globalThis, 'Performance', perf_hooks.Performance);
78-
exposeInterface(globalThis, 'PerformanceEntry', perf_hooks.PerformanceEntry);
79-
exposeInterface(globalThis, 'PerformanceMark', perf_hooks.PerformanceMark);
80-
exposeInterface(globalThis, 'PerformanceMeasure', perf_hooks.PerformanceMeasure);
81-
exposeInterface(globalThis, 'PerformanceObserver', perf_hooks.PerformanceObserver);
82-
exposeInterface(globalThis, 'PerformanceObserverEntryList', perf_hooks.PerformanceObserverEntryList);
83-
exposeInterface(globalThis, 'PerformanceResourceTiming', perf_hooks.PerformanceResourceTiming);
84-
defineReplaceableAttribute(globalThis, 'performance',
85-
perf_hooks.performance);
55+
exposeLazyInterfaces(globalThis, 'perf_hooks', [
56+
'Performance', 'PerformanceEntry', 'PerformanceMark', 'PerformanceMeasure',
57+
'PerformanceObserver', 'PerformanceObserverEntryList', 'PerformanceResourceTiming',
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']);
8667

8768
function createGlobalConsole() {
8869
const consoleFromNode =
@@ -120,86 +101,43 @@ function exposeGetterAndSetter(target, name, getter, setter = undefined) {
120101
});
121102
}
122103

123-
// https://webidl.spec.whatwg.org/#Replaceable
124-
function defineReplaceableAttribute(target, name, value) {
125-
let slot = value;
126-
127-
// https://webidl.spec.whatwg.org/#dfn-attribute-getter
128-
function get() {
129-
return slot;
130-
}
131-
ObjectDefineProperty(get, 'name', {
132-
__proto__: null,
133-
value: `get ${name}`,
134-
});
135-
136-
function set(value) {
137-
slot = value;
138-
}
139-
ObjectDefineProperty(set, 'name', {
140-
__proto__: null,
141-
value: `set ${name}`,
142-
});
143-
144-
ObjectDefineProperty(target, name, {
145-
__proto__: null,
146-
enumerable: true,
147-
configurable: true,
148-
get,
149-
set,
150-
});
151-
}
152-
153104
// Web Streams API
154-
const {
155-
TransformStream,
156-
TransformStreamDefaultController,
157-
} = require('internal/webstreams/transformstream');
158-
159-
const {
160-
WritableStream,
161-
WritableStreamDefaultController,
162-
WritableStreamDefaultWriter,
163-
} = require('internal/webstreams/writablestream');
105+
exposeLazyInterfaces(
106+
globalThis,
107+
'internal/webstreams/transformstream',
108+
['TransformStream', 'TransformStreamDefaultController']);
164109

165-
const {
166-
ReadableStream,
167-
ReadableStreamDefaultReader,
168-
ReadableStreamBYOBReader,
169-
ReadableStreamBYOBRequest,
170-
ReadableByteStreamController,
171-
ReadableStreamDefaultController,
172-
} = require('internal/webstreams/readablestream');
110+
exposeLazyInterfaces(
111+
globalThis,
112+
'internal/webstreams/writablestream',
113+
['WritableStream', 'WritableStreamDefaultController', 'WritableStreamDefaultWriter']);
173114

174-
const {
175-
ByteLengthQueuingStrategy,
176-
CountQueuingStrategy,
177-
} = 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+
]);
178130

179-
const {
180-
TextEncoderStream,
181-
TextDecoderStream,
182-
} = require('internal/webstreams/encoding');
131+
exposeLazyInterfaces(
132+
globalThis,
133+
'internal/webstreams/encoding',
134+
[
135+
'TextEncoderStream', 'TextDecoderStream',
136+
]);
183137

184-
const {
185-
CompressionStream,
186-
DecompressionStream,
187-
} = require('internal/webstreams/compression');
188-
189-
exposeInterface(globalThis, 'ReadableStream', ReadableStream);
190-
exposeInterface(globalThis, 'ReadableStreamDefaultReader', ReadableStreamDefaultReader);
191-
exposeInterface(globalThis, 'ReadableStreamBYOBReader', ReadableStreamBYOBReader);
192-
exposeInterface(globalThis, 'ReadableStreamBYOBRequest', ReadableStreamBYOBRequest);
193-
exposeInterface(globalThis, 'ReadableByteStreamController', ReadableByteStreamController);
194-
exposeInterface(globalThis, 'ReadableStreamDefaultController', ReadableStreamDefaultController);
195-
exposeInterface(globalThis, 'TransformStream', TransformStream);
196-
exposeInterface(globalThis, 'TransformStreamDefaultController', TransformStreamDefaultController);
197-
exposeInterface(globalThis, 'WritableStream', WritableStream);
198-
exposeInterface(globalThis, 'WritableStreamDefaultWriter', WritableStreamDefaultWriter);
199-
exposeInterface(globalThis, 'WritableStreamDefaultController', WritableStreamDefaultController);
200-
exposeInterface(globalThis, 'ByteLengthQueuingStrategy', ByteLengthQueuingStrategy);
201-
exposeInterface(globalThis, 'CountQueuingStrategy', CountQueuingStrategy);
202-
exposeInterface(globalThis, 'TextEncoderStream', TextEncoderStream);
203-
exposeInterface(globalThis, 'TextDecoderStream', TextDecoderStream);
204-
exposeInterface(globalThis, 'CompressionStream', CompressionStream);
205-
exposeInterface(globalThis, 'DecompressionStream', DecompressionStream);
138+
exposeLazyInterfaces(
139+
globalThis,
140+
'internal/webstreams/compression',
141+
[
142+
'CompressionStream', 'DecompressionStream',
143+
]);

0 commit comments

Comments
 (0)