diff options
Diffstat (limited to 'lib/internal/bootstrap/loaders.js')
-rw-r--r-- | lib/internal/bootstrap/loaders.js | 48 |
1 files changed, 37 insertions, 11 deletions
diff --git a/lib/internal/bootstrap/loaders.js b/lib/internal/bootstrap/loaders.js index e85d5de9b7..c04a4207c0 100644 --- a/lib/internal/bootstrap/loaders.js +++ b/lib/internal/bootstrap/loaders.js @@ -127,6 +127,8 @@ const config = getBinding('config'); const codeCache = getInternalBinding('code_cache'); + const codeCacheHash = getInternalBinding('code_cache_hash'); + const sourceHash = getInternalBinding('natives_hash'); const compiledWithoutCache = NativeModule.compiledWithoutCache = []; const compiledWithCache = NativeModule.compiledWithCache = []; @@ -232,32 +234,56 @@ }; NativeModule.prototype.compile = function() { - let source = NativeModule.getSource(this.id); + const id = this.id; + let source = NativeModule.getSource(id); source = NativeModule.wrap(source); this.loading = true; try { + // Currently V8 only checks that the length of the source code is the + // same as the code used to generate the hash, so we add an additional + // check here: + // 1. During compile time, when generating node_javascript.cc and + // node_code_cache.cc, we compute and include the hash of the + // (unwrapped) JavaScript source in both. + // 2. At runtime, we check that the hash of the code being compiled + // and the hash of the code used to generate the cache + // (inside the wrapper) is the same. + // This is based on the assumptions: + // 1. `internalBinding('code_cache_hash')` must be in sync with + // `internalBinding('code_cache')` (same C++ file) + // 2. `internalBinding('natives_hash')` must be in sync with + // `process.binding('natives')` (same C++ file) + // 3. If `internalBinding('natives_hash')` is in sync with + // `internalBinding('natives_hash')`, then the (unwrapped) + // code used to generate `internalBinding('code_cache')` + // should be in sync with the (unwrapped) code in + // `process.binding('natives')` + // There will be, however, false positives if the wrapper used + // to generate the cache is different from the one used at run time, + // and the length of the wrapper somehow stays the same. + // But that should be rare and can be eased once we make the + // two bootstrappers cached and checked as well. + const cache = codeCacheHash[id] && + (codeCacheHash[id] === sourceHash[id]) ? codeCache[id] : undefined; + // (code, filename, lineOffset, columnOffset // cachedData, produceCachedData, parsingContext) const script = new ContextifyScript( source, this.filename, 0, 0, - codeCache[this.id], false, undefined + cache, false, undefined ); + // This will be used to create code cache in tools/generate_code_cache.js this.script = script; // One of these conditions may be false when any of the inputs // of the `node_js2c` target in node.gyp is modified. - // FIXME(joyeecheung): - // 1. Figure out how to resolve the dependency issue. When the - // code cache was introduced we were at a point where refactoring - // node.gyp may not be worth the effort. - // 2. Calculate checksums in both js2c and generate_code_cache.js - // and compare them before compiling the native modules since - // V8 only checks the length of the source to decide whether to - // reject the cache. - if (!codeCache[this.id] || script.cachedDataRejected) { + // FIXME(joyeecheung): Figure out how to resolve the dependency issue. + // When the code cache was introduced we were at a point where refactoring + // node.gyp may not be worth the effort. + if (!cache || script.cachedDataRejected) { compiledWithoutCache.push(this.id); } else { compiledWithCache.push(this.id); |