aboutsummaryrefslogtreecommitdiff
path: root/lib/internal/bootstrap/loaders.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/internal/bootstrap/loaders.js')
-rw-r--r--lib/internal/bootstrap/loaders.js48
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);