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: 322 334 96.4 %
Date: 2017-12-18 Branches: 602 810 74.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 "util-inl.h"
25
26
#include "uv.h"
27
#include "v8.h"
28
#include "v8-profiler.h"
29
30
using v8::Array;
31
using v8::Context;
32
using v8::Float64Array;
33
using v8::Function;
34
using v8::FunctionCallbackInfo;
35
using v8::FunctionTemplate;
36
using v8::HandleScope;
37
using v8::HeapProfiler;
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::PropertyCallbackInfo;
48
using v8::RetainedObjectInfo;
49
using v8::String;
50
using v8::Symbol;
51
using v8::TryCatch;
52
using v8::Undefined;
53
using v8::Value;
54
55
using AsyncHooks = node::Environment::AsyncHooks;
56
57
namespace node {
58
59
static const char* const provider_names[] = {
60
#define V(PROVIDER)                                                           \
61
  #PROVIDER,
62
  NODE_ASYNC_PROVIDER_TYPES(V)
63
#undef V
64
};
65
66
67
// Report correct information in a heapdump.
68
69
4
class RetainedAsyncInfo: public RetainedObjectInfo {
70
 public:
71
  explicit RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap);
72
73
  void Dispose() override;
74
  bool IsEquivalent(RetainedObjectInfo* other) override;
75
  intptr_t GetHash() override;
76
  const char* GetLabel() override;
77
  intptr_t GetSizeInBytes() override;
78
79
 private:
80
  const char* label_;
81
  const AsyncWrap* wrap_;
82
  const int length_;
83
};
84
85
86
2
RetainedAsyncInfo::RetainedAsyncInfo(uint16_t class_id, AsyncWrap* wrap)
87
2
    : label_(provider_names[class_id - NODE_ASYNC_ID_OFFSET]),
88
      wrap_(wrap),
89
4
      length_(wrap->self_size()) {
90
2
}
91
92
93
2
void RetainedAsyncInfo::Dispose() {
94
2
  delete this;
95
2
}
96
97
98
bool RetainedAsyncInfo::IsEquivalent(RetainedObjectInfo* other) {
99
  return label_ == other->GetLabel() &&
100
          wrap_ == static_cast<RetainedAsyncInfo*>(other)->wrap_;
101
}
102
103
104
4
intptr_t RetainedAsyncInfo::GetHash() {
105
4
  return reinterpret_cast<intptr_t>(wrap_);
106
}
107
108
109
6
const char* RetainedAsyncInfo::GetLabel() {
110
6
  return label_;
111
}
112
113
114
2
intptr_t RetainedAsyncInfo::GetSizeInBytes() {
115
2
  return length_;
116
}
117
118
119
2
RetainedObjectInfo* WrapperInfo(uint16_t class_id, Local<Value> wrapper) {
120
  // No class_id should be the provider type of NONE.
121
2
  CHECK_GT(class_id, NODE_ASYNC_ID_OFFSET);
122
  // And make sure the class_id doesn't extend past the last provider.
123
2
  CHECK_LE(class_id - NODE_ASYNC_ID_OFFSET, AsyncWrap::PROVIDERS_LENGTH);
124
2
  CHECK(wrapper->IsObject());
125
2
  CHECK(!wrapper.IsEmpty());
126
127
2
  Local<Object> object = wrapper.As<Object>();
128
2
  CHECK_GT(object->InternalFieldCount(), 0);
129
130
2
  AsyncWrap* wrap = Unwrap<AsyncWrap>(object);
131
2
  CHECK_NE(nullptr, wrap);
132
133
2
  return new RetainedAsyncInfo(class_id, wrap);
134
}
135
136
137
// end RetainedAsyncInfo
138
139
140
62120
static void DestroyAsyncIdsCallback(Environment* env, void* data) {
141
62120
  Local<Function> fn = env->async_hooks_destroy_function();
142
143
62120
  FatalTryCatch try_catch(env);
144
145

62122
  do {
146
62122
    std::vector<double> destroy_async_id_list;
147
62122
    destroy_async_id_list.swap(*env->destroy_async_id_list());
148

127727
    for (auto async_id : destroy_async_id_list) {
149
      // Want each callback to be cleaned up after itself, instead of cleaning
150
      // them all up after the while() loop completes.
151
65605
      HandleScope scope(env->isolate());
152
65605
      Local<Value> async_id_value = Number::New(env->isolate(), async_id);
153
      MaybeLocal<Value> ret = fn->Call(
154
196815
          env->context(), Undefined(env->isolate()), 1, &async_id_value);
155
156
65605
      if (ret.IsEmpty())
157
62120
        return;
158
127727
    }
159
124242
  } while (!env->destroy_async_id_list()->empty());
160
}
161
162
163
621
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
164
621
  AsyncHooks* async_hooks = env->async_hooks();
165
166
621
  if (async_hooks->fields()[AsyncHooks::kPromiseResolve] == 0)
167
1240
    return;
168
169
2
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
170
2
  Local<Function> fn = env->async_hooks_promise_resolve_function();
171
2
  FatalTryCatch try_catch(env);
172
6
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
173
}
174
175
176
350715
void AsyncWrap::EmitTraceEventBefore() {
177








350715
  switch (provider_type()) {
178
#define V(PROVIDER)                                                           \
179
    case PROVIDER_ ## PROVIDER:                                               \
180
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("node.async_hooks",                   \
181
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
182
      break;
183
    NODE_ASYNC_PROVIDER_TYPES(V)
184
#undef V
185
    default:
186
      UNREACHABLE();
187
  }
188
350715
}
189
190
191
351652
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
192
351652
  AsyncHooks* async_hooks = env->async_hooks();
193
194
351652
  if (async_hooks->fields()[AsyncHooks::kBefore] == 0)
195
701916
    return;
196
197
1388
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
198
1388
  Local<Function> fn = env->async_hooks_before_function();
199
1388
  FatalTryCatch try_catch(env);
200
4164
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
201
}
202
203
204
350605
void AsyncWrap::EmitTraceEventAfter() {
205








350605
  switch (provider_type()) {
206
#define V(PROVIDER)                                                           \
207
    case PROVIDER_ ## PROVIDER:                                               \
208
      TRACE_EVENT_NESTABLE_ASYNC_END0("node.async_hooks",                     \
209
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
210
      break;
211
    NODE_ASYNC_PROVIDER_TYPES(V)
212
#undef V
213
    default:
214
      UNREACHABLE();
215
  }
216
350605
}
217
218
219
351562
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
220
351562
  AsyncHooks* async_hooks = env->async_hooks();
221
222
351562
  if (async_hooks->fields()[AsyncHooks::kAfter] == 0)
223
701771
    return;
224
225
  // If the user's callback failed then the after() hooks will be called at the
226
  // end of _fatalException().
227
1353
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
228
1353
  Local<Function> fn = env->async_hooks_after_function();
229
1353
  FatalTryCatch try_catch(env);
230
4059
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
231
}
232
233
1030
class PromiseWrap : public AsyncWrap {
234
 public:
235
656
  PromiseWrap(Environment* env, Local<Object> object, bool silent)
236
656
      : AsyncWrap(env, object, silent) {
237
656
    MakeWeak(this);
238
656
  }
239
  size_t self_size() const override { return sizeof(*this); }
240
241
  static constexpr int kPromiseField = 1;
242
  static constexpr int kParentAsyncIdField = 2;
243
  static constexpr int kInternalFieldCount = 3;
244
245
  static PromiseWrap* New(Environment* env,
246
                          Local<Promise> promise,
247
                          PromiseWrap* parent_wrap,
248
                          bool silent);
249
  static void GetPromise(Local<String> property,
250
                         const PropertyCallbackInfo<Value>& info);
251
  static void getParentAsyncId(Local<String> property,
252
                          const PropertyCallbackInfo<Value>& info);
253
};
254
255
656
PromiseWrap* PromiseWrap::New(Environment* env,
256
                              Local<Promise> promise,
257
                              PromiseWrap* parent_wrap,
258
                              bool silent) {
259
  Local<Object> object = env->promise_wrap_template()
260
1968
                            ->NewInstance(env->context()).ToLocalChecked();
261
656
  object->SetInternalField(PromiseWrap::kPromiseField, promise);
262
656
  if (parent_wrap != nullptr) {
263
    object->SetInternalField(PromiseWrap::kParentAsyncIdField,
264
                             Number::New(env->isolate(),
265
806
                                         parent_wrap->get_async_id()));
266
  }
267
1312
  CHECK_EQ(promise->GetAlignedPointerFromInternalField(0), nullptr);
268
656
  promise->SetInternalField(0, object);
269
656
  return new PromiseWrap(env, object, silent);
270
}
271
272
791
void PromiseWrap::GetPromise(Local<String> property,
273
                             const PropertyCallbackInfo<Value>& info) {
274
3164
  info.GetReturnValue().Set(info.Holder()->GetInternalField(kPromiseField));
275
791
}
276
277
2
void PromiseWrap::getParentAsyncId(Local<String> property,
278
                              const PropertyCallbackInfo<Value>& info) {
279
  info.GetReturnValue().Set(
280
8
    info.Holder()->GetInternalField(kParentAsyncIdField));
281
2
}
282
283
1816
static void PromiseHook(PromiseHookType type, Local<Promise> promise,
284
                        Local<Value> parent, void* arg) {
285
1816
  Environment* env = static_cast<Environment*>(arg);
286
3632
  Local<Value> resource_object_value = promise->GetInternalField(0);
287
1816
  PromiseWrap* wrap = nullptr;
288
1816
  if (resource_object_value->IsObject()) {
289
1162
    Local<Object> resource_object = resource_object_value.As<Object>();
290
1162
    wrap = Unwrap<PromiseWrap>(resource_object);
291
  }
292
293

1816
  if (type == PromiseHookType::kInit || wrap == nullptr) {
294
654
    bool silent = type != PromiseHookType::kInit;
295
654
    PromiseWrap* parent_wrap = nullptr;
296
297
    // set parent promise's async Id as this promise's triggerAsyncId
298
654
    if (parent->IsPromise()) {
299
      // parent promise exists, current promise
300
      // is a chained promise, so we set parent promise's id as
301
      // current promise's triggerAsyncId
302
403
      Local<Promise> parent_promise = parent.As<Promise>();
303
806
      Local<Value> parent_resource = parent_promise->GetInternalField(0);
304
403
      if (parent_resource->IsObject()) {
305
401
        parent_wrap = Unwrap<PromiseWrap>(parent_resource.As<Object>());
306
      }
307
308
403
      if (parent_wrap == nullptr) {
309
2
        parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true);
310
      }
311
      // get id from parentWrap
312
403
      double trigger_async_id = parent_wrap->get_async_id();
313
403
      env->set_init_trigger_async_id(trigger_async_id);
314
    }
315
316
654
    wrap = PromiseWrap::New(env, promise, parent_wrap, silent);
317
  }
318
319
1816
  CHECK_NE(wrap, nullptr);
320
1816
  if (type == PromiseHookType::kBefore) {
321
    env->async_hooks()->push_async_ids(
322
273
      wrap->get_async_id(), wrap->get_trigger_async_id());
323
273
      wrap->EmitTraceEventBefore();
324
273
    AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id());
325
1543
  } else if (type == PromiseHookType::kAfter) {
326
278
    wrap->EmitTraceEventAfter();
327
278
    AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id());
328
278
    if (env->execution_async_id() == wrap->get_async_id()) {
329
      // This condition might not be true if async_hooks was enabled during
330
      // the promise callback execution.
331
      // Popping it off the stack can be skipped in that case, because is is
332
      // known that it would correspond to exactly one call with
333
      // PromiseHookType::kBefore that was not witnessed by the PromiseHook.
334
273
      env->async_hooks()->pop_async_id(wrap->get_async_id());
335
    }
336
1265
  } else if (type == PromiseHookType::kResolve) {
337
621
    AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id());
338
  }
339
1816
}
340
341
342
3348
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
343
3348
  Environment* env = Environment::GetCurrent(args);
344
345
6696
  if (!args[0]->IsObject())
346
3348
    return env->ThrowTypeError("first argument must be an object");
347
348
  // All of init, before, after, destroy are supplied by async_hooks
349
  // internally, so this should every only be called once. At which time all
350
  // the functions should be set. Detect this by checking if init !IsEmpty().
351
6696
  CHECK(env->async_hooks_init_function().IsEmpty());
352
353
6696
  Local<Object> fn_obj = args[0].As<Object>();
354
355
#define SET_HOOK_FN(name)                                                     \
356
  Local<Value> name##_v = fn_obj->Get(                                        \
357
      env->context(),                                                         \
358
      FIXED_ONE_BYTE_STRING(env->isolate(), #name)).ToLocalChecked();         \
359
  CHECK(name##_v->IsFunction());                                              \
360
  env->set_async_hooks_##name##_function(name##_v.As<Function>());
361
362
20088
  SET_HOOK_FN(init);
363
20088
  SET_HOOK_FN(before);
364
20088
  SET_HOOK_FN(after);
365
20088
  SET_HOOK_FN(destroy);
366
20088
  SET_HOOK_FN(promise_resolve);
367
#undef SET_HOOK_FN
368
369
  {
370
    Local<FunctionTemplate> ctor =
371
3348
        FunctionTemplate::New(env->isolate());
372
6696
    ctor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PromiseWrap"));
373
3348
    Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
374
    promise_wrap_template->SetInternalFieldCount(
375
3348
        PromiseWrap::kInternalFieldCount);
376
    promise_wrap_template->SetAccessor(
377
        FIXED_ONE_BYTE_STRING(env->isolate(), "promise"),
378
6696
        PromiseWrap::GetPromise);
379
    promise_wrap_template->SetAccessor(
380
        FIXED_ONE_BYTE_STRING(env->isolate(), "parentId"),
381
6696
        PromiseWrap::getParentAsyncId);
382
3348
    env->set_promise_wrap_template(promise_wrap_template);
383
  }
384
}
385
386
387
271
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
388
271
  Environment* env = Environment::GetCurrent(args);
389
271
  env->AddPromiseHook(PromiseHook, static_cast<void*>(env));
390
271
}
391
392
393
102
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
394
102
  Environment* env = Environment::GetCurrent(args);
395
396
  // Delay the call to `RemovePromiseHook` because we might currently be
397
  // between the `before` and `after` calls of a Promise.
398
306
  env->isolate()->EnqueueMicrotask([](void* data) {
399
102
    Environment* env = static_cast<Environment*>(data);
400
102
    env->RemovePromiseHook(PromiseHook, data);
401
408
  }, static_cast<void*>(env));
402
102
}
403
404
405
92
class DestroyParam {
406
 public:
407
  double asyncId;
408
  v8::Persistent<Object> target;
409
  v8::Persistent<Object> propBag;
410
};
411
412
413
2
void AsyncWrap::WeakCallback(const v8::WeakCallbackInfo<DestroyParam>& info) {
414
2
  HandleScope scope(info.GetIsolate());
415
416
2
  Environment* env = Environment::GetCurrent(info.GetIsolate());
417
2
  DestroyParam* p = info.GetParameter();
418
4
  Local<Object> prop_bag = PersistentToLocal(info.GetIsolate(), p->propBag);
419
420
4
  Local<Value> val = prop_bag->Get(env->destroyed_string());
421
2
  if (val->IsFalse()) {
422
1
    AsyncWrap::EmitDestroy(env, p->asyncId);
423
  }
424
2
  p->target.Reset();
425
2
  p->propBag.Reset();
426
2
  delete p;
427
2
}
428
429
430
30
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) {
431
60
  CHECK(args[0]->IsObject());
432
60
  CHECK(args[1]->IsNumber());
433
60
  CHECK(args[2]->IsObject());
434
435
30
  Isolate* isolate = args.GetIsolate();
436
30
  DestroyParam* p = new DestroyParam();
437
90
  p->asyncId = args[1].As<Number>()->Value();
438
90
  p->target.Reset(isolate, args[0].As<Object>());
439
90
  p->propBag.Reset(isolate, args[2].As<Object>());
440
  p->target.SetWeak(
441
30
    p, AsyncWrap::WeakCallback, v8::WeakCallbackType::kParameter);
442
30
}
443
444
445
17507
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
446
  AsyncWrap* wrap;
447
35014
  args.GetReturnValue().Set(-1);
448
35014
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
449
52494
  args.GetReturnValue().Set(wrap->get_async_id());
450
}
451
452
453
442937
void AsyncWrap::PushAsyncIds(const FunctionCallbackInfo<Value>& args) {
454
442937
  Environment* env = Environment::GetCurrent(args);
455
  // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail
456
  // then the checks in push_async_ids() and pop_async_id() will.
457
1771748
  double async_id = args[0]->NumberValue(env->context()).FromJust();
458
1771748
  double trigger_async_id = args[1]->NumberValue(env->context()).FromJust();
459
442937
  env->async_hooks()->push_async_ids(async_id, trigger_async_id);
460
442937
}
461
462
463
443873
void AsyncWrap::PopAsyncIds(const FunctionCallbackInfo<Value>& args) {
464
443873
  Environment* env = Environment::GetCurrent(args);
465
1775492
  double async_id = args[0]->NumberValue(env->context()).FromJust();
466
1331607
  args.GetReturnValue().Set(env->async_hooks()->pop_async_id(async_id));
467
443867
}
468
469
470
3176
void AsyncWrap::AsyncIdStackSize(const FunctionCallbackInfo<Value>& args) {
471
3176
  Environment* env = Environment::GetCurrent(args);
472
  args.GetReturnValue().Set(
473
9528
      static_cast<double>(env->async_hooks()->stack_size()));
474
3176
}
475
476
477
44
void AsyncWrap::ClearAsyncIdStack(const FunctionCallbackInfo<Value>& args) {
478
44
  Environment* env = Environment::GetCurrent(args);
479
44
  env->async_hooks()->clear_async_id_stack();
480
44
}
481
482
483
26
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) {
484
  AsyncWrap* wrap;
485
52
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
486

52
  double execution_async_id = args[0]->IsNumber() ? args[0]->NumberValue() : -1;
487
26
  wrap->AsyncReset(execution_async_id);
488
}
489
490
491
64887
void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
492
129774
  CHECK(args[0]->IsNumber());
493
  AsyncWrap::EmitDestroy(
494
129774
      Environment::GetCurrent(args), args[0]->NumberValue());
495
64887
}
496
497
64886
void AsyncWrap::AddWrapMethods(Environment* env,
498
                               Local<FunctionTemplate> constructor,
499
                               int flag) {
500
64886
  env->SetProtoMethod(constructor, "getAsyncId", AsyncWrap::GetAsyncId);
501
64886
  if (flag & kFlagHasReset)
502
3642
    env->SetProtoMethod(constructor, "asyncReset", AsyncWrap::AsyncReset);
503
64886
}
504
505
3348
void AsyncWrap::Initialize(Local<Object> target,
506
                           Local<Value> unused,
507
                           Local<Context> context) {
508
3348
  Environment* env = Environment::GetCurrent(context);
509
3348
  Isolate* isolate = env->isolate();
510
3348
  HandleScope scope(isolate);
511
512
3348
  env->SetMethod(target, "setupHooks", SetupHooks);
513
3348
  env->SetMethod(target, "pushAsyncIds", PushAsyncIds);
514
3348
  env->SetMethod(target, "popAsyncIds", PopAsyncIds);
515
3348
  env->SetMethod(target, "asyncIdStackSize", AsyncIdStackSize);
516
3348
  env->SetMethod(target, "clearAsyncIdStack", ClearAsyncIdStack);
517
3348
  env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
518
3348
  env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
519
3348
  env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
520
3348
  env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
521
522
  v8::PropertyAttribute ReadOnlyDontDelete =
523
3348
      static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);
524
525
#define FORCE_SET_TARGET_FIELD(obj, str, field)                               \
526
  (obj)->DefineOwnProperty(context,                                           \
527
                           FIXED_ONE_BYTE_STRING(isolate, str),               \
528
                           field,                                             \
529
                           ReadOnlyDontDelete).FromJust()
530
531
  // Attach the uint32_t[] where each slot contains the count of the number of
532
  // callbacks waiting to be called on a particular event. It can then be
533
  // incremented/decremented from JS quickly to communicate to C++ if there are
534
  // any callbacks waiting to be called.
535
13392
  FORCE_SET_TARGET_FIELD(target,
536
                         "async_hook_fields",
537
                         env->async_hooks()->fields().GetJSArray());
538
539
  // The following v8::Float64Array has 5 fields. These fields are shared in
540
  // this way to allow JS and C++ to read/write each value as quickly as
541
  // possible. The fields are represented as follows:
542
  //
543
  // kAsyncUid: Maintains the state of the next unique id to be assigned.
544
  //
545
  // kInitTriggerAsyncId: Write the id of the resource responsible for a
546
  //   handle's creation just before calling the new handle's constructor.
547
  //   After the new handle is constructed kInitTriggerAsyncId is set back to 0.
548
13392
  FORCE_SET_TARGET_FIELD(target,
549
                         "async_id_fields",
550
                         env->async_hooks()->async_id_fields().GetJSArray());
551
552
3348
  Local<Object> constants = Object::New(isolate);
553
#define SET_HOOKS_CONSTANT(name)                                              \
554
  FORCE_SET_TARGET_FIELD(                                                     \
555
      constants, #name, Integer::New(isolate, AsyncHooks::name));
556
557
13392
  SET_HOOKS_CONSTANT(kInit);
558
13392
  SET_HOOKS_CONSTANT(kBefore);
559
13392
  SET_HOOKS_CONSTANT(kAfter);
560
13392
  SET_HOOKS_CONSTANT(kDestroy);
561
13392
  SET_HOOKS_CONSTANT(kPromiseResolve);
562
13392
  SET_HOOKS_CONSTANT(kTotals);
563
13392
  SET_HOOKS_CONSTANT(kCheck);
564
13392
  SET_HOOKS_CONSTANT(kExecutionAsyncId);
565
13392
  SET_HOOKS_CONSTANT(kTriggerAsyncId);
566
13392
  SET_HOOKS_CONSTANT(kAsyncIdCounter);
567
13392
  SET_HOOKS_CONSTANT(kInitTriggerAsyncId);
568
#undef SET_HOOKS_CONSTANT
569
10044
  FORCE_SET_TARGET_FIELD(target, "constants", constants);
570
571
3348
  Local<Object> async_providers = Object::New(isolate);
572
#define V(p)                                                                  \
573
  FORCE_SET_TARGET_FIELD(                                                     \
574
      async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p));
575
344844
  NODE_ASYNC_PROVIDER_TYPES(V)
576
#undef V
577
10044
  FORCE_SET_TARGET_FIELD(target, "Providers", async_providers);
578
579
  // These Symbols are used throughout node so the stored values on each object
580
  // can be accessed easily across files.
581
13392
  FORCE_SET_TARGET_FIELD(
582
      target,
583
      "async_id_symbol",
584
      Symbol::New(isolate, FIXED_ONE_BYTE_STRING(isolate, "asyncId")));
585
13392
  FORCE_SET_TARGET_FIELD(
586
      target,
587
      "trigger_async_id_symbol",
588
      Symbol::New(isolate, FIXED_ONE_BYTE_STRING(isolate, "triggerAsyncId")));
589
590
#undef FORCE_SET_TARGET_FIELD
591
592
3348
  env->set_async_hooks_init_function(Local<Function>());
593
3348
  env->set_async_hooks_before_function(Local<Function>());
594
3348
  env->set_async_hooks_after_function(Local<Function>());
595
3348
  env->set_async_hooks_destroy_function(Local<Function>());
596
3348
  env->set_async_hooks_promise_resolve_function(Local<Function>());
597
3348
}
598
599
600
3352
void LoadAsyncWrapperInfo(Environment* env) {
601
3352
  HeapProfiler* heap_profiler = env->isolate()->GetHeapProfiler();
602
#define V(PROVIDER)                                                           \
603
  heap_profiler->SetWrapperClassInfoProvider(                                 \
604
      (NODE_ASYNC_ID_OFFSET + AsyncWrap::PROVIDER_ ## PROVIDER), WrapperInfo);
605
3352
  NODE_ASYNC_PROVIDER_TYPES(V)
606
#undef V
607
3352
}
608
609
610
250497
AsyncWrap::AsyncWrap(Environment* env,
611
                     Local<Object> object,
612
                     ProviderType provider,
613
                     double execution_async_id)
614
    : BaseObject(env, object),
615
250497
      provider_type_(provider) {
616
250497
  CHECK_NE(provider, PROVIDER_NONE);
617
250497
  CHECK_GE(object->InternalFieldCount(), 1);
618
619
  // Shift provider value over to prevent id collision.
620
250497
  persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider);
621
622
  // Use AsyncReset() call to execute the init() callbacks.
623
250497
  AsyncReset(execution_async_id);
624
250497
}
625
626
627
// This is specifically used by the PromiseWrap constructor.
628
656
AsyncWrap::AsyncWrap(Environment* env,
629
                     Local<Object> object,
630
                     bool silent)
631
    : BaseObject(env, object),
632
656
      provider_type_(PROVIDER_PROMISE) {
633
656
  CHECK_GE(object->InternalFieldCount(), 1);
634
635
  // Shift provider value over to prevent id collision.
636
656
  persistent().SetWrapperClassId(NODE_ASYNC_ID_OFFSET + provider_type_);
637
638
  // Use AsyncReset() call to execute the init() callbacks.
639
656
  AsyncReset(-1, silent);
640
656
}
641
642
643
483900
AsyncWrap::~AsyncWrap() {
644
241950
  EmitTraceEventDestroy();
645
241950
  EmitDestroy(env(), get_async_id());
646
241950
}
647
648
244305
void AsyncWrap::EmitTraceEventDestroy() {
649








244305
  switch (provider_type()) {
650
  #define V(PROVIDER)                                                         \
651
    case PROVIDER_ ## PROVIDER:                                               \
652
      TRACE_EVENT_NESTABLE_ASYNC_END0("node.async_hooks",                     \
653
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
654
      break;
655
    NODE_ASYNC_PROVIDER_TYPES(V)
656
  #undef V
657
    default:
658
      UNREACHABLE();
659
  }
660
244305
}
661
662
309213
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
663
309213
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0)
664
552395
    return;
665
666
66031
  if (env->destroy_async_id_list()->empty()) {
667
62146
    env->SetImmediate(DestroyAsyncIdsCallback, nullptr);
668
  }
669
670
66031
  env->destroy_async_id_list()->push_back(async_id);
671
}
672
673
674
// Generalized call for both the constructor and for handles that are pooled
675
// and reused over their lifetime. This way a new uid can be assigned when
676
// the resource is pulled out of the pool and put back into use.
677
253559
void AsyncWrap::AsyncReset(double execution_async_id, bool silent) {
678
  async_id_ =
679
253559
    execution_async_id == -1 ? env()->new_async_id() : execution_async_id;
680
253559
  trigger_async_id_ = env()->get_init_trigger_async_id();
681
682








253559
  switch (provider_type()) {
683
#define V(PROVIDER)                                                           \
684
    case PROVIDER_ ## PROVIDER:                                               \
685
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN2("node.async_hooks",                   \
686
        #PROVIDER, static_cast<int64_t>(get_async_id()),                      \
687
        "executionAsyncId",                                                   \
688
        static_cast<int64_t>(env()->execution_async_id()),                    \
689
        "triggerAsyncId",                                                     \
690
        static_cast<int64_t>(get_trigger_async_id()));                        \
691
      break;
692
    NODE_ASYNC_PROVIDER_TYPES(V)
693
#undef V
694
    default:
695
      UNREACHABLE();
696
  }
697
698
507118
  if (silent) return;
699
700
  EmitAsyncInit(env(), object(),
701
253547
                env()->async_hooks()->provider_string(provider_type()),
702
507094
                async_id_, trigger_async_id_);
703
}
704
705
706
253568
void AsyncWrap::EmitAsyncInit(Environment* env,
707
                              Local<Object> object,
708
                              Local<String> type,
709
                              double async_id,
710
                              double trigger_async_id) {
711
253568
  CHECK(!object.IsEmpty());
712
253568
  CHECK(!type.IsEmpty());
713
253568
  AsyncHooks* async_hooks = env->async_hooks();
714
715
  // Nothing to execute, so can continue normally.
716
253568
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
717
505765
    return;
718
  }
719
720
1371
  HandleScope scope(env->isolate());
721
1371
  Local<Function> init_fn = env->async_hooks_init_function();
722
723
  Local<Value> argv[] = {
724
    Number::New(env->isolate(), async_id),
725
    type,
726
    Number::New(env->isolate(), trigger_async_id),
727
    object,
728
6855
  };
729
730
2742
  FatalTryCatch try_catch(env);
731
5484
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
732
}
733
734
735
350442
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
736
                                          int argc,
737
                                          Local<Value>* argv) {
738
350442
  EmitTraceEventBefore();
739
740
350442
  async_context context { get_async_id(), get_trigger_async_id() };
741
  MaybeLocal<Value> ret = InternalMakeCallback(
742
350442
      env(), object(), cb, argc, argv, context);
743
744
350327
  EmitTraceEventAfter();
745
746
350327
  return ret;
747
}
748
749
750
/* Public C++ embedder API */
751
752
753
2
async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) {
754
2
  return Environment::GetCurrent(isolate)->execution_async_id();
755
}
756
757
758
2
async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) {
759
2
  return Environment::GetCurrent(isolate)->trigger_async_id();
760
}
761
762
763
15
async_context EmitAsyncInit(Isolate* isolate,
764
                            Local<Object> resource,
765
                            const char* name,
766
                            async_id trigger_async_id) {
767
  Local<String> type =
768
      String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized)
769
30
          .ToLocalChecked();
770
15
  return EmitAsyncInit(isolate, resource, type, trigger_async_id);
771
}
772
773
21
async_context EmitAsyncInit(Isolate* isolate,
774
                            Local<Object> resource,
775
                            v8::Local<v8::String> name,
776
                            async_id trigger_async_id) {
777
21
  Environment* env = Environment::GetCurrent(isolate);
778
779
  // Initialize async context struct
780
21
  if (trigger_async_id == -1)
781
18
    trigger_async_id = env->get_init_trigger_async_id();
782
783
  async_context context = {
784
21
    env->new_async_id(),  // async_id_
785
    trigger_async_id  // trigger_async_id_
786
21
  };
787
788
  // Run init hooks
789
  AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id,
790
21
                           context.trigger_async_id);
791
792
21
  return context;
793
}
794
795
20
void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) {
796
  AsyncWrap::EmitDestroy(
797
20
      Environment::GetCurrent(isolate), asyncContext.async_id);
798
20
}
799
800
}  // namespace node
801
802
3391
NODE_BUILTIN_MODULE_CONTEXT_AWARE(async_wrap, node::AsyncWrap::Initialize)