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: 381 405 94.1 %
Date: 2020-05-27 22:15:15 Branches: 710 1199 59.2 %

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::Maybe;
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
4594
  static Local<FunctionTemplate> GetConstructorTemplate(Environment* env) {
86
4594
    Local<FunctionTemplate> tmpl = env->async_wrap_object_ctor_template();
87
4594
    if (tmpl.IsEmpty()) {
88
4594
      tmpl = env->NewFunctionTemplate(AsyncWrapObject::New);
89
9188
      tmpl->SetClassName(
90
4594
          FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"));
91
9188
      tmpl->Inherit(AsyncWrap::GetConstructorTemplate(env));
92
13782
      tmpl->InstanceTemplate()->SetInternalFieldCount(
93
4594
          AsyncWrapObject::kInternalFieldCount);
94
4594
      env->set_async_wrap_object_ctor_template(tmpl);
95
    }
96
4594
    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
22342
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) {
105
22342
  Local<Function> fn = env->async_hooks_destroy_function();
106
107
44684
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
108
109

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

97344
    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
150000
      HandleScope scope(env->isolate());
117
75000
      Local<Value> async_id_value = Number::New(env->isolate(), async_id);
118
      MaybeLocal<Value> ret = fn->Call(
119
225000
          env->context(), Undefined(env->isolate()), 1, &async_id_value);
120
121
75000
      if (ret.IsEmpty())
122
        return;
123
    }
124
22344
  } while (!env->destroy_async_id_list()->empty());
125
}
126
127
1215504
void Emit(Environment* env, double async_id, AsyncHooks::Fields type,
128
          Local<Function> fn) {
129
1215504
  AsyncHooks* async_hooks = env->async_hooks();
130
131

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












571630
  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















































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












572267
  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















































1144542
    NODE_ASYNC_PROVIDER_TYPES(V)
178
#undef V
179
    default:
180
      UNREACHABLE();
181
  }
182
572271
}
183
184
185
607422
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
607422
  Emit(env, async_id, AsyncHooks::kAfter,
189
607425
       env->async_hooks_after_function());
190
607423
}
191
192
1768
class PromiseWrap : public AsyncWrap {
193
 public:
194
1075
  PromiseWrap(Environment* env, Local<Object> object, bool silent)
195
1075
      : AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) {
196
1075
    MakeWeak();
197
1075
  }
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
1075
PromiseWrap* PromiseWrap::New(Environment* env,
221
                              Local<Promise> promise,
222
                              bool silent) {
223
1075
  Local<Context> context = env->context();
224
225
  Local<Object> obj;
226
3225
  if (!env->promise_wrap_template()->NewInstance(context).ToLocal(&obj))
227
    return nullptr;
228
229
2150
  CHECK_NULL(promise->GetAlignedPointerFromInternalField(0));
230
1075
  promise->SetInternalField(0, obj);
231
232
  // Skip for init events
233
1075
  if (silent) {
234
    Local<Value> maybeAsyncId = promise
235
39
        ->Get(context, env->async_id_symbol())
236
13
        .ToLocalChecked();
237
238
    Local<Value> maybeTriggerAsyncId = promise
239
39
        ->Get(context, env->trigger_async_id_symbol())
240
13
        .ToLocalChecked();
241
242

13
    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
1075
  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
4594
void PromiseWrap::Initialize(Environment* env) {
276
4594
  Isolate* isolate = env->isolate();
277
9188
  HandleScope scope(isolate);
278
279
4594
  Local<FunctionTemplate> ctor = FunctionTemplate::New(isolate);
280
9188
  ctor->SetClassName(FIXED_ONE_BYTE_STRING(isolate, "PromiseWrap"));
281
282
4594
  Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate();
283
4594
  env->set_promise_wrap_template(promise_wrap_template);
284
285
4594
  promise_wrap_template->SetInternalFieldCount(
286
4594
      PromiseWrap::kInternalFieldCount);
287
288
13782
  promise_wrap_template->SetAccessor(
289
      env->async_id_symbol(),
290
4594
      PromiseWrap::GetAsyncId);
291
292
13782
  promise_wrap_template->SetAccessor(
293
      env->trigger_async_id_symbol(),
294
4594
      PromiseWrap::GetTriggerAsyncId);
295
4594
}
296
297
3711
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
7422
  Local<Value> obj = promise->GetInternalField(0);
303
6347
  return obj->IsObject() ? Unwrap<PromiseWrap>(obj.As<Object>()) : nullptr;
304
}
305
306
249
static uint16_t ToAsyncHooksType(PromiseHookType type) {
307

249
  switch (type) {
308
87
    case PromiseHookType::kInit:    return AsyncHooks::kInit;
309
34
    case PromiseHookType::kBefore:  return AsyncHooks::kBefore;
310
36
    case PromiseHookType::kAfter:   return AsyncHooks::kAfter;
311
92
    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
249
static void FastPromiseHook(PromiseHookType type, Local<Promise> promise,
318
                            Local<Value> parent) {
319
249
  Local<Context> context = promise->CreationContext();
320
249
  Environment* env = Environment::GetCurrent(context);
321
249
  if (env == nullptr) return;
322
323
  Local<Value> argv[] = {
324
249
    Integer::New(env->isolate(), ToAsyncHooksType(type)),
325
    promise,
326
    parent
327
996
  };
328
329
498
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
330
249
  Local<Function> promise_hook = env->promise_hook_handler();
331
498
  USE(promise_hook->Call(context, Undefined(env->isolate()), 3, argv));
332
}
333
334
3148
static void FullPromiseHook(PromiseHookType type, Local<Promise> promise,
335
                            Local<Value> parent) {
336
3148
  Local<Context> context = promise->CreationContext();
337
338
3148
  Environment* env = Environment::GetCurrent(context);
339
3148
  if (env == nullptr) return;
340
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
341
6296
                              "EnvPromiseHook", env);
342
343
3148
  PromiseWrap* wrap = extractPromiseWrap(promise);
344

3148
  if (type == PromiseHookType::kInit || wrap == nullptr) {
345
1074
    bool silent = type != PromiseHookType::kInit;
346
347
    // set parent promise's async Id as this promise's triggerAsyncId
348
1074
    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
563
      Local<Promise> parent_promise = parent.As<Promise>();
353
563
      PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise);
354
563
      if (parent_wrap == nullptr) {
355
1
        parent_wrap = PromiseWrap::New(env, parent_promise, true);
356
1
        if (parent_wrap == nullptr) return;
357
      }
358
359
1126
      AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap);
360
563
      wrap = PromiseWrap::New(env, promise, silent);
361
    } else {
362
511
      wrap = PromiseWrap::New(env, promise, silent);
363
    }
364
  }
365
366
3148
  if (wrap == nullptr) return;
367
368
3148
  if (type == PromiseHookType::kBefore) {
369
1557
    env->async_hooks()->push_async_context(wrap->get_async_id(),
370
519
      wrap->get_trigger_async_id(), wrap->object());
371
519
    wrap->EmitTraceEventBefore();
372
519
    AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id());
373
2629
  } else if (type == PromiseHookType::kAfter) {
374
519
    wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id());
375
519
    AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id());
376
519
    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
517
      env->async_hooks()->pop_async_context(wrap->get_async_id());
383
    }
384
2110
  } else if (type == PromiseHookType::kResolve) {
385
1048
    AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id());
386
  }
387
}
388
389
4594
static void SetupHooks(const FunctionCallbackInfo<Value>& args) {
390
4594
  Environment* env = Environment::GetCurrent(args);
391
392
9188
  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
9188
  CHECK(env->async_hooks_init_function().IsEmpty());
399
400
9188
  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
27564
  SET_HOOK_FN(init);
413
27564
  SET_HOOK_FN(before);
414
27564
  SET_HOOK_FN(after);
415
27564
  SET_HOOK_FN(destroy);
416
27564
  SET_HOOK_FN(promise_resolve);
417
#undef SET_HOOK_FN
418
4594
}
419
420
290
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
421
290
  Environment* env = Environment::GetCurrent(args);
422
423
580
  if (args[0]->IsFunction()) {
424
100
    env->set_promise_hook_handler(args[0].As<Function>());
425
50
    args.GetIsolate()->SetPromiseHook(FastPromiseHook);
426
  } else {
427
240
    args.GetIsolate()->SetPromiseHook(FullPromiseHook);
428
  }
429
290
}
430
431
432
63
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
433
63
  Environment* env = Environment::GetCurrent(args);
434
63
  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
63
  args.GetIsolate()->SetPromiseHook(nullptr);
440
63
}
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
93028
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) {
493
  AsyncWrap* wrap;
494
186056
  args.GetReturnValue().Set(kInvalidAsyncId);
495
93028
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
496
279021
  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, args[2]);
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
39
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) {
518
78
  CHECK(args[0]->IsObject());
519
520
  AsyncWrap* wrap;
521
39
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
522
523
78
  Local<Object> resource = args[0].As<Object>();
524
  double execution_async_id =
525
78
      args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId;
526
39
  wrap->AsyncReset(resource, execution_async_id);
527
}
528
529
530
39
void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) {
531
  AsyncWrap* wrap;
532
78
  args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE);
533
39
  ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
534
117
  args.GetReturnValue().Set(wrap->provider_type());
535
}
536
537
538
184753
void AsyncWrap::EmitDestroy(bool from_gc) {
539
184753
  AsyncWrap::EmitDestroy(env(), async_id_);
540
  // Ensure no double destroy is emitted via AsyncReset().
541
184752
  async_id_ = kInvalidAsyncId;
542
543

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












184520
  switch (provider_type()) {
736
  #define V(PROVIDER)                                                         \
737
    case PROVIDER_ ## PROVIDER:                                               \
738
      TRACE_EVENT_NESTABLE_ASYNC_END0(                                        \
739
        TRACING_CATEGORY_NODE1(async_hooks),                                  \
740
        #PROVIDER, static_cast<int64_t>(get_async_id()));                     \
741
      break;
742















































369038
    NODE_ASYNC_PROVIDER_TYPES(V)
743
  #undef V
744
    default:
745
      UNREACHABLE();
746
  }
747
184520
}
748
749
246549
void AsyncWrap::EmitDestroy(Environment* env, double async_id) {
750

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












182901
  switch (provider_type()) {
791
#define V(PROVIDER)                                                           \
792
    case PROVIDER_ ## PROVIDER:                                               \
793
      if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(                        \
794
          TRACING_CATEGORY_NODE1(async_hooks))) {                             \
795
        auto data = tracing::TracedValue::Create();                           \
796
        data->SetInteger("executionAsyncId",                                  \
797
                         static_cast<int64_t>(env()->execution_async_id()));  \
798
        data->SetInteger("triggerAsyncId",                                    \
799
                         static_cast<int64_t>(get_trigger_async_id()));       \
800
        TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(                                    \
801
          TRACING_CATEGORY_NODE1(async_hooks),                                \
802
          #PROVIDER, static_cast<int64_t>(get_async_id()),                    \
803
          "data", std::move(data));                                           \
804
        }                                                                     \
805
      break;
806






































































50
    NODE_ASYNC_PROVIDER_TYPES(V)
807
#undef V
808
    default:
809
      UNREACHABLE();
810
  }
811
812
182901
  if (silent) return;
813
814
365776
  EmitAsyncInit(env(), resource,
815
182888
                env()->async_hooks()->provider_string(provider_type()),
816
182888
                async_id_, trigger_async_id_);
817
}
818
819
820
183438
void AsyncWrap::EmitAsyncInit(Environment* env,
821
                              Local<Object> object,
822
                              Local<String> type,
823
                              double async_id,
824
                              double trigger_async_id) {
825
183438
  CHECK(!object.IsEmpty());
826
183438
  CHECK(!type.IsEmpty());
827
183438
  AsyncHooks* async_hooks = env->async_hooks();
828
829
  // Nothing to execute, so can continue normally.
830
183438
  if (async_hooks->fields()[AsyncHooks::kInit] == 0) {
831
168745
    return;
832
  }
833
834
29386
  HandleScope scope(env->isolate());
835
14693
  Local<Function> init_fn = env->async_hooks_init_function();
836
837
  Local<Value> argv[] = {
838
    Number::New(env->isolate(), async_id),
839
    type,
840
    Number::New(env->isolate(), trigger_async_id),
841
    object,
842
73465
  };
843
844
29386
  TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal);
845
44079
  USE(init_fn->Call(env->context(), object, arraysize(argv), argv));
846
}
847
848
849
571322
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb,
850
                                          int argc,
851
                                          Local<Value>* argv) {
852
571322
  EmitTraceEventBefore();
853
854
571189
  ProviderType provider = provider_type();
855
571844
  async_context context { get_async_id(), get_trigger_async_id() };
856
  MaybeLocal<Value> ret = InternalMakeCallback(
857
571851
      env(), object(), object(), cb, argc, argv, context);
858
859
  // This is a static call with cached values because the `this` object may
860
  // no longer be alive at this point.
861
571754
  EmitTraceEventAfter(provider, context.async_id);
862
863
571752
  return ret;
864
}
865
866
std::string AsyncWrap::MemoryInfoName() const {
867
  return provider_names[provider_type()];
868
}
869
870
std::string AsyncWrap::diagnostic_name() const {
871
  return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" +
872
      std::to_string(static_cast<int64_t>(async_id_)) + ")";
873
}
874
875
247
Local<Object> AsyncWrap::GetOwner() {
876
247
  return GetOwner(env(), object());
877
}
878
879
247
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) {
880
247
  EscapableHandleScope handle_scope(env->isolate());
881
247
  CHECK(!obj.IsEmpty());
882
883
494
  TryCatchScope ignore_exceptions(env);
884
  while (true) {
885
    Local<Value> owner;
886
1920
    if (!obj->Get(env->context(),
887

3360
                  env->owner_symbol()).ToLocal(&owner) ||
888
480
        !owner->IsObject()) {
889
494
      return handle_scope.Escape(obj);
890
    }
891
892
233
    obj = owner.As<Object>();
893
233
  }
894
}
895
896
}  // namespace node
897
898
4325
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize)