1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22#include "async_wrap.h" // NOLINT(build/include_inline) 23#include "async_wrap-inl.h" 24#include "env-inl.h" 25#include "node_errors.h" 26#include "node_external_reference.h" 27#include "tracing/traced_value.h" 28#include "util-inl.h" 29 30#include "v8.h" 31 32using v8::Context; 33using v8::DontDelete; 34using v8::EscapableHandleScope; 35using v8::Function; 36using v8::FunctionCallbackInfo; 37using v8::FunctionTemplate; 38using v8::Global; 39using v8::HandleScope; 40using v8::Integer; 41using v8::Isolate; 42using v8::Local; 43using v8::MaybeLocal; 44using v8::Nothing; 45using v8::Number; 46using v8::Object; 47using v8::PropertyAttribute; 48using v8::ReadOnly; 49using v8::String; 50using v8::Undefined; 51using v8::Value; 52using v8::WeakCallbackInfo; 53using v8::WeakCallbackType; 54 55using TryCatchScope = node::errors::TryCatchScope; 56 57namespace node { 58 59static const char* const provider_names[] = { 60#define V(PROVIDER) \ 61 #PROVIDER, 62 NODE_ASYNC_PROVIDER_TYPES(V) 63#undef V 64}; 65 66void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) { 67 Local<Function> fn = env->async_hooks_destroy_function(); 68 69 TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal); 70 71 do { 72 std::vector<double> destroy_async_id_list; 73 destroy_async_id_list.swap(*env->destroy_async_id_list()); 74 if (!env->can_call_into_js()) return; 75 for (auto async_id : destroy_async_id_list) { 76 // Want each callback to be cleaned up after itself, instead of cleaning 77 // them all up after the while() loop completes. 78 HandleScope scope(env->isolate()); 79 Local<Value> async_id_value = Number::New(env->isolate(), async_id); 80 MaybeLocal<Value> ret = fn->Call( 81 env->context(), Undefined(env->isolate()), 1, &async_id_value); 82 83 if (ret.IsEmpty()) 84 return; 85 } 86 } while (!env->destroy_async_id_list()->empty()); 87} 88 89void Emit(Environment* env, double async_id, AsyncHooks::Fields type, 90 Local<Function> fn) { 91 AsyncHooks* async_hooks = env->async_hooks(); 92 93 if (async_hooks->fields()[type] == 0 || !env->can_call_into_js()) 94 return; 95 96 HandleScope handle_scope(env->isolate()); 97 Local<Value> async_id_value = Number::New(env->isolate(), async_id); 98 TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal); 99 USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value)); 100} 101 102 103void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) { 104 Emit(env, async_id, AsyncHooks::kPromiseResolve, 105 env->async_hooks_promise_resolve_function()); 106} 107 108 109void AsyncWrap::EmitTraceEventBefore() { 110 switch (provider_type()) { 111#define V(PROVIDER) \ 112 case PROVIDER_ ## PROVIDER: \ 113 TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( \ 114 TRACING_CATEGORY_NODE1(async_hooks), \ 115 #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id())); \ 116 break; 117 NODE_ASYNC_PROVIDER_TYPES(V) 118#undef V 119 default: 120 UNREACHABLE(); 121 } 122} 123 124 125void AsyncWrap::EmitBefore(Environment* env, double async_id) { 126 Emit(env, async_id, AsyncHooks::kBefore, 127 env->async_hooks_before_function()); 128} 129 130 131void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) { 132 switch (type) { 133#define V(PROVIDER) \ 134 case PROVIDER_ ## PROVIDER: \ 135 TRACE_EVENT_NESTABLE_ASYNC_END0( \ 136 TRACING_CATEGORY_NODE1(async_hooks), \ 137 #PROVIDER "_CALLBACK", static_cast<int64_t>(async_id)); \ 138 break; 139 NODE_ASYNC_PROVIDER_TYPES(V) 140#undef V 141 default: 142 UNREACHABLE(); 143 } 144} 145 146 147void AsyncWrap::EmitAfter(Environment* env, double async_id) { 148 // If the user's callback failed then the after() hooks will be called at the 149 // end of _fatalException(). 150 Emit(env, async_id, AsyncHooks::kAfter, 151 env->async_hooks_after_function()); 152} 153 154static void SetupHooks(const FunctionCallbackInfo<Value>& args) { 155 Environment* env = Environment::GetCurrent(args); 156 157 CHECK(args[0]->IsObject()); 158 159 // All of init, before, after, destroy, and promise_resolve are supplied by 160 // async_hooks internally, so this should only ever be called once. At which 161 // time all the functions should be set. Detect this by checking if 162 // init !IsEmpty(). 163 CHECK(env->async_hooks_init_function().IsEmpty()); 164 165 Local<Object> fn_obj = args[0].As<Object>(); 166 167#define SET_HOOK_FN(name) \ 168 do { \ 169 Local<Value> v = \ 170 fn_obj->Get(env->context(), \ 171 FIXED_ONE_BYTE_STRING(env->isolate(), #name)) \ 172 .ToLocalChecked(); \ 173 CHECK(v->IsFunction()); \ 174 env->set_async_hooks_##name##_function(v.As<Function>()); \ 175 } while (0) 176 177 SET_HOOK_FN(init); 178 SET_HOOK_FN(before); 179 SET_HOOK_FN(after); 180 SET_HOOK_FN(destroy); 181 SET_HOOK_FN(promise_resolve); 182#undef SET_HOOK_FN 183} 184 185static void SetPromiseHooks(const FunctionCallbackInfo<Value>& args) { 186 Environment* env = Environment::GetCurrent(args); 187 188 env->ResetPromiseHooks( 189 args[0]->IsFunction() ? args[0].As<Function>() : Local<Function>(), 190 args[1]->IsFunction() ? args[1].As<Function>() : Local<Function>(), 191 args[2]->IsFunction() ? args[2].As<Function>() : Local<Function>(), 192 args[3]->IsFunction() ? args[3].As<Function>() : Local<Function>()); 193} 194 195class DestroyParam { 196 public: 197 double asyncId; 198 Environment* env; 199 Global<Object> target; 200 Global<Object> propBag; 201}; 202 203static void DestroyParamCleanupHook(void* ptr) { 204 delete static_cast<DestroyParam*>(ptr); 205} 206 207void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) { 208 HandleScope scope(info.GetIsolate()); 209 210 std::unique_ptr<DestroyParam> p{info.GetParameter()}; 211 Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(), 212 p->propBag); 213 Local<Value> val; 214 215 p->env->RemoveCleanupHook(DestroyParamCleanupHook, p.get()); 216 217 if (!prop_bag.IsEmpty() && 218 !prop_bag->Get(p->env->context(), p->env->destroyed_string()) 219 .ToLocal(&val)) { 220 return; 221 } 222 223 if (val.IsEmpty() || val->IsFalse()) { 224 AsyncWrap::EmitDestroy(p->env, p->asyncId); 225 } 226 // unique_ptr goes out of scope here and pointer is deleted. 227} 228 229 230static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) { 231 CHECK(args[0]->IsObject()); 232 CHECK(args[1]->IsNumber()); 233 CHECK(args.Length() == 2 || args[2]->IsObject()); 234 235 Isolate* isolate = args.GetIsolate(); 236 DestroyParam* p = new DestroyParam(); 237 p->asyncId = args[1].As<Number>()->Value(); 238 p->env = Environment::GetCurrent(args); 239 p->target.Reset(isolate, args[0].As<Object>()); 240 if (args.Length() > 2) { 241 p->propBag.Reset(isolate, args[2].As<Object>()); 242 } 243 p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter); 244 p->env->AddCleanupHook(DestroyParamCleanupHook, p); 245} 246 247void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) { 248 AsyncWrap* wrap; 249 args.GetReturnValue().Set(kInvalidAsyncId); 250 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 251 args.GetReturnValue().Set(wrap->get_async_id()); 252} 253 254 255void AsyncWrap::PushAsyncContext(const FunctionCallbackInfo<Value>& args) { 256 Environment* env = Environment::GetCurrent(args); 257 // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail 258 // then the checks in push_async_ids() and pop_async_id() will. 259 double async_id = args[0]->NumberValue(env->context()).FromJust(); 260 double trigger_async_id = args[1]->NumberValue(env->context()).FromJust(); 261 env->async_hooks()->push_async_context(async_id, trigger_async_id, {}); 262} 263 264 265void AsyncWrap::PopAsyncContext(const FunctionCallbackInfo<Value>& args) { 266 Environment* env = Environment::GetCurrent(args); 267 double async_id = args[0]->NumberValue(env->context()).FromJust(); 268 args.GetReturnValue().Set(env->async_hooks()->pop_async_context(async_id)); 269} 270 271 272void AsyncWrap::ExecutionAsyncResource( 273 const FunctionCallbackInfo<Value>& args) { 274 Environment* env = Environment::GetCurrent(args); 275 uint32_t index; 276 if (!args[0]->Uint32Value(env->context()).To(&index)) return; 277 args.GetReturnValue().Set( 278 env->async_hooks()->native_execution_async_resource(index)); 279} 280 281 282void AsyncWrap::ClearAsyncIdStack(const FunctionCallbackInfo<Value>& args) { 283 Environment* env = Environment::GetCurrent(args); 284 env->async_hooks()->clear_async_id_stack(); 285} 286 287 288void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) { 289 CHECK(args[0]->IsObject()); 290 291 AsyncWrap* wrap; 292 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 293 294 Local<Object> resource = args[0].As<Object>(); 295 double execution_async_id = 296 args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId; 297 wrap->AsyncReset(resource, execution_async_id); 298} 299 300 301void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) { 302 AsyncWrap* wrap; 303 args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE); 304 ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); 305 args.GetReturnValue().Set(wrap->provider_type()); 306} 307 308 309void AsyncWrap::EmitDestroy(bool from_gc) { 310 AsyncWrap::EmitDestroy(env(), async_id_); 311 // Ensure no double destroy is emitted via AsyncReset(). 312 async_id_ = kInvalidAsyncId; 313 314 if (!persistent().IsEmpty() && !from_gc) { 315 HandleScope handle_scope(env()->isolate()); 316 USE(object()->Set(env()->context(), env()->resource_symbol(), object())); 317 } 318} 319 320void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) { 321 CHECK(args[0]->IsNumber()); 322 AsyncWrap::EmitDestroy( 323 Environment::GetCurrent(args), 324 args[0].As<Number>()->Value()); 325} 326 327void AsyncWrap::SetCallbackTrampoline(const FunctionCallbackInfo<Value>& args) { 328 Environment* env = Environment::GetCurrent(args); 329 330 if (args[0]->IsFunction()) { 331 env->set_async_hooks_callback_trampoline(args[0].As<Function>()); 332 } else { 333 env->set_async_hooks_callback_trampoline(Local<Function>()); 334 } 335} 336 337Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) { 338 Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template(); 339 if (tmpl.IsEmpty()) { 340 Isolate* isolate = env->isolate(); 341 tmpl = NewFunctionTemplate(isolate, nullptr); 342 tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap")); 343 tmpl->Inherit(BaseObject::GetConstructorTemplate(env)); 344 SetProtoMethod(isolate, tmpl, "getAsyncId", AsyncWrap::GetAsyncId); 345 SetProtoMethod(isolate, tmpl, "asyncReset", AsyncWrap::AsyncReset); 346 SetProtoMethod( 347 isolate, tmpl, "getProviderType", AsyncWrap::GetProviderType); 348 env->set_async_wrap_ctor_template(tmpl); 349 } 350 return tmpl; 351} 352 353void AsyncWrap::Initialize(Local<Object> target, 354 Local<Value> unused, 355 Local<Context> context, 356 void* priv) { 357 Environment* env = Environment::GetCurrent(context); 358 Isolate* isolate = env->isolate(); 359 HandleScope scope(isolate); 360 361 SetMethod(context, target, "setupHooks", SetupHooks); 362 SetMethod(context, target, "setCallbackTrampoline", SetCallbackTrampoline); 363 SetMethod(context, target, "pushAsyncContext", PushAsyncContext); 364 SetMethod(context, target, "popAsyncContext", PopAsyncContext); 365 SetMethod(context, target, "executionAsyncResource", ExecutionAsyncResource); 366 SetMethod(context, target, "clearAsyncIdStack", ClearAsyncIdStack); 367 SetMethod(context, target, "queueDestroyAsyncId", QueueDestroyAsyncId); 368 SetMethod(context, target, "setPromiseHooks", SetPromiseHooks); 369 SetMethod(context, target, "registerDestroyHook", RegisterDestroyHook); 370 371 PropertyAttribute ReadOnlyDontDelete = 372 static_cast<PropertyAttribute>(ReadOnly | DontDelete); 373 374#define FORCE_SET_TARGET_FIELD(obj, str, field) \ 375 (obj)->DefineOwnProperty(context, \ 376 FIXED_ONE_BYTE_STRING(isolate, str), \ 377 field, \ 378 ReadOnlyDontDelete).FromJust() 379 380 // Attach the uint32_t[] where each slot contains the count of the number of 381 // callbacks waiting to be called on a particular event. It can then be 382 // incremented/decremented from JS quickly to communicate to C++ if there are 383 // any callbacks waiting to be called. 384 FORCE_SET_TARGET_FIELD(target, 385 "async_hook_fields", 386 env->async_hooks()->fields().GetJSArray()); 387 388 // The following v8::Float64Array has 5 fields. These fields are shared in 389 // this way to allow JS and C++ to read/write each value as quickly as 390 // possible. The fields are represented as follows: 391 // 392 // kAsyncIdCounter: Maintains the state of the next unique id to be assigned. 393 // 394 // kDefaultTriggerAsyncId: Write the id of the resource responsible for a 395 // handle's creation just before calling the new handle's constructor. 396 // After the new handle is constructed kDefaultTriggerAsyncId is set back 397 // to kInvalidAsyncId. 398 FORCE_SET_TARGET_FIELD(target, 399 "async_id_fields", 400 env->async_hooks()->async_id_fields().GetJSArray()); 401 402 FORCE_SET_TARGET_FIELD(target, 403 "execution_async_resources", 404 env->async_hooks()->js_execution_async_resources()); 405 406 target->Set(context, 407 env->async_ids_stack_string(), 408 env->async_hooks()->async_ids_stack().GetJSArray()).Check(); 409 410 Local<Object> constants = Object::New(isolate); 411#define SET_HOOKS_CONSTANT(name) \ 412 FORCE_SET_TARGET_FIELD( \ 413 constants, #name, Integer::New(isolate, AsyncHooks::name)) 414 415 SET_HOOKS_CONSTANT(kInit); 416 SET_HOOKS_CONSTANT(kBefore); 417 SET_HOOKS_CONSTANT(kAfter); 418 SET_HOOKS_CONSTANT(kDestroy); 419 SET_HOOKS_CONSTANT(kPromiseResolve); 420 SET_HOOKS_CONSTANT(kTotals); 421 SET_HOOKS_CONSTANT(kCheck); 422 SET_HOOKS_CONSTANT(kExecutionAsyncId); 423 SET_HOOKS_CONSTANT(kTriggerAsyncId); 424 SET_HOOKS_CONSTANT(kAsyncIdCounter); 425 SET_HOOKS_CONSTANT(kDefaultTriggerAsyncId); 426 SET_HOOKS_CONSTANT(kUsesExecutionAsyncResource); 427 SET_HOOKS_CONSTANT(kStackLength); 428#undef SET_HOOKS_CONSTANT 429 FORCE_SET_TARGET_FIELD(target, "constants", constants); 430 431 Local<Object> async_providers = Object::New(isolate); 432#define V(p) \ 433 FORCE_SET_TARGET_FIELD( \ 434 async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p)); 435 NODE_ASYNC_PROVIDER_TYPES(V) 436#undef V 437 FORCE_SET_TARGET_FIELD(target, "Providers", async_providers); 438 439#undef FORCE_SET_TARGET_FIELD 440 441 env->set_async_hooks_init_function(Local<Function>()); 442 env->set_async_hooks_before_function(Local<Function>()); 443 env->set_async_hooks_after_function(Local<Function>()); 444 env->set_async_hooks_destroy_function(Local<Function>()); 445 env->set_async_hooks_promise_resolve_function(Local<Function>()); 446 env->set_async_hooks_callback_trampoline(Local<Function>()); 447 env->set_async_hooks_binding(target); 448} 449 450void AsyncWrap::RegisterExternalReferences( 451 ExternalReferenceRegistry* registry) { 452 registry->Register(SetupHooks); 453 registry->Register(SetCallbackTrampoline); 454 registry->Register(PushAsyncContext); 455 registry->Register(PopAsyncContext); 456 registry->Register(ExecutionAsyncResource); 457 registry->Register(ClearAsyncIdStack); 458 registry->Register(QueueDestroyAsyncId); 459 registry->Register(SetPromiseHooks); 460 registry->Register(RegisterDestroyHook); 461 registry->Register(AsyncWrap::GetAsyncId); 462 registry->Register(AsyncWrap::AsyncReset); 463 registry->Register(AsyncWrap::GetProviderType); 464} 465 466AsyncWrap::AsyncWrap(Environment* env, 467 Local<Object> object, 468 ProviderType provider, 469 double execution_async_id) 470 : AsyncWrap(env, object, provider, execution_async_id, false) {} 471 472AsyncWrap::AsyncWrap(Environment* env, 473 Local<Object> object, 474 ProviderType provider, 475 double execution_async_id, 476 bool silent) 477 : AsyncWrap(env, object) { 478 CHECK_NE(provider, PROVIDER_NONE); 479 provider_type_ = provider; 480 481 // Use AsyncReset() call to execute the init() callbacks. 482 AsyncReset(object, execution_async_id, silent); 483 init_hook_ran_ = true; 484} 485 486AsyncWrap::AsyncWrap(Environment* env, 487 Local<Object> object, 488 ProviderType provider, 489 double execution_async_id, 490 double trigger_async_id) 491 : AsyncWrap(env, object, provider, execution_async_id, true) { 492 trigger_async_id_ = trigger_async_id; 493} 494 495AsyncWrap::AsyncWrap(Environment* env, Local<Object> object) 496 : BaseObject(env, object) { 497} 498 499// This method is necessary to work around one specific problem: 500// Before the init() hook runs, if there is one, the BaseObject() constructor 501// registers this object with the Environment for finalization and debugging 502// purposes. 503// If the Environment decides to inspect this object for debugging, it tries to 504// call virtual methods on this object that are only (meaningfully) implemented 505// by the subclasses of AsyncWrap. 506// This could, with bad luck, happen during the AsyncWrap() constructor, 507// because we run JS code as part of it and that in turn can lead to a heapdump 508// being taken, either through the inspector or our programmatic API for it. 509// The object being initialized is not fully constructed at that point, and 510// in particular its virtual function table points to the AsyncWrap one 511// (as the subclass constructor has not yet begun execution at that point). 512// This means that the functions that are used for heap dump memory tracking 513// are not yet available, and trying to call them would crash the process. 514// We use this particular `IsDoneInitializing()` method to tell the Environment 515// that such debugging methods are not yet available. 516// This may be somewhat unreliable when it comes to future changes, because 517// at this point it *only* protects AsyncWrap subclasses, and *only* for cases 518// where heap dumps are being taken while the init() hook is on the call stack. 519// For now, it seems like the best solution, though. 520bool AsyncWrap::IsDoneInitializing() const { 521 return init_hook_ran_; 522} 523 524AsyncWrap::~AsyncWrap() { 525 EmitTraceEventDestroy(); 526 EmitDestroy(true /* from gc */); 527} 528 529void AsyncWrap::EmitTraceEventDestroy() { 530 switch (provider_type()) { 531 #define V(PROVIDER) \ 532 case PROVIDER_ ## PROVIDER: \ 533 TRACE_EVENT_NESTABLE_ASYNC_END0( \ 534 TRACING_CATEGORY_NODE1(async_hooks), \ 535 #PROVIDER, static_cast<int64_t>(get_async_id())); \ 536 break; 537 NODE_ASYNC_PROVIDER_TYPES(V) 538 #undef V 539 default: 540 UNREACHABLE(); 541 } 542} 543 544void AsyncWrap::EmitDestroy(Environment* env, double async_id) { 545 if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 || 546 !env->can_call_into_js()) { 547 return; 548 } 549 550 if (env->destroy_async_id_list()->empty()) { 551 env->SetImmediate(&DestroyAsyncIdsCallback, CallbackFlags::kUnrefed); 552 } 553 554 // If the list gets very large empty it faster using a Microtask. 555 // Microtasks can't be added in GC context therefore we use an 556 // interrupt to get this Microtask scheduled as fast as possible. 557 if (env->destroy_async_id_list()->size() == 16384) { 558 env->RequestInterrupt([](Environment* env) { 559 env->context()->GetMicrotaskQueue()->EnqueueMicrotask( 560 env->isolate(), 561 [](void* arg) { 562 DestroyAsyncIdsCallback(static_cast<Environment*>(arg)); 563 }, env); 564 }); 565 } 566 567 env->destroy_async_id_list()->push_back(async_id); 568} 569 570// Generalized call for both the constructor and for handles that are pooled 571// and reused over their lifetime. This way a new uid can be assigned when 572// the resource is pulled out of the pool and put back into use. 573void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id, 574 bool silent) { 575 CHECK_NE(provider_type(), PROVIDER_NONE); 576 577 if (async_id_ != kInvalidAsyncId) { 578 // This instance was in use before, we have already emitted an init with 579 // its previous async_id and need to emit a matching destroy for that 580 // before generating a new async_id. 581 EmitDestroy(); 582 } 583 584 // Now we can assign a new async_id_ to this instance. 585 async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id() 586 : execution_async_id; 587 trigger_async_id_ = env()->get_default_trigger_async_id(); 588 589 { 590 HandleScope handle_scope(env()->isolate()); 591 Local<Object> obj = object(); 592 CHECK(!obj.IsEmpty()); 593 if (resource != obj) { 594 USE(obj->Set(env()->context(), env()->resource_symbol(), resource)); 595 } 596 } 597 598 switch (provider_type()) { 599#define V(PROVIDER) \ 600 case PROVIDER_ ## PROVIDER: \ 601 if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( \ 602 TRACING_CATEGORY_NODE1(async_hooks))) { \ 603 auto data = tracing::TracedValue::Create(); \ 604 data->SetInteger("executionAsyncId", \ 605 static_cast<int64_t>(env()->execution_async_id())); \ 606 data->SetInteger("triggerAsyncId", \ 607 static_cast<int64_t>(get_trigger_async_id())); \ 608 TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( \ 609 TRACING_CATEGORY_NODE1(async_hooks), \ 610 #PROVIDER, static_cast<int64_t>(get_async_id()), \ 611 "data", std::move(data)); \ 612 } \ 613 break; 614 NODE_ASYNC_PROVIDER_TYPES(V) 615#undef V 616 default: 617 UNREACHABLE(); 618 } 619 620 if (silent) return; 621 622 EmitAsyncInit(env(), resource, 623 env()->async_hooks()->provider_string(provider_type()), 624 async_id_, trigger_async_id_); 625} 626 627 628void AsyncWrap::EmitAsyncInit(Environment* env, 629 Local<Object> object, 630 Local<String> type, 631 double async_id, 632 double trigger_async_id) { 633 CHECK(!object.IsEmpty()); 634 CHECK(!type.IsEmpty()); 635 AsyncHooks* async_hooks = env->async_hooks(); 636 637 // Nothing to execute, so can continue normally. 638 if (async_hooks->fields()[AsyncHooks::kInit] == 0) { 639 return; 640 } 641 642 HandleScope scope(env->isolate()); 643 Local<Function> init_fn = env->async_hooks_init_function(); 644 645 Local<Value> argv[] = { 646 Number::New(env->isolate(), async_id), 647 type, 648 Number::New(env->isolate(), trigger_async_id), 649 object, 650 }; 651 652 TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal); 653 USE(init_fn->Call(env->context(), object, arraysize(argv), argv)); 654} 655 656 657MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb, 658 int argc, 659 Local<Value>* argv) { 660 EmitTraceEventBefore(); 661 662 ProviderType provider = provider_type(); 663 async_context context { get_async_id(), get_trigger_async_id() }; 664 MaybeLocal<Value> ret = InternalMakeCallback( 665 env(), object(), object(), cb, argc, argv, context); 666 667 // This is a static call with cached values because the `this` object may 668 // no longer be alive at this point. 669 EmitTraceEventAfter(provider, context.async_id); 670 671 return ret; 672} 673 674const char* AsyncWrap::MemoryInfoName() const { 675 return provider_names[provider_type()]; 676} 677 678std::string AsyncWrap::diagnostic_name() const { 679 char buf[64]; 680 snprintf(buf, 681 sizeof(buf), 682 "%s(%" PRIu64 ":%.0f)", 683 MemoryInfoName(), 684 env()->thread_id(), 685 async_id_); 686 return buf; 687} 688 689Local<Object> AsyncWrap::GetOwner() { 690 return GetOwner(env(), object()); 691} 692 693Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) { 694 EscapableHandleScope handle_scope(env->isolate()); 695 CHECK(!obj.IsEmpty()); 696 697 TryCatchScope ignore_exceptions(env); 698 while (true) { 699 Local<Value> owner; 700 if (!obj->Get(env->context(), 701 env->owner_symbol()).ToLocal(&owner) || 702 !owner->IsObject()) { 703 return handle_scope.Escape(obj); 704 } 705 706 obj = owner.As<Object>(); 707 } 708} 709 710} // namespace node 711 712NODE_BINDING_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize) 713NODE_BINDING_EXTERNAL_REFERENCE(async_wrap, 714 node::AsyncWrap::RegisterExternalReferences) 715