Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v8: introduce v8.emitCodeGenFromStringEvent() #34863

Closed
wants to merge 2 commits into from
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
30 changes: 30 additions & 0 deletions doc/api/v8.md
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,36 @@ added: v8.0.0
A subclass of [`Deserializer`][] corresponding to the format written by
[`DefaultSerializer`][].

## `v8.emitCodeGenFromStringEvent()`
<!-- YAML
added: REPLACEME
-->

After this methode is called, calling `eval(code)` or `new Function(code)`
will emit a `codeGenerationFromString` event on `process` with the value
of `code`. The call to `eval` or `new Function` will happen after the
event is emitted.

Calls to the `vm` module such as `vm.runInContext` will not emit the event.

Calling `v8.emitCodeGenFromStringEvent()` when the
`--disallow-code-generation-from-strings` flag is used will be a noop.

```js
const v8 = require('v8');
v8.emitCodeGenFromStringEvent();
process.on('codeGenerationFromString', (code) => {
console.log('Generating code from string`', code, '`');
});
const item = { foo: 0 };
eval('item.foo++');
```

will log
```text
Generating code from string` item.foo++ `
```

[`Buffer`]: buffer.html
[`DefaultDeserializer`]: #v8_class_v8_defaultdeserializer
[`DefaultSerializer`]: #v8_class_v8_defaultserializer
Expand Down
2 changes: 2 additions & 0 deletions lib/v8.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class Deserializer extends _Deserializer { }

const {
cachedDataVersionTag,
emitCodeGenFromStringEvent,
setFlagsFromString: _setFlagsFromString,
heapStatisticsBuffer,
heapSpaceStatisticsBuffer,
Expand Down Expand Up @@ -265,6 +266,7 @@ function deserialize(buffer) {

module.exports = {
cachedDataVersionTag,
emitCodeGenFromStringEvent,
getHeapSnapshot,
getHeapStatistics,
getHeapSpaceStatistics,
Expand Down
27 changes: 27 additions & 0 deletions src/node_v8.cc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "memory_tracker-inl.h"
#include "util-inl.h"
#include "v8.h"
#include "node_process.h"

namespace node {

Expand Down Expand Up @@ -167,6 +168,29 @@ void SetFlagsFromString(const FunctionCallbackInfo<Value>& args) {
V8::SetFlagsFromString(*flags, static_cast<size_t>(flags.length()));
}

static v8::ModifyCodeGenerationFromStringsResult CodeGenCallback(
Local<Context> context,
Local<Value> source) {
Environment* env = Environment::GetCurrent(context);
ProcessEmit(env, "codeGenerationFromString", source);
// expected signature is {bool, Local<Value>} but {bool} is also valid and
// fallbacks on the original argument.
return {true};
}

static void EmitCodeGenFromStringEvent(
const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = args.GetIsolate();
Local<Context> context = env->context();

// This only makes sense if code generation from string is allowed.
if (context->IsCodeGenerationFromStringsAllowed()) {
// V8 requires that this is set to false for it to call the callback
context->AllowCodeGenerationFromStrings(false);
isolate->SetModifyCodeGenerationFromStringsCallback(CodeGenCallback);
}
}

void Initialize(Local<Object> target,
Local<Value> unused,
Expand All @@ -180,6 +204,9 @@ void Initialize(Local<Object> target,
env->SetMethodNoSideEffect(target, "cachedDataVersionTag",
CachedDataVersionTag);

env->SetMethod(
target, "emitCodeGenFromStringEvent", EmitCodeGenFromStringEvent);

// Export symbols used by v8.getHeapStatistics()
env->SetMethod(
target, "updateHeapStatisticsBuffer", UpdateHeapStatisticsBuffer);
Expand Down
23 changes: 23 additions & 0 deletions test/parallel/test-v8-codegen-from-string.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const v8 = require('v8');

const beforeSetupHandler =
common.mustNotCall('called before v8.emitCodeGenFromStringEvent()');

process.on('codeGenerationFromString', beforeSetupHandler);

const item = { foo: 0 };
eval('++item.foo');
process.off('codeGenerationFromString', beforeSetupHandler);

assert.strictEqual(item.foo, 1);

v8.emitCodeGenFromStringEvent();
process.on('codeGenerationFromString', common.mustCall((code) => {
assert.strictEqual(code, 'item.foo++');
}));

eval('item.foo++');
assert.strictEqual(item.foo, 2);