v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
async-hooks-wrapper.cc
Go to the documentation of this file.
1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
10#include "include/v8-template.h"
11#include "src/api/api-inl.h"
12#include "src/api/api.h"
13#include "src/d8/d8.h"
16
17namespace v8 {
18
19namespace {
20std::shared_ptr<AsyncHooksWrap> UnwrapHook(
23 v8::Isolate* v8_isolate = info.GetIsolate();
24 HandleScope scope(v8_isolate);
25 Local<Object> hook = info.This();
26
27 AsyncHooks* hooks = PerIsolateData::Get(v8_isolate)->GetAsyncHooks();
28
29 if (!hooks->async_hook_ctor.Get(v8_isolate)->HasInstance(hook)) {
30 v8_isolate->ThrowError(
31 "Invalid 'this' passed instead of AsyncHooks instance");
32 return nullptr;
33 }
34
36 Utils::OpenDirectHandle(*hook->GetInternalField(0));
37 return Cast<i::Managed<AsyncHooksWrap>>(handle)->get();
38}
39
40void EnableHook(const v8::FunctionCallbackInfo<v8::Value>& info) {
42 auto wrap = UnwrapHook(info);
43 if (wrap) wrap->Enable();
44}
45
46void DisableHook(const v8::FunctionCallbackInfo<v8::Value>& info) {
48 auto wrap = UnwrapHook(info);
49 if (wrap) wrap->Disable();
50}
51
52} // namespace
53
54AsyncHooks::AsyncHooks(v8::Isolate* v8_isolate) : v8_isolate_(v8_isolate) {
55 AsyncContext ctx;
56 ctx.execution_async_id = 1;
57 ctx.trigger_async_id = 0;
58 asyncContexts.push(ctx);
60
61 HandleScope handle_scope(v8_isolate_);
62
65 ->SetClassName(String::NewFromUtf8Literal(v8_isolate_, "AsyncHook"));
66
68 async_hook_ctor.Get(v8_isolate_)->InstanceTemplate());
69 async_hooks_templ.Get(v8_isolate_)->SetInternalFieldCount(1);
71 ->Set(v8_isolate_, "enable",
74 ->Set(v8_isolate_, "disable",
76
79
81}
82
87
89
91
117
119 return asyncContexts.top().execution_async_id;
120}
121
123 return asyncContexts.top().trigger_async_id;
124}
125
129 v8::Isolate* v8_isolate = info.GetIsolate();
130 EscapableHandleScope handle_scope(v8_isolate);
131
132 if (v8_isolate->IsExecutionTerminating()) {
133 return Local<Object>();
134 }
135
136 Local<Context> currentContext = v8_isolate->GetCurrentContext();
137
138 if (info.Length() != 1 || !info[0]->IsObject()) {
139 v8_isolate->ThrowError("Invalid arguments passed to createHook");
140 return Local<Object>();
141 }
142
143 std::shared_ptr<AsyncHooksWrap> wrap =
144 std::make_shared<AsyncHooksWrap>(v8_isolate);
145
146 Local<Object> fn_obj = info[0].As<Object>();
147
148 v8::TryCatch try_catch(v8_isolate);
149#define SET_HOOK_FN(name) \
150 MaybeLocal<Value> name##_maybe_func = fn_obj->Get( \
151 currentContext, String::NewFromUtf8Literal(v8_isolate, #name)); \
152 Local<Value> name##_func; \
153 if (name##_maybe_func.ToLocal(&name##_func) && name##_func->IsFunction()) { \
154 wrap->set_##name##_function(name##_func.As<Function>()); \
155 } else { \
156 try_catch.ReThrow(); \
157 }
158
159 SET_HOOK_FN(init);
160 SET_HOOK_FN(before);
161 SET_HOOK_FN(after);
162 SET_HOOK_FN(promiseResolve);
163#undef SET_HOOK_FN
164
165 Local<Object> obj = async_hooks_templ.Get(v8_isolate)
166 ->NewInstance(currentContext)
167 .ToLocalChecked();
169 reinterpret_cast<i::Isolate*>(v8_isolate), sizeof(AsyncHooksWrap), wrap);
170 obj->SetInternalField(0, Utils::ToLocal(managed));
171
172 async_wraps_.push_back(std::move(wrap));
173
174 return handle_scope.Escape(obj);
175}
176
178 Local<Value> parent) {
179 v8::Isolate* v8_isolate = promise->GetIsolate();
180 AsyncHooks* hooks = PerIsolateData::Get(v8_isolate)->GetAsyncHooks();
181 if (v8_isolate->IsExecutionTerminating() || hooks->skip_after_termination_) {
182 hooks->skip_after_termination_ = true;
183 return;
184 }
185 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
186
187 HandleScope handle_scope(v8_isolate);
189 // Keep track of any previously thrown exception.
190 if (i_isolate->has_exception()) {
191 exception = direct_handle(i_isolate->exception(), i_isolate);
192 }
193 {
194 TryCatch try_catch(v8_isolate);
195 try_catch.SetVerbose(true);
196
197 Local<Context> currentContext = v8_isolate->GetCurrentContext();
198 DCHECK(!currentContext.IsEmpty());
199
200 if (type == PromiseHookType::kInit) {
201 ++hooks->current_async_id;
202 Local<Integer> async_id =
203 Integer::New(v8_isolate, hooks->current_async_id);
204 CHECK(!promise
205 ->HasPrivate(currentContext,
206 hooks->async_id_symbol.Get(v8_isolate))
207 .ToChecked());
208 promise->SetPrivate(currentContext,
209 hooks->async_id_symbol.Get(v8_isolate), async_id);
210
211 if (parent->IsPromise()) {
212 Local<Promise> parent_promise = parent.As<Promise>();
213 Local<Value> parent_async_id =
214 parent_promise
215 ->GetPrivate(currentContext,
216 hooks->async_id_symbol.Get(v8_isolate))
217 .ToLocalChecked();
218 promise->SetPrivate(currentContext,
219 hooks->trigger_id_symbol.Get(v8_isolate),
220 parent_async_id);
221 } else {
222 CHECK(parent->IsUndefined());
223 promise->SetPrivate(currentContext,
224 hooks->trigger_id_symbol.Get(v8_isolate),
225 Integer::New(v8_isolate, 0));
226 }
227 } else if (type == PromiseHookType::kBefore) {
228 AsyncContext ctx;
230 promise
231 ->GetPrivate(currentContext,
232 hooks->async_id_symbol.Get(v8_isolate))
233 .ToLocalChecked()
234 .As<Integer>()
235 ->Value();
236 ctx.trigger_async_id =
237 promise
238 ->GetPrivate(currentContext,
239 hooks->trigger_id_symbol.Get(v8_isolate))
240 .ToLocalChecked()
241 .As<Integer>()
242 ->Value();
243 hooks->asyncContexts.push(ctx);
244 } else if (type == PromiseHookType::kAfter) {
245 hooks->asyncContexts.pop();
246 }
247 if (!i::StackLimitCheck{i_isolate}.HasOverflowed()) {
248 for (size_t i = 0; i < hooks->async_wraps_.size(); ++i) {
249 std::shared_ptr<AsyncHooksWrap> wrap = hooks->async_wraps_[i];
250 PromiseHookDispatch(type, promise, parent, *wrap, hooks);
251 if (try_catch.HasCaught()) break;
252 }
253 if (try_catch.HasCaught()) Shell::ReportException(v8_isolate, try_catch);
254 }
255 }
256 if (!exception.is_null()) {
257 i_isolate->set_exception(*exception);
258 }
259}
260
262 Local<Promise> promise,
263 Local<Value> parent,
264 const AsyncHooksWrap& wrap,
265 AsyncHooks* hooks) {
266 if (!wrap.IsEnabled()) return;
267 v8::Isolate* v8_isolate = hooks->v8_isolate_;
268 if (v8_isolate->IsExecutionTerminating()) return;
269 HandleScope handle_scope(v8_isolate);
270
271 Local<Value> rcv = Undefined(v8_isolate);
272 Local<Context> context = v8_isolate->GetCurrentContext();
273 Local<Value> async_id =
274 promise->GetPrivate(context, hooks->async_id_symbol.Get(v8_isolate))
275 .ToLocalChecked();
276 Local<Value> args[1] = {async_id};
277
278 switch (type) {
280 if (!wrap.init_function().IsEmpty()) {
281 Local<Value> initArgs[4] = {
282 async_id, String::NewFromUtf8Literal(v8_isolate, "PROMISE"),
283 promise
284 ->GetPrivate(context, hooks->trigger_id_symbol.Get(v8_isolate))
285 .ToLocalChecked(),
286 promise};
287 USE(wrap.init_function()->Call(context, rcv, 4, initArgs));
288 }
289 break;
291 if (!wrap.before_function().IsEmpty()) {
292 USE(wrap.before_function()->Call(context, rcv, 1, args));
293 }
294 break;
296 if (!wrap.after_function().IsEmpty()) {
297 USE(wrap.after_function()->Call(context, rcv, 1, args));
298 }
299 break;
301 if (!wrap.promiseResolve_function().IsEmpty()) {
302 USE(wrap.promiseResolve_function()->Call(context, rcv, 1, args));
303 }
304 }
305}
306
307} // namespace v8
#define SET_HOOK_FN(name)
void set_before_function(v8::Local< v8::Function > value)
void set_after_function(v8::Local< v8::Function > value)
Persistent< v8::Function > after_function_
void set_promiseResolve_function(v8::Local< v8::Function > value)
v8::Local< v8::Function > after_function() const
v8::Local< v8::Function > before_function() const
v8::Local< v8::Function > promiseResolve_function() const
void set_init_function(v8::Local< v8::Function > value)
v8::Local< v8::Function > init_function() const
Persistent< v8::Function > init_function_
Persistent< v8::Function > promiseResolve_function_
Persistent< v8::Function > before_function_
std::stack< AsyncContext > asyncContexts
static void PromiseHookDispatch(PromiseHookType type, Local< Promise > promise, Local< Value > parent, const AsyncHooksWrap &wrap, AsyncHooks *hooks)
Persistent< ObjectTemplate > async_hooks_templ
v8::Isolate * v8_isolate_
Persistent< FunctionTemplate > async_hook_ctor
async_id_t current_async_id
Persistent< Private > trigger_id_symbol
std::vector< std::shared_ptr< AsyncHooksWrap > > async_wraps_
async_id_t GetTriggerAsyncId() const
AsyncHooks(Isolate *isolate)
async_id_t GetExecutionAsyncId() const
Persistent< Private > async_id_symbol
static void ShellPromiseHook(PromiseHookType type, Local< Promise > promise, Local< Value > parent)
Local< Object > CreateHook(const v8::FunctionCallbackInfo< v8::Value > &info)
V8_INLINE Local< T > Escape(Local< T > value)
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, const CFunction *c_function=nullptr, uint16_t instance_type=0, uint16_t allowed_receiver_instance_type_range_start=0, uint16_t allowed_receiver_instance_type_range_end=0)
Definition api.cc:1101
static Local< Integer > New(Isolate *isolate, int32_t value)
Definition api.cc:9568
void SetPromiseHook(PromiseHook hook)
Definition api.cc:10472
Local< Value > ThrowError(const char(&message)[N])
bool IsExecutionTerminating()
Definition api.cc:9893
Local< Context > GetCurrentContext()
Definition api.cc:9756
V8_INLINE Local< S > As() const
AsyncHooks * GetAsyncHooks()
Definition d8.h:329
static PerIsolateData * Get(Isolate *isolate)
Definition d8.h:300
V8_INLINE Local< T > Get(Isolate *isolate) const
static Local< Private > New(Isolate *isolate, Local< String > name=Local< String >())
Definition api.cc:9538
static void ReportException(Isolate *isolate, Local< Message > message, Local< Value > exception)
Definition d8.cc:3648
static V8_WARN_UNUSED_RESULT Local< String > NewFromUtf8Literal(Isolate *isolate, const char(&literal)[N], NewStringType type=NewStringType::kNormal)
void SetVerbose(bool value)
Definition api.cc:2856
bool HasCaught() const
Definition api.cc:2781
static v8::internal::DirectHandle< To > OpenDirectHandle(v8::Local< From > handle)
Definition api.h:279
Tagged< Object > exception()
void set_exception(Tagged< Object > exception_obj)
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
bool V8_EXPORT ValidateCallbackInfo(const FunctionCallbackInfo< void > &info)
Definition api.cc:12301
V8_INLINE Local< Primitive > Undefined(Isolate *isolate)
double async_id_t
PromiseHookType
Definition v8-promise.h:141
#define CHECK(condition)
Definition logging.h:124
#define DCHECK(condition)
Definition logging.h:482
#define USE(...)
Definition macros.h:293
async_id_t execution_async_id