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: 418 442 94.6 %
Date: 2020-07-19 22:14:24 Branches: 714 1361 52.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::Local;
43
using v8::MaybeLocal;
44
using v8::Name;
45
using v8::Number;
46
using v8::Object;
47
using v8::ObjectTemplate;
48
using v8::Promise;
49
using v8::PromiseHookType;
50
using v8::PropertyAttribute;
51
using v8::PropertyCallbackInfo;
52
using v8::ReadOnly;
53
using v8::String;
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
198
struct AsyncWrapObject : public AsyncWrap {
73
99
  static inline void New(const FunctionCallbackInfo<Value>& args) {
74
99
    Environment* env = Environment::GetCurrent(args);
75
99
    CHECK(args.IsConstructCall());
76
198
    CHECK(env->async_wrap_object_ctor_template()->HasInstance(args.This()));
77
198
    CHECK(args[0]->IsUint32());
78
297
    auto type = static_cast<ProviderType>(args[0].As<Uint32>()->Value());
79
99
    new AsyncWrapObject(env, args.This(), type);
80
99
  }
81
82
99
  inline AsyncWrapObject(Environment* env, Local<Object> object,
83
99
                         ProviderType type) : AsyncWrap(env, object, type) {}
84
85
384
  static Local<FunctionTemplate> GetConstructorTemplate(Environment* env) {
86
384
    Local<FunctionTemplate> tmpl = env->async_wrap_object_ctor_template();
87
384
    if (tmpl.IsEmpty()) {
88
384
      tmpl = env->NewFunctionTemplate(AsyncWrapObject::New);
89
768
      tmpl->SetClassName(
90
384
          FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
91
768
      tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
92
1152
      tmpl->InstanceTemplate()->SetInternalFieldCount(
93
384
          AsyncWrapObject::kInternalFieldCount);
94
384
      env->set_async_wrap_object_ctor_template(tmpl);
95
    }
96
384
    return tmpl;
97
  }
98
99
3
  SET_NO_MEMORY_INFO()
100
3
  SET_MEMORY_INFO_NAME(AsyncWrapObject)
101
3
  SET_SELF_SIZE(AsyncWrapObject)
102
};
103
104
22310
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) {
105
22310
  Local<Function> fn = env->async_hooks_destroy_function();
106
107
44620
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
108
109

22312
  do {
110
44624
    std::vector<double> destroy_async_id_list;
111
22312
    destroy_async_id_list.swap(*env->destroy_async_id_list());
112
22312
    if (!env->can_call_into_js()) return;
113

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

314287
  if (async_hooks->fields()[type] == 0 || !env->can_call_into_js())
132
312960
    return;
133
134
2654
  HandleScope handle_scope(env->isolate());
135
1327
  Local<Value> async_id_value = Number::New(env->isolate(), async_id);
136
2654
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
137
3981
  USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value));
138
}
139
140
141
1089
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) {
142
1089
  Emit(env, async_id, AsyncHooks::kPromiseResolve,
143
1089
       env->async_hooks_promise_resolve_function());
144
1089
}
145
146
147
657156
void AsyncWrap::EmitTraceEventBefore() {
148













657156
  switch (provider_type()) {
149
#define V(PROVIDER)                                                           \
150
    case PROVIDER_ ## PROVIDER:                                               \
151
      TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(                                      \
152
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
153
        #PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id()));         \
154
      break;
155






















































1314328
    NODE_ASYNC_PROVIDER_TYPES(V)
156
#undef V
157
    default:
158
      UNREACHABLE();
159
  }
160
657164
}
161
162
163
156605
void AsyncWrap::EmitBefore(Environment* env, double async_id) {
164
156605
  Emit(env, async_id, AsyncHooks::kBefore,
165
156605
       env->async_hooks_before_function());
166
156605
}
167
168
169
657196
void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) {
170













657196
  switch (type) {
171
#define V(PROVIDER)                                                           \
172
    case PROVIDER_ ## PROVIDER:                                               \
173
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
174
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
175
        #PROVIDER "_CALLBACK", static_cast<int64_t>(async_id));               \
176
      break;
177






















































1314394
    NODE_ASYNC_PROVIDER_TYPES(V)
178
#undef V
179
    default:
180
      UNREACHABLE();
181
  }
182
657197
}
183
184
185
156593
void AsyncWrap::EmitAfter(Environment* env, double async_id) {
186
  // If the user's callback failed then the after() hooks will be called at the
187
  // end of _fatalException().
188
156593
  Emit(env, async_id, AsyncHooks::kAfter,
189
156593
       env->async_hooks_after_function());
190
156593
}
191
192
1966
class PromiseWrap : public AsyncWrap {
193
 public:
194
1119
  PromiseWrap(Environment* env, Local<Object> object, bool silent)
195
1119
      : AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) {
196
1119
    MakeWeak();
197
1119
  }
198
199
  PromiseWrap(Environment* env, Local<Object> object, double asyncId,
200
    double triggerAsyncId)
201
      : AsyncWrap(env, object, PROVIDER_PROMISE, asyncId, triggerAsyncId) {
202
    MakeWeak();
203
  }
204
205
5
  SET_NO_MEMORY_INFO()
206
5
  SET_MEMORY_INFO_NAME(PromiseWrap)
207
5
  SET_SELF_SIZE(PromiseWrap)
208
209
  static PromiseWrap* New(Environment* env,
210
                          Local<Promise> promise,
211
                          bool silent);
212
  static void GetAsyncId(Local<Name> property,
213
                         const PropertyCallbackInfo<Value>& args);
214
  static void GetTriggerAsyncId(Local<Name> property,
215
                                const PropertyCallbackInfo<Value>& args);
216
217
  static void Initialize(Environment* env);
218
};
219
220
1119
PromiseWrap* PromiseWrap::New(Environment* env,
221
                              Local<Promise> promise,
222
                              bool silent) {
223
1119
  Local<Context> context = env->context();
224
225
  Local<Object> obj;
226
3357
  if (!env->promise_wrap_template()->NewInstance(context).ToLocal(&obj))
227
    return nullptr;
228
229
2238
  CHECK_NULL(promise->GetAlignedPointerFromInternalField(0));
230
1119
  promise->SetInternalField(0, obj);
231
232
  // Skip for init events
233
1119
  if (silent) {
234
    Local<Value> maybeAsyncId = promise
235
93
        ->Get(context, env->async_id_symbol())
236
31
        .ToLocalChecked();
237
238
    Local<Value> maybeTriggerAsyncId = promise
239
93
        ->Get(context, env->trigger_async_id_symbol())
240
31
        .ToLocalChecked();
241
242

31
    if (maybeAsyncId->IsNumber() && maybeTriggerAsyncId->IsNumber()) {
243
      double asyncId = maybeAsyncId->NumberValue(context).ToChecked();
244
      double triggerAsyncId = maybeTriggerAsyncId->NumberValue(context)
245
          .ToChecked();
246
      return new PromiseWrap(env, obj, asyncId, triggerAsyncId);
247
    }
248
  }
249
250
1119
  return new PromiseWrap(env, obj, silent);
251
}
252
253
7
void PromiseWrap::GetAsyncId(Local<Name> property,
254
                             const PropertyCallbackInfo<Value>& info) {
255
7
  Isolate* isolate = info.GetIsolate();
256
14
  HandleScope scope(isolate);
257
258
7
  PromiseWrap* wrap = Unwrap<PromiseWrap>(info.Holder());
259
7
  double value = wrap->get_async_id();
260
261
21
  info.GetReturnValue().Set(Number::New(isolate, value));
262
7
}
263
264
7
void PromiseWrap::GetTriggerAsyncId(Local<Name> property,
265
                                    const PropertyCallbackInfo<Value>& info) {
266
7
  Isolate* isolate = info.GetIsolate();
267
14
  HandleScope scope(isolate);
268
269
7
  PromiseWrap* wrap = Unwrap<PromiseWrap>(info.Holder());
270
7
  double value = wrap->get_trigger_async_id();
271
272
21
  info.GetReturnValue().Set(Number::New(isolate, value));
273
7
}
274
275
384
void PromiseWrap::Initialize(Environment* env) {
276
384
  Isolate* isolate = env->isolate();
277
768
  HandleScope scope(isolate);
278
279
384
  Local<FunctionTemplate> ctor = FunctionTemplate::New(isolate);
280
768
  ctor->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "PromiseWrap"));
281
282
384
  Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
283
384
  env->set_promise_wrap_template(promise_wrap_template);
284
285
384
  promise_wrap_template->SetInternalFieldCount(
286
384
      PromiseWrap::kInternalFieldCount);
287
288
1152
  promise_wrap_template->SetAccessor(
289
      env->async_id_symbol(),
290
384
      PromiseWrap::GetAsyncId);
291
292
1152
  promise_wrap_template->SetAccessor(
293
      env->trigger_async_id_symbol(),
294
384
      PromiseWrap::GetTriggerAsyncId);
295
384
}
296
297
3947
static PromiseWrap* extractPromiseWrap(Local<Promise> promise) {
298
  // This check is imperfect. If the internal field is set, it should
299
  // be an object. If it's not, we just ignore it. Ideally v8 would
300
  // have had GetInternalField returning a MaybeLocal but this works
301
  // for now.
302
7894
  Local<Value> obj = promise->GetInternalField(0);
303
6775
  return obj->IsObject() ? Unwrap<PromiseWrap>(obj.As<Object>()) : nullptr;
304
}
305
306
299
static uint16_t ToAsyncHooksType(PromiseHookType type) {
307

299
  switch (type) {
308
100
    case PromiseHookType::kInit:    return AsyncHooks::kInit;
309
44
    case PromiseHookType::kBefore:  return AsyncHooks::kBefore;
310
46
    case PromiseHookType::kAfter:   return AsyncHooks::kAfter;
311
109
    case PromiseHookType::kResolve: return AsyncHooks::kPromiseResolve;
312
  }
313
  UNREACHABLE();
314
}
315
316
// Simplified JavaScript hook fast-path for when there is no destroy hook
317
299
static void FastPromiseHook(PromiseHookType type, Local<Promise> promise,
318
                            Local<Value> parent) {
319
299
  Local<Context> context = promise->CreationContext();
320
299
  Environment* env = Environment::GetCurrent(context);
321
299
  if (env == nullptr) return;
322
323
  Local<Value> argv[] = {
324
299
    Integer::New(env->isolate(), ToAsyncHooksType(type)),
325
    promise,
326
    parent
327
1196
  };
328
329
598
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
330
299
  Local<Function> promise_hook = env->promise_hook_handler();
331
598
  USE(promise_hook->Call(context, Undefined(env->isolate()), 3, argv));
332
}
333
334
3355
static void FullPromiseHook(PromiseHookType type, Local<Promise> promise,
335
                            Local<Value> parent) {
336
3355
  Local<Context> context = promise->CreationContext();
337
338
3355
  Environment* env = Environment::GetCurrent(context);
339
3355
  if (env == nullptr) return;
340
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
341
6710
                              "EnvPromiseHook", env);
342
343
3355
  PromiseWrap* wrap = extractPromiseWrap(promise);
344

3355
  if (type == PromiseHookType::kInit || wrap == nullptr) {
345
1100
    bool silent = type != PromiseHookType::kInit;
346
347
    // set parent promise's async Id as this promise's triggerAsyncId
348
1100
    if (parent->IsPromise()) {
349
      // parent promise exists, current promise
350
      // is a chained promise, so we set parent promise's id as
351
      // current promise's triggerAsyncId
352
592
      Local<Promise> parent_promise = parent.As<Promise>();
353
592
      PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise);
354
592
      if (parent_wrap == nullptr) {
355
19
        parent_wrap = PromiseWrap::New(env, parent_promise, true);
356
19
        if (parent_wrap == nullptr) return;
357
      }
358
359
1184
      AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap);
360
592
      wrap = PromiseWrap::New(env, promise, silent);
361
    } else {
362
508
      wrap = PromiseWrap::New(env, promise, silent);
363
    }
364
  }
365
366
3355
  if (wrap == nullptr) return;
367
368
3355
  if (type == PromiseHookType::kBefore) {
369
589
    env->async_hooks()->push_async_context(wrap->get_async_id(),
370
589
      wrap->get_trigger_async_id(), wrap->object());
371
589
    wrap->EmitTraceEventBefore();
372
589
    AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id());
373
2766
  } else if (type == PromiseHookType::kAfter) {
374
589
    wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id());
375
589
    AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id());
376
589
    if (env->execution_async_id() == wrap->get_async_id()) {
377
      // This condition might not be true if async_hooks was enabled during
378
      // the promise callback execution.
379
      // Popping it off the stack can be skipped in that case, because it is
380
      // known that it would correspond to exactly one call with
381
      // PromiseHookType::kBefore that was not witnessed by the PromiseHook.
382
587
      env->async_hooks()->pop_async_context(wrap->get_async_id());
383
    }
384
2177
  } else if (type == PromiseHookType::kResolve) {
385
1089
    AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id());
386
  }
387
}
388
389
384
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
390
384
  Environment* env = Environment::GetCurrent(args);
391
392
768
  CHECK(args[0]->IsObject());
393
394
  // All of init, before, after, destroy, and promise_resolve are supplied by
395
  // async_hooks internally, so this should only ever be called once. At which
396
  // time all the functions should be set. Detect this by checking if
397
  // init !IsEmpty().
398
768
  CHECK(env->async_hooks_init_function().IsEmpty());
399
400
768
  Local<Object> fn_obj = args[0].As<Object>();
401
402
#define SET_HOOK_FN(name)                                                      \
403
  do {                                                                         \
404
    Local<Value> v =                                                           \
405
        fn_obj->Get(env->context(),                                            \
406
                    FIXED_ONE_BYTE_STRING(env->isolate(), #name))              \
407
            .ToLocalChecked();                                                 \
408
    CHECK(v->IsFunction());                                                    \
409
    env->set_async_hooks_##name##_function(v.As<Function>());                  \
410
  } while (0)
411
412
2304
  SET_HOOK_FN(init);
413
2304
  SET_HOOK_FN(before);
414
2304
  SET_HOOK_FN(after);
415
2304
  SET_HOOK_FN(destroy);
416
2304
  SET_HOOK_FN(promise_resolve);
417
#undef SET_HOOK_FN
418
384
}
419
420
296
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
421
296
  Environment* env = Environment::GetCurrent(args);
422
423
592
  if (args[0]->IsFunction()) {
424
108
    env->set_promise_hook_handler(args[0].As<Function>());
425
54
    args.GetIsolate()->SetPromiseHook(FastPromiseHook);
426
  } else {
427
242
    args.GetIsolate()->SetPromiseHook(FullPromiseHook);
428
  }
429
296
}
430
431
432
64
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
433
64
  Environment* env = Environment::GetCurrent(args);
434
64
  env->set_promise_hook_handler(Local<Function>());
435
436
  // The per-Isolate API provides no way of knowing whether there are multiple
437
  // users of the PromiseHook. That hopefully goes away when V8 introduces
438
  // a per-context API.
439
64
  args.GetIsolate()->SetPromiseHook(nullptr);
440
64
}
441
442
443
12975
class DestroyParam {
444
 public:
445
  double asyncId;
446
  Environment* env;
447
  Global<Object> target;
448
  Global<Object> propBag;
449
};
450
451
9
static void DestroyParamCleanupHook(void* ptr) {
452
9
  delete static_cast<DestroyParam*>(ptr);
453
9
}
454
455
2153
void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) {
456
4306
  HandleScope scope(info.GetIsolate());
457
458
4306
  std::unique_ptr<DestroyParam> p{info.GetParameter()};
459
  Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(),
460
4306
                                                      p->propBag);
461
  Local<Value> val;
462
463
2153
  p->env->RemoveCleanupHook(DestroyParamCleanupHook, p.get());
464
465
8612
  if (!prop_bag->Get(p->env->context(), p->env->destroyed_string())
466
2153
        .ToLocal(&val)) {
467
    return;
468
  }
469
470
2153
  if (val->IsFalse()) {
471
2152
    AsyncWrap::EmitDestroy(p->env, p->asyncId);
472
  }
473
  // unique_ptr goes out of scope here and pointer is deleted.
474
}
475
476
477
2163
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) {
478
4326
  CHECK(args[0]->IsObject());
479
4326
  CHECK(args[1]->IsNumber());
480
4326
  CHECK(args[2]->IsObject());
481
482
2163
  Isolate* isolate = args.GetIsolate();
483
2163
  DestroyParam* p = new DestroyParam();
484
6489
  p->asyncId = args[1].As<Number>()->Value();
485
2163
  p->env = Environment::GetCurrent(args);
486
6489
  p->target.Reset(isolate, args[0].As<Object>());
487
6489
  p->propBag.Reset(isolate, args[2].As<Object>());
488
2163
  p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter);
489
2163
  p->env->AddCleanupHook(DestroyParamCleanupHook, p);
490
2163
}
491
492
94221
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
493
  AsyncWrap* wrap;
494
188442
  args.GetReturnValue().Set(kInvalidAsyncId);
495
94221
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
496
282600
  args.GetReturnValue().Set(wrap->get_async_id());
497
}
498
499
500
4
void AsyncWrap::PushAsyncContext(const FunctionCallbackInfo<Value>& args) {
501
4
  Environment* env = Environment::GetCurrent(args);
502
  // No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail
503
  // then the checks in push_async_ids() and pop_async_id() will.
504
16
  double async_id = args[0]->NumberValue(env->context()).FromJust();
505
16
  double trigger_async_id = args[1]->NumberValue(env->context()).FromJust();
506
4
  env->async_hooks()->push_async_context(async_id, trigger_async_id, {});
507
4
}
508
509
510
3
void AsyncWrap::PopAsyncContext(const FunctionCallbackInfo<Value>& args) {
511
3
  Environment* env = Environment::GetCurrent(args);
512
12
  double async_id = args[0]->NumberValue(env->context()).FromJust();
513
3
  args.GetReturnValue().Set(env->async_hooks()->pop_async_context(async_id));
514
}
515
516
517
488
void AsyncWrap::ExecutionAsyncResource(
518
    const FunctionCallbackInfo<Value>& args) {
519
488
  Environment* env = Environment::GetCurrent(args);
520
  uint32_t index;
521
1952
  if (!args[0]->Uint32Value(env->context()).To(&index)) return;
522
1464
  args.GetReturnValue().Set(
523
      env->async_hooks()->native_execution_async_resource(index));
524
}
525
526
527
1212
void AsyncWrap::ClearAsyncIdStack(const FunctionCallbackInfo<Value>& args) {
528
1212
  Environment* env = Environment::GetCurrent(args);
529
1212
  env->async_hooks()->clear_async_id_stack();
530
1212
}
531
532
533
39
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) {
534
78
  CHECK(args[0]->IsObject());
535
536
  AsyncWrap* wrap;
537
39
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
538
539
78
  Local<Object> resource = args[0].As<Object>();
540
  double execution_async_id =
541
78
      args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId;
542
39
  wrap->AsyncReset(resource, execution_async_id);
543
}
544
545
546
39
void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) {
547
  AsyncWrap* wrap;
548
78
  args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE);
549
39
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
550
117
  args.GetReturnValue().Set(wrap->provider_type());
551
}
552
553
554
195119
void AsyncWrap::EmitDestroy(bool from_gc) {
555
195119
  AsyncWrap::EmitDestroy(env(), async_id_);
556
  // Ensure no double destroy is emitted via AsyncReset().
557
195126
  async_id_ = kInvalidAsyncId;
558
559

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













194737
  switch (provider_type()) {
784
  #define V(PROVIDER)                                                         \
785
    case PROVIDER_ ## PROVIDER:                                               \
786
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
787
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
788
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
789
      break;
790






















































389470
    NODE_ASYNC_PROVIDER_TYPES(V)
791
  #undef V
792
    default:
793
      UNREACHABLE();
794
  }
795
194735
}
796
797
256854
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
798

332408
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
799
75554
      !env->can_call_into_js()) {
800
181778
    return;
801
  }
802
803
75078
  if (env->destroy_async_id_list()->empty()) {
804
22333
    env->SetImmediate(&DestroyAsyncIdsCallback, CallbackFlags::kUnrefed);
805
  }
806
807
75078
  env->destroy_async_id_list()->push_back(async_id);
808
}
809
810
// Generalized call for both the constructor and for handles that are pooled
811
// and reused over their lifetime. This way a new uid can be assigned when
812
// the resource is pulled out of the pool and put back into use.
813
193408
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
814
                           bool silent) {
815
193408
  CHECK_NE(provider_type(), PROVIDER_NONE);
816
817
193408
  if (async_id_ != kInvalidAsyncId) {
818
    // This instance was in use before, we have already emitted an init with
819
    // its previous async_id and need to emit a matching destroy for that
820
    // before generating a new async_id.
821
385
    EmitDestroy();
822
  }
823
824
  // Now we can assign a new async_id_ to this instance.
825
193408
  async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id()
826
                                                     : execution_async_id;
827
193408
  trigger_async_id_ = env()->get_default_trigger_async_id();
828
829
  {
830
386816
    HandleScope handle_scope(env()->isolate());
831
193408
    Local<Object> obj = object();
832
193408
    CHECK(!obj.IsEmpty());
833
193408
    if (resource != obj) {
834
17631
      USE(obj->Set(env()->context(), env()->resource_symbol(), resource));
835
    }
836
  }
837
838













193408
  switch (provider_type()) {
839
#define V(PROVIDER)                                                           \
840
    case PROVIDER_ ## PROVIDER:                                               \
841
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
842
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
843
        auto data = tracing::TracedValue::Create();                           \
844
        data->SetInteger("executionAsyncId",                                  \
845
                         static_cast<int64_t>(env()->execution_async_id()));  \
846
        data->SetInteger("triggerAsyncId",                                    \
847
                         static_cast<int64_t>(get_trigger_async_id()));       \
848
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
849
          TRACING_CATEGORY_NODE1(async_hooks),                                \
850
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
851
          "data", std::move(data));                                           \
852
        }                                                                     \
853
      break;
854

















































































50
    NODE_ASYNC_PROVIDER_TYPES(V)
855
#undef V
856
    default:
857
      UNREACHABLE();
858
  }
859
860
193408
  if (silent) return;
861
862
386754
  EmitAsyncInit(env(), resource,
863
193377
                env()->async_hooks()->provider_string(provider_type()),
864
193377
                async_id_, trigger_async_id_);
865
}
866
867
868
193927
void AsyncWrap::EmitAsyncInit(Environment* env,
869
                              Local<Object> object,
870
                              Local<String> type,
871
                              double async_id,
872
                              double trigger_async_id) {
873
193927
  CHECK(!object.IsEmpty());
874
193927
  CHECK(!type.IsEmpty());
875
193927
  AsyncHooks* async_hooks = env->async_hooks();
876
877
  // Nothing to execute, so can continue normally.
878
193927
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
879
178859
    return;
880
  }
881
882
30136
  HandleScope scope(env->isolate());
883
15068
  Local<Function> init_fn = env->async_hooks_init_function();
884
885
  Local<Value> argv[] = {
886
    Number::New(env->isolate(), async_id),
887
    type,
888
    Number::New(env->isolate(), trigger_async_id),
889
    object,
890
75340
  };
891
892
30136
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
893
45204
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
894
}
895
896
897
656632
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
898
                                          int argc,
899
                                          Local<Value>* argv) {
900
656632
  EmitTraceEventBefore();
901
902
656557
  ProviderType provider = provider_type();
903
656717
  async_context context { get_async_id(), get_trigger_async_id() };
904
  MaybeLocal<Value> ret = InternalMakeCallback(
905
656732
      env(), object(), object(), cb, argc, argv, context);
906
907
  // This is a static call with cached values because the `this` object may
908
  // no longer be alive at this point.
909
656610
  EmitTraceEventAfter(provider, context.async_id);
910
911
656610
  return ret;
912
}
913
914
std::string AsyncWrap::MemoryInfoName() const {
915
  return provider_names[provider_type()];
916
}
917
918
std::string AsyncWrap::diagnostic_name() const {
919
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
920
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
921
}
922
923
249
Local<Object> AsyncWrap::GetOwner() {
924
249
  return GetOwner(env(), object());
925
}
926
927
249
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
928
249
  EscapableHandleScope handle_scope(env->isolate());
929
249
  CHECK(!obj.IsEmpty());
930
931
498
  TryCatchScope ignore_exceptions(env);
932
  while (true) {
933
    Local<Value> owner;
934
1936
    if (!obj->Get(env->context(),
935

3388
                  env->owner_symbol()).ToLocal(&owner) ||
936
484
        !owner->IsObject()) {
937
498
      return handle_scope.Escape(obj);
938
    }
939
940
235
    obj = owner.As<Object>();
941
235
  }
942
}
943
944
}  // namespace node
945
946
4989
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)
947

19890
NODE_MODULE_EXTERNAL_REFERENCE(async_wrap,
948
                               node::AsyncWrap::RegisterExternalReferences)