Skip to content

Commit f37c26b

Browse files
QardStephen Belanger
authored and
Stephen Belanger
committed
async_hooks: use new v8::Context PromiseHook API
PR-URL: #36394 Reviewed-By: Bryan English <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent c8e4020 commit f37c26b

File tree

2 files changed

+59
-48
lines changed

2 files changed

+59
-48
lines changed

lib/internal/async_hooks.js

Lines changed: 48 additions & 48 deletions
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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,15 @@ static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
452452
}
453453
}
454454

455+
static void SetPromiseHooks(const FunctionCallbackInfo<Value>& args) {
456+
Environment* env = Environment::GetCurrent(args);
457+
Local<Context> ctx = env->context();
458+
ctx->SetPromiseHooks(
459+
args[0]->IsFunction() ? args[0].As<Function>() : Local<Function>(),
460+
args[1]->IsFunction() ? args[1].As<Function>() : Local<Function>(),
461+
args[2]->IsFunction() ? args[2].As<Function>() : Local<Function>(),
462+
args[3]->IsFunction() ? args[3].As<Function>() : Local<Function>());
463+
}
455464

456465
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
457466
Environment* env = Environment::GetCurrent(args);
@@ -631,6 +640,7 @@ void AsyncWrap::Initialize(Local<Object> target,
631640
env->SetMethod(target, "clearAsyncIdStack", ClearAsyncIdStack);
632641
env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
633642
env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
643+
env->SetMethod(target, "setPromiseHooks", SetPromiseHooks);
634644
env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
635645
env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
636646

@@ -725,6 +735,7 @@ void AsyncWrap::RegisterExternalReferences(
725735
registry->Register(ClearAsyncIdStack);
726736
registry->Register(QueueDestroyAsyncId);
727737
registry->Register(EnablePromiseHook);
738+
registry->Register(SetPromiseHooks);
728739
registry->Register(DisablePromiseHook);
729740
registry->Register(RegisterDestroyHook);
730741
registry->Register(AsyncWrap::GetAsyncId);

0 commit comments

Comments
 (0)