GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/api/callback.cc Lines: 132 148 89.2 %
Date: 2021-04-27 04:12:29 Branches: 85 104 81.7 %

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
647
CallbackScope::CallbackScope(Isolate* isolate,
20
                             Local<Object> object,
21
647
                             async_context asyncContext)
22
647
  : private_(new InternalCallbackScope(Environment::GetCurrent(isolate),
23
                                       object,
24
647
                                       asyncContext)),
25
1294
    try_catch_(isolate) {
26
647
  try_catch_.SetVerbose(true);
27
647
}
28
29
1292
CallbackScope::~CallbackScope() {
30
646
  if (try_catch_.HasCaught())
31
1
    private_->MarkAsFailed();
32
646
  delete private_;
33
646
}
34
35
51388
InternalCallbackScope::InternalCallbackScope(AsyncWrap* async_wrap, int flags)
36
    : InternalCallbackScope(async_wrap->env(),
37
                            async_wrap->object(),
38
51388
                            { async_wrap->get_async_id(),
39
51388
                              async_wrap->get_trigger_async_id() },
40
102776
                            flags) {}
41
42
1297814
InternalCallbackScope::InternalCallbackScope(Environment* env,
43
                                             Local<Object> object,
44
                                             const async_context& asyncContext,
45
1297814
                                             int flags)
46
  : env_(env),
47
    async_context_(asyncContext),
48
    object_(object),
49
1297814
    skip_hooks_(flags & kSkipAsyncHooks),
50
2595628
    skip_task_queues_(flags & kSkipTaskQueues) {
51
1297814
  CHECK_NOT_NULL(env);
52
1297814
  env->PushAsyncCallbackScope();
53
54
1297850
  if (!env->can_call_into_js()) {
55
10550
    failed_ = true;
56
10550
    return;
57
  }
58
59
2574639
  HandleScope handle_scope(env->isolate());
60
  // If you hit this assertion, you forgot to enter the v8::Context first.
61
1287285
  CHECK_EQ(Environment::GetCurrent(env->isolate()), env);
62
63
1287350
  env->isolate()->SetIdle(false);
64
65
1287333
  env->async_hooks()->push_async_context(
66
1287326
    async_context_.async_id, async_context_.trigger_async_id, object);
67
68
1287349
  pushed_ids_ = true;
69
70

1287349
  if (asyncContext.async_id != 0 && !skip_hooks_) {
71
    // No need to check a return value because the application will exit if
72
    // an exception occurs.
73
52028
    AsyncWrap::EmitBefore(env, asyncContext.async_id);
74
  }
75
}
76
77
2594708
InternalCallbackScope::~InternalCallbackScope() {
78
1297398
  Close();
79
1297312
  env_->PopAsyncCallbackScope();
80
1297310
}
81
82
2006990
void InternalCallbackScope::Close() {
83
3597351
  if (closed_) return;
84
1297555
  closed_ = true;
85
86
3011294
  auto idle = OnScopeLeave([&]() { env_->isolate()->SetIdle(true); });
87
88
1297509
  if (!env_->can_call_into_js()) return;
89
2491046
  auto perform_stopping_check = [&]() {
90
2491096
    if (env_->is_stopping()) {
91
50
      MarkAsFailed();
92
50
      env_->async_hooks()->clear_async_id_stack();
93
    }
94
3777961
  };
95
1286952
  perform_stopping_check();
96
97

1286953
  if (!failed_ && async_context_.async_id != 0 && !skip_hooks_) {
98
52016
    AsyncWrap::EmitAfter(env_, async_context_.async_id);
99
  }
100
101
1286957
  if (pushed_ids_)
102
1286955
    env_->async_hooks()->pop_async_context(async_context_.async_id);
103
104
1286885
  if (failed_) return;
105
106

1285900
  if (env_->async_callback_scope_depth() > 1 || skip_task_queues_) {
107
82377
    return;
108
  }
109
110
1203524
  TickInfo* tick_info = env_->tick_info();
111
112
1203509
  if (!env_->can_call_into_js()) return;
113
114
2823360
  auto weakref_cleanup = OnScopeLeave([&]() { env_->RunWeakRefCleanup(); });
115
116
1203570
  if (!tick_info->has_tick_scheduled()) {
117
1575397
    env_->context()->GetMicrotaskQueue()->PerformCheckpoint(env_->isolate());
118
119
787731
    perform_stopping_check();
120
  }
121
122
  // Make sure the stack unwound properly. If there are nested MakeCallback's
123
  // then it should return early and not reach this code.
124
1203616
  if (env_->async_hooks()->fields()[AsyncHooks::kTotals]) {
125
66515
    CHECK_EQ(env_->execution_async_id(), 0);
126
66515
    CHECK_EQ(env_->trigger_async_id(), 0);
127
  }
128
129

1203607
  if (!tick_info->has_tick_scheduled() && !tick_info->has_rejection_to_warn()) {
130
786985
    return;
131
  }
132
133
833027
  HandleScope handle_scope(env_->isolate());
134
416623
  Local<Object> process = env_->process_object();
135
136
416623
  if (!env_->can_call_into_js()) return;
137
138
416623
  Local<Function> tick_callback = env_->tick_callback_function();
139
140
  // The tick is triggered before JS land calls SetTickCallback
141
  // to initializes the tick callback during bootstrap.
142
416623
  CHECK(!tick_callback.IsEmpty());
143
144
1249650
  if (tick_callback->Call(env_->context(), process, 0, nullptr).IsEmpty()) {
145
197
    failed_ = true;
146
  }
147
416404
  perform_stopping_check();
148
}
149
150
711598
MaybeLocal<Value> InternalMakeCallback(Environment* env,
151
                                       Local<Object> resource,
152
                                       Local<Object> recv,
153
                                       const Local<Function> callback,
154
                                       int argc,
155
                                       Local<Value> argv[],
156
                                       async_context asyncContext) {
157
711598
  CHECK(!recv.IsEmpty());
158
#ifdef DEBUG
159
  for (int i = 0; i < argc; i++)
160
    CHECK(!argv[i].IsEmpty());
161
#endif
162
163
711598
  Local<Function> hook_cb = env->async_hooks_callback_trampoline();
164
711654
  int flags = InternalCallbackScope::kNoFlags;
165
711654
  bool use_async_hooks_trampoline = false;
166
711654
  AsyncHooks* async_hooks = env->async_hooks();
167
711650
  if (!hook_cb.IsEmpty()) {
168
    // Use the callback trampoline if there are any before or after hooks, or
169
    // we can expect some kind of usage of async_hooks.executionAsyncResource().
170
711621
    flags = InternalCallbackScope::kSkipAsyncHooks;
171
711620
    use_async_hooks_trampoline =
172
1423258
        async_hooks->fields()[AsyncHooks::kBefore] +
173
2134864
        async_hooks->fields()[AsyncHooks::kAfter] +
174
1423257
        async_hooks->fields()[AsyncHooks::kUsesExecutionAsyncResource] > 0;
175
  }
176
177
1423074
  InternalCallbackScope scope(env, resource, asyncContext, flags);
178
711669
  if (scope.Failed()) {
179
952
    return MaybeLocal<Value>();
180
  }
181
182
  MaybeLocal<Value> ret;
183
184
710640
  if (use_async_hooks_trampoline) {
185
59510
    MaybeStackBuffer<Local<Value>, 16> args(3 + argc);
186
59514
    args[0] = v8::Number::New(env->isolate(), asyncContext.async_id);
187
59514
    args[1] = resource;
188
59514
    args[2] = callback;
189
39746
    for (int i = 0; i < argc; i++) {
190
9989
      args[i + 3] = argv[i];
191
    }
192
89271
    ret = hook_cb->Call(env->context(), recv, args.length(), &args[0]);
193
  } else {
194
1361831
    ret = callback->Call(env->context(), recv, argc, argv);
195
  }
196
197
710651
  if (ret.IsEmpty()) {
198
1004
    scope.MarkAsFailed();
199
1004
    return MaybeLocal<Value>();
200
  }
201
202
709647
  scope.Close();
203
709470
  if (scope.Failed()) {
204
109
    return MaybeLocal<Value>();
205
  }
206
207
709360
  return ret;
208
}
209
210
// Public MakeCallback()s
211
212
9110
MaybeLocal<Value> MakeCallback(Isolate* isolate,
213
                               Local<Object> recv,
214
                               const char* method,
215
                               int argc,
216
                               Local<Value> argv[],
217
                               async_context asyncContext) {
218
  Local<String> method_string =
219
18222
      String::NewFromUtf8(isolate, method).ToLocalChecked();
220
9112
  return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext);
221
}
222
223
9118
MaybeLocal<Value> MakeCallback(Isolate* isolate,
224
                               Local<Object> recv,
225
                               Local<String> symbol,
226
                               int argc,
227
                               Local<Value> argv[],
228
                               async_context asyncContext) {
229
  // Check can_call_into_js() first because calling Get() might do so.
230
  Environment* env =
231
18237
      Environment::GetCurrent(recv->GetCreationContext().ToLocalChecked());
232
9120
  CHECK_NOT_NULL(env);
233
9124
  if (!env->can_call_into_js()) return Local<Value>();
234
235
  Local<Value> callback_v;
236
27346
  if (!recv->Get(isolate->GetCurrentContext(), symbol).ToLocal(&callback_v))
237
    return Local<Value>();
238
9116
  if (!callback_v->IsFunction()) {
239
    // This used to return an empty value, but Undefined() makes more sense
240
    // since no exception is pending here.
241
    return Undefined(isolate);
242
  }
243
9116
  Local<Function> callback = callback_v.As<Function>();
244
9116
  return MakeCallback(isolate, recv, callback, argc, argv, asyncContext);
245
}
246
247
125739
MaybeLocal<Value> MakeCallback(Isolate* isolate,
248
                               Local<Object> recv,
249
                               Local<Function> callback,
250
                               int argc,
251
                               Local<Value> argv[],
252
                               async_context asyncContext) {
253
  // Observe the following two subtleties:
254
  //
255
  // 1. The environment is retrieved from the callback function's context.
256
  // 2. The context to enter is retrieved from the environment.
257
  //
258
  // Because of the AssignToContext() call in src/node_contextify.cc,
259
  // the two contexts need not be the same.
260
  Environment* env =
261
251478
      Environment::GetCurrent(callback->GetCreationContext().ToLocalChecked());
262
125738
  CHECK_NOT_NULL(env);
263
125738
  Context::Scope context_scope(env->context());
264
  MaybeLocal<Value> ret =
265
125737
      InternalMakeCallback(env, recv, recv, callback, argc, argv, asyncContext);
266

125716
  if (ret.IsEmpty() && env->async_callback_scope_depth() == 0) {
267
    // This is only for legacy compatibility and we may want to look into
268
    // removing/adjusting it.
269
2002
    return Undefined(env->isolate());
270
  }
271
124715
  return ret;
272
}
273
274
// Use this if you just want to safely invoke some JS callback and
275
// would like to retain the currently active async_context, if any.
276
// In case none is available, a fixed default context will be
277
// installed otherwise.
278
16
MaybeLocal<Value> MakeSyncCallback(Isolate* isolate,
279
                                   Local<Object> recv,
280
                                   Local<Function> callback,
281
                                   int argc,
282
                                   Local<Value> argv[]) {
283
  Environment* env =
284
32
      Environment::GetCurrent(callback->GetCreationContext().ToLocalChecked());
285
16
  CHECK_NOT_NULL(env);
286
16
  if (!env->can_call_into_js()) return Local<Value>();
287
288
16
  Context::Scope context_scope(env->context());
289
16
  if (env->async_callback_scope_depth()) {
290
    // There's another MakeCallback() on the stack, piggy back on it.
291
    // In particular, retain the current async_context.
292
32
    return callback->Call(env->context(), recv, argc, argv);
293
  }
294
295
  // This is a toplevel invocation and the caller (intentionally)
296
  // didn't provide any async_context to run in. Install a default context.
297
  MaybeLocal<Value> ret =
298
    InternalMakeCallback(env, env->process_object(), recv, callback, argc, argv,
299
                         async_context{0, 0});
300
  return ret;
301
}
302
303
// Legacy MakeCallback()s
304
305
Local<Value> MakeCallback(Isolate* isolate,
306
                          Local<Object> recv,
307
                          const char* method,
308
                          int argc,
309
                          Local<Value>* argv) {
310
  EscapableHandleScope handle_scope(isolate);
311
  return handle_scope.Escape(
312
      MakeCallback(isolate, recv, method, argc, argv, {0, 0})
313
          .FromMaybe(Local<Value>()));
314
}
315
316
Local<Value> MakeCallback(Isolate* isolate,
317
                          Local<Object> recv,
318
                          Local<String> symbol,
319
                          int argc,
320
                          Local<Value>* argv) {
321
  EscapableHandleScope handle_scope(isolate);
322
  return handle_scope.Escape(
323
      MakeCallback(isolate, recv, symbol, argc, argv, {0, 0})
324
          .FromMaybe(Local<Value>()));
325
}
326
327
Local<Value> MakeCallback(Isolate* isolate,
328
                          Local<Object> recv,
329
                          Local<Function> callback,
330
                          int argc,
331
                          Local<Value>* argv) {
332
  EscapableHandleScope handle_scope(isolate);
333
  return handle_scope.Escape(
334
      MakeCallback(isolate, recv, callback, argc, argv, {0, 0})
335
          .FromMaybe(Local<Value>()));
336
}
337
338

14487
}  // namespace node