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: 239 288 83.0 %
Date: 2020-02-27 22:14:15 Branches: 85 160 53.1 %

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::FinalizationGroup;
16
using v8::Function;
17
using v8::HandleScope;
18
using v8::Isolate;
19
using v8::Local;
20
using v8::MaybeLocal;
21
using v8::MicrotasksPolicy;
22
using v8::Null;
23
using v8::Object;
24
using v8::ObjectTemplate;
25
using v8::Private;
26
using v8::String;
27
using v8::Value;
28
29
47
static bool AllowWasmCodeGenerationCallback(Local<Context> context,
30
                                            Local<String>) {
31
  Local<Value> wasm_code_gen =
32
94
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
33

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

64
         (env->is_main_thread() || !env->is_stopping()) &&
41

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

71633
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
75
2
    try_catch.ReThrow();
76
  }
77
71633
  return result;
78
}
79
80
3
static void HostCleanupFinalizationGroupCallback(
81
    Local<Context> context, Local<FinalizationGroup> group) {
82
3
  Environment* env = Environment::GetCurrent(context);
83
3
  if (env == nullptr) {
84
    return;
85
  }
86
3
  env->RegisterFinalizationGroupForCleanup(group);
87
}
88
89
92001
void* NodeArrayBufferAllocator::Allocate(size_t size) {
90
  void* ret;
91

92001
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
92
57650
    ret = UncheckedCalloc(size);
93
  else
94
34351
    ret = UncheckedMalloc(size);
95
92001
  if (LIKELY(ret != nullptr))
96
92001
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
97
92001
  return ret;
98
}
99
100
366861
void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
101
366861
  void* ret = node::UncheckedMalloc(size);
102
366861
  if (LIKELY(ret != nullptr))
103
366861
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
104
366861
  return ret;
105
}
106
107
293260
void* NodeArrayBufferAllocator::Reallocate(
108
    void* data, size_t old_size, size_t size) {
109
293260
  void* ret = UncheckedRealloc<char>(static_cast<char*>(data), size);
110

293260
  if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
111
293260
    total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
112
293260
  return ret;
113
}
114
115
452292
void NodeArrayBufferAllocator::Free(void* data, size_t size) {
116
452292
  total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
117
452292
  free(data);
118
452292
}
119
120
9
DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
121
3
  CHECK(allocations_.empty());
122
6
}
123
124
42
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
125
84
  Mutex::ScopedLock lock(mutex_);
126
42
  void* data = NodeArrayBufferAllocator::Allocate(size);
127
42
  RegisterPointerInternal(data, size);
128
84
  return data;
129
}
130
131
8
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
132
16
  Mutex::ScopedLock lock(mutex_);
133
8
  void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
134
8
  RegisterPointerInternal(data, size);
135
16
  return data;
136
}
137
138
50
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
139
100
  Mutex::ScopedLock lock(mutex_);
140
50
  UnregisterPointerInternal(data, size);
141
50
  NodeArrayBufferAllocator::Free(data, size);
142
50
}
143
144
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
145
                                                size_t old_size,
146
                                                size_t size) {
147
  Mutex::ScopedLock lock(mutex_);
148
  void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size);
149
  if (ret == nullptr) {
150
    if (size == 0)  // i.e. equivalent to free().
151
      UnregisterPointerInternal(data, old_size);
152
    return nullptr;
153
  }
154
155
  if (data != nullptr) {
156
    auto it = allocations_.find(data);
157
    CHECK_NE(it, allocations_.end());
158
    allocations_.erase(it);
159
  }
160
161
  RegisterPointerInternal(ret, size);
162
  return ret;
163
}
164
165
void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
166
  Mutex::ScopedLock lock(mutex_);
167
  NodeArrayBufferAllocator::RegisterPointer(data, size);
168
  RegisterPointerInternal(data, size);
169
}
170
171
void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
172
  Mutex::ScopedLock lock(mutex_);
173
  NodeArrayBufferAllocator::UnregisterPointer(data, size);
174
  UnregisterPointerInternal(data, size);
175
}
176
177
50
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
178
                                                              size_t size) {
179
50
  if (data == nullptr) return;
180
50
  auto it = allocations_.find(data);
181
50
  CHECK_NE(it, allocations_.end());
182
50
  if (size > 0) {
183
    // We allow allocations with size 1 for 0-length buffers to avoid having
184
    // to deal with nullptr values.
185
50
    CHECK_EQ(it->second, size);
186
  }
187
50
  allocations_.erase(it);
188
}
189
190
50
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
191
                                                            size_t size) {
192
50
  if (data == nullptr) return;
193
50
  CHECK_EQ(allocations_.count(data), 0);
194
50
  allocations_[data] = size;
195
}
196
197
4408
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
198

4408
  if (debug || per_process::cli_options->debug_arraybuffer_allocations)
199
3
    return std::make_unique<DebuggingArrayBufferAllocator>();
200
  else
201
4405
    return std::make_unique<NodeArrayBufferAllocator>();
202
}
203
204
41
ArrayBufferAllocator* CreateArrayBufferAllocator() {
205
41
  return ArrayBufferAllocator::Create().release();
206
}
207
208
41
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
209
41
  delete allocator;
210
41
}
211
212
4408
void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
213
4408
  const uint64_t constrained_memory = uv_get_constrained_memory();
214
4408
  const uint64_t total_memory = constrained_memory > 0 ?
215
4408
      std::min(uv_get_total_memory(), constrained_memory) :
216
4408
      uv_get_total_memory();
217
4408
  if (total_memory > 0) {
218
    // V8 defaults to 700MB or 1.4GB on 32 and 64 bit platforms respectively.
219
    // This default is based on browser use-cases. Tell V8 to configure the
220
    // heap based on the actual physical memory.
221
4408
    params->constraints.ConfigureDefaults(total_memory, 0);
222
  }
223
4408
}
224
225
4408
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
226
4408
  if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL)
227
4408
    isolate->AddMessageListenerWithErrorLevel(
228
            errors::PerIsolateMessageListener,
229
            Isolate::MessageErrorLevel::kMessageError |
230
4408
                Isolate::MessageErrorLevel::kMessageWarning);
231
232
4408
  auto* abort_callback = s.should_abort_on_uncaught_exception_callback ?
233
      s.should_abort_on_uncaught_exception_callback :
234
4408
      ShouldAbortOnUncaughtException;
235
4408
  isolate->SetAbortOnUncaughtExceptionCallback(abort_callback);
236
237
4408
  auto* fatal_error_cb = s.fatal_error_callback ?
238
4408
      s.fatal_error_callback : OnFatalError;
239
4408
  isolate->SetFatalErrorHandler(fatal_error_cb);
240
241
4408
  auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
242
4408
      s.prepare_stack_trace_callback : PrepareStackTraceCallback;
243
4408
  isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
244
4408
}
245
246
4409
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
247
4409
  isolate->SetMicrotasksPolicy(s.policy);
248
249
4409
  auto* allow_wasm_codegen_cb = s.allow_wasm_code_generation_callback ?
250
4409
    s.allow_wasm_code_generation_callback : AllowWasmCodeGenerationCallback;
251
4409
  isolate->SetAllowWasmCodeGenerationCallback(allow_wasm_codegen_cb);
252
253
4409
  auto* promise_reject_cb = s.promise_reject_callback ?
254
4409
    s.promise_reject_callback : task_queue::PromiseRejectCallback;
255
4409
  isolate->SetPromiseRejectCallback(promise_reject_cb);
256
257
4409
  auto* host_cleanup_cb = s.host_cleanup_finalization_group_callback ?
258
    s.host_cleanup_finalization_group_callback :
259
4409
    HostCleanupFinalizationGroupCallback;
260
4409
  isolate->SetHostCleanupFinalizationGroupCallback(host_cleanup_cb);
261
262
4409
  if (s.flags & DETAILED_SOURCE_POSITIONS_FOR_PROFILING)
263
4409
    v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
264
4409
}
265
266
269
void SetIsolateUpForNode(v8::Isolate* isolate,
267
                         const IsolateSettings& settings) {
268
269
  SetIsolateErrorHandlers(isolate, settings);
269
269
  SetIsolateMiscHandlers(isolate, settings);
270
269
}
271
272
269
void SetIsolateUpForNode(v8::Isolate* isolate) {
273
269
  IsolateSettings settings;
274
269
  SetIsolateUpForNode(isolate, settings);
275
269
}
276
277
Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
278
  return NewIsolate(allocator, event_loop, GetMainThreadMultiIsolatePlatform());
279
}
280
281
// TODO(joyeecheung): we may want to expose this, but then we need to be
282
// careful about what we override in the params.
283
40
Isolate* NewIsolate(Isolate::CreateParams* params,
284
                    uv_loop_t* event_loop,
285
                    MultiIsolatePlatform* platform) {
286
40
  Isolate* isolate = Isolate::Allocate();
287
40
  if (isolate == nullptr) return nullptr;
288
289
  // Register the isolate on the platform before the isolate gets initialized,
290
  // so that the isolate can access the platform during initialization.
291
40
  platform->RegisterIsolate(isolate, event_loop);
292
293
40
  SetIsolateCreateParamsForNode(params);
294
40
  Isolate::Initialize(isolate, *params);
295
40
  SetIsolateUpForNode(isolate);
296
297
40
  return isolate;
298
}
299
300
40
Isolate* NewIsolate(ArrayBufferAllocator* allocator,
301
                    uv_loop_t* event_loop,
302
                    MultiIsolatePlatform* platform) {
303
80
  Isolate::CreateParams params;
304
40
  if (allocator != nullptr) params.array_buffer_allocator = allocator;
305
80
  return NewIsolate(&params, event_loop, platform);
306
}
307
308
Isolate* NewIsolate(std::shared_ptr<ArrayBufferAllocator> allocator,
309
                    uv_loop_t* event_loop,
310
                    MultiIsolatePlatform* platform) {
311
  Isolate::CreateParams params;
312
  if (allocator) params.array_buffer_allocator_shared = allocator;
313
  return NewIsolate(&params, event_loop, platform);
314
}
315
316
254
IsolateData* CreateIsolateData(Isolate* isolate,
317
                               uv_loop_t* loop,
318
                               MultiIsolatePlatform* platform,
319
                               ArrayBufferAllocator* allocator) {
320
254
  return new IsolateData(isolate, loop, platform, allocator);
321
}
322
323
254
void FreeIsolateData(IsolateData* isolate_data) {
324
254
  delete isolate_data;
325
254
}
326
327
25
Environment* CreateEnvironment(IsolateData* isolate_data,
328
                               Local<Context> context,
329
                               int argc,
330
                               const char* const* argv,
331
                               int exec_argc,
332
                               const char* const* exec_argv) {
333
25
  Isolate* isolate = context->GetIsolate();
334
50
  HandleScope handle_scope(isolate);
335
  Context::Scope context_scope(context);
336
  // TODO(addaleax): This is a much better place for parsing per-Environment
337
  // options than the global parse call.
338
50
  std::vector<std::string> args(argv, argv + argc);
339
50
  std::vector<std::string> exec_args(exec_argv, exec_argv + exec_argc);
340
  // TODO(addaleax): Provide more sensible flags, in an embedder-accessible way.
341
  Environment* env = new Environment(
342
      isolate_data,
343
      context,
344
      args,
345
      exec_args,
346
      static_cast<Environment::Flags>(Environment::kIsMainThread |
347
                                      Environment::kOwnsProcessState |
348
25
                                      Environment::kOwnsInspector));
349
25
  env->InitializeLibuv(per_process::v8_is_profiling);
350
50
  if (env->RunBootstrapping().IsEmpty())
351
    return nullptr;
352
25
  return env;
353
}
354
355
253
void FreeEnvironment(Environment* env) {
356
253
  env->RunCleanup();
357
252
  delete env;
358
253
}
359
360
5
Environment* GetCurrentEnvironment(Local<Context> context) {
361
5
  return Environment::GetCurrent(context);
362
}
363
364
MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
365
  return per_process::v8_platform.Platform();
366
}
367
368
MultiIsolatePlatform* CreatePlatform(
369
    int thread_pool_size,
370
    node::tracing::TracingController* tracing_controller) {
371
  return new NodePlatform(thread_pool_size, tracing_controller);
372
}
373
374
void FreePlatform(MultiIsolatePlatform* platform) {
375
  delete platform;
376
}
377
378
39828
MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
379
39828
  Isolate* isolate = context->GetIsolate();
380
39829
  EscapableHandleScope handle_scope(isolate);
381
382
39827
  Local<Object> global = context->Global();
383
  Local<Private> key = Private::ForApi(isolate,
384
39828
      FIXED_ONE_BYTE_STRING(isolate, "node:per_context_binding_exports"));
385
386
  Local<Value> existing_value;
387
79656
  if (!global->GetPrivate(context, key).ToLocal(&existing_value))
388
    return MaybeLocal<Object>();
389
39827
  if (existing_value->IsObject())
390
39573
    return handle_scope.Escape(existing_value.As<Object>());
391
392
255
  Local<Object> exports = Object::New(isolate);
393

1023
  if (context->Global()->SetPrivate(context, key, exports).IsNothing() ||
394
255
      !InitializePrimordials(context))
395
    return MaybeLocal<Object>();
396
256
  return handle_scope.Escape(exports);
397
}
398
399
// Any initialization logic should be performed in
400
// InitializeContext, because embedders don't necessarily
401
// call NewContext and so they will experience breakages.
402
255
Local<Context> NewContext(Isolate* isolate,
403
                          Local<ObjectTemplate> object_template) {
404
510
  auto context = Context::New(isolate, nullptr, object_template);
405
254
  if (context.IsEmpty()) return context;
406
407
254
  if (!InitializeContext(context)) {
408
    return Local<Context>();
409
  }
410
411
255
  return context;
412
}
413
414
// This runs at runtime, regardless of whether the context
415
// is created from a snapshot.
416
4954
void InitializeContextRuntime(Local<Context> context) {
417
4954
  Isolate* isolate = context->GetIsolate();
418
9908
  HandleScope handle_scope(isolate);
419
420
  // Delete `Intl.v8BreakIterator`
421
  // https://github.com/nodejs/node/issues/14909
422
4954
  Local<String> intl_string = FIXED_ONE_BYTE_STRING(isolate, "Intl");
423
  Local<String> break_iter_string =
424
4954
    FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
425
  Local<Value> intl_v;
426

19816
  if (context->Global()->Get(context, intl_string).ToLocal(&intl_v) &&
427
4954
      intl_v->IsObject()) {
428
4954
    Local<Object> intl = intl_v.As<Object>();
429
9908
    intl->Delete(context, break_iter_string).FromJust();
430
  }
431
432
  // Delete `Atomics.wake`
433
  // https://github.com/nodejs/node/issues/21219
434
4954
  Local<String> atomics_string = FIXED_ONE_BYTE_STRING(isolate, "Atomics");
435
4954
  Local<String> wake_string = FIXED_ONE_BYTE_STRING(isolate, "wake");
436
  Local<Value> atomics_v;
437

19816
  if (context->Global()->Get(context, atomics_string).ToLocal(&atomics_v) &&
438
4954
      atomics_v->IsObject()) {
439
4953
    Local<Object> atomics = atomics_v.As<Object>();
440
9906
    atomics->Delete(context, wake_string).FromJust();
441
  }
442
4954
}
443
444
254
bool InitializeContextForSnapshot(Local<Context> context) {
445
254
  Isolate* isolate = context->GetIsolate();
446
510
  HandleScope handle_scope(isolate);
447
448
510
  context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
449
255
                           True(isolate));
450
510
  return InitializePrimordials(context);
451
}
452
453
510
bool InitializePrimordials(Local<Context> context) {
454
  // Run per-context JS files.
455
510
  Isolate* isolate = context->GetIsolate();
456
  Context::Scope context_scope(context);
457
  Local<Object> exports;
458
459
  Local<String> primordials_string =
460
511
      FIXED_ONE_BYTE_STRING(isolate, "primordials");
461
510
  Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
462
510
  Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
463
464
  // Create primordials first and make it available to per-context scripts.
465
511
  Local<Object> primordials = Object::New(isolate);
466

2552
  if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
467

2042
      !GetPerContextExports(context).ToLocal(&exports) ||
468
1532
      !exports->Set(context, primordials_string, primordials).FromJust()) {
469
    return false;
470
  }
471
472
  static const char* context_files[] = {"internal/per_context/primordials",
473
                                        "internal/per_context/domexception",
474
                                        "internal/per_context/messageport",
475
                                        nullptr};
476
477
2043
  for (const char** module = context_files; *module != nullptr; module++) {
478
    std::vector<Local<String>> parameters = {
479
3065
        global_string, exports_string, primordials_string};
480
7663
    Local<Value> arguments[] = {context->Global(), exports, primordials};
481
    MaybeLocal<Function> maybe_fn =
482
        native_module::NativeModuleEnv::LookupAndCompile(
483
1533
            context, *module, &parameters, nullptr);
484
1533
    if (maybe_fn.IsEmpty()) {
485
      return false;
486
    }
487
1533
    Local<Function> fn = maybe_fn.ToLocalChecked();
488
    MaybeLocal<Value> result =
489
3066
        fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
490
    // Execution failed during context creation.
491
    // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
492
1533
    if (result.IsEmpty()) {
493
      return false;
494
    }
495
  }
496
497
511
  return true;
498
}
499
500
254
bool InitializeContext(Local<Context> context) {
501
254
  if (!InitializeContextForSnapshot(context)) {
502
    return false;
503
  }
504
505
255
  InitializeContextRuntime(context);
506
255
  return true;
507
}
508
509
8
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
510
16
  HandleScope handle_scope(isolate);
511
8
  Local<Context> context = isolate->GetCurrentContext();
512
8
  if (context.IsEmpty()) return nullptr;
513
8
  Environment* env = Environment::GetCurrent(context);
514
8
  if (env == nullptr) return nullptr;
515
8
  return env->event_loop();
516
}
517
518
1
void AddLinkedBinding(Environment* env, const node_module& mod) {
519
1
  CHECK_NOT_NULL(env);
520
2
  Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
521
522
1
  node_module* prev_head = env->extra_linked_bindings_head();
523
1
  env->extra_linked_bindings()->push_back(mod);
524
1
  if (prev_head != nullptr)
525
    prev_head->nm_link = &env->extra_linked_bindings()->back();
526
1
}
527
528
1
void AddLinkedBinding(Environment* env,
529
                      const char* name,
530
                      addon_context_register_func fn,
531
                      void* priv) {
532
  node_module mod = {
533
    NODE_MODULE_VERSION,
534
    NM_F_LINKED,
535
    nullptr,  // nm_dso_handle
536
    nullptr,  // nm_filename
537
    nullptr,  // nm_register_func
538
    fn,
539
    name,
540
    priv,
541
    nullptr   // nm_link
542
1
  };
543
1
  AddLinkedBinding(env, mod);
544
1
}
545
546
}  // namespace node