diff --git a/src/api/callback.cc b/src/api/callback.cc index 217aebae9e16..43cbdf40aa5a 100644 --- a/src/api/callback.cc +++ b/src/api/callback.cc @@ -4,6 +4,8 @@ #include "node.h" #include "v8.h" +#include + namespace node { using v8::Context; @@ -112,9 +114,12 @@ InternalCallbackScope::InternalCallbackScope( isolate->SetIdle(false); - // The prior frame is usually undefined: no global handle then. - Local prior_context_frame = - async_context_frame::exchange(env, context_frame); + // The prior frame is usually undefined: no global handle then. Usually it + // is also the frame of the callback, and there is nothing to set. + Local prior_context_frame = async_context_frame::current(isolate); + if (prior_context_frame != context_frame) { + async_context_frame::set(env, context_frame); + } if (!prior_context_frame->IsUndefined()) { prior_context_frame_.Reset(isolate, prior_context_frame); } @@ -349,7 +354,14 @@ MaybeLocal InternalMakeCallback(Isolate* isolate, } Environment* env = Environment::GetCurrent(context); CHECK_NOT_NULL(env); - Context::Scope context_scope(env->context()); + // Entering the context changes nothing when it is already the entered and + // the current one, which is the common case for addons. + Local env_context = env->context(); + std::optional context_scope; + if (isolate->GetEnteredOrMicrotaskContext() != env_context || + isolate->GetCurrentContext() != env_context) { + context_scope.emplace(env_context); + } MaybeLocal ret = InternalMakeCallback( env, recv, recv, callback, argc, argv, asyncContext, context_frame); if (ret.IsEmpty() && env->async_callback_scope_depth() == 0) { diff --git a/src/env.cc b/src/env.cc index 1f8235598c85..7ec6c02cd655 100644 --- a/src/env.cc +++ b/src/env.cc @@ -133,7 +133,7 @@ void Environment::ResetPromiseHooks(Local init, void AsyncHooks::push_async_context( double async_id, double trigger_async_id, - std::variant*, Global*> resource) { + const std::variant*, Global*>& resource) { std::visit([](auto* ptr) { CHECK_IMPLIES(ptr != nullptr, !ptr->IsEmpty()); }, resource); @@ -161,9 +161,13 @@ void AsyncHooks::push_async_context( // False positive: https://github.com/cpplint/cpplint/issues/410 // NOLINTNEXTLINE(whitespace/newline) if (std::visit([](auto* ptr) { return ptr != nullptr; }, resource)) { - native_execution_async_resources_.resize(offset + 1); // Caveat: This is a v8::Local<>* assignment, we do not keep a v8::Global<>! - native_execution_async_resources_[offset] = resource; + if (native_execution_async_resources_.size() == offset) { + native_execution_async_resources_.push_back(resource); + } else { + native_execution_async_resources_.resize(offset + 1); + native_execution_async_resources_[offset] = resource; + } } } @@ -196,7 +200,11 @@ bool AsyncHooks::pop_async_context(double async_id) { native_execution_async_resources_[i]); } #endif - native_execution_async_resources_.resize(offset); + if (native_execution_async_resources_.size() == offset + 1) { + native_execution_async_resources_.pop_back(); + } else { + native_execution_async_resources_.resize(offset); + } native_execution_async_resources_.shrink_to_fit(); } diff --git a/src/env.h b/src/env.h index bbe417852e97..ad54cd1ea421 100644 --- a/src/env.h +++ b/src/env.h @@ -427,7 +427,7 @@ class AsyncHooks : public MemoryRetainer { void push_async_context( double async_id, double trigger_async_id, - std::variant*, v8::Global*> + const std::variant*, v8::Global*>& execution_async_resource); bool pop_async_context(double async_id); void clear_async_id_stack(); // Used in fatal exceptions.