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: 136 152 89.5 %
Date: 2021-06-03 04:12:28 Branches: 83 104 79.8 %

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
113608
CallbackScope::CallbackScope(Isolate* isolate,
20
                             Local<Object> object,
21
113608
                             async_context asyncContext)
22
113608
  : private_(new InternalCallbackScope(Environment::GetCurrent(isolate),
23
                                       object,
24
113608
                                       asyncContext)),
25
227216
    try_catch_(isolate) {
26
113608
  try_catch_.SetVerbose(true);
27
113608
}
28
29
227214
CallbackScope::~CallbackScope() {
30
113607
  if (try_catch_.HasCaught())
31
1
    private_->MarkAsFailed();
32
113607
  delete private_;
33
113607
}
34
35
51421
InternalCallbackScope::InternalCallbackScope(AsyncWrap* async_wrap, int flags)
36
    : InternalCallbackScope(async_wrap->env(),
37
                            async_wrap->object(),
38
51421
                            { async_wrap->get_async_id(),
39
51421
                              async_wrap->get_trigger_async_id() },
40
102842
                            flags) {}
41
42
825473
InternalCallbackScope::InternalCallbackScope(Environment* env,
43
                                             Local<Object> object,
44
                                             const async_context& asyncContext,
45
825473
                                             int flags)
46
  : env_(env),
47
    async_context_(asyncContext),
48
    object_(object),
49
825473
    skip_hooks_(flags & kSkipAsyncHooks),
50
1650946
    skip_task_queues_(flags & kSkipTaskQueues) {
51
825473
  CHECK_NOT_NULL(env);
52
825473
  env->PushAsyncCallbackScope();
53
54
825578
  if (!env->can_call_into_js()) {
55
10605
    failed_ = true;
56
10605
    return;
57
  }
58
59
814952
  Isolate* isolate = env->isolate();
60
61
1629993
  HandleScope handle_scope(isolate);
62
  // If you hit this assertion, you forgot to enter the v8::Context first.
63
814991
  CHECK_EQ(Environment::GetCurrent(isolate), env);
64
65
815056
  env->isolate()->SetIdle(false);
66
67
815050
  env->async_hooks()->push_async_context(
68
815048
    async_context_.async_id, async_context_.trigger_async_id, object);
69
70
815042
  pushed_ids_ = true;
71
72

815042
  if (asyncContext.async_id != 0 && !skip_hooks_) {
73
    // No need to check a return value because the application will exit if
74
    // an exception occurs.
75
165019
    AsyncWrap::EmitBefore(env, asyncContext.async_id);
76
  }
77
}
78
79
1650137
InternalCallbackScope::~InternalCallbackScope() {
80
825117
  Close();
81
825023
  env_->PopAsyncCallbackScope();
82
825020
}
83
84
1235976
void InternalCallbackScope::Close() {
85
2300237
  if (closed_) return;
86
825280
  closed_ = true;
87
88
825280
  Isolate* isolate = env_->isolate();
89
1821832
  auto idle = OnScopeLeave([&]() { isolate->SetIdle(true); });
90
91
825198
  if (!env_->can_call_into_js()) return;
92
1546357
  auto perform_stopping_check = [&]() {
93
1546406
    if (env_->is_stopping()) {
94
49
      MarkAsFailed();
95
49
      env_->async_hooks()->clear_async_id_stack();
96
    }
97
2360794
  };
98
814524
  perform_stopping_check();
99
100

814485
  if (!failed_ && async_context_.async_id != 0 && !skip_hooks_) {
101
165007
    AsyncWrap::EmitAfter(env_, async_context_.async_id);
102
  }
103
104
814489
  if (pushed_ids_)
105
814489
    env_->async_hooks()->pop_async_context(async_context_.async_id);
106
107
814470
  if (failed_) return;
108
109

813485
  if (env_->async_callback_scope_depth() > 1 || skip_task_queues_) {
110
82374
    return;
111
  }
112
113
731108
  TickInfo* tick_info = env_->tick_info();
114
115
731106
  if (!env_->can_call_into_js()) return;
116
117
1633702
  auto weakref_cleanup = OnScopeLeave([&]() { env_->RunWeakRefCleanup(); });
118
119
731139
  Local<Context> context = env_->context();
120
731119
  if (!tick_info->has_tick_scheduled()) {
121
560215
    context->GetMicrotaskQueue()->PerformCheckpoint(isolate);
122
123
560417
    perform_stopping_check();
124
  }
125
126
  // Make sure the stack unwound properly. If there are nested MakeCallback's
127
  // then it should return early and not reach this code.
128
731305
  if (env_->async_hooks()->fields()[AsyncHooks::kTotals]) {
129
66089
    CHECK_EQ(env_->execution_async_id(), 0);
130
66089
    CHECK_EQ(env_->trigger_async_id(), 0);
131
  }
132
133

731297
  if (!tick_info->has_tick_scheduled() && !tick_info->has_rejection_to_warn()) {
134
559546
    return;
135
  }
136
137
343212
  HandleScope handle_scope(isolate);
138
171715
  Local<Object> process = env_->process_object();
139
140
171715
  if (!env_->can_call_into_js()) return;
141
142
171715
  Local<Function> tick_callback = env_->tick_callback_function();
143
144
  // The tick is triggered before JS land calls SetTickCallback
145
  // to initializes the tick callback during bootstrap.
146
171715
  CHECK(!tick_callback.IsEmpty());
147
148
343212
  if (tick_callback->Call(context, process, 0, nullptr).IsEmpty()) {
149
196
    failed_ = true;
150
  }
151
171497
  perform_stopping_check();
152
}
153
154
412946
MaybeLocal<Value> InternalMakeCallback(Environment* env,
155
                                       Local<Object> resource,
156
                                       Local<Object> recv,
157
                                       const Local<Function> callback,
158
                                       int argc,
159
                                       Local<Value> argv[],
160
                                       async_context asyncContext) {
161
412946
  CHECK(!recv.IsEmpty());
162
#ifdef DEBUG
163
  for (int i = 0; i < argc; i++)
164
    CHECK(!argv[i].IsEmpty());
165
#endif
166
167
412946
  Local<Function> hook_cb = env->async_hooks_callback_trampoline();
168
412996
  int flags = InternalCallbackScope::kNoFlags;
169
412996
  bool use_async_hooks_trampoline = false;
170
412996
  AsyncHooks* async_hooks = env->async_hooks();
171
412986
  if (!hook_cb.IsEmpty()) {
172
    // Use the callback trampoline if there are any before or after hooks, or
173
    // we can expect some kind of usage of async_hooks.executionAsyncResource().
174
412986
    flags = InternalCallbackScope::kSkipAsyncHooks;
175
412926
    use_async_hooks_trampoline =
176
825929
        async_hooks->fields()[AsyncHooks::kBefore] +
177
1238829
        async_hooks->fields()[AsyncHooks::kAfter] +
178
825869
        async_hooks->fields()[AsyncHooks::kUsesExecutionAsyncResource] > 0;
179
  }
180
181
825677
  InternalCallbackScope scope(env, resource, asyncContext, flags);
182
413000
  if (scope.Failed()) {
183
961
    return MaybeLocal<Value>();
184
  }
185
186
  MaybeLocal<Value> ret;
187
188
412027
  Local<Context> context = env->context();
189
411883
  if (use_async_hooks_trampoline) {
190
58948
    MaybeStackBuffer<Local<Value>, 16> args(3 + argc);
191
58952
    args[0] = v8::Number::New(env->isolate(), asyncContext.async_id);
192
58952
    args[1] = resource;
193
58952
    args[2] = callback;
194
39192
    for (int i = 0; i < argc; i++) {
195
9716
      args[i + 3] = argv[i];
196
    }
197
58952
    ret = hook_cb->Call(context, recv, args.length(), &args[0]);
198
  } else {
199
382407
    ret = callback->Call(context, recv, argc, argv);
200
  }
201
202
412044
  if (ret.IsEmpty()) {
203
1006
    scope.MarkAsFailed();
204
1006
    return MaybeLocal<Value>();
205
  }
206
207
411038
  scope.Close();
208
410792
  if (scope.Failed()) {
209
109
    return MaybeLocal<Value>();
210
  }
211
212
410675
  return ret;
213
}
214
215
// Public MakeCallback()s
216
217
9144
MaybeLocal<Value> MakeCallback(Isolate* isolate,
218
                               Local<Object> recv,
219
                               const char* method,
220
                               int argc,
221
                               Local<Value> argv[],
222
                               async_context asyncContext) {
223
  Local<String> method_string =
224
18287
      String::NewFromUtf8(isolate, method).ToLocalChecked();
225
9143
  return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext);
226
}
227
228
9152
MaybeLocal<Value> MakeCallback(Isolate* isolate,
229
                               Local<Object> recv,
230
                               Local<String> symbol,
231
                               int argc,
232
                               Local<Value> argv[],
233
                               async_context asyncContext) {
234
  // Check can_call_into_js() first because calling Get() might do so.
235
  Environment* env =
236
18304
      Environment::GetCurrent(recv->GetCreationContext().ToLocalChecked());
237
9152
  CHECK_NOT_NULL(env);
238
9154
  if (!env->can_call_into_js()) return Local<Value>();
239
240
  Local<Value> callback_v;
241
27450
  if (!recv->Get(isolate->GetCurrentContext(), symbol).ToLocal(&callback_v))
242
    return Local<Value>();
243
9150
  if (!callback_v->IsFunction()) {
244
    // This used to return an empty value, but Undefined() makes more sense
245
    // since no exception is pending here.
246
    return Undefined(isolate);
247
  }
248
9150
  Local<Function> callback = callback_v.As<Function>();
249
9150
  return MakeCallback(isolate, recv, callback, argc, argv, asyncContext);
250
}
251
252
73489
MaybeLocal<Value> MakeCallback(Isolate* isolate,
253
                               Local<Object> recv,
254
                               Local<Function> callback,
255
                               int argc,
256
                               Local<Value> argv[],
257
                               async_context asyncContext) {
258
  // Observe the following two subtleties:
259
  //
260
  // 1. The environment is retrieved from the callback function's context.
261
  // 2. The context to enter is retrieved from the environment.
262
  //
263
  // Because of the AssignToContext() call in src/node_contextify.cc,
264
  // the two contexts need not be the same.
265
  Environment* env =
266
146978
      Environment::GetCurrent(callback->GetCreationContext().ToLocalChecked());
267
73489
  CHECK_NOT_NULL(env);
268
73489
  Context::Scope context_scope(env->context());
269
  MaybeLocal<Value> ret =
270
73488
      InternalMakeCallback(env, recv, recv, callback, argc, argv, asyncContext);
271

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

14532
}  // namespace node