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: 313 324 96.6 %
Date: 2019-05-05 22:32:45 Branches: 683 1100 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.h"  // NOLINT(build/include_inline)
23
#include "async_wrap-inl.h"
24
#include "env-inl.h"
25
#include "node_errors.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::Global;
39
using v8::HandleScope;
40
using v8::Integer;
41
using v8::Isolate;
42
using v8::Local;
43
using v8::MaybeLocal;
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 TryCatchScope = node::errors::TryCatchScope;
61
62
namespace node {
63
64
static const char* const provider_names[] = {
65
#define V(PROVIDER)                                                           \
66
  #PROVIDER,
67
  NODE_ASYNC_PROVIDER_TYPES(V)
68
#undef V
69
};
70
71
72
186
struct AsyncWrapObject : public AsyncWrap {
73
93
  static inline void New(const FunctionCallbackInfo<Value>& args) {
74
93
    Environment* env = Environment::GetCurrent(args);
75
93
    CHECK(args.IsConstructCall());
76
186
    CHECK(env->async_wrap_object_ctor_template()->HasInstance(args.This()));
77
186
    CHECK(args[0]->IsUint32());
78
279
    auto type = static_cast<ProviderType>(args[0].As<Uint32>()->Value());
79
93
    new AsyncWrapObject(env, args.This(), type);
80
93
  }
81
82
93
  inline AsyncWrapObject(Environment* env, Local<Object> object,
83
93
                         ProviderType type) : AsyncWrap(env, object, type) {}
84
85
3
  SET_NO_MEMORY_INFO()
86
3
  SET_MEMORY_INFO_NAME(AsyncWrapObject)
87
3
  SET_SELF_SIZE(AsyncWrapObject)
88
};
89
90
22175
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env, void* data) {
91
22175
  Local<Function> fn = env->async_hooks_destroy_function();
92
93
22175
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
94
95

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

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


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











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











































1740996
    NODE_ASYNC_PROVIDER_TYPES(V)
142
#undef V
143
    default:
144
      UNREACHABLE();
145
  }
146
870498
}
147
148
149
872368
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
150
  Emit(env, async_id, AsyncHooks::kBefore,
151
872368
       env->async_hooks_before_function());
152
872364
}
153
154
155
870391
void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) {
156











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











































1740784
    NODE_ASYNC_PROVIDER_TYPES(V)
164
#undef V
165
    default:
166
      UNREACHABLE();
167
  }
168
870392
}
169
170
171
872272
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
172
  // If the user's callback failed then the after() hooks will be called at the
173
  // end of _fatalException().
174
  Emit(env, async_id, AsyncHooks::kAfter,
175
872272
       env->async_hooks_after_function());
176
872275
}
177
178
1610
class PromiseWrap : public AsyncWrap {
179
 public:
180
941
  PromiseWrap(Environment* env, Local<Object> object, bool silent)
181
941
      : AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) {
182
941
    MakeWeak();
183
941
  }
184
185
6
  SET_NO_MEMORY_INFO()
186
6
  SET_MEMORY_INFO_NAME(PromiseWrap)
187
6
  SET_SELF_SIZE(PromiseWrap)
188
189
  static constexpr int kIsChainedPromiseField = 1;
190
  static constexpr int kInternalFieldCount = 2;
191
192
  static PromiseWrap* New(Environment* env,
193
                          Local<Promise> promise,
194
                          PromiseWrap* parent_wrap,
195
                          bool silent);
196
  static void getIsChainedPromise(Local<String> property,
197
                                  const PropertyCallbackInfo<Value>& info);
198
};
199
200
941
PromiseWrap* PromiseWrap::New(Environment* env,
201
                              Local<Promise> promise,
202
                              PromiseWrap* parent_wrap,
203
                              bool silent) {
204
  Local<Object> obj;
205
2823
  if (!env->promise_wrap_template()->NewInstance(env->context()).ToLocal(&obj))
206
    return nullptr;
207
  obj->SetInternalField(PromiseWrap::kIsChainedPromiseField,
208
496
                        parent_wrap != nullptr ? v8::True(env->isolate())
209
2327
                                               : v8::False(env->isolate()));
210
1882
  CHECK_NULL(promise->GetAlignedPointerFromInternalField(0));
211
941
  promise->SetInternalField(0, obj);
212
941
  return new PromiseWrap(env, obj, silent);
213
}
214
215
2
void PromiseWrap::getIsChainedPromise(Local<String> property,
216
                                      const PropertyCallbackInfo<Value>& info) {
217
  info.GetReturnValue().Set(
218
8
    info.Holder()->GetInternalField(kIsChainedPromiseField));
219
2
}
220
221
3264
static PromiseWrap* extractPromiseWrap(Local<Promise> promise) {
222
6528
  Local<Value> resource_object_value = promise->GetInternalField(0);
223
3264
  if (resource_object_value->IsObject()) {
224
2323
    return Unwrap<PromiseWrap>(resource_object_value.As<Object>());
225
  }
226
941
  return nullptr;
227
}
228
229
2768
static void PromiseHook(PromiseHookType type, Local<Promise> promise,
230
                        Local<Value> parent) {
231
2768
  Local<Context> context = promise->CreationContext();
232
233
2768
  Environment* env = Environment::GetCurrent(context);
234
2768
  if (env == nullptr) return;
235
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
236
2768
                              "EnvPromiseHook", env);
237
238
2768
  PromiseWrap* wrap = extractPromiseWrap(promise);
239

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

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











243803
  switch (provider_type()) {
591
  #define V(PROVIDER)                                                         \
592
    case PROVIDER_ ## PROVIDER:                                               \
593
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
594
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
595
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
596
      break;
597











































487606
    NODE_ASYNC_PROVIDER_TYPES(V)
598
  #undef V
599
    default:
600
      UNREACHABLE();
601
  }
602
243803
}
603
604
307887
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
605


384675
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
606
76788
      !env->can_call_into_js()) {
607
539919
    return;
608
  }
609
610
75855
  if (env->destroy_async_id_list()->empty()) {
611
22198
    env->SetUnrefImmediate(DestroyAsyncIdsCallback, nullptr);
612
  }
613
614
75855
  env->destroy_async_id_list()->push_back(async_id);
615
}
616
617
211006
void AsyncWrap::AsyncReset(double execution_async_id, bool silent) {
618
211006
  AsyncReset(object(), execution_async_id, silent);
619
211006
}
620
621
// Generalized call for both the constructor and for handles that are pooled
622
// and reused over their lifetime. This way a new uid can be assigned when
623
// the resource is pulled out of the pool and put back into use.
624
242356
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
625
                           bool silent) {
626
242356
  CHECK_NE(provider_type(), PROVIDER_NONE);
627
628
242356
  if (async_id_ != kInvalidAsyncId) {
629
    // This instance was in use before, we have already emitted an init with
630
    // its previous async_id and need to emit a matching destroy for that
631
    // before generating a new async_id.
632
236
    EmitDestroy();
633
  }
634
635
  // Now we can assign a new async_id_ to this instance.
636
242356
  async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id()
637
484712
                                                     : execution_async_id;
638
242356
  trigger_async_id_ = env()->get_default_trigger_async_id();
639
640











242356
  switch (provider_type()) {
641
#define V(PROVIDER)                                                           \
642
    case PROVIDER_ ## PROVIDER:                                               \
643
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
644
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
645
        auto data = tracing::TracedValue::Create();                           \
646
        data->SetInteger("executionAsyncId",                                  \
647
                         static_cast<int64_t>(env()->execution_async_id()));  \
648
        data->SetInteger("triggerAsyncId",                                    \
649
                         static_cast<int64_t>(get_trigger_async_id()));       \
650
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
651
          TRACING_CATEGORY_NODE1(async_hooks),                                \
652
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
653
          "data", std::move(data));                                           \
654
        }                                                                     \
655
      break;
656
































































34
    NODE_ASYNC_PROVIDER_TYPES(V)
657
#undef V
658
    default:
659
      UNREACHABLE();
660
  }
661
662
484712
  if (silent) return;
663
664
  EmitAsyncInit(env(), resource,
665
242342
                env()->async_hooks()->provider_string(provider_type()),
666
484684
                async_id_, trigger_async_id_);
667
}
668
669
670
242884
void AsyncWrap::EmitAsyncInit(Environment* env,
671
                              Local<Object> object,
672
                              Local<String> type,
673
                              double async_id,
674
                              double trigger_async_id) {
675
242884
  CHECK(!object.IsEmpty());
676
242884
  CHECK(!type.IsEmpty());
677
242884
  AsyncHooks* async_hooks = env->async_hooks();
678
679
  // Nothing to execute, so can continue normally.
680
242884
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
681
472236
    return;
682
  }
683
684
13532
  HandleScope scope(env->isolate());
685
13532
  Local<Function> init_fn = env->async_hooks_init_function();
686
687
  Local<Value> argv[] = {
688
    Number::New(env->isolate(), async_id),
689
    type,
690
    Number::New(env->isolate(), trigger_async_id),
691
    object,
692
67660
  };
693
694
27064
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
695
54128
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
696
}
697
698
699
870040
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
700
                                          int argc,
701
                                          Local<Value>* argv) {
702
870040
  EmitTraceEventBefore();
703
704
870038
  ProviderType provider = provider_type();
705
870038
  async_context context { get_async_id(), get_trigger_async_id() };
706
  MaybeLocal<Value> ret = InternalMakeCallback(
707
870036
      env(), object(), cb, argc, argv, context);
708
709
  // This is a static call with cached values because the `this` object may
710
  // no longer be alive at this point.
711
869932
  EmitTraceEventAfter(provider, context.async_id);
712
713
869930
  return ret;
714
}
715
716
std::string AsyncWrap::MemoryInfoName() const {
717
  return provider_names[provider_type()];
718
}
719
720
std::string AsyncWrap::diagnostic_name() const {
721
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
722
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
723
}
724
725
31
Local<Object> AsyncWrap::GetOwner() {
726
31
  return GetOwner(env(), object());
727
}
728
729
31
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
730
31
  EscapableHandleScope handle_scope(env->isolate());
731
31
  CHECK(!obj.IsEmpty());
732
733
62
  TryCatchScope ignore_exceptions(env);
734
  while (true) {
735
    Local<Value> owner;
736
96
    if (!obj->Get(env->context(),
737


336
                  env->owner_symbol()).ToLocal(&owner) ||
738
48
        !owner->IsObject()) {
739
62
      return handle_scope.Escape(obj);
740
    }
741
742
17
    obj = owner.As<Object>();
743
  }
744
}
745
746
}  // namespace node
747
748
4523
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)