xref: /third_party/node/src/async_wrap.cc (revision 1cb0ef41)
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