Skip to content

Commit 0d79c53

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 524b230 commit 0d79c53

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,13 +1,16 @@
11
'use strict';
22

33
const {
4+
ArrayPrototypeUnshift,
45
Error,
56
FunctionPrototypeBind,
67
ObjectDefineProperty,
8+
ReflectApply,
79
Symbol,
810
} = primordials;
911

1012
const async_wrap = internalBinding('async_wrap');
13+
const { setCallbackTrampoline } = async_wrap;
1114
/* async_hook_fields is a Uint32Array wrapping the uint32_t array of
1215
* Environment::AsyncHooks::fields_[]. Each index tracks the number of active
1316
* hooks for each type.
@@ -100,6 +103,26 @@ const emitDestroyNative = emitHookFactory(destroy_symbol, 'emitDestroyNative');
100103
const emitPromiseResolveNative =
101104
emitHookFactory(promise_resolve_symbol, 'emitPromiseResolveNative');
102105

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

105128
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
@@ -469,6 +469,14 @@ void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) {
469469
args[0].As<Number>()->Value());
470470
}
471471

472+
void AsyncWrap::SetCallbackTrampoline(const FunctionCallbackInfo<Value>& args) {
473+
Environment* env = Environment::GetCurrent(args);
474+
475+
CHECK(args[0]->IsFunction());
476+
477+
env->set_async_hooks_callback_trampoline(args[0].As<Function>());
478+
}
479+
472480
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) {
473481
Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template();
474482
if (tmpl.IsEmpty()) {
@@ -491,6 +499,7 @@ void AsyncWrap::Initialize(Local<Object> target,
491499
HandleScope scope(isolate);
492500

493501
env->SetMethod(target, "setupHooks", SetupHooks);
502+
env->SetMethod(target, "setCallbackTrampoline", SetCallbackTrampoline);
494503
env->SetMethod(target, "pushAsyncContext", PushAsyncContext);
495504
env->SetMethod(target, "popAsyncContext", PopAsyncContext);
496505
env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId);

src/async_wrap.h

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

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

src/env.h

+1
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,7 @@ constexpr size_t kFsStatsBufferLength =
434434
V(as_callback_data, v8::Object) \
435435
V(async_hooks_after_function, v8::Function) \
436436
V(async_hooks_before_function, v8::Function) \
437+
V(async_hooks_callback_trampoline, v8::Function) \
437438
V(async_hooks_binding, v8::Object) \
438439
V(async_hooks_destroy_function, v8::Function) \
439440
V(async_hooks_init_function, v8::Function) \

0 commit comments

Comments
 (0)