5 #include "src/async-hooks-wrapper.h" 7 #include "src/isolate-inl.h" 11 void AsyncHooksWrap::Enable() { enabled_ =
true; }
13 void AsyncHooksWrap::Disable() { enabled_ =
false; }
16 return init_function_.Get(isolate_);
19 init_function_.
Reset(isolate_, value);
22 return before_function_.Get(isolate_);
25 before_function_.
Reset(isolate_, value);
28 return after_function_.Get(isolate_);
31 after_function_.
Reset(isolate_, value);
34 return promiseResolve_function_.Get(isolate_);
36 void AsyncHooksWrap::set_promiseResolve_function(
38 promiseResolve_function_.
Reset(isolate_, value);
41 static AsyncHooksWrap* UnwrapHook(
43 Isolate* isolate = args.GetIsolate();
44 HandleScope scope(isolate);
45 Local<Object> hook = args.This();
47 AsyncHooks* hooks = PerIsolateData::Get(isolate)->GetAsyncHooks();
49 if (!hooks->async_hook_ctor.Get(isolate)->HasInstance(hook)) {
50 isolate->ThrowException(
52 isolate,
"Invalid 'this' passed instead of AsyncHooks instance",
59 void* ptr = wrap->Value();
60 return static_cast<AsyncHooksWrap*
>(ptr);
64 AsyncHooksWrap* wrap = UnwrapHook(args);
71 AsyncHooksWrap* wrap = UnwrapHook(args);
77 async_id_t AsyncHooks::GetExecutionAsyncId()
const {
78 return asyncContexts.top().execution_async_id;
81 async_id_t AsyncHooks::GetTriggerAsyncId()
const {
82 return asyncContexts.top().trigger_async_id;
85 Local<Object> AsyncHooks::CreateHook(
87 Isolate* isolate = args.GetIsolate();
88 EscapableHandleScope handle_scope(isolate);
90 Local<Context> currentContext = isolate->GetCurrentContext();
92 if (args.Length() != 1 || !args[0]->IsObject()) {
93 isolate->ThrowException(
97 return Local<Object>();
100 AsyncHooksWrap* wrap =
new AsyncHooksWrap(isolate);
102 Local<Object> fn_obj = args[0].As<Object>();
104 #define SET_HOOK_FN(name) \ 105 Local<Value> name##_v = \ 107 ->Get(currentContext, \ 108 String::NewFromUtf8(isolate, #name, NewStringType::kNormal) \ 111 if (name##_v->IsFunction()) { \ 112 wrap->set_##name##_function(name##_v.As<Function>()); \ 118 SET_HOOK_FN(promiseResolve);
121 async_wraps_.push_back(wrap);
123 Local<Object> obj = async_hooks_templ.Get(isolate)
124 ->NewInstance(currentContext)
126 obj->SetInternalField(0, External::New(isolate, wrap));
128 return handle_scope.Escape(obj);
131 void AsyncHooks::ShellPromiseHook(PromiseHookType type, Local<Promise> promise,
132 Local<Value> parent) {
134 PerIsolateData::Get(promise->GetIsolate())->GetAsyncHooks();
136 HandleScope handle_scope(hooks->isolate_);
138 Local<Context> currentContext = hooks->isolate_->GetCurrentContext();
140 if (type == PromiseHookType::kInit) {
141 ++hooks->current_async_id;
142 Local<Integer> async_id =
143 Integer::New(hooks->isolate_, hooks->current_async_id);
146 ->HasPrivate(currentContext,
147 hooks->async_id_smb.Get(hooks->isolate_))
149 promise->SetPrivate(currentContext,
150 hooks->async_id_smb.Get(hooks->isolate_), async_id);
152 if (parent->IsPromise()) {
153 Local<Promise> parent_promise = parent.As<Promise>();
154 Local<Value> parent_async_id =
156 ->GetPrivate(hooks->isolate_->GetCurrentContext(),
157 hooks->async_id_smb.Get(hooks->isolate_))
159 promise->SetPrivate(currentContext,
160 hooks->trigger_id_smb.Get(hooks->isolate_),
163 CHECK(parent->IsUndefined());
164 Local<Integer> trigger_id = Integer::New(hooks->isolate_, 0);
165 promise->SetPrivate(currentContext,
166 hooks->trigger_id_smb.Get(hooks->isolate_),
169 }
else if (type == PromiseHookType::kBefore) {
171 ctx.execution_async_id =
173 ->GetPrivate(hooks->isolate_->GetCurrentContext(),
174 hooks->async_id_smb.Get(hooks->isolate_))
178 ctx.trigger_async_id =
180 ->GetPrivate(hooks->isolate_->GetCurrentContext(),
181 hooks->trigger_id_smb.Get(hooks->isolate_))
185 hooks->asyncContexts.push(ctx);
186 }
else if (type == PromiseHookType::kAfter) {
187 hooks->asyncContexts.pop();
190 for (AsyncHooksWrap* wrap : hooks->async_wraps_) {
191 PromiseHookDispatch(type, promise, parent, wrap, hooks);
195 void AsyncHooks::Initialize() {
196 HandleScope handle_scope(isolate_);
199 async_hook_ctor.Get(isolate_)->SetClassName(
203 async_hooks_templ.Reset(isolate_,
204 async_hook_ctor.Get(isolate_)->InstanceTemplate());
205 async_hooks_templ.Get(isolate_)->SetInternalFieldCount(1);
206 async_hooks_templ.Get(isolate_)->Set(
210 async_hooks_templ.Get(isolate_)->Set(
218 isolate_->SetPromiseHook(ShellPromiseHook);
221 void AsyncHooks::Deinitialize() {
222 isolate_->SetPromiseHook(
nullptr);
223 for (AsyncHooksWrap* wrap : async_wraps_) {
228 void AsyncHooks::PromiseHookDispatch(PromiseHookType type,
229 Local<Promise> promise,
230 Local<Value> parent, AsyncHooksWrap* wrap,
232 if (!wrap->IsEnabled()) {
236 HandleScope handle_scope(hooks->isolate_);
238 TryCatch try_catch(hooks->isolate_);
239 try_catch.SetVerbose(
true);
242 if (isolate->has_scheduled_exception()) {
243 isolate->ScheduleThrow(isolate->scheduled_exception());
245 DCHECK(try_catch.HasCaught());
246 Shell::ReportException(hooks->isolate_, &try_catch);
250 Local<Value> rcv = Undefined(hooks->isolate_);
251 Local<Context> context = hooks->isolate_->GetCurrentContext();
252 Local<Value> async_id =
253 promise->GetPrivate(context, hooks->async_id_smb.Get(hooks->isolate_))
255 Local<Value> args[1] = {async_id};
259 MaybeLocal<Value> result;
262 if (type == PromiseHookType::kInit) {
263 if (!wrap->init_function().IsEmpty()) {
264 Local<Value> initArgs[4] = {
270 ->GetPrivate(context, hooks->trigger_id_smb.Get(hooks->isolate_))
273 result = wrap->init_function()->Call(context, rcv, 4, initArgs);
275 }
else if (type == PromiseHookType::kBefore) {
276 if (!wrap->before_function().IsEmpty()) {
277 result = wrap->before_function()->Call(context, rcv, 1, args);
279 }
else if (type == PromiseHookType::kAfter) {
280 if (!wrap->after_function().IsEmpty()) {
281 result = wrap->after_function()->Call(context, rcv, 1, args);
283 }
else if (type == PromiseHookType::kResolve) {
284 if (!wrap->promiseResolve_function().IsEmpty()) {
285 result = wrap->promiseResolve_function()->Call(context, rcv, 1, args);
289 if (try_catch.HasCaught()) {
290 Shell::ReportException(hooks->isolate_, &try_catch);
static V8_INLINE Local< T > Cast(Local< S > that)
static Local< Private > New(Isolate *isolate, Local< String > name=Local< String >())
static V8_WARN_UNUSED_RESULT MaybeLocal< String > NewFromUtf8(Isolate *isolate, const char *data, v8::NewStringType type, int length=-1)
static Local< FunctionTemplate > New(Isolate *isolate, FunctionCallback callback=nullptr, Local< Value > data=Local< Value >(), Local< Signature > signature=Local< Signature >(), int length=0, ConstructorBehavior behavior=ConstructorBehavior::kAllow, SideEffectType side_effect_type=SideEffectType::kHasSideEffect)