GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/api/environment.cc Lines: 175 232 75.4 %
Date: 2019-09-26 22:31:05 Branches: 87 157 55.4 %

Line Branch Exec Source
1
#include "node.h"
2
#include "node_context_data.h"
3
#include "node_errors.h"
4
#include "node_internals.h"
5
#include "node_native_module_env.h"
6
#include "node_platform.h"
7
#include "node_v8_platform-inl.h"
8
#include "uv.h"
9
10
namespace node {
11
using errors::TryCatchScope;
12
using v8::Array;
13
using v8::Context;
14
using v8::EscapableHandleScope;
15
using v8::Function;
16
using v8::HandleScope;
17
using v8::Isolate;
18
using v8::Local;
19
using v8::MaybeLocal;
20
using v8::MicrotasksPolicy;
21
using v8::Null;
22
using v8::Object;
23
using v8::ObjectTemplate;
24
using v8::Private;
25
using v8::String;
26
using v8::Value;
27
28
22
static bool AllowWasmCodeGenerationCallback(Local<Context> context,
29
                                            Local<String>) {
30
  Local<Value> wasm_code_gen =
31
44
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
32

66
  return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
33
}
34
35
32
static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
36
32
  DebugSealHandleScope scope(isolate);
37
32
  Environment* env = Environment::GetCurrent(isolate);
38
32
  return env != nullptr &&
39

95
         (env->is_main_thread() || !env->is_stopping()) &&
40

158
         env->should_abort_on_uncaught_toggle()[0] &&
41
66
         !env->inside_should_not_abort_on_uncaught_scope();
42
}
43
44
69869
static MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
45
                                      Local<Value> exception,
46
                                      Local<Array> trace) {
47
69869
  Environment* env = Environment::GetCurrent(context);
48
69869
  if (env == nullptr) {
49
    MaybeLocal<String> s = exception->ToString(context);
50
    return s.IsEmpty() ?
51
      MaybeLocal<Value>() :
52
      MaybeLocal<Value>(s.ToLocalChecked());
53
  }
54
69869
  Local<Function> prepare = env->prepare_stack_trace_callback();
55
69869
  if (prepare.IsEmpty()) {
56
    MaybeLocal<String> s = exception->ToString(context);
57
    return s.IsEmpty() ?
58
      MaybeLocal<Value>() :
59
      MaybeLocal<Value>(s.ToLocalChecked());
60
  }
61
  Local<Value> args[] = {
62
      context->Global(),
63
      exception,
64
      trace,
65
279476
  };
66
  // This TryCatch + Rethrow is required by V8 due to details around exception
67
  // handling there. For C++ callbacks, V8 expects a scheduled exception (which
68
  // is what ReThrow gives us). Just returning the empty MaybeLocal would leave
69
  // us with a pending exception.
70
69869
  TryCatchScope try_catch(env);
71
  MaybeLocal<Value> result = prepare->Call(
72
139738
      context, Undefined(env->isolate()), arraysize(args), args);
73

69869
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
74
2
    try_catch.ReThrow();
75
  }
76
69869
  return result;
77
}
78
79
908197
void* NodeArrayBufferAllocator::Allocate(size_t size) {
80

908197
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
81
61738
    return UncheckedCalloc(size);
82
  else
83
846459
    return UncheckedMalloc(size);
84
}
85
86
3
DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
87
1
  CHECK(allocations_.empty());
88
2
}
89
90
27
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
91
27
  Mutex::ScopedLock lock(mutex_);
92
27
  void* data = NodeArrayBufferAllocator::Allocate(size);
93
27
  RegisterPointerInternal(data, size);
94
27
  return data;
95
}
96
97
5
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
98
5
  Mutex::ScopedLock lock(mutex_);
99
5
  void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
100
5
  RegisterPointerInternal(data, size);
101
5
  return data;
102
}
103
104
32
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
105
32
  Mutex::ScopedLock lock(mutex_);
106
32
  UnregisterPointerInternal(data, size);
107
32
  NodeArrayBufferAllocator::Free(data, size);
108
32
}
109
110
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
111
                                                size_t old_size,
112
                                                size_t size) {
113
  Mutex::ScopedLock lock(mutex_);
114
  void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size);
115
  if (ret == nullptr) {
116
    if (size == 0)  // i.e. equivalent to free().
117
      UnregisterPointerInternal(data, old_size);
118
    return nullptr;
119
  }
120
121
  if (data != nullptr) {
122
    auto it = allocations_.find(data);
123
    CHECK_NE(it, allocations_.end());
124
    allocations_.erase(it);
125
  }
126
127
  RegisterPointerInternal(ret, size);
128
  return ret;
129
}
130
131
void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
132
  Mutex::ScopedLock lock(mutex_);
133
  RegisterPointerInternal(data, size);
134
}
135
136
void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
137
  Mutex::ScopedLock lock(mutex_);
138
  UnregisterPointerInternal(data, size);
139
}
140
141
32
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
142
                                                              size_t size) {
143
64
  if (data == nullptr) return;
144
32
  auto it = allocations_.find(data);
145
32
  CHECK_NE(it, allocations_.end());
146
32
  if (size > 0) {
147
    // We allow allocations with size 1 for 0-length buffers to avoid having
148
    // to deal with nullptr values.
149
32
    CHECK_EQ(it->second, size);
150
  }
151
32
  allocations_.erase(it);
152
}
153
154
32
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
155
                                                            size_t size) {
156
64
  if (data == nullptr) return;
157
32
  CHECK_EQ(allocations_.count(data), 0);
158
32
  allocations_[data] = size;
159
}
160
161
5111
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
162

5111
  if (debug || per_process::cli_options->debug_arraybuffer_allocations)
163
2
    return std::make_unique<DebuggingArrayBufferAllocator>();
164
  else
165
5109
    return std::make_unique<NodeArrayBufferAllocator>();
166
}
167
168
ArrayBufferAllocator* CreateArrayBufferAllocator() {
169
  return ArrayBufferAllocator::Create().release();
170
}
171
172
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
173
  delete allocator;
174
}
175
176
5110
void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
177
5110
  const uint64_t constrained_memory = uv_get_constrained_memory();
178
5110
  const uint64_t total_memory = constrained_memory > 0 ?
179
5110
      std::min(uv_get_total_memory(), constrained_memory) :
180
10220
      uv_get_total_memory();
181
5110
  if (total_memory > 0) {
182
    // V8 defaults to 700MB or 1.4GB on 32 and 64 bit platforms respectively.
183
    // This default is based on browser use-cases. Tell V8 to configure the
184
    // heap based on the actual physical memory.
185
5110
    params->constraints.ConfigureDefaults(total_memory, 0);
186
  }
187
5110
}
188
189
10221
void SetIsolateUpForNode(v8::Isolate* isolate, IsolateSettingCategories cat) {
190
10221
  switch (cat) {
191
    case IsolateSettingCategories::kErrorHandlers:
192
      isolate->AddMessageListenerWithErrorLevel(
193
          errors::PerIsolateMessageListener,
194
          Isolate::MessageErrorLevel::kMessageError |
195
5110
              Isolate::MessageErrorLevel::kMessageWarning);
196
      isolate->SetAbortOnUncaughtExceptionCallback(
197
5110
          ShouldAbortOnUncaughtException);
198
5110
      isolate->SetFatalErrorHandler(OnFatalError);
199
5110
      isolate->SetPrepareStackTraceCallback(PrepareStackTraceCallback);
200
5110
      break;
201
    case IsolateSettingCategories::kMisc:
202
5111
      isolate->SetMicrotasksPolicy(MicrotasksPolicy::kExplicit);
203
      isolate->SetAllowWasmCodeGenerationCallback(
204
5111
          AllowWasmCodeGenerationCallback);
205
5111
      isolate->SetPromiseRejectCallback(task_queue::PromiseRejectCallback);
206
5111
      v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
207
5111
      break;
208
    default:
209
      UNREACHABLE();
210
      break;
211
  }
212
10221
}
213
214
216
void SetIsolateUpForNode(v8::Isolate* isolate) {
215
216
  SetIsolateUpForNode(isolate, IsolateSettingCategories::kErrorHandlers);
216
216
  SetIsolateUpForNode(isolate, IsolateSettingCategories::kMisc);
217
216
}
218
219
216
Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
220
216
  return NewIsolate(allocator, event_loop, GetMainThreadMultiIsolatePlatform());
221
}
222
223
// TODO(joyeecheung): we may want to expose this, but then we need to be
224
// careful about what we override in the params.
225
216
Isolate* NewIsolate(Isolate::CreateParams* params,
226
                    uv_loop_t* event_loop,
227
                    MultiIsolatePlatform* platform) {
228
216
  Isolate* isolate = Isolate::Allocate();
229
216
  if (isolate == nullptr) return nullptr;
230
231
  // Register the isolate on the platform before the isolate gets initialized,
232
  // so that the isolate can access the platform during initialization.
233
216
  platform->RegisterIsolate(isolate, event_loop);
234
235
216
  SetIsolateCreateParamsForNode(params);
236
216
  Isolate::Initialize(isolate, *params);
237
216
  SetIsolateUpForNode(isolate);
238
239
216
  return isolate;
240
}
241
242
216
Isolate* NewIsolate(ArrayBufferAllocator* allocator,
243
                    uv_loop_t* event_loop,
244
                    MultiIsolatePlatform* platform) {
245
216
  Isolate::CreateParams params;
246
216
  if (allocator != nullptr) params.array_buffer_allocator = allocator;
247
216
  return NewIsolate(&params, event_loop, platform);
248
}
249
250
216
IsolateData* CreateIsolateData(Isolate* isolate,
251
                               uv_loop_t* loop,
252
                               MultiIsolatePlatform* platform,
253
                               ArrayBufferAllocator* allocator) {
254
216
  return new IsolateData(isolate, loop, platform, allocator);
255
}
256
257
216
void FreeIsolateData(IsolateData* isolate_data) {
258
216
  delete isolate_data;
259
216
}
260
261
Environment* CreateEnvironment(IsolateData* isolate_data,
262
                               Local<Context> context,
263
                               int argc,
264
                               const char* const* argv,
265
                               int exec_argc,
266
                               const char* const* exec_argv) {
267
  Isolate* isolate = context->GetIsolate();
268
  HandleScope handle_scope(isolate);
269
  Context::Scope context_scope(context);
270
  // TODO(addaleax): This is a much better place for parsing per-Environment
271
  // options than the global parse call.
272
  std::vector<std::string> args(argv, argv + argc);
273
  std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
274
  // TODO(addaleax): Provide more sensible flags, in an embedder-accessible way.
275
  Environment* env = new Environment(
276
      isolate_data,
277
      context,
278
      args,
279
      exec_args,
280
      static_cast<Environment::Flags>(Environment::kIsMainThread |
281
                                      Environment::kOwnsProcessState |
282
                                      Environment::kOwnsInspector));
283
  env->InitializeLibuv(per_process::v8_is_profiling);
284
  if (env->RunBootstrapping().IsEmpty()) {
285
    return nullptr;
286
  }
287
288
  std::vector<Local<String>> parameters = {
289
      env->require_string(),
290
      FIXED_ONE_BYTE_STRING(env->isolate(), "markBootstrapComplete")};
291
  std::vector<Local<Value>> arguments = {
292
      env->native_module_require(),
293
      env->NewFunctionTemplate(MarkBootstrapComplete)
294
          ->GetFunction(env->context())
295
          .ToLocalChecked()};
296
  if (ExecuteBootstrapper(
297
          env, "internal/bootstrap/environment", &parameters, &arguments)
298
          .IsEmpty()) {
299
    return nullptr;
300
  }
301
  return env;
302
}
303
304
209
void FreeEnvironment(Environment* env) {
305
209
  env->RunCleanup();
306
210
  delete env;
307
210
}
308
309
Environment* GetCurrentEnvironment(Local<Context> context) {
310
  return Environment::GetCurrent(context);
311
}
312
313
216
MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
314
216
  return per_process::v8_platform.Platform();
315
}
316
317
MultiIsolatePlatform* CreatePlatform(
318
    int thread_pool_size,
319
    node::tracing::TracingController* tracing_controller) {
320
  return new NodePlatform(thread_pool_size, tracing_controller);
321
}
322
323
4895
MultiIsolatePlatform* InitializeV8Platform(int thread_pool_size) {
324
4895
  per_process::v8_platform.Initialize(thread_pool_size);
325
4895
  return per_process::v8_platform.Platform();
326
}
327
328
void FreePlatform(MultiIsolatePlatform* platform) {
329
  delete platform;
330
}
331
332
9472
MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
333
9472
  Isolate* isolate = context->GetIsolate();
334
9472
  EscapableHandleScope handle_scope(isolate);
335
336
9472
  Local<Object> global = context->Global();
337
  Local<Private> key = Private::ForApi(isolate,
338
9472
      FIXED_ONE_BYTE_STRING(isolate, "node:per_context_binding_exports"));
339
340
  Local<Value> existing_value;
341
18944
  if (!global->GetPrivate(context, key).ToLocal(&existing_value))
342
    return MaybeLocal<Object>();
343
9472
  if (existing_value->IsObject())
344
8720
    return handle_scope.Escape(existing_value.As<Object>());
345
346
752
  Local<Object> exports = Object::New(isolate);
347
2256
  if (context->Global()->SetPrivate(context, key, exports).IsNothing())
348
    return MaybeLocal<Object>();
349
752
  return handle_scope.Escape(exports);
350
}
351
352
752
Local<Context> NewContext(Isolate* isolate,
353
                          Local<ObjectTemplate> object_template) {
354
1504
  auto context = Context::New(isolate, nullptr, object_template);
355
752
  if (context.IsEmpty()) return context;
356
357
752
  if (!InitializeContext(context)) {
358
83
    return Local<Context>();
359
  }
360
361
669
  InitializeContextRuntime(context);
362
363
669
  return context;
364
}
365
366
// This runs at runtime, regardless of whether the context
367
// is created from a snapshot.
368
5562
void InitializeContextRuntime(Local<Context> context) {
369
5562
  Isolate* isolate = context->GetIsolate();
370
5562
  HandleScope handle_scope(isolate);
371
372
  // Delete `Intl.v8BreakIterator`
373
  // https://github.com/nodejs/node/issues/14909
374
5562
  Local<String> intl_string = FIXED_ONE_BYTE_STRING(isolate, "Intl");
375
  Local<String> break_iter_string =
376
5562
    FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
377
  Local<Value> intl_v;
378



33372
  if (context->Global()->Get(context, intl_string).ToLocal(&intl_v) &&
379
5562
      intl_v->IsObject()) {
380
5562
    Local<Object> intl = intl_v.As<Object>();
381
11124
    intl->Delete(context, break_iter_string).FromJust();
382
  }
383
384
  // Delete `Atomics.wake`
385
  // https://github.com/nodejs/node/issues/21219
386
5562
  Local<String> atomics_string = FIXED_ONE_BYTE_STRING(isolate, "Atomics");
387
5562
  Local<String> wake_string = FIXED_ONE_BYTE_STRING(isolate, "wake");
388
  Local<Value> atomics_v;
389



33372
  if (context->Global()->Get(context, atomics_string).ToLocal(&atomics_v) &&
390
5562
      atomics_v->IsObject()) {
391
5561
    Local<Object> atomics = atomics_v.As<Object>();
392
11122
    atomics->Delete(context, wake_string).FromJust();
393
5562
  }
394
5562
}
395
396
752
bool InitializeContext(Local<Context> context) {
397
752
  Isolate* isolate = context->GetIsolate();
398
752
  HandleScope handle_scope(isolate);
399
400
  context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
401
752
                           True(isolate));
402
403
  {
404
    // Run per-context JS files.
405
    Context::Scope context_scope(context);
406
    Local<Object> exports;
407
408
    Local<String> primordials_string =
409
752
        FIXED_ONE_BYTE_STRING(isolate, "primordials");
410
752
    Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
411
752
    Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
412
413
    // Create primordials first and make it available to per-context scripts.
414
752
    Local<Object> primordials = Object::New(isolate);
415


5264
    if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
416

5264
        !GetPerContextExports(context).ToLocal(&exports) ||
417

3760
        !exports->Set(context, primordials_string, primordials).FromJust()) {
418
      return false;
419
    }
420
421
    static const char* context_files[] = {"internal/per_context/primordials",
422
                                          "internal/per_context/domexception",
423
                                          nullptr};
424
425
2090
    for (const char** module = context_files; *module != nullptr; module++) {
426
      std::vector<Local<String>> parameters = {
427
1421
          global_string, exports_string, primordials_string};
428
7105
      Local<Value> arguments[] = {context->Global(), exports, primordials};
429
      MaybeLocal<Function> maybe_fn =
430
          native_module::NativeModuleEnv::LookupAndCompile(
431
1421
              context, *module, &parameters, nullptr);
432
1421
      if (maybe_fn.IsEmpty()) {
433
        return false;
434
      }
435
1421
      Local<Function> fn = maybe_fn.ToLocalChecked();
436
      MaybeLocal<Value> result =
437
          fn->Call(context, Undefined(isolate),
438
2842
                   arraysize(arguments), arguments);
439
      // Execution failed during context creation.
440
      // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
441
1421
      if (result.IsEmpty()) {
442
83
        return false;
443
      }
444
2007
    }
445
  }
446
447
669
  return true;
448
}
449
450
8
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
451
8
  HandleScope handle_scope(isolate);
452
8
  Local<Context> context = isolate->GetCurrentContext();
453
8
  if (context.IsEmpty()) return nullptr;
454
8
  Environment* env = Environment::GetCurrent(context);
455
8
  if (env == nullptr) return nullptr;
456
8
  return env->event_loop();
457
}
458
459
}  // namespace node