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::MicrotasksScope; |
||
16 |
using v8::Object; |
||
17 |
using v8::String; |
||
18 |
using v8::Value; |
||
19 |
|||
20 |
647 |
CallbackScope::CallbackScope(Isolate* isolate, |
|
21 |
Local<Object> object, |
||
22 |
647 |
async_context asyncContext) |
|
23 |
647 |
: private_(new InternalCallbackScope(Environment::GetCurrent(isolate), |
|
24 |
object, |
||
25 |
647 |
asyncContext)), |
|
26 |
1294 |
try_catch_(isolate) { |
|
27 |
647 |
try_catch_.SetVerbose(true); |
|
28 |
647 |
} |
|
29 |
|||
30 |
1292 |
CallbackScope::~CallbackScope() { |
|
31 |
✓✓ | 646 |
if (try_catch_.HasCaught()) |
32 |
1 |
private_->MarkAsFailed(); |
|
33 |
✓✗ | 646 |
delete private_; |
34 |
646 |
} |
|
35 |
|||
36 |
51509 |
InternalCallbackScope::InternalCallbackScope(AsyncWrap* async_wrap, int flags) |
|
37 |
: InternalCallbackScope(async_wrap->env(), |
||
38 |
async_wrap->object(), |
||
39 |
51509 |
{ async_wrap->get_async_id(), |
|
40 |
51509 |
async_wrap->get_trigger_async_id() }, |
|
41 |
103018 |
flags) {} |
|
42 |
|||
43 |
1251715 |
InternalCallbackScope::InternalCallbackScope(Environment* env, |
|
44 |
Local<Object> object, |
||
45 |
const async_context& asyncContext, |
||
46 |
1251715 |
int flags) |
|
47 |
: env_(env), |
||
48 |
async_context_(asyncContext), |
||
49 |
object_(object), |
||
50 |
1251715 |
skip_hooks_(flags & kSkipAsyncHooks), |
|
51 |
2503430 |
skip_task_queues_(flags & kSkipTaskQueues) { |
|
52 |
✗✓ | 1251715 |
CHECK_NOT_NULL(env); |
53 |
1251715 |
env->PushAsyncCallbackScope(); |
|
54 |
|||
55 |
✓✓ | 1251752 |
if (!env->can_call_into_js()) { |
56 |
10089 |
failed_ = true; |
|
57 |
10089 |
return; |
|
58 |
} |
||
59 |
|||
60 |
2483322 |
HandleScope handle_scope(env->isolate()); |
|
61 |
// If you hit this assertion, you forgot to enter the v8::Context first. |
||
62 |
✗✓ | 1241687 |
CHECK_EQ(Environment::GetCurrent(env->isolate()), env); |
63 |
|||
64 |
1241718 |
env->async_hooks()->push_async_context( |
|
65 |
1241707 |
async_context_.async_id, async_context_.trigger_async_id, object); |
|
66 |
|||
67 |
1241694 |
pushed_ids_ = true; |
|
68 |
|||
69 |
✓✓✓✓ |
1241694 |
if (asyncContext.async_id != 0 && !skip_hooks_) { |
70 |
// No need to check a return value because the application will exit if |
||
71 |
// an exception occurs. |
||
72 |
52149 |
AsyncWrap::EmitBefore(env, asyncContext.async_id); |
|
73 |
} |
||
74 |
} |
||
75 |
|||
76 |
2502457 |
InternalCallbackScope::~InternalCallbackScope() { |
|
77 |
1251255 |
Close(); |
|
78 |
1251197 |
env_->PopAsyncCallbackScope(); |
|
79 |
1251202 |
} |
|
80 |
|||
81 |
1936015 |
void InternalCallbackScope::Close() { |
|
82 |
✓✓ | 3461453 |
if (closed_) return; |
83 |
1251439 |
closed_ = true; |
|
84 |
|||
85 |
✓✓ | 1251439 |
if (!env_->can_call_into_js()) return; |
86 |
2400920 |
auto perform_stopping_check = [&]() { |
|
87 |
✓✓ | 2400937 |
if (env_->is_stopping()) { |
88 |
17 |
MarkAsFailed(); |
|
89 |
17 |
env_->async_hooks()->clear_async_id_stack(); |
|
90 |
} |
||
91 |
3642086 |
}; |
|
92 |
1241240 |
perform_stopping_check(); |
|
93 |
|||
94 |
✓✓✓✓ ✓✓ |
1241203 |
if (!failed_ && async_context_.async_id != 0 && !skip_hooks_) { |
95 |
52137 |
AsyncWrap::EmitAfter(env_, async_context_.async_id); |
|
96 |
} |
||
97 |
|||
98 |
✓✗ | 1241205 |
if (pushed_ids_) |
99 |
1241205 |
env_->async_hooks()->pop_async_context(async_context_.async_id); |
|
100 |
|||
101 |
✓✓ | 1241228 |
if (failed_) return; |
102 |
|||
103 |
✓✓✓✓ ✓✓ |
1240241 |
if (env_->async_callback_scope_depth() > 1 || skip_task_queues_) { |
104 |
80961 |
return; |
|
105 |
} |
||
106 |
|||
107 |
1159278 |
TickInfo* tick_info = env_->tick_info(); |
|
108 |
|||
109 |
✗✓ | 1159275 |
if (!env_->can_call_into_js()) return; |
110 |
|||
111 |
2728745 |
auto weakref_cleanup = OnScopeLeave([&]() { env_->RunWeakRefCleanup(); }); |
|
112 |
|||
113 |
✓✓ | 1159238 |
if (!tick_info->has_tick_scheduled()) { |
114 |
749338 |
MicrotasksScope::PerformCheckpoint(env_->isolate()); |
|
115 |
|||
116 |
749441 |
perform_stopping_check(); |
|
117 |
} |
||
118 |
|||
119 |
// Make sure the stack unwound properly. If there are nested MakeCallback's |
||
120 |
// then it should return early and not reach this code. |
||
121 |
✓✓ | 1159338 |
if (env_->async_hooks()->fields()[AsyncHooks::kTotals]) { |
122 |
✗✓ | 64274 |
CHECK_EQ(env_->execution_async_id(), 0); |
123 |
✗✓ | 64274 |
CHECK_EQ(env_->trigger_async_id(), 0); |
124 |
} |
||
125 |
|||
126 |
✓✓✓✓ ✓✓ |
1159328 |
if (!tick_info->has_tick_scheduled() && !tick_info->has_rejection_to_warn()) { |
127 |
748770 |
return; |
|
128 |
} |
||
129 |
|||
130 |
✓✓ | 820911 |
HandleScope handle_scope(env_->isolate()); |
131 |
410548 |
Local<Object> process = env_->process_object(); |
|
132 |
|||
133 |
✗✓ | 410548 |
if (!env_->can_call_into_js()) return; |
134 |
|||
135 |
410548 |
Local<Function> tick_callback = env_->tick_callback_function(); |
|
136 |
|||
137 |
// The tick is triggered before JS land calls SetTickCallback |
||
138 |
// to initializes the tick callback during bootstrap. |
||
139 |
✗✓ | 410548 |
CHECK(!tick_callback.IsEmpty()); |
140 |
|||
141 |
✓✓ | 1231459 |
if (tick_callback->Call(env_->context(), process, 0, nullptr).IsEmpty()) { |
142 |
158 |
failed_ = true; |
|
143 |
} |
||
144 |
✓✗ | 410363 |
perform_stopping_check(); |
145 |
} |
||
146 |
|||
147 |
686727 |
MaybeLocal<Value> InternalMakeCallback(Environment* env, |
|
148 |
Local<Object> resource, |
||
149 |
Local<Object> recv, |
||
150 |
const Local<Function> callback, |
||
151 |
int argc, |
||
152 |
Local<Value> argv[], |
||
153 |
async_context asyncContext) { |
||
154 |
✗✓ | 686727 |
CHECK(!recv.IsEmpty()); |
155 |
#ifdef DEBUG |
||
156 |
for (int i = 0; i < argc; i++) |
||
157 |
CHECK(!argv[i].IsEmpty()); |
||
158 |
#endif |
||
159 |
|||
160 |
686727 |
Local<Function> hook_cb = env->async_hooks_callback_trampoline(); |
|
161 |
686735 |
int flags = InternalCallbackScope::kNoFlags; |
|
162 |
686735 |
bool use_async_hooks_trampoline = false; |
|
163 |
686735 |
AsyncHooks* async_hooks = env->async_hooks(); |
|
164 |
✓✓ | 686731 |
if (!hook_cb.IsEmpty()) { |
165 |
// Use the callback trampoline if there are any before or after hooks, or |
||
166 |
// we can expect some kind of usage of async_hooks.executionAsyncResource(). |
||
167 |
686716 |
flags = InternalCallbackScope::kSkipAsyncHooks; |
|
168 |
686719 |
use_async_hooks_trampoline = |
|
169 |
1373443 |
async_hooks->fields()[AsyncHooks::kBefore] + |
|
170 |
2060185 |
async_hooks->fields()[AsyncHooks::kAfter] + |
|
171 |
1373446 |
async_hooks->fields()[AsyncHooks::kUsesExecutionAsyncResource] > 0; |
|
172 |
} |
||
173 |
|||
174 |
1373289 |
InternalCallbackScope scope(env, resource, asyncContext, flags); |
|
175 |
✓✓ | 686797 |
if (scope.Failed()) { |
176 |
890 |
return MaybeLocal<Value>(); |
|
177 |
} |
||
178 |
|||
179 |
MaybeLocal<Value> ret; |
||
180 |
|||
181 |
✓✓ | 685887 |
if (use_async_hooks_trampoline) { |
182 |
56168 |
MaybeStackBuffer<Local<Value>, 16> args(3 + argc); |
|
183 |
56172 |
args[0] = v8::Number::New(env->isolate(), asyncContext.async_id); |
|
184 |
56172 |
args[1] = resource; |
|
185 |
56172 |
args[2] = callback; |
|
186 |
✓✓ | 36338 |
for (int i = 0; i < argc; i++) { |
187 |
8252 |
args[i + 3] = argv[i]; |
|
188 |
} |
||
189 |
84258 |
ret = hook_cb->Call(env->context(), recv, args.length(), &args[0]); |
|
190 |
} else { |
||
191 |
1315623 |
ret = callback->Call(env->context(), recv, argc, argv); |
|
192 |
} |
||
193 |
|||
194 |
✓✓ | 685866 |
if (ret.IsEmpty()) { |
195 |
1026 |
scope.MarkAsFailed(); |
|
196 |
1026 |
return MaybeLocal<Value>(); |
|
197 |
} |
||
198 |
|||
199 |
684840 |
scope.Close(); |
|
200 |
✓✓ | 684642 |
if (scope.Failed()) { |
201 |
73 |
return MaybeLocal<Value>(); |
|
202 |
} |
||
203 |
|||
204 |
684566 |
return ret; |
|
205 |
} |
||
206 |
|||
207 |
// Public MakeCallback()s |
||
208 |
|||
209 |
8800 |
MaybeLocal<Value> MakeCallback(Isolate* isolate, |
|
210 |
Local<Object> recv, |
||
211 |
const char* method, |
||
212 |
int argc, |
||
213 |
Local<Value> argv[], |
||
214 |
async_context asyncContext) { |
||
215 |
Local<String> method_string = |
||
216 |
17600 |
String::NewFromUtf8(isolate, method).ToLocalChecked(); |
|
217 |
8800 |
return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext); |
|
218 |
} |
||
219 |
|||
220 |
8808 |
MaybeLocal<Value> MakeCallback(Isolate* isolate, |
|
221 |
Local<Object> recv, |
||
222 |
Local<String> symbol, |
||
223 |
int argc, |
||
224 |
Local<Value> argv[], |
||
225 |
async_context asyncContext) { |
||
226 |
// Check can_call_into_js() first because calling Get() might do so. |
||
227 |
8808 |
Environment* env = Environment::GetCurrent(recv->CreationContext()); |
|
228 |
✗✓ | 8808 |
CHECK_NOT_NULL(env); |
229 |
✗✓ | 8808 |
if (!env->can_call_into_js()) return Local<Value>(); |
230 |
|||
231 |
Local<Value> callback_v; |
||
232 |
✗✓ | 26424 |
if (!recv->Get(isolate->GetCurrentContext(), symbol).ToLocal(&callback_v)) |
233 |
return Local<Value>(); |
||
234 |
✗✓ | 8808 |
if (!callback_v->IsFunction()) { |
235 |
// This used to return an empty value, but Undefined() makes more sense |
||
236 |
// since no exception is pending here. |
||
237 |
return Undefined(isolate); |
||
238 |
} |
||
239 |
8808 |
Local<Function> callback = callback_v.As<Function>(); |
|
240 |
8808 |
return MakeCallback(isolate, recv, callback, argc, argv, asyncContext); |
|
241 |
} |
||
242 |
|||
243 |
110526 |
MaybeLocal<Value> MakeCallback(Isolate* isolate, |
|
244 |
Local<Object> recv, |
||
245 |
Local<Function> callback, |
||
246 |
int argc, |
||
247 |
Local<Value> argv[], |
||
248 |
async_context asyncContext) { |
||
249 |
// Observe the following two subtleties: |
||
250 |
// |
||
251 |
// 1. The environment is retrieved from the callback function's context. |
||
252 |
// 2. The context to enter is retrieved from the environment. |
||
253 |
// |
||
254 |
// Because of the AssignToContext() call in src/node_contextify.cc, |
||
255 |
// the two contexts need not be the same. |
||
256 |
110526 |
Environment* env = Environment::GetCurrent(callback->CreationContext()); |
|
257 |
✗✓ | 110526 |
CHECK_NOT_NULL(env); |
258 |
110526 |
Context::Scope context_scope(env->context()); |
|
259 |
MaybeLocal<Value> ret = |
||
260 |
110526 |
InternalMakeCallback(env, recv, recv, callback, argc, argv, asyncContext); |
|
261 |
✓✓✓✓ ✓✓ |
110507 |
if (ret.IsEmpty() && env->async_callback_scope_depth() == 0) { |
262 |
// This is only for legacy compatibility and we may want to look into |
||
263 |
// removing/adjusting it. |
||
264 |
2002 |
return Undefined(env->isolate()); |
|
265 |
} |
||
266 |
109506 |
return ret; |
|
267 |
} |
||
268 |
|||
269 |
// Legacy MakeCallback()s |
||
270 |
|||
271 |
Local<Value> MakeCallback(Isolate* isolate, |
||
272 |
Local<Object> recv, |
||
273 |
const char* method, |
||
274 |
int argc, |
||
275 |
Local<Value>* argv) { |
||
276 |
EscapableHandleScope handle_scope(isolate); |
||
277 |
return handle_scope.Escape( |
||
278 |
MakeCallback(isolate, recv, method, argc, argv, {0, 0}) |
||
279 |
.FromMaybe(Local<Value>())); |
||
280 |
} |
||
281 |
|||
282 |
Local<Value> MakeCallback(Isolate* isolate, |
||
283 |
Local<Object> recv, |
||
284 |
Local<String> symbol, |
||
285 |
int argc, |
||
286 |
Local<Value>* argv) { |
||
287 |
EscapableHandleScope handle_scope(isolate); |
||
288 |
return handle_scope.Escape( |
||
289 |
MakeCallback(isolate, recv, symbol, argc, argv, {0, 0}) |
||
290 |
.FromMaybe(Local<Value>())); |
||
291 |
} |
||
292 |
|||
293 |
Local<Value> MakeCallback(Isolate* isolate, |
||
294 |
Local<Object> recv, |
||
295 |
Local<Function> callback, |
||
296 |
int argc, |
||
297 |
Local<Value>* argv) { |
||
298 |
EscapableHandleScope handle_scope(isolate); |
||
299 |
return handle_scope.Escape( |
||
300 |
MakeCallback(isolate, recv, callback, argc, argv, {0, 0}) |
||
301 |
.FromMaybe(Local<Value>())); |
||
302 |
} |
||
303 |
|||
304 |
✓✗✓✗ |
14034 |
} // namespace node |
Generated by: GCOVR (Version 3.4) |