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: 130 146 89.0 %
Date: 2020-12-12 04:11:07 Branches: 81 102 79.4 %

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
51604
InternalCallbackScope::InternalCallbackScope(AsyncWrap* async_wrap, int flags)
37
    : InternalCallbackScope(async_wrap->env(),
38
                            async_wrap->object(),
39
51604
                            { async_wrap->get_async_id(),
40
51604
                              async_wrap->get_trigger_async_id() },
41
103208
                            flags) {}
42
43
1253627
InternalCallbackScope::InternalCallbackScope(Environment* env,
44
                                             Local<Object> object,
45
                                             const async_context& asyncContext,
46
1253627
                                             int flags)
47
  : env_(env),
48
    async_context_(asyncContext),
49
    object_(object),
50
1253627
    skip_hooks_(flags & kSkipAsyncHooks),
51
2507254
    skip_task_queues_(flags & kSkipTaskQueues) {
52
1253627
  CHECK_NOT_NULL(env);
53
1253627
  env->PushAsyncCallbackScope();
54
55
1253651
  if (!env->can_call_into_js()) {
56
10325
    failed_ = true;
57
10325
    return;
58
  }
59
60
2486723
  HandleScope handle_scope(env->isolate());
61
  // If you hit this assertion, you forgot to enter the v8::Context first.
62
1243359
  CHECK_EQ(Environment::GetCurrent(env->isolate()), env);
63
64
1243416
  env->async_hooks()->push_async_context(
65
1243410
    async_context_.async_id, async_context_.trigger_async_id, object);
66
67
1243371
  pushed_ids_ = true;
68
69

1243371
  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
52244
    AsyncWrap::EmitBefore(env, asyncContext.async_id);
73
  }
74
}
75
76
2506542
InternalCallbackScope::~InternalCallbackScope() {
77
1253312
  Close();
78
1253222
  env_->PopAsyncCallbackScope();
79
1253230
}
80
81
1939693
void InternalCallbackScope::Close() {
82
3467807
  if (closed_) return;
83
1253335
  closed_ = true;
84
85
1253335
  if (!env_->can_call_into_js()) return;
86
2404313
  auto perform_stopping_check = [&]() {
87
2404331
    if (env_->is_stopping()) {
88
18
      MarkAsFailed();
89
18
      env_->async_hooks()->clear_async_id_stack();
90
    }
91
3647121
  };
92
1242891
  perform_stopping_check();
93
94

1242858
  if (!failed_ && async_context_.async_id != 0 && !skip_hooks_) {
95
52232
    AsyncWrap::EmitAfter(env_, async_context_.async_id);
96
  }
97
98
1242863
  if (pushed_ids_)
99
1242863
    env_->async_hooks()->pop_async_context(async_context_.async_id);
100
101
1242931
  if (failed_) return;
102
103

1241944
  if (env_->async_callback_scope_depth() > 1 || skip_task_queues_) {
104
81022
    return;
105
  }
106
107
1160920
  TickInfo* tick_info = env_->tick_info();
108
109
1160917
  if (!env_->can_call_into_js()) return;
110
111
2733274
  auto weakref_cleanup = OnScopeLeave([&]() { env_->RunWeakRefCleanup(); });
112
113
1160865
  if (!tick_info->has_tick_scheduled()) {
114
749928
    MicrotasksScope::PerformCheckpoint(env_->isolate());
115
116
750053
    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
1160979
  if (env_->async_hooks()->fields()[AsyncHooks::kTotals]) {
122
64234
    CHECK_EQ(env_->execution_async_id(), 0);
123
64234
    CHECK_EQ(env_->trigger_async_id(), 0);
124
  }
125
126

1160976
  if (!tick_info->has_tick_scheduled() && !tick_info->has_rejection_to_warn()) {
127
749367
    return;
128
  }
129
130
823104
  HandleScope handle_scope(env_->isolate());
131
411601
  Local<Object> process = env_->process_object();
132
133
411601
  if (!env_->can_call_into_js()) return;
134
135
411601
  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
411601
  CHECK(!tick_callback.IsEmpty());
140
141
1234705
  if (tick_callback->Call(env_->context(), process, 0, nullptr).IsEmpty()) {
142
158
    failed_ = true;
143
  }
144
411503
  perform_stopping_check();
145
}
146
147
688345
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
688345
  CHECK(!recv.IsEmpty());
155
#ifdef DEBUG
156
  for (int i = 0; i < argc; i++)
157
    CHECK(!argv[i].IsEmpty());
158
#endif
159
160
688345
  Local<Function> hook_cb = env->async_hooks_callback_trampoline();
161
688440
  int flags = InternalCallbackScope::kNoFlags;
162
688440
  bool use_async_hooks_trampoline = false;
163
688440
  AsyncHooks* async_hooks = env->async_hooks();
164
688447
  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
688440
    flags = InternalCallbackScope::kSkipAsyncHooks;
168
688465
    use_async_hooks_trampoline =
169
1376910
        async_hooks->fields()[AsyncHooks::kBefore] +
170
2065396
        async_hooks->fields()[AsyncHooks::kAfter] +
171
1376935
        async_hooks->fields()[AsyncHooks::kUsesExecutionAsyncResource] > 0;
172
  }
173
174
1376836
  InternalCallbackScope scope(env, resource, asyncContext, flags);
175
688470
  if (scope.Failed()) {
176
908
    return MaybeLocal<Value>();
177
  }
178
179
  MaybeLocal<Value> ret;
180
181
687471
  if (use_async_hooks_trampoline) {
182
56280
    MaybeStackBuffer<Local<Value>, 16> args(3 + argc);
183
56284
    args[0] = v8::Number::New(env->isolate(), asyncContext.async_id);
184
56284
    args[1] = resource;
185
56284
    args[2] = callback;
186
36450
    for (int i = 0; i < argc; i++) {
187
8308
      args[i + 3] = argv[i];
188
    }
189
84426
    ret = hook_cb->Call(env->context(), recv, args.length(), &args[0]);
190
  } else {
191
1318754
    ret = callback->Call(env->context(), recv, argc, argv);
192
  }
193
194
687553
  if (ret.IsEmpty()) {
195
1026
    scope.MarkAsFailed();
196
1026
    return MaybeLocal<Value>();
197
  }
198
199
686527
  scope.Close();
200
686432
  if (scope.Failed()) {
201
75
    return MaybeLocal<Value>();
202
  }
203
204
686355
  return ret;
205
}
206
207
// Public MakeCallback()s
208
209
9006
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
18013
      String::NewFromUtf8(isolate, method).ToLocalChecked();
217
9007
  return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext);
218
}
219
220
9015
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
9015
  Environment* env = Environment::GetCurrent(recv->CreationContext());
228
9015
  CHECK_NOT_NULL(env);
229
9015
  if (!env->can_call_into_js()) return Local<Value>();
230
231
  Local<Value> callback_v;
232
27046
  if (!recv->Get(isolate->GetCurrentContext(), symbol).ToLocal(&callback_v))
233
    return Local<Value>();
234
9016
  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
9016
  Local<Function> callback = callback_v.As<Function>();
240
9016
  return MakeCallback(isolate, recv, callback, argc, argv, asyncContext);
241
}
242
243
110197
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
110197
  Environment* env = Environment::GetCurrent(callback->CreationContext());
257
110197
  CHECK_NOT_NULL(env);
258
110197
  Context::Scope context_scope(env->context());
259
  MaybeLocal<Value> ret =
260
110196
      InternalMakeCallback(env, recv, recv, callback, argc, argv, asyncContext);
261

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

14073
}  // namespace node