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: 319 330 96.7 %
Date: 2019-09-17 22:33:17 Branches: 690 1122 61.5 %

Line Branch Exec Source
1
// Copyright Joyent, Inc. and other Node contributors.
2
//
3
// Permission is hereby granted, free of charge, to any person obtaining a
4
// copy of this software and associated documentation files (the
5
// "Software"), to deal in the Software without restriction, including
6
// without limitation the rights to use, copy, modify, merge, publish,
7
// distribute, sublicense, and/or sell copies of the Software, and to permit
8
// persons to whom the Software is furnished to do so, subject to the
9
// following conditions:
10
//
11
// The above copyright notice and this permission notice shall be included
12
// in all copies or substantial portions of the Software.
13
//
14
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20
// USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22
#include "async_wrap.h"  // NOLINT(build/include_inline)
23
#include "async_wrap-inl.h"
24
#include "env-inl.h"
25
#include "node_errors.h"
26
#include "tracing/traced_value.h"
27
#include "util-inl.h"
28
29
#include "v8.h"
30
#include "v8-profiler.h"
31
32
using v8::Context;
33
using v8::DontDelete;
34
using v8::EscapableHandleScope;
35
using v8::Function;
36
using v8::FunctionCallbackInfo;
37
using v8::FunctionTemplate;
38
using v8::Global;
39
using v8::HandleScope;
40
using v8::Integer;
41
using v8::Isolate;
42
using v8::Local;
43
using v8::MaybeLocal;
44
using v8::Number;
45
using v8::Object;
46
using v8::ObjectTemplate;
47
using v8::Promise;
48
using v8::PromiseHookType;
49
using v8::PropertyAttribute;
50
using v8::PropertyCallbackInfo;
51
using v8::ReadOnly;
52
using v8::String;
53
using v8::TryCatch;
54
using v8::Uint32;
55
using v8::Undefined;
56
using v8::Value;
57
using v8::WeakCallbackInfo;
58
using v8::WeakCallbackType;
59
60
using TryCatchScope = node::errors::TryCatchScope;
61
62
namespace node {
63
64
static const char* const provider_names[] = {
65
#define V(PROVIDER)                                                           \
66
  #PROVIDER,
67
  NODE_ASYNC_PROVIDER_TYPES(V)
68
#undef V
69
};
70
71
72
194
struct AsyncWrapObject : public AsyncWrap {
73
97
  static inline void New(const FunctionCallbackInfo<Value>& args) {
74
97
    Environment* env = Environment::GetCurrent(args);
75
97
    CHECK(args.IsConstructCall());
76
194
    CHECK(env->async_wrap_object_ctor_template()->HasInstance(args.This()));
77
194
    CHECK(args[0]->IsUint32());
78
291
    auto type = static_cast<ProviderType>(args[0].As<Uint32>()->Value());
79
97
    new AsyncWrapObject(env, args.This(), type);
80
97
  }
81
82
97
  inline AsyncWrapObject(Environment* env, Local<Object> object,
83
97
                         ProviderType type) : AsyncWrap(env, object, type) {}
84
85
3
  SET_NO_MEMORY_INFO()
86
3
  SET_MEMORY_INFO_NAME(AsyncWrapObject)
87
3
  SET_SELF_SIZE(AsyncWrapObject)
88
};
89
90
22202
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) {
91
22202
  Local<Function> fn = env->async_hooks_destroy_function();
92
93
22202
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
94
95

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

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


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











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












































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











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












































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

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

56
      args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId;
421
28
  wrap->AsyncReset(resource, execution_async_id);
422
}
423
424
425
28
void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) {
426
  AsyncWrap* wrap;
427
56
  args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE);
428
56
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
429
84
  args.GetReturnValue().Set(wrap->provider_type());
430
}
431
432
433
323061
void AsyncWrap::EmitDestroy() {
434
323061
  AsyncWrap::EmitDestroy(env(), async_id_);
435
  // Ensure no double destroy is emitted via AsyncReset().
436
323063
  async_id_ = kInvalidAsyncId;
437
323063
}
438
439
55732
void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
440
111464
  CHECK(args[0]->IsNumber());
441
  AsyncWrap::EmitDestroy(
442
      Environment::GetCurrent(args),
443
167196
      args[0].As<Number>()->Value());
444
55732
}
445
446
81874
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) {
447
81874
  Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template();
448
81874
  if (tmpl.IsEmpty()) {
449
5183
    tmpl = env->NewFunctionTemplate(nullptr);
450
10366
    tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
451
5183
    env->SetProtoMethod(tmpl, "getAsyncId", AsyncWrap::GetAsyncId);
452
5183
    env->SetProtoMethod(tmpl, "asyncReset", AsyncWrap::AsyncReset);
453
5183
    env->SetProtoMethod(tmpl, "getProviderType", AsyncWrap::GetProviderType);
454
5183
    env->set_async_wrap_ctor_template(tmpl);
455
  }
456
81874
  return tmpl;
457
}
458
459
5183
void AsyncWrap::Initialize(Local<Object> target,
460
                           Local<Value> unused,
461
                           Local<Context> context,
462
                           void* priv) {
463
5183
  Environment* env = Environment::GetCurrent(context);
464
5183
  Isolate* isolate = env->isolate();
465
5183
  HandleScope scope(isolate);
466
467
5183
  env->SetMethod(target, "setupHooks", SetupHooks);
468
5183
  env->SetMethod(target, "pushAsyncIds", PushAsyncIds);
469
5183
  env->SetMethod(target, "popAsyncIds", PopAsyncIds);
470
5183
  env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
471
5183
  env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
472
5183
  env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
473
5183
  env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
474
475
  PropertyAttribute ReadOnlyDontDelete =
476
5183
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
477
478
#define FORCE_SET_TARGET_FIELD(obj, str, field)                               \
479
  (obj)->DefineOwnProperty(context,                                           \
480
                           FIXED_ONE_BYTE_STRING(isolate, str),               \
481
                           field,                                             \
482
                           ReadOnlyDontDelete).FromJust()
483
484
  // Attach the uint32_t[] where each slot contains the count of the number of
485
  // callbacks waiting to be called on a particular event. It can then be
486
  // incremented/decremented from JS quickly to communicate to C++ if there are
487
  // any callbacks waiting to be called.
488
20732
  FORCE_SET_TARGET_FIELD(target,
489
                         "async_hook_fields",
490
                         env->async_hooks()->fields().GetJSArray());
491
492
  // The following v8::Float64Array has 5 fields. These fields are shared in
493
  // this way to allow JS and C++ to read/write each value as quickly as
494
  // possible. The fields are represented as follows:
495
  //
496
  // kAsyncIdCounter: Maintains the state of the next unique id to be assigned.
497
  //
498
  // kDefaultTriggerAsyncId: Write the id of the resource responsible for a
499
  //   handle's creation just before calling the new handle's constructor.
500
  //   After the new handle is constructed kDefaultTriggerAsyncId is set back
501
  //   to kInvalidAsyncId.
502
20732
  FORCE_SET_TARGET_FIELD(target,
503
                         "async_id_fields",
504
                         env->async_hooks()->async_id_fields().GetJSArray());
505
506
  target->Set(context,
507
              env->async_ids_stack_string(),
508
20732
              env->async_hooks()->async_ids_stack().GetJSArray()).Check();
509
510
  target->Set(context,
511
              FIXED_ONE_BYTE_STRING(env->isolate(), "owner_symbol"),
512
20732
              env->owner_symbol()).Check();
513
514
5183
  Local<Object> constants = Object::New(isolate);
515
#define SET_HOOKS_CONSTANT(name)                                              \
516
  FORCE_SET_TARGET_FIELD(                                                     \
517
      constants, #name, Integer::New(isolate, AsyncHooks::name))
518
519
20732
  SET_HOOKS_CONSTANT(kInit);
520
20732
  SET_HOOKS_CONSTANT(kBefore);
521
20732
  SET_HOOKS_CONSTANT(kAfter);
522
20732
  SET_HOOKS_CONSTANT(kDestroy);
523
20732
  SET_HOOKS_CONSTANT(kPromiseResolve);
524
20732
  SET_HOOKS_CONSTANT(kTotals);
525
20732
  SET_HOOKS_CONSTANT(kCheck);
526
20732
  SET_HOOKS_CONSTANT(kExecutionAsyncId);
527
20732
  SET_HOOKS_CONSTANT(kTriggerAsyncId);
528
20732
  SET_HOOKS_CONSTANT(kAsyncIdCounter);
529
20732
  SET_HOOKS_CONSTANT(kDefaultTriggerAsyncId);
530
20732
  SET_HOOKS_CONSTANT(kStackLength);
531
#undef SET_HOOKS_CONSTANT
532
15549
  FORCE_SET_TARGET_FIELD(target, "constants", constants);
533
534
5183
  Local<Object> async_providers = Object::New(isolate);
535
#define V(p)                                                                  \
536
  FORCE_SET_TARGET_FIELD(                                                     \
537
      async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p));
538
689339
  NODE_ASYNC_PROVIDER_TYPES(V)
539
#undef V
540
15549
  FORCE_SET_TARGET_FIELD(target, "Providers", async_providers);
541
542
#undef FORCE_SET_TARGET_FIELD
543
544
5183
  env->set_async_hooks_init_function(Local<Function>());
545
5183
  env->set_async_hooks_before_function(Local<Function>());
546
5183
  env->set_async_hooks_after_function(Local<Function>());
547
5183
  env->set_async_hooks_destroy_function(Local<Function>());
548
5183
  env->set_async_hooks_promise_resolve_function(Local<Function>());
549
5183
  env->set_async_hooks_binding(target);
550
551
  // TODO(addaleax): This block might better work as a
552
  // AsyncWrapObject::Initialize() or AsyncWrapObject::GetConstructorTemplate()
553
  // function.
554
  {
555
5183
    auto class_name = FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap");
556
5183
    auto function_template = env->NewFunctionTemplate(AsyncWrapObject::New);
557
5183
    function_template->SetClassName(class_name);
558
10366
    function_template->Inherit(AsyncWrap::GetConstructorTemplate(env));
559
5183
    auto instance_template = function_template->InstanceTemplate();
560
5183
    instance_template->SetInternalFieldCount(1);
561
    auto function =
562
15549
        function_template->GetFunction(env->context()).ToLocalChecked();
563
15549
    target->Set(env->context(), class_name, function).Check();
564
5183
    env->set_async_wrap_object_ctor_template(function_template);
565
5183
  }
566
5183
}
567
568
569
276188
AsyncWrap::AsyncWrap(Environment* env,
570
                     Local<Object> object,
571
                     ProviderType provider,
572
                     double execution_async_id)
573
276188
    : AsyncWrap(env, object, provider, execution_async_id, false) {}
574
575
277173
AsyncWrap::AsyncWrap(Environment* env,
576
                     Local<Object> object,
577
                     ProviderType provider,
578
                     double execution_async_id,
579
                     bool silent)
580
277173
    : AsyncWrap(env, object) {
581
277173
  CHECK_NE(provider, PROVIDER_NONE);
582
277173
  provider_type_ = provider;
583
584
  // Use AsyncReset() call to execute the init() callbacks.
585
277173
  AsyncReset(execution_async_id, silent);
586
277173
  init_hook_ran_ = true;
587
277173
}
588
589
280193
AsyncWrap::AsyncWrap(Environment* env, Local<Object> object)
590
280193
  : BaseObject(env, object) {
591
280193
}
592
593
// This method is necessary to work around one specific problem:
594
// Before the init() hook runs, if there is one, the BaseObject() constructor
595
// registers this object with the Environment for finilization and debugging
596
// purposes.
597
// If the Environment decides to inspect this object for debugging, it tries to
598
// call virtual methods on this object that are only (meaningfully) implemented
599
// by the subclasses of AsyncWrap.
600
// This could, with bad luck, happen during the AsyncWrap() constructor,
601
// because we run JS code as part of it and that in turn can lead to a heapdump
602
// being taken, either through the inspector or our programmatic API for it.
603
// The object being initialized is not fully constructed at that point, and
604
// in particular its virtual function table points to the AsyncWrap one
605
// (as the subclass constructor has not yet begun execution at that point).
606
// This means that the functions that are used for heap dump memory tracking
607
// are not yet available, and trying to call them would crash the process.
608
// We use this particular `IsDoneInitializing()` method to tell the Environment
609
// that such debugging methods are not yet available.
610
// This may be somewhat unreliable when it comes to future changes, because
611
// at this point it *only* protects AsyncWrap subclasses, and *only* for cases
612
// where heap dumps are being taken while the init() hook is on the call stack.
613
// For now, it seems like the best solution, though.
614
153
bool AsyncWrap::IsDoneInitializing() const {
615
153
  return init_hook_ran_;
616
}
617
618
558447
AsyncWrap::~AsyncWrap() {
619
279223
  EmitTraceEventDestroy();
620
279224
  EmitDestroy();
621
279224
}
622
623
322824
void AsyncWrap::EmitTraceEventDestroy() {
624











322824
  switch (provider_type()) {
625
  #define V(PROVIDER)                                                         \
626
    case PROVIDER_ ## PROVIDER:                                               \
627
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
628
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
629
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
630
      break;
631












































645648
    NODE_ASYNC_PROVIDER_TYPES(V)
632
  #undef V
633
    default:
634
      UNREACHABLE();
635
  }
636
322824
}
637
638
383495
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
639


454980
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
640
71485
      !env->can_call_into_js()) {
641
695775
    return;
642
  }
643
644
71215
  if (env->destroy_async_id_list()->empty()) {
645
22232
    env->SetUnrefImmediate(&DestroyAsyncIdsCallback);
646
  }
647
648
71215
  env->destroy_async_id_list()->push_back(async_id);
649
}
650
651
277379
void AsyncWrap::AsyncReset(double execution_async_id, bool silent) {
652
277379
  AsyncReset(object(), execution_async_id, silent);
653
277379
}
654
655
// Generalized call for both the constructor and for handles that are pooled
656
// and reused over their lifetime. This way a new uid can be assigned when
657
// the resource is pulled out of the pool and put back into use.
658
321215
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
659
                           bool silent) {
660
321215
  CHECK_NE(provider_type(), PROVIDER_NONE);
661
662
321215
  if (async_id_ != kInvalidAsyncId) {
663
    // This instance was in use before, we have already emitted an init with
664
    // its previous async_id and need to emit a matching destroy for that
665
    // before generating a new async_id.
666
237
    EmitDestroy();
667
  }
668
669
  // Now we can assign a new async_id_ to this instance.
670
321215
  async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id()
671
642430
                                                     : execution_async_id;
672
321215
  trigger_async_id_ = env()->get_default_trigger_async_id();
673
674











321215
  switch (provider_type()) {
675
#define V(PROVIDER)                                                           \
676
    case PROVIDER_ ## PROVIDER:                                               \
677
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
678
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
679
        auto data = tracing::TracedValue::Create();                           \
680
        data->SetInteger("executionAsyncId",                                  \
681
                         static_cast<int64_t>(env()->execution_async_id()));  \
682
        data->SetInteger("triggerAsyncId",                                    \
683
                         static_cast<int64_t>(get_trigger_async_id()));       \
684
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
685
          TRACING_CATEGORY_NODE1(async_hooks),                                \
686
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
687
          "data", std::move(data));                                           \
688
        }                                                                     \
689
      break;
690


































































34
    NODE_ASYNC_PROVIDER_TYPES(V)
691
#undef V
692
    default:
693
      UNREACHABLE();
694
  }
695
696
642430
  if (silent) return;
697
698
  EmitAsyncInit(env(), resource,
699
321199
                env()->async_hooks()->provider_string(provider_type()),
700
642398
                async_id_, trigger_async_id_);
701
}
702
703
704
321746
void AsyncWrap::EmitAsyncInit(Environment* env,
705
                              Local<Object> object,
706
                              Local<String> type,
707
                              double async_id,
708
                              double trigger_async_id) {
709
321746
  CHECK(!object.IsEmpty());
710
321746
  CHECK(!type.IsEmpty());
711
321746
  AsyncHooks* async_hooks = env->async_hooks();
712
713
  // Nothing to execute, so can continue normally.
714
321746
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
715
629901
    return;
716
  }
717
718
13591
  HandleScope scope(env->isolate());
719
13591
  Local<Function> init_fn = env->async_hooks_init_function();
720
721
  Local<Value> argv[] = {
722
    Number::New(env->isolate(), async_id),
723
    type,
724
    Number::New(env->isolate(), trigger_async_id),
725
    object,
726
67955
  };
727
728
27182
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
729
54364
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
730
}
731
732
733
1110296
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
734
                                          int argc,
735
                                          Local<Value>* argv) {
736
1110296
  EmitTraceEventBefore();
737
738
1110222
  ProviderType provider = provider_type();
739
1110400
  async_context context { get_async_id(), get_trigger_async_id() };
740
  MaybeLocal<Value> ret = InternalMakeCallback(
741
1110405
      env(), object(), cb, argc, argv, context);
742
743
  // This is a static call with cached values because the `this` object may
744
  // no longer be alive at this point.
745
1110314
  EmitTraceEventAfter(provider, context.async_id);
746
747
1110312
  return ret;
748
}
749
750
std::string AsyncWrap::MemoryInfoName() const {
751
  return provider_names[provider_type()];
752
}
753
754
std::string AsyncWrap::diagnostic_name() const {
755
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
756
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
757
}
758
759
240
Local<Object> AsyncWrap::GetOwner() {
760
240
  return GetOwner(env(), object());
761
}
762
763
240
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
764
240
  EscapableHandleScope handle_scope(env->isolate());
765
240
  CHECK(!obj.IsEmpty());
766
767
480
  TryCatchScope ignore_exceptions(env);
768
  while (true) {
769
    Local<Value> owner;
770
932
    if (!obj->Get(env->context(),
771


3262
                  env->owner_symbol()).ToLocal(&owner) ||
772
466
        !owner->IsObject()) {
773
480
      return handle_scope.Escape(obj);
774
    }
775
776
226
    obj = owner.As<Object>();
777
  }
778
}
779
780
}  // namespace node
781
782
5036
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)