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 <matteo.collina@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Daeyeon Jeong <daeyeon.dev@gmail.com> Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Minwoo Jung <nodecorelab@gmail.com> Reviewed-By: Tierney Cyren <hello@bnb.im>
1 parent 75dbce9 commit e2caf7c

26 files changed

Lines changed: 321 additions & 367 deletions

‎lib/buffer.js‎

Lines changed: 13 additions & 13 deletions
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‎

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,6 @@ const {
5757

5858
constpathModule=require('path');
5959
const{ isArrayBufferView }=require('internal/util/types');
60-
constnonNativeWatcher=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-
constwatchers=require('internal/fs/watchers');
144-
constReadFileContext=require('internal/fs/read_file_context');
145-
146138
lettruncateWarn=true;
147139
letfs;
148140

@@ -379,6 +371,7 @@ function checkAborted(signal, callback) {
379371
functionreadFile(path,options,callback){
380372
callback=maybeCallback(callback||options);
381373
options=getOptions(options,{flag: 'r'});
374+
constReadFileContext=require('internal/fs/read_file_context');
382375
constcontext=newReadFileContext(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
letwatcher;
2301-
2294+
constwatchers=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+
constnonNativeWatcher=require('internal/fs/recursive_watch');
23062300
watcher=newnonNativeWatcher.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+
constwatchers=require('internal/fs/watchers');
23742368
if(stat===undefined){
23752369
stat=newwatchers.StatWatcher(options.bigint);
23762370
stat[watchers.kFSStatWatcherStart](filename,
@@ -2396,7 +2390,7 @@ function unwatchFile(filename, listener) {
23962390
conststat=statWatchers.get(filename);
23972391

23982392
if(stat===undefined)return;
2399-
2393+
constwatchers=require('internal/fs/watchers');
24002394
if(typeoflistener==='function'){
24012395
constbeforeListenerCount=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‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@ const {
1010

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

13-
constpromiseHooks=require('internal/promise_hooks');
14-
1513
constasync_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+
constpromiseHooks=require('internal/promise_hooks');
387386
stopPromiseHook=promiseHooks.createHook({
388387
init: initHook,
389388
before: promiseBeforeHook,

‎lib/internal/bootstrap/browser.js‎

Lines changed: 62 additions & 124 deletions
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
constconfig=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
consttimers=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-
constbuffer=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-
constperf_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
functioncreateGlobalConsole(){
8869
constconsoleFromNode=
@@ -120,86 +101,43 @@ function exposeGetterAndSetter(target, name, getter, setter = undefined) {
120101
});
121102
}
122103

123-
// https://webidl.spec.whatwg.org/#Replaceable
124-
functiondefineReplaceableAttribute(target,name,value){
125-
letslot=value;
126-
127-
// https://webidl.spec.whatwg.org/#dfn-attribute-getter
128-
functionget(){
129-
returnslot;
130-
}
131-
ObjectDefineProperty(get,'name',{
132-
__proto__: null,
133-
value: `get ${name}`,
134-
});
135-
136-
functionset(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)