vm: allow cachedData to also be TypedArray|DataView

PR-URL: https://github.com/nodejs/node/pull/22921
Refs: https://github.com/nodejs/node/issues/1826
Refs: https://github.com/nodejs/node/pull/22921#issuecomment-422350213
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Refael Ackermann <refack@gmail.com>
This commit is contained in:
Benjamin Chen 2018-09-18 01:28:41 -04:00 committed by Refael Ackermann
parent 74ba48294b
commit 65fe999ed7
5 changed files with 37 additions and 29 deletions

View File

@ -434,10 +434,10 @@ changes:
in stack traces produced by this script. in stack traces produced by this script.
* `columnOffset` {number} Specifies the column number offset that is displayed * `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script. in stack traces produced by this script.
* `cachedData` {Buffer} Provides an optional `Buffer` with V8's code cache * `cachedData` {Buffer|TypedArray|DataView} Provides an optional `Buffer` or
data for the supplied source. When supplied, the `cachedDataRejected` value `TypedArray`, or `DataView` with V8's code cache data for the supplied
will be set to either `true` or `false` depending on acceptance of the data source. When supplied, the `cachedDataRejected` value will be set to
by V8. either `true` or `false` depending on acceptance of the data by V8.
* `produceCachedData` {boolean} When `true` and no `cachedData` is present, V8 * `produceCachedData` {boolean} When `true` and no `cachedData` is present, V8
will attempt to produce code cache data for `code`. Upon success, a will attempt to produce code cache data for `code`. Upon success, a
`Buffer` with V8's code cache data will be produced and stored in the `Buffer` with V8's code cache data will be produced and stored in the
@ -669,8 +669,9 @@ added: v10.10.0
in stack traces produced by this script. **Default:** `0`. in stack traces produced by this script. **Default:** `0`.
* `columnOffset` {number} Specifies the column number offset that is displayed * `columnOffset` {number} Specifies the column number offset that is displayed
in stack traces produced by this script. **Default:** `0`. in stack traces produced by this script. **Default:** `0`.
* `cachedData` {Buffer} Provides an optional `Buffer` with V8's code cache * `cachedData` {Buffer|TypedArray|DataView} Provides an optional `Buffer` or
data for the supplied source. `TypedArray`, or `DataView` with V8's code cache data for the supplied
source.
* `produceCachedData` {boolean} Specifies whether to produce new cache data. * `produceCachedData` {boolean} Specifies whether to produce new cache data.
**Default:** `false`. **Default:** `false`.
* `parsingContext` {Object} The [contextified][] sandbox in which the said * `parsingContext` {Object} The [contextified][] sandbox in which the said

View File

@ -32,7 +32,7 @@ const {
ERR_INVALID_ARG_TYPE, ERR_INVALID_ARG_TYPE,
ERR_VM_MODULE_NOT_MODULE, ERR_VM_MODULE_NOT_MODULE,
} = require('internal/errors').codes; } = require('internal/errors').codes;
const { isModuleNamespaceObject, isUint8Array } = require('util').types; const { isModuleNamespaceObject, isArrayBufferView } = require('util').types;
const { validateInt32, validateUint32 } = require('internal/validators'); const { validateInt32, validateUint32 } = require('internal/validators');
const kParsingContext = Symbol('script parsing context'); const kParsingContext = Symbol('script parsing context');
@ -64,9 +64,12 @@ class Script extends ContextifyScript {
} }
validateInt32(lineOffset, 'options.lineOffset'); validateInt32(lineOffset, 'options.lineOffset');
validateInt32(columnOffset, 'options.columnOffset'); validateInt32(columnOffset, 'options.columnOffset');
if (cachedData !== undefined && !isUint8Array(cachedData)) { if (cachedData !== undefined && !isArrayBufferView(cachedData)) {
throw new ERR_INVALID_ARG_TYPE('options.cachedData', throw new ERR_INVALID_ARG_TYPE(
['Buffer', 'Uint8Array'], cachedData); 'options.cachedData',
['Buffer', 'TypedArray', 'DataView'],
cachedData
);
} }
if (typeof produceCachedData !== 'boolean') { if (typeof produceCachedData !== 'boolean') {
throw new ERR_INVALID_ARG_TYPE('options.produceCachedData', 'boolean', throw new ERR_INVALID_ARG_TYPE('options.produceCachedData', 'boolean',
@ -346,10 +349,10 @@ function compileFunction(code, params, options = {}) {
} }
validateUint32(columnOffset, 'options.columnOffset'); validateUint32(columnOffset, 'options.columnOffset');
validateUint32(lineOffset, 'options.lineOffset'); validateUint32(lineOffset, 'options.lineOffset');
if (cachedData !== undefined && !isUint8Array(cachedData)) { if (cachedData !== undefined && !isArrayBufferView(cachedData)) {
throw new ERR_INVALID_ARG_TYPE( throw new ERR_INVALID_ARG_TYPE(
'options.cachedData', 'options.cachedData',
'Uint8Array', ['Buffer', 'TypedArray', 'DataView'],
cachedData cachedData
); );
} }

View File

@ -33,6 +33,7 @@ namespace contextify {
using v8::Array; using v8::Array;
using v8::ArrayBuffer; using v8::ArrayBuffer;
using v8::ArrayBufferView;
using v8::Boolean; using v8::Boolean;
using v8::Context; using v8::Context;
using v8::EscapableHandleScope; using v8::EscapableHandleScope;
@ -64,7 +65,6 @@ using v8::String;
using v8::Symbol; using v8::Symbol;
using v8::TryCatch; using v8::TryCatch;
using v8::Uint32; using v8::Uint32;
using v8::Uint8Array;
using v8::UnboundScript; using v8::UnboundScript;
using v8::Value; using v8::Value;
using v8::WeakCallbackInfo; using v8::WeakCallbackInfo;
@ -629,7 +629,7 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
Local<Integer> line_offset; Local<Integer> line_offset;
Local<Integer> column_offset; Local<Integer> column_offset;
Local<Uint8Array> cached_data_buf; Local<ArrayBufferView> cached_data_buf;
bool produce_cached_data = false; bool produce_cached_data = false;
Local<Context> parsing_context = context; Local<Context> parsing_context = context;
@ -642,8 +642,8 @@ void ContextifyScript::New(const FunctionCallbackInfo<Value>& args) {
CHECK(args[3]->IsNumber()); CHECK(args[3]->IsNumber());
column_offset = args[3].As<Integer>(); column_offset = args[3].As<Integer>();
if (!args[4]->IsUndefined()) { if (!args[4]->IsUndefined()) {
CHECK(args[4]->IsUint8Array()); CHECK(args[4]->IsArrayBufferView());
cached_data_buf = args[4].As<Uint8Array>(); cached_data_buf = args[4].As<ArrayBufferView>();
} }
CHECK(args[5]->IsBoolean()); CHECK(args[5]->IsBoolean());
produce_cached_data = args[5]->IsTrue(); produce_cached_data = args[5]->IsTrue();
@ -994,10 +994,10 @@ void ContextifyContext::CompileFunction(
Local<Integer> column_offset = args[3].As<Integer>(); Local<Integer> column_offset = args[3].As<Integer>();
// Argument 5: cached data (optional) // Argument 5: cached data (optional)
Local<Uint8Array> cached_data_buf; Local<ArrayBufferView> cached_data_buf;
if (!args[4]->IsUndefined()) { if (!args[4]->IsUndefined()) {
CHECK(args[4]->IsUint8Array()); CHECK(args[4]->IsArrayBufferView());
cached_data_buf = args[4].As<Uint8Array>(); cached_data_buf = args[4].As<ArrayBufferView>();
} }
// Argument 6: produce cache data // Argument 6: produce cache data

View File

@ -178,18 +178,20 @@ const vm = require('vm');
'filename': 'string', 'filename': 'string',
'columnOffset': 'number', 'columnOffset': 'number',
'lineOffset': 'number', 'lineOffset': 'number',
'cachedData': 'Uint8Array', 'cachedData': 'Buffer, TypedArray, or DataView',
'produceCachedData': 'boolean', 'produceCachedData': 'boolean',
}; };
for (const option in optionTypes) { for (const option in optionTypes) {
const typeErrorMessage = `The "options.${option}" property must be ` +
`${option === 'cachedData' ? 'one of' : 'of'} type`;
common.expectsError(() => { common.expectsError(() => {
vm.compileFunction('', undefined, { [option]: null }); vm.compileFunction('', undefined, { [option]: null });
}, { }, {
type: TypeError, type: TypeError,
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
message: `The "options.${option}" property must be of type ` + message: typeErrorMessage +
`${optionTypes[option]}. Received type object` ` ${optionTypes[option]}. Received type object`
}); });
} }

View File

@ -41,12 +41,14 @@ function testProduceConsume() {
const data = produce(source); const data = produce(source);
for (const cachedData of common.getArrayBufferViews(data)) {
// It should consume code cache // It should consume code cache
const script = new vm.Script(source, { const script = new vm.Script(source, {
cachedData: data cachedData
}); });
assert(!script.cachedDataRejected); assert(!script.cachedDataRejected);
assert.strictEqual(script.runInThisContext()(), 'original'); assert.strictEqual(script.runInThisContext()(), 'original');
}
} }
testProduceConsume(); testProduceConsume();
@ -91,5 +93,5 @@ common.expectsError(() => {
}, { }, {
code: 'ERR_INVALID_ARG_TYPE', code: 'ERR_INVALID_ARG_TYPE',
type: TypeError, type: TypeError,
message: /must be one of type Buffer or Uint8Array/ message: /must be one of type Buffer, TypedArray, or DataView/
}); });