GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/environment.cc Lines: 345 390 88.5 %
Date: 2022-04-27 04:15:16 Branches: 116 190 61.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_options-inl.h"
7
#include "node_platform.h"
8
#include "node_v8_platform-inl.h"
9
#include "node_wasm_web_api.h"
10
#include "uv.h"
11
12
#if HAVE_INSPECTOR
13
#include "inspector/worker_inspector.h"  // ParentInspectorHandle
14
#endif
15
16
namespace node {
17
using errors::TryCatchScope;
18
using v8::Array;
19
using v8::Context;
20
using v8::EscapableHandleScope;
21
using v8::Function;
22
using v8::FunctionCallbackInfo;
23
using v8::HandleScope;
24
using v8::Isolate;
25
using v8::Just;
26
using v8::Local;
27
using v8::Maybe;
28
using v8::MaybeLocal;
29
using v8::Nothing;
30
using v8::Null;
31
using v8::Object;
32
using v8::ObjectTemplate;
33
using v8::Private;
34
using v8::PropertyDescriptor;
35
using v8::SealHandleScope;
36
using v8::String;
37
using v8::Value;
38
39
355
bool AllowWasmCodeGenerationCallback(Local<Context> context,
40
                                     Local<String>) {
41
  Local<Value> wasm_code_gen =
42
710
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
43

1065
  return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
44
}
45
46
33
bool ShouldAbortOnUncaughtException(Isolate* isolate) {
47
33
  DebugSealHandleScope scope(isolate);
48
33
  Environment* env = Environment::GetCurrent(isolate);
49
33
  return env != nullptr &&
50

68
         (env->is_main_thread() || !env->is_stopping()) &&
51
63
         env->abort_on_uncaught_exception() &&
52
96
         env->should_abort_on_uncaught_toggle()[0] &&
53
34
         !env->inside_should_not_abort_on_uncaught_scope();
54
}
55
56
65294
MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
57
                                            Local<Value> exception,
58
                                            Local<Array> trace) {
59
65294
  Environment* env = Environment::GetCurrent(context);
60
65294
  if (env == nullptr) {
61
    return exception->ToString(context).FromMaybe(Local<Value>());
62
  }
63
65294
  Local<Function> prepare = env->prepare_stack_trace_callback();
64
65294
  if (prepare.IsEmpty()) {
65
    return exception->ToString(context).FromMaybe(Local<Value>());
66
  }
67
  Local<Value> args[] = {
68
      context->Global(),
69
      exception,
70
      trace,
71
130588
  };
72
  // This TryCatch + Rethrow is required by V8 due to details around exception
73
  // handling there. For C++ callbacks, V8 expects a scheduled exception (which
74
  // is what ReThrow gives us). Just returning the empty MaybeLocal would leave
75
  // us with a pending exception.
76
65294
  TryCatchScope try_catch(env);
77
  MaybeLocal<Value> result = prepare->Call(
78
130588
      context, Undefined(env->isolate()), arraysize(args), args);
79

65294
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
80
2
    try_catch.ReThrow();
81
  }
82
65294
  return result;
83
}
84
85
331515
void* NodeArrayBufferAllocator::Allocate(size_t size) {
86
  void* ret;
87

331515
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
88
54647
    ret = UncheckedCalloc(size);
89
  else
90
276868
    ret = UncheckedMalloc(size);
91
331515
  if (LIKELY(ret != nullptr))
92
331515
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
93
331515
  return ret;
94
}
95
96
149124
void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
97
149124
  void* ret = node::UncheckedMalloc(size);
98
149124
  if (LIKELY(ret != nullptr))
99
149124
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
100
149124
  return ret;
101
}
102
103
60772
void* NodeArrayBufferAllocator::Reallocate(
104
    void* data, size_t old_size, size_t size) {
105
60772
  void* ret = UncheckedRealloc<char>(static_cast<char*>(data), size);
106

60772
  if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
107
60772
    total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
108
60772
  return ret;
109
}
110
111
461995
void NodeArrayBufferAllocator::Free(void* data, size_t size) {
112
461995
  total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
113
461995
  free(data);
114
461995
}
115
116
12
DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
117
6
  CHECK(allocations_.empty());
118
12
}
119
120
78
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
121
78
  Mutex::ScopedLock lock(mutex_);
122
78
  void* data = NodeArrayBufferAllocator::Allocate(size);
123
78
  RegisterPointerInternal(data, size);
124
78
  return data;
125
}
126
127
41
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
128
41
  Mutex::ScopedLock lock(mutex_);
129
41
  void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
130
41
  RegisterPointerInternal(data, size);
131
41
  return data;
132
}
133
134
119
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
135
238
  Mutex::ScopedLock lock(mutex_);
136
119
  UnregisterPointerInternal(data, size);
137
119
  NodeArrayBufferAllocator::Free(data, size);
138
119
}
139
140
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
141
                                                size_t old_size,
142
                                                size_t size) {
143
  Mutex::ScopedLock lock(mutex_);
144
  void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size);
145
  if (ret == nullptr) {
146
    if (size == 0) {  // i.e. equivalent to free().
147
      // suppress coverity warning as data is used as key versus as pointer
148
      // in UnregisterPointerInternal
149
      // coverity[pass_freed_arg]
150
      UnregisterPointerInternal(data, old_size);
151
    }
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
119
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
178
                                                              size_t size) {
179
119
  if (data == nullptr) return;
180
119
  auto it = allocations_.find(data);
181
119
  CHECK_NE(it, allocations_.end());
182
119
  if (size > 0) {
183
    // We allow allocations with size 1 for 0-length buffers to avoid having
184
    // to deal with nullptr values.
185
119
    CHECK_EQ(it->second, size);
186
  }
187
119
  allocations_.erase(it);
188
}
189
190
119
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
191
                                                            size_t size) {
192
119
  if (data == nullptr) return;
193
119
  CHECK_EQ(allocations_.count(data), 0);
194
119
  allocations_[data] = size;
195
}
196
197
5590
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
198

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

1911
      InitializePrimordials(context).IsNothing())
523
4
    return MaybeLocal<Object>();
524
633
  return handle_scope.Escape(exports);
525
}
526
527
// Any initialization logic should be performed in
528
// InitializeContext, because embedders don't necessarily
529
// call NewContext and so they will experience breakages.
530
631
Local<Context> NewContext(Isolate* isolate,
531
                          Local<ObjectTemplate> object_template) {
532
1262
  auto context = Context::New(isolate, nullptr, object_template);
533
631
  if (context.IsEmpty()) return context;
534
535
1262
  if (InitializeContext(context).IsNothing()) {
536
4
    return Local<Context>();
537
  }
538
539
627
  return context;
540
}
541
542
8
void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
543
8
  THROW_ERR_PROTO_ACCESS(info.GetIsolate());
544
8
}
545
546
// This runs at runtime, regardless of whether the context
547
// is created from a snapshot.
548
6168
Maybe<bool> InitializeContextRuntime(Local<Context> context) {
549
6168
  Isolate* isolate = context->GetIsolate();
550
12336
  HandleScope handle_scope(isolate);
551
552
  // Delete `Intl.v8BreakIterator`
553
  // https://github.com/nodejs/node/issues/14909
554
  {
555
    Local<String> intl_string =
556
6168
      FIXED_ONE_BYTE_STRING(isolate, "Intl");
557
    Local<String> break_iter_string =
558
6168
      FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
559
560
    Local<Value> intl_v;
561
6168
    if (!context->Global()
562
6168
        ->Get(context, intl_string)
563
6168
        .ToLocal(&intl_v)) {
564
      return Nothing<bool>();
565
    }
566
567
12336
    if (intl_v->IsObject() &&
568
6168
        intl_v.As<Object>()
569
12336
          ->Delete(context, break_iter_string)
570
6168
          .IsNothing()) {
571
      return Nothing<bool>();
572
    }
573
  }
574
575
  // Delete `Atomics.wake`
576
  // https://github.com/nodejs/node/issues/21219
577
  {
578
    Local<String> atomics_string =
579
6168
      FIXED_ONE_BYTE_STRING(isolate, "Atomics");
580
    Local<String> wake_string =
581
6168
      FIXED_ONE_BYTE_STRING(isolate, "wake");
582
583
    Local<Value> atomics_v;
584
6168
    if (!context->Global()
585
6168
        ->Get(context, atomics_string)
586
6168
        .ToLocal(&atomics_v)) {
587
      return Nothing<bool>();
588
    }
589
590
12330
    if (atomics_v->IsObject() &&
591
6162
        atomics_v.As<Object>()
592
12330
          ->Delete(context, wake_string)
593
6162
          .IsNothing()) {
594
      return Nothing<bool>();
595
    }
596
  }
597
598
  // Remove __proto__
599
  // https://github.com/nodejs/node/issues/31951
600
  Local<Object> prototype;
601
  {
602
    Local<String> object_string =
603
6168
      FIXED_ONE_BYTE_STRING(isolate, "Object");
604
    Local<String> prototype_string =
605
6168
      FIXED_ONE_BYTE_STRING(isolate, "prototype");
606
607
    Local<Value> object_v;
608
6168
    if (!context->Global()
609
6168
        ->Get(context, object_string)
610
6168
        .ToLocal(&object_v)) {
611
      return Nothing<bool>();
612
    }
613
614
    Local<Value> prototype_v;
615
6168
    if (!object_v.As<Object>()
616
6168
        ->Get(context, prototype_string)
617
6168
        .ToLocal(&prototype_v)) {
618
      return Nothing<bool>();
619
    }
620
621
6168
    prototype = prototype_v.As<Object>();
622
  }
623
624
  Local<String> proto_string =
625
6168
    FIXED_ONE_BYTE_STRING(isolate, "__proto__");
626
627
6168
  if (per_process::cli_options->disable_proto == "delete") {
628
4
    if (prototype
629
4
        ->Delete(context, proto_string)
630
4
        .IsNothing()) {
631
      return Nothing<bool>();
632
    }
633
6164
  } else if (per_process::cli_options->disable_proto == "throw") {
634
    Local<Value> thrower;
635
4
    if (!Function::New(context, ProtoThrower)
636
4
        .ToLocal(&thrower)) {
637
      return Nothing<bool>();
638
    }
639
640
4
    PropertyDescriptor descriptor(thrower, thrower);
641
4
    descriptor.set_enumerable(false);
642
4
    descriptor.set_configurable(true);
643
4
    if (prototype
644
4
        ->DefineProperty(context, proto_string, descriptor)
645
4
        .IsNothing()) {
646
      return Nothing<bool>();
647
    }
648
6160
  } else if (per_process::cli_options->disable_proto != "") {
649
    // Validated in ProcessGlobalArgs
650
    FatalError("InitializeContextRuntime()",
651
               "invalid --disable-proto mode");
652
  }
653
654
6168
  return Just(true);
655
}
656
657
632
Maybe<bool> InitializeContextForSnapshot(Local<Context> context) {
658
632
  Isolate* isolate = context->GetIsolate();
659
1264
  HandleScope handle_scope(isolate);
660
661
1264
  context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
662
                           True(isolate));
663
664
632
  return InitializePrimordials(context);
665
}
666
667
1269
Maybe<bool> InitializePrimordials(Local<Context> context) {
668
  // Run per-context JS files.
669
1269
  Isolate* isolate = context->GetIsolate();
670
1269
  Context::Scope context_scope(context);
671
  Local<Object> exports;
672
673
  Local<String> primordials_string =
674
1269
      FIXED_ONE_BYTE_STRING(isolate, "primordials");
675
1269
  Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
676
1269
  Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
677
678
  // Create primordials first and make it available to per-context scripts.
679
1269
  Local<Object> primordials = Object::New(isolate);
680
2538
  if (primordials->SetPrototype(context, Null(isolate)).IsNothing() ||
681

3803
      !GetPerContextExports(context).ToLocal(&exports) ||
682

3799
      exports->Set(context, primordials_string, primordials).IsNothing()) {
683
4
    return Nothing<bool>();
684
  }
685
686
  static const char* context_files[] = {"internal/per_context/primordials",
687
                                        "internal/per_context/domexception",
688
                                        "internal/per_context/messageport",
689
                                        nullptr};
690
691
5048
  for (const char** module = context_files; *module != nullptr; module++) {
692
    std::vector<Local<String>> parameters = {
693
3787
        global_string, exports_string, primordials_string};
694
7574
    Local<Value> arguments[] = {context->Global(), exports, primordials};
695
    MaybeLocal<Function> maybe_fn =
696
        native_module::NativeModuleEnv::LookupAndCompile(
697
3787
            context, *module, &parameters, nullptr);
698
    Local<Function> fn;
699
3787
    if (!maybe_fn.ToLocal(&fn)) {
700
      return Nothing<bool>();
701
    }
702
    MaybeLocal<Value> result =
703
7574
        fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
704
    // Execution failed during context creation.
705
3787
    if (result.IsEmpty()) {
706
4
      return Nothing<bool>();
707
    }
708
  }
709
710
1261
  return Just(true);
711
}
712
713
632
Maybe<bool> InitializeContext(Local<Context> context) {
714
1264
  if (InitializeContextForSnapshot(context).IsNothing()) {
715
4
    return Nothing<bool>();
716
  }
717
718
628
  return InitializeContextRuntime(context);
719
}
720
721
9
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
722
18
  HandleScope handle_scope(isolate);
723
9
  Local<Context> context = isolate->GetCurrentContext();
724
9
  if (context.IsEmpty()) return nullptr;
725
9
  Environment* env = Environment::GetCurrent(context);
726
9
  if (env == nullptr) return nullptr;
727
9
  return env->event_loop();
728
}
729
730
9
void AddLinkedBinding(Environment* env, const node_module& mod) {
731
9
  CHECK_NOT_NULL(env);
732
18
  Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
733
734
9
  node_module* prev_tail = env->extra_linked_bindings_tail();
735
9
  env->extra_linked_bindings()->push_back(mod);
736
9
  if (prev_tail != nullptr)
737
5
    prev_tail->nm_link = &env->extra_linked_bindings()->back();
738
9
}
739
740
3
void AddLinkedBinding(Environment* env, const napi_module& mod) {
741
3
  AddLinkedBinding(env, napi_module_to_node_module(&mod));
742
3
}
743
744
6
void AddLinkedBinding(Environment* env,
745
                      const char* name,
746
                      addon_context_register_func fn,
747
                      void* priv) {
748
6
  node_module mod = {
749
    NODE_MODULE_VERSION,
750
    NM_F_LINKED,
751
    nullptr,  // nm_dso_handle
752
    nullptr,  // nm_filename
753
    nullptr,  // nm_register_func
754
    fn,
755
    name,
756
    priv,
757
    nullptr   // nm_link
758
6
  };
759
6
  AddLinkedBinding(env, mod);
760
6
}
761
762
static std::atomic<uint64_t> next_thread_id{0};
763
764
5809
ThreadId AllocateEnvironmentThreadId() {
765
5809
  return ThreadId { next_thread_id++ };
766
}
767
768
514
void DefaultProcessExitHandler(Environment* env, int exit_code) {
769
514
  env->set_can_call_into_js(false);
770
514
  env->stop_sub_worker_contexts();
771
514
  DisposePlatform();
772
514
  uv_library_shutdown();
773
514
  exit(exit_code);
774
}
775
776
777
574
void SetProcessExitHandler(Environment* env,
778
                           std::function<void(Environment*, int)>&& handler) {
779
574
  env->set_process_exit_handler(std::move(handler));
780
574
}
781
782
}  // namespace node