GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: async_wrap.cc Lines: 287 308 93.2 %
Date: 2022-12-31 04:22:30 Branches: 820 1422 57.7 %

Line Branch Exec Source
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
32
using v8::Context;
33
using v8::DontDelete;
34
using v8::EscapableHandleScope;
35
using v8::Function;
36
using v8::FunctionCallbackInfo;
37
using v8::FunctionTemplate;
38
using v8::Global;
39
using v8::HandleScope;
40
using v8::Integer;
41
using v8::Isolate;
42
using v8::Local;
43
using v8::MaybeLocal;
44
using v8::Nothing;
45
using v8::Number;
46
using v8::Object;
47
using v8::PropertyAttribute;
48
using v8::ReadOnly;
49
using v8::String;
50
using v8::Undefined;
51
using v8::Value;
52
using v8::WeakCallbackInfo;
53
using v8::WeakCallbackType;
54
55
using TryCatchScope = node::errors::TryCatchScope;
56
57
namespace node {
58
59
static const char* const provider_names[] = {
60
#define V(PROVIDER)                                                           \
61
  #PROVIDER,
62
  NODE_ASYNC_PROVIDER_TYPES(V)
63
#undef V
64
};
65
66
24845
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) {
67
24845
  Local<Function> fn = env->async_hooks_destroy_function();
68
69
24845
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
70
71
4
  do {
72
24849
    std::vector<double> destroy_async_id_list;
73
24849
    destroy_async_id_list.swap(*env->destroy_async_id_list());
74
24849
    if (!env->can_call_into_js()) return;
75
204703
    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
179856
      HandleScope scope(env->isolate());
79
359712
      Local<Value> async_id_value = Number::New(env->isolate(), async_id);
80
      MaybeLocal<Value> ret = fn->Call(
81
359712
          env->context(), Undefined(env->isolate()), 1, &async_id_value);
82
83
179854
      if (ret.IsEmpty())
84
        return;
85
    }
86
24847
  } while (!env->destroy_async_id_list()->empty());
87
}
88
89
1024982
void Emit(Environment* env, double async_id, AsyncHooks::Fields type,
90
          Local<Function> fn) {
91
1024982
  AsyncHooks* async_hooks = env->async_hooks();
92
93

1024982
  if (async_hooks->fields()[type] == 0 || !env->can_call_into_js())
94
1024680
    return;
95
96
604
  HandleScope handle_scope(env->isolate());
97
302
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
98
302
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
99
604
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
100
}
101
102
103
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
104
  Emit(env, async_id, AsyncHooks::kPromiseResolve,
105
       env->async_hooks_promise_resolve_function());
106
}
107
108
109
381919
void AsyncWrap::EmitTraceEventBefore() {
110














381919
  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


























































773754
    NODE_ASYNC_PROVIDER_TYPES(V)
118
#undef V
119
    default:
120
      UNREACHABLE();
121
  }
122
381919
}
123
124
125
512531
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
126
512531
  Emit(env, async_id, AsyncHooks::kBefore,
127
       env->async_hooks_before_function());
128
512531
}
129
130
131
381751
void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) {
132














381751
  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


























































773354
    NODE_ASYNC_PROVIDER_TYPES(V)
140
#undef V
141
    default:
142
      UNREACHABLE();
143
  }
144
381751
}
145
146
147
512451
void 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
512451
  Emit(env, async_id, AsyncHooks::kAfter,
151
       env->async_hooks_after_function());
152
512451
}
153
154
827
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
155
827
  Environment* env = Environment::GetCurrent(args);
156
157
827
  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
1654
  CHECK(env->async_hooks_init_function().IsEmpty());
164
165
1654
  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
3308
  SET_HOOK_FN(init);
178
4135
  SET_HOOK_FN(before);
179
3308
  SET_HOOK_FN(after);
180
3308
  SET_HOOK_FN(destroy);
181
3308
  SET_HOOK_FN(promise_resolve);
182
#undef SET_HOOK_FN
183
827
}
184
185
16638
static void SetPromiseHooks(const FunctionCallbackInfo<Value>& args) {
186
16638
  Environment* env = Environment::GetCurrent(args);
187
188


75325
  env->ResetPromiseHooks(
189
25411
      args[0]->IsFunction() ? args[0].As<Function>() : Local<Function>(),
190
25125
      args[1]->IsFunction() ? args[1].As<Function>() : Local<Function>(),
191
24812
      args[2]->IsFunction() ? args[2].As<Function>() : Local<Function>(),
192
16863
      args[3]->IsFunction() ? args[3].As<Function>() : Local<Function>());
193
16638
}
194
195
class DestroyParam {
196
 public:
197
  double asyncId;
198
  Environment* env;
199
  Global<Object> target;
200
  Global<Object> propBag;
201
};
202
203
32814
static void DestroyParamCleanupHook(void* ptr) {
204
32814
  delete static_cast<DestroyParam*>(ptr);
205
32814
}
206
207
67687
void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) {
208
67687
  HandleScope scope(info.GetIsolate());
209
210
67687
  std::unique_ptr<DestroyParam> p{info.GetParameter()};
211
  Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(),
212
67687
                                                      p->propBag);
213
  Local<Value> val;
214
215
67687
  p->env->RemoveCleanupHook(DestroyParamCleanupHook, p.get());
216
217
69979
  if (!prop_bag.IsEmpty() &&
218
72271
      !prop_bag->Get(p->env->context(), p->env->destroyed_string())
219
2292
        .ToLocal(&val)) {
220
    return;
221
  }
222
223

69979
  if (val.IsEmpty() || val->IsFalse()) {
224
67681
    AsyncWrap::EmitDestroy(p->env, p->asyncId);
225
  }
226
  // unique_ptr goes out of scope here and pointer is deleted.
227
}
228
229
230
101569
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) {
231
101569
  CHECK(args[0]->IsObject());
232
101569
  CHECK(args[1]->IsNumber());
233

105007
  CHECK(args.Length() == 2 || args[2]->IsObject());
234
235
101569
  Isolate* isolate = args.GetIsolate();
236
101569
  DestroyParam* p = new DestroyParam();
237
203138
  p->asyncId = args[1].As<Number>()->Value();
238
101569
  p->env = Environment::GetCurrent(args);
239
406276
  p->target.Reset(isolate, args[0].As<Object>());
240
101569
  if (args.Length() > 2) {
241
13752
    p->propBag.Reset(isolate, args[2].As<Object>());
242
  }
243
101569
  p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter);
244
101569
  p->env->AddCleanupHook(DestroyParamCleanupHook, p);
245
101569
}
246
247
101852
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
248
  AsyncWrap* wrap;
249
203704
  args.GetReturnValue().Set(kInvalidAsyncId);
250
101852
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
251
203664
  args.GetReturnValue().Set(wrap->get_async_id());
252
}
253
254
255
4
void AsyncWrap::PushAsyncContext(const FunctionCallbackInfo<Value>& args) {
256
4
  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
8
  double async_id = args[0]->NumberValue(env->context()).FromJust();
260
4
  double trigger_async_id = args[1]->NumberValue(env->context()).FromJust();
261
4
  env->async_hooks()->push_async_context(async_id, trigger_async_id, {});
262
4
}
263
264
265
3
void AsyncWrap::PopAsyncContext(const FunctionCallbackInfo<Value>& args) {
266
3
  Environment* env = Environment::GetCurrent(args);
267
6
  double async_id = args[0]->NumberValue(env->context()).FromJust();
268
3
  args.GetReturnValue().Set(env->async_hooks()->pop_async_context(async_id));
269
}
270
271
272
2411
void AsyncWrap::ExecutionAsyncResource(
273
    const FunctionCallbackInfo<Value>& args) {
274
2411
  Environment* env = Environment::GetCurrent(args);
275
  uint32_t index;
276
4822
  if (!args[0]->Uint32Value(env->context()).To(&index)) return;
277
4822
  args.GetReturnValue().Set(
278
      env->async_hooks()->native_execution_async_resource(index));
279
}
280
281
282
1278
void AsyncWrap::ClearAsyncIdStack(const FunctionCallbackInfo<Value>& args) {
283
1278
  Environment* env = Environment::GetCurrent(args);
284
1278
  env->async_hooks()->clear_async_id_stack();
285
1278
}
286
287
288
421
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) {
289
421
  CHECK(args[0]->IsObject());
290
291
  AsyncWrap* wrap;
292
421
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
293
294
842
  Local<Object> resource = args[0].As<Object>();
295
  double execution_async_id =
296
421
      args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId;
297
421
  wrap->AsyncReset(resource, execution_async_id);
298
}
299
300
301
421
void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) {
302
  AsyncWrap* wrap;
303
842
  args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE);
304
421
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
305
842
  args.GetReturnValue().Set(wrap->provider_type());
306
}
307
308
309
219991
void AsyncWrap::EmitDestroy(bool from_gc) {
310
219991
  AsyncWrap::EmitDestroy(env(), async_id_);
311
  // Ensure no double destroy is emitted via AsyncReset().
312
219991
  async_id_ = kInvalidAsyncId;
313
314

219991
  if (!persistent().IsEmpty() && !from_gc) {
315
6925
    HandleScope handle_scope(env()->isolate());
316
27700
    USE(object()->Set(env()->context(), env()->resource_symbol(), object()));
317
  }
318
219991
}
319
320
102163
void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
321
102163
  CHECK(args[0]->IsNumber());
322
102163
  AsyncWrap::EmitDestroy(
323
      Environment::GetCurrent(args),
324
204326
      args[0].As<Number>()->Value());
325
102163
}
326
327
920
void AsyncWrap::SetCallbackTrampoline(const FunctionCallbackInfo<Value>& args) {
328
920
  Environment* env = Environment::GetCurrent(args);
329
330
920
  if (args[0]->IsFunction()) {
331
1228
    env->set_async_hooks_callback_trampoline(args[0].As<Function>());
332
  } else {
333
306
    env->set_async_hooks_callback_trampoline(Local<Function>());
334
  }
335
920
}
336
337
168042
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(
338
    IsolateData* isolate_data) {
339
168042
  Local<FunctionTemplate> tmpl = isolate_data->async_wrap_ctor_template();
340
168042
  if (tmpl.IsEmpty()) {
341
831
    Isolate* isolate = isolate_data->isolate();
342
831
    tmpl = NewFunctionTemplate(isolate, nullptr);
343
831
    tmpl->SetClassName(
344
        FIXED_ONE_BYTE_STRING(isolate_data->isolate(), "AsyncWrap"));
345
831
    tmpl->Inherit(BaseObject::GetConstructorTemplate(isolate_data));
346
831
    SetProtoMethod(isolate, tmpl, "getAsyncId", AsyncWrap::GetAsyncId);
347
831
    SetProtoMethod(isolate, tmpl, "asyncReset", AsyncWrap::AsyncReset);
348
831
    SetProtoMethod(
349
        isolate, tmpl, "getProviderType", AsyncWrap::GetProviderType);
350
831
    isolate_data->set_async_wrap_ctor_template(tmpl);
351
  }
352
168042
  return tmpl;
353
}
354
355
827
void AsyncWrap::Initialize(Local<Object> target,
356
                           Local<Value> unused,
357
                           Local<Context> context,
358
                           void* priv) {
359
827
  Environment* env = Environment::GetCurrent(context);
360
827
  Isolate* isolate = env->isolate();
361
1654
  HandleScope scope(isolate);
362
363
827
  SetMethod(context, target, "setupHooks", SetupHooks);
364
827
  SetMethod(context, target, "setCallbackTrampoline", SetCallbackTrampoline);
365
827
  SetMethod(context, target, "pushAsyncContext", PushAsyncContext);
366
827
  SetMethod(context, target, "popAsyncContext", PopAsyncContext);
367
827
  SetMethod(context, target, "executionAsyncResource", ExecutionAsyncResource);
368
827
  SetMethod(context, target, "clearAsyncIdStack", ClearAsyncIdStack);
369
827
  SetMethod(context, target, "queueDestroyAsyncId", QueueDestroyAsyncId);
370
827
  SetMethod(context, target, "setPromiseHooks", SetPromiseHooks);
371
827
  SetMethod(context, target, "registerDestroyHook", RegisterDestroyHook);
372
373
827
  PropertyAttribute ReadOnlyDontDelete =
374
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
375
376
#define FORCE_SET_TARGET_FIELD(obj, str, field)                               \
377
  (obj)->DefineOwnProperty(context,                                           \
378
                           FIXED_ONE_BYTE_STRING(isolate, str),               \
379
                           field,                                             \
380
                           ReadOnlyDontDelete).FromJust()
381
382
  // Attach the uint32_t[] where each slot contains the count of the number of
383
  // callbacks waiting to be called on a particular event. It can then be
384
  // incremented/decremented from JS quickly to communicate to C++ if there are
385
  // any callbacks waiting to be called.
386
3308
  FORCE_SET_TARGET_FIELD(target,
387
                         "async_hook_fields",
388
                         env->async_hooks()->fields().GetJSArray());
389
390
  // The following v8::Float64Array has 5 fields. These fields are shared in
391
  // this way to allow JS and C++ to read/write each value as quickly as
392
  // possible. The fields are represented as follows:
393
  //
394
  // kAsyncIdCounter: Maintains the state of the next unique id to be assigned.
395
  //
396
  // kDefaultTriggerAsyncId: Write the id of the resource responsible for a
397
  //   handle's creation just before calling the new handle's constructor.
398
  //   After the new handle is constructed kDefaultTriggerAsyncId is set back
399
  //   to kInvalidAsyncId.
400
3308
  FORCE_SET_TARGET_FIELD(target,
401
                         "async_id_fields",
402
                         env->async_hooks()->async_id_fields().GetJSArray());
403
404
3308
  FORCE_SET_TARGET_FIELD(target,
405
                         "execution_async_resources",
406
                         env->async_hooks()->js_execution_async_resources());
407
408
827
  target->Set(context,
409
              env->async_ids_stack_string(),
410
2481
              env->async_hooks()->async_ids_stack().GetJSArray()).Check();
411
412
827
  Local<Object> constants = Object::New(isolate);
413
#define SET_HOOKS_CONSTANT(name)                                              \
414
  FORCE_SET_TARGET_FIELD(                                                     \
415
      constants, #name, Integer::New(isolate, AsyncHooks::name))
416
417
3308
  SET_HOOKS_CONSTANT(kInit);
418
3308
  SET_HOOKS_CONSTANT(kBefore);
419
3308
  SET_HOOKS_CONSTANT(kAfter);
420
3308
  SET_HOOKS_CONSTANT(kDestroy);
421
3308
  SET_HOOKS_CONSTANT(kPromiseResolve);
422
3308
  SET_HOOKS_CONSTANT(kTotals);
423
3308
  SET_HOOKS_CONSTANT(kCheck);
424
3308
  SET_HOOKS_CONSTANT(kExecutionAsyncId);
425
3308
  SET_HOOKS_CONSTANT(kTriggerAsyncId);
426
3308
  SET_HOOKS_CONSTANT(kAsyncIdCounter);
427
3308
  SET_HOOKS_CONSTANT(kDefaultTriggerAsyncId);
428
3308
  SET_HOOKS_CONSTANT(kUsesExecutionAsyncResource);
429
3308
  SET_HOOKS_CONSTANT(kStackLength);
430
#undef SET_HOOKS_CONSTANT
431
1654
  FORCE_SET_TARGET_FIELD(target, "constants", constants);
432
433
827
  Local<Object> async_providers = Object::New(isolate);
434
#define V(p)                                                                  \
435
  FORCE_SET_TARGET_FIELD(                                                     \
436
      async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p));
437
144725
  NODE_ASYNC_PROVIDER_TYPES(V)
438
#undef V
439
2481
  FORCE_SET_TARGET_FIELD(target, "Providers", async_providers);
440
441
#undef FORCE_SET_TARGET_FIELD
442
443
827
  env->set_async_hooks_init_function(Local<Function>());
444
827
  env->set_async_hooks_before_function(Local<Function>());
445
827
  env->set_async_hooks_after_function(Local<Function>());
446
827
  env->set_async_hooks_destroy_function(Local<Function>());
447
827
  env->set_async_hooks_promise_resolve_function(Local<Function>());
448
827
  env->set_async_hooks_callback_trampoline(Local<Function>());
449
827
  env->set_async_hooks_binding(target);
450
827
}
451
452
5716
void AsyncWrap::RegisterExternalReferences(
453
    ExternalReferenceRegistry* registry) {
454
5716
  registry->Register(SetupHooks);
455
5716
  registry->Register(SetCallbackTrampoline);
456
5716
  registry->Register(PushAsyncContext);
457
5716
  registry->Register(PopAsyncContext);
458
5716
  registry->Register(ExecutionAsyncResource);
459
5716
  registry->Register(ClearAsyncIdStack);
460
5716
  registry->Register(QueueDestroyAsyncId);
461
5716
  registry->Register(SetPromiseHooks);
462
5716
  registry->Register(RegisterDestroyHook);
463
5716
  registry->Register(AsyncWrap::GetAsyncId);
464
5716
  registry->Register(AsyncWrap::AsyncReset);
465
5716
  registry->Register(AsyncWrap::GetProviderType);
466
5716
}
467
468
208980
AsyncWrap::AsyncWrap(Environment* env,
469
                     Local<Object> object,
470
                     ProviderType provider,
471
208980
                     double execution_async_id)
472
208980
    : AsyncWrap(env, object, provider, execution_async_id, false) {}
473
474
208980
AsyncWrap::AsyncWrap(Environment* env,
475
                     Local<Object> object,
476
                     ProviderType provider,
477
                     double execution_async_id,
478
208980
                     bool silent)
479
208980
    : AsyncWrap(env, object) {
480
208980
  CHECK_NE(provider, PROVIDER_NONE);
481
208980
  provider_type_ = provider;
482
483
  // Use AsyncReset() call to execute the init() callbacks.
484
208980
  AsyncReset(object, execution_async_id, silent);
485
208980
  init_hook_ran_ = true;
486
208980
}
487
488
AsyncWrap::AsyncWrap(Environment* env,
489
                     Local<Object> object,
490
                     ProviderType provider,
491
                     double execution_async_id,
492
                     double trigger_async_id)
493
    : AsyncWrap(env, object, provider, execution_async_id, true) {
494
  trigger_async_id_ = trigger_async_id;
495
}
496
497
214271
AsyncWrap::AsyncWrap(Environment* env, Local<Object> object)
498
214271
  : BaseObject(env, object) {
499
214271
}
500
501
// This method is necessary to work around one specific problem:
502
// Before the init() hook runs, if there is one, the BaseObject() constructor
503
// registers this object with the Environment for finalization and debugging
504
// purposes.
505
// If the Environment decides to inspect this object for debugging, it tries to
506
// call virtual methods on this object that are only (meaningfully) implemented
507
// by the subclasses of AsyncWrap.
508
// This could, with bad luck, happen during the AsyncWrap() constructor,
509
// because we run JS code as part of it and that in turn can lead to a heapdump
510
// being taken, either through the inspector or our programmatic API for it.
511
// The object being initialized is not fully constructed at that point, and
512
// in particular its virtual function table points to the AsyncWrap one
513
// (as the subclass constructor has not yet begun execution at that point).
514
// This means that the functions that are used for heap dump memory tracking
515
// are not yet available, and trying to call them would crash the process.
516
// We use this particular `IsDoneInitializing()` method to tell the Environment
517
// that such debugging methods are not yet available.
518
// This may be somewhat unreliable when it comes to future changes, because
519
// at this point it *only* protects AsyncWrap subclasses, and *only* for cases
520
// where heap dumps are being taken while the init() hook is on the call stack.
521
// For now, it seems like the best solution, though.
522
190283
bool AsyncWrap::IsDoneInitializing() const {
523
190283
  return init_hook_ran_;
524
}
525
526
426132
AsyncWrap::~AsyncWrap() {
527
426132
  EmitTraceEventDestroy();
528
426132
  EmitDestroy(true /* from gc */);
529
}
530
531
219373
void AsyncWrap::EmitTraceEventDestroy() {
532














219373
  switch (provider_type()) {
533
  #define V(PROVIDER)                                                         \
534
    case PROVIDER_ ## PROVIDER:                                               \
535
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
536
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
537
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
538
      break;
539


























































452400
    NODE_ASYNC_PROVIDER_TYPES(V)
540
  #undef V
541
    default:
542
      UNREACHABLE();
543
  }
544
219373
}
545
546
390386
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
547

571743
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
548
181357
      !env->can_call_into_js()) {
549
209219
    return;
550
  }
551
552
181167
  if (env->destroy_async_id_list()->empty()) {
553
24906
    env->SetImmediate(&DestroyAsyncIdsCallback, CallbackFlags::kUnrefed);
554
  }
555
556
  // If the list gets very large empty it faster using a Microtask.
557
  // Microtasks can't be added in GC context therefore we use an
558
  // interrupt to get this Microtask scheduled as fast as possible.
559
181167
  if (env->destroy_async_id_list()->size() == 16384) {
560
1
    env->RequestInterrupt([](Environment* env) {
561
3
      env->context()->GetMicrotaskQueue()->EnqueueMicrotask(
562
        env->isolate(),
563
1
        [](void* arg) {
564
1
          DestroyAsyncIdsCallback(static_cast<Environment*>(arg));
565
1
        }, env);
566
1
      });
567
  }
568
569
181167
  env->destroy_async_id_list()->push_back(async_id);
570
}
571
572
// Generalized call for both the constructor and for handles that are pooled
573
// and reused over their lifetime. This way a new uid can be assigned when
574
// the resource is pulled out of the pool and put back into use.
575
216106
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
576
                           bool silent) {
577
216106
  CHECK_NE(provider_type(), PROVIDER_NONE);
578
579
216106
  if (async_id_ != kInvalidAsyncId) {
580
    // This instance was in use before, we have already emitted an init with
581
    // its previous async_id and need to emit a matching destroy for that
582
    // before generating a new async_id.
583
618
    EmitDestroy();
584
  }
585
586
  // Now we can assign a new async_id_ to this instance.
587
216106
  async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id()
588
                                                     : execution_async_id;
589
216106
  trigger_async_id_ = env()->get_default_trigger_async_id();
590
591
  {
592
432212
    HandleScope handle_scope(env()->isolate());
593
216106
    Local<Object> obj = object();
594
216106
    CHECK(!obj.IsEmpty());
595
216106
    if (resource != obj) {
596
14252
      USE(obj->Set(env()->context(), env()->resource_symbol(), resource));
597
    }
598
  }
599
600














216106
  switch (provider_type()) {
601
#define V(PROVIDER)                                                           \
602
    case PROVIDER_ ## PROVIDER:                                               \
603
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
604
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
605
        auto data = tracing::TracedValue::Create();                           \
606
        data->SetInteger("executionAsyncId",                                  \
607
                         static_cast<int64_t>(env()->execution_async_id()));  \
608
        data->SetInteger("triggerAsyncId",                                    \
609
                         static_cast<int64_t>(get_trigger_async_id()));       \
610
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
611
          TRACING_CATEGORY_NODE1(async_hooks),                                \
612
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
613
          "data", std::move(data));                                           \
614
        }                                                                     \
615
      break;
616























































































216165
    NODE_ASYNC_PROVIDER_TYPES(V)
617
#undef V
618
    default:
619
      UNREACHABLE();
620
  }
621
622
216106
  if (silent) return;
623
624
432212
  EmitAsyncInit(env(), resource,
625
216106
                env()->async_hooks()->provider_string(provider_type()),
626
                async_id_, trigger_async_id_);
627
}
628
629
630
216661
void AsyncWrap::EmitAsyncInit(Environment* env,
631
                              Local<Object> object,
632
                              Local<String> type,
633
                              double async_id,
634
                              double trigger_async_id) {
635
216661
  CHECK(!object.IsEmpty());
636
216661
  CHECK(!type.IsEmpty());
637
216661
  AsyncHooks* async_hooks = env->async_hooks();
638
639
  // Nothing to execute, so can continue normally.
640
216661
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
641
201069
    return;
642
  }
643
644
31184
  HandleScope scope(env->isolate());
645
15592
  Local<Function> init_fn = env->async_hooks_init_function();
646
647
  Local<Value> argv[] = {
648
    Number::New(env->isolate(), async_id),
649
    type,
650
    Number::New(env->isolate(), trigger_async_id),
651
    object,
652
46776
  };
653
654
15592
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
655
15592
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
656
}
657
658
659
381919
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
660
                                          int argc,
661
                                          Local<Value>* argv) {
662
381919
  EmitTraceEventBefore();
663
664
381919
  ProviderType provider = provider_type();
665
381919
  async_context context { get_async_id(), get_trigger_async_id() };
666
  MaybeLocal<Value> ret = InternalMakeCallback(
667
381919
      env(), object(), object(), cb, argc, argv, context);
668
669
  // This is a static call with cached values because the `this` object may
670
  // no longer be alive at this point.
671
381751
  EmitTraceEventAfter(provider, context.async_id);
672
673
381751
  return ret;
674
}
675
676
std::string AsyncWrap::MemoryInfoName() const {
677
  return provider_names[provider_type()];
678
}
679
680
std::string AsyncWrap::diagnostic_name() const {
681
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
682
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
683
}
684
685
1028
Local<Object> AsyncWrap::GetOwner() {
686
1028
  return GetOwner(env(), object());
687
}
688
689
1028
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
690
1028
  EscapableHandleScope handle_scope(env->isolate());
691
1028
  CHECK(!obj.IsEmpty());
692
693
1028
  TryCatchScope ignore_exceptions(env);
694
  while (true) {
695
    Local<Value> owner;
696
6126
    if (!obj->Get(env->context(),
697

8168
                  env->owner_symbol()).ToLocal(&owner) ||
698
2042
        !owner->IsObject()) {
699
1028
      return handle_scope.Escape(obj);
700
    }
701
702
1014
    obj = owner.As<Object>();
703
1014
  }
704
}
705
706
}  // namespace node
707
708
5787
NODE_BINDING_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)
709
5716
NODE_BINDING_EXTERNAL_REFERENCE(async_wrap,
710
                                node::AsyncWrap::RegisterExternalReferences)