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: 330 371 88.9 %
Date: 2020-06-24 22:13:30 Branches: 104 170 61.2 %

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
#if HAVE_INSPECTOR
11
#include "inspector/worker_inspector.h"  // ParentInspectorHandle
12
#endif
13
14
namespace node {
15
using errors::TryCatchScope;
16
using v8::Array;
17
using v8::Context;
18
using v8::EscapableHandleScope;
19
using v8::Function;
20
using v8::FunctionCallbackInfo;
21
using v8::HandleScope;
22
using v8::Isolate;
23
using v8::Local;
24
using v8::MaybeLocal;
25
using v8::Null;
26
using v8::Object;
27
using v8::ObjectTemplate;
28
using v8::Private;
29
using v8::PropertyDescriptor;
30
using v8::SealHandleScope;
31
using v8::String;
32
using v8::Value;
33
34
45
static bool AllowWasmCodeGenerationCallback(Local<Context> context,
35
                                            Local<String>) {
36
  Local<Value> wasm_code_gen =
37
90
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
38

135
  return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
39
}
40
41
32
static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
42
32
  DebugSealHandleScope scope(isolate);
43
32
  Environment* env = Environment::GetCurrent(isolate);
44
32
  return env != nullptr &&
45

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

96
         env->should_abort_on_uncaught_toggle()[0] &&
47
65
         !env->inside_should_not_abort_on_uncaught_scope();
48
}
49
50
73141
static MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
51
                                      Local<Value> exception,
52
                                      Local<Array> trace) {
53
73141
  Environment* env = Environment::GetCurrent(context);
54
73141
  if (env == nullptr) {
55
    return exception->ToString(context).FromMaybe(Local<Value>());
56
  }
57
73141
  Local<Function> prepare = env->prepare_stack_trace_callback();
58
73141
  if (prepare.IsEmpty()) {
59
    return exception->ToString(context).FromMaybe(Local<Value>());
60
  }
61
  Local<Value> args[] = {
62
      context->Global(),
63
      exception,
64
      trace,
65
292564
  };
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
146282
  TryCatchScope try_catch(env);
71
  MaybeLocal<Value> result = prepare->Call(
72
146282
      context, Undefined(env->isolate()), arraysize(args), args);
73

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

462672
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
82
66269
    ret = UncheckedCalloc(size);
83
  else
84
396403
    ret = UncheckedMalloc(size);
85
462672
  if (LIKELY(ret != nullptr))
86
462672
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
87
462672
  return ret;
88
}
89
90
25862
void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
91
25862
  void* ret = node::UncheckedMalloc(size);
92
25862
  if (LIKELY(ret != nullptr))
93
25862
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
94
25862
  return ret;
95
}
96
97
316237
void* NodeArrayBufferAllocator::Reallocate(
98
    void* data, size_t old_size, size_t size) {
99
316237
  void* ret = UncheckedRealloc<char>(static_cast<char*>(data), size);
100

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

4734
  if (debug || per_process::cli_options->debug_arraybuffer_allocations)
189
3
    return std::make_unique<DebuggingArrayBufferAllocator>();
190
  else
191
4731
    return std::make_unique<NodeArrayBufferAllocator>();
192
}
193
194
47
ArrayBufferAllocator* CreateArrayBufferAllocator() {
195
47
  return ArrayBufferAllocator::Create().release();
196
}
197
198
47
void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) {
199
47
  delete allocator;
200
47
}
201
202
4732
void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
203
4732
  const uint64_t constrained_memory = uv_get_constrained_memory();
204
4733
  const uint64_t total_memory = constrained_memory > 0 ?
205
4733
      std::min(uv_get_total_memory(), constrained_memory) :
206
4733
      uv_get_total_memory();
207
4733
  if (total_memory > 0) {
208
    // V8 defaults to 700MB or 1.4GB on 32 and 64 bit platforms respectively.
209
    // This default is based on browser use-cases. Tell V8 to configure the
210
    // heap based on the actual physical memory.
211
4733
    params->constraints.ConfigureDefaults(total_memory, 0);
212
  }
213
4733
  params->embedder_wrapper_object_index = BaseObject::InternalFields::kSlot;
214
4733
  params->embedder_wrapper_type_index = std::numeric_limits<int>::max();
215
4733
}
216
217
4733
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
218
4733
  if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL)
219
4733
    isolate->AddMessageListenerWithErrorLevel(
220
            errors::PerIsolateMessageListener,
221
            Isolate::MessageErrorLevel::kMessageError |
222
4733
                Isolate::MessageErrorLevel::kMessageWarning);
223
224
4733
  auto* abort_callback = s.should_abort_on_uncaught_exception_callback ?
225
      s.should_abort_on_uncaught_exception_callback :
226
4733
      ShouldAbortOnUncaughtException;
227
4733
  isolate->SetAbortOnUncaughtExceptionCallback(abort_callback);
228
229
4733
  auto* fatal_error_cb = s.fatal_error_callback ?
230
4733
      s.fatal_error_callback : OnFatalError;
231
4733
  isolate->SetFatalErrorHandler(fatal_error_cb);
232
233
4733
  auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
234
4733
      s.prepare_stack_trace_callback : PrepareStackTraceCallback;
235
4733
  isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
236
4733
}
237
238
4734
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
239
4734
  isolate->SetMicrotasksPolicy(s.policy);
240
241
4734
  auto* allow_wasm_codegen_cb = s.allow_wasm_code_generation_callback ?
242
4734
    s.allow_wasm_code_generation_callback : AllowWasmCodeGenerationCallback;
243
4734
  isolate->SetAllowWasmCodeGenerationCallback(allow_wasm_codegen_cb);
244
245
4734
  auto* promise_reject_cb = s.promise_reject_callback ?
246
4734
    s.promise_reject_callback : task_queue::PromiseRejectCallback;
247
4734
  isolate->SetPromiseRejectCallback(promise_reject_cb);
248
249
4734
  if (s.flags & DETAILED_SOURCE_POSITIONS_FOR_PROFILING)
250
4734
    v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
251
4734
}
252
253
402
void SetIsolateUpForNode(v8::Isolate* isolate,
254
                         const IsolateSettings& settings) {
255
402
  SetIsolateErrorHandlers(isolate, settings);
256
402
  SetIsolateMiscHandlers(isolate, settings);
257
402
}
258
259
402
void SetIsolateUpForNode(v8::Isolate* isolate) {
260
402
  IsolateSettings settings;
261
402
  SetIsolateUpForNode(isolate, settings);
262
402
}
263
264
Isolate* NewIsolate(ArrayBufferAllocator* allocator, uv_loop_t* event_loop) {
265
  return NewIsolate(allocator, event_loop, GetMainThreadMultiIsolatePlatform());
266
}
267
268
// TODO(joyeecheung): we may want to expose this, but then we need to be
269
// careful about what we override in the params.
270
52
Isolate* NewIsolate(Isolate::CreateParams* params,
271
                    uv_loop_t* event_loop,
272
                    MultiIsolatePlatform* platform) {
273
52
  Isolate* isolate = Isolate::Allocate();
274
52
  if (isolate == nullptr) return nullptr;
275
276
  // Register the isolate on the platform before the isolate gets initialized,
277
  // so that the isolate can access the platform during initialization.
278
52
  platform->RegisterIsolate(isolate, event_loop);
279
280
52
  SetIsolateCreateParamsForNode(params);
281
52
  Isolate::Initialize(isolate, *params);
282
52
  SetIsolateUpForNode(isolate);
283
284
52
  return isolate;
285
}
286
287
46
Isolate* NewIsolate(ArrayBufferAllocator* allocator,
288
                    uv_loop_t* event_loop,
289
                    MultiIsolatePlatform* platform) {
290
92
  Isolate::CreateParams params;
291
46
  if (allocator != nullptr) params.array_buffer_allocator = allocator;
292
92
  return NewIsolate(&params, event_loop, platform);
293
}
294
295
6
Isolate* NewIsolate(std::shared_ptr<ArrayBufferAllocator> allocator,
296
                    uv_loop_t* event_loop,
297
                    MultiIsolatePlatform* platform) {
298
12
  Isolate::CreateParams params;
299
6
  if (allocator) params.array_buffer_allocator_shared = allocator;
300
12
  return NewIsolate(&params, event_loop, platform);
301
}
302
303
387
IsolateData* CreateIsolateData(Isolate* isolate,
304
                               uv_loop_t* loop,
305
                               MultiIsolatePlatform* platform,
306
                               ArrayBufferAllocator* allocator) {
307
387
  return new IsolateData(isolate, loop, platform, allocator);
308
}
309
310
383
void FreeIsolateData(IsolateData* isolate_data) {
311
383
  delete isolate_data;
312
384
}
313
314
555
InspectorParentHandle::~InspectorParentHandle() {}
315
316
// Hide the internal handle class from the public API.
317
#if HAVE_INSPECTOR
318
1110
struct InspectorParentHandleImpl : public InspectorParentHandle {
319
  std::unique_ptr<inspector::ParentInspectorHandle> impl;
320
321
555
  explicit InspectorParentHandleImpl(
322
      std::unique_ptr<inspector::ParentInspectorHandle>&& impl)
323
555
    : impl(std::move(impl)) {}
324
};
325
#endif
326
327
1
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
2
  return CreateEnvironment(
334
      isolate_data, context,
335
2
      std::vector<std::string>(argv, argv + argc),
336
4
      std::vector<std::string>(exec_argv, exec_argv + exec_argc));
337
}
338
339
4703
Environment* CreateEnvironment(
340
    IsolateData* isolate_data,
341
    Local<Context> context,
342
    const std::vector<std::string>& args,
343
    const std::vector<std::string>& exec_args,
344
    EnvironmentFlags::Flags flags,
345
    ThreadId thread_id,
346
    std::unique_ptr<InspectorParentHandle> inspector_parent_handle) {
347
4703
  Isolate* isolate = context->GetIsolate();
348
9406
  HandleScope handle_scope(isolate);
349
  Context::Scope context_scope(context);
350
  // TODO(addaleax): This is a much better place for parsing per-Environment
351
  // options than the global parse call.
352
  Environment* env = new Environment(
353
      isolate_data,
354
      context,
355
      args,
356
      exec_args,
357
      flags,
358
4703
      thread_id);
359
4703
  if (flags & EnvironmentFlags::kOwnsProcessState) {
360
    env->set_abort_on_uncaught_exception(false);
361
  }
362
363
#if HAVE_INSPECTOR
364
4703
  if (inspector_parent_handle) {
365
672
    env->InitializeInspector(
366
        std::move(static_cast<InspectorParentHandleImpl*>(
367
672
            inspector_parent_handle.get())->impl));
368
  } else {
369
4367
    env->InitializeInspector({});
370
  }
371
#endif
372
373
9405
  if (env->RunBootstrapping().IsEmpty()) {
374
    FreeEnvironment(env);
375
    return nullptr;
376
  }
377
378
4703
  return env;
379
}
380
381
4232
void FreeEnvironment(Environment* env) {
382
  Isolate::DisallowJavascriptExecutionScope disallow_js(env->isolate(),
383
8465
      Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
384
  {
385
8465
    HandleScope handle_scope(env->isolate());  // For env->context().
386
4232
    Context::Scope context_scope(env->context());
387
8465
    SealHandleScope seal_handle_scope(env->isolate());
388
389
4233
    env->set_stopping(true);
390
4233
    env->stop_sub_worker_contexts();
391
4232
    env->RunCleanup();
392
4233
    RunAtExit(env);
393
  }
394
395
  // This call needs to be made while the `Environment` is still alive
396
  // because we assume that it is available for async tracking in the
397
  // NodePlatform implementation.
398
4233
  MultiIsolatePlatform* platform = env->isolate_data()->platform();
399
4233
  if (platform != nullptr)
400
4233
    platform->DrainTasks(env->isolate());
401
402
4233
  delete env;
403
4232
}
404
405
555
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
406
    Environment* env,
407
    ThreadId thread_id,
408
    const char* url) {
409
555
  CHECK_NOT_NULL(env);
410
555
  CHECK_NE(thread_id.id, static_cast<uint64_t>(-1));
411
#if HAVE_INSPECTOR
412
1110
  return std::make_unique<InspectorParentHandleImpl>(
413
1665
      env->inspector_agent()->GetParentHandle(thread_id.id, url));
414
#else
415
  return {};
416
#endif
417
}
418
419
4331
void LoadEnvironment(Environment* env) {
420
8350
  USE(LoadEnvironment(env,
421
8350
                      StartExecutionCallback{},
422
12369
                      {}));
423
4019
}
424
425
4679
MaybeLocal<Value> LoadEnvironment(
426
    Environment* env,
427
    StartExecutionCallback cb,
428
    std::unique_ptr<InspectorParentHandle> removeme) {
429
4679
  env->InitializeLibuv(per_process::v8_is_profiling);
430
4679
  env->InitializeDiagnostics();
431
432
4679
  return StartExecution(env, cb);
433
}
434
435
9
MaybeLocal<Value> LoadEnvironment(
436
    Environment* env,
437
    const char* main_script_source_utf8,
438
    std::unique_ptr<InspectorParentHandle> removeme) {
439
9
  CHECK_NOT_NULL(main_script_source_utf8);
440
  return LoadEnvironment(
441
      env,
442
9
      [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
443
        // This is a slightly hacky way to convert UTF-8 to UTF-16.
444
        Local<String> str =
445
90
            String::NewFromUtf8(env->isolate(),
446
9
                                main_script_source_utf8,
447
27
                                v8::NewStringType::kNormal).ToLocalChecked();
448
16
        auto main_utf16 = std::make_unique<String::Value>(env->isolate(), str);
449
450
        // TODO(addaleax): Avoid having a global table for all scripts.
451
16
        std::string name = "embedder_main_" + std::to_string(env->thread_id());
452
9
        native_module::NativeModuleEnv::Add(
453
            name.c_str(),
454
18
            UnionBytes(**main_utf16, main_utf16->length()));
455
18
        env->set_main_utf16(std::move(main_utf16));
456
        std::vector<Local<String>> params = {
457
9
            env->process_string(),
458
25
            env->require_string()};
459
        std::vector<Local<Value>> args = {
460
            env->process_object(),
461
34
            env->native_module_require()};
462
25
        return ExecuteBootstrapper(env, name.c_str(), &params, &args);
463
9
      });
464
}
465
466
5
Environment* GetCurrentEnvironment(Local<Context> context) {
467
5
  return Environment::GetCurrent(context);
468
}
469
470
MultiIsolatePlatform* GetMainThreadMultiIsolatePlatform() {
471
  return per_process::v8_platform.Platform();
472
}
473
474
1
MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env) {
475
1
  return GetMultiIsolatePlatform(env->isolate_data());
476
}
477
478
1
MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
479
1
  return env->platform();
480
}
481
482
MultiIsolatePlatform* CreatePlatform(
483
    int thread_pool_size,
484
    node::tracing::TracingController* tracing_controller) {
485
  return CreatePlatform(
486
      thread_pool_size,
487
      static_cast<v8::TracingController*>(tracing_controller));
488
}
489
490
MultiIsolatePlatform* CreatePlatform(
491
    int thread_pool_size,
492
    v8::TracingController* tracing_controller) {
493
  return MultiIsolatePlatform::Create(thread_pool_size, tracing_controller)
494
      .release();
495
}
496
497
void FreePlatform(MultiIsolatePlatform* platform) {
498
  delete platform;
499
}
500
501
5
std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
502
    int thread_pool_size,
503
    v8::TracingController* tracing_controller) {
504
5
  return std::make_unique<NodePlatform>(thread_pool_size, tracing_controller);
505
}
506
507
42657
MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
508
42657
  Isolate* isolate = context->GetIsolate();
509
42657
  EscapableHandleScope handle_scope(isolate);
510
511
42657
  Local<Object> global = context->Global();
512
  Local<Private> key = Private::ForApi(isolate,
513
42657
      FIXED_ONE_BYTE_STRING(isolate, "node:per_context_binding_exports"));
514
515
  Local<Value> existing_value;
516
85314
  if (!global->GetPrivate(context, key).ToLocal(&existing_value))
517
    return MaybeLocal<Object>();
518
42657
  if (existing_value->IsObject())
519
42273
    return handle_scope.Escape(existing_value.As<Object>());
520
521
384
  Local<Object> exports = Object::New(isolate);
522

1536
  if (context->Global()->SetPrivate(context, key, exports).IsNothing() ||
523
384
      !InitializePrimordials(context))
524
4
    return MaybeLocal<Object>();
525
380
  return handle_scope.Escape(exports);
526
}
527
528
// Any initialization logic should be performed in
529
// InitializeContext, because embedders don't necessarily
530
// call NewContext and so they will experience breakages.
531
379
Local<Context> NewContext(Isolate* isolate,
532
                          Local<ObjectTemplate> object_template) {
533
758
  auto context = Context::New(isolate, nullptr, object_template);
534
379
  if (context.IsEmpty()) return context;
535
536
379
  if (!InitializeContext(context)) {
537
4
    return Local<Context>();
538
  }
539
540
375
  return context;
541
}
542
543
8
void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
544
8
  THROW_ERR_PROTO_ACCESS(info.GetIsolate());
545
8
}
546
547
// This runs at runtime, regardless of whether the context
548
// is created from a snapshot.
549
5268
void InitializeContextRuntime(Local<Context> context) {
550
5268
  Isolate* isolate = context->GetIsolate();
551
10536
  HandleScope handle_scope(isolate);
552
553
  // Delete `Intl.v8BreakIterator`
554
  // https://github.com/nodejs/node/issues/14909
555
5268
  Local<String> intl_string = FIXED_ONE_BYTE_STRING(isolate, "Intl");
556
  Local<String> break_iter_string =
557
5268
    FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
558
  Local<Value> intl_v;
559

21072
  if (context->Global()->Get(context, intl_string).ToLocal(&intl_v) &&
560
5268
      intl_v->IsObject()) {
561
5268
    Local<Object> intl = intl_v.As<Object>();
562
10536
    intl->Delete(context, break_iter_string).Check();
563
  }
564
565
  // Delete `Atomics.wake`
566
  // https://github.com/nodejs/node/issues/21219
567
5268
  Local<String> atomics_string = FIXED_ONE_BYTE_STRING(isolate, "Atomics");
568
5268
  Local<String> wake_string = FIXED_ONE_BYTE_STRING(isolate, "wake");
569
  Local<Value> atomics_v;
570

21072
  if (context->Global()->Get(context, atomics_string).ToLocal(&atomics_v) &&
571
5268
      atomics_v->IsObject()) {
572
5267
    Local<Object> atomics = atomics_v.As<Object>();
573
10534
    atomics->Delete(context, wake_string).Check();
574
  }
575
576
  // Remove __proto__
577
  // https://github.com/nodejs/node/issues/31951
578
5268
  Local<String> object_string = FIXED_ONE_BYTE_STRING(isolate, "Object");
579
5268
  Local<String> prototype_string = FIXED_ONE_BYTE_STRING(isolate, "prototype");
580
10536
  Local<Object> prototype = context->Global()
581
15804
                                ->Get(context, object_string)
582
10536
                                .ToLocalChecked()
583
10536
                                .As<Object>()
584
15804
                                ->Get(context, prototype_string)
585
10536
                                .ToLocalChecked()
586
5268
                                .As<Object>();
587
5268
  Local<String> proto_string = FIXED_ONE_BYTE_STRING(isolate, "__proto__");
588
5268
  if (per_process::cli_options->disable_proto == "delete") {
589
8
    prototype->Delete(context, proto_string).ToChecked();
590
5264
  } else if (per_process::cli_options->disable_proto == "throw") {
591
    Local<Value> thrower =
592
8
        Function::New(context, ProtoThrower).ToLocalChecked();
593
8
    PropertyDescriptor descriptor(thrower, thrower);
594
4
    descriptor.set_enumerable(false);
595
4
    descriptor.set_configurable(true);
596
8
    prototype->DefineProperty(context, proto_string, descriptor).ToChecked();
597
5260
  } else if (per_process::cli_options->disable_proto != "") {
598
    // Validated in ProcessGlobalArgs
599
    FatalError("InitializeContextRuntime()", "invalid --disable-proto mode");
600
  }
601
5268
}
602
603
379
bool InitializeContextForSnapshot(Local<Context> context) {
604
379
  Isolate* isolate = context->GetIsolate();
605
758
  HandleScope handle_scope(isolate);
606
607
758
  context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
608
379
                           True(isolate));
609
758
  return InitializePrimordials(context);
610
}
611
612
763
bool InitializePrimordials(Local<Context> context) {
613
  // Run per-context JS files.
614
763
  Isolate* isolate = context->GetIsolate();
615
  Context::Scope context_scope(context);
616
  Local<Object> exports;
617
618
  Local<String> primordials_string =
619
763
      FIXED_ONE_BYTE_STRING(isolate, "primordials");
620
763
  Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
621
763
  Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
622
623
  // Create primordials first and make it available to per-context scripts.
624
763
  Local<Object> primordials = Object::New(isolate);
625

3815
  if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
626

3048
      !GetPerContextExports(context).ToLocal(&exports) ||
627
2281
      !exports->Set(context, primordials_string, primordials).FromJust()) {
628
4
    return false;
629
  }
630
631
  static const char* context_files[] = {"internal/per_context/primordials",
632
                                        "internal/per_context/domexception",
633
                                        "internal/per_context/messageport",
634
                                        nullptr};
635
636
3024
  for (const char** module = context_files; *module != nullptr; module++) {
637
    std::vector<Local<String>> parameters = {
638
4534
        global_string, exports_string, primordials_string};
639
11345
    Local<Value> arguments[] = {context->Global(), exports, primordials};
640
    MaybeLocal<Function> maybe_fn =
641
        native_module::NativeModuleEnv::LookupAndCompile(
642
2269
            context, *module, &parameters, nullptr);
643
    Local<Function> fn;
644
2269
    if (!maybe_fn.ToLocal(&fn)) {
645
      return false;
646
    }
647
    MaybeLocal<Value> result =
648
4538
        fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
649
    // Execution failed during context creation.
650
    // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
651
2269
    if (result.IsEmpty()) {
652
4
      return false;
653
    }
654
  }
655
656
755
  return true;
657
}
658
659
379
bool InitializeContext(Local<Context> context) {
660
379
  if (!InitializeContextForSnapshot(context)) {
661
4
    return false;
662
  }
663
664
375
  InitializeContextRuntime(context);
665
375
  return true;
666
}
667
668
8
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
669
16
  HandleScope handle_scope(isolate);
670
8
  Local<Context> context = isolate->GetCurrentContext();
671
8
  if (context.IsEmpty()) return nullptr;
672
8
  Environment* env = Environment::GetCurrent(context);
673
8
  if (env == nullptr) return nullptr;
674
8
  return env->event_loop();
675
}
676
677
1
void AddLinkedBinding(Environment* env, const node_module& mod) {
678
1
  CHECK_NOT_NULL(env);
679
2
  Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
680
681
1
  node_module* prev_head = env->extra_linked_bindings_head();
682
1
  env->extra_linked_bindings()->push_back(mod);
683
1
  if (prev_head != nullptr)
684
    prev_head->nm_link = &env->extra_linked_bindings()->back();
685
1
}
686
687
1
void AddLinkedBinding(Environment* env,
688
                      const char* name,
689
                      addon_context_register_func fn,
690
                      void* priv) {
691
  node_module mod = {
692
    NODE_MODULE_VERSION,
693
    NM_F_LINKED,
694
    nullptr,  // nm_dso_handle
695
    nullptr,  // nm_filename
696
    nullptr,  // nm_register_func
697
    fn,
698
    name,
699
    priv,
700
    nullptr   // nm_link
701
1
  };
702
1
  AddLinkedBinding(env, mod);
703
1
}
704
705
static std::atomic<uint64_t> next_thread_id{0};
706
707
4922
ThreadId AllocateEnvironmentThreadId() {
708
4922
  return ThreadId { next_thread_id++ };
709
}
710
711
465
void DefaultProcessExitHandler(Environment* env, int exit_code) {
712
465
  env->set_can_call_into_js(false);
713
465
  env->stop_sub_worker_contexts();
714
465
  DisposePlatform();
715
465
  exit(exit_code);
716
}
717
718
719
336
void SetProcessExitHandler(Environment* env,
720
                           std::function<void(Environment*, int)>&& handler) {
721
336
  env->set_process_exit_handler(std::move(handler));
722
336
}
723
724
}  // namespace node