diff --git a/src/node_perf.cc b/src/node_perf.cc index 1e1fe13d938566..da2405d3752012 100644 --- a/src/node_perf.cc +++ b/src/node_perf.cc @@ -310,7 +310,7 @@ void TimerFunctionCall(const FunctionCallbackInfo<Value>& args) { Isolate* isolate = args.GetIsolate(); HandleScope scope(isolate); Environment* env = Environment::GetCurrent(isolate); - CHECK_NOT_NULL(env); // TODO(addaleax): Verify that this is correct. + CHECK_NOT_NULL(env); Local<Context> context = env->context(); Local<Function> fn = args.Data().As<Function>(); size_t count = args.Length(); diff --git a/test/addons/non-node-context/binding.cc b/test/addons/non-node-context/binding.cc new file mode 100644 index 00000000000000..324f5c5a1ef16f --- /dev/null +++ b/test/addons/non-node-context/binding.cc @@ -0,0 +1,55 @@ +#include <node.h> +#include <assert.h> + +namespace { + +using v8::Context; +using v8::Function; +using v8::FunctionTemplate; +using v8::Isolate; +using v8::Local; +using v8::MaybeLocal; +using v8::NewStringType; +using v8::Object; +using v8::Script; +using v8::String; +using v8::Value; + +inline void RunInNewContext( + const v8::FunctionCallbackInfo<v8::Value>& args) { + Isolate* isolate = args.GetIsolate(); + Local<Context> context = Context::New(isolate); + Context::Scope context_scope(context); + + context->Global()->Set( + context, + String::NewFromUtf8(isolate, "data", NewStringType::kNormal) + .ToLocalChecked(), + args[1]).FromJust(); + + assert(args[0]->IsString()); // source code + Local<Script> script; + Local<Value> ret; + if (!Script::Compile(context, args[0].As<String>()).ToLocal(&script) || + !script->Run(context).ToLocal(&ret)) { + return; + } + + args.GetReturnValue().Set(ret); +} + +inline void Initialize(Local<Object> exports, + Local<Value> module, + Local<Context> context) { + Isolate* isolate = context->GetIsolate(); + Local<String> key = String::NewFromUtf8( + isolate, "runInNewContext", NewStringType::kNormal).ToLocalChecked(); + Local<Function> value = FunctionTemplate::New(isolate, RunInNewContext) + ->GetFunction(context) + .ToLocalChecked(); + assert(exports->Set(context, key, value).IsJust()); +} + +} // anonymous namespace + +NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize) diff --git a/test/addons/non-node-context/binding.gyp b/test/addons/non-node-context/binding.gyp new file mode 100644 index 00000000000000..b83bae308260f2 --- /dev/null +++ b/test/addons/non-node-context/binding.gyp @@ -0,0 +1,8 @@ +{ + 'targets': [ + { + 'target_name': 'binding', + 'sources': ['binding.cc'] + }, + ] +} diff --git a/test/addons/non-node-context/test-perf-hooks-timerify.js b/test/addons/non-node-context/test-perf-hooks-timerify.js new file mode 100644 index 00000000000000..10a9ab8064227e --- /dev/null +++ b/test/addons/non-node-context/test-perf-hooks-timerify.js @@ -0,0 +1,17 @@ +'use strict'; + +const common = require('../../common'); +const assert = require('assert'); +const { runInNewContext } = require(`./build/${common.buildType}/binding`); +const { performance } = require('perf_hooks'); + +// Check that performance.timerify() works when called from another context, +// for a function created in another context. + +const check = runInNewContext(` +const { performance, assert } = data; +const timerified = performance.timerify(function() { return []; }); +assert.strictEqual(timerified().constructor, Array); +'success'; +`, { performance, assert }); +assert.strictEqual(check, 'success');