GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/async_wrap.cc Lines: 291 308 94.5 %
Date: 2019-03-02 22:23:06 Branches: 651 1048 62.1 %

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-inl.h"
23
#include "env-inl.h"
24
#include "node_errors.h"
25
#include "tracing/traced_value.h"
26
#include "util-inl.h"
27
28
#include "v8.h"
29
#include "v8-profiler.h"
30
31
using v8::Context;
32
using v8::DontDelete;
33
using v8::EscapableHandleScope;
34
using v8::Function;
35
using v8::FunctionCallbackInfo;
36
using v8::FunctionTemplate;
37
using v8::HandleScope;
38
using v8::Integer;
39
using v8::Isolate;
40
using v8::Local;
41
using v8::MaybeLocal;
42
using v8::Number;
43
using v8::Object;
44
using v8::ObjectTemplate;
45
using v8::Promise;
46
using v8::PromiseHookType;
47
using v8::PropertyAttribute;
48
using v8::PropertyCallbackInfo;
49
using v8::ReadOnly;
50
using v8::String;
51
using v8::TryCatch;
52
using v8::Uint32;
53
using v8::Undefined;
54
using v8::Value;
55
using v8::WeakCallbackInfo;
56
using v8::WeakCallbackType;
57
58
using AsyncHooks = node::Environment::AsyncHooks;
59
using TryCatchScope = node::errors::TryCatchScope;
60
61
namespace node {
62
63
static const char* const provider_names[] = {
64
#define V(PROVIDER)                                                           \
65
  #PROVIDER,
66
  NODE_ASYNC_PROVIDER_TYPES(V)
67
#undef V
68
};
69
70
71
176
struct AsyncWrapObject : public AsyncWrap {
72
88
  static inline void New(const FunctionCallbackInfo<Value>& args) {
73
88
    Environment* env = Environment::GetCurrent(args);
74
88
    CHECK(args.IsConstructCall());
75
176
    CHECK(env->async_wrap_object_ctor_template()->HasInstance(args.This()));
76
176
    CHECK(args[0]->IsUint32());
77
264
    auto type = static_cast<ProviderType>(args[0].As<Uint32>()->Value());
78
88
    new AsyncWrapObject(env, args.This(), type);
79
88
  }
80
81
88
  inline AsyncWrapObject(Environment* env, Local<Object> object,
82
88
                         ProviderType type) : AsyncWrap(env, object, type) {}
83
84
  SET_NO_MEMORY_INFO()
85
  SET_MEMORY_INFO_NAME(AsyncWrapObject)
86
  SET_SELF_SIZE(AsyncWrapObject)
87
};
88
89
22163
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env, void* data) {
90
22163
  Local<Function> fn = env->async_hooks_destroy_function();
91
92
22163
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
93
94

22164
  do {
95
22164
    std::vector<double> destroy_async_id_list;
96
22164
    destroy_async_id_list.swap(*env->destroy_async_id_list());
97
22164
    if (!env->can_call_into_js()) return;
98

99383
    for (auto async_id : destroy_async_id_list) {
99
      // Want each callback to be cleaned up after itself, instead of cleaning
100
      // them all up after the while() loop completes.
101
77219
      HandleScope scope(env->isolate());
102
77219
      Local<Value> async_id_value = Number::New(env->isolate(), async_id);
103
      MaybeLocal<Value> ret = fn->Call(
104
231657
          env->context(), Undefined(env->isolate()), 1, &async_id_value);
105
106
77219
      if (ret.IsEmpty())
107
        return;
108
99383
    }
109
44327
  } while (!env->destroy_async_id_list()->empty());
110
}
111
112
2080707
void Emit(Environment* env, double async_id, AsyncHooks::Fields type,
113
          Local<Function> fn) {
114
2080707
  AsyncHooks* async_hooks = env->async_hooks();
115
116


2080705
  if (async_hooks->fields()[type] == 0 || !env->can_call_into_js())
117
4154588
    return;
118
119
6822
  HandleScope handle_scope(env->isolate());
120
6822
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
121
13644
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
122
27288
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
123
}
124
125
126
1436
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
127
  Emit(env, async_id, AsyncHooks::kPromiseResolve,
128
1436
       env->async_hooks_promise_resolve_function());
129
1436
}
130
131
132
1037840
void AsyncWrap::EmitTraceEventBefore() {
133










1037840
  switch (provider_type()) {
134
#define V(PROVIDER)                                                           \
135
    case PROVIDER_ ## PROVIDER:                                               \
136
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(                                      \
137
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
138
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
139
      break;
140









































2075672
    NODE_ASYNC_PROVIDER_TYPES(V)
141
#undef V
142
    default:
143
      UNREACHABLE();
144
  }
145
1037836
}
146
147
148
1039681
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
149
  Emit(env, async_id, AsyncHooks::kBefore,
150
1039681
       env->async_hooks_before_function());
151
1039682
}
152
153
154
1037743
void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) {
155










1037743
  switch (type) {
156
#define V(PROVIDER)                                                           \
157
    case PROVIDER_ ## PROVIDER:                                               \
158
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
159
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
160
        #PROVIDER "_CALLBACK", static_cast<int64_t>(async_id));               \
161
      break;
162









































2075488
    NODE_ASYNC_PROVIDER_TYPES(V)
163
#undef V
164
    default:
165
      UNREACHABLE();
166
  }
167
1037744
}
168
169
170
1039589
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
171
  // If the user's callback failed then the after() hooks will be called at the
172
  // end of _fatalException().
173
  Emit(env, async_id, AsyncHooks::kAfter,
174
1039589
       env->async_hooks_after_function());
175
1039590
}
176
177
2314
class PromiseWrap : public AsyncWrap {
178
 public:
179
1283
  PromiseWrap(Environment* env, Local<Object> object, bool silent)
180
1283
      : AsyncWrap(env, object, PROVIDER_PROMISE, -1, silent) {
181
1283
    MakeWeak();
182
1283
  }
183
184
  SET_NO_MEMORY_INFO()
185
  SET_MEMORY_INFO_NAME(PromiseWrap)
186
  SET_SELF_SIZE(PromiseWrap)
187
188
  static constexpr int kIsChainedPromiseField = 1;
189
  static constexpr int kInternalFieldCount = 2;
190
191
  static PromiseWrap* New(Environment* env,
192
                          Local<Promise> promise,
193
                          PromiseWrap* parent_wrap,
194
                          bool silent);
195
  static void getIsChainedPromise(Local<String> property,
196
                                  const PropertyCallbackInfo<Value>& info);
197
};
198
199
1283
PromiseWrap* PromiseWrap::New(Environment* env,
200
                              Local<Promise> promise,
201
                              PromiseWrap* parent_wrap,
202
                              bool silent) {
203
  Local<Object> obj;
204
3849
  if (!env->promise_wrap_template()->NewInstance(env->context()).ToLocal(&obj))
205
    return nullptr;
206
  obj->SetInternalField(PromiseWrap::kIsChainedPromiseField,
207
840
                        parent_wrap != nullptr ? v8::True(env->isolate())
208
3009
                                               : v8::False(env->isolate()));
209
2566
  CHECK_NULL(promise->GetAlignedPointerFromInternalField(0));
210
1283
  promise->SetInternalField(0, obj);
211
1283
  return new PromiseWrap(env, obj, silent);
212
}
213
214
2
void PromiseWrap::getIsChainedPromise(Local<String> property,
215
                                      const PropertyCallbackInfo<Value>& info) {
216
  info.GetReturnValue().Set(
217
8
    info.Holder()->GetInternalField(kIsChainedPromiseField));
218
2
}
219
220
4798
static PromiseWrap* extractPromiseWrap(Local<Promise> promise) {
221
9596
  Local<Value> resource_object_value = promise->GetInternalField(0);
222
4798
  if (resource_object_value->IsObject()) {
223
3515
    return Unwrap<PromiseWrap>(resource_object_value.As<Object>());
224
  }
225
1283
  return nullptr;
226
}
227
228
3958
static void PromiseHook(PromiseHookType type, Local<Promise> promise,
229
                        Local<Value> parent, void* arg) {
230
3958
  Environment* env = static_cast<Environment*>(arg);
231
3958
  PromiseWrap* wrap = extractPromiseWrap(promise);
232

3958
  if (type == PromiseHookType::kInit || wrap == nullptr) {
233
1281
    bool silent = type != PromiseHookType::kInit;
234
235
    // set parent promise's async Id as this promise's triggerAsyncId
236
1281
    if (parent->IsPromise()) {
237
      // parent promise exists, current promise
238
      // is a chained promise, so we set parent promise's id as
239
      // current promise's triggerAsyncId
240
840
      Local<Promise> parent_promise = parent.As<Promise>();
241
840
      PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise);
242
840
      if (parent_wrap == nullptr) {
243
2
        parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true);
244
2
        if (parent_wrap == nullptr) return;
245
      }
246
247
840
      AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap);
248
840
      wrap = PromiseWrap::New(env, promise, parent_wrap, silent);
249
    } else {
250
441
      wrap = PromiseWrap::New(env, promise, nullptr, silent);
251
    }
252
  }
253
254
3958
  if (wrap == nullptr) return;
255
256
3958
  if (type == PromiseHookType::kBefore) {
257
    env->async_hooks()->push_async_ids(
258
626
      wrap->get_async_id(), wrap->get_trigger_async_id());
259
626
    wrap->EmitTraceEventBefore();
260
626
    AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id());
261
3332
  } else if (type == PromiseHookType::kAfter) {
262
631
    wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id());
263
631
    AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id());
264
631
    if (env->execution_async_id() == wrap->get_async_id()) {
265
      // This condition might not be true if async_hooks was enabled during
266
      // the promise callback execution.
267
      // Popping it off the stack can be skipped in that case, because it is
268
      // known that it would correspond to exactly one call with
269
      // PromiseHookType::kBefore that was not witnessed by the PromiseHook.
270
626
      env->async_hooks()->pop_async_id(wrap->get_async_id());
271
    }
272
2701
  } else if (type == PromiseHookType::kResolve) {
273
1436
    AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id());
274
  }
275
}
276
277
278
4408
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
279
4408
  Environment* env = Environment::GetCurrent(args);
280
281
8816
  CHECK(args[0]->IsObject());
282
283
  // All of init, before, after, destroy are supplied by async_hooks
284
  // internally, so this should every only be called once. At which time all
285
  // the functions should be set. Detect this by checking if init !IsEmpty().
286
8816
  CHECK(env->async_hooks_init_function().IsEmpty());
287
288
8816
  Local<Object> fn_obj = args[0].As<Object>();
289
290
#define SET_HOOK_FN(name)                                                     \
291
  Local<Value> name##_v = fn_obj->Get(                                        \
292
      env->context(),                                                         \
293
      FIXED_ONE_BYTE_STRING(env->isolate(), #name)).ToLocalChecked();         \
294
  CHECK(name##_v->IsFunction());                                              \
295
  env->set_async_hooks_##name##_function(name##_v.As<Function>());
296
297
26448
  SET_HOOK_FN(init);
298
26448
  SET_HOOK_FN(before);
299
26448
  SET_HOOK_FN(after);
300
26448
  SET_HOOK_FN(destroy);
301
26448
  SET_HOOK_FN(promise_resolve);
302
#undef SET_HOOK_FN
303
304
  {
305
    Local<FunctionTemplate> ctor =
306
4408
        FunctionTemplate::New(env->isolate());
307
8816
    ctor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PromiseWrap"));
308
4408
    Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
309
    promise_wrap_template->SetInternalFieldCount(
310
4408
        PromiseWrap::kInternalFieldCount);
311
    promise_wrap_template->SetAccessor(
312
        FIXED_ONE_BYTE_STRING(env->isolate(), "isChainedPromise"),
313
8816
        PromiseWrap::getIsChainedPromise);
314
4408
    env->set_promise_wrap_template(promise_wrap_template);
315
  }
316
4408
}
317
318
319
249
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
320
249
  Environment* env = Environment::GetCurrent(args);
321
249
  env->AddPromiseHook(PromiseHook, static_cast<void*>(env));
322
249
}
323
324
325
228
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
326
228
  Environment* env = Environment::GetCurrent(args);
327
328
  // Delay the call to `RemovePromiseHook` because we might currently be
329
  // between the `before` and `after` calls of a Promise.
330
650
  env->isolate()->EnqueueMicrotask([](void* data) {
331
211
    Environment* env = static_cast<Environment*>(data);
332
211
    env->RemovePromiseHook(PromiseHook, data);
333
878
  }, static_cast<void*>(env));
334
228
}
335
336
337
19014
class DestroyParam {
338
 public:
339
  double asyncId;
340
  Environment* env;
341
  Persistent<Object> target;
342
  Persistent<Object> propBag;
343
};
344
345
2152
void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) {
346
2152
  HandleScope scope(info.GetIsolate());
347
348
4304
  std::unique_ptr<DestroyParam> p{info.GetParameter()};
349
  Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(),
350
4304
                                                      p->propBag);
351
  Local<Value> val;
352
353
10760
  if (!prop_bag->Get(p->env->context(), p->env->destroyed_string())
354
6456
        .ToLocal(&val)) {
355
2152
    return;
356
  }
357
358
2152
  if (val->IsFalse()) {
359
2151
    AsyncWrap::EmitDestroy(p->env, p->asyncId);
360
2152
  }
361
  // unique_ptr goes out of scope here and pointer is deleted.
362
}
363
364
365
4186
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) {
366
8372
  CHECK(args[0]->IsObject());
367
8372
  CHECK(args[1]->IsNumber());
368
8372
  CHECK(args[2]->IsObject());
369
370
4186
  Isolate* isolate = args.GetIsolate();
371
4186
  DestroyParam* p = new DestroyParam();
372
12558
  p->asyncId = args[1].As<Number>()->Value();
373
4186
  p->env = Environment::GetCurrent(args);
374
12558
  p->target.Reset(isolate, args[0].As<Object>());
375
12558
  p->propBag.Reset(isolate, args[2].As<Object>());
376
4186
  p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter);
377
4186
}
378
379
380
132662
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
381
  AsyncWrap* wrap;
382
265324
  args.GetReturnValue().Set(-1);
383
265324
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
384
397923
  args.GetReturnValue().Set(wrap->get_async_id());
385
}
386
387
388
8
void AsyncWrap::PushAsyncIds(const FunctionCallbackInfo<Value>& args) {
389
8
  Environment* env = Environment::GetCurrent(args);
390
  // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail
391
  // then the checks in push_async_ids() and pop_async_id() will.
392
32
  double async_id = args[0]->NumberValue(env->context()).FromJust();
393
32
  double trigger_async_id = args[1]->NumberValue(env->context()).FromJust();
394
8
  env->async_hooks()->push_async_ids(async_id, trigger_async_id);
395
8
}
396
397
398
3
void AsyncWrap::PopAsyncIds(const FunctionCallbackInfo<Value>& args) {
399
3
  Environment* env = Environment::GetCurrent(args);
400
12
  double async_id = args[0]->NumberValue(env->context()).FromJust();
401
3
  args.GetReturnValue().Set(env->async_hooks()->pop_async_id(async_id));
402
}
403
404
405
27
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) {
406
  AsyncWrap* wrap;
407
54
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
408
  double execution_async_id =
409

54
      args[0]->IsNumber() ? args[0].As<Number>()->Value() : -1;
410
27
  wrap->AsyncReset(execution_async_id);
411
}
412
413
414
60824
void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
415
121648
  CHECK(args[0]->IsNumber());
416
  AsyncWrap::EmitDestroy(
417
      Environment::GetCurrent(args),
418
182472
      args[0].As<Number>()->Value());
419
60824
}
420
421
66726
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) {
422
66726
  Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template();
423
66726
  if (tmpl.IsEmpty()) {
424
4415
    tmpl = env->NewFunctionTemplate(nullptr);
425
8830
    tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
426
4415
    env->SetProtoMethod(tmpl, "getAsyncId", AsyncWrap::GetAsyncId);
427
4415
    env->SetProtoMethod(tmpl, "asyncReset", AsyncWrap::AsyncReset);
428
4415
    env->set_async_wrap_ctor_template(tmpl);
429
  }
430
66726
  return tmpl;
431
}
432
433
4408
void AsyncWrap::Initialize(Local<Object> target,
434
                           Local<Value> unused,
435
                           Local<Context> context,
436
                           void* priv) {
437
4408
  Environment* env = Environment::GetCurrent(context);
438
4408
  Isolate* isolate = env->isolate();
439
4408
  HandleScope scope(isolate);
440
441
4408
  env->SetMethod(target, "setupHooks", SetupHooks);
442
4408
  env->SetMethod(target, "pushAsyncIds", PushAsyncIds);
443
4408
  env->SetMethod(target, "popAsyncIds", PopAsyncIds);
444
4408
  env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
445
4408
  env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
446
4408
  env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
447
4408
  env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
448
449
  PropertyAttribute ReadOnlyDontDelete =
450
4408
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
451
452
#define FORCE_SET_TARGET_FIELD(obj, str, field)                               \
453
  (obj)->DefineOwnProperty(context,                                           \
454
                           FIXED_ONE_BYTE_STRING(isolate, str),               \
455
                           field,                                             \
456
                           ReadOnlyDontDelete).FromJust()
457
458
  // Attach the uint32_t[] where each slot contains the count of the number of
459
  // callbacks waiting to be called on a particular event. It can then be
460
  // incremented/decremented from JS quickly to communicate to C++ if there are
461
  // any callbacks waiting to be called.
462
17632
  FORCE_SET_TARGET_FIELD(target,
463
                         "async_hook_fields",
464
                         env->async_hooks()->fields().GetJSArray());
465
466
  // The following v8::Float64Array has 5 fields. These fields are shared in
467
  // this way to allow JS and C++ to read/write each value as quickly as
468
  // possible. The fields are represented as follows:
469
  //
470
  // kAsyncIdCounter: Maintains the state of the next unique id to be assigned.
471
  //
472
  // kDefaultTriggerAsyncId: Write the id of the resource responsible for a
473
  //   handle's creation just before calling the new handle's constructor.
474
  //   After the new handle is constructed kDefaultTriggerAsyncId is set back
475
  //   to -1.
476
17632
  FORCE_SET_TARGET_FIELD(target,
477
                         "async_id_fields",
478
                         env->async_hooks()->async_id_fields().GetJSArray());
479
480
  target->Set(context,
481
              env->async_ids_stack_string(),
482
17632
              env->async_hooks()->async_ids_stack().GetJSArray()).FromJust();
483
484
  target->Set(context,
485
              FIXED_ONE_BYTE_STRING(env->isolate(), "owner_symbol"),
486
17632
              env->owner_symbol()).FromJust();
487
488
4408
  Local<Object> constants = Object::New(isolate);
489
#define SET_HOOKS_CONSTANT(name)                                              \
490
  FORCE_SET_TARGET_FIELD(                                                     \
491
      constants, #name, Integer::New(isolate, AsyncHooks::name));
492
493
17632
  SET_HOOKS_CONSTANT(kInit);
494
17632
  SET_HOOKS_CONSTANT(kBefore);
495
17632
  SET_HOOKS_CONSTANT(kAfter);
496
17632
  SET_HOOKS_CONSTANT(kDestroy);
497
17632
  SET_HOOKS_CONSTANT(kPromiseResolve);
498
17632
  SET_HOOKS_CONSTANT(kTotals);
499
17632
  SET_HOOKS_CONSTANT(kCheck);
500
17632
  SET_HOOKS_CONSTANT(kExecutionAsyncId);
501
17632
  SET_HOOKS_CONSTANT(kTriggerAsyncId);
502
17632
  SET_HOOKS_CONSTANT(kAsyncIdCounter);
503
17632
  SET_HOOKS_CONSTANT(kDefaultTriggerAsyncId);
504
17632
  SET_HOOKS_CONSTANT(kStackLength);
505
#undef SET_HOOKS_CONSTANT
506
13224
  FORCE_SET_TARGET_FIELD(target, "constants", constants);
507
508
4408
  Local<Object> async_providers = Object::New(isolate);
509
#define V(p)                                                                  \
510
  FORCE_SET_TARGET_FIELD(                                                     \
511
      async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p));
512
546592
  NODE_ASYNC_PROVIDER_TYPES(V)
513
#undef V
514
13224
  FORCE_SET_TARGET_FIELD(target, "Providers", async_providers);
515
516
#undef FORCE_SET_TARGET_FIELD
517
518
4408
  env->set_async_hooks_init_function(Local<Function>());
519
4408
  env->set_async_hooks_before_function(Local<Function>());
520
4408
  env->set_async_hooks_after_function(Local<Function>());
521
4408
  env->set_async_hooks_destroy_function(Local<Function>());
522
4408
  env->set_async_hooks_promise_resolve_function(Local<Function>());
523
4408
  env->set_async_hooks_binding(target);
524
525
  // TODO(addaleax): This block might better work as a
526
  // AsyncWrapObject::Initialize() or AsyncWrapObject::GetConstructorTemplate()
527
  // function.
528
  {
529
4408
    auto class_name = FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap");
530
4408
    auto function_template = env->NewFunctionTemplate(AsyncWrapObject::New);
531
4408
    function_template->SetClassName(class_name);
532
8816
    function_template->Inherit(AsyncWrap::GetConstructorTemplate(env));
533
4408
    auto instance_template = function_template->InstanceTemplate();
534
4408
    instance_template->SetInternalFieldCount(1);
535
    auto function =
536
13224
        function_template->GetFunction(env->context()).ToLocalChecked();
537
13224
    target->Set(env->context(), class_name, function).FromJust();
538
4408
    env->set_async_wrap_object_ctor_template(function_template);
539
4408
  }
540
4408
}
541
542
543
325008
AsyncWrap::AsyncWrap(Environment* env,
544
                     Local<Object> object,
545
                     ProviderType provider,
546
                     double execution_async_id)
547
325008
    : AsyncWrap(env, object, provider, execution_async_id, false) {}
548
549
326291
AsyncWrap::AsyncWrap(Environment* env,
550
                     Local<Object> object,
551
                     ProviderType provider,
552
                     double execution_async_id,
553
                     bool silent)
554
    : BaseObject(env, object),
555
326291
      provider_type_(provider) {
556
326291
  CHECK_NE(provider, PROVIDER_NONE);
557
326291
  CHECK_GE(object->InternalFieldCount(), 1);
558
559
  // Use AsyncReset() call to execute the init() callbacks.
560
326291
  AsyncReset(execution_async_id, silent);
561
326291
}
562
563
564
650654
AsyncWrap::~AsyncWrap() {
565
325327
  EmitTraceEventDestroy();
566
325327
  EmitDestroy(env(), get_async_id());
567
325327
}
568
569
357384
void AsyncWrap::EmitTraceEventDestroy() {
570










357384
  switch (provider_type()) {
571
  #define V(PROVIDER)                                                         \
572
    case PROVIDER_ ## PROVIDER:                                               \
573
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
574
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
575
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
576
      break;
577









































714768
    NODE_ASYNC_PROVIDER_TYPES(V)
578
  #undef V
579
    default:
580
      UNREACHABLE();
581
  }
582
357384
}
583
584
450526
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
585


527835
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
586
77309
      !env->can_call_into_js()) {
587
823749
    return;
588
  }
589
590
77303
  if (env->destroy_async_id_list()->empty()) {
591
22180
    env->SetUnrefImmediate(DestroyAsyncIdsCallback, nullptr);
592
  }
593
594
77303
  env->destroy_async_id_list()->push_back(async_id);
595
}
596
597
598
// Generalized call for both the constructor and for handles that are pooled
599
// and reused over their lifetime. This way a new uid can be assigned when
600
// the resource is pulled out of the pool and put back into use.
601
355920
void AsyncWrap::AsyncReset(double execution_async_id, bool silent) {
602
355920
  if (async_id_ != -1) {
603
    // This instance was in use before, we have already emitted an init with
604
    // its previous async_id and need to emit a matching destroy for that
605
    // before generating a new async_id.
606
29629
    EmitDestroy(env(), async_id_);
607
  }
608
609
  // Now we can assign a new async_id_ to this instance.
610
  async_id_ =
611
355920
    execution_async_id == -1 ? env()->new_async_id() : execution_async_id;
612
355920
  trigger_async_id_ = env()->get_default_trigger_async_id();
613
614










355920
  switch (provider_type()) {
615
#define V(PROVIDER)                                                           \
616
    case PROVIDER_ ## PROVIDER:                                               \
617
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
618
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
619
        auto data = tracing::TracedValue::Create();                           \
620
        data->SetInteger("executionAsyncId",                                  \
621
                         static_cast<int64_t>(env()->execution_async_id()));  \
622
        data->SetInteger("triggerAsyncId",                                    \
623
                         static_cast<int64_t>(get_trigger_async_id()));       \
624
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
625
          TRACING_CATEGORY_NODE1(async_hooks),                                \
626
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
627
          "data", std::move(data));                                           \
628
        }                                                                     \
629
      break;
630





























































34
    NODE_ASYNC_PROVIDER_TYPES(V)
631
#undef V
632
    default:
633
      UNREACHABLE();
634
  }
635
636
711840
  if (silent) return;
637
638
  EmitAsyncInit(env(), object(),
639
355902
                env()->async_hooks()->provider_string(provider_type()),
640
711804
                async_id_, trigger_async_id_);
641
}
642
643
644
356443
void AsyncWrap::EmitAsyncInit(Environment* env,
645
                              Local<Object> object,
646
                              Local<String> type,
647
                              double async_id,
648
                              double trigger_async_id) {
649
356443
  CHECK(!object.IsEmpty());
650
356443
  CHECK(!type.IsEmpty());
651
356443
  AsyncHooks* async_hooks = env->async_hooks();
652
653
  // Nothing to execute, so can continue normally.
654
356443
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
655
699050
    return;
656
  }
657
658
13836
  HandleScope scope(env->isolate());
659
13836
  Local<Function> init_fn = env->async_hooks_init_function();
660
661
  Local<Value> argv[] = {
662
    Number::New(env->isolate(), async_id),
663
    type,
664
    Number::New(env->isolate(), trigger_async_id),
665
    object,
666
69180
  };
667
668
27672
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
669
55344
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
670
}
671
672
673
1037211
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
674
                                          int argc,
675
                                          Local<Value>* argv) {
676
1037211
  EmitTraceEventBefore();
677
678
1037211
  ProviderType provider = provider_type();
679
1037212
  async_context context { get_async_id(), get_trigger_async_id() };
680
  MaybeLocal<Value> ret = InternalMakeCallback(
681
1037214
      env(), object(), cb, argc, argv, context);
682
683
  // This is a static call with cached values because the `this` object may
684
  // no longer be alive at this point.
685
1037113
  EmitTraceEventAfter(provider, context.async_id);
686
687
1037113
  return ret;
688
}
689
690
std::string AsyncWrap::MemoryInfoName() const {
691
  return provider_names[provider_type()];
692
}
693
694
std::string AsyncWrap::diagnostic_name() const {
695
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
696
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
697
}
698
699
31
Local<Object> AsyncWrap::GetOwner() {
700
31
  return GetOwner(env(), object());
701
}
702
703
31
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
704
31
  EscapableHandleScope handle_scope(env->isolate());
705
31
  CHECK(!obj.IsEmpty());
706
707
62
  TryCatchScope ignore_exceptions(env);
708
  while (true) {
709
    Local<Value> owner;
710
96
    if (!obj->Get(env->context(),
711


336
                  env->owner_symbol()).ToLocal(&owner) ||
712
48
        !owner->IsObject()) {
713
62
      return handle_scope.Escape(obj);
714
    }
715
716
17
    obj = owner.As<Object>();
717
  }
718
}
719
720
}  // namespace node
721
722
4292
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)