GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
// Copyright Joyent, Inc. and other Node contributors. |
||
2 |
// |
||
3 |
// Permission is hereby granted, free of charge, to any person obtaining a |
||
4 |
// copy of this software and associated documentation files (the |
||
5 |
// "Software"), to deal in the Software without restriction, including |
||
6 |
// without limitation the rights to use, copy, modify, merge, publish, |
||
7 |
// distribute, sublicense, and/or sell copies of the Software, and to permit |
||
8 |
// persons to whom the Software is furnished to do so, subject to the |
||
9 |
// following conditions: |
||
10 |
// |
||
11 |
// The above copyright notice and this permission notice shall be included |
||
12 |
// in all copies or substantial portions of the Software. |
||
13 |
// |
||
14 |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
||
15 |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
16 |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
||
17 |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
||
18 |
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
||
19 |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
||
20 |
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
21 |
|||
22 |
#include "async_wrap.h" // NOLINT(build/include_inline) |
||
23 |
#include "async_wrap-inl.h" |
||
24 |
#include "env-inl.h" |
||
25 |
#include "node_errors.h" |
||
26 |
#include "tracing/traced_value.h" |
||
27 |
#include "util-inl.h" |
||
28 |
|||
29 |
#include "v8.h" |
||
30 |
#include "v8-profiler.h" |
||
31 |
|||
32 |
using v8::Context; |
||
33 |
using v8::DontDelete; |
||
34 |
using v8::EscapableHandleScope; |
||
35 |
using v8::Function; |
||
36 |
using v8::FunctionCallbackInfo; |
||
37 |
using v8::FunctionTemplate; |
||
38 |
using v8::Global; |
||
39 |
using v8::HandleScope; |
||
40 |
using v8::Integer; |
||
41 |
using v8::Isolate; |
||
42 |
using v8::Local; |
||
43 |
using v8::MaybeLocal; |
||
44 |
using v8::Number; |
||
45 |
using v8::Object; |
||
46 |
using v8::ObjectTemplate; |
||
47 |
using v8::Promise; |
||
48 |
using v8::PromiseHookType; |
||
49 |
using v8::PropertyAttribute; |
||
50 |
using v8::PropertyCallbackInfo; |
||
51 |
using v8::ReadOnly; |
||
52 |
using v8::String; |
||
53 |
using v8::TryCatch; |
||
54 |
using v8::Uint32; |
||
55 |
using v8::Undefined; |
||
56 |
using v8::Value; |
||
57 |
using v8::WeakCallbackInfo; |
||
58 |
using v8::WeakCallbackType; |
||
59 |
|||
60 |
using TryCatchScope = node::errors::TryCatchScope; |
||
61 |
|||
62 |
namespace node { |
||
63 |
|||
64 |
static const char* const provider_names[] = { |
||
65 |
#define V(PROVIDER) \ |
||
66 |
#PROVIDER, |
||
67 |
NODE_ASYNC_PROVIDER_TYPES(V) |
||
68 |
#undef V |
||
69 |
}; |
||
70 |
|||
71 |
|||
72 |
✗✓ | 194 |
struct AsyncWrapObject : public AsyncWrap { |
73 |
97 |
static inline void New(const FunctionCallbackInfo<Value>& args) { |
|
74 |
97 |
Environment* env = Environment::GetCurrent(args); |
|
75 |
✗✓ | 97 |
CHECK(args.IsConstructCall()); |
76 |
✗✓ | 194 |
CHECK(env->async_wrap_object_ctor_template()->HasInstance(args.This())); |
77 |
✗✓ | 194 |
CHECK(args[0]->IsUint32()); |
78 |
291 |
auto type = static_cast<ProviderType>(args[0].As<Uint32>()->Value()); |
|
79 |
97 |
new AsyncWrapObject(env, args.This(), type); |
|
80 |
97 |
} |
|
81 |
|||
82 |
97 |
inline AsyncWrapObject(Environment* env, Local<Object> object, |
|
83 |
97 |
ProviderType type) : AsyncWrap(env, object, type) {} |
|
84 |
|||
85 |
3 |
SET_NO_MEMORY_INFO() |
|
86 |
3 |
SET_MEMORY_INFO_NAME(AsyncWrapObject) |
|
87 |
3 |
SET_SELF_SIZE(AsyncWrapObject) |
|
88 |
}; |
||
89 |
|||
90 |
22209 |
void AsyncWrap::DestroyAsyncIdsCallback(Environment* env) { |
|
91 |
22209 |
Local<Function> fn = env->async_hooks_destroy_function(); |
|
92 |
|||
93 |
22209 |
TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal); |
|
94 |
|||
95 |
✓✓✓✗ |
22211 |
do { |
96 |
22211 |
std::vector<double> destroy_async_id_list; |
|
97 |
22211 |
destroy_async_id_list.swap(*env->destroy_async_id_list()); |
|
98 |
✗✓ | 22211 |
if (!env->can_call_into_js()) return; |
99 |
✓✗✓✓ |
93140 |
for (auto async_id : destroy_async_id_list) { |
100 |
// Want each callback to be cleaned up after itself, instead of cleaning |
||
101 |
// them all up after the while() loop completes. |
||
102 |
70929 |
HandleScope scope(env->isolate()); |
|
103 |
70929 |
Local<Value> async_id_value = Number::New(env->isolate(), async_id); |
|
104 |
MaybeLocal<Value> ret = fn->Call( |
||
105 |
212787 |
env->context(), Undefined(env->isolate()), 1, &async_id_value); |
|
106 |
|||
107 |
✗✓ | 70929 |
if (ret.IsEmpty()) |
108 |
return; |
||
109 |
93140 |
} |
|
110 |
44420 |
} while (!env->destroy_async_id_list()->empty()); |
|
111 |
} |
||
112 |
|||
113 |
2218738 |
void Emit(Environment* env, double async_id, AsyncHooks::Fields type, |
|
114 |
Local<Function> fn) { |
||
115 |
2218738 |
AsyncHooks* async_hooks = env->async_hooks(); |
|
116 |
|||
117 |
✓✓✗✓ ✓✓✓✓ |
2218754 |
if (async_hooks->fields()[type] == 0 || !env->can_call_into_js()) |
118 |
4428541 |
return; |
|
119 |
|||
120 |
9137 |
HandleScope handle_scope(env->isolate()); |
|
121 |
9137 |
Local<Value> async_id_value = Number::New(env->isolate(), async_id); |
|
122 |
18274 |
TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal); |
|
123 |
36548 |
USE(fn->Call(env->context(), Undefined(env->isolate()), 1, &async_id_value)); |
|
124 |
} |
||
125 |
|||
126 |
|||
127 |
968 |
void AsyncWrap::EmitPromiseResolve(Environment* env, double async_id) { |
|
128 |
Emit(env, async_id, AsyncHooks::kPromiseResolve, |
||
129 |
968 |
env->async_hooks_promise_resolve_function()); |
|
130 |
968 |
} |
|
131 |
|||
132 |
|||
133 |
1106104 |
void AsyncWrap::EmitTraceEventBefore() { |
|
134 |
✗✗✗✓ ✗✓✓✗ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✗ |
1106104 |
switch (provider_type()) { |
135 |
#define V(PROVIDER) \ |
||
136 |
case PROVIDER_ ## PROVIDER: \ |
||
137 |
TRACE_EVENT_NESTABLE_ASYNC_BEGIN0( \ |
||
138 |
TRACING_CATEGORY_NODE1(async_hooks), \ |
||
139 |
#PROVIDER "_CALLBACK", static_cast<int64_t>(get_async_id())); \ |
||
140 |
break; |
||
141 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✗✓ ✗✗✗✗ ✓✓✗✓ ✓✓✗✓ ✗✗✗✗ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✓✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✓✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ |
2212208 |
NODE_ASYNC_PROVIDER_TYPES(V) |
142 |
#undef V |
||
143 |
default: |
||
144 |
UNREACHABLE(); |
||
145 |
} |
||
146 |
1106104 |
} |
|
147 |
|||
148 |
|||
149 |
1108978 |
void AsyncWrap::EmitBefore(Environment* env, double async_id) { |
|
150 |
Emit(env, async_id, AsyncHooks::kBefore, |
||
151 |
1108978 |
env->async_hooks_before_function()); |
|
152 |
1108982 |
} |
|
153 |
|||
154 |
|||
155 |
1106065 |
void AsyncWrap::EmitTraceEventAfter(ProviderType type, double async_id) { |
|
156 |
✗✗✗✓ ✗✓✓✗ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✗ |
1106065 |
switch (type) { |
157 |
#define V(PROVIDER) \ |
||
158 |
case PROVIDER_ ## PROVIDER: \ |
||
159 |
TRACE_EVENT_NESTABLE_ASYNC_END0( \ |
||
160 |
TRACING_CATEGORY_NODE1(async_hooks), \ |
||
161 |
#PROVIDER "_CALLBACK", static_cast<int64_t>(async_id)); \ |
||
162 |
break; |
||
163 |
✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✓✓✗✓ ✗✗✗✗ ✓✓✗✓ ✓✓✗✓ ✗✗✗✗ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✓✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✓✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ |
2212132 |
NODE_ASYNC_PROVIDER_TYPES(V) |
164 |
#undef V |
||
165 |
default: |
||
166 |
UNREACHABLE(); |
||
167 |
} |
||
168 |
1106066 |
} |
|
169 |
|||
170 |
|||
171 |
1108913 |
void AsyncWrap::EmitAfter(Environment* env, double async_id) { |
|
172 |
// If the user's callback failed then the after() hooks will be called at the |
||
173 |
// end of _fatalException(). |
||
174 |
Emit(env, async_id, AsyncHooks::kAfter, |
||
175 |
1108913 |
env->async_hooks_after_function()); |
|
176 |
1108917 |
} |
|
177 |
|||
178 |
✗✓ | 1828 |
class PromiseWrap : public AsyncWrap { |
179 |
public: |
||
180 |
983 |
PromiseWrap(Environment* env, Local<Object> object, bool silent) |
|
181 |
983 |
: AsyncWrap(env, object, PROVIDER_PROMISE, kInvalidAsyncId, silent) { |
|
182 |
983 |
MakeWeak(); |
|
183 |
983 |
} |
|
184 |
|||
185 |
11 |
SET_NO_MEMORY_INFO() |
|
186 |
11 |
SET_MEMORY_INFO_NAME(PromiseWrap) |
|
187 |
11 |
SET_SELF_SIZE(PromiseWrap) |
|
188 |
|||
189 |
static constexpr int kIsChainedPromiseField = 1; |
||
190 |
static constexpr int kInternalFieldCount = 2; |
||
191 |
|||
192 |
static PromiseWrap* New(Environment* env, |
||
193 |
Local<Promise> promise, |
||
194 |
PromiseWrap* parent_wrap, |
||
195 |
bool silent); |
||
196 |
static void getIsChainedPromise(Local<String> property, |
||
197 |
const PropertyCallbackInfo<Value>& info); |
||
198 |
}; |
||
199 |
|||
200 |
983 |
PromiseWrap* PromiseWrap::New(Environment* env, |
|
201 |
Local<Promise> promise, |
||
202 |
PromiseWrap* parent_wrap, |
||
203 |
bool silent) { |
||
204 |
Local<Object> obj; |
||
205 |
✗✓ | 2949 |
if (!env->promise_wrap_template()->NewInstance(env->context()).ToLocal(&obj)) |
206 |
return nullptr; |
||
207 |
obj->SetInternalField(PromiseWrap::kIsChainedPromiseField, |
||
208 |
519 |
parent_wrap != nullptr ? v8::True(env->isolate()) |
|
209 |
✓✓ | 2430 |
: v8::False(env->isolate())); |
210 |
✗✓ | 1966 |
CHECK_NULL(promise->GetAlignedPointerFromInternalField(0)); |
211 |
983 |
promise->SetInternalField(0, obj); |
|
212 |
983 |
return new PromiseWrap(env, obj, silent); |
|
213 |
} |
||
214 |
|||
215 |
8 |
void PromiseWrap::getIsChainedPromise(Local<String> property, |
|
216 |
const PropertyCallbackInfo<Value>& info) { |
||
217 |
info.GetReturnValue().Set( |
||
218 |
32 |
info.Holder()->GetInternalField(kIsChainedPromiseField)); |
|
219 |
8 |
} |
|
220 |
|||
221 |
3416 |
static PromiseWrap* extractPromiseWrap(Local<Promise> promise) { |
|
222 |
6832 |
Local<Value> resource_object_value = promise->GetInternalField(0); |
|
223 |
✓✓ | 3416 |
if (resource_object_value->IsObject()) { |
224 |
2433 |
return Unwrap<PromiseWrap>(resource_object_value.As<Object>()); |
|
225 |
} |
||
226 |
983 |
return nullptr; |
|
227 |
} |
||
228 |
|||
229 |
2897 |
static void PromiseHook(PromiseHookType type, Local<Promise> promise, |
|
230 |
Local<Value> parent) { |
||
231 |
2897 |
Local<Context> context = promise->CreationContext(); |
|
232 |
|||
233 |
2897 |
Environment* env = Environment::GetCurrent(context); |
|
234 |
✗✓ | 2897 |
if (env == nullptr) return; |
235 |
TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment), |
||
236 |
2897 |
"EnvPromiseHook", env); |
|
237 |
|||
238 |
2897 |
PromiseWrap* wrap = extractPromiseWrap(promise); |
|
239 |
✓✓✓✓ |
2897 |
if (type == PromiseHookType::kInit || wrap == nullptr) { |
240 |
981 |
bool silent = type != PromiseHookType::kInit; |
|
241 |
|||
242 |
// set parent promise's async Id as this promise's triggerAsyncId |
||
243 |
✓✓ | 981 |
if (parent->IsPromise()) { |
244 |
// parent promise exists, current promise |
||
245 |
// is a chained promise, so we set parent promise's id as |
||
246 |
// current promise's triggerAsyncId |
||
247 |
519 |
Local<Promise> parent_promise = parent.As<Promise>(); |
|
248 |
519 |
PromiseWrap* parent_wrap = extractPromiseWrap(parent_promise); |
|
249 |
✓✓ | 519 |
if (parent_wrap == nullptr) { |
250 |
2 |
parent_wrap = PromiseWrap::New(env, parent_promise, nullptr, true); |
|
251 |
✗✓ | 2 |
if (parent_wrap == nullptr) return; |
252 |
} |
||
253 |
|||
254 |
519 |
AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(parent_wrap); |
|
255 |
519 |
wrap = PromiseWrap::New(env, promise, parent_wrap, silent); |
|
256 |
} else { |
||
257 |
462 |
wrap = PromiseWrap::New(env, promise, nullptr, silent); |
|
258 |
} |
||
259 |
} |
||
260 |
|||
261 |
✗✓ | 2897 |
if (wrap == nullptr) return; |
262 |
|||
263 |
✓✓ | 2897 |
if (type == PromiseHookType::kBefore) { |
264 |
env->async_hooks()->push_async_ids( |
||
265 |
479 |
wrap->get_async_id(), wrap->get_trigger_async_id()); |
|
266 |
479 |
wrap->EmitTraceEventBefore(); |
|
267 |
479 |
AsyncWrap::EmitBefore(wrap->env(), wrap->get_async_id()); |
|
268 |
✓✓ | 2418 |
} else if (type == PromiseHookType::kAfter) { |
269 |
483 |
wrap->EmitTraceEventAfter(wrap->provider_type(), wrap->get_async_id()); |
|
270 |
483 |
AsyncWrap::EmitAfter(wrap->env(), wrap->get_async_id()); |
|
271 |
✓✓ | 483 |
if (env->execution_async_id() == wrap->get_async_id()) { |
272 |
// This condition might not be true if async_hooks was enabled during |
||
273 |
// the promise callback execution. |
||
274 |
// Popping it off the stack can be skipped in that case, because it is |
||
275 |
// known that it would correspond to exactly one call with |
||
276 |
// PromiseHookType::kBefore that was not witnessed by the PromiseHook. |
||
277 |
478 |
env->async_hooks()->pop_async_id(wrap->get_async_id()); |
|
278 |
} |
||
279 |
✓✓ | 1935 |
} else if (type == PromiseHookType::kResolve) { |
280 |
✓✗ | 968 |
AsyncWrap::EmitPromiseResolve(wrap->env(), wrap->get_async_id()); |
281 |
2897 |
} |
|
282 |
} |
||
283 |
|||
284 |
|||
285 |
5103 |
static void SetupHooks(const FunctionCallbackInfo<Value>& args) { |
|
286 |
5103 |
Environment* env = Environment::GetCurrent(args); |
|
287 |
|||
288 |
✗✓ | 10206 |
CHECK(args[0]->IsObject()); |
289 |
|||
290 |
// All of init, before, after, destroy are supplied by async_hooks |
||
291 |
// internally, so this should every only be called once. At which time all |
||
292 |
// the functions should be set. Detect this by checking if init !IsEmpty(). |
||
293 |
✗✓ | 10206 |
CHECK(env->async_hooks_init_function().IsEmpty()); |
294 |
|||
295 |
10206 |
Local<Object> fn_obj = args[0].As<Object>(); |
|
296 |
|||
297 |
#define SET_HOOK_FN(name) \ |
||
298 |
do { \ |
||
299 |
Local<Value> v = \ |
||
300 |
fn_obj->Get(env->context(), \ |
||
301 |
FIXED_ONE_BYTE_STRING(env->isolate(), #name)) \ |
||
302 |
.ToLocalChecked(); \ |
||
303 |
CHECK(v->IsFunction()); \ |
||
304 |
env->set_async_hooks_##name##_function(v.As<Function>()); \ |
||
305 |
} while (0) |
||
306 |
|||
307 |
✗✓ | 30618 |
SET_HOOK_FN(init); |
308 |
✗✓ | 30618 |
SET_HOOK_FN(before); |
309 |
✗✓ | 30618 |
SET_HOOK_FN(after); |
310 |
✗✓ | 30618 |
SET_HOOK_FN(destroy); |
311 |
✗✓ | 30618 |
SET_HOOK_FN(promise_resolve); |
312 |
#undef SET_HOOK_FN |
||
313 |
|||
314 |
{ |
||
315 |
Local<FunctionTemplate> ctor = |
||
316 |
5103 |
FunctionTemplate::New(env->isolate()); |
|
317 |
10206 |
ctor->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "PromiseWrap")); |
|
318 |
5103 |
Local<ObjectTemplate> promise_wrap_template = ctor->InstanceTemplate(); |
|
319 |
promise_wrap_template->SetInternalFieldCount( |
||
320 |
5103 |
PromiseWrap::kInternalFieldCount); |
|
321 |
promise_wrap_template->SetAccessor( |
||
322 |
FIXED_ONE_BYTE_STRING(env->isolate(), "isChainedPromise"), |
||
323 |
10206 |
PromiseWrap::getIsChainedPromise); |
|
324 |
5103 |
env->set_promise_wrap_template(promise_wrap_template); |
|
325 |
} |
||
326 |
5103 |
} |
|
327 |
|||
328 |
|||
329 |
266 |
static void EnablePromiseHook(const FunctionCallbackInfo<Value>& args) { |
|
330 |
266 |
args.GetIsolate()->SetPromiseHook(PromiseHook); |
|
331 |
266 |
} |
|
332 |
|||
333 |
|||
334 |
61 |
static void DisablePromiseHook(const FunctionCallbackInfo<Value>& args) { |
|
335 |
61 |
Isolate* isolate = args.GetIsolate(); |
|
336 |
|||
337 |
// The per-Isolate API provides no way of knowing whether there are multiple |
||
338 |
// users of the PromiseHook. That hopefully goes away when V8 introduces |
||
339 |
// a per-context API. |
||
340 |
61 |
isolate->SetPromiseHook(nullptr); |
|
341 |
61 |
} |
|
342 |
|||
343 |
|||
344 |
25020 |
class DestroyParam { |
|
345 |
public: |
||
346 |
double asyncId; |
||
347 |
Environment* env; |
||
348 |
Global<Object> target; |
||
349 |
Global<Object> propBag; |
||
350 |
}; |
||
351 |
|||
352 |
4159 |
void AsyncWrap::WeakCallback(const WeakCallbackInfo<DestroyParam>& info) { |
|
353 |
4159 |
HandleScope scope(info.GetIsolate()); |
|
354 |
|||
355 |
✓✗ | 8318 |
std::unique_ptr<DestroyParam> p{info.GetParameter()}; |
356 |
Local<Object> prop_bag = PersistentToLocal::Default(info.GetIsolate(), |
||
357 |
8318 |
p->propBag); |
|
358 |
Local<Value> val; |
||
359 |
|||
360 |
✗✓ | 20795 |
if (!prop_bag->Get(p->env->context(), p->env->destroyed_string()) |
361 |
12477 |
.ToLocal(&val)) { |
|
362 |
4159 |
return; |
|
363 |
} |
||
364 |
|||
365 |
✓✓ | 4159 |
if (val->IsFalse()) { |
366 |
✓✗ | 4158 |
AsyncWrap::EmitDestroy(p->env, p->asyncId); |
367 |
4159 |
} |
|
368 |
// unique_ptr goes out of scope here and pointer is deleted. |
||
369 |
} |
||
370 |
|||
371 |
|||
372 |
4181 |
static void RegisterDestroyHook(const FunctionCallbackInfo<Value>& args) { |
|
373 |
✗✓ | 8362 |
CHECK(args[0]->IsObject()); |
374 |
✗✓ | 8362 |
CHECK(args[1]->IsNumber()); |
375 |
✗✓ | 8362 |
CHECK(args[2]->IsObject()); |
376 |
|||
377 |
4181 |
Isolate* isolate = args.GetIsolate(); |
|
378 |
4181 |
DestroyParam* p = new DestroyParam(); |
|
379 |
12543 |
p->asyncId = args[1].As<Number>()->Value(); |
|
380 |
4181 |
p->env = Environment::GetCurrent(args); |
|
381 |
12543 |
p->target.Reset(isolate, args[0].As<Object>()); |
|
382 |
12543 |
p->propBag.Reset(isolate, args[2].As<Object>()); |
|
383 |
4181 |
p->target.SetWeak(p, AsyncWrap::WeakCallback, WeakCallbackType::kParameter); |
|
384 |
4181 |
} |
|
385 |
|||
386 |
|||
387 |
161154 |
void AsyncWrap::GetAsyncId(const FunctionCallbackInfo<Value>& args) { |
|
388 |
AsyncWrap* wrap; |
||
389 |
322308 |
args.GetReturnValue().Set(kInvalidAsyncId); |
|
390 |
✓✓ | 322308 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
391 |
483399 |
args.GetReturnValue().Set(wrap->get_async_id()); |
|
392 |
} |
||
393 |
|||
394 |
|||
395 |
8 |
void AsyncWrap::PushAsyncIds(const FunctionCallbackInfo<Value>& args) { |
|
396 |
8 |
Environment* env = Environment::GetCurrent(args); |
|
397 |
// No need for CHECK(IsNumber()) on args because if FromJust() doesn't fail |
||
398 |
// then the checks in push_async_ids() and pop_async_id() will. |
||
399 |
32 |
double async_id = args[0]->NumberValue(env->context()).FromJust(); |
|
400 |
32 |
double trigger_async_id = args[1]->NumberValue(env->context()).FromJust(); |
|
401 |
8 |
env->async_hooks()->push_async_ids(async_id, trigger_async_id); |
|
402 |
8 |
} |
|
403 |
|||
404 |
|||
405 |
3 |
void AsyncWrap::PopAsyncIds(const FunctionCallbackInfo<Value>& args) { |
|
406 |
3 |
Environment* env = Environment::GetCurrent(args); |
|
407 |
12 |
double async_id = args[0]->NumberValue(env->context()).FromJust(); |
|
408 |
3 |
args.GetReturnValue().Set(env->async_hooks()->pop_async_id(async_id)); |
|
409 |
} |
||
410 |
|||
411 |
|||
412 |
28 |
void AsyncWrap::AsyncReset(const FunctionCallbackInfo<Value>& args) { |
|
413 |
✗✓ | 56 |
CHECK(args[0]->IsObject()); |
414 |
|||
415 |
AsyncWrap* wrap; |
||
416 |
✗✓ | 56 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
417 |
|||
418 |
56 |
Local<Object> resource = args[0].As<Object>(); |
|
419 |
double execution_async_id = |
||
420 |
✗✓✗✓ ✗✓ |
56 |
args[1]->IsNumber() ? args[1].As<Number>()->Value() : kInvalidAsyncId; |
421 |
28 |
wrap->AsyncReset(resource, execution_async_id); |
|
422 |
} |
||
423 |
|||
424 |
|||
425 |
28 |
void AsyncWrap::GetProviderType(const FunctionCallbackInfo<Value>& args) { |
|
426 |
AsyncWrap* wrap; |
||
427 |
56 |
args.GetReturnValue().Set(AsyncWrap::PROVIDER_NONE); |
|
428 |
✗✓ | 56 |
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder()); |
429 |
84 |
args.GetReturnValue().Set(wrap->provider_type()); |
|
430 |
} |
||
431 |
|||
432 |
|||
433 |
320873 |
void AsyncWrap::EmitDestroy() { |
|
434 |
320873 |
AsyncWrap::EmitDestroy(env(), async_id_); |
|
435 |
// Ensure no double destroy is emitted via AsyncReset(). |
||
436 |
320875 |
async_id_ = kInvalidAsyncId; |
|
437 |
320875 |
} |
|
438 |
|||
439 |
55749 |
void AsyncWrap::QueueDestroyAsyncId(const FunctionCallbackInfo<Value>& args) { |
|
440 |
✗✓ | 111498 |
CHECK(args[0]->IsNumber()); |
441 |
AsyncWrap::EmitDestroy( |
||
442 |
Environment::GetCurrent(args), |
||
443 |
167247 |
args[0].As<Number>()->Value()); |
|
444 |
55749 |
} |
|
445 |
|||
446 |
80739 |
Local<FunctionTemplate> AsyncWrap::GetConstructorTemplate(Environment* env) { |
|
447 |
80739 |
Local<FunctionTemplate> tmpl = env->async_wrap_ctor_template(); |
|
448 |
✓✓ | 80739 |
if (tmpl.IsEmpty()) { |
449 |
5103 |
tmpl = env->NewFunctionTemplate(nullptr); |
|
450 |
10206 |
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap")); |
|
451 |
5103 |
env->SetProtoMethod(tmpl, "getAsyncId", AsyncWrap::GetAsyncId); |
|
452 |
5103 |
env->SetProtoMethod(tmpl, "asyncReset", AsyncWrap::AsyncReset); |
|
453 |
5103 |
env->SetProtoMethod(tmpl, "getProviderType", AsyncWrap::GetProviderType); |
|
454 |
5103 |
env->set_async_wrap_ctor_template(tmpl); |
|
455 |
} |
||
456 |
80739 |
return tmpl; |
|
457 |
} |
||
458 |
|||
459 |
5103 |
void AsyncWrap::Initialize(Local<Object> target, |
|
460 |
Local<Value> unused, |
||
461 |
Local<Context> context, |
||
462 |
void* priv) { |
||
463 |
5103 |
Environment* env = Environment::GetCurrent(context); |
|
464 |
5103 |
Isolate* isolate = env->isolate(); |
|
465 |
5103 |
HandleScope scope(isolate); |
|
466 |
|||
467 |
5103 |
env->SetMethod(target, "setupHooks", SetupHooks); |
|
468 |
5103 |
env->SetMethod(target, "pushAsyncIds", PushAsyncIds); |
|
469 |
5103 |
env->SetMethod(target, "popAsyncIds", PopAsyncIds); |
|
470 |
5103 |
env->SetMethod(target, "queueDestroyAsyncId", QueueDestroyAsyncId); |
|
471 |
5103 |
env->SetMethod(target, "enablePromiseHook", EnablePromiseHook); |
|
472 |
5103 |
env->SetMethod(target, "disablePromiseHook", DisablePromiseHook); |
|
473 |
5103 |
env->SetMethod(target, "registerDestroyHook", RegisterDestroyHook); |
|
474 |
|||
475 |
PropertyAttribute ReadOnlyDontDelete = |
||
476 |
5103 |
static_cast<PropertyAttribute>(ReadOnly | DontDelete); |
|
477 |
|||
478 |
#define FORCE_SET_TARGET_FIELD(obj, str, field) \ |
||
479 |
(obj)->DefineOwnProperty(context, \ |
||
480 |
FIXED_ONE_BYTE_STRING(isolate, str), \ |
||
481 |
field, \ |
||
482 |
ReadOnlyDontDelete).FromJust() |
||
483 |
|||
484 |
// Attach the uint32_t[] where each slot contains the count of the number of |
||
485 |
// callbacks waiting to be called on a particular event. It can then be |
||
486 |
// incremented/decremented from JS quickly to communicate to C++ if there are |
||
487 |
// any callbacks waiting to be called. |
||
488 |
20412 |
FORCE_SET_TARGET_FIELD(target, |
|
489 |
"async_hook_fields", |
||
490 |
env->async_hooks()->fields().GetJSArray()); |
||
491 |
|||
492 |
// The following v8::Float64Array has 5 fields. These fields are shared in |
||
493 |
// this way to allow JS and C++ to read/write each value as quickly as |
||
494 |
// possible. The fields are represented as follows: |
||
495 |
// |
||
496 |
// kAsyncIdCounter: Maintains the state of the next unique id to be assigned. |
||
497 |
// |
||
498 |
// kDefaultTriggerAsyncId: Write the id of the resource responsible for a |
||
499 |
// handle's creation just before calling the new handle's constructor. |
||
500 |
// After the new handle is constructed kDefaultTriggerAsyncId is set back |
||
501 |
// to kInvalidAsyncId. |
||
502 |
20412 |
FORCE_SET_TARGET_FIELD(target, |
|
503 |
"async_id_fields", |
||
504 |
env->async_hooks()->async_id_fields().GetJSArray()); |
||
505 |
|||
506 |
target->Set(context, |
||
507 |
env->async_ids_stack_string(), |
||
508 |
20412 |
env->async_hooks()->async_ids_stack().GetJSArray()).Check(); |
|
509 |
|||
510 |
target->Set(context, |
||
511 |
FIXED_ONE_BYTE_STRING(env->isolate(), "owner_symbol"), |
||
512 |
20412 |
env->owner_symbol()).Check(); |
|
513 |
|||
514 |
5103 |
Local<Object> constants = Object::New(isolate); |
|
515 |
#define SET_HOOKS_CONSTANT(name) \ |
||
516 |
FORCE_SET_TARGET_FIELD( \ |
||
517 |
constants, #name, Integer::New(isolate, AsyncHooks::name)) |
||
518 |
|||
519 |
20412 |
SET_HOOKS_CONSTANT(kInit); |
|
520 |
20412 |
SET_HOOKS_CONSTANT(kBefore); |
|
521 |
20412 |
SET_HOOKS_CONSTANT(kAfter); |
|
522 |
20412 |
SET_HOOKS_CONSTANT(kDestroy); |
|
523 |
20412 |
SET_HOOKS_CONSTANT(kPromiseResolve); |
|
524 |
20412 |
SET_HOOKS_CONSTANT(kTotals); |
|
525 |
20412 |
SET_HOOKS_CONSTANT(kCheck); |
|
526 |
20412 |
SET_HOOKS_CONSTANT(kExecutionAsyncId); |
|
527 |
20412 |
SET_HOOKS_CONSTANT(kTriggerAsyncId); |
|
528 |
20412 |
SET_HOOKS_CONSTANT(kAsyncIdCounter); |
|
529 |
20412 |
SET_HOOKS_CONSTANT(kDefaultTriggerAsyncId); |
|
530 |
20412 |
SET_HOOKS_CONSTANT(kStackLength); |
|
531 |
#undef SET_HOOKS_CONSTANT |
||
532 |
15309 |
FORCE_SET_TARGET_FIELD(target, "constants", constants); |
|
533 |
|||
534 |
5103 |
Local<Object> async_providers = Object::New(isolate); |
|
535 |
#define V(p) \ |
||
536 |
FORCE_SET_TARGET_FIELD( \ |
||
537 |
async_providers, #p, Integer::New(isolate, AsyncWrap::PROVIDER_ ## p)); |
||
538 |
678699 |
NODE_ASYNC_PROVIDER_TYPES(V) |
|
539 |
#undef V |
||
540 |
15309 |
FORCE_SET_TARGET_FIELD(target, "Providers", async_providers); |
|
541 |
|||
542 |
#undef FORCE_SET_TARGET_FIELD |
||
543 |
|||
544 |
5103 |
env->set_async_hooks_init_function(Local<Function>()); |
|
545 |
5103 |
env->set_async_hooks_before_function(Local<Function>()); |
|
546 |
5103 |
env->set_async_hooks_after_function(Local<Function>()); |
|
547 |
5103 |
env->set_async_hooks_destroy_function(Local<Function>()); |
|
548 |
5103 |
env->set_async_hooks_promise_resolve_function(Local<Function>()); |
|
549 |
5103 |
env->set_async_hooks_binding(target); |
|
550 |
|||
551 |
// TODO(addaleax): This block might better work as a |
||
552 |
// AsyncWrapObject::Initialize() or AsyncWrapObject::GetConstructorTemplate() |
||
553 |
// function. |
||
554 |
{ |
||
555 |
5103 |
auto class_name = FIXED_ONE_BYTE_STRING(env->isolate(), "AsyncWrap"); |
|
556 |
5103 |
auto function_template = env->NewFunctionTemplate(AsyncWrapObject::New); |
|
557 |
5103 |
function_template->SetClassName(class_name); |
|
558 |
10206 |
function_template->Inherit(AsyncWrap::GetConstructorTemplate(env)); |
|
559 |
5103 |
auto instance_template = function_template->InstanceTemplate(); |
|
560 |
5103 |
instance_template->SetInternalFieldCount(1); |
|
561 |
auto function = |
||
562 |
15309 |
function_template->GetFunction(env->context()).ToLocalChecked(); |
|
563 |
15309 |
target->Set(env->context(), class_name, function).Check(); |
|
564 |
5103 |
env->set_async_wrap_object_ctor_template(function_template); |
|
565 |
5103 |
} |
|
566 |
5103 |
} |
|
567 |
|||
568 |
|||
569 |
273913 |
AsyncWrap::AsyncWrap(Environment* env, |
|
570 |
Local<Object> object, |
||
571 |
ProviderType provider, |
||
572 |
double execution_async_id) |
||
573 |
273913 |
: AsyncWrap(env, object, provider, execution_async_id, false) {} |
|
574 |
|||
575 |
274896 |
AsyncWrap::AsyncWrap(Environment* env, |
|
576 |
Local<Object> object, |
||
577 |
ProviderType provider, |
||
578 |
double execution_async_id, |
||
579 |
bool silent) |
||
580 |
274896 |
: AsyncWrap(env, object) { |
|
581 |
✗✓ | 274897 |
CHECK_NE(provider, PROVIDER_NONE); |
582 |
274897 |
provider_type_ = provider; |
|
583 |
|||
584 |
// Use AsyncReset() call to execute the init() callbacks. |
||
585 |
274897 |
AsyncReset(execution_async_id, silent); |
|
586 |
274897 |
init_hook_ran_ = true; |
|
587 |
274897 |
} |
|
588 |
|||
589 |
277900 |
AsyncWrap::AsyncWrap(Environment* env, Local<Object> object) |
|
590 |
277900 |
: BaseObject(env, object) { |
|
591 |
277900 |
} |
|
592 |
|||
593 |
// This method is necessary to work around one specific problem: |
||
594 |
// Before the init() hook runs, if there is one, the BaseObject() constructor |
||
595 |
// registers this object with the Environment for finilization and debugging |
||
596 |
// purposes. |
||
597 |
// If the Environment decides to inspect this object for debugging, it tries to |
||
598 |
// call virtual methods on this object that are only (meaningfully) implemented |
||
599 |
// by the subclasses of AsyncWrap. |
||
600 |
// This could, with bad luck, happen during the AsyncWrap() constructor, |
||
601 |
// because we run JS code as part of it and that in turn can lead to a heapdump |
||
602 |
// being taken, either through the inspector or our programmatic API for it. |
||
603 |
// The object being initialized is not fully constructed at that point, and |
||
604 |
// in particular its virtual function table points to the AsyncWrap one |
||
605 |
// (as the subclass constructor has not yet begun execution at that point). |
||
606 |
// This means that the functions that are used for heap dump memory tracking |
||
607 |
// are not yet available, and trying to call them would crash the process. |
||
608 |
// We use this particular `IsDoneInitializing()` method to tell the Environment |
||
609 |
// that such debugging methods are not yet available. |
||
610 |
// This may be somewhat unreliable when it comes to future changes, because |
||
611 |
// at this point it *only* protects AsyncWrap subclasses, and *only* for cases |
||
612 |
// where heap dumps are being taken while the init() hook is on the call stack. |
||
613 |
// For now, it seems like the best solution, though. |
||
614 |
153 |
bool AsyncWrap::IsDoneInitializing() const { |
|
615 |
153 |
return init_hook_ran_; |
|
616 |
} |
||
617 |
|||
618 |
554011 |
AsyncWrap::~AsyncWrap() { |
|
619 |
277006 |
EmitTraceEventDestroy(); |
|
620 |
277006 |
EmitDestroy(); |
|
621 |
✗✓ | 277006 |
} |
622 |
|||
623 |
320638 |
void AsyncWrap::EmitTraceEventDestroy() { |
|
624 |
✗✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✗ |
320638 |
switch (provider_type()) { |
625 |
#define V(PROVIDER) \ |
||
626 |
case PROVIDER_ ## PROVIDER: \ |
||
627 |
TRACE_EVENT_NESTABLE_ASYNC_END0( \ |
||
628 |
TRACING_CATEGORY_NODE1(async_hooks), \ |
||
629 |
#PROVIDER, static_cast<int64_t>(get_async_id())); \ |
||
630 |
break; |
||
631 |
✗✗✗✗ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✓✓ ✓✓✗✓ ✓✓✗✓ ✓✓✓✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✓✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ ✓✓✗✓ |
641274 |
NODE_ASYNC_PROVIDER_TYPES(V) |
632 |
#undef V |
||
633 |
default: |
||
634 |
UNREACHABLE(); |
||
635 |
} |
||
636 |
320637 |
} |
|
637 |
|||
638 |
381324 |
void AsyncWrap::EmitDestroy(Environment* env, double async_id) { |
|
639 |
✓✓✓✓ ✓✗✓✓ |
452824 |
if (env->async_hooks()->fields()[AsyncHooks::kDestroy] == 0 || |
640 |
71500 |
!env->can_call_into_js()) { |
|
641 |
691417 |
return; |
|
642 |
} |
||
643 |
|||
644 |
✓✓ | 71229 |
if (env->destroy_async_id_list()->empty()) { |
645 |
22239 |
env->SetUnrefImmediate(&DestroyAsyncIdsCallback); |
|
646 |
} |
||
647 |
|||
648 |
71229 |
env->destroy_async_id_list()->push_back(async_id); |
|
649 |
} |
||
650 |
|||
651 |
275102 |
void AsyncWrap::AsyncReset(double execution_async_id, bool silent) { |
|
652 |
275102 |
AsyncReset(object(), execution_async_id, silent); |
|
653 |
275103 |
} |
|
654 |
|||
655 |
// Generalized call for both the constructor and for handles that are pooled |
||
656 |
// and reused over their lifetime. This way a new uid can be assigned when |
||
657 |
// the resource is pulled out of the pool and put back into use. |
||
658 |
318966 |
void AsyncWrap::AsyncReset(Local<Object> resource, double execution_async_id, |
|
659 |
bool silent) { |
||
660 |
✗✓ | 318966 |
CHECK_NE(provider_type(), PROVIDER_NONE); |
661 |
|||
662 |
✓✓ | 318967 |
if (async_id_ != kInvalidAsyncId) { |
663 |
// This instance was in use before, we have already emitted an init with |
||
664 |
// its previous async_id and need to emit a matching destroy for that |
||
665 |
// before generating a new async_id. |
||
666 |
237 |
EmitDestroy(); |
|
667 |
} |
||
668 |
|||
669 |
// Now we can assign a new async_id_ to this instance. |
||
670 |
318967 |
async_id_ = execution_async_id == kInvalidAsyncId ? env()->new_async_id() |
|
671 |
✓✗ | 637934 |
: execution_async_id; |
672 |
318967 |
trigger_async_id_ = env()->get_default_trigger_async_id(); |
|
673 |
|||
674 |
✗✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✗ |
318967 |
switch (provider_type()) { |
675 |
#define V(PROVIDER) \ |
||
676 |
case PROVIDER_ ## PROVIDER: \ |
||
677 |
if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED( \ |
||
678 |
TRACING_CATEGORY_NODE1(async_hooks))) { \ |
||
679 |
auto data = tracing::TracedValue::Create(); \ |
||
680 |
data->SetInteger("executionAsyncId", \ |
||
681 |
static_cast<int64_t>(env()->execution_async_id())); \ |
||
682 |
data->SetInteger("triggerAsyncId", \ |
||
683 |
static_cast<int64_t>(get_trigger_async_id())); \ |
||
684 |
TRACE_EVENT_NESTABLE_ASYNC_BEGIN1( \ |
||
685 |
TRACING_CATEGORY_NODE1(async_hooks), \ |
||
686 |
#PROVIDER, static_cast<int64_t>(get_async_id()), \ |
||
687 |
"data", std::move(data)); \ |
||
688 |
} \ |
||
689 |
break; |
||
690 |
✗✗✗✗ ✗✗✗✗ ✗✓✗✗ ✗✗✓✓ ✗✓✓✗ ✓✗✗✗ ✗✗✗✗ ✗✗✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✗ ✗✗✓✗ ✗✗✗✗ ✗✗✓✗ ✗✗✗✗ ✗✓✗✗ ✗✗✗✗ ✗✗✗✓ ✗✗✗✗ ✗✗✗✗ ✗✗✗✓ ✗✗✓✗ ✗✗✗✗ ✗✗✗✗ ✓✗✗✓ ✗✗✗✓ ✗✗✗✗ ✗✓✗✗ ✗✗✗✗ ✗✗✗✗ ✗✓✗✗ ✗✗✗✗ ✗✓✗✗ ✗✗✗✗ ✗✗✗✓ ✗✓✗✗ ✗✓✗✗ ✗✗✗✓ ✗✗✗✗ ✗✓✗✗ ✗✗✗✗ ✗✗✓✗ ✗✓✗✗ ✓✗✗✗ ✗✗✗✗ ✗✓✗✗ ✓✗✗✓ ✓✗✓✓ ✓✗✗✓ ✓✗✗✗ ✗✗✓✗ ✗✓✓✗ ✗✗✗✗ ✗✗✗✗ ✗✗✓✗ ✗✗✓✗ ✗✗✗✗ ✗✗✗✓ ✗✗✓✓ ✗✗✓✓ ✗✓✗✗ ✗✓✓✗ ✗✓✗✗ ✗✓✗✓ ✗✗✗✓ ✗✗✗✓ |
34 |
NODE_ASYNC_PROVIDER_TYPES(V) |
691 |
#undef V |
||
692 |
default: |
||
693 |
UNREACHABLE(); |
||
694 |
} |
||
695 |
|||
696 |
✓✓ | 637933 |
if (silent) return; |
697 |
|||
698 |
EmitAsyncInit(env(), resource, |
||
699 |
318950 |
env()->async_hooks()->provider_string(provider_type()), |
|
700 |
637900 |
async_id_, trigger_async_id_); |
|
701 |
} |
||
702 |
|||
703 |
|||
704 |
319497 |
void AsyncWrap::EmitAsyncInit(Environment* env, |
|
705 |
Local<Object> object, |
||
706 |
Local<String> type, |
||
707 |
double async_id, |
||
708 |
double trigger_async_id) { |
||
709 |
✗✓ | 319497 |
CHECK(!object.IsEmpty()); |
710 |
✗✓ | 319497 |
CHECK(!type.IsEmpty()); |
711 |
319497 |
AsyncHooks* async_hooks = env->async_hooks(); |
|
712 |
|||
713 |
// Nothing to execute, so can continue normally. |
||
714 |
✓✓ | 319498 |
if (async_hooks->fields()[AsyncHooks::kInit] == 0) { |
715 |
625407 |
return; |
|
716 |
} |
||
717 |
|||
718 |
13589 |
HandleScope scope(env->isolate()); |
|
719 |
13589 |
Local<Function> init_fn = env->async_hooks_init_function(); |
|
720 |
|||
721 |
Local<Value> argv[] = { |
||
722 |
Number::New(env->isolate(), async_id), |
||
723 |
type, |
||
724 |
Number::New(env->isolate(), trigger_async_id), |
||
725 |
object, |
||
726 |
67945 |
}; |
|
727 |
|||
728 |
27178 |
TryCatchScope try_catch(env, TryCatchScope::CatchMode::kFatal); |
|
729 |
54356 |
USE(init_fn->Call(env->context(), object, arraysize(argv), argv)); |
|
730 |
} |
||
731 |
|||
732 |
|||
733 |
1105682 |
MaybeLocal<Value> AsyncWrap::MakeCallback(const Local<Function> cb, |
|
734 |
int argc, |
||
735 |
Local<Value>* argv) { |
||
736 |
1105682 |
EmitTraceEventBefore(); |
|
737 |
|||
738 |
1105603 |
ProviderType provider = provider_type(); |
|
739 |
1105683 |
async_context context { get_async_id(), get_trigger_async_id() }; |
|
740 |
MaybeLocal<Value> ret = InternalMakeCallback( |
||
741 |
1105679 |
env(), object(), cb, argc, argv, context); |
|
742 |
|||
743 |
// This is a static call with cached values because the `this` object may |
||
744 |
// no longer be alive at this point. |
||
745 |
1105585 |
EmitTraceEventAfter(provider, context.async_id); |
|
746 |
|||
747 |
1105585 |
return ret; |
|
748 |
} |
||
749 |
|||
750 |
std::string AsyncWrap::MemoryInfoName() const { |
||
751 |
return provider_names[provider_type()]; |
||
752 |
} |
||
753 |
|||
754 |
std::string AsyncWrap::diagnostic_name() const { |
||
755 |
return MemoryInfoName() + " (" + std::to_string(env()->thread_id()) + ":" + |
||
756 |
std::to_string(static_cast<int64_t>(async_id_)) + ")"; |
||
757 |
} |
||
758 |
|||
759 |
240 |
Local<Object> AsyncWrap::GetOwner() { |
|
760 |
240 |
return GetOwner(env(), object()); |
|
761 |
} |
||
762 |
|||
763 |
240 |
Local<Object> AsyncWrap::GetOwner(Environment* env, Local<Object> obj) { |
|
764 |
240 |
EscapableHandleScope handle_scope(env->isolate()); |
|
765 |
✗✓ | 240 |
CHECK(!obj.IsEmpty()); |
766 |
|||
767 |
480 |
TryCatchScope ignore_exceptions(env); |
|
768 |
while (true) { |
||
769 |
Local<Value> owner; |
||
770 |
✓✓ | 932 |
if (!obj->Get(env->context(), |
771 |
✓✗✓✓ ✓✗✗✓ |
3262 |
env->owner_symbol()).ToLocal(&owner) || |
772 |
466 |
!owner->IsObject()) { |
|
773 |
480 |
return handle_scope.Escape(obj); |
|
774 |
} |
||
775 |
|||
776 |
226 |
obj = owner.As<Object>(); |
|
777 |
} |
||
778 |
} |
||
779 |
|||
780 |
} // namespace node |
||
781 |
|||
782 |
4957 |
NODE_MODULE_CONTEXT_AWARE_INTERNAL(async_wrap, node::AsyncWrap::Initialize) |
Generated by: GCOVR (Version 3.4) |