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: 2021-01-16 04:10:54 Branches: 80 102 78.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::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
51530
InternalCallbackScope::InternalCallbackScope(AsyncWrap* async_wrap, int flags)
36
    : InternalCallbackScope(async_wrap->env(),
37
                            async_wrap->object(),
38
51530
                            { async_wrap->get_async_id(),
39
51530
                              async_wrap->get_trigger_async_id() },
40
103060
                            flags) {}
41
42
1254334
InternalCallbackScope::InternalCallbackScope(Environment* env,
43
                                             Local<Object> object,
44
                                             const async_context& asyncContext,
45
1254334
                                             int flags)
46
  : env_(env),
47
    async_context_(asyncContext),
48
    object_(object),
49
1254334
    skip_hooks_(flags & kSkipAsyncHooks),
50
2508668
    skip_task_queues_(flags & kSkipTaskQueues) {
51
1254334
  CHECK_NOT_NULL(env);
52
1254334
  env->PushAsyncCallbackScope();
53
54
1254431
  if (!env->can_call_into_js()) {
55
10032
    failed_ = true;
56
10032
    return;
57
  }
58
59
2488784
  HandleScope handle_scope(env->isolate());
60
  // If you hit this assertion, you forgot to enter the v8::Context first.
61
1244390
  CHECK_EQ(Environment::GetCurrent(env->isolate()), env);
62
63
1244484
  env->async_hooks()->push_async_context(
64
1244482
    async_context_.async_id, async_context_.trigger_async_id, object);
65
66
1244399
  pushed_ids_ = true;
67
68

1244399
  if (asyncContext.async_id != 0 && !skip_hooks_) {
69
    // No need to check a return value because the application will exit if
70
    // an exception occurs.
71
52170
    AsyncWrap::EmitBefore(env, asyncContext.async_id);
72
  }
73
}
74
75
2507732
InternalCallbackScope::~InternalCallbackScope() {
76
1253903
  Close();
77
1253826
  env_->PopAsyncCallbackScope();
78
1253829
}
79
80
1944000
void InternalCallbackScope::Close() {
81
3476190
  if (closed_) return;
82
1254049
  closed_ = true;
83
84
1254049
  if (!env_->can_call_into_js()) return;
85
2406257
  auto perform_stopping_check = [&]() {
86
2406275
    if (env_->is_stopping()) {
87
18
      MarkAsFailed();
88
18
      env_->async_hooks()->clear_async_id_stack();
89
    }
90
3650064
  };
91
1243913
  perform_stopping_check();
92
93

1243852
  if (!failed_ && async_context_.async_id != 0 && !skip_hooks_) {
94
52158
    AsyncWrap::EmitAfter(env_, async_context_.async_id);
95
  }
96
97
1243854
  if (pushed_ids_)
98
1243854
    env_->async_hooks()->pop_async_context(async_context_.async_id);
99
100
1243852
  if (failed_) return;
101
102

1242865
  if (env_->async_callback_scope_depth() > 1 || skip_task_queues_) {
103
80943
    return;
104
  }
105
106
1161920
  TickInfo* tick_info = env_->tick_info();
107
108
1161923
  if (!env_->can_call_into_js()) return;
109
110
2735414
  auto weakref_cleanup = OnScopeLeave([&]() { env_->RunWeakRefCleanup(); });
111
112
1161954
  if (!tick_info->has_tick_scheduled()) {
113
1501598
    env_->context()->GetMicrotaskQueue()->PerformCheckpoint(env_->isolate());
114
115
750910
    perform_stopping_check();
116
  }
117
118
  // Make sure the stack unwound properly. If there are nested MakeCallback's
119
  // then it should return early and not reach this code.
120
1162052
  if (env_->async_hooks()->fields()[AsyncHooks::kTotals]) {
121
64225
    CHECK_EQ(env_->execution_async_id(), 0);
122
64225
    CHECK_EQ(env_->trigger_async_id(), 0);
123
  }
124
125

1162046
  if (!tick_info->has_tick_scheduled() && !tick_info->has_rejection_to_warn()) {
126
750217
    return;
127
  }
128
129
823414
  HandleScope handle_scope(env_->isolate());
130
411803
  Local<Object> process = env_->process_object();
131
132
411802
  if (!env_->can_call_into_js()) return;
133
134
411802
  Local<Function> tick_callback = env_->tick_callback_function();
135
136
  // The tick is triggered before JS land calls SetTickCallback
137
  // to initializes the tick callback during bootstrap.
138
411802
  CHECK(!tick_callback.IsEmpty());
139
140
1235216
  if (tick_callback->Call(env_->context(), process, 0, nullptr).IsEmpty()) {
141
158
    failed_ = true;
142
  }
143
411613
  perform_stopping_check();
144
}
145
146
691865
MaybeLocal<Value> InternalMakeCallback(Environment* env,
147
                                       Local<Object> resource,
148
                                       Local<Object> recv,
149
                                       const Local<Function> callback,
150
                                       int argc,
151
                                       Local<Value> argv[],
152
                                       async_context asyncContext) {
153
691865
  CHECK(!recv.IsEmpty());
154
#ifdef DEBUG
155
  for (int i = 0; i < argc; i++)
156
    CHECK(!argv[i].IsEmpty());
157
#endif
158
159
691865
  Local<Function> hook_cb = env->async_hooks_callback_trampoline();
160
692065
  int flags = InternalCallbackScope::kNoFlags;
161
692065
  bool use_async_hooks_trampoline = false;
162
692065
  AsyncHooks* async_hooks = env->async_hooks();
163
692083
  if (!hook_cb.IsEmpty()) {
164
    // Use the callback trampoline if there are any before or after hooks, or
165
    // we can expect some kind of usage of async_hooks.executionAsyncResource().
166
692124
    flags = InternalCallbackScope::kSkipAsyncHooks;
167
692175
    use_async_hooks_trampoline =
168
1384301
        async_hooks->fields()[AsyncHooks::kBefore] +
169
2076498
        async_hooks->fields()[AsyncHooks::kAfter] +
170
1384352
        async_hooks->fields()[AsyncHooks::kUsesExecutionAsyncResource] > 0;
171
  }
172
173
1384102
  InternalCallbackScope scope(env, resource, asyncContext, flags);
174
692215
  if (scope.Failed()) {
175
896
    return MaybeLocal<Value>();
176
  }
177
178
  MaybeLocal<Value> ret;
179
180
690997
  if (use_async_hooks_trampoline) {
181
56296
    MaybeStackBuffer<Local<Value>, 16> args(3 + argc);
182
56300
    args[0] = v8::Number::New(env->isolate(), asyncContext.async_id);
183
56300
    args[1] = resource;
184
56300
    args[2] = callback;
185
36469
    for (int i = 0; i < argc; i++) {
186
8319
      args[i + 3] = argv[i];
187
    }
188
84450
    ret = hook_cb->Call(env->context(), recv, args.length(), &args[0]);
189
  } else {
190
1325918
    ret = callback->Call(env->context(), recv, argc, argv);
191
  }
192
193
691262
  if (ret.IsEmpty()) {
194
1027
    scope.MarkAsFailed();
195
1027
    return MaybeLocal<Value>();
196
  }
197
198
690235
  scope.Close();
199
690045
  if (scope.Failed()) {
200
76
    return MaybeLocal<Value>();
201
  }
202
203
689969
  return ret;
204
}
205
206
// Public MakeCallback()s
207
208
8718
MaybeLocal<Value> MakeCallback(Isolate* isolate,
209
                               Local<Object> recv,
210
                               const char* method,
211
                               int argc,
212
                               Local<Value> argv[],
213
                               async_context asyncContext) {
214
  Local<String> method_string =
215
17437
      String::NewFromUtf8(isolate, method).ToLocalChecked();
216
8719
  return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext);
217
}
218
219
8726
MaybeLocal<Value> MakeCallback(Isolate* isolate,
220
                               Local<Object> recv,
221
                               Local<String> symbol,
222
                               int argc,
223
                               Local<Value> argv[],
224
                               async_context asyncContext) {
225
  // Check can_call_into_js() first because calling Get() might do so.
226
8726
  Environment* env = Environment::GetCurrent(recv->CreationContext());
227
8727
  CHECK_NOT_NULL(env);
228
8727
  if (!env->can_call_into_js()) return Local<Value>();
229
230
  Local<Value> callback_v;
231
26183
  if (!recv->Get(isolate->GetCurrentContext(), symbol).ToLocal(&callback_v))
232
    return Local<Value>();
233
8727
  if (!callback_v->IsFunction()) {
234
    // This used to return an empty value, but Undefined() makes more sense
235
    // since no exception is pending here.
236
    return Undefined(isolate);
237
  }
238
8728
  Local<Function> callback = callback_v.As<Function>();
239
8728
  return MakeCallback(isolate, recv, callback, argc, argv, asyncContext);
240
}
241
242
115390
MaybeLocal<Value> MakeCallback(Isolate* isolate,
243
                               Local<Object> recv,
244
                               Local<Function> callback,
245
                               int argc,
246
                               Local<Value> argv[],
247
                               async_context asyncContext) {
248
  // Observe the following two subtleties:
249
  //
250
  // 1. The environment is retrieved from the callback function's context.
251
  // 2. The context to enter is retrieved from the environment.
252
  //
253
  // Because of the AssignToContext() call in src/node_contextify.cc,
254
  // the two contexts need not be the same.
255
115390
  Environment* env = Environment::GetCurrent(callback->CreationContext());
256
115389
  CHECK_NOT_NULL(env);
257
115389
  Context::Scope context_scope(env->context());
258
  MaybeLocal<Value> ret =
259
115387
      InternalMakeCallback(env, recv, recv, callback, argc, argv, asyncContext);
260

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

13995
}  // namespace node