Skip to content

Commit 62024b6

Browse files
joyeecheungtargos
authored andcommitted
build: create V8 code cache after script is run
This patch makes it possible to generate the code cache for the builtins directly from the original script object (instead of compiling a new one) and after the script has been run (via `NativeModule.require`). Before this patch only the top level functions (the wrapped ones) are included in the cache, after this patch the inner functions in those modules will be included as well. Also blacklists modules from dependencies like V8 and node-inspect since we cannot guarantee that they are suitable to be executed directly. PR-URL: #21567 Refs: #21563 Reviewed-By: James M Snell <[email protected]> Reviewed-By: Tiancheng "Timothy" Gu <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: John-David Dalton <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
1 parent 67d7a15 commit 62024b6

File tree

4 files changed

+55
-35
lines changed

4 files changed

+55
-35
lines changed

lib/internal/bootstrap/cache.js

+38-11
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,50 @@ const {
99
NativeModule, internalBinding
1010
} = require('internal/bootstrap/loaders');
1111

12+
function getCodeCache(id) {
13+
const cached = NativeModule.getCached(id);
14+
if (cached && (cached.loaded || cached.loading)) {
15+
return cached.script.createCachedData();
16+
}
17+
18+
// The script has not been compiled and run
19+
NativeModule.require(id);
20+
return getCodeCache(id);
21+
}
22+
23+
const depsModule = Object.keys(NativeModule._source).filter(
24+
(key) => NativeModule.isDepsModule(key) || key.startsWith('internal/deps')
25+
);
26+
27+
// Modules with source code compiled in js2c that
28+
// cannot be compiled with the code cache
29+
const cannotUseCache = [
30+
'config',
31+
'sys', // deprecated
32+
'internal/v8_prof_polyfill',
33+
'internal/v8_prof_processor',
34+
35+
'internal/per_context',
36+
37+
'internal/test/binding',
38+
// TODO(joyeecheung): update the C++ side so that
39+
// the code cache is also used when compiling these
40+
// two files.
41+
'internal/bootstrap/loaders',
42+
'internal/bootstrap/node'
43+
].concat(depsModule);
44+
1245
module.exports = {
46+
cachableBuiltins: Object.keys(NativeModule._source).filter(
47+
(key) => !cannotUseCache.includes(key)
48+
),
1349
builtinSource: Object.assign({}, NativeModule._source),
50+
getCodeCache,
1451
codeCache: internalBinding('code_cache'),
1552
compiledWithoutCache: NativeModule.compiledWithoutCache,
1653
compiledWithCache: NativeModule.compiledWithCache,
1754
nativeModuleWrap(script) {
1855
return NativeModule.wrap(script);
1956
},
20-
// Modules with source code compiled in js2c that
21-
// cannot be compiled with the code cache
22-
cannotUseCache: [
23-
'config',
24-
// TODO(joyeecheung): update the C++ side so that
25-
// the code cache is also used when compiling these
26-
// two files.
27-
'internal/bootstrap/loaders',
28-
'internal/bootstrap/node',
29-
'internal/per_context',
30-
]
57+
cannotUseCache
3158
};

lib/internal/bootstrap/loaders.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
this.exportKeys = undefined;
119119
this.loaded = false;
120120
this.loading = false;
121+
this.script = null; // The ContextifyScript of the module
121122
}
122123

123124
NativeModule._source = getBinding('natives');
@@ -165,11 +166,14 @@
165166
return nativeModule.exports;
166167
};
167168

169+
NativeModule.isDepsModule = function(id) {
170+
return id.startsWith('node-inspect/') || id.startsWith('v8/');
171+
};
172+
168173
NativeModule.requireForDeps = function(id) {
169174
if (!NativeModule.exists(id) ||
170175
// TODO(TimothyGu): remove when DEP0084 reaches end of life.
171-
id.startsWith('node-inspect/') ||
172-
id.startsWith('v8/')) {
176+
NativeModule.isDepsModule(id)) {
173177
id = `internal/deps/${id}`;
174178
}
175179
return NativeModule.require(id);
@@ -241,6 +245,8 @@
241245
codeCache[this.id], false, undefined
242246
);
243247

248+
this.script = script;
249+
244250
// One of these conditions may be false when any of the inputs
245251
// of the `node_js2c` target in node.gyp is modified.
246252
// FIXME(joyeecheung):

test/code-cache/test-code-cache.js

+2-4
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@ const {
1212
}
1313
} = require('util');
1414
const {
15-
builtinSource,
15+
cachableBuiltins,
1616
codeCache,
17-
cannotUseCache,
1817
compiledWithCache,
1918
compiledWithoutCache
2019
} = require('internal/bootstrap/cache');
@@ -35,8 +34,7 @@ for (const key of loadedModules) {
3534
`"${key}" should've been compiled with code cache`);
3635
}
3736

38-
for (const key of Object.keys(builtinSource)) {
39-
if (cannotUseCache.includes(key)) continue;
37+
for (const key of cachableBuiltins) {
4038
assert(isUint8Array(codeCache[key]) && codeCache[key].length > 0,
4139
`Code cache for "${key}" should've been generated`);
4240
}

tools/generate_code_cache.js

+7-18
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@
88
// of `configure`.
99

1010
const {
11-
nativeModuleWrap,
12-
builtinSource,
13-
cannotUseCache
11+
getCodeCache,
12+
cachableBuiltins
1413
} = require('internal/bootstrap/cache');
1514

16-
const vm = require('vm');
1715
const fs = require('fs');
1816

1917
const resultPath = process.argv[2];
@@ -72,25 +70,16 @@ const cacheInitializers = [];
7270
let totalCacheSize = 0;
7371

7472

75-
for (const key of Object.keys(builtinSource)) {
76-
if (cannotUseCache.includes(key)) continue;
77-
const code = nativeModuleWrap(builtinSource[key]);
78-
79-
// Note that this must corresponds to the code in
80-
// NativeModule.prototype.compile
81-
const script = new vm.Script(code, {
82-
filename: `${key}.js`,
83-
produceCachedData: true
84-
});
85-
86-
if (!script.cachedData) {
73+
for (const key of cachableBuiltins) {
74+
const cachedData = getCodeCache(key);
75+
if (!cachedData.length) {
8776
console.error(`Failed to generate code cache for '${key}'`);
8877
process.exit(1);
8978
}
9079

91-
const length = script.cachedData.length;
80+
const length = cachedData.length;
9281
totalCacheSize += length;
93-
const { definition, initializer } = getInitalizer(key, script.cachedData);
82+
const { definition, initializer } = getInitalizer(key, cachedData);
9483
cacheDefinitions.push(definition);
9584
cacheInitializers.push(initializer);
9685
console.log(`Generated cache for '${key}', size = ${formatSize(length)}` +

0 commit comments

Comments
 (0)