Skip to content

Commit f3563d3

Browse files
QardMylesBorins
authored andcommittedAug 31, 2021
async_hooks: use new v8::Context PromiseHook API
PR-URL: #36394 Backport-PR-URL: #38577 Reviewed-By: Bryan English <bryan@bryanenglish.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de> Reviewed-By: James M Snell <jasnell@gmail.com>
1 parent d9b58a0 commit f3563d3

File tree

2 files changed

+58
-48
lines changed

2 files changed

+58
-48
lines changed
 

‎lib/internal/async_hooks.js

+48-48
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const {
55
ErrorCaptureStackTrace,
66
ObjectPrototypeHasOwnProperty,
77
ObjectDefineProperty,
8-
Promise,
98
Symbol,
109
} = primordials;
1110

@@ -53,7 +52,7 @@ const {
5352
clearAsyncIdStack,
5453
} = async_wrap;
5554
// For performance reasons, only track Promises when a hook is enabled.
56-
const { enablePromiseHook, disablePromiseHook } = async_wrap;
55+
const { enablePromiseHook, disablePromiseHook, setPromiseHooks } = async_wrap;
5756
// Properties in active_hooks are used to keep track of the set of hooks being
5857
// executed in case another hook is enabled/disabled. The new set of hooks is
5958
// then restored once the active set of hooks is finished executing.
@@ -303,71 +302,68 @@ function restoreActiveHooks() {
303302
active_hooks.tmp_fields = null;
304303
}
305304

306-
function trackPromise(promise, parent, silent) {
307-
const asyncId = getOrSetAsyncId(promise);
305+
function trackPromise(promise, parent) {
306+
if (promise[async_id_symbol]) {
307+
return;
308+
}
308309

310+
promise[async_id_symbol] = newAsyncId();
309311
promise[trigger_async_id_symbol] = parent ? getOrSetAsyncId(parent) :
310312
getDefaultTriggerAsyncId();
313+
}
311314

312-
if (!silent && initHooksExist()) {
313-
const triggerId = promise[trigger_async_id_symbol];
314-
emitInitScript(asyncId, 'PROMISE', triggerId, promise);
315-
}
315+
function promiseInitHook(promise, parent) {
316+
trackPromise(promise, parent);
317+
const asyncId = promise[async_id_symbol];
318+
const triggerAsyncId = promise[trigger_async_id_symbol];
319+
emitInitScript(asyncId, 'PROMISE', triggerAsyncId, promise);
316320
}
317321

318-
function fastPromiseHook(type, promise, parent) {
319-
if (type === kInit || !promise[async_id_symbol]) {
320-
const silent = type !== kInit;
321-
if (parent instanceof Promise) {
322-
trackPromise(promise, parent, silent);
323-
} else {
324-
trackPromise(promise, null, silent);
325-
}
322+
function promiseBeforeHook(promise) {
323+
trackPromise(promise);
324+
const asyncId = promise[async_id_symbol];
325+
const triggerId = promise[trigger_async_id_symbol];
326+
emitBeforeScript(asyncId, triggerId, promise);
327+
}
326328

327-
if (!silent) return;
329+
function promiseAfterHook(promise) {
330+
trackPromise(promise);
331+
const asyncId = promise[async_id_symbol];
332+
if (hasHooks(kAfter)) {
333+
emitAfterNative(asyncId);
328334
}
335+
if (asyncId === executionAsyncId()) {
336+
// This condition might not be true if async_hooks was enabled during
337+
// the promise callback execution.
338+
// Popping it off the stack can be skipped in that case, because it is
339+
// known that it would correspond to exactly one call with
340+
// PromiseHookType::kBefore that was not witnessed by the PromiseHook.
341+
popAsyncContext(asyncId);
342+
}
343+
}
329344

345+
function promiseResolveHook(promise) {
346+
trackPromise(promise);
330347
const asyncId = promise[async_id_symbol];
331-
switch (type) {
332-
case kBefore:
333-
const triggerId = promise[trigger_async_id_symbol];
334-
emitBeforeScript(asyncId, triggerId, promise);
335-
break;
336-
case kAfter:
337-
if (hasHooks(kAfter)) {
338-
emitAfterNative(asyncId);
339-
}
340-
if (asyncId === executionAsyncId()) {
341-
// This condition might not be true if async_hooks was enabled during
342-
// the promise callback execution.
343-
// Popping it off the stack can be skipped in that case, because it is
344-
// known that it would correspond to exactly one call with
345-
// PromiseHookType::kBefore that was not witnessed by the PromiseHook.
346-
popAsyncContext(asyncId);
347-
}
348-
break;
349-
case kPromiseResolve:
350-
emitPromiseResolveNative(asyncId);
351-
break;
352-
}
348+
emitPromiseResolveNative(asyncId);
353349
}
354350

355351
let wantPromiseHook = false;
356352
function enableHooks() {
357353
async_hook_fields[kCheck] += 1;
358354
}
359355

360-
let promiseHookMode = -1;
361356
function updatePromiseHookMode() {
362357
wantPromiseHook = true;
363358
if (destroyHooksExist()) {
364-
if (promiseHookMode !== 1) {
365-
promiseHookMode = 1;
366-
enablePromiseHook();
367-
}
368-
} else if (promiseHookMode !== 0) {
369-
promiseHookMode = 0;
370-
enablePromiseHook(fastPromiseHook);
359+
enablePromiseHook();
360+
} else {
361+
setPromiseHooks(
362+
initHooksExist() ? promiseInitHook : undefined,
363+
promiseBeforeHook,
364+
promiseAfterHook,
365+
promiseResolveHooksExist() ? promiseResolveHook : undefined,
366+
);
371367
}
372368
}
373369

@@ -383,8 +379,8 @@ function disableHooks() {
383379

384380
function disablePromiseHookIfNecessary() {
385381
if (!wantPromiseHook) {
386-
promiseHookMode = -1;
387382
disablePromiseHook();
383+
setPromiseHooks(undefined, undefined, undefined, undefined);
388384
}
389385
}
390386

@@ -458,6 +454,10 @@ function destroyHooksExist() {
458454
return hasHooks(kDestroy);
459455
}
460456

457+
function promiseResolveHooksExist() {
458+
return hasHooks(kPromiseResolve);
459+
}
460+
461461

462462
function emitInitScript(asyncId, type, triggerAsyncId, resource) {
463463
// Short circuit all checks for the common case. Which is that no hooks have

‎src/async_wrap.cc

+10
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,15 @@ static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
491491
}
492492
}
493493

494+
static void SetPromiseHooks(const FunctionCallbackInfo<Value>& args) {
495+
Environment* env = Environment::GetCurrent(args);
496+
Local<Context> ctx = env->context();
497+
ctx->SetPromiseHooks(
498+
args[0]->IsFunction() ? args[0].As<Function>() : Local<Function>(),
499+
args[1]->IsFunction() ? args[1].As<Function>() : Local<Function>(),
500+
args[2]->IsFunction() ? args[2].As<Function>() : Local<Function>(),
501+
args[3]->IsFunction() ? args[3].As<Function>() : Local<Function>());
502+
}
494503

495504
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
496505
Environment* env = Environment::GetCurrent(args);
@@ -670,6 +679,7 @@ void AsyncWrap::Initialize(Local<Object> target,
670679
env->SetMethod(target, "clearAsyncIdStack", ClearAsyncIdStack);
671680
env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
672681
env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
682+
env->SetMethod(target, "setPromiseHooks", SetPromiseHooks);
673683
env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
674684
env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
675685

0 commit comments

Comments
 (0)
Please sign in to comment.