Skip to content

Commit ef05e15

Browse files
Qardcodebytere
authored andcommitted
async_hooks: callback trampoline for MakeCallback
PR-URL: #33801 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Vladimir de Turckheim <[email protected]> Reviewed-By: Gus Caplan <[email protected]> Reviewed-By: Andrey Pechkurov <[email protected]> Reviewed-By: Gerhard Stöbich <[email protected]>
1 parent e3d53f9 commit ef05e15

File tree

5 files changed

+68
-7
lines changed

5 files changed

+68
-7
lines changed

lib/internal/async_hooks.js

+23
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
'use strict';
22

33
const {
4+
ArrayPrototypeUnshift,
45
Error,
56
FunctionPrototypeBind,
67
ObjectPrototypeHasOwnProperty,
78
ObjectDefineProperty,
89
Promise,
10+
ReflectApply,
911
Symbol,
1012
} = primordials;
1113

1214
const async_wrap = internalBinding('async_wrap');
15+
const { setCallbackTrampoline } = async_wrap;
1316
/* async_hook_fields is a Uint32Array wrapping the uint32_t array of
1417
* Environment::AsyncHooks::fields_[]. Each index tracks the number of active
1518
* hooks for each type.
@@ -103,6 +106,26 @@ const emitDestroyNative = emitHookFactory(destroy_symbol, 'emitDestroyNative');
103106
const emitPromiseResolveNative =
104107
emitHookFactory(promise_resolve_symbol, 'emitPromiseResolveNative');
105108

109+
function callbackTrampoline(asyncId, cb, domain_cb, ...args) {
110+
if (hasHooks(kBefore))
111+
emitBeforeNative(asyncId);
112+
113+
let result;
114+
if (typeof domain_cb === 'function') {
115+
ArrayPrototypeUnshift(args, cb);
116+
result = ReflectApply(domain_cb, this, args);
117+
} else {
118+
result = ReflectApply(cb, this, args);
119+
}
120+
121+
if (hasHooks(kAfter))
122+
emitAfterNative(asyncId);
123+
124+
return result;
125+
}
126+
127+
setCallbackTrampoline(callbackTrampoline);
128+
106129
const topLevelResource = {};
107130

108131
function executionAsyncResource() {

src/api/callback.cc

+33-7
Original file line numberDiff line numberDiff line change
@@ -158,20 +158,46 @@ MaybeLocal<Value> InternalMakeCallback(Environment* env,
158158
CHECK(!argv[i].IsEmpty());
159159
#endif
160160

161-
InternalCallbackScope scope(env, resource, asyncContext);
161+
Local<Function> hook_cb = env->async_hooks_callback_trampoline();
162+
int flags = InternalCallbackScope::kNoFlags;
163+
int hook_count = 0;
164+
if (!hook_cb.IsEmpty()) {
165+
flags = InternalCallbackScope::kSkipAsyncHooks;
166+
AsyncHooks* async_hooks = env->async_hooks();
167+
hook_count = async_hooks->fields()[AsyncHooks::kBefore] +
168+
async_hooks->fields()[AsyncHooks::kAfter];
169+
}
170+
171+
InternalCallbackScope scope(env, resource, asyncContext, flags);
162172
if (scope.Failed()) {
163173
return MaybeLocal<Value>();
164174
}
165175

166176
Local<Function> domain_cb = env->domain_callback();
167177
MaybeLocal<Value> ret;
168-
if (asyncContext.async_id != 0 || domain_cb.IsEmpty()) {
169-
ret = callback->Call(env->context(), recv, argc, argv);
170-
} else {
171-
std::vector<Local<Value>> args(1 + argc);
178+
179+
if (asyncContext.async_id != 0 && hook_count != 0) {
180+
MaybeStackBuffer<Local<Value>, 16> args(3 + argc);
181+
args[0] = v8::Number::New(env->isolate(), asyncContext.async_id);
182+
args[1] = callback;
183+
if (domain_cb.IsEmpty()) {
184+
args[2] = Undefined(env->isolate());
185+
} else {
186+
args[2] = domain_cb;
187+
}
188+
for (int i = 0; i < argc; i++) {
189+
args[i + 3] = argv[i];
190+
}
191+
ret = hook_cb->Call(env->context(), recv, args.length(), &args[0]);
192+
} else if (asyncContext.async_id == 0 && !domain_cb.IsEmpty()) {
193+
MaybeStackBuffer<Local<Value>, 16> args(1 + argc);
172194
args[0] = callback;
173-
std::copy(&argv[0], &argv[argc], args.begin() + 1);
174-
ret = domain_cb->Call(env->context(), recv, args.size(), &args[0]);
195+
for (int i = 0; i < argc; i++) {
196+
args[i + 1] = argv[i];
197+
}
198+
ret = domain_cb->Call(env->context(), recv, args.length(), &args[0]);
199+
} else {
200+
ret = callback->Call(env->context(), recv, argc, argv);
175201
}
176202

177203
if (ret.IsEmpty()) {

src/async_wrap.cc

+9
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,14 @@ void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
552552
args[0].As<Number>()->Value());
553553
}
554554

555+
void AsyncWrap::SetCallbackTrampoline(const FunctionCallbackInfo<Value>& args) {
556+
Environment* env = Environment::GetCurrent(args);
557+
558+
CHECK(args[0]->IsFunction());
559+
560+
env->set_async_hooks_callback_trampoline(args[0].As<Function>());
561+
}
562+
555563
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) {
556564
Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template();
557565
if (tmpl.IsEmpty()) {
@@ -574,6 +582,7 @@ void AsyncWrap::Initialize(Local<Object> target,
574582
HandleScope scope(isolate);
575583

576584
env->SetMethod(target, "setupHooks", SetupHooks);
585+
env->SetMethod(target, "setCallbackTrampoline", SetCallbackTrampoline);
577586
env->SetMethod(target, "pushAsyncContext", PushAsyncContext);
578587
env->SetMethod(target, "popAsyncContext", PopAsyncContext);
579588
env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);

src/async_wrap.h

+2
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ class AsyncWrap : public BaseObject {
141141
static void GetProviderType(const v8::FunctionCallbackInfo<v8::Value>& args);
142142
static void QueueDestroyAsyncId(
143143
const v8::FunctionCallbackInfo<v8::Value>& args);
144+
static void SetCallbackTrampoline(
145+
const v8::FunctionCallbackInfo<v8::Value>& args);
144146

145147
static void EmitAsyncInit(Environment* env,
146148
v8::Local<v8::Object> object,

src/env.h

+1
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ constexpr size_t kFsStatsBufferLength =
426426
#define ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) \
427427
V(async_hooks_after_function, v8::Function) \
428428
V(async_hooks_before_function, v8::Function) \
429+
V(async_hooks_callback_trampoline, v8::Function) \
429430
V(async_hooks_binding, v8::Object) \
430431
V(async_hooks_destroy_function, v8::Function) \
431432
V(async_hooks_init_function, v8::Function) \

0 commit comments

Comments
 (0)