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: 336 348 96.6 %
Date: 2020-02-19 22:14:06 Branches: 694 1174 59.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
31
using v8::Context;
32
using v8::DontDelete;
33
using v8::EscapableHandleScope;
34
using v8::Function;
35
using v8::FunctionCallbackInfo;
36
using v8::FunctionTemplate;
37
using v8::Global;
38
using v8::HandleScope;
39
using v8::Integer;
40
using v8::Isolate;
41
using v8::Local;
42
using v8::MaybeLocal;
43
using v8::Number;
44
using v8::Object;
45
using v8::ObjectTemplate;
46
using v8::Promise;
47
using v8::PromiseHookType;
48
using v8::PropertyAttribute;
49
using v8::PropertyCallbackInfo;
50
using v8::ReadOnly;
51
using v8::String;
52
using v8::TryCatch;
53
using v8::Uint32;
54
using v8::Undefined;
55
using v8::Value;
56
using v8::WeakCallbackInfo;
57
using v8::WeakCallbackType;
58
59
using TryCatchScope = node::errors::TryCatchScope;
60
61
namespace node {
62
63
static const char* const provider_names[] = {
64
#define V(PROVIDER)                                                           \
65
  #PROVIDER,
66
  NODE_ASYNC_PROVIDER_TYPES(V)
67
#undef V
68
};
69
70
71
198
struct AsyncWrapObject : public AsyncWrap {
72
99
  static inline void New(const FunctionCallbackInfo<Value>& args) {
73
99
    Environment* env = Environment::GetCurrent(args);
74
99
    CHECK(args.IsConstructCall());
75
198
    CHECK(env->async_wrap_object_ctor_template()->HasInstance(args.This()));
76
198
    CHECK(args[0]->IsUint32());
77
297
    auto type = static_cast<ProviderType>(args[0].As<Uint32>()->Value());
78
99
    new AsyncWrapObject(env, args.This(), type);
79
99
  }
80
81
99
  inline AsyncWrapObject(Environment* env, Local<Object> object,
82
99
                         ProviderType type) : AsyncWrap(env, object, type) {}
83
84
3
  SET_NO_MEMORY_INFO()
85
3
  SET_MEMORY_INFO_NAME(AsyncWrapObject)
86
3
  SET_SELF_SIZE(AsyncWrapObject)
87
};
88
89
22309
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) {
90
22309
  Local<Function> fn = env->async_hooks_destroy_function();
91
92
44618
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
93
94

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

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

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












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















































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












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















































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

3210
  if (type == PromiseHookType::kInit || wrap == nullptr) {
239
1096
    bool silent = type != PromiseHookType::kInit;
240
241
    // set parent promise's async Id as this promise's triggerAsyncId
242
1096
    if (parent->IsPromise()) {
243
      // parent promise exists, current promise
244
      // is a chained promise, so we set parent promise's id as
245
      // current promise's triggerAsyncId
246
565
      Local<Promise> parent_promise = parent.As<Promise>();
247
565
      PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise);
248
565
      if (parent_wrap == nullptr) {
249
1
        parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true);
250
1
        if (parent_wrap == nullptr) return;
251
      }
252
253
1130
      AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap);
254
565
      wrap = PromiseWrap::New(env, promise, parent_wrap, silent);
255
    } else {
256
531
      wrap = PromiseWrap::New(env, promise, nullptr, silent);
257
    }
258
  }
259
260
3210
  if (wrap == nullptr) return;
261
262
3210
  if (type == PromiseHookType::kBefore) {
263
1569
    env->async_hooks()->push_async_context(wrap->get_async_id(),
264
523
      wrap->get_trigger_async_id(), wrap->object());
265
523
    wrap->EmitTraceEventBefore();
266
523
    AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id());
267
2687
  } else if (type == PromiseHookType::kAfter) {
268
526
    wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id());
269
526
    AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id());
270
526
    if (env->execution_async_id() == wrap->get_async_id()) {
271
      // This condition might not be true if async_hooks was enabled during
272
      // the promise callback execution.
273
      // Popping it off the stack can be skipped in that case, because it is
274
      // known that it would correspond to exactly one call with
275
      // PromiseHookType::kBefore that was not witnessed by the PromiseHook.
276
521
      env->async_hooks()->pop_async_context(wrap->get_async_id());
277
    }
278
2161
  } else if (type == PromiseHookType::kResolve) {
279
1079
    AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id());
280
  }
281
}
282
283
284
4377
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
285
4377
  Environment* env = Environment::GetCurrent(args);
286
287
8754
  CHECK(args[0]->IsObject());
288
289
  // All of init, before, after, destroy are supplied by async_hooks
290
  // internally, so this should every only be called once. At which time all
291
  // the functions should be set. Detect this by checking if init !IsEmpty().
292
8754
  CHECK(env->async_hooks_init_function().IsEmpty());
293
294
8754
  Local<Object> fn_obj = args[0].As<Object>();
295
296
#define SET_HOOK_FN(name)                                                      \
297
  do {                                                                         \
298
    Local<Value> v =                                                           \
299
        fn_obj->Get(env->context(),                                            \
300
                    FIXED_ONE_BYTE_STRING(env->isolate(), #name))              \
301
            .ToLocalChecked();                                                 \
302
    CHECK(v->IsFunction());                                                    \
303
    env->set_async_hooks_##name##_function(v.As<Function>());                  \
304
  } while (0)
305
306
26262
  SET_HOOK_FN(init);
307
26262
  SET_HOOK_FN(before);
308
26262
  SET_HOOK_FN(after);
309
26262
  SET_HOOK_FN(destroy);
310
26262
  SET_HOOK_FN(promise_resolve);
311
#undef SET_HOOK_FN
312
313
  {
314
    Local<FunctionTemplate> ctor =
315
4377
        FunctionTemplate::New(env->isolate());
316
8754
    ctor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PromiseWrap"));
317
4377
    Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
318
4377
    promise_wrap_template->SetInternalFieldCount(
319
4377
        PromiseWrap::kInternalFieldCount);
320
13131
    promise_wrap_template->SetAccessor(
321
        FIXED_ONE_BYTE_STRING(env->isolate(), "isChainedPromise"),
322
4377
        PromiseWrap::getIsChainedPromise);
323
4377
    env->set_promise_wrap_template(promise_wrap_template);
324
  }
325
4377
}
326
327
328
270
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
329
270
  args.GetIsolate()->SetPromiseHook(PromiseHook);
330
270
}
331
332
333
60
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
334
60
  Isolate* isolate = args.GetIsolate();
335
336
  // The per-Isolate API provides no way of knowing whether there are multiple
337
  // users of the PromiseHook. That hopefully goes away when V8 introduces
338
  // a per-context API.
339
60
  isolate->SetPromiseHook(nullptr);
340
60
}
341
342
343
21657
class DestroyParam {
344
 public:
345
  double asyncId;
346
  Environment* env;
347
  Global<Object> target;
348
  Global<Object> propBag;
349
};
350
351
3039
void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) {
352
6078
  HandleScope scope(info.GetIsolate());
353
354
6078
  std::unique_ptr<DestroyParam> p{info.GetParameter()};
355
  Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(),
356
6078
                                                      p->propBag);
357
  Local<Value> val;
358
359
12156
  if (!prop_bag->Get(p->env->context(), p->env->destroyed_string())
360
3039
        .ToLocal(&val)) {
361
    return;
362
  }
363
364
3039
  if (val->IsFalse()) {
365
3037
    AsyncWrap::EmitDestroy(p->env, p->asyncId);
366
  }
367
  // unique_ptr goes out of scope here and pointer is deleted.
368
}
369
370
371
4180
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) {
372
8360
  CHECK(args[0]->IsObject());
373
8360
  CHECK(args[1]->IsNumber());
374
8360
  CHECK(args[2]->IsObject());
375
376
4180
  Isolate* isolate = args.GetIsolate();
377
4180
  DestroyParam* p = new DestroyParam();
378
12540
  p->asyncId = args[1].As<Number>()->Value();
379
4180
  p->env = Environment::GetCurrent(args);
380
12540
  p->target.Reset(isolate, args[0].As<Object>());
381
12540
  p->propBag.Reset(isolate, args[2].As<Object>());
382
4180
  p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter);
383
4180
}
384
385
92509
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
386
  AsyncWrap* wrap;
387
185018
  args.GetReturnValue().Set(kInvalidAsyncId);
388
92509
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
389
277464
  args.GetReturnValue().Set(wrap->get_async_id());
390
}
391
392
393
8
void AsyncWrap::PushAsyncContext(const FunctionCallbackInfo<Value>& args) {
394
8
  Environment* env = Environment::GetCurrent(args);
395
  // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail
396
  // then the checks in push_async_ids() and pop_async_id() will.
397
32
  double async_id = args[0]->NumberValue(env->context()).FromJust();
398
32
  double trigger_async_id = args[1]->NumberValue(env->context()).FromJust();
399
8
  env->async_hooks()->push_async_context(async_id, trigger_async_id, args[2]);
400
8
}
401
402
403
3
void AsyncWrap::PopAsyncContext(const FunctionCallbackInfo<Value>& args) {
404
3
  Environment* env = Environment::GetCurrent(args);
405
12
  double async_id = args[0]->NumberValue(env->context()).FromJust();
406
3
  args.GetReturnValue().Set(env->async_hooks()->pop_async_context(async_id));
407
}
408
409
410
29
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) {
411
58
  CHECK(args[0]->IsObject());
412
413
  AsyncWrap* wrap;
414
29
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
415
416
58
  Local<Object> resource = args[0].As<Object>();
417
  double execution_async_id =
418
58
      args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId;
419
29
  wrap->AsyncReset(resource, execution_async_id);
420
}
421
422
423
29
void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) {
424
  AsyncWrap* wrap;
425
58
  args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE);
426
29
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
427
87
  args.GetReturnValue().Set(wrap->provider_type());
428
}
429
430
431
180145
void AsyncWrap::EmitDestroy() {
432
180145
  AsyncWrap::EmitDestroy(env(), async_id_);
433
  // Ensure no double destroy is emitted via AsyncReset().
434
180149
  async_id_ = kInvalidAsyncId;
435
180149
  resource_.Reset();
436
180149
}
437
438
58833
void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
439
117666
  CHECK(args[0]->IsNumber());
440
58833
  AsyncWrap::EmitDestroy(
441
      Environment::GetCurrent(args),
442
176499
      args[0].As<Number>()->Value());
443
58833
}
444
445
77753
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) {
446
77753
  Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template();
447
77753
  if (tmpl.IsEmpty()) {
448
4377
    tmpl = env->NewFunctionTemplate(nullptr);
449
8754
    tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
450
4377
    env->SetProtoMethod(tmpl, "getAsyncId", AsyncWrap::GetAsyncId);
451
4377
    env->SetProtoMethod(tmpl, "asyncReset", AsyncWrap::AsyncReset);
452
4377
    env->SetProtoMethod(tmpl, "getProviderType", AsyncWrap::GetProviderType);
453
4377
    env->set_async_wrap_ctor_template(tmpl);
454
  }
455
77753
  return tmpl;
456
}
457
458
4377
void AsyncWrap::Initialize(Local<Object> target,
459
                           Local<Value> unused,
460
                           Local<Context> context,
461
                           void* priv) {
462
4377
  Environment* env = Environment::GetCurrent(context);
463
4377
  Isolate* isolate = env->isolate();
464
8754
  HandleScope scope(isolate);
465
466
4377
  env->SetMethod(target, "setupHooks", SetupHooks);
467
4377
  env->SetMethod(target, "pushAsyncContext", PushAsyncContext);
468
4377
  env->SetMethod(target, "popAsyncContext", PopAsyncContext);
469
4377
  env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
470
4377
  env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
471
4377
  env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
472
4377
  env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
473
474
  PropertyAttribute ReadOnlyDontDelete =
475
4377
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
476
477
#define FORCE_SET_TARGET_FIELD(obj, str, field)                               \
478
  (obj)->DefineOwnProperty(context,                                           \
479
                           FIXED_ONE_BYTE_STRING(isolate, str),               \
480
                           field,                                             \
481
                           ReadOnlyDontDelete).FromJust()
482
483
  // Attach the uint32_t[] where each slot contains the count of the number of
484
  // callbacks waiting to be called on a particular event. It can then be
485
  // incremented/decremented from JS quickly to communicate to C++ if there are
486
  // any callbacks waiting to be called.
487
17508
  FORCE_SET_TARGET_FIELD(target,
488
                         "async_hook_fields",
489
                         env->async_hooks()->fields().GetJSArray());
490
491
  // The following v8::Float64Array has 5 fields. These fields are shared in
492
  // this way to allow JS and C++ to read/write each value as quickly as
493
  // possible. The fields are represented as follows:
494
  //
495
  // kAsyncIdCounter: Maintains the state of the next unique id to be assigned.
496
  //
497
  // kDefaultTriggerAsyncId: Write the id of the resource responsible for a
498
  //   handle's creation just before calling the new handle's constructor.
499
  //   After the new handle is constructed kDefaultTriggerAsyncId is set back
500
  //   to kInvalidAsyncId.
501
17508
  FORCE_SET_TARGET_FIELD(target,
502
                         "async_id_fields",
503
                         env->async_hooks()->async_id_fields().GetJSArray());
504
505
17508
  FORCE_SET_TARGET_FIELD(target,
506
                         "execution_async_resources",
507
                         env->async_hooks()->execution_async_resources());
508
509
8754
  target->Set(context,
510
              env->async_ids_stack_string(),
511
17508
              env->async_hooks()->async_ids_stack().GetJSArray()).Check();
512
513
8754
  target->Set(context,
514
              FIXED_ONE_BYTE_STRING(env->isolate(), "owner_symbol"),
515
17508
              env->owner_symbol()).Check();
516
517
4377
  Local<Object> constants = Object::New(isolate);
518
#define SET_HOOKS_CONSTANT(name)                                              \
519
  FORCE_SET_TARGET_FIELD(                                                     \
520
      constants, #name, Integer::New(isolate, AsyncHooks::name))
521
522
17508
  SET_HOOKS_CONSTANT(kInit);
523
17508
  SET_HOOKS_CONSTANT(kBefore);
524
17508
  SET_HOOKS_CONSTANT(kAfter);
525
17508
  SET_HOOKS_CONSTANT(kDestroy);
526
17508
  SET_HOOKS_CONSTANT(kPromiseResolve);
527
17508
  SET_HOOKS_CONSTANT(kTotals);
528
17508
  SET_HOOKS_CONSTANT(kCheck);
529
17508
  SET_HOOKS_CONSTANT(kExecutionAsyncId);
530
17508
  SET_HOOKS_CONSTANT(kTriggerAsyncId);
531
17508
  SET_HOOKS_CONSTANT(kAsyncIdCounter);
532
17508
  SET_HOOKS_CONSTANT(kDefaultTriggerAsyncId);
533
17508
  SET_HOOKS_CONSTANT(kStackLength);
534
#undef SET_HOOKS_CONSTANT
535
13131
  FORCE_SET_TARGET_FIELD(target, "constants", constants);
536
537
4377
  Local<Object> async_providers = Object::New(isolate);
538
#define V(p)                                                                  \
539
  FORCE_SET_TARGET_FIELD(                                                     \
540
      async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p));
541
621534
  NODE_ASYNC_PROVIDER_TYPES(V)
542
#undef V
543
13131
  FORCE_SET_TARGET_FIELD(target, "Providers", async_providers);
544
545
#undef FORCE_SET_TARGET_FIELD
546
547
4377
  env->set_async_hooks_init_function(Local<Function>());
548
4377
  env->set_async_hooks_before_function(Local<Function>());
549
4377
  env->set_async_hooks_after_function(Local<Function>());
550
4377
  env->set_async_hooks_destroy_function(Local<Function>());
551
4377
  env->set_async_hooks_promise_resolve_function(Local<Function>());
552
4377
  env->set_async_hooks_binding(target);
553
554
  // TODO(addaleax): This block might better work as a
555
  // AsyncWrapObject::Initialize() or AsyncWrapObject::GetConstructorTemplate()
556
  // function.
557
  {
558
4377
    auto class_name = FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap");
559
4377
    auto function_template = env->NewFunctionTemplate(AsyncWrapObject::New);
560
4377
    function_template->SetClassName(class_name);
561
8754
    function_template->Inherit(AsyncWrap::GetConstructorTemplate(env));
562
4377
    auto instance_template = function_template->InstanceTemplate();
563
4377
    instance_template->SetInternalFieldCount(1);
564
    auto function =
565
13131
        function_template->GetFunction(env->context()).ToLocalChecked();
566
13131
    target->Set(env->context(), class_name, function).Check();
567
4377
    env->set_async_wrap_object_ctor_template(function_template);
568
  }
569
4377
}
570
571
572
171845
AsyncWrap::AsyncWrap(Environment* env,
573
                     Local<Object> object,
574
                     ProviderType provider,
575
171845
                     double execution_async_id)
576
171845
    : AsyncWrap(env, object, provider, execution_async_id, false) {}
577
578
172942
AsyncWrap::AsyncWrap(Environment* env,
579
                     Local<Object> object,
580
                     ProviderType provider,
581
                     double execution_async_id,
582
172942
                     bool silent)
583
172942
    : AsyncWrap(env, object) {
584
172942
  CHECK_NE(provider, PROVIDER_NONE);
585
172942
  provider_type_ = provider;
586
587
  // Use AsyncReset() call to execute the init() callbacks.
588
172942
  AsyncReset(execution_async_id, silent);
589
172942
  init_hook_ran_ = true;
590
172942
}
591
592
175848
AsyncWrap::AsyncWrap(Environment* env, Local<Object> object)
593
175848
  : BaseObject(env, object) {
594
175848
}
595
596
// This method is necessary to work around one specific problem:
597
// Before the init() hook runs, if there is one, the BaseObject() constructor
598
// registers this object with the Environment for finilization and debugging
599
// purposes.
600
// If the Environment decides to inspect this object for debugging, it tries to
601
// call virtual methods on this object that are only (meaningfully) implemented
602
// by the subclasses of AsyncWrap.
603
// This could, with bad luck, happen during the AsyncWrap() constructor,
604
// because we run JS code as part of it and that in turn can lead to a heapdump
605
// being taken, either through the inspector or our programmatic API for it.
606
// The object being initialized is not fully constructed at that point, and
607
// in particular its virtual function table points to the AsyncWrap one
608
// (as the subclass constructor has not yet begun execution at that point).
609
// This means that the functions that are used for heap dump memory tracking
610
// are not yet available, and trying to call them would crash the process.
611
// We use this particular `IsDoneInitializing()` method to tell the Environment
612
// that such debugging methods are not yet available.
613
// This may be somewhat unreliable when it comes to future changes, because
614
// at this point it *only* protects AsyncWrap subclasses, and *only* for cases
615
// where heap dumps are being taken while the init() hook is on the call stack.
616
// For now, it seems like the best solution, though.
617
416487
bool AsyncWrap::IsDoneInitializing() const {
618
416487
  return init_hook_ran_;
619
}
620
621
524778
AsyncWrap::~AsyncWrap() {
622
174924
  EmitTraceEventDestroy();
623
174926
  EmitDestroy();
624
174927
}
625
626
179918
void AsyncWrap::EmitTraceEventDestroy() {
627












179918
  switch (provider_type()) {
628
  #define V(PROVIDER)                                                         \
629
    case PROVIDER_ ## PROVIDER:                                               \
630
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
631
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
632
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
633
      break;
634















































359834
    NODE_ASYNC_PROVIDER_TYPES(V)
635
  #undef V
636
    default:
637
      UNREACHABLE();
638
  }
639
179917
}
640
641
242559
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
642

317201
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
643
74642
      !env->can_call_into_js()) {
644
168413
    return;
645
  }
646
647
74149
  if (env->destroy_async_id_list()->empty()) {
648
22340
    env->SetUnrefImmediate(&DestroyAsyncIdsCallback);
649
  }
650
651
74149
  env->destroy_async_id_list()->push_back(async_id);
652
}
653
654
173136
void AsyncWrap::AsyncReset(double execution_async_id, bool silent) {
655
173136
  AsyncReset(object(), execution_async_id, silent);
656
173140
}
657
658
// Generalized call for both the constructor and for handles that are pooled
659
// and reused over their lifetime. This way a new uid can be assigned when
660
// the resource is pulled out of the pool and put back into use.
661
178359
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
662
                           bool silent) {
663
178359
  CHECK_NE(provider_type(), PROVIDER_NONE);
664
665
178359
  if (async_id_ != kInvalidAsyncId) {
666
    // This instance was in use before, we have already emitted an init with
667
    // its previous async_id and need to emit a matching destroy for that
668
    // before generating a new async_id.
669
229
    EmitDestroy();
670
  }
671
672
  // Now we can assign a new async_id_ to this instance.
673
178359
  async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id()
674
                                                     : execution_async_id;
675
178359
  trigger_async_id_ = env()->get_default_trigger_async_id();
676
677
356718
  if (resource != object()) {
678
    // TODO(addaleax): Using a strong reference here makes it very easy to
679
    // introduce memory leaks. Move away from using a strong reference.
680
5219
    resource_.Reset(env()->isolate(), resource);
681
  }
682
683












178359
  switch (provider_type()) {
684
#define V(PROVIDER)                                                           \
685
    case PROVIDER_ ## PROVIDER:                                               \
686
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
687
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
688
        auto data = tracing::TracedValue::Create();                           \
689
        data->SetInteger("executionAsyncId",                                  \
690
                         static_cast<int64_t>(env()->execution_async_id()));  \
691
        data->SetInteger("triggerAsyncId",                                    \
692
                         static_cast<int64_t>(get_trigger_async_id()));       \
693
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
694
          TRACING_CATEGORY_NODE1(async_hooks),                                \
695
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
696
          "data", std::move(data));                                           \
697
        }                                                                     \
698
      break;
699






































































50
    NODE_ASYNC_PROVIDER_TYPES(V)
700
#undef V
701
    default:
702
      UNREACHABLE();
703
  }
704
705
178359
  if (silent) return;
706
707
356688
  EmitAsyncInit(env(), resource,
708
178344
                env()->async_hooks()->provider_string(provider_type()),
709
178344
                async_id_, trigger_async_id_);
710
}
711
712
713
178891
void AsyncWrap::EmitAsyncInit(Environment* env,
714
                              Local<Object> object,
715
                              Local<String> type,
716
                              double async_id,
717
                              double trigger_async_id) {
718
178891
  CHECK(!object.IsEmpty());
719
178891
  CHECK(!type.IsEmpty());
720
178891
  AsyncHooks* async_hooks = env->async_hooks();
721
722
  // Nothing to execute, so can continue normally.
723
178891
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
724
164911
    return;
725
  }
726
727
27960
  HandleScope scope(env->isolate());
728
13980
  Local<Function> init_fn = env->async_hooks_init_function();
729
730
  Local<Value> argv[] = {
731
    Number::New(env->isolate(), async_id),
732
    type,
733
    Number::New(env->isolate(), trigger_async_id),
734
    object,
735
69900
  };
736
737
27960
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
738
41940
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
739
}
740
741
742
559804
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
743
                                          int argc,
744
                                          Local<Value>* argv) {
745
559804
  EmitTraceEventBefore();
746
747
559405
  ProviderType provider = provider_type();
748
559980
  async_context context { get_async_id(), get_trigger_async_id() };
749
  MaybeLocal<Value> ret = InternalMakeCallback(
750
560012
      env(), object(), cb, argc, argv, context);
751
752
  // This is a static call with cached values because the `this` object may
753
  // no longer be alive at this point.
754
559916
  EmitTraceEventAfter(provider, context.async_id);
755
756
559913
  return ret;
757
}
758
759
std::string AsyncWrap::MemoryInfoName() const {
760
  return provider_names[provider_type()];
761
}
762
763
std::string AsyncWrap::diagnostic_name() const {
764
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
765
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
766
}
767
768
239
Local<Object> AsyncWrap::GetOwner() {
769
239
  return GetOwner(env(), object());
770
}
771
772
239
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
773
239
  EscapableHandleScope handle_scope(env->isolate());
774
239
  CHECK(!obj.IsEmpty());
775
776
478
  TryCatchScope ignore_exceptions(env);
777
  while (true) {
778
    Local<Value> owner;
779
1856
    if (!obj->Get(env->context(),
780

3248
                  env->owner_symbol()).ToLocal(&owner) ||
781
464
        !owner->IsObject()) {
782
478
      return handle_scope.Escape(obj);
783
    }
784
785
225
    obj = owner.As<Object>();
786
225
  }
787
}
788
789
34853
Local<Object> AsyncWrap::GetResource() {
790
69706
  if (resource_.IsEmpty()) {
791
3984
    return object();
792
  }
793
794
61738
  return resource_.Get(env()->isolate());
795
}
796
797
}  // namespace node
798
799
4185
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)