Skip to content
Permalink
Browse files

vm: add Script.createCodeCache()

PR-URL: #20300
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: John-David Dalton <john.david.dalton@gmail.com>
Reviewed-By: Tiancheng "Timothy" Gu <timothygu99@gmail.com>
Reviewed-By: Yang Guo <yangguo@chromium.org>
  • Loading branch information...
devsnek authored and targos committed Apr 25, 2018
1 parent 9f2bf3c commit 4fc05ac7e1a8bf373ef3f0cc30eab4d48571f868
Showing with 87 additions and 2 deletions.
  1. +9 −0 doc/api/deprecations.md
  2. +32 −0 doc/api/vm.md
  3. +24 −2 src/node_contextify.cc
  4. +22 −0 test/parallel/test-vm-createcacheddata.js
@@ -993,6 +993,14 @@ because it also made sense to interpret the value as the number of bytes
read by the engine, but is inconsistent with other streams in Node.js that
expose values under these names.
<a id="DEP00XX"></a>
### DEP00XX: vm.Script cached data
Type: Documentation-only
The option `produceCachedData` has been deprecated. Use
[`script.createCachedData()`][] instead.
[`--pending-deprecation`]: cli.html#cli_pending_deprecation
[`Buffer.allocUnsafeSlow(size)`]: buffer.html#buffer_class_method_buffer_allocunsafeslow_size
[`Buffer.from(array)`]: buffer.html#buffer_class_method_buffer_from_array
@@ -1039,6 +1047,7 @@ expose values under these names.
[`process.env`]: process.html#process_process_env
[`punycode`]: punycode.html
[`require.extensions`]: modules.html#modules_require_extensions
[`script.createCachedData()`]: vm.html#vm_script_create_cached_data
[`setInterval()`]: timers.html#timers_setinterval_callback_delay_args
[`setTimeout()`]: timers.html#timers_settimeout_callback_delay_args
[`tls.CryptoStream`]: tls.html#tls_class_cryptostream
@@ -411,6 +411,10 @@ changes:
pr-url: https://github.com/nodejs/node/pull/4777
description: The `cachedData` and `produceCachedData` options are
supported now.
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/20300
description: The `produceCachedData` is deprecated in favour of
`script.createCachedData()`
-->

* `code` {string} The JavaScript code to compile.
@@ -431,11 +435,39 @@ changes:
`cachedData` property of the returned `vm.Script` instance.
The `cachedDataProduced` value will be set to either `true` or `false`
depending on whether code cache data is produced successfully.
This option is deprecated in favor of `script.createCachedData`.

Creating a new `vm.Script` object compiles `code` but does not run it. The
compiled `vm.Script` can be run later multiple times. The `code` is not bound to
any global object; rather, it is bound before each run, just for that run.

### script.createCachedData()
<!-- YAML
added: REPLACEME
-->

* Returns: {Buffer}

Creates a code cache that can be used with the Script constructor's
`cachedData` option. Returns a Buffer. This method may be called at any
time and any number of times.

```js
const script = new vm.Script(`
function add(a, b) {
return a + b;
}
const x = add(1, 2);
`);
const cacheWithoutX = script.createCachedData();
script.runInThisContext();
const cacheWithX = script.createCachedData();
```

### script.runInContext(contextifiedSandbox[, options])
<!-- YAML
added: v0.3.1
@@ -24,6 +24,7 @@
#include "base_object-inl.h"
#include "node_contextify.h"
#include "node_context_data.h"
#include "node_errors.h"

namespace node {
namespace contextify {
@@ -595,6 +596,7 @@ class ContextifyScript : public BaseObject {
Local<FunctionTemplate> script_tmpl = env->NewFunctionTemplate(New);
script_tmpl->InstanceTemplate()->SetInternalFieldCount(1);
script_tmpl->SetClassName(class_name);
env->SetProtoMethod(script_tmpl, "createCachedData", CreateCachedData);
env->SetProtoMethod(script_tmpl, "runInContext", RunInContext);
env->SetProtoMethod(script_tmpl, "runInThisContext", RunInThisContext);

@@ -636,7 +638,7 @@ class ContextifyScript : public BaseObject {
Local<Context> parsing_context = context;

if (argc > 2) {
// new ContextifyScript(code, filename, lineOffset, columnOffset
// new ContextifyScript(code, filename, lineOffset, columnOffset,
// cachedData, produceCachedData, parsingContext)
CHECK_EQ(argc, 7);
CHECK(args[2]->IsNumber());
@@ -718,7 +720,7 @@ class ContextifyScript : public BaseObject {
Boolean::New(isolate, source.GetCachedData()->rejected));
} else if (produce_cached_data) {
const ScriptCompiler::CachedData* cached_data =
ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked(), code);
ScriptCompiler::CreateCodeCache(v8_script.ToLocalChecked());
bool cached_data_produced = cached_data != nullptr;
if (cached_data_produced) {
MaybeLocal<Object> buf = Buffer::Copy(
@@ -744,6 +746,26 @@ class ContextifyScript : public BaseObject {
}


static void CreateCachedData(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
ContextifyScript* wrapped_script;
ASSIGN_OR_RETURN_UNWRAP(&wrapped_script, args.Holder());
Local<UnboundScript> unbound_script =
PersistentToLocal(env->isolate(), wrapped_script->script_);
std::unique_ptr<ScriptCompiler::CachedData> cached_data(
ScriptCompiler::CreateCodeCache(unbound_script));
if (!cached_data) {
args.GetReturnValue().Set(Buffer::New(env, 0).ToLocalChecked());
} else {
MaybeLocal<Object> buf = Buffer::Copy(
env,
reinterpret_cast<const char*>(cached_data->data),
cached_data->length);
args.GetReturnValue().Set(buf.ToLocalChecked());
}
}


static void RunInThisContext(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);

@@ -0,0 +1,22 @@
'use strict';

require('../common');

const { Script } = require('vm');
const assert = require('assert');

const source = 'function x() {} const y = x();';

const script = new Script(source);
let cachedData = script.createCachedData();
assert(cachedData instanceof Buffer);

assert(!new Script(source, { cachedData }).cachedDataRejected);

script.runInNewContext();

for (let i = 0; i < 10; i += 1) {
cachedData = script.createCachedData();

assert(!new Script(source, { cachedData }).cachedDataRejected);
}

0 comments on commit 4fc05ac

Please sign in to comment.
You can’t perform that action at this time.