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: 401 477 84.1 %
Date: 2021-06-01 04:11:54 Branches: 840 1489 56.4 %

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::Undefined;
58
using v8::Value;
59
using v8::WeakCallbackInfo;
60
using v8::WeakCallbackType;
61
62
using TryCatchScope = node::errors::TryCatchScope;
63
64
namespace node {
65
66
static const char* const provider_names[] = {
67
#define V(PROVIDER)                                                           \
68
  #PROVIDER,
69
  NODE_ASYNC_PROVIDER_TYPES(V)
70
#undef V
71
};
72
73
22970
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) {
74
22970
  Local<Function> fn = env->async_hooks_destroy_function();
75
76
45938
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
77
78

22970
  do {
79
45942
    std::vector<double> destroy_async_id_list;
80
22972
    destroy_async_id_list.swap(*env->destroy_async_id_list());
81
22972
    if (!env->can_call_into_js()) return;
82

135057
    for (auto async_id : destroy_async_id_list) {
83
      // Want each callback to be cleaned up after itself, instead of cleaning
84
      // them all up after the while() loop completes.
85
224172
      HandleScope scope(env->isolate());
86
112087
      Local<Value> async_id_value = Number::New(env->isolate(), async_id);
87
      MaybeLocal<Value> ret = fn->Call(
88
336261
          env->context(), Undefined(env->isolate()), 1, &async_id_value);
89
90
112085
      if (ret.IsEmpty())
91
        return;
92
    }
93
22970
  } while (!env->destroy_async_id_list()->empty());
94
}
95
96
375661
void Emit(Environment* env, double async_id, AsyncHooks::Fields type,
97
          Local<Function> fn) {
98
375661
  AsyncHooks* async_hooks = env->async_hooks();
99
100

375661
  if (async_hooks->fields()[type] == 0 || !env->can_call_into_js())
101
372660
    return;
102
103
6002
  HandleScope handle_scope(env->isolate());
104
3001
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
105
6002
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
106
9003
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
107
}
108
109
110
22541
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
111
22541
  Emit(env, async_id, AsyncHooks::kPromiseResolve,
112
22541
       env->async_hooks_promise_resolve_function());
113
22541
}
114
115
116
349704
void AsyncWrap::EmitTraceEventBefore() {
117














349704
  switch (provider_type()) {
118
#define V(PROVIDER)                                                           \
119
    case PROVIDER_ ## PROVIDER:                                               \
120
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(                                      \
121
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
122
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
123
      break;
124






















































699464
    NODE_ASYNC_PROVIDER_TYPES(V)
125
#undef V
126
    default:
127
      UNREACHABLE();
128
  }
129
349732
}
130
131
132
176567
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
133
176567
  Emit(env, async_id, AsyncHooks::kBefore,
134
176567
       env->async_hooks_before_function());
135
176567
}
136
137
138
349910
void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) {
139














349910
  switch (type) {
140
#define V(PROVIDER)                                                           \
141
    case PROVIDER_ ## PROVIDER:                                               \
142
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
143
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
144
        #PROVIDER "_CALLBACK", static_cast<int64_t>(async_id));               \
145
      break;
146






















































699816
    NODE_ASYNC_PROVIDER_TYPES(V)
147
#undef V
148
    default:
149
      UNREACHABLE();
150
  }
151
349908
}
152
153
154
176553
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
155
  // If the user's callback failed then the after() hooks will be called at the
156
  // end of _fatalException().
157
176553
  Emit(env, async_id, AsyncHooks::kAfter,
158
176553
       env->async_hooks_after_function());
159
176553
}
160
161
// TODO(addaleax): Remove once we're on C++17.
162
constexpr double AsyncWrap::kInvalidAsyncId;
163
164
262
static Maybe<double> GetAssignedPromiseAsyncId(Environment* env,
165
                                               Local<Promise> promise,
166
                                               Local<Value> id_symbol) {
167
  Local<Value> maybe_async_id;
168

786
  if (!promise->Get(env->context(), id_symbol).ToLocal(&maybe_async_id)) {
169
    return Nothing<double>();
170
  }
171
262
  return maybe_async_id->IsNumber()
172
      ? maybe_async_id->NumberValue(env->context())
173
262
      : Just(AsyncWrap::kInvalidAsyncId);
174
}
175
176
43246
class PromiseWrap : public AsyncWrap {
177
 public:
178
22525
  PromiseWrap(Environment* env, Local<Object> object, bool silent)
179
22525
      : AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) {
180
22525
    MakeWeak();
181
22525
  }
182
183
  PromiseWrap(Environment* env, Local<Object> object, double asyncId,
184
    double triggerAsyncId)
185
      : AsyncWrap(env, object, PROVIDER_PROMISE, asyncId, triggerAsyncId) {
186
    MakeWeak();
187
  }
188
189
5
  SET_NO_MEMORY_INFO()
190
5
  SET_MEMORY_INFO_NAME(PromiseWrap)
191
5
  SET_SELF_SIZE(PromiseWrap)
192
193
  static PromiseWrap* New(Environment* env,
194
                          Local<Promise> promise,
195
                          bool silent);
196
  static void GetAsyncId(Local<Name> property,
197
                         const PropertyCallbackInfo<Value>& args);
198
  static void GetTriggerAsyncId(Local<Name> property,
199
                                const PropertyCallbackInfo<Value>& args);
200
201
  static void Initialize(Environment* env);
202
};
203
204
22525
PromiseWrap* PromiseWrap::New(Environment* env,
205
                              Local<Promise> promise,
206
                              bool silent) {
207
22525
  Local<Context> context = env->context();
208
209
  Local<Object> obj;
210
67575
  if (!env->promise_wrap_template()->NewInstance(context).ToLocal(&obj))
211
    return nullptr;
212
213
45050
  CHECK_NULL(promise->GetAlignedPointerFromInternalField(0));
214
22525
  promise->SetInternalField(0, obj);
215
216
  // Skip for init events
217
22525
  if (silent) {
218
    double async_id;
219
    double trigger_async_id;
220
393
    if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol())
221
131
            .To(&async_id)) return nullptr;
222
393
    if (!GetAssignedPromiseAsyncId(env, promise, env->trigger_async_id_symbol())
223
131
            .To(&trigger_async_id)) return nullptr;
224
225

131
    if (async_id != AsyncWrap::kInvalidAsyncId &&
226
        trigger_async_id != AsyncWrap::kInvalidAsyncId) {
227
      return new PromiseWrap(
228
          env, obj, async_id, trigger_async_id);
229
    }
230
  }
231
232
22525
  return new PromiseWrap(env, obj, silent);
233
}
234
235
19
void PromiseWrap::GetAsyncId(Local<Name> property,
236
                             const PropertyCallbackInfo<Value>& info) {
237
19
  Isolate* isolate = info.GetIsolate();
238
38
  HandleScope scope(isolate);
239
240
19
  PromiseWrap* wrap = Unwrap<PromiseWrap>(info.Holder());
241
19
  double value = wrap->get_async_id();
242
243
57
  info.GetReturnValue().Set(Number::New(isolate, value));
244
19
}
245
246
19
void PromiseWrap::GetTriggerAsyncId(Local<Name> property,
247
                                    const PropertyCallbackInfo<Value>& info) {
248
19
  Isolate* isolate = info.GetIsolate();
249
38
  HandleScope scope(isolate);
250
251
19
  PromiseWrap* wrap = Unwrap<PromiseWrap>(info.Holder());
252
19
  double value = wrap->get_trigger_async_id();
253
254
57
  info.GetReturnValue().Set(Number::New(isolate, value));
255
19
}
256
257
464
void PromiseWrap::Initialize(Environment* env) {
258
464
  Isolate* isolate = env->isolate();
259
928
  HandleScope scope(isolate);
260
261
464
  Local<FunctionTemplate> ctor = FunctionTemplate::New(isolate);
262
928
  ctor->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "PromiseWrap"));
263
264
464
  Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
265
464
  env->set_promise_wrap_template(promise_wrap_template);
266
267
464
  promise_wrap_template->SetInternalFieldCount(
268
464
      PromiseWrap::kInternalFieldCount);
269
270
1392
  promise_wrap_template->SetAccessor(
271
      env->async_id_symbol(),
272
464
      PromiseWrap::GetAsyncId);
273
274
1392
  promise_wrap_template->SetAccessor(
275
      env->trigger_async_id_symbol(),
276
464
      PromiseWrap::GetTriggerAsyncId);
277
464
}
278
279
79005
static PromiseWrap* extractPromiseWrap(Local<Promise> promise) {
280
  // This check is imperfect. If the internal field is set, it should
281
  // be an object. If it's not, we just ignore it. Ideally v8 would
282
  // have had GetInternalField returning a MaybeLocal but this works
283
  // for now.
284
158010
  Local<Value> obj = promise->GetInternalField(0);
285
135485
  return obj->IsObject() ? Unwrap<PromiseWrap>(obj.As<Object>()) : nullptr;
286
}
287
288
static uint16_t ToAsyncHooksType(PromiseHookType type) {
289
  switch (type) {
290
    case PromiseHookType::kInit:    return AsyncHooks::kInit;
291
    case PromiseHookType::kBefore:  return AsyncHooks::kBefore;
292
    case PromiseHookType::kAfter:   return AsyncHooks::kAfter;
293
    case PromiseHookType::kResolve: return AsyncHooks::kPromiseResolve;
294
  }
295
  UNREACHABLE();
296
}
297
298
// Simplified JavaScript hook fast-path for when there is no destroy hook
299
static void FastPromiseHook(PromiseHookType type, Local<Promise> promise,
300
                            Local<Value> parent) {
301
  Local<Context> context = promise->GetCreationContext().ToLocalChecked();
302
  Environment* env = Environment::GetCurrent(context);
303
  if (env == nullptr) return;
304
305
  if (type == PromiseHookType::kBefore &&
306
      env->async_hooks()->fields()[AsyncHooks::kBefore] == 0) {
307
    double async_id;
308
    double trigger_async_id;
309
    if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol())
310
            .To(&async_id)) return;
311
    if (!GetAssignedPromiseAsyncId(env, promise, env->trigger_async_id_symbol())
312
            .To(&trigger_async_id)) return;
313
314
    if (async_id != AsyncWrap::kInvalidAsyncId &&
315
        trigger_async_id != AsyncWrap::kInvalidAsyncId) {
316
      env->async_hooks()->push_async_context(
317
          async_id, trigger_async_id, promise);
318
      return;
319
    }
320
  }
321
322
  if (type == PromiseHookType::kAfter &&
323
      env->async_hooks()->fields()[AsyncHooks::kAfter] == 0) {
324
    double async_id;
325
    if (!GetAssignedPromiseAsyncId(env, promise, env->async_id_symbol())
326
            .To(&async_id)) return;
327
328
    if (async_id != AsyncWrap::kInvalidAsyncId) {
329
      if (env->execution_async_id() == async_id) {
330
        // This condition might not be true if async_hooks was enabled during
331
        // the promise callback execution.
332
        env->async_hooks()->pop_async_context(async_id);
333
      }
334
      return;
335
    }
336
  }
337
338
  if (type == PromiseHookType::kResolve &&
339
      env->async_hooks()->fields()[AsyncHooks::kPromiseResolve] == 0) {
340
    return;
341
  }
342
343
  // Getting up to this point means either init type or
344
  // that there are active hooks of another type.
345
  // In both cases fast-path JS hook should be called.
346
347
  Local<Value> argv[] = {
348
    Integer::New(env->isolate(), ToAsyncHooksType(type)),
349
    promise,
350
    parent
351
  };
352
353
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
354
  Local<Function> promise_hook = env->promise_hook_handler();
355
  USE(promise_hook->Call(context, Undefined(env->isolate()), 3, argv));
356
}
357
358
67709
static void FullPromiseHook(PromiseHookType type, Local<Promise> promise,
359
                            Local<Value> parent) {
360
135418
  Local<Context> context = promise->GetCreationContext().ToLocalChecked();
361
362
67709
  Environment* env = Environment::GetCurrent(context);
363
67709
  if (env == nullptr) return;
364
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
365
135418
                              "EnvPromiseHook", env);
366
367
67709
  PromiseWrap* wrap = extractPromiseWrap(promise);
368

67709
  if (type == PromiseHookType::kInit || wrap == nullptr) {
369
22501
    bool silent = type != PromiseHookType::kInit;
370
371
    // set parent promise's async Id as this promise's triggerAsyncId
372
22501
    if (parent->IsPromise()) {
373
      // parent promise exists, current promise
374
      // is a chained promise, so we set parent promise's id as
375
      // current promise's triggerAsyncId
376
11296
      Local<Promise> parent_promise = parent.As<Promise>();
377
11296
      PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise);
378
11296
      if (parent_wrap == nullptr) {
379
24
        parent_wrap = PromiseWrap::New(env, parent_promise, true);
380
24
        if (parent_wrap == nullptr) return;
381
      }
382
383
22592
      AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap);
384
11296
      wrap = PromiseWrap::New(env, promise, silent);
385
    } else {
386
11205
      wrap = PromiseWrap::New(env, promise, silent);
387
    }
388
  }
389
390
67709
  if (wrap == nullptr) return;
391
392
67709
  if (type == PromiseHookType::kBefore) {
393
11388
    env->async_hooks()->push_async_context(wrap->get_async_id(),
394
11388
      wrap->get_trigger_async_id(), wrap->object());
395
11388
    wrap->EmitTraceEventBefore();
396
11388
    AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id());
397
56321
  } else if (type == PromiseHookType::kAfter) {
398
11386
    wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id());
399
11386
    AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id());
400
11386
    if (env->execution_async_id() == wrap->get_async_id()) {
401
      // This condition might not be true if async_hooks was enabled during
402
      // the promise callback execution.
403
      // Popping it off the stack can be skipped in that case, because it is
404
      // known that it would correspond to exactly one call with
405
      // PromiseHookType::kBefore that was not witnessed by the PromiseHook.
406
11386
      env->async_hooks()->pop_async_context(wrap->get_async_id());
407
    }
408
44935
  } else if (type == PromiseHookType::kResolve) {
409
22541
    AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id());
410
  }
411
}
412
413
464
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
414
464
  Environment* env = Environment::GetCurrent(args);
415
416
928
  CHECK(args[0]->IsObject());
417
418
  // All of init, before, after, destroy, and promise_resolve are supplied by
419
  // async_hooks internally, so this should only ever be called once. At which
420
  // time all the functions should be set. Detect this by checking if
421
  // init !IsEmpty().
422
928
  CHECK(env->async_hooks_init_function().IsEmpty());
423
424
928
  Local<Object> fn_obj = args[0].As<Object>();
425
426
#define SET_HOOK_FN(name)                                                      \
427
  do {                                                                         \
428
    Local<Value> v =                                                           \
429
        fn_obj->Get(env->context(),                                            \
430
                    FIXED_ONE_BYTE_STRING(env->isolate(), #name))              \
431
            .ToLocalChecked();                                                 \
432
    CHECK(v->IsFunction());                                                    \
433
    env->set_async_hooks_##name##_function(v.As<Function>());                  \
434
  } while (0)
435
436
2784
  SET_HOOK_FN(init);
437
2784
  SET_HOOK_FN(before);
438
2784
  SET_HOOK_FN(after);
439
2784
  SET_HOOK_FN(destroy);
440
2784
  SET_HOOK_FN(promise_resolve);
441
#undef SET_HOOK_FN
442
464
}
443
444
2749
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
445
2749
  Environment* env = Environment::GetCurrent(args);
446
447
5498
  if (args[0]->IsFunction()) {
448
    env->set_promise_hook_handler(args[0].As<Function>());
449
    args.GetIsolate()->SetPromiseHook(FastPromiseHook);
450
  } else {
451
2749
    args.GetIsolate()->SetPromiseHook(FullPromiseHook);
452
  }
453
2749
}
454
455
238
static void SetPromiseHooks(const FunctionCallbackInfo<Value>& args) {
456
238
  Environment* env = Environment::GetCurrent(args);
457
238
  Local<Context> ctx = env->context();
458


1628
  ctx->SetPromiseHooks(
459
877
    args[0]->IsFunction() ? args[0].As<Function>() : Local<Function>(),
460
888
    args[1]->IsFunction() ? args[1].As<Function>() : Local<Function>(),
461
888
    args[2]->IsFunction() ? args[2].As<Function>() : Local<Function>(),
462
955
    args[3]->IsFunction() ? args[3].As<Function>() : Local<Function>());
463
238
}
464
465
64
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
466
64
  Environment* env = Environment::GetCurrent(args);
467
64
  env->set_promise_hook_handler(Local<Function>());
468
469
  // The per-Isolate API provides no way of knowing whether there are multiple
470
  // users of the PromiseHook. That hopefully goes away when V8 introduces
471
  // a per-context API.
472
64
  args.GetIsolate()->SetPromiseHook(nullptr);
473
64
}
474
475
476
14931
class DestroyParam {
477
 public:
478
  double asyncId;
479
  Environment* env;
480
  Global<Object> target;
481
  Global<Object> propBag;
482
};
483
484
11
static void DestroyParamCleanupHook(void* ptr) {
485
11
  delete static_cast<DestroyParam*>(ptr);
486
11
}
487
488
2477
void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) {
489
4954
  HandleScope scope(info.GetIsolate());
490
491
4954
  std::unique_ptr<DestroyParam> p{info.GetParameter()};
492
  Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(),
493
4954
                                                      p->propBag);
494
  Local<Value> val;
495
496
2477
  p->env->RemoveCleanupHook(DestroyParamCleanupHook, p.get());
497
498
9908
  if (!prop_bag->Get(p->env->context(), p->env->destroyed_string())
499
2477
        .ToLocal(&val)) {
500
    return;
501
  }
502
503
2477
  if (val->IsFalse()) {
504
2472
    AsyncWrap::EmitDestroy(p->env, p->asyncId);
505
  }
506
  // unique_ptr goes out of scope here and pointer is deleted.
507
}
508
509
510
2489
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) {
511
4978
  CHECK(args[0]->IsObject());
512
4978
  CHECK(args[1]->IsNumber());
513
4978
  CHECK(args[2]->IsObject());
514
515
2489
  Isolate* isolate = args.GetIsolate();
516
2489
  DestroyParam* p = new DestroyParam();
517
7467
  p->asyncId = args[1].As<Number>()->Value();
518
2489
  p->env = Environment::GetCurrent(args);
519
7467
  p->target.Reset(isolate, args[0].As<Object>());
520
7467
  p->propBag.Reset(isolate, args[2].As<Object>());
521
2489
  p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter);
522
2489
  p->env->AddCleanupHook(DestroyParamCleanupHook, p);
523
2489
}
524
525
96271
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
526
  AsyncWrap* wrap;
527
192542
  args.GetReturnValue().Set(kInvalidAsyncId);
528
96271
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
529
288750
  args.GetReturnValue().Set(wrap->get_async_id());
530
}
531
532
533
10
void AsyncWrap::PushAsyncContext(const FunctionCallbackInfo<Value>& args) {
534
10
  Environment* env = Environment::GetCurrent(args);
535
  // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail
536
  // then the checks in push_async_ids() and pop_async_id() will.
537
40
  double async_id = args[0]->NumberValue(env->context()).FromJust();
538
40
  double trigger_async_id = args[1]->NumberValue(env->context()).FromJust();
539
10
  env->async_hooks()->push_async_context(async_id, trigger_async_id, {});
540
10
}
541
542
543
3
void AsyncWrap::PopAsyncContext(const FunctionCallbackInfo<Value>& args) {
544
3
  Environment* env = Environment::GetCurrent(args);
545
12
  double async_id = args[0]->NumberValue(env->context()).FromJust();
546
3
  args.GetReturnValue().Set(env->async_hooks()->pop_async_context(async_id));
547
}
548
549
550
239
void AsyncWrap::ExecutionAsyncResource(
551
    const FunctionCallbackInfo<Value>& args) {
552
239
  Environment* env = Environment::GetCurrent(args);
553
  uint32_t index;
554
956
  if (!args[0]->Uint32Value(env->context()).To(&index)) return;
555
717
  args.GetReturnValue().Set(
556
      env->async_hooks()->native_execution_async_resource(index));
557
}
558
559
560
1232
void AsyncWrap::ClearAsyncIdStack(const FunctionCallbackInfo<Value>& args) {
561
1232
  Environment* env = Environment::GetCurrent(args);
562
1232
  env->async_hooks()->clear_async_id_stack();
563
1232
}
564
565
566
283
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) {
567
566
  CHECK(args[0]->IsObject());
568
569
  AsyncWrap* wrap;
570
283
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
571
572
566
  Local<Object> resource = args[0].As<Object>();
573
  double execution_async_id =
574
566
      args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId;
575
283
  wrap->AsyncReset(resource, execution_async_id);
576
}
577
578
579
283
void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) {
580
  AsyncWrap* wrap;
581
566
  args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE);
582
283
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
583
849
  args.GetReturnValue().Set(wrap->provider_type());
584
}
585
586
587
220810
void AsyncWrap::EmitDestroy(bool from_gc) {
588
220810
  AsyncWrap::EmitDestroy(env(), async_id_);
589
  // Ensure no double destroy is emitted via AsyncReset().
590
220815
  async_id_ = kInvalidAsyncId;
591
592

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














220333
  switch (provider_type()) {
813
  #define V(PROVIDER)                                                         \
814
    case PROVIDER_ ## PROVIDER:                                               \
815
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
816
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
817
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
818
      break;
819

























































440666
    NODE_ASYNC_PROVIDER_TYPES(V)
820
  #undef V
821
    default:
822
      UNREACHABLE();
823
  }
824
220333
}
825
826
295676
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
827

408586
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
828
112910
      !env->can_call_into_js()) {
829
183107
    return;
830
  }
831
832
112573
  if (env->destroy_async_id_list()->empty()) {
833
23014
    env->SetImmediate(&DestroyAsyncIdsCallback, CallbackFlags::kUnrefed);
834
  }
835
836
  // If the list gets very large empty it faster using a Microtask.
837
  // Microtasks can't be added in GC context therefore we use an
838
  // interrupt to get this Microtask scheduled as fast as possible.
839
112573
  if (env->destroy_async_id_list()->size() == 16384) {
840
2
    env->RequestInterrupt([](Environment* env) {
841
4
      env->context()->GetMicrotaskQueue()->EnqueueMicrotask(
842
        env->isolate(),
843
3
        [](void* arg) {
844
1
          DestroyAsyncIdsCallback(static_cast<Environment*>(arg));
845
5
        }, env);
846
2
      });
847
  }
848
849
112573
  env->destroy_async_id_list()->push_back(async_id);
850
}
851
852
// Generalized call for both the constructor and for handles that are pooled
853
// and reused over their lifetime. This way a new uid can be assigned when
854
// the resource is pulled out of the pool and put back into use.
855
219322
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
856
                           bool silent) {
857
219322
  CHECK_NE(provider_type(), PROVIDER_NONE);
858
859
219322
  if (async_id_ != kInvalidAsyncId) {
860
    // This instance was in use before, we have already emitted an init with
861
    // its previous async_id and need to emit a matching destroy for that
862
    // before generating a new async_id.
863
477
    EmitDestroy();
864
  }
865
866
  // Now we can assign a new async_id_ to this instance.
867
219322
  async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id()
868
                                                     : execution_async_id;
869
219322
  trigger_async_id_ = env()->get_default_trigger_async_id();
870
871
  {
872
438644
    HandleScope handle_scope(env()->isolate());
873
219322
    Local<Object> obj = object();
874
219322
    CHECK(!obj.IsEmpty());
875
219322
    if (resource != obj) {
876
19806
      USE(obj->Set(env()->context(), env()->resource_symbol(), resource));
877
    }
878
  }
879
880














219322
  switch (provider_type()) {
881
#define V(PROVIDER)                                                           \
882
    case PROVIDER_ ## PROVIDER:                                               \
883
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
884
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
885
        auto data = tracing::TracedValue::Create();                           \
886
        data->SetInteger("executionAsyncId",                                  \
887
                         static_cast<int64_t>(env()->execution_async_id()));  \
888
        data->SetInteger("triggerAsyncId",                                    \
889
                         static_cast<int64_t>(get_trigger_async_id()));       \
890
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
891
          TRACING_CATEGORY_NODE1(async_hooks),                                \
892
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
893
          "data", std::move(data));                                           \
894
        }                                                                     \
895
      break;
896























































































52
    NODE_ASYNC_PROVIDER_TYPES(V)
897
#undef V
898
    default:
899
      UNREACHABLE();
900
  }
901
902
219322
  if (silent) return;
903
904
438382
  EmitAsyncInit(env(), resource,
905
219191
                env()->async_hooks()->provider_string(provider_type()),
906
219191
                async_id_, trigger_async_id_);
907
}
908
909
910
219744
void AsyncWrap::EmitAsyncInit(Environment* env,
911
                              Local<Object> object,
912
                              Local<String> type,
913
                              double async_id,
914
                              double trigger_async_id) {
915
219744
  CHECK(!object.IsEmpty());
916
219744
  CHECK(!type.IsEmpty());
917
219744
  AsyncHooks* async_hooks = env->async_hooks();
918
919
  // Nothing to execute, so can continue normally.
920
219744
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
921
180200
    return;
922
  }
923
924
79088
  HandleScope scope(env->isolate());
925
39544
  Local<Function> init_fn = env->async_hooks_init_function();
926
927
  Local<Value> argv[] = {
928
    Number::New(env->isolate(), async_id),
929
    type,
930
    Number::New(env->isolate(), trigger_async_id),
931
    object,
932
197720
  };
933
934
79088
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
935
118632
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
936
}
937
938
939
338348
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
940
                                          int argc,
941
                                          Local<Value>* argv) {
942
338348
  EmitTraceEventBefore();
943
944
338454
  ProviderType provider = provider_type();
945
338667
  async_context context { get_async_id(), get_trigger_async_id() };
946
  MaybeLocal<Value> ret = InternalMakeCallback(
947
338665
      env(), object(), object(), cb, argc, argv, context);
948
949
  // This is a static call with cached values because the `this` object may
950
  // no longer be alive at this point.
951
338524
  EmitTraceEventAfter(provider, context.async_id);
952
953
338526
  return ret;
954
}
955
956
std::string AsyncWrap::MemoryInfoName() const {
957
  return provider_names[provider_type()];
958
}
959
960
std::string AsyncWrap::diagnostic_name() const {
961
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
962
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
963
}
964
965
939
Local<Object> AsyncWrap::GetOwner() {
966
939
  return GetOwner(env(), object());
967
}
968
969
939
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
970
939
  EscapableHandleScope handle_scope(env->isolate());
971
939
  CHECK(!obj.IsEmpty());
972
973
1878
  TryCatchScope ignore_exceptions(env);
974
  while (true) {
975
    Local<Value> owner;
976
7456
    if (!obj->Get(env->context(),
977

13048
                  env->owner_symbol()).ToLocal(&owner) ||
978
1864
        !owner->IsObject()) {
979
1878
      return handle_scope.Escape(obj);
980
    }
981
982
925
    obj = owner.As<Object>();
983
925
  }
984
}
985
986
}  // namespace node
987
988
4832
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)
989

19294
NODE_MODULE_EXTERNAL_REFERENCE(async_wrap,
990
                               node::AsyncWrap::RegisterExternalReferences)