GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
#include "node.h" |
||
2 |
#include "async_wrap-inl.h" |
||
3 |
#include "env-inl.h" |
||
4 |
#include "v8.h" |
||
5 |
|||
6 |
namespace node { |
||
7 |
|||
8 |
using v8::Context; |
||
9 |
using v8::EscapableHandleScope; |
||
10 |
using v8::Function; |
||
11 |
using v8::HandleScope; |
||
12 |
using v8::Isolate; |
||
13 |
using v8::Local; |
||
14 |
using v8::MaybeLocal; |
||
15 |
using v8::Object; |
||
16 |
using v8::String; |
||
17 |
using v8::Value; |
||
18 |
|||
19 |
4 |
CallbackScope::CallbackScope(Isolate* isolate, |
|
20 |
Local<Object> object, |
||
21 |
4 |
async_context async_context) |
|
22 |
4 |
: CallbackScope(Environment::GetCurrent(isolate), object, async_context) {} |
|
23 |
|||
24 |
115539 |
CallbackScope::CallbackScope(Environment* env, |
|
25 |
Local<Object> object, |
||
26 |
115539 |
async_context asyncContext) |
|
27 |
: private_(new InternalCallbackScope(env, |
||
28 |
object, |
||
29 |
115539 |
asyncContext)), |
|
30 |
231078 |
try_catch_(env->isolate()) { |
|
31 |
115539 |
try_catch_.SetVerbose(true); |
|
32 |
115539 |
} |
|
33 |
|||
34 |
115538 |
CallbackScope::~CallbackScope() { |
|
35 |
✓✓ | 115538 |
if (try_catch_.HasCaught()) |
36 |
1 |
private_->MarkAsFailed(); |
|
37 |
✓✗ | 115538 |
delete private_; |
38 |
115538 |
} |
|
39 |
|||
40 |
53002 |
InternalCallbackScope::InternalCallbackScope(AsyncWrap* async_wrap, int flags) |
|
41 |
: InternalCallbackScope(async_wrap->env(), |
||
42 |
async_wrap->object(), |
||
43 |
53002 |
{ async_wrap->get_async_id(), |
|
44 |
53002 |
async_wrap->get_trigger_async_id() }, |
|
45 |
53002 |
flags) {} |
|
46 |
|||
47 |
779863 |
InternalCallbackScope::InternalCallbackScope(Environment* env, |
|
48 |
Local<Object> object, |
||
49 |
const async_context& asyncContext, |
||
50 |
779863 |
int flags) |
|
51 |
: env_(env), |
||
52 |
async_context_(asyncContext), |
||
53 |
object_(object), |
||
54 |
779863 |
skip_hooks_(flags & kSkipAsyncHooks), |
|
55 |
1559726 |
skip_task_queues_(flags & kSkipTaskQueues) { |
|
56 |
✗✓ | 779863 |
CHECK_NOT_NULL(env); |
57 |
779863 |
env->PushAsyncCallbackScope(); |
|
58 |
|||
59 |
✓✓ | 779863 |
if (!env->can_call_into_js()) { |
60 |
11425 |
failed_ = true; |
|
61 |
11425 |
return; |
|
62 |
} |
||
63 |
|||
64 |
768438 |
Isolate* isolate = env->isolate(); |
|
65 |
|||
66 |
1536876 |
HandleScope handle_scope(isolate); |
|
67 |
// If you hit this assertion, you forgot to enter the v8::Context first. |
||
68 |
✗✓ | 768438 |
CHECK_EQ(Environment::GetCurrent(isolate), env); |
69 |
|||
70 |
768438 |
env->isolate()->SetIdle(false); |
|
71 |
|||
72 |
768438 |
env->async_hooks()->push_async_context( |
|
73 |
async_context_.async_id, async_context_.trigger_async_id, object); |
||
74 |
|||
75 |
768438 |
pushed_ids_ = true; |
|
76 |
|||
77 |
✓✓✓✓ |
768438 |
if (asyncContext.async_id != 0 && !skip_hooks_) { |
78 |
// No need to check a return value because the application will exit if |
||
79 |
// an exception occurs. |
||
80 |
168531 |
AsyncWrap::EmitBefore(env, asyncContext.async_id); |
|
81 |
} |
||
82 |
} |
||
83 |
|||
84 |
1558768 |
InternalCallbackScope::~InternalCallbackScope() { |
|
85 |
779415 |
Close(); |
|
86 |
779353 |
env_->PopAsyncCallbackScope(); |
|
87 |
779353 |
} |
|
88 |
|||
89 |
1178219 |
void InternalCallbackScope::Close() { |
|
90 |
✓✓ | 1777141 |
if (closed_) return; |
91 |
779529 |
closed_ = true; |
|
92 |
|||
93 |
779529 |
Isolate* isolate = env_->isolate(); |
|
94 |
1558882 |
auto idle = OnScopeLeave([&]() { isolate->SetIdle(true); }); |
|
95 |
|||
96 |
✓✓ | 779529 |
if (!env_->can_call_into_js()) return; |
97 |
1453736 |
auto perform_stopping_check = [&]() { |
|
98 |
✓✓ | 1453736 |
if (env_->is_stopping()) { |
99 |
77 |
MarkAsFailed(); |
|
100 |
77 |
env_->async_hooks()->clear_async_id_stack(); |
|
101 |
} |
||
102 |
2221786 |
}; |
|
103 |
768050 |
perform_stopping_check(); |
|
104 |
|||
105 |
✓✓✓✓ ✓✓ |
768050 |
if (!failed_ && async_context_.async_id != 0 && !skip_hooks_) { |
106 |
168519 |
AsyncWrap::EmitAfter(env_, async_context_.async_id); |
|
107 |
} |
||
108 |
|||
109 |
✓✗ | 768050 |
if (pushed_ids_) |
110 |
768050 |
env_->async_hooks()->pop_async_context(async_context_.async_id); |
|
111 |
|||
112 |
✓✓ | 768049 |
if (failed_) return; |
113 |
|||
114 |
✓✓✓✓ ✓✓ |
767062 |
if (env_->async_callback_scope_depth() > 1 || skip_task_queues_) { |
115 |
82252 |
return; |
|
116 |
} |
||
117 |
|||
118 |
684810 |
TickInfo* tick_info = env_->tick_info(); |
|
119 |
|||
120 |
✓✓ | 684810 |
if (!env_->can_call_into_js()) return; |
121 |
|||
122 |
1369439 |
auto weakref_cleanup = OnScopeLeave([&]() { env_->RunWeakRefCleanup(); }); |
|
123 |
|||
124 |
684807 |
Local<Context> context = env_->context(); |
|
125 |
✓✓ | 684807 |
if (!tick_info->has_tick_scheduled()) { |
126 |
505290 |
context->GetMicrotaskQueue()->PerformCheckpoint(isolate); |
|
127 |
|||
128 |
505255 |
perform_stopping_check(); |
|
129 |
} |
||
130 |
|||
131 |
// Make sure the stack unwound properly. If there are nested MakeCallback's |
||
132 |
// then it should return early and not reach this code. |
||
133 |
✓✓ | 684772 |
if (env_->async_hooks()->fields()[AsyncHooks::kTotals]) { |
134 |
✗✓ | 67806 |
CHECK_EQ(env_->execution_async_id(), 0); |
135 |
✗✓ | 67806 |
CHECK_EQ(env_->trigger_async_id(), 0); |
136 |
} |
||
137 |
|||
138 |
✓✓✓✓ ✓✓ |
684772 |
if (!tick_info->has_tick_scheduled() && !tick_info->has_rejection_to_warn()) { |
139 |
504201 |
return; |
|
140 |
} |
||
141 |
|||
142 |
180571 |
HandleScope handle_scope(isolate); |
|
143 |
180571 |
Local<Object> process = env_->process_object(); |
|
144 |
|||
145 |
✗✓ | 180571 |
if (!env_->can_call_into_js()) return; |
146 |
|||
147 |
180571 |
Local<Function> tick_callback = env_->tick_callback_function(); |
|
148 |
|||
149 |
// The tick is triggered before JS land calls SetTickCallback |
||
150 |
// to initializes the tick callback during bootstrap. |
||
151 |
✗✓ | 180571 |
CHECK(!tick_callback.IsEmpty()); |
152 |
|||
153 |
✓✓ | 361002 |
if (tick_callback->Call(context, process, 0, nullptr).IsEmpty()) { |
154 |
223 |
failed_ = true; |
|
155 |
} |
||
156 |
180431 |
perform_stopping_check(); |
|
157 |
} |
||
158 |
|||
159 |
401131 |
MaybeLocal<Value> InternalMakeCallback(Environment* env, |
|
160 |
Local<Object> resource, |
||
161 |
Local<Object> recv, |
||
162 |
const Local<Function> callback, |
||
163 |
int argc, |
||
164 |
Local<Value> argv[], |
||
165 |
async_context asyncContext) { |
||
166 |
✗✓ | 401131 |
CHECK(!recv.IsEmpty()); |
167 |
#ifdef DEBUG |
||
168 |
for (int i = 0; i < argc; i++) |
||
169 |
CHECK(!argv[i].IsEmpty()); |
||
170 |
#endif |
||
171 |
|||
172 |
401131 |
Local<Function> hook_cb = env->async_hooks_callback_trampoline(); |
|
173 |
401131 |
int flags = InternalCallbackScope::kNoFlags; |
|
174 |
401131 |
bool use_async_hooks_trampoline = false; |
|
175 |
401131 |
AsyncHooks* async_hooks = env->async_hooks(); |
|
176 |
✓✗ | 401131 |
if (!hook_cb.IsEmpty()) { |
177 |
// Use the callback trampoline if there are any before or after hooks, or |
||
178 |
// we can expect some kind of usage of async_hooks.executionAsyncResource(). |
||
179 |
401131 |
flags = InternalCallbackScope::kSkipAsyncHooks; |
|
180 |
401131 |
use_async_hooks_trampoline = |
|
181 |
401131 |
async_hooks->fields()[AsyncHooks::kBefore] + |
|
182 |
401131 |
async_hooks->fields()[AsyncHooks::kAfter] + |
|
183 |
401131 |
async_hooks->fields()[AsyncHooks::kUsesExecutionAsyncResource] > 0; |
|
184 |
} |
||
185 |
|||
186 |
802090 |
InternalCallbackScope scope(env, resource, asyncContext, flags); |
|
187 |
✓✓ | 401131 |
if (scope.Failed()) { |
188 |
1254 |
return MaybeLocal<Value>(); |
|
189 |
} |
||
190 |
|||
191 |
MaybeLocal<Value> ret; |
||
192 |
|||
193 |
399877 |
Local<Context> context = env->context(); |
|
194 |
✓✓ | 399877 |
if (use_async_hooks_trampoline) { |
195 |
30378 |
MaybeStackBuffer<Local<Value>, 16> args(3 + argc); |
|
196 |
60756 |
args[0] = v8::Number::New(env->isolate(), asyncContext.async_id); |
|
197 |
30378 |
args[1] = resource; |
|
198 |
30378 |
args[2] = callback; |
|
199 |
✓✓ | 41249 |
for (int i = 0; i < argc; i++) { |
200 |
10871 |
args[i + 3] = argv[i]; |
|
201 |
} |
||
202 |
30378 |
ret = hook_cb->Call(context, recv, args.length(), &args[0]); |
|
203 |
} else { |
||
204 |
369499 |
ret = callback->Call(context, recv, argc, argv); |
|
205 |
} |
||
206 |
|||
207 |
✓✓ | 399819 |
if (ret.IsEmpty()) { |
208 |
1015 |
scope.MarkAsFailed(); |
|
209 |
1015 |
return MaybeLocal<Value>(); |
|
210 |
} |
||
211 |
|||
212 |
398804 |
scope.Close(); |
|
213 |
✓✓ | 398690 |
if (scope.Failed()) { |
214 |
136 |
return MaybeLocal<Value>(); |
|
215 |
} |
||
216 |
|||
217 |
398554 |
return ret; |
|
218 |
} |
||
219 |
|||
220 |
// Public MakeCallback()s |
||
221 |
|||
222 |
9506 |
MaybeLocal<Value> MakeCallback(Isolate* isolate, |
|
223 |
Local<Object> recv, |
||
224 |
const char* method, |
||
225 |
int argc, |
||
226 |
Local<Value> argv[], |
||
227 |
async_context asyncContext) { |
||
228 |
Local<String> method_string = |
||
229 |
9506 |
String::NewFromUtf8(isolate, method).ToLocalChecked(); |
|
230 |
9506 |
return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext); |
|
231 |
} |
||
232 |
|||
233 |
9514 |
MaybeLocal<Value> MakeCallback(Isolate* isolate, |
|
234 |
Local<Object> recv, |
||
235 |
Local<String> symbol, |
||
236 |
int argc, |
||
237 |
Local<Value> argv[], |
||
238 |
async_context asyncContext) { |
||
239 |
// Check can_call_into_js() first because calling Get() might do so. |
||
240 |
Environment* env = |
||
241 |
19028 |
Environment::GetCurrent(recv->GetCreationContext().ToLocalChecked()); |
|
242 |
✗✓ | 9514 |
CHECK_NOT_NULL(env); |
243 |
✓✓ | 9529 |
if (!env->can_call_into_js()) return Local<Value>(); |
244 |
|||
245 |
Local<Value> callback_v; |
||
246 |
✗✓ | 18998 |
if (!recv->Get(isolate->GetCurrentContext(), symbol).ToLocal(&callback_v)) |
247 |
return Local<Value>(); |
||
248 |
✗✓ | 9499 |
if (!callback_v->IsFunction()) { |
249 |
// This used to return an empty value, but Undefined() makes more sense |
||
250 |
// since no exception is pending here. |
||
251 |
return Undefined(isolate); |
||
252 |
} |
||
253 |
9499 |
Local<Function> callback = callback_v.As<Function>(); |
|
254 |
9499 |
return MakeCallback(isolate, recv, callback, argc, argv, asyncContext); |
|
255 |
} |
||
256 |
|||
257 |
50360 |
MaybeLocal<Value> MakeCallback(Isolate* isolate, |
|
258 |
Local<Object> recv, |
||
259 |
Local<Function> callback, |
||
260 |
int argc, |
||
261 |
Local<Value> argv[], |
||
262 |
async_context asyncContext) { |
||
263 |
// Observe the following two subtleties: |
||
264 |
// |
||
265 |
// 1. The environment is retrieved from the callback function's context. |
||
266 |
// 2. The context to enter is retrieved from the environment. |
||
267 |
// |
||
268 |
// Because of the AssignToContext() call in src/node_contextify.cc, |
||
269 |
// the two contexts need not be the same. |
||
270 |
Environment* env = |
||
271 |
100720 |
Environment::GetCurrent(callback->GetCreationContext().ToLocalChecked()); |
|
272 |
✗✓ | 50360 |
CHECK_NOT_NULL(env); |
273 |
50360 |
Context::Scope context_scope(env->context()); |
|
274 |
MaybeLocal<Value> ret = |
||
275 |
50360 |
InternalMakeCallback(env, recv, recv, callback, argc, argv, asyncContext); |
|
276 |
✓✓✓✓ ✓✓ |
50346 |
if (ret.IsEmpty() && env->async_callback_scope_depth() == 0) { |
277 |
// This is only for legacy compatibility and we may want to look into |
||
278 |
// removing/adjusting it. |
||
279 |
1005 |
return Undefined(isolate); |
|
280 |
} |
||
281 |
49341 |
return ret; |
|
282 |
} |
||
283 |
|||
284 |
// Use this if you just want to safely invoke some JS callback and |
||
285 |
// would like to retain the currently active async_context, if any. |
||
286 |
// In case none is available, a fixed default context will be |
||
287 |
// installed otherwise. |
||
288 |
16 |
MaybeLocal<Value> MakeSyncCallback(Isolate* isolate, |
|
289 |
Local<Object> recv, |
||
290 |
Local<Function> callback, |
||
291 |
int argc, |
||
292 |
Local<Value> argv[]) { |
||
293 |
Environment* env = |
||
294 |
32 |
Environment::GetCurrent(callback->GetCreationContext().ToLocalChecked()); |
|
295 |
✗✓ | 16 |
CHECK_NOT_NULL(env); |
296 |
✗✓ | 16 |
if (!env->can_call_into_js()) return Local<Value>(); |
297 |
|||
298 |
16 |
Local<Context> context = env->context(); |
|
299 |
16 |
Context::Scope context_scope(context); |
|
300 |
✓✗ | 16 |
if (env->async_callback_scope_depth()) { |
301 |
// There's another MakeCallback() on the stack, piggy back on it. |
||
302 |
// In particular, retain the current async_context. |
||
303 |
16 |
return callback->Call(context, recv, argc, argv); |
|
304 |
} |
||
305 |
|||
306 |
// This is a toplevel invocation and the caller (intentionally) |
||
307 |
// didn't provide any async_context to run in. Install a default context. |
||
308 |
MaybeLocal<Value> ret = |
||
309 |
InternalMakeCallback(env, env->process_object(), recv, callback, argc, argv, |
||
310 |
async_context{0, 0}); |
||
311 |
return ret; |
||
312 |
} |
||
313 |
|||
314 |
// Legacy MakeCallback()s |
||
315 |
|||
316 |
Local<Value> MakeCallback(Isolate* isolate, |
||
317 |
Local<Object> recv, |
||
318 |
const char* method, |
||
319 |
int argc, |
||
320 |
Local<Value>* argv) { |
||
321 |
EscapableHandleScope handle_scope(isolate); |
||
322 |
return handle_scope.Escape( |
||
323 |
MakeCallback(isolate, recv, method, argc, argv, {0, 0}) |
||
324 |
.FromMaybe(Local<Value>())); |
||
325 |
} |
||
326 |
|||
327 |
Local<Value> MakeCallback(Isolate* isolate, |
||
328 |
Local<Object> recv, |
||
329 |
Local<String> symbol, |
||
330 |
int argc, |
||
331 |
Local<Value>* argv) { |
||
332 |
EscapableHandleScope handle_scope(isolate); |
||
333 |
return handle_scope.Escape( |
||
334 |
MakeCallback(isolate, recv, symbol, argc, argv, {0, 0}) |
||
335 |
.FromMaybe(Local<Value>())); |
||
336 |
} |
||
337 |
|||
338 |
Local<Value> MakeCallback(Isolate* isolate, |
||
339 |
Local<Object> recv, |
||
340 |
Local<Function> callback, |
||
341 |
int argc, |
||
342 |
Local<Value>* argv) { |
||
343 |
EscapableHandleScope handle_scope(isolate); |
||
344 |
return handle_scope.Escape( |
||
345 |
MakeCallback(isolate, recv, callback, argc, argv, {0, 0}) |
||
346 |
.FromMaybe(Local<Value>())); |
||
347 |
} |
||
348 |
|||
349 |
} // namespace node |
Generated by: GCOVR (Version 4.2) |