mirror of
https://github.com/nodejs/node.git
synced 2026-11-09 15:11:11 -05:00
AsyncResource saves the async context frame when it is created, and MakeCallback() enters it with async_context_frame::Scope. Then node::MakeCallback() opens the callback scope with an undefined frame, so the callback never runs in the saved one. Since AsyncContextFrame is the default, AsyncLocalStorage loses its store in these callbacks. Pass the saved frame to InternalMakeCallback(), as the Node-API AsyncContext already does. This also removes the Scope from every call, with its two Environment lookups and its global handle. Refs: https://github.com/nodejs/node/pull/66316 Refs: https://github.com/nodejs/node/issues/43038 Refs: https://github.com/nodejs/performance/issues/24 Signed-off-by: Nigro Simone <nigro.simone@gmail.com> PR-URL: https://github.com/nodejs/node/pull/66326 Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Chengzhong Wu <legendecas@gmail.com>
103 lines
3.4 KiB
C++
103 lines
3.4 KiB
C++
#include "async_context_frame.h"
|
|
#include "env-inl.h"
|
|
#include "node.h"
|
|
#include "node_internals.h"
|
|
|
|
namespace node {
|
|
|
|
using v8::Function;
|
|
using v8::Isolate;
|
|
using v8::Local;
|
|
using v8::MaybeLocal;
|
|
using v8::Object;
|
|
using v8::String;
|
|
using v8::Undefined;
|
|
using v8::Value;
|
|
|
|
AsyncResource::AsyncResource(Isolate* isolate,
|
|
Local<Object> resource,
|
|
const char* name,
|
|
async_id trigger_async_id)
|
|
: AsyncResource(
|
|
isolate, resource, std::string_view(name), trigger_async_id) {}
|
|
|
|
AsyncResource::AsyncResource(Isolate* isolate,
|
|
Local<Object> resource,
|
|
std::string_view name,
|
|
async_id trigger_async_id)
|
|
: env_(Environment::GetCurrent(isolate)),
|
|
resource_(isolate, resource),
|
|
context_frame_(isolate, async_context_frame::current(isolate)) {
|
|
CHECK_NOT_NULL(env_);
|
|
async_context_ = EmitAsyncInit(isolate, resource, name, trigger_async_id);
|
|
}
|
|
|
|
AsyncResource::~AsyncResource() {
|
|
CHECK_NOT_NULL(env_);
|
|
EmitAsyncDestroy(env_, async_context_);
|
|
}
|
|
|
|
MaybeLocal<Value> AsyncResource::MakeCallback(Local<Function> callback,
|
|
int argc,
|
|
Local<Value>* argv) {
|
|
auto isolate = env_->isolate();
|
|
// As in Node-API: node::MakeCallback() would run it with no frame.
|
|
return InternalMakeCallback(isolate,
|
|
get_resource(),
|
|
callback,
|
|
argc,
|
|
argv,
|
|
async_context_,
|
|
context_frame_.Get(isolate));
|
|
}
|
|
|
|
MaybeLocal<Value> AsyncResource::MakeCallback(const char* method,
|
|
int argc,
|
|
Local<Value>* argv) {
|
|
Local<String> method_string;
|
|
if (!String::NewFromUtf8(env_->isolate(), method).ToLocal(&method_string)) {
|
|
return {};
|
|
}
|
|
return MakeCallback(method_string, argc, argv);
|
|
}
|
|
|
|
MaybeLocal<Value> AsyncResource::MakeCallback(Local<String> symbol,
|
|
int argc,
|
|
Local<Value>* argv) {
|
|
auto isolate = env_->isolate();
|
|
// Check can_call_into_js() first because calling Get() might do so.
|
|
if (!env_->can_call_into_js()) return {};
|
|
Local<Value> callback;
|
|
{
|
|
// A getter runs in the saved frame too, so what it enters stays there.
|
|
async_context_frame::Scope async_context_frame_scope(
|
|
isolate, context_frame_.Get(isolate));
|
|
if (!get_resource()
|
|
->Get(isolate->GetCurrentContext(), symbol)
|
|
.ToLocal(&callback)) {
|
|
return {};
|
|
}
|
|
}
|
|
if (!callback->IsFunction()) return Undefined(isolate);
|
|
return MakeCallback(callback.As<Function>(), argc, argv);
|
|
}
|
|
|
|
Local<Object> AsyncResource::get_resource() {
|
|
return resource_.Get(env_->isolate());
|
|
}
|
|
|
|
async_id AsyncResource::get_async_id() const {
|
|
return async_context_.async_id;
|
|
}
|
|
|
|
async_id AsyncResource::get_trigger_async_id() const {
|
|
return async_context_.trigger_async_id;
|
|
}
|
|
|
|
AsyncResource::CallbackScope::CallbackScope(AsyncResource* res)
|
|
: node::CallbackScope(res->env_,
|
|
res->resource_.Get(res->env_->isolate()),
|
|
res->async_context_) {}
|
|
|
|
} // namespace node
|