Skip to content

Commit 69bb9b8

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 d213c4a commit 69bb9b8

File tree

2 files changed

+58
-47
lines changed

2 files changed

+58
-47
lines changed

lib/internal/async_hooks.js

+48-47
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const {
5757
clearAsyncIdStack,
5858
} = async_wrap;
5959
// For performance reasons, only track Promises when a hook is enabled.
60-
const { enablePromiseHook, disablePromiseHook } = async_wrap;
60+
const { enablePromiseHook, disablePromiseHook, setPromiseHooks } = async_wrap;
6161
// Properties in active_hooks are used to keep track of the set of hooks being
6262
// executed in case another hook is enabled/disabled. The new set of hooks is
6363
// then restored once the active set of hooks is finished executing.
@@ -306,71 +306,68 @@ function restoreActiveHooks() {
306306
active_hooks.tmp_fields = null;
307307
}
308308

309-
function trackPromise(promise, parent, silent) {
310-
const asyncId = getOrSetAsyncId(promise);
309+
function trackPromise(promise, parent) {
310+
if (promise[async_id_symbol]) {
311+
return;
312+
}
311313

314+
promise[async_id_symbol] = newAsyncId();
312315
promise[trigger_async_id_symbol] = parent ? getOrSetAsyncId(parent) :
313316
getDefaultTriggerAsyncId();
317+
}
314318

315-
if (!silent && initHooksExist()) {
316-
const triggerId = promise[trigger_async_id_symbol];
317-
emitInitScript(asyncId, 'PROMISE', triggerId, promise);
318-
}
319+
function promiseInitHook(promise, parent) {
320+
trackPromise(promise, parent);
321+
const asyncId = promise[async_id_symbol];
322+
const triggerAsyncId = promise[trigger_async_id_symbol];
323+
emitInitScript(asyncId, 'PROMISE', triggerAsyncId, promise);
319324
}
320325

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

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

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

358355
let wantPromiseHook = false;
359356
function enableHooks() {
360357
async_hook_fields[kCheck] += 1;
361358
}
362359

363-
let promiseHookMode = -1;
364360
function updatePromiseHookMode() {
365361
wantPromiseHook = true;
366362
if (destroyHooksExist()) {
367-
if (promiseHookMode !== 1) {
368-
promiseHookMode = 1;
369-
enablePromiseHook();
370-
}
371-
} else if (promiseHookMode !== 0) {
372-
promiseHookMode = 0;
373-
enablePromiseHook(fastPromiseHook);
363+
enablePromiseHook();
364+
} else {
365+
setPromiseHooks(
366+
initHooksExist() ? promiseInitHook : undefined,
367+
promiseBeforeHook,
368+
promiseAfterHook,
369+
promiseResolveHooksExist() ? promiseResolveHook : undefined,
370+
);
374371
}
375372
}
376373

@@ -386,8 +383,8 @@ function disableHooks() {
386383

387384
function disablePromiseHookIfNecessary() {
388385
if (!wantPromiseHook) {
389-
promiseHookMode = -1;
390386
disablePromiseHook();
387+
setPromiseHooks(undefined, undefined, undefined, undefined);
391388
}
392389
}
393390

@@ -461,6 +458,10 @@ function destroyHooksExist() {
461458
return hasHooks(kDestroy);
462459
}
463460

461+
function promiseResolveHooksExist() {
462+
return hasHooks(kPromiseResolve);
463+
}
464+
464465

465466
function emitInitScript(asyncId, type, triggerAsyncId, resource) {
466467
// 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
@@ -485,6 +485,15 @@ static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) {
485485
}
486486
}
487487

488+
static void SetPromiseHooks(const FunctionCallbackInfo<Value>& args) {
489+
Environment* env = Environment::GetCurrent(args);
490+
Local<Context> ctx = env->context();
491+
ctx->SetPromiseHooks(
492+
args[0]->IsFunction() ? args[0].As<Function>() : Local<Function>(),
493+
args[1]->IsFunction() ? args[1].As<Function>() : Local<Function>(),
494+
args[2]->IsFunction() ? args[2].As<Function>() : Local<Function>(),
495+
args[3]->IsFunction() ? args[3].As<Function>() : Local<Function>());
496+
}
488497

489498
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) {
490499
Environment* env = Environment::GetCurrent(args);
@@ -664,6 +673,7 @@ void AsyncWrap::Initialize(Local<Object> target,
664673
env->SetMethod(target, "clearAsyncIdStack", ClearAsyncIdStack);
665674
env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);
666675
env->SetMethod(target, "enablePromiseHook", EnablePromiseHook);
676+
env->SetMethod(target, "setPromiseHooks", SetPromiseHooks);
667677
env->SetMethod(target, "disablePromiseHook", DisablePromiseHook);
668678
env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook);
669679

0 commit comments

Comments
 (0)