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: 333 359 92.8 %
Date: 2017-11-19 Branches: 534 752 71.0 %

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
62095
static void DestroyAsyncIdsCallback(uv_timer_t* handle) {
141
62095
  Environment* env = Environment::from_destroy_async_ids_timer_handle(handle);
142
143
62095
  HandleScope handle_scope(env->isolate());
144
62095
  Context::Scope context_scope(env->context());
145
62095
  Local<Function> fn = env->async_hooks_destroy_function();
146
147
124190
  TryCatch try_catch(env->isolate());
148
149
62096
  do {
150
62096
    std::vector<double> destroy_async_id_list;
151
62096
    destroy_async_id_list.swap(*env->destroy_async_id_list());
152
127880
    for (auto async_id : destroy_async_id_list) {
153
      // Want each callback to be cleaned up after itself, instead of cleaning
154
      // them all up after the while() loop completes.
155
65784
      HandleScope scope(env->isolate());
156
65784
      Local<Value> async_id_value = Number::New(env->isolate(), async_id);
157
      MaybeLocal<Value> ret = fn->Call(
158
197352
          env->context(), Undefined(env->isolate()), 1, &async_id_value);
159
160
65784
      if (ret.IsEmpty()) {
161
        ClearFatalExceptionHandlers(env);
162
        FatalException(env->isolate(), try_catch);
163
        UNREACHABLE();
164
      }
165
127880
    }
166
124191
  } while (!env->destroy_async_id_list()->empty());
167
62095
}
168
169
170
949
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
171
949
  AsyncHooks* async_hooks = env->async_hooks();
172
173
949
  if (async_hooks->fields()[AsyncHooks::kPromiseResolve] == 0)
174
1896
    return;
175
176
2
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
177
2
  Local<Function> fn = env->async_hooks_promise_resolve_function();
178
2
  TryCatch try_catch(env->isolate());
179
  MaybeLocal<Value> ar = fn->Call(
180
6
      env->context(), Undefined(env->isolate()), 1, &async_id_value);
181
2
  if (ar.IsEmpty()) {
182
    ClearFatalExceptionHandlers(env);
183
    FatalException(env->isolate(), try_catch);
184
    UNREACHABLE();
185
2
  }
186
}
187
188
189
329077
void AsyncWrap::EmitTraceEventBefore() {
190








329077
  switch (provider_type()) {
191
#define V(PROVIDER)                                                           \
192
    case PROVIDER_ ## PROVIDER:                                               \
193
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN0("node.async_hooks",                   \
194
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
195
      break;
196
    NODE_ASYNC_PROVIDER_TYPES(V)
197
#undef V
198
    default:
199
      UNREACHABLE();
200
  }
201
329077
}
202
203
204
331319
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
205
331319
  AsyncHooks* async_hooks = env->async_hooks();
206
207
331319
  if (async_hooks->fields()[AsyncHooks::kBefore] == 0)
208
661072
    return;
209
210
1566
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
211
1566
  Local<Function> fn = env->async_hooks_before_function();
212
1566
  TryCatch try_catch(env->isolate());
213
  MaybeLocal<Value> ar = fn->Call(
214
4698
      env->context(), Undefined(env->isolate()), 1, &async_id_value);
215
1566
  if (ar.IsEmpty()) {
216
    ClearFatalExceptionHandlers(env);
217
    FatalException(env->isolate(), try_catch);
218
    UNREACHABLE();
219
1566
  }
220
}
221
222
223
328967
void AsyncWrap::EmitTraceEventAfter() {
224








328967
  switch (provider_type()) {
225
#define V(PROVIDER)                                                           \
226
    case PROVIDER_ ## PROVIDER:                                               \
227
      TRACE_EVENT_NESTABLE_ASYNC_END0("node.async_hooks",                     \
228
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
229
      break;
230
    NODE_ASYNC_PROVIDER_TYPES(V)
231
#undef V
232
    default:
233
      UNREACHABLE();
234
  }
235
328967
}
236
237
238
331230
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
239
331230
  AsyncHooks* async_hooks = env->async_hooks();
240
241
331230
  if (async_hooks->fields()[AsyncHooks::kAfter] == 0)
242
660929
    return;
243
244
  // If the user's callback failed then the after() hooks will be called at the
245
  // end of _fatalException().
246
1531
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
247
1531
  Local<Function> fn = env->async_hooks_after_function();
248
1531
  TryCatch try_catch(env->isolate());
249
  MaybeLocal<Value> ar = fn->Call(
250
4593
      env->context(), Undefined(env->isolate()), 1, &async_id_value);
251
1531
  if (ar.IsEmpty()) {
252
    ClearFatalExceptionHandlers(env);
253
    FatalException(env->isolate(), try_catch);
254
    UNREACHABLE();
255
1531
  }
256
}
257
258
1630
class PromiseWrap : public AsyncWrap {
259
 public:
260
960
  PromiseWrap(Environment* env, Local<Object> object, bool silent)
261
960
      : AsyncWrap(env, object, silent) {
262
960
    MakeWeak(this);
263
960
  }
264
  size_t self_size() const override { return sizeof(*this); }
265
266
  static constexpr int kPromiseField = 1;
267
  static constexpr int kParentAsyncIdField = 2;
268
  static constexpr int kInternalFieldCount = 3;
269
270
  static PromiseWrap* New(Environment* env,
271
                          Local<Promise> promise,
272
                          PromiseWrap* parent_wrap,
273
                          bool silent);
274
  static void GetPromise(Local<String> property,
275
                         const PropertyCallbackInfo<Value>& info);
276
  static void getParentAsyncId(Local<String> property,
277
                          const PropertyCallbackInfo<Value>& info);
278
};
279
280
960
PromiseWrap* PromiseWrap::New(Environment* env,
281
                              Local<Promise> promise,
282
                              PromiseWrap* parent_wrap,
283
                              bool silent) {
284
  Local<Object> object = env->promise_wrap_template()
285
2880
                            ->NewInstance(env->context()).ToLocalChecked();
286
960
  object->SetInternalField(PromiseWrap::kPromiseField, promise);
287
960
  if (parent_wrap != nullptr) {
288
    object->SetInternalField(PromiseWrap::kParentAsyncIdField,
289
                             Number::New(env->isolate(),
290
1226
                                         parent_wrap->get_async_id()));
291
  }
292
1920
  CHECK_EQ(promise->GetAlignedPointerFromInternalField(0), nullptr);
293
960
  promise->SetInternalField(0, object);
294
960
  return new PromiseWrap(env, object, silent);
295
}
296
297
803
void PromiseWrap::GetPromise(Local<String> property,
298
                             const PropertyCallbackInfo<Value>& info) {
299
3212
  info.GetReturnValue().Set(info.Holder()->GetInternalField(kPromiseField));
300
803
}
301
302
2
void PromiseWrap::getParentAsyncId(Local<String> property,
303
                              const PropertyCallbackInfo<Value>& info) {
304
  info.GetReturnValue().Set(
305
8
    info.Holder()->GetInternalField(kParentAsyncIdField));
306
2
}
307
308
2868
static void PromiseHook(PromiseHookType type, Local<Promise> promise,
309
                        Local<Value> parent, void* arg) {
310
2868
  Environment* env = static_cast<Environment*>(arg);
311
5736
  Local<Value> resource_object_value = promise->GetInternalField(0);
312
2868
  PromiseWrap* wrap = nullptr;
313
2868
  if (resource_object_value->IsObject()) {
314
1910
    Local<Object> resource_object = resource_object_value.As<Object>();
315
1910
    wrap = Unwrap<PromiseWrap>(resource_object);
316
  }
317
318

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

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








233526
  switch (provider_type()) {
675
  #define V(PROVIDER)                                                         \
676
    case PROVIDER_ ## PROVIDER:                                               \
677
      TRACE_EVENT_NESTABLE_ASYNC_END0("node.async_hooks",                     \
678
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
679
      break;
680
    NODE_ASYNC_PROVIDER_TYPES(V)
681
  #undef V
682
    default:
683
      UNREACHABLE();
684
  }
685
233526
}
686
687
298443
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
688
298443
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0)
689
530524
    return;
690
691
66362
  if (env->destroy_async_id_list()->empty()) {
692
    uv_timer_start(env->destroy_async_ids_timer_handle(),
693
62118
                   DestroyAsyncIdsCallback, 0, 0);
694
  }
695
696
66362
  env->destroy_async_id_list()->push_back(async_id);
697
}
698
699
700
// Generalized call for both the constructor and for handles that are pooled
701
// and reused over their lifetime. This way a new uid can be assigned when
702
// the resource is pulled out of the pool and put back into use.
703
242931
void AsyncWrap::AsyncReset(double execution_async_id, bool silent) {
704
  async_id_ =
705
242931
    execution_async_id == -1 ? env()->new_async_id() : execution_async_id;
706
242931
  trigger_async_id_ = env()->get_init_trigger_async_id();
707
708








242931
  switch (provider_type()) {
709
#define V(PROVIDER)                                                           \
710
    case PROVIDER_ ## PROVIDER:                                               \
711
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN1("node.async_hooks",                   \
712
        #PROVIDER, static_cast<int64_t>(get_async_id()),                      \
713
        "triggerAsyncId", static_cast<int64_t>(get_trigger_async_id()));      \
714
      break;
715
    NODE_ASYNC_PROVIDER_TYPES(V)
716
#undef V
717
    default:
718
      UNREACHABLE();
719
  }
720
721
485862
  if (silent) return;
722
723
  EmitAsyncInit(env(), object(),
724
242919
                env()->async_hooks()->provider_string(provider_type()),
725
485838
                async_id_, trigger_async_id_);
726
}
727
728
729
242940
void AsyncWrap::EmitAsyncInit(Environment* env,
730
                              Local<Object> object,
731
                              Local<String> type,
732
                              double async_id,
733
                              double trigger_async_id) {
734
242940
  CHECK(!object.IsEmpty());
735
242940
  CHECK(!type.IsEmpty());
736
242940
  AsyncHooks* async_hooks = env->async_hooks();
737
738
  // Nothing to execute, so can continue normally.
739
242940
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
740
484189
    return;
741
  }
742
743
1691
  HandleScope scope(env->isolate());
744
1691
  Local<Function> init_fn = env->async_hooks_init_function();
745
746
  Local<Value> argv[] = {
747
    Number::New(env->isolate(), async_id),
748
    type,
749
    Number::New(env->isolate(), trigger_async_id),
750
    object,
751
8455
  };
752
753
3382
  TryCatch try_catch(env->isolate());
754
  MaybeLocal<Value> ret = init_fn->Call(
755
5073
      env->context(), object, arraysize(argv), argv);
756
757
1691
  if (ret.IsEmpty()) {
758
    ClearFatalExceptionHandlers(env);
759
    FatalException(env->isolate(), try_catch);
760
1691
  }
761
}
762
763
764
328594
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
765
                                          int argc,
766
                                          Local<Value>* argv) {
767
328594
  EmitTraceEventBefore();
768
769
328594
  async_context context { get_async_id(), get_trigger_async_id() };
770
  MaybeLocal<Value> ret = InternalMakeCallback(
771
328594
      env(), object(), cb, argc, argv, context);
772
773
328479
  EmitTraceEventAfter();
774
775
328479
  return ret;
776
}
777
778
779
/* Public C++ embedder API */
780
781
782
2
async_id AsyncHooksGetExecutionAsyncId(Isolate* isolate) {
783
2
  return Environment::GetCurrent(isolate)->execution_async_id();
784
}
785
786
787
2
async_id AsyncHooksGetTriggerAsyncId(Isolate* isolate) {
788
2
  return Environment::GetCurrent(isolate)->trigger_async_id();
789
}
790
791
792
15
async_context EmitAsyncInit(Isolate* isolate,
793
                            Local<Object> resource,
794
                            const char* name,
795
                            async_id trigger_async_id) {
796
  Local<String> type =
797
      String::NewFromUtf8(isolate, name, v8::NewStringType::kInternalized)
798
30
          .ToLocalChecked();
799
15
  return EmitAsyncInit(isolate, resource, type, trigger_async_id);
800
}
801
802
21
async_context EmitAsyncInit(Isolate* isolate,
803
                            Local<Object> resource,
804
                            v8::Local<v8::String> name,
805
                            async_id trigger_async_id) {
806
21
  Environment* env = Environment::GetCurrent(isolate);
807
808
  // Initialize async context struct
809
21
  if (trigger_async_id == -1)
810
18
    trigger_async_id = env->get_init_trigger_async_id();
811
812
  async_context context = {
813
21
    env->new_async_id(),  // async_id_
814
    trigger_async_id  // trigger_async_id_
815
21
  };
816
817
  // Run init hooks
818
  AsyncWrap::EmitAsyncInit(env, resource, name, context.async_id,
819
21
                           context.trigger_async_id);
820
821
21
  return context;
822
}
823
824
20
void EmitAsyncDestroy(Isolate* isolate, async_context asyncContext) {
825
  AsyncWrap::EmitDestroy(
826
20
      Environment::GetCurrent(isolate), asyncContext.async_id);
827
20
}
828
829
}  // namespace node
830
831
3332
NODE_BUILTIN_MODULE_CONTEXT_AWARE(async_wrap, node::AsyncWrap::Initialize)