diff --git a/src/node.cc b/src/node.cc index 111b83bf70c016..9f8eac23342d7c 100644 --- a/src/node.cc +++ b/src/node.cc @@ -1304,45 +1304,48 @@ Local MakeCallback(Environment* env, Local MakeCallback(Isolate* isolate, - Local recv, - const char* method, - int argc, - Local argv[]) { + Local recv, + const char* method, + int argc, + Local argv[]) { EscapableHandleScope handle_scope(isolate); - Local context = recv->CreationContext(); - Environment* env = Environment::GetCurrent(context); - Context::Scope context_scope(context); + Local method_string = OneByteString(isolate, method); return handle_scope.Escape( - Local::New(isolate, MakeCallback(env, recv, method, argc, argv))); + MakeCallback(isolate, recv, method_string, argc, argv)); } Local MakeCallback(Isolate* isolate, - Local recv, - Local symbol, - int argc, - Local argv[]) { + Local recv, + Local symbol, + int argc, + Local argv[]) { EscapableHandleScope handle_scope(isolate); - Local context = recv->CreationContext(); - Environment* env = Environment::GetCurrent(context); - Context::Scope context_scope(context); - return handle_scope.Escape( - Local::New(isolate, MakeCallback(env, recv, symbol, argc, argv))); + Local callback_v = recv->Get(symbol); + if (callback_v.IsEmpty()) return Local(); + if (!callback_v->IsFunction()) return Local(); + Local callback = callback_v.As(); + return handle_scope.Escape(MakeCallback(isolate, recv, callback, argc, argv)); } Local MakeCallback(Isolate* isolate, - Local recv, - Local callback, - int argc, - Local argv[]) { + Local recv, + Local callback, + int argc, + Local argv[]) { + // Observe the following two subtleties: + // + // 1. The environment is retrieved from the callback function's context. + // 2. The context to enter is retrieved from the environment. + // + // Because of the AssignToContext() call in src/node_contextify.cc, + // the two contexts need not be the same. EscapableHandleScope handle_scope(isolate); - Local context = recv->CreationContext(); - Environment* env = Environment::GetCurrent(context); - Context::Scope context_scope(context); - return handle_scope.Escape(Local::New( - isolate, - MakeCallback(env, recv.As(), callback, argc, argv))); + Environment* env = Environment::GetCurrent(callback->CreationContext()); + Context::Scope context_scope(env->context()); + return handle_scope.Escape( + MakeCallback(env, recv.As(), callback, argc, argv)); } diff --git a/test/addons/make-callback/test.js b/test/addons/make-callback/test.js index 43ad014c4af478..b67d1146a6bf1b 100644 --- a/test/addons/make-callback/test.js +++ b/test/addons/make-callback/test.js @@ -36,6 +36,10 @@ const recv = { assert.strictEqual(42, makeCallback(recv, 'one')); assert.strictEqual(42, makeCallback(recv, 'two', 1337)); +// Check that callbacks on a receiver from a different context works. +const foreignObject = vm.runInNewContext('({ fortytwo() { return 42; } })'); +assert.strictEqual(42, makeCallback(foreignObject, 'fortytwo')); + // Check that the callback is made in the context of the receiver. const target = vm.runInNewContext(` (function($Object) {