Browse Source

vm: fix `produceCachedData`

Fix segmentation faults when compiling the same code with
`produceCachedData` option. V8 ignores the option when the code is in
its compilation cache and does not return cached data. Added
`cachedDataProduced` property to `v8.Script` to denote whether the
cached data is produced successfully.

PR-URL: https://github.com/nodejs/node/pull/5343
Reviewed-By: Fedor Indutny <fedor@indutny.com>
process-exit-stdio-flushing
Jiho Choi 9 years ago
committed by Fedor Indutny
parent
commit
d5c04c34f1
  1. 9
      doc/api/vm.markdown
  2. 1
      src/env.h
  3. 16
      src/node_contextify.cc
  4. 11
      test/parallel/test-vm-cached-data.js

9
doc/api/vm.markdown

@ -41,9 +41,12 @@ The options when creating a script are:
- `cachedData`: an optional `Buffer` with V8's code cache data for the supplied - `cachedData`: an optional `Buffer` with V8's code cache data for the supplied
source. When supplied `cachedDataRejected` value will be set to either source. When supplied `cachedDataRejected` value will be set to either
`true` or `false` depending on acceptance of the data by V8. `true` or `false` depending on acceptance of the data by V8.
- `produceCachedData`: if `true` and no `cachedData` is present - a `Buffer` - `produceCachedData`: if `true` and no `cachedData` is present - V8 tries to
with V8's code cache data will be produced and stored in `cachedData` property produce code cache data for `code`. Upon success, a `Buffer` with V8's code
of the returned `vm.Script` instance. cache data will be produced and stored in `cachedData` property of the
returned `vm.Script` instance. `cachedDataProduced` value will be set to
either `true` or `false` depending on whether code cache data is produced
successfully.
### script.runInContext(contextifiedSandbox[, options]) ### script.runInContext(contextifiedSandbox[, options])

1
src/env.h

@ -72,6 +72,7 @@ namespace node {
V(bytes_string, "bytes") \ V(bytes_string, "bytes") \
V(bytes_parsed_string, "bytesParsed") \ V(bytes_parsed_string, "bytesParsed") \
V(cached_data_string, "cachedData") \ V(cached_data_string, "cachedData") \
V(cached_data_produced_string, "cachedDataProduced") \
V(cached_data_rejected_string, "cachedDataRejected") \ V(cached_data_rejected_string, "cachedDataRejected") \
V(callback_string, "callback") \ V(callback_string, "callback") \
V(change_string, "change") \ V(change_string, "change") \

16
src/node_contextify.cc

@ -545,11 +545,17 @@ class ContextifyScript : public BaseObject {
Boolean::New(env->isolate(), source.GetCachedData()->rejected)); Boolean::New(env->isolate(), source.GetCachedData()->rejected));
} else if (compile_options == ScriptCompiler::kProduceCodeCache) { } else if (compile_options == ScriptCompiler::kProduceCodeCache) {
const ScriptCompiler::CachedData* cached_data = source.GetCachedData(); const ScriptCompiler::CachedData* cached_data = source.GetCachedData();
MaybeLocal<Object> buf = Buffer::Copy( bool cached_data_produced = cached_data != nullptr;
env, if (cached_data_produced) {
reinterpret_cast<const char*>(cached_data->data), MaybeLocal<Object> buf = Buffer::Copy(
cached_data->length); env,
args.This()->Set(env->cached_data_string(), buf.ToLocalChecked()); reinterpret_cast<const char*>(cached_data->data),
cached_data->length);
args.This()->Set(env->cached_data_string(), buf.ToLocalChecked());
}
args.This()->Set(
env->cached_data_produced_string(),
Boolean::New(env->isolate(), cached_data_produced));
} }
} }

11
test/parallel/test-vm-cached-data.js

@ -12,7 +12,7 @@ function produce(source) {
const script = new vm.Script(source, { const script = new vm.Script(source, {
produceCachedData: true produceCachedData: true
}); });
assert(script.cachedData instanceof Buffer); assert(!script.cachedDataProduced || script.cachedData instanceof Buffer);
return script.cachedData; return script.cachedData;
} }
@ -31,6 +31,15 @@ function testProduceConsume() {
} }
testProduceConsume(); testProduceConsume();
function testProduceMultiple() {
const source = getSource('original');
produce(source);
produce(source);
produce(source);
}
testProduceMultiple();
function testRejectInvalid() { function testRejectInvalid() {
const source = getSource('invalid'); const source = getSource('invalid');

Loading…
Cancel
Save