vm: add Script.createCodeCache() by devsnek · Pull Request #20300 · nodejs/node · GitHub
Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/api/deprecations.md
32 changes: 32 additions & 0 deletions doc/api/vm.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

favour -> favor

`script.createCachedData()`

This comment was marked as resolved.

-->

* `code` {string} The JavaScript code to compile.
Expand All @@ -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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Script in backticks?

`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
Expand Down
26 changes: 24 additions & 2 deletions src/node_contextify.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "base_object-inl.h"
#include "node_contextify.h"
#include "node_context_data.h"
#include "node_errors.h"

namespace node {
namespace contextify {
Expand Down Expand Up @@ -596,6 +597,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);

Expand Down Expand Up @@ -637,7 +639,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());
Expand Down Expand Up @@ -719,7 +721,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(
Expand All @@ -745,6 +747,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());

This comment was marked as resolved.

@joyeecheung joyeecheung Jun 13, 2018

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be a good idea to throw ERR_BUFFER_TOO_LARGE if cached_data->length > Buffer::kMaxLength before Buffer::Copy and ERR_MEMORY_ALLOCATION_FAILED if buf.IsEmpty() is true instead of doing buf.ToLocalChecked()

}
}


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

Expand Down
22 changes: 22 additions & 0 deletions test/parallel/test-vm-createcacheddata.js