31 #include "v8-profiler.h" 34 using v8::ArrayBuffer;
36 using v8::Float64Array;
38 using v8::FunctionCallbackInfo;
39 using v8::FunctionTemplate;
40 using v8::HandleScope;
41 using v8::HeapProfiler;
48 using v8::ObjectTemplate;
50 using v8::PromiseHookType;
51 using v8::PropertyCallbackInfo;
52 using v8::RetainedObjectInfo;
56 using v8::Uint32Array;
64 static const char*
const provider_names[] = {
67 NODE_ASYNC_PROVIDER_TYPES(
V)
86 const AsyncWrap* wrap_;
92 : label_(provider_names[class_id - NODE_ASYNC_ID_OFFSET]),
94 length_(wrap->self_size()) {
104 return label_ == other->GetLabel() &&
110 return reinterpret_cast<intptr_t
>(wrap_);
124 RetainedObjectInfo*
WrapperInfo(uint16_t class_id, Local<Value> wrapper) {
126 CHECK_GT(class_id, NODE_ASYNC_ID_OFFSET);
128 CHECK_LE(class_id - NODE_ASYNC_ID_OFFSET, AsyncWrap::PROVIDERS_LENGTH);
129 CHECK(wrapper->IsObject());
130 CHECK(!wrapper.IsEmpty());
132 Local<Object>
object = wrapper.As<Object>();
133 CHECK_GT(object->InternalFieldCount(), 0);
135 AsyncWrap*
wrap = Unwrap<AsyncWrap>(object);
136 CHECK_NE(
nullptr, wrap);
145 static void DestroyIdsCb(uv_timer_t* handle) {
146 Environment* env = Environment::from_destroy_ids_timer_handle(handle);
148 HandleScope handle_scope(env->isolate());
149 Context::Scope context_scope(env->context());
150 Local<Function> fn = env->async_hooks_destroy_function();
152 TryCatch try_catch(env->isolate());
155 std::vector<double> destroy_ids_list;
156 destroy_ids_list.swap(*env->destroy_ids_list());
157 for (
auto current_id : destroy_ids_list) {
160 HandleScope scope(env->isolate());
161 Local<Value> argv =
Number::New(env->isolate(), current_id);
162 MaybeLocal<Value> ret = fn->Call(
163 env->context(), Undefined(env->isolate()), 1, &argv);
171 }
while (!env->destroy_ids_list()->empty());
175 static void PushBackDestroyId(Environment* env,
double id) {
176 if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0)
179 if (env->destroy_ids_list()->empty())
180 uv_timer_start(env->destroy_ids_timer_handle(), DestroyIdsCb, 0, 0);
182 env->destroy_ids_list()->push_back(
id);
187 Local<Value> domain_v =
object->Get(env->domain_string());
188 if (domain_v->IsObject()) {
189 Local<Object> domain = domain_v.As<Object>();
190 if (domain->Get(env->disposed_string())->IsTrue())
192 Local<Value> enter_v = domain->Get(env->enter_string());
193 if (enter_v->IsFunction()) {
194 if (enter_v.As<Function>()->Call(domain, 0,
nullptr).IsEmpty()) {
196 "domain enter callback threw, please report this");
204 bool DomainExit(Environment* env, v8::Local<v8::Object>
object) {
205 Local<Value> domain_v =
object->Get(env->domain_string());
206 if (domain_v->IsObject()) {
207 Local<Object> domain = domain_v.As<Object>();
208 if (domain->Get(env->disposed_string())->IsTrue())
210 Local<Value> exit_v = domain->Get(env->exit_string());
211 if (exit_v->IsFunction()) {
212 if (exit_v.As<Function>()->Call(domain, 0,
nullptr).IsEmpty()) {
214 "domain exit callback threw, please report this");
222 void AsyncWrap::EmitBefore(Environment* env,
double async_id) {
225 if (async_hooks->fields()[AsyncHooks::kBefore] == 0)
229 Local<Function> fn = env->async_hooks_before_function();
230 TryCatch try_catch(env->isolate());
231 MaybeLocal<Value> ar = fn->Call(
232 env->context(), Undefined(env->isolate()), 1, &uid);
241 void AsyncWrap::EmitAfter(Environment* env,
double async_id) {
244 if (async_hooks->fields()[AsyncHooks::kAfter] == 0)
250 Local<Function> fn = env->async_hooks_after_function();
251 TryCatch try_catch(env->isolate());
252 MaybeLocal<Value> ar = fn->Call(
253 env->context(), Undefined(env->isolate()), 1, &uid);
264 : AsyncWrap(env, object, PROVIDER_PROMISE, silent) {
267 size_t self_size()
const override {
return sizeof(*this); }
269 static constexpr
int kPromiseField = 1;
270 static constexpr
int kParentIdField = 2;
271 static constexpr
int kInternalFieldCount = 3;
274 Local<Promise> promise,
277 static void GetPromise(Local<String> property,
278 const PropertyCallbackInfo<Value>& info);
279 static void GetParentId(Local<String> property,
280 const PropertyCallbackInfo<Value>& info);
284 Local<Promise> promise,
287 Local<Object>
object = env->promise_wrap_template()
288 ->NewInstance(env->context()).ToLocalChecked();
290 if (parent_wrap !=
nullptr) {
293 parent_wrap->get_id()));
295 CHECK_EQ(promise->GetAlignedPointerFromInternalField(0),
nullptr);
296 promise->SetInternalField(0,
object);
301 const PropertyCallbackInfo<Value>& info) {
302 info.GetReturnValue().Set(info.Holder()->GetInternalField(kPromiseField));
306 const PropertyCallbackInfo<Value>& info) {
307 info.GetReturnValue().Set(info.Holder()->GetInternalField(kParentIdField));
310 static void PromiseHook(PromiseHookType type, Local<Promise> promise,
311 Local<Value> parent,
void* arg) {
312 Environment* env =
static_cast<Environment*
>(arg);
313 Local<Value> resource_object_value = promise->GetInternalField(0);
315 if (resource_object_value->IsObject()) {
316 Local<Object> resource_object = resource_object_value.As<Object>();
317 wrap = Unwrap<PromiseWrap>(resource_object);
320 if (type == PromiseHookType::kInit || wrap ==
nullptr) {
321 bool silent = type != PromiseHookType::kInit;
325 if (parent->IsPromise()) {
329 Local<Promise> parent_promise = parent.As<Promise>();
330 Local<Value> parent_resource = parent_promise->GetInternalField(0);
331 if (parent_resource->IsObject()) {
332 parent_wrap = Unwrap<PromiseWrap>(parent_resource.As<Object>());
335 if (parent_wrap ==
nullptr) {
339 double trigger_id = parent_wrap->get_id();
340 env->set_init_trigger_id(trigger_id);
344 }
else if (type == PromiseHookType::kResolve) {
348 CHECK_NE(wrap,
nullptr);
349 if (type == PromiseHookType::kBefore) {
350 env->async_hooks()->push_ids(wrap->get_id(), wrap->get_trigger_id());
351 AsyncWrap::EmitBefore(wrap->env(), wrap->get_id());
352 }
else if (type == PromiseHookType::kAfter) {
353 AsyncWrap::EmitAfter(wrap->env(), wrap->get_id());
354 if (env->current_async_id() == wrap->get_id()) {
360 env->async_hooks()->pop_ids(wrap->get_id());
366 static void SetupHooks(
const FunctionCallbackInfo<Value>& args) {
367 Environment* env = Environment::GetCurrent(args);
369 if (!args[0]->IsObject())
370 return env->ThrowTypeError(
"first argument must be an object");
375 CHECK(env->async_hooks_init_function().IsEmpty());
377 Local<Object> fn_obj = args[0].As<Object>();
379 #define SET_HOOK_FN(name) \ 380 Local<Value> name##_v = fn_obj->Get( \ 382 FIXED_ONE_BYTE_STRING(env->isolate(), #name)).ToLocalChecked(); \ 383 CHECK(name##_v->IsFunction()); \ 384 env->set_async_hooks_##name##_function(name##_v.As<Function>()); 393 Local<FunctionTemplate> ctor =
395 ctor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(),
"PromiseWrap"));
396 Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
397 promise_wrap_template->SetInternalFieldCount(
399 promise_wrap_template->SetAccessor(
400 FIXED_ONE_BYTE_STRING(env->isolate(),
"promise"),
402 promise_wrap_template->SetAccessor(
403 FIXED_ONE_BYTE_STRING(env->isolate(),
"parentId"),
405 env->set_promise_wrap_template(promise_wrap_template);
410 static void EnablePromiseHook(
const FunctionCallbackInfo<Value>& args) {
411 Environment* env = Environment::GetCurrent(args);
412 env->AddPromiseHook(PromiseHook, static_cast<void*>(env));
416 static void DisablePromiseHook(
const FunctionCallbackInfo<Value>& args) {
417 Environment* env = Environment::GetCurrent(args);
421 env->isolate()->EnqueueMicrotask([](
void*
data) {
422 Environment* env =
static_cast<Environment*
>(
data);
423 env->RemovePromiseHook(PromiseHook, data);
424 },
static_cast<void*
>(env));
428 void AsyncWrap::GetAsyncId(
const FunctionCallbackInfo<Value>& args) {
430 args.GetReturnValue().Set(-1);
431 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
432 args.GetReturnValue().Set(wrap->get_id());
436 void AsyncWrap::PushAsyncIds(
const FunctionCallbackInfo<Value>& args) {
437 Environment* env = Environment::GetCurrent(args);
440 double async_id = args[0]->NumberValue(env->context()).FromJust();
441 double trigger_id = args[1]->NumberValue(env->context()).FromJust();
442 env->async_hooks()->push_ids(async_id, trigger_id);
446 void AsyncWrap::PopAsyncIds(
const FunctionCallbackInfo<Value>& args) {
447 Environment* env = Environment::GetCurrent(args);
448 double async_id = args[0]->NumberValue(env->context()).FromJust();
449 args.GetReturnValue().Set(env->async_hooks()->pop_ids(async_id));
453 void AsyncWrap::AsyncIdStackSize(
const FunctionCallbackInfo<Value>& args) {
454 Environment* env = Environment::GetCurrent(args);
455 args.GetReturnValue().Set(
456 static_cast<double>(env->async_hooks()->stack_size()));
460 void AsyncWrap::ClearIdStack(
const FunctionCallbackInfo<Value>& args) {
461 Environment* env = Environment::GetCurrent(args);
462 env->async_hooks()->clear_id_stack();
466 void AsyncWrap::AsyncReset(
const FunctionCallbackInfo<Value>& args) {
468 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
473 void AsyncWrap::QueueDestroyId(
const FunctionCallbackInfo<Value>& args) {
474 CHECK(args[0]->IsNumber());
475 PushBackDestroyId(Environment::GetCurrent(args), args[0]->NumberValue());
478 void AsyncWrap::AddWrapMethods(Environment* env,
479 Local<FunctionTemplate> constructor,
481 env->SetProtoMethod(constructor,
"getAsyncId", AsyncWrap::GetAsyncId);
482 if (flag & kFlagHasReset)
483 env->SetProtoMethod(constructor,
"asyncReset", AsyncWrap::AsyncReset);
488 Local<Context> context) {
489 Environment* env = Environment::GetCurrent(context);
490 Isolate* isolate = env->isolate();
491 HandleScope scope(isolate);
493 env->SetMethod(target,
"setupHooks", SetupHooks);
494 env->SetMethod(target,
"pushAsyncIds", PushAsyncIds);
495 env->SetMethod(target,
"popAsyncIds", PopAsyncIds);
496 env->SetMethod(target,
"asyncIdStackSize", AsyncIdStackSize);
497 env->SetMethod(target,
"clearIdStack", ClearIdStack);
498 env->SetMethod(target,
"addIdToDestroyList", QueueDestroyId);
499 env->SetMethod(target,
"enablePromiseHook", EnablePromiseHook);
500 env->SetMethod(target,
"disablePromiseHook", DisablePromiseHook);
502 v8::PropertyAttribute ReadOnlyDontDelete =
503 static_cast<v8::PropertyAttribute
>(v8::ReadOnly | v8::DontDelete);
505 #define FORCE_SET_TARGET_FIELD(obj, str, field) \ 506 (obj)->DefineOwnProperty(context, \ 507 FIXED_ONE_BYTE_STRING(isolate, str), \ 509 ReadOnlyDontDelete).FromJust() 515 uint32_t* fields_ptr = env->async_hooks()->fields();
516 int fields_count = env->async_hooks()->fields_count();
517 Local<ArrayBuffer> fields_ab =
532 double* uid_fields_ptr = env->async_hooks()->uid_fields();
533 int uid_fields_count = env->async_hooks()->uid_fields_count();
537 uid_fields_count *
sizeof(*uid_fields_ptr));
543 #define SET_HOOKS_CONSTANT(name) \ 544 FORCE_SET_TARGET_FIELD( \ 545 constants, #name, Integer::New(isolate, AsyncHooks::name)); 556 #undef SET_HOOKS_CONSTANT 559 Local<Object> async_providers =
Object::New(isolate);
561 FORCE_SET_TARGET_FIELD( \ 562 async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p)); 563 NODE_ASYNC_PROVIDER_TYPES(
V)
572 Symbol::New(isolate, FIXED_ONE_BYTE_STRING(isolate,
"asyncId")));
576 Symbol::New(isolate, FIXED_ONE_BYTE_STRING(isolate,
"triggerId")));
578 #undef FORCE_SET_TARGET_FIELD 580 env->set_async_hooks_init_function(Local<Function>());
581 env->set_async_hooks_before_function(Local<Function>());
582 env->set_async_hooks_after_function(Local<Function>());
583 env->set_async_hooks_destroy_function(Local<Function>());
588 HeapProfiler* heap_profiler = env->isolate()->GetHeapProfiler();
589 #define V(PROVIDER) \ 590 heap_profiler->SetWrapperClassInfoProvider( \ 591 (NODE_ASYNC_ID_OFFSET + AsyncWrap::PROVIDER_ ## PROVIDER), WrapperInfo); 592 NODE_ASYNC_PROVIDER_TYPES(
V)
597 AsyncWrap::AsyncWrap(Environment* env,
598 Local<Object>
object,
599 ProviderType provider,
601 : BaseObject(env,
object),
602 provider_type_(provider) {
603 CHECK_NE(provider, PROVIDER_NONE);
604 CHECK_GE(object->InternalFieldCount(), 1);
607 persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider);
614 AsyncWrap::~AsyncWrap() {
615 PushBackDestroyId(env(), get_id());
622 void AsyncWrap::AsyncReset(
bool silent) {
623 async_id_ = env()->new_async_id();
624 trigger_id_ = env()->get_init_trigger_id();
630 env()->async_hooks()->provider_string(provider_type()),
631 async_id_, trigger_id_);
636 Local<Object>
object,
640 CHECK(!
object.IsEmpty());
641 CHECK(!type.IsEmpty());
645 if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
649 HandleScope scope(env->isolate());
650 Local<Function> init_fn = env->async_hooks_init_function();
652 Local<Value> argv[] = {
659 TryCatch try_catch(env->isolate());
660 MaybeLocal<Value> ret = init_fn->Call(
661 env->context(), object, arraysize(argv), argv);
672 Local<Value>* argv) {
673 CHECK(env()->context() == env()->isolate()->GetCurrentContext());
675 Environment::AsyncCallbackScope callback_scope(env());
677 Environment::AsyncHooks::ExecScope exec_scope(env(),
683 if (env()->using_domains() &&
DomainEnter(env(),
object())) {
684 return Undefined(env()->isolate());
689 AsyncWrap::EmitBefore(env(), get_id());
691 MaybeLocal<Value> ret = cb->Call(env()->context(),
object(), argc, argv);
697 AsyncWrap::EmitAfter(env(), get_id());
701 if (env()->using_domains() &&
DomainExit(env(),
object())) {
702 return Undefined(env()->isolate());
705 exec_scope.Dispose();
707 if (callback_scope.in_makecallback()) {
711 Environment::TickInfo* tick_info = env()->tick_info();
713 if (tick_info->length() == 0) {
714 env()->isolate()->RunMicrotasks();
719 CHECK_EQ(env()->current_async_id(), 0);
720 CHECK_EQ(env()->trigger_id(), 0);
722 Local<Object> process = env()->process_object();
724 if (tick_info->length() == 0) {
725 tick_info->set_index(0);
729 MaybeLocal<Value> rcheck =
730 env()->tick_callback_function()->Call(env()->context(),
736 CHECK_EQ(env()->current_async_id(), 0);
737 CHECK_EQ(env()->trigger_id(), 0);
739 return rcheck.IsEmpty() ? MaybeLocal<Value>() : ret;
747 return Environment::GetCurrent(isolate)->current_async_id();
756 return Environment::GetCurrent(isolate)->trigger_id();
765 Local<Object> resource,
767 async_id trigger_async_id) {
768 Environment* env = Environment::GetCurrent(isolate);
771 if (trigger_async_id == -1)
772 trigger_async_id = env->get_init_trigger_id();
781 String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized)
790 PushBackDestroyId(Environment::GetCurrent(isolate), asyncContext.
async_id);
804 Local<Function> callback,
809 return MakeCallback(isolate, recv, callback, argc, argv,
810 {asyncId, triggerAsyncId});
821 {asyncId, triggerAsyncId});
826 Local<String> symbol,
832 {asyncId, triggerAsyncId});
839 Local<Object> resource,
842 return EmitAsyncInit__New(isolate,
RetainedObjectInfo * WrapperInfo(uint16_t class_id, Local< Value > wrapper)
void ClearFatalExceptionHandlers(Environment *env)
#define FORCE_SET_TARGET_FIELD(obj, str, field)
RetainedAsyncInfo(uint16_t class_id, AsyncWrap *wrap)
NODE_MODULE_CONTEXT_AWARE_BUILTIN(inspector, node::inspector::Agent::InitInspector)
async_id AsyncHooksGetTriggerId(Isolate *isolate)
size_t self_size() const override
void FatalException(Isolate *isolate, Local< Value > error, Local< Message > message)
async_context EmitAsyncInit(Isolate *isolate, Local< Object > resource, const char *name, async_id trigger_async_id)
static constexpr int kPromiseField
NO_RETURN void FatalError(const char *location, const char *message)
static void GetPromise(Local< String > property, const PropertyCallbackInfo< Value > &info)
union node::cares_wrap::@8::CaresAsyncData::@0 data
bool DomainEnter(Environment *env, Local< Object > object)
bool IsEquivalent(RetainedObjectInfo *other) override
async_id AsyncHooksGetExecutionAsyncId(Isolate *isolate)
static PromiseWrap * New(Environment *env, Local< Promise > promise, PromiseWrap *parent_wrap, bool silent)
intptr_t GetSizeInBytes() override
void Initialize(Local< Object > target, Local< Value > unused, Local< Context > context, void *priv)
static constexpr int kParentIdField
PromiseWrap(Environment *env, Local< Object > object, bool silent)
void EmitAsyncDestroy(Isolate *isolate, async_context asyncContext)
::node::async_id trigger_async_id
::node::async_id async_id
async_id AsyncHooksGetCurrentId(Isolate *isolate)
node::Environment::AsyncHooks AsyncHooks
MaybeLocal< Object > New(Isolate *isolate, Local< String > string, enum encoding enc)
MaybeLocal< Value > MakeCallback(Isolate *isolate, Local< Object > recv, Local< Function > callback, int argc, Local< Value > *argv, async_id asyncId, async_id triggerAsyncId)
void LoadAsyncWrapperInfo(Environment *env)
node::Environment::AsyncHooks AsyncHooks
bool DomainExit(Environment *env, v8::Local< v8::Object > object)
static constexpr int kInternalFieldCount
#define SET_HOOK_FN(name)
intptr_t GetHash() override
MaybeLocal< Value > MakeCallback(Isolate *isolate, Local< Object > recv, Local< String > symbol, int argc, Local< Value > *argv, async_id asyncId, async_id triggerAsyncId)
async_id AsyncHooksGetTriggerAsyncId(Isolate *isolate)
#define SET_HOOKS_CONSTANT(name)
static void GetParentId(Local< String > property, const PropertyCallbackInfo< Value > &info)
const char * GetLabel() override