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: 453 475 95.4 %
Date: 2020-08-22 22:13:06 Branches: 749 1401 53.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 "node_external_reference.h"
27
#include "tracing/traced_value.h"
28
#include "util-inl.h"
29
30
#include "v8.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::Just;
43
using v8::Local;
44
using v8::Maybe;
45
using v8::MaybeLocal;
46
using v8::Name;
47
using v8::Nothing;
48
using v8::Number;
49
using v8::Object;
50
using v8::ObjectTemplate;
51
using v8::Promise;
52
using v8::PromiseHookType;
53
using v8::PropertyAttribute;
54
using v8::PropertyCallbackInfo;
55
using v8::ReadOnly;
56
using v8::String;
57
using v8::Uint32;
58
using v8::Undefined;
59
using v8::Value;
60
using v8::WeakCallbackInfo;
61
using v8::WeakCallbackType;
62
63
using TryCatchScope = node::errors::TryCatchScope;
64
65
namespace node {
66
67
static const char* const provider_names[] = {
68
#define V(PROVIDER)                                                           \
69
  #PROVIDER,
70
  NODE_ASYNC_PROVIDER_TYPES(V)
71
#undef V
72
};
73
74
75
198
struct AsyncWrapObject : public AsyncWrap {
76
99
  static inline void New(const FunctionCallbackInfo<Value>& args) {
77
99
    Environment* env = Environment::GetCurrent(args);
78
99
    CHECK(args.IsConstructCall());
79
198
    CHECK(env->async_wrap_object_ctor_template()->HasInstance(args.This()));
80
198
    CHECK(args[0]->IsUint32());
81
297
    auto type = static_cast<ProviderType>(args[0].As<Uint32>()->Value());
82
99
    new AsyncWrapObject(env, args.This(), type);
83
99
  }
84
85
99
  inline AsyncWrapObject(Environment* env, Local<Object> object,
86
99
                         ProviderType type) : AsyncWrap(env, object, type) {}
87
88
454
  static Local<FunctionTemplate> GetConstructorTemplate(Environment* env) {
89
454
    Local<FunctionTemplate> tmpl = env->async_wrap_object_ctor_template();
90
454
    if (tmpl.IsEmpty()) {
91
454
      tmpl = env->NewFunctionTemplate(AsyncWrapObject::New);
92
908
      tmpl->SetClassName(
93
454
          FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
94
908
      tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
95
1362
      tmpl->InstanceTemplate()->SetInternalFieldCount(
96
454
          AsyncWrapObject::kInternalFieldCount);
97
454
      env->set_async_wrap_object_ctor_template(tmpl);
98
    }
99
454
    return tmpl;
100
  }
101
102
3
  SET_NO_MEMORY_INFO()
103
3
  SET_MEMORY_INFO_NAME(AsyncWrapObject)
104
3
  SET_SELF_SIZE(AsyncWrapObject)
105
};
106
107
21957
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) {
108
21957
  Local<Function> fn = env->async_hooks_destroy_function();
109
110
43914
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
111
112

21959
  do {
113
43918
    std::vector<double> destroy_async_id_list;
114
21959
    destroy_async_id_list.swap(*env->destroy_async_id_list());
115
21959
    if (!env->can_call_into_js()) return;
116

117226
    for (auto async_id : destroy_async_id_list) {
117
      // Want each callback to be cleaned up after itself, instead of cleaning
118
      // them all up after the while() loop completes.
119
190534
      HandleScope scope(env->isolate());
120
95267
      Local<Value> async_id_value = Number::New(env->isolate(), async_id);
121
      MaybeLocal<Value> ret = fn->Call(
122
285801
          env->context(), Undefined(env->isolate()), 1, &async_id_value);
123
124
95267
      if (ret.IsEmpty())
125
        return;
126
    }
127
21959
  } while (!env->destroy_async_id_list()->empty());
128
}
129
130
112287
void Emit(Environment* env, double async_id, AsyncHooks::Fields type,
131
          Local<Function> fn) {
132
112287
  AsyncHooks* async_hooks = env->async_hooks();
133
134

112287
  if (async_hooks->fields()[type] == 0 || !env->can_call_into_js())
135
110920
    return;
136
137
2734
  HandleScope handle_scope(env->isolate());
138
1367
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
139
2734
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
140
4101
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
141
}
142
143
144
21127
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
145
21127
  Emit(env, async_id, AsyncHooks::kPromiseResolve,
146
21127
       env->async_hooks_promise_resolve_function());
147
21127
}
148
149
150
598848
void AsyncWrap::EmitTraceEventBefore() {
151













598848
  switch (provider_type()) {
152
#define V(PROVIDER)                                                           \
153
    case PROVIDER_ ## PROVIDER:                                               \
154
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(                                      \
155
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
156
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
157
      break;
158






















































1197592
    NODE_ASYNC_PROVIDER_TYPES(V)
159
#undef V
160
    default:
161
      UNREACHABLE();
162
  }
163
598796
}
164
165
166
45586
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
167
45586
  Emit(env, async_id, AsyncHooks::kBefore,
168
45586
       env->async_hooks_before_function());
169
45586
}
170
171
172
599084
void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) {
173













599084
  switch (type) {
174
#define V(PROVIDER)                                                           \
175
    case PROVIDER_ ## PROVIDER:                                               \
176
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
177
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
178
        #PROVIDER "_CALLBACK", static_cast<int64_t>(async_id));               \
179
      break;
180






















































1198178
    NODE_ASYNC_PROVIDER_TYPES(V)
181
#undef V
182
    default:
183
      UNREACHABLE();
184
  }
185
599089
}
186
187
188
45574
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
189
  // If the user's callback failed then the after() hooks will be called at the
190
  // end of _fatalException().
191
45574
  Emit(env, async_id, AsyncHooks::kAfter,
192
45574
       env->async_hooks_after_function());
193
45574
}
194
195
// TODO(addaleax): Remove once we're on C++17.
196
constexpr double AsyncWrap::kInvalidAsyncId;
197
198
195
static Maybe<double> GetAssignedPromiseAsyncId(Environment* env,
199
                                               Local<Promise> promise,
200
                                               Local<Value> id_symbol) {
201
  Local<Value> maybe_async_id;
202
585
  if (!promise->Get(env->context(), id_symbol).ToLocal(&maybe_async_id)) {
203
1
    return Nothing<double>();
204
  }
205
194
  return maybe_async_id->IsNumber()
206
248
      ? maybe_async_id->NumberValue(env->context())
207
318
      : Just(AsyncWrap::kInvalidAsyncId);
208
}
209
210
41982
class PromiseWrap : public AsyncWrap {
211
 public:
212
21171
  PromiseWrap(Environment* env, Local<Object> object, bool silent)
213
21171
      : AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) {
214
21171
    MakeWeak();
215
21171
  }
216
217
  PromiseWrap(Environment* env, Local<Object> object, double asyncId,
218
    double triggerAsyncId)
219
      : AsyncWrap(env, object, PROVIDER_PROMISE, asyncId, triggerAsyncId) {
220
    MakeWeak();
221
  }
222
223
5
  SET_NO_MEMORY_INFO()
224
5
  SET_MEMORY_INFO_NAME(PromiseWrap)
225
5
  SET_SELF_SIZE(PromiseWrap)
226
227
  static PromiseWrap* New(Environment* env,
228
                          Local<Promise> promise,
229
                          bool silent);
230
  static void GetAsyncId(Local<Name> property,
231
                         const PropertyCallbackInfo<Value>& args);
232
  static void GetTriggerAsyncId(Local<Name> property,
233
                                const PropertyCallbackInfo<Value>& args);
234
235
  static void Initialize(Environment* env);
236
};
237
238
21171
PromiseWrap* PromiseWrap::New(Environment* env,
239
                              Local<Promise> promise,
240
                              bool silent) {
241
21171
  Local<Context> context = env->context();
242
243
  Local<Object> obj;
244
63513
  if (!env->promise_wrap_template()->NewInstance(context).ToLocal(&obj))
245
    return nullptr;
246
247
42342
  CHECK_NULL(promise->GetAlignedPointerFromInternalField(0));
248
21171
  promise->SetInternalField(0, obj);
249
250
  // Skip for init events
251
21171
  if (silent) {
252
    double async_id;
253
    double trigger_async_id;
254
102
    if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol())
255
34
            .To(&async_id)) return nullptr;
256
102
    if (!GetAssignedPromiseAsyncId(env, promise, env->trigger_async_id_symbol())
257
34
            .To(&trigger_async_id)) return nullptr;
258
259

34
    if (async_id != AsyncWrap::kInvalidAsyncId &&
260
        trigger_async_id != AsyncWrap::kInvalidAsyncId) {
261
      return new PromiseWrap(
262
          env, obj, async_id, trigger_async_id);
263
    }
264
  }
265
266
21171
  return new PromiseWrap(env, obj, silent);
267
}
268
269
7
void PromiseWrap::GetAsyncId(Local<Name> property,
270
                             const PropertyCallbackInfo<Value>& info) {
271
7
  Isolate* isolate = info.GetIsolate();
272
14
  HandleScope scope(isolate);
273
274
7
  PromiseWrap* wrap = Unwrap<PromiseWrap>(info.Holder());
275
7
  double value = wrap->get_async_id();
276
277
21
  info.GetReturnValue().Set(Number::New(isolate, value));
278
7
}
279
280
7
void PromiseWrap::GetTriggerAsyncId(Local<Name> property,
281
                                    const PropertyCallbackInfo<Value>& info) {
282
7
  Isolate* isolate = info.GetIsolate();
283
14
  HandleScope scope(isolate);
284
285
7
  PromiseWrap* wrap = Unwrap<PromiseWrap>(info.Holder());
286
7
  double value = wrap->get_trigger_async_id();
287
288
21
  info.GetReturnValue().Set(Number::New(isolate, value));
289
7
}
290
291
454
void PromiseWrap::Initialize(Environment* env) {
292
454
  Isolate* isolate = env->isolate();
293
908
  HandleScope scope(isolate);
294
295
454
  Local<FunctionTemplate> ctor = FunctionTemplate::New(isolate);
296
908
  ctor->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "PromiseWrap"));
297
298
454
  Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
299
454
  env->set_promise_wrap_template(promise_wrap_template);
300
301
454
  promise_wrap_template->SetInternalFieldCount(
302
454
      PromiseWrap::kInternalFieldCount);
303
304
1362
  promise_wrap_template->SetAccessor(
305
      env->async_id_symbol(),
306
454
      PromiseWrap::GetAsyncId);
307
308
1362
  promise_wrap_template->SetAccessor(
309
      env->trigger_async_id_symbol(),
310
454
      PromiseWrap::GetTriggerAsyncId);
311
454
}
312
313
74097
static PromiseWrap* extractPromiseWrap(Local<Promise> promise) {
314
  // This check is imperfect. If the internal field is set, it should
315
  // be an object. If it's not, we just ignore it. Ideally v8 would
316
  // have had GetInternalField returning a MaybeLocal but this works
317
  // for now.
318
148194
  Local<Value> obj = promise->GetInternalField(0);
319
127023
  return obj->IsObject() ? Unwrap<PromiseWrap>(obj.As<Object>()) : nullptr;
320
}
321
322
108
static uint16_t ToAsyncHooksType(PromiseHookType type) {
323

108
  switch (type) {
324
98
    case PromiseHookType::kInit:    return AsyncHooks::kInit;
325
4
    case PromiseHookType::kBefore:  return AsyncHooks::kBefore;
326
4
    case PromiseHookType::kAfter:   return AsyncHooks::kAfter;
327
2
    case PromiseHookType::kResolve: return AsyncHooks::kPromiseResolve;
328
  }
329
  UNREACHABLE();
330
}
331
332
// Simplified JavaScript hook fast-path for when there is no destroy hook
333
300
static void FastPromiseHook(PromiseHookType type, Local<Promise> promise,
334
                            Local<Value> parent) {
335
300
  Local<Context> context = promise->CreationContext();
336
300
  Environment* env = Environment::GetCurrent(context);
337
492
  if (env == nullptr) return;
338
339

645
  if (type == PromiseHookType::kBefore &&
340
345
      env->async_hooks()->fields()[AsyncHooks::kBefore] == 0) {
341
    double async_id;
342
    double trigger_async_id;
343
126
    if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol())
344
83
            .To(&async_id)) return;
345
126
    if (!GetAssignedPromiseAsyncId(env, promise, env->trigger_async_id_symbol())
346
42
            .To(&trigger_async_id)) return;
347
348

83
    if (async_id != AsyncWrap::kInvalidAsyncId &&
349
41
        trigger_async_id != AsyncWrap::kInvalidAsyncId) {
350
82
      env->async_hooks()->push_async_context(
351
82
          async_id, trigger_async_id, promise);
352
41
      return;
353
    }
354
  }
355
356

565
  if (type == PromiseHookType::kAfter &&
357
306
      env->async_hooks()->fields()[AsyncHooks::kAfter] == 0) {
358
    double async_id;
359
129
    if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol())
360
87
            .To(&async_id)) return;
361
362
42
    if (async_id != AsyncWrap::kInvalidAsyncId) {
363
42
      if (env->execution_async_id() == async_id) {
364
        // This condition might not be true if async_hooks was enabled during
365
        // the promise callback execution.
366
40
        env->async_hooks()->pop_async_context(async_id);
367
      }
368
42
      return;
369
    }
370
  }
371
372

542
  if (type == PromiseHookType::kResolve &&
373
326
      env->async_hooks()->fields()[AsyncHooks::kPromiseResolve] == 0) {
374
108
    return;
375
  }
376
377
  // Getting up to this point means either init type or
378
  // that there are active hooks of another type.
379
  // In both cases fast-path JS hook should be called.
380
381
  Local<Value> argv[] = {
382
108
    Integer::New(env->isolate(), ToAsyncHooksType(type)),
383
    promise,
384
    parent
385
432
  };
386
387
216
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
388
108
  Local<Function> promise_hook = env->promise_hook_handler();
389
216
  USE(promise_hook->Call(context, Undefined(env->isolate()), 3, argv));
390
}
391
392
63478
static void FullPromiseHook(PromiseHookType type, Local<Promise> promise,
393
                            Local<Value> parent) {
394
63478
  Local<Context> context = promise->CreationContext();
395
396
63478
  Environment* env = Environment::GetCurrent(context);
397
63478
  if (env == nullptr) return;
398
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
399
126956
                              "EnvPromiseHook", env);
400
401
63478
  PromiseWrap* wrap = extractPromiseWrap(promise);
402

63478
  if (type == PromiseHookType::kInit || wrap == nullptr) {
403
21150
    bool silent = type != PromiseHookType::kInit;
404
405
    // set parent promise's async Id as this promise's triggerAsyncId
406
21150
    if (parent->IsPromise()) {
407
      // parent promise exists, current promise
408
      // is a chained promise, so we set parent promise's id as
409
      // current promise's triggerAsyncId
410
10619
      Local<Promise> parent_promise = parent.As<Promise>();
411
10619
      PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise);
412
10619
      if (parent_wrap == nullptr) {
413
21
        parent_wrap = PromiseWrap::New(env, parent_promise, true);
414
21
        if (parent_wrap == nullptr) return;
415
      }
416
417
21238
      AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap);
418
10619
      wrap = PromiseWrap::New(env, promise, silent);
419
    } else {
420
10531
      wrap = PromiseWrap::New(env, promise, silent);
421
    }
422
  }
423
424
63478
  if (wrap == nullptr) return;
425
426
63478
  if (type == PromiseHookType::kBefore) {
427
10607
    env->async_hooks()->push_async_context(wrap->get_async_id(),
428
10607
      wrap->get_trigger_async_id(), wrap->object());
429
10607
    wrap->EmitTraceEventBefore();
430
10607
    AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id());
431
52871
  } else if (type == PromiseHookType::kAfter) {
432
10607
    wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id());
433
10607
    AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id());
434
10607
    if (env->execution_async_id() == wrap->get_async_id()) {
435
      // This condition might not be true if async_hooks was enabled during
436
      // the promise callback execution.
437
      // Popping it off the stack can be skipped in that case, because it is
438
      // known that it would correspond to exactly one call with
439
      // PromiseHookType::kBefore that was not witnessed by the PromiseHook.
440
10605
      env->async_hooks()->pop_async_context(wrap->get_async_id());
441
    }
442
42264
  } else if (type == PromiseHookType::kResolve) {
443
21127
    AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id());
444
  }
445
}
446
447
454
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
448
454
  Environment* env = Environment::GetCurrent(args);
449
450
908
  CHECK(args[0]->IsObject());
451
452
  // All of init, before, after, destroy, and promise_resolve are supplied by
453
  // async_hooks internally, so this should only ever be called once. At which
454
  // time all the functions should be set. Detect this by checking if
455
  // init !IsEmpty().
456
908
  CHECK(env->async_hooks_init_function().IsEmpty());
457
458
908
  Local<Object> fn_obj = args[0].As<Object>();
459
460
#define SET_HOOK_FN(name)                                                      \
461
  do {                                                                         \
462
    Local<Value> v =                                                           \
463
        fn_obj->Get(env->context(),                                            \
464
                    FIXED_ONE_BYTE_STRING(env->isolate(), #name))              \
465
            .ToLocalChecked();                                                 \
466
    CHECK(v->IsFunction());                                                    \
467
    env->set_async_hooks_##name##_function(v.As<Function>());                  \
468
  } while (0)
469
470
2724
  SET_HOOK_FN(init);
471
2724
  SET_HOOK_FN(before);
472
2724
  SET_HOOK_FN(after);
473
2724
  SET_HOOK_FN(destroy);
474
2724
  SET_HOOK_FN(promise_resolve);
475
#undef SET_HOOK_FN
476
454
}
477
478
298
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
479
298
  Environment* env = Environment::GetCurrent(args);
480
481
596
  if (args[0]->IsFunction()) {
482
108
    env->set_promise_hook_handler(args[0].As<Function>());
483
54
    args.GetIsolate()->SetPromiseHook(FastPromiseHook);
484
  } else {
485
244
    args.GetIsolate()->SetPromiseHook(FullPromiseHook);
486
  }
487
298
}
488
489
490
64
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
491
64
  Environment* env = Environment::GetCurrent(args);
492
64
  env->set_promise_hook_handler(Local<Function>());
493
494
  // The per-Isolate API provides no way of knowing whether there are multiple
495
  // users of the PromiseHook. That hopefully goes away when V8 introduces
496
  // a per-context API.
497
64
  args.GetIsolate()->SetPromiseHook(nullptr);
498
64
}
499
500
501
13059
class DestroyParam {
502
 public:
503
  double asyncId;
504
  Environment* env;
505
  Global<Object> target;
506
  Global<Object> propBag;
507
};
508
509
10
static void DestroyParamCleanupHook(void* ptr) {
510
10
  delete static_cast<DestroyParam*>(ptr);
511
10
}
512
513
2166
void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) {
514
4332
  HandleScope scope(info.GetIsolate());
515
516
4332
  std::unique_ptr<DestroyParam> p{info.GetParameter()};
517
  Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(),
518
4332
                                                      p->propBag);
519
  Local<Value> val;
520
521
2166
  p->env->RemoveCleanupHook(DestroyParamCleanupHook, p.get());
522
523
8664
  if (!prop_bag->Get(p->env->context(), p->env->destroyed_string())
524
2166
        .ToLocal(&val)) {
525
    return;
526
  }
527
528
2166
  if (val->IsFalse()) {
529
2160
    AsyncWrap::EmitDestroy(p->env, p->asyncId);
530
  }
531
  // unique_ptr goes out of scope here and pointer is deleted.
532
}
533
534
535
2177
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) {
536
4354
  CHECK(args[0]->IsObject());
537
4354
  CHECK(args[1]->IsNumber());
538
4354
  CHECK(args[2]->IsObject());
539
540
2177
  Isolate* isolate = args.GetIsolate();
541
2177
  DestroyParam* p = new DestroyParam();
542
6531
  p->asyncId = args[1].As<Number>()->Value();
543
2177
  p->env = Environment::GetCurrent(args);
544
6531
  p->target.Reset(isolate, args[0].As<Object>());
545
6531
  p->propBag.Reset(isolate, args[2].As<Object>());
546
2177
  p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter);
547
2177
  p->env->AddCleanupHook(DestroyParamCleanupHook, p);
548
2177
}
549
550
93494
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
551
  AsyncWrap* wrap;
552
186988
  args.GetReturnValue().Set(kInvalidAsyncId);
553
93494
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
554
280419
  args.GetReturnValue().Set(wrap->get_async_id());
555
}
556
557
558
8
void AsyncWrap::PushAsyncContext(const FunctionCallbackInfo<Value>& args) {
559
8
  Environment* env = Environment::GetCurrent(args);
560
  // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail
561
  // then the checks in push_async_ids() and pop_async_id() will.
562
32
  double async_id = args[0]->NumberValue(env->context()).FromJust();
563
32
  double trigger_async_id = args[1]->NumberValue(env->context()).FromJust();
564
8
  env->async_hooks()->push_async_context(async_id, trigger_async_id, {});
565
8
}
566
567
568
3
void AsyncWrap::PopAsyncContext(const FunctionCallbackInfo<Value>& args) {
569
3
  Environment* env = Environment::GetCurrent(args);
570
12
  double async_id = args[0]->NumberValue(env->context()).FromJust();
571
3
  args.GetReturnValue().Set(env->async_hooks()->pop_async_context(async_id));
572
}
573
574
575
274
void AsyncWrap::ExecutionAsyncResource(
576
    const FunctionCallbackInfo<Value>& args) {
577
274
  Environment* env = Environment::GetCurrent(args);
578
  uint32_t index;
579
1096
  if (!args[0]->Uint32Value(env->context()).To(&index)) return;
580
822
  args.GetReturnValue().Set(
581
      env->async_hooks()->native_execution_async_resource(index));
582
}
583
584
585
1219
void AsyncWrap::ClearAsyncIdStack(const FunctionCallbackInfo<Value>& args) {
586
1219
  Environment* env = Environment::GetCurrent(args);
587
1219
  env->async_hooks()->clear_async_id_stack();
588
1219
}
589
590
591
233
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) {
592
466
  CHECK(args[0]->IsObject());
593
594
  AsyncWrap* wrap;
595
233
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
596
597
466
  Local<Object> resource = args[0].As<Object>();
598
  double execution_async_id =
599
466
      args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId;
600
233
  wrap->AsyncReset(resource, execution_async_id);
601
}
602
603
604
233
void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) {
605
  AsyncWrap* wrap;
606
466
  args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE);
607
233
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
608
699
  args.GetReturnValue().Set(wrap->provider_type());
609
}
610
611
612
209715
void AsyncWrap::EmitDestroy(bool from_gc) {
613
209715
  AsyncWrap::EmitDestroy(env(), async_id_);
614
  // Ensure no double destroy is emitted via AsyncReset().
615
209718
  async_id_ = kInvalidAsyncId;
616
617

419435
  if (!persistent().IsEmpty() && !from_gc) {
618
11238
    HandleScope handle_scope(env()->isolate());
619
22476
    USE(object()->Set(env()->context(), env()->resource_symbol(), object()));
620
  }
621
209717
}
622
623
59409
void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
624
118818
  CHECK(args[0]->IsNumber());
625
59409
  AsyncWrap::EmitDestroy(
626
      Environment::GetCurrent(args),
627
178227
      args[0].As<Number>()->Value());
628
59409
}
629
630
454
void AsyncWrap::SetCallbackTrampoline(const FunctionCallbackInfo<Value>& args) {
631
454
  Environment* env = Environment::GetCurrent(args);
632
633
908
  CHECK(args[0]->IsFunction());
634
635
908
  env->set_async_hooks_callback_trampoline(args[0].As<Function>());
636
454
}
637
638
67457
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) {
639
67457
  Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template();
640
67459
  if (tmpl.IsEmpty()) {
641
454
    tmpl = env->NewFunctionTemplate(nullptr);
642
908
    tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
643
908
    tmpl->Inherit(BaseObject::GetConstructorTemplate(env));
644
454
    env->SetProtoMethod(tmpl, "getAsyncId", AsyncWrap::GetAsyncId);
645
454
    env->SetProtoMethod(tmpl, "asyncReset", AsyncWrap::AsyncReset);
646
454
    env->SetProtoMethod(tmpl, "getProviderType", AsyncWrap::GetProviderType);
647
454
    env->set_async_wrap_ctor_template(tmpl);
648
  }
649
67459
  return tmpl;
650
}
651
652
454
void AsyncWrap::Initialize(Local<Object> target,
653
                           Local<Value> unused,
654
                           Local<Context> context,
655
                           void* priv) {
656
454
  Environment* env = Environment::GetCurrent(context);
657
454
  Isolate* isolate = env->isolate();
658
908
  HandleScope scope(isolate);
659
660
454
  env->SetMethod(target, "setupHooks", SetupHooks);
661
454
  env->SetMethod(target, "setCallbackTrampoline", SetCallbackTrampoline);
662
454
  env->SetMethod(target, "pushAsyncContext", PushAsyncContext);
663
454
  env->SetMethod(target, "popAsyncContext", PopAsyncContext);
664
454
  env->SetMethod(target, "executionAsyncResource", ExecutionAsyncResource);
665
454
  env->SetMethod(target, "clearAsyncIdStack", ClearAsyncIdStack);
666
454
  env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
667
454
  env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
668
454
  env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
669
454
  env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
670
671
  PropertyAttribute ReadOnlyDontDelete =
672
454
      static_cast<PropertyAttribute>(ReadOnly | DontDelete);
673
674
#define FORCE_SET_TARGET_FIELD(obj, str, field)                               \
675
  (obj)->DefineOwnProperty(context,                                           \
676
                           FIXED_ONE_BYTE_STRING(isolate, str),               \
677
                           field,                                             \
678
                           ReadOnlyDontDelete).FromJust()
679
680
  // Attach the uint32_t[] where each slot contains the count of the number of
681
  // callbacks waiting to be called on a particular event. It can then be
682
  // incremented/decremented from JS quickly to communicate to C++ if there are
683
  // any callbacks waiting to be called.
684
1816
  FORCE_SET_TARGET_FIELD(target,
685
                         "async_hook_fields",
686
                         env->async_hooks()->fields().GetJSArray());
687
688
  // The following v8::Float64Array has 5 fields. These fields are shared in
689
  // this way to allow JS and C++ to read/write each value as quickly as
690
  // possible. The fields are represented as follows:
691
  //
692
  // kAsyncIdCounter: Maintains the state of the next unique id to be assigned.
693
  //
694
  // kDefaultTriggerAsyncId: Write the id of the resource responsible for a
695
  //   handle's creation just before calling the new handle's constructor.
696
  //   After the new handle is constructed kDefaultTriggerAsyncId is set back
697
  //   to kInvalidAsyncId.
698
1816
  FORCE_SET_TARGET_FIELD(target,
699
                         "async_id_fields",
700
                         env->async_hooks()->async_id_fields().GetJSArray());
701
702
1816
  FORCE_SET_TARGET_FIELD(target,
703
                         "execution_async_resources",
704
                         env->async_hooks()->js_execution_async_resources());
705
706
908
  target->Set(context,
707
              env->async_ids_stack_string(),
708
1816
              env->async_hooks()->async_ids_stack().GetJSArray()).Check();
709
710
454
  Local<Object> constants = Object::New(isolate);
711
#define SET_HOOKS_CONSTANT(name)                                              \
712
  FORCE_SET_TARGET_FIELD(                                                     \
713
      constants, #name, Integer::New(isolate, AsyncHooks::name))
714
715
1816
  SET_HOOKS_CONSTANT(kInit);
716
1816
  SET_HOOKS_CONSTANT(kBefore);
717
1816
  SET_HOOKS_CONSTANT(kAfter);
718
1816
  SET_HOOKS_CONSTANT(kDestroy);
719
1816
  SET_HOOKS_CONSTANT(kPromiseResolve);
720
1816
  SET_HOOKS_CONSTANT(kTotals);
721
1816
  SET_HOOKS_CONSTANT(kCheck);
722
1816
  SET_HOOKS_CONSTANT(kExecutionAsyncId);
723
1816
  SET_HOOKS_CONSTANT(kTriggerAsyncId);
724
1816
  SET_HOOKS_CONSTANT(kAsyncIdCounter);
725
1816
  SET_HOOKS_CONSTANT(kDefaultTriggerAsyncId);
726
1816
  SET_HOOKS_CONSTANT(kUsesExecutionAsyncResource);
727
1816
  SET_HOOKS_CONSTANT(kStackLength);
728
#undef SET_HOOKS_CONSTANT
729
1362
  FORCE_SET_TARGET_FIELD(target, "constants", constants);
730
731
454
  Local<Object> async_providers = Object::New(isolate);
732
#define V(p)                                                                  \
733
  FORCE_SET_TARGET_FIELD(                                                     \
734
      async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p));
735
74002
  NODE_ASYNC_PROVIDER_TYPES(V)
736
#undef V
737
1362
  FORCE_SET_TARGET_FIELD(target, "Providers", async_providers);
738
739
#undef FORCE_SET_TARGET_FIELD
740
741
454
  env->set_async_hooks_init_function(Local<Function>());
742
454
  env->set_async_hooks_before_function(Local<Function>());
743
454
  env->set_async_hooks_after_function(Local<Function>());
744
454
  env->set_async_hooks_destroy_function(Local<Function>());
745
454
  env->set_async_hooks_promise_resolve_function(Local<Function>());
746
454
  env->set_async_hooks_binding(target);
747
748
908
  target->Set(env->context(),
749
      FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"),
750
908
      AsyncWrapObject::GetConstructorTemplate(env)
751
2724
          ->GetFunction(env->context()).ToLocalChecked()).Check();
752
753
  // TODO(qard): maybe this should be GetConstructorTemplate instead?
754
454
  PromiseWrap::Initialize(env);
755
454
}
756
757
4395
void AsyncWrap::RegisterExternalReferences(
758
    ExternalReferenceRegistry* registry) {
759
4395
  registry->Register(SetupHooks);
760
4395
  registry->Register(SetCallbackTrampoline);
761
4395
  registry->Register(PushAsyncContext);
762
4395
  registry->Register(PopAsyncContext);
763
4395
  registry->Register(ExecutionAsyncResource);
764
4395
  registry->Register(ClearAsyncIdStack);
765
4395
  registry->Register(QueueDestroyAsyncId);
766
4395
  registry->Register(EnablePromiseHook);
767
4395
  registry->Register(DisablePromiseHook);
768
4395
  registry->Register(RegisterDestroyHook);
769
4395
  registry->Register(AsyncWrapObject::New);
770
4395
  registry->Register(AsyncWrap::GetAsyncId);
771
4395
  registry->Register(AsyncWrap::AsyncReset);
772
4395
  registry->Register(AsyncWrap::GetProviderType);
773
4395
  registry->Register(PromiseWrap::GetAsyncId);
774
4395
  registry->Register(PromiseWrap::GetTriggerAsyncId);
775
4395
}
776
777
180806
AsyncWrap::AsyncWrap(Environment* env,
778
                     Local<Object> object,
779
                     ProviderType provider,
780
180806
                     double execution_async_id)
781
180806
    : AsyncWrap(env, object, provider, execution_async_id, false) {}
782
783
201977
AsyncWrap::AsyncWrap(Environment* env,
784
                     Local<Object> object,
785
                     ProviderType provider,
786
                     double execution_async_id,
787
201977
                     bool silent)
788
201977
    : AsyncWrap(env, object) {
789
201977
  CHECK_NE(provider, PROVIDER_NONE);
790
201977
  provider_type_ = provider;
791
792
  // Use AsyncReset() call to execute the init() callbacks.
793
201977
  AsyncReset(object, execution_async_id, silent);
794
201977
  init_hook_ran_ = true;
795
201977
}
796
797
AsyncWrap::AsyncWrap(Environment* env,
798
                     Local<Object> object,
799
                     ProviderType provider,
800
                     double execution_async_id,
801
                     double trigger_async_id)
802
    : AsyncWrap(env, object, provider, execution_async_id, true) {
803
  trigger_async_id_ = trigger_async_id;
804
}
805
806
205017
AsyncWrap::AsyncWrap(Environment* env, Local<Object> object)
807
205017
  : BaseObject(env, object) {
808
205017
}
809
810
// This method is necessary to work around one specific problem:
811
// Before the init() hook runs, if there is one, the BaseObject() constructor
812
// registers this object with the Environment for finalization and debugging
813
// purposes.
814
// If the Environment decides to inspect this object for debugging, it tries to
815
// call virtual methods on this object that are only (meaningfully) implemented
816
// by the subclasses of AsyncWrap.
817
// This could, with bad luck, happen during the AsyncWrap() constructor,
818
// because we run JS code as part of it and that in turn can lead to a heapdump
819
// being taken, either through the inspector or our programmatic API for it.
820
// The object being initialized is not fully constructed at that point, and
821
// in particular its virtual function table points to the AsyncWrap one
822
// (as the subclass constructor has not yet begun execution at that point).
823
// This means that the functions that are used for heap dump memory tracking
824
// are not yet available, and trying to call them would crash the process.
825
// We use this particular `IsDoneInitializing()` method to tell the Environment
826
// that such debugging methods are not yet available.
827
// This may be somewhat unreliable when it comes to future changes, because
828
// at this point it *only* protects AsyncWrap subclasses, and *only* for cases
829
// where heap dumps are being taken while the init() hook is on the call stack.
830
// For now, it seems like the best solution, though.
831
431202
bool AsyncWrap::IsDoneInitializing() const {
832
431202
  return init_hook_ran_;
833
}
834
835
408194
AsyncWrap::~AsyncWrap() {
836
204096
  EmitTraceEventDestroy();
837
204097
  EmitDestroy(true /* from gc */);
838
204101
}
839
840
209288
void AsyncWrap::EmitTraceEventDestroy() {
841













209288
  switch (provider_type()) {
842
  #define V(PROVIDER)                                                         \
843
    case PROVIDER_ ## PROVIDER:                                               \
844
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
845
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
846
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
847
      break;
848






















































418574
    NODE_ASYNC_PROVIDER_TYPES(V)
849
  #undef V
850
    default:
851
      UNREACHABLE();
852
  }
853
209287
}
854
855
271830
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
856

367881
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
857
96051
      !env->can_call_into_js()) {
858
176301
    return;
859
  }
860
861
95534
  if (env->destroy_async_id_list()->empty()) {
862
21980
    env->SetImmediate(&DestroyAsyncIdsCallback, CallbackFlags::kUnrefed);
863
  }
864
865
  // If the list gets very large empty it faster using a Microtask.
866
  // Microtasks can't be added in GC context therefore we use an
867
  // interrupt to get this Microtask scheduled as fast as possible.
868
95534
  if (env->destroy_async_id_list()->size() == 16384) {
869
2
    env->RequestInterrupt([](Environment* env) {
870
2
      env->isolate()->EnqueueMicrotask(
871
3
        [](void* arg) {
872
1
          DestroyAsyncIdsCallback(static_cast<Environment*>(arg));
873
4
        }, env);
874
2
      });
875
  }
876
877
95534
  env->destroy_async_id_list()->push_back(async_id);
878
}
879
880
// Generalized call for both the constructor and for handles that are pooled
881
// and reused over their lifetime. This way a new uid can be assigned when
882
// the resource is pulled out of the pool and put back into use.
883
207789
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
884
                           bool silent) {
885
207789
  CHECK_NE(provider_type(), PROVIDER_NONE);
886
887
207789
  if (async_id_ != kInvalidAsyncId) {
888
    // This instance was in use before, we have already emitted an init with
889
    // its previous async_id and need to emit a matching destroy for that
890
    // before generating a new async_id.
891
427
    EmitDestroy();
892
  }
893
894
  // Now we can assign a new async_id_ to this instance.
895
207790
  async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id()
896
                                                     : execution_async_id;
897
207790
  trigger_async_id_ = env()->get_default_trigger_async_id();
898
899
  {
900
415579
    HandleScope handle_scope(env()->isolate());
901
207790
    Local<Object> obj = object();
902
207790
    CHECK(!obj.IsEmpty());
903
207790
    if (resource != obj) {
904
17439
      USE(obj->Set(env()->context(), env()->resource_symbol(), resource));
905
    }
906
  }
907
908













207790
  switch (provider_type()) {
909
#define V(PROVIDER)                                                           \
910
    case PROVIDER_ ## PROVIDER:                                               \
911
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
912
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
913
        auto data = tracing::TracedValue::Create();                           \
914
        data->SetInteger("executionAsyncId",                                  \
915
                         static_cast<int64_t>(env()->execution_async_id()));  \
916
        data->SetInteger("triggerAsyncId",                                    \
917
                         static_cast<int64_t>(get_trigger_async_id()));       \
918
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
919
          TRACING_CATEGORY_NODE1(async_hooks),                                \
920
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
921
          "data", std::move(data));                                           \
922
        }                                                                     \
923
      break;
924

















































































50
    NODE_ASYNC_PROVIDER_TYPES(V)
925
#undef V
926
    default:
927
      UNREACHABLE();
928
  }
929
930
207790
  if (silent) return;
931
932
415512
  EmitAsyncInit(env(), resource,
933
207756
                env()->async_hooks()->provider_string(provider_type()),
934
207756
                async_id_, trigger_async_id_);
935
}
936
937
938
208306
void AsyncWrap::EmitAsyncInit(Environment* env,
939
                              Local<Object> object,
940
                              Local<String> type,
941
                              double async_id,
942
                              double trigger_async_id) {
943
208306
  CHECK(!object.IsEmpty());
944
208306
  CHECK(!type.IsEmpty());
945
208306
  AsyncHooks* async_hooks = env->async_hooks();
946
947
  // Nothing to execute, so can continue normally.
948
208306
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
949
173461
    return;
950
  }
951
952
69690
  HandleScope scope(env->isolate());
953
34845
  Local<Function> init_fn = env->async_hooks_init_function();
954
955
  Local<Value> argv[] = {
956
    Number::New(env->isolate(), async_id),
957
    type,
958
    Number::New(env->isolate(), trigger_async_id),
959
    object,
960
174225
  };
961
962
69690
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
963
104535
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
964
}
965
966
967
588547
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
968
                                          int argc,
969
                                          Local<Value>* argv) {
970
588547
  EmitTraceEventBefore();
971
972
588600
  ProviderType provider = provider_type();
973
588661
  async_context context { get_async_id(), get_trigger_async_id() };
974
  MaybeLocal<Value> ret = InternalMakeCallback(
975
588612
      env(), object(), object(), cb, argc, argv, context);
976
977
  // This is a static call with cached values because the `this` object may
978
  // no longer be alive at this point.
979
588542
  EmitTraceEventAfter(provider, context.async_id);
980
981
588529
  return ret;
982
}
983
984
std::string AsyncWrap::MemoryInfoName() const {
985
  return provider_names[provider_type()];
986
}
987
988
std::string AsyncWrap::diagnostic_name() const {
989
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
990
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
991
}
992
993
249
Local<Object> AsyncWrap::GetOwner() {
994
249
  return GetOwner(env(), object());
995
}
996
997
249
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
998
249
  EscapableHandleScope handle_scope(env->isolate());
999
249
  CHECK(!obj.IsEmpty());
1000
1001
498
  TryCatchScope ignore_exceptions(env);
1002
  while (true) {
1003
    Local<Value> owner;
1004
1936
    if (!obj->Get(env->context(),
1005

3388
                  env->owner_symbol()).ToLocal(&owner) ||
1006
484
        !owner->IsObject()) {
1007
498
      return handle_scope.Escape(obj);
1008
    }
1009
1010
235
    obj = owner.As<Object>();
1011
235
  }
1012
}
1013
1014
}  // namespace node
1015
1016
4464
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)
1017

17790
NODE_MODULE_EXTERNAL_REFERENCE(async_wrap,
1018
                               node::AsyncWrap::RegisterExternalReferences)