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: 388 412 94.2 %
Date: 2020-06-24 22:13:30 Branches: 711 1333 53.3 %

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

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

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

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













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





















































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













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





















































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

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

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

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

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













185138
  switch (provider_type()) {
745
  #define V(PROVIDER)                                                         \
746
    case PROVIDER_ ## PROVIDER:                                               \
747
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
748
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
749
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
750
      break;
751





















































370274
    NODE_ASYNC_PROVIDER_TYPES(V)
752
  #undef V
753
    default:
754
      UNREACHABLE();
755
  }
756
185137
}
757
758
247155
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
759

322715
  if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 ||
760
75560
      !env->can_call_into_js()) {
761
172042
    return;
762
  }
763
764
75112
  if (env->destroy_async_id_list()->empty()) {
765
22362
    env->SetImmediate(&DestroyAsyncIdsCallback, CallbackFlags::kUnrefed);
766
  }
767
768
75112
  env->destroy_async_id_list()->push_back(async_id);
769
}
770
771
// Generalized call for both the constructor and for handles that are pooled
772
// and reused over their lifetime. This way a new uid can be assigned when
773
// the resource is pulled out of the pool and put back into use.
774
183458
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id,
775
                           bool silent) {
776
183458
  CHECK_NE(provider_type(), PROVIDER_NONE);
777
778
183458
  if (async_id_ != kInvalidAsyncId) {
779
    // This instance was in use before, we have already emitted an init with
780
    // its previous async_id and need to emit a matching destroy for that
781
    // before generating a new async_id.
782
233
    EmitDestroy();
783
  }
784
785
  // Now we can assign a new async_id_ to this instance.
786
183458
  async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id()
787
                                                     : execution_async_id;
788
183458
  trigger_async_id_ = env()->get_default_trigger_async_id();
789
790
  {
791
366916
    HandleScope handle_scope(env()->isolate());
792
183458
    Local<Object> obj = object();
793
183458
    CHECK(!obj.IsEmpty());
794
183458
    if (resource != obj) {
795
16767
      USE(obj->Set(env()->context(), env()->resource_symbol(), resource));
796
    }
797
  }
798
799













183458
  switch (provider_type()) {
800
#define V(PROVIDER)                                                           \
801
    case PROVIDER_ ## PROVIDER:                                               \
802
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
803
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
804
        auto data = tracing::TracedValue::Create();                           \
805
        data->SetInteger("executionAsyncId",                                  \
806
                         static_cast<int64_t>(env()->execution_async_id()));  \
807
        data->SetInteger("triggerAsyncId",                                    \
808
                         static_cast<int64_t>(get_trigger_async_id()));       \
809
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
810
          TRACING_CATEGORY_NODE1(async_hooks),                                \
811
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
812
          "data", std::move(data));                                           \
813
        }                                                                     \
814
      break;
815















































































50
    NODE_ASYNC_PROVIDER_TYPES(V)
816
#undef V
817
    default:
818
      UNREACHABLE();
819
  }
820
821
183458
  if (silent) return;
822
823
366890
  EmitAsyncInit(env(), resource,
824
183445
                env()->async_hooks()->provider_string(provider_type()),
825
183445
                async_id_, trigger_async_id_);
826
}
827
828
829
183995
void AsyncWrap::EmitAsyncInit(Environment* env,
830
                              Local<Object> object,
831
                              Local<String> type,
832
                              double async_id,
833
                              double trigger_async_id) {
834
183995
  CHECK(!object.IsEmpty());
835
183995
  CHECK(!type.IsEmpty());
836
183995
  AsyncHooks* async_hooks = env->async_hooks();
837
838
  // Nothing to execute, so can continue normally.
839
183995
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
840
169330
    return;
841
  }
842
843
29330
  HandleScope scope(env->isolate());
844
14665
  Local<Function> init_fn = env->async_hooks_init_function();
845
846
  Local<Value> argv[] = {
847
    Number::New(env->isolate(), async_id),
848
    type,
849
    Number::New(env->isolate(), trigger_async_id),
850
    object,
851
73325
  };
852
853
29330
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
854
43995
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
855
}
856
857
858
572824
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
859
                                          int argc,
860
                                          Local<Value>* argv) {
861
572824
  EmitTraceEventBefore();
862
863
572880
  ProviderType provider = provider_type();
864
572924
  async_context context { get_async_id(), get_trigger_async_id() };
865
  MaybeLocal<Value> ret = InternalMakeCallback(
866
572929
      env(), object(), object(), cb, argc, argv, context);
867
868
  // This is a static call with cached values because the `this` object may
869
  // no longer be alive at this point.
870
572809
  EmitTraceEventAfter(provider, context.async_id);
871
872
572809
  return ret;
873
}
874
875
std::string AsyncWrap::MemoryInfoName() const {
876
  return provider_names[provider_type()];
877
}
878
879
std::string AsyncWrap::diagnostic_name() const {
880
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
881
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
882
}
883
884
249
Local<Object> AsyncWrap::GetOwner() {
885
249
  return GetOwner(env(), object());
886
}
887
888
249
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
889
249
  EscapableHandleScope handle_scope(env->isolate());
890
249
  CHECK(!obj.IsEmpty());
891
892
498
  TryCatchScope ignore_exceptions(env);
893
  while (true) {
894
    Local<Value> owner;
895
1936
    if (!obj->Get(env->context(),
896

3388
                  env->owner_symbol()).ToLocal(&owner) ||
897
484
        !owner->IsObject()) {
898
498
      return handle_scope.Escape(obj);
899
    }
900
901
235
    obj = owner.As<Object>();
902
235
  }
903
}
904
905
}  // namespace node
906
907
4398
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)