GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/async_wrap.cc Lines: 315 335 94.0 %
Date: 2019-01-07 12:15:22 Branches: 655 1052 62.3 %

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

22642
  do {
97
22642
    std::vector<double> destroy_async_id_list;
98
22642
    destroy_async_id_list.swap(*env->destroy_async_id_list());
99
22642
    if (!env->can_call_into_js()) return;
100

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


1349389
  if (async_hooks->fields()[type] == 0 || !env->can_call_into_js())
119
2691296
    return;
120
121
7484
  HandleScope handle_scope(env->isolate());
122
7484
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
123
14968
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
124
29936
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
125
}
126
127
128
1440
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
129
  Emit(env, async_id, AsyncHooks::kPromiseResolve,
130
1440
       env->async_hooks_promise_resolve_function());
131
1440
}
132
133
134
672047
void AsyncWrap::EmitTraceEventBefore() {
135










672047
  switch (provider_type()) {
136
#define V(PROVIDER)                                                           \
137
    case PROVIDER_ ## PROVIDER:                                               \
138
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(                                      \
139
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
140
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
141
      break;
142
    NODE_ASYNC_PROVIDER_TYPES(V)
143
#undef V
144
    default:
145
      UNREACHABLE();
146
  }
147
672020
}
148
149
150
674008
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
151
  Emit(env, async_id, AsyncHooks::kBefore,
152
674008
       env->async_hooks_before_function());
153
674008
}
154
155
156
671977
void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) {
157










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

3966
  if (type == PromiseHookType::kInit || wrap == nullptr) {
235
1281
    bool silent = type != PromiseHookType::kInit;
236
237
    // set parent promise's async Id as this promise's triggerAsyncId
238
1281
    if (parent->IsPromise()) {
239
      // parent promise exists, current promise
240
      // is a chained promise, so we set parent promise's id as
241
      // current promise's triggerAsyncId
242
840
      Local<Promise> parent_promise = parent.As<Promise>();
243
840
      PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise);
244
840
      if (parent_wrap == nullptr) {
245
2
        parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true);
246
      }
247
248
840
      AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap);
249
840
      wrap = PromiseWrap::New(env, promise, parent_wrap, silent);
250
    } else {
251
441
      wrap = PromiseWrap::New(env, promise, nullptr, silent);
252
    }
253
  }
254
255
3966
  CHECK_NOT_NULL(wrap);
256
3966
  if (type == PromiseHookType::kBefore) {
257
    env->async_hooks()->push_async_ids(
258
628
      wrap->get_async_id(), wrap->get_trigger_async_id());
259
628
    wrap->EmitTraceEventBefore();
260
628
    AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id());
261
3338
  } else if (type == PromiseHookType::kAfter) {
262
633
    wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id());
263
633
    AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id());
264
633
    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
628
      env->async_hooks()->pop_async_id(wrap->get_async_id());
271
    }
272
2705
  } else if (type == PromiseHookType::kResolve) {
273
1440
    AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id());
274
  }
275
3966
}
276
277
278
3661
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
279
3661
  Environment* env = Environment::GetCurrent(args);
280
281
7322
  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
7322
  CHECK(env->async_hooks_init_function().IsEmpty());
287
288
7322
  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
21966
  SET_HOOK_FN(init);
298
21966
  SET_HOOK_FN(before);
299
21966
  SET_HOOK_FN(after);
300
21966
  SET_HOOK_FN(destroy);
301
21966
  SET_HOOK_FN(promise_resolve);
302
#undef SET_HOOK_FN
303
304
  {
305
    Local<FunctionTemplate> ctor =
306
3661
        FunctionTemplate::New(env->isolate());
307
7322
    ctor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PromiseWrap"));
308
3661
    Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
309
    promise_wrap_template->SetInternalFieldCount(
310
3661
        PromiseWrap::kInternalFieldCount);
311
    promise_wrap_template->SetAccessor(
312
        FIXED_ONE_BYTE_STRING(env->isolate(), "isChainedPromise"),
313
7322
        PromiseWrap::getIsChainedPromise);
314
3661
    env->set_promise_wrap_template(promise_wrap_template);
315
  }
316
3661
}
317
318
319
242
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
320
242
  Environment* env = Environment::GetCurrent(args);
321
242
  env->AddPromiseHook(PromiseHook, static_cast<void*>(env));
322
242
}
323
324
325
63
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
326
63
  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
187
  env->isolate()->EnqueueMicrotask([](void* data) {
331
62
    Environment* env = static_cast<Environment*>(data);
332
62
    env->RemovePromiseHook(PromiseHook, data);
333
250
  }, static_cast<void*>(env));
334
63
}
335
336
337
18990
class DestroyParam {
338
 public:
339
  double asyncId;
340
  Environment* env;
341
  Persistent<Object> target;
342
  Persistent<Object> propBag;
343
};
344
345
2148
void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) {
346
2148
  HandleScope scope(info.GetIsolate());
347
348
4296
  std::unique_ptr<DestroyParam> p{info.GetParameter()};
349
  Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(),
350
4296
                                                      p->propBag);
351
  Local<Value> val;
352
353
10740
  if (!prop_bag->Get(p->env->context(), p->env->destroyed_string())
354
6444
        .ToLocal(&val)) {
355
2148
    return;
356
  }
357
358
2148
  if (val->IsFalse()) {
359
2147
    AsyncWrap::EmitDestroy(p->env, p->asyncId);
360
2148
  }
361
  // unique_ptr goes out of scope here and pointer is deleted.
362
}
363
364
365
4182
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) {
366
8364
  CHECK(args[0]->IsObject());
367
8364
  CHECK(args[1]->IsNumber());
368
8364
  CHECK(args[2]->IsObject());
369
370
4182
  Isolate* isolate = args.GetIsolate();
371
4182
  DestroyParam* p = new DestroyParam();
372
12546
  p->asyncId = args[1].As<Number>()->Value();
373
4182
  p->env = Environment::GetCurrent(args);
374
12546
  p->target.Reset(isolate, args[0].As<Object>());
375
12546
  p->propBag.Reset(isolate, args[2].As<Object>());
376
4182
  p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter);
377
4182
}
378
379
380
85796
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
381
  AsyncWrap* wrap;
382
171592
  args.GetReturnValue().Set(-1);
383
171592
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
384
257325
  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
60276
void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
415
120552
  CHECK(args[0]->IsNumber());
416
  AsyncWrap::EmitDestroy(
417
      Environment::GetCurrent(args),
418
180828
      args[0].As<Number>()->Value());
419
60276
}
420
421
52926
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) {
422
52926
  Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template();
423
52926
  if (tmpl.IsEmpty()) {
424
3671
    tmpl = env->NewFunctionTemplate(nullptr);
425
7342
    tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
426
3671
    env->SetProtoMethod(tmpl, "getAsyncId", AsyncWrap::GetAsyncId);
427
3671
    env->SetProtoMethod(tmpl, "asyncReset", AsyncWrap::AsyncReset);
428
3671
    env->set_async_wrap_ctor_template(tmpl);
429
  }
430
52926
  return tmpl;
431
}
432
433
3661
void AsyncWrap::Initialize(Local<Object> target,
434
                           Local<Value> unused,
435
                           Local<Context> context,
436
                           void* priv) {
437
3661
  Environment* env = Environment::GetCurrent(context);
438
3661
  Isolate* isolate = env->isolate();
439
3661
  HandleScope scope(isolate);
440
441
3661
  env->SetMethod(target, "setupHooks", SetupHooks);
442
3661
  env->SetMethod(target, "pushAsyncIds", PushAsyncIds);
443
3661
  env->SetMethod(target, "popAsyncIds", PopAsyncIds);
444
3661
  env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
445
3661
  env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
446
3661
  env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
447
3661
  env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
448
449
  PropertyAttribute ReadOnlyDontDelete =
450
3661
      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
14644
  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
14644
  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
14644
              env->async_hooks()->async_ids_stack().GetJSArray()).FromJust();
483
484
  target->Set(context,
485
              FIXED_ONE_BYTE_STRING(env->isolate(), "owner_symbol"),
486
14644
              env->owner_symbol()).FromJust();
487
488
3661
  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
14644
  SET_HOOKS_CONSTANT(kInit);
494
14644
  SET_HOOKS_CONSTANT(kBefore);
495
14644
  SET_HOOKS_CONSTANT(kAfter);
496
14644
  SET_HOOKS_CONSTANT(kDestroy);
497
14644
  SET_HOOKS_CONSTANT(kPromiseResolve);
498
14644
  SET_HOOKS_CONSTANT(kTotals);
499
14644
  SET_HOOKS_CONSTANT(kCheck);
500
14644
  SET_HOOKS_CONSTANT(kExecutionAsyncId);
501
14644
  SET_HOOKS_CONSTANT(kTriggerAsyncId);
502
14644
  SET_HOOKS_CONSTANT(kAsyncIdCounter);
503
14644
  SET_HOOKS_CONSTANT(kDefaultTriggerAsyncId);
504
14644
  SET_HOOKS_CONSTANT(kStackLength);
505
#undef SET_HOOKS_CONSTANT
506
10983
  FORCE_SET_TARGET_FIELD(target, "constants", constants);
507
508
3661
  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
453964
  NODE_ASYNC_PROVIDER_TYPES(V)
513
#undef V
514
10983
  FORCE_SET_TARGET_FIELD(target, "Providers", async_providers);
515
516
#undef FORCE_SET_TARGET_FIELD
517
518
3661
  env->set_async_hooks_init_function(Local<Function>());
519
3661
  env->set_async_hooks_before_function(Local<Function>());
520
3661
  env->set_async_hooks_after_function(Local<Function>());
521
3661
  env->set_async_hooks_destroy_function(Local<Function>());
522
3661
  env->set_async_hooks_promise_resolve_function(Local<Function>());
523
3661
  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
3661
    auto class_name = FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap");
530
3661
    auto function_template = env->NewFunctionTemplate(AsyncWrapObject::New);
531
3661
    function_template->SetClassName(class_name);
532
7322
    function_template->Inherit(AsyncWrap::GetConstructorTemplate(env));
533
3661
    auto instance_template = function_template->InstanceTemplate();
534
3661
    instance_template->SetInternalFieldCount(1);
535
    auto function =
536
10983
        function_template->GetFunction(env->context()).ToLocalChecked();
537
10983
    target->Set(env->context(), class_name, function).FromJust();
538
3661
    env->set_async_wrap_object_ctor_template(function_template);
539
3661
  }
540
3661
}
541
542
543
264369
AsyncWrap::AsyncWrap(Environment* env,
544
                     Local<Object> object,
545
                     ProviderType provider,
546
                     double execution_async_id)
547
264369
    : AsyncWrap(env, object, provider, execution_async_id, false) {}
548
549
265652
AsyncWrap::AsyncWrap(Environment* env,
550
                     Local<Object> object,
551
                     ProviderType provider,
552
                     double execution_async_id,
553
                     bool silent)
554
    : BaseObject(env, object),
555
265652
      provider_type_(provider) {
556
265652
  CHECK_NE(provider, PROVIDER_NONE);
557
265652
  CHECK_GE(object->InternalFieldCount(), 1);
558
559
  // Use AsyncReset() call to execute the init() callbacks.
560
265652
  AsyncReset(execution_async_id, silent);
561
265652
}
562
563
564
529828
AsyncWrap::~AsyncWrap() {
565
264914
  EmitTraceEventDestroy();
566
264914
  EmitDestroy(env(), get_async_id());
567
264914
}
568
569
269698
void AsyncWrap::EmitTraceEventDestroy() {
570










269698
  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
    NODE_ASYNC_PROVIDER_TYPES(V)
578
  #undef V
579
    default:
580
      UNREACHABLE();
581
  }
582
269698
}
583
584
335180
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
585


413050
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
586
77870
      !env->can_call_into_js()) {
587
593759
    return;
588
  }
589
590
76601
  if (env->destroy_async_id_list()->empty()) {
591
22660
    env->SetUnrefImmediate(DestroyAsyncIdsCallback, nullptr);
592
  }
593
594
76601
  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
268173
void AsyncWrap::AsyncReset(double execution_async_id, bool silent) {
602
268173
  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
2521
    EmitDestroy(env(), async_id_);
607
  }
608
609
  // Now we can assign a new async_id_ to this instance.
610
  async_id_ =
611
268173
    execution_async_id == -1 ? env()->new_async_id() : execution_async_id;
612
268173
  trigger_async_id_ = env()->get_default_trigger_async_id();
613
614










268173
  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
    NODE_ASYNC_PROVIDER_TYPES(V)
631
#undef V
632
    default:
633
      UNREACHABLE();
634
  }
635
636
536346
  if (silent) return;
637
638
  EmitAsyncInit(env(), object(),
639
268155
                env()->async_hooks()->provider_string(provider_type()),
640
536310
                async_id_, trigger_async_id_);
641
}
642
643
644
268696
void AsyncWrap::EmitAsyncInit(Environment* env,
645
                              Local<Object> object,
646
                              Local<String> type,
647
                              double async_id,
648
                              double trigger_async_id) {
649
268696
  CHECK(!object.IsEmpty());
650
268696
  CHECK(!type.IsEmpty());
651
268696
  AsyncHooks* async_hooks = env->async_hooks();
652
653
  // Nothing to execute, so can continue normally.
654
268696
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
655
523729
    return;
656
  }
657
658
13663
  HandleScope scope(env->isolate());
659
13663
  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
68315
  };
667
668
27326
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
669
54652
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
670
}
671
672
673
671442
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
674
                                          int argc,
675
                                          Local<Value>* argv) {
676
671442
  EmitTraceEventBefore();
677
678
671408
  ProviderType provider = provider_type();
679
671432
  async_context context { get_async_id(), get_trigger_async_id() };
680
  MaybeLocal<Value> ret = InternalMakeCallback(
681
671437
      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
671344
  EmitTraceEventAfter(provider, context.async_id);
686
687
671344
  return ret;
688
}
689
690
691
/* Public C++ embedder API */
692
693
694
2
async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) {
695
  // Environment::GetCurrent() allocates a Local<> handle.
696
2
  HandleScope handle_scope(isolate);
697
2
  Environment* env = Environment::GetCurrent(isolate);
698
2
  if (env == nullptr) return -1;
699
2
  return env->execution_async_id();
700
}
701
702
703
2
async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) {
704
  // Environment::GetCurrent() allocates a Local<> handle.
705
2
  HandleScope handle_scope(isolate);
706
2
  Environment* env = Environment::GetCurrent(isolate);
707
2
  if (env == nullptr) return -1;
708
2
  return env->trigger_async_id();
709
}
710
711
712
534
async_context EmitAsyncInit(Isolate* isolate,
713
                            Local<Object> resource,
714
                            const char* name,
715
                            async_id trigger_async_id) {
716
534
  HandleScope handle_scope(isolate);
717
  Local<String> type =
718
      String::NewFromUtf8(isolate, name, NewStringType::kInternalized)
719
1068
          .ToLocalChecked();
720
534
  return EmitAsyncInit(isolate, resource, type, trigger_async_id);
721
}
722
723
541
async_context EmitAsyncInit(Isolate* isolate,
724
                            Local<Object> resource,
725
                            Local<String> name,
726
                            async_id trigger_async_id) {
727
541
  HandleScope handle_scope(isolate);
728
541
  Environment* env = Environment::GetCurrent(isolate);
729
541
  CHECK_NOT_NULL(env);
730
731
  // Initialize async context struct
732
541
  if (trigger_async_id == -1)
733
538
    trigger_async_id = env->get_default_trigger_async_id();
734
735
  async_context context = {
736
541
    env->new_async_id(),  // async_id_
737
    trigger_async_id  // trigger_async_id_
738
541
  };
739
740
  // Run init hooks
741
  AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id,
742
541
                           context.trigger_async_id);
743
744
541
  return context;
745
}
746
747
538
void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) {
748
  // Environment::GetCurrent() allocates a Local<> handle.
749
538
  HandleScope handle_scope(isolate);
750
  AsyncWrap::EmitDestroy(
751
538
      Environment::GetCurrent(isolate), asyncContext.async_id);
752
538
}
753
754
std::string AsyncWrap::MemoryInfoName() const {
755
  return provider_names[provider_type()];
756
}
757
758
std::string AsyncWrap::diagnostic_name() const {
759
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
760
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
761
}
762
763
31
Local<Object> AsyncWrap::GetOwner() {
764
31
  return GetOwner(env(), object());
765
}
766
767
31
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
768
31
  EscapableHandleScope handle_scope(env->isolate());
769
31
  CHECK(!obj.IsEmpty());
770
771
62
  TryCatchScope ignore_exceptions(env);
772
  while (true) {
773
    Local<Value> owner;
774
96
    if (!obj->Get(env->context(),
775


336
                  env->owner_symbol()).ToLocal(&owner) ||
776
48
        !owner->IsObject()) {
777
62
      return handle_scope.Escape(obj);
778
    }
779
780
17
    obj = owner.As<Object>();
781
  }
782
}
783
784
}  // namespace node
785
786
3596
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)