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: 118 130 90.8 %
Date: 2020-06-24 22:13:30 Branches: 74 88 84.1 %

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

661713
  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
36014
    AsyncWrap::EmitBefore(env, asyncContext.async_id);
74
  }
75
}
76
77
1324216
InternalCallbackScope::~InternalCallbackScope() {
78
662122
  Close();
79
662096
  env_->PopAsyncCallbackScope();
80
662094
}
81
82
1272267
void InternalCallbackScope::Close() {
83
2127299
  if (closed_) return;
84
662212
  closed_ = true;
85
86
662212
  if (!env_->can_call_into_js()) return;
87
1261806
  auto perform_stopping_check = [&]() {
88
1261817
    if (env_->is_stopping()) {
89
11
      MarkAsFailed();
90
11
      env_->async_hooks()->clear_async_id_stack();
91
    }
92
1923132
  };
93
661322
  perform_stopping_check();
94
95

661320
  if (!failed_ && async_context_.async_id != 0 && !skip_hooks_) {
96
36002
    AsyncWrap::EmitAfter(env_, async_context_.async_id);
97
  }
98
99
661322
  if (pushed_ids_)
100
661322
    env_->async_hooks()->pop_async_context(async_context_.async_id);
101
102
661325
  if (failed_) return;
103
104

660722
  if (env_->async_callback_scope_depth() > 1 || skip_task_queues_) {
105
60524
    return;
106
  }
107
108
600198
  TickInfo* tick_info = env_->tick_info();
109
110
600198
  if (!env_->can_call_into_js()) return;
111
112
1617393
  auto weakref_cleanup = OnScopeLeave([&]() { env_->RunWeakRefCleanup(); });
113
114
600199
  if (!tick_info->has_tick_scheduled()) {
115
183407
    MicrotasksScope::PerformCheckpoint(env_->isolate());
116
117
183383
    perform_stopping_check();
118
  }
119
120
  // Make sure the stack unwound properly. If there are nested MakeCallback's
121
  // then it should return early and not reach this code.
122
600176
  if (env_->async_hooks()->fields()[AsyncHooks::kTotals]) {
123
38001
    CHECK_EQ(env_->execution_async_id(), 0);
124
38001
    CHECK_EQ(env_->trigger_async_id(), 0);
125
  }
126
127

600178
  if (!tick_info->has_tick_scheduled() && !tick_info->has_rejection_to_warn()) {
128
182955
    return;
129
  }
130
131
834340
  HandleScope handle_scope(env_->isolate());
132
417222
  Local<Object> process = env_->process_object();
133
134
417222
  if (!env_->can_call_into_js()) return;
135
136
417222
  Local<Function> tick_callback = env_->tick_callback_function();
137
138
  // The tick is triggered before JS land calls SetTickCallback
139
  // to initializes the tick callback during bootstrap.
140
417222
  CHECK(!tick_callback.IsEmpty());
141
142
1251563
  if (tick_callback->Call(env_->context(), process, 0, nullptr).IsEmpty()) {
143
534
    failed_ = true;
144
  }
145
417119
  perform_stopping_check();
146
}
147
148
611539
MaybeLocal<Value> InternalMakeCallback(Environment* env,
149
                                       Local<Object> resource,
150
                                       Local<Object> recv,
151
                                       const Local<Function> callback,
152
                                       int argc,
153
                                       Local<Value> argv[],
154
                                       async_context asyncContext) {
155
611539
  CHECK(!recv.IsEmpty());
156
#ifdef DEBUG
157
  for (int i = 0; i < argc; i++)
158
    CHECK(!argv[i].IsEmpty());
159
#endif
160
161
611539
  Local<Function> hook_cb = env->async_hooks_callback_trampoline();
162
611577
  int flags = InternalCallbackScope::kNoFlags;
163
611577
  int hook_count = 0;
164
611577
  if (!hook_cb.IsEmpty()) {
165
611587
    flags = InternalCallbackScope::kSkipAsyncHooks;
166
611587
    AsyncHooks* async_hooks = env->async_hooks();
167
1223115
    hook_count = async_hooks->fields()[AsyncHooks::kBefore] +
168
1223130
                 async_hooks->fields()[AsyncHooks::kAfter];
169
  }
170
171
1223072
  InternalCallbackScope scope(env, resource, asyncContext, flags);
172
611601
  if (scope.Failed()) {
173
771
    return MaybeLocal<Value>();
174
  }
175
176
  MaybeLocal<Value> ret;
177
178
610823
  if (hook_count != 0) {
179
53151
    MaybeStackBuffer<Local<Value>, 16> args(2 + argc);
180
53156
    args[0] = v8::Number::New(env->isolate(), asyncContext.async_id);
181
53156
    args[1] = callback;
182
32584
    for (int i = 0; i < argc; i++) {
183
6006
      args[i + 2] = argv[i];
184
    }
185
79734
    ret = hook_cb->Call(env->context(), recv, args.length(), &args[0]);
186
  } else {
187
1168494
    ret = callback->Call(env->context(), recv, argc, argv);
188
  }
189
190
610792
  if (ret.IsEmpty()) {
191
636
    scope.MarkAsFailed();
192
636
    return MaybeLocal<Value>();
193
  }
194
195
610156
  scope.Close();
196
610064
  if (scope.Failed()) {
197
502
    return MaybeLocal<Value>();
198
  }
199
200
609562
  return ret;
201
}
202
203
// Public MakeCallback()s
204
205
8358
MaybeLocal<Value> MakeCallback(Isolate* isolate,
206
                               Local<Object> recv,
207
                               const char* method,
208
                               int argc,
209
                               Local<Value> argv[],
210
                               async_context asyncContext) {
211
  Local<String> method_string =
212
16716
      String::NewFromUtf8(isolate, method, NewStringType::kNormal)
213
8358
          .ToLocalChecked();
214
8358
  return MakeCallback(isolate, recv, method_string, argc, argv, asyncContext);
215
}
216
217
8367
MaybeLocal<Value> MakeCallback(Isolate* isolate,
218
                               Local<Object> recv,
219
                               Local<String> symbol,
220
                               int argc,
221
                               Local<Value> argv[],
222
                               async_context asyncContext) {
223
  Local<Value> callback_v =
224
25101
      recv->Get(isolate->GetCurrentContext(), symbol).ToLocalChecked();
225
8367
  if (callback_v.IsEmpty()) return Local<Value>();
226
8443
  if (!callback_v->IsFunction()) return Local<Value>();
227
8291
  Local<Function> callback = callback_v.As<Function>();
228
8291
  return MakeCallback(isolate, recv, callback, argc, argv, asyncContext);
229
}
230
231
38679
MaybeLocal<Value> MakeCallback(Isolate* isolate,
232
                               Local<Object> recv,
233
                               Local<Function> callback,
234
                               int argc,
235
                               Local<Value> argv[],
236
                               async_context asyncContext) {
237
  // Observe the following two subtleties:
238
  //
239
  // 1. The environment is retrieved from the callback function's context.
240
  // 2. The context to enter is retrieved from the environment.
241
  //
242
  // Because of the AssignToContext() call in src/node_contextify.cc,
243
  // the two contexts need not be the same.
244
38679
  Environment* env = Environment::GetCurrent(callback->CreationContext());
245
38679
  CHECK_NOT_NULL(env);
246
38679
  Context::Scope context_scope(env->context());
247
  MaybeLocal<Value> ret =
248
38678
      InternalMakeCallback(env, recv, recv, callback, argc, argv, asyncContext);
249

38659
  if (ret.IsEmpty() && env->async_callback_scope_depth() == 0) {
250
    // This is only for legacy compatibility and we may want to look into
251
    // removing/adjusting it.
252
2096
    return Undefined(env->isolate());
253
  }
254
37611
  return ret;
255
}
256
257
// Legacy MakeCallback()s
258
259
Local<Value> MakeCallback(Isolate* isolate,
260
                          Local<Object> recv,
261
                          const char* method,
262
                          int argc,
263
                          Local<Value>* argv) {
264
  EscapableHandleScope handle_scope(isolate);
265
  return handle_scope.Escape(
266
      MakeCallback(isolate, recv, method, argc, argv, {0, 0})
267
          .FromMaybe(Local<Value>()));
268
}
269
270
Local<Value> MakeCallback(Isolate* isolate,
271
                          Local<Object> recv,
272
                          Local<String> symbol,
273
                          int argc,
274
                          Local<Value>* argv) {
275
  EscapableHandleScope handle_scope(isolate);
276
  return handle_scope.Escape(
277
      MakeCallback(isolate, recv, symbol, argc, argv, {0, 0})
278
          .FromMaybe(Local<Value>()));
279
}
280
281
Local<Value> MakeCallback(Isolate* isolate,
282
                          Local<Object> recv,
283
                          Local<Function> callback,
284
                          int argc,
285
                          Local<Value>* argv) {
286
  EscapableHandleScope handle_scope(isolate);
287
  return handle_scope.Escape(
288
      MakeCallback(isolate, recv, callback, argc, argv, {0, 0})
289
          .FromMaybe(Local<Value>()));
290
}
291
292
}  // namespace node