GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/environment.cc Lines: 340 385 88.3 %
Date: 2022-04-06 04:15:27 Branches: 114 188 60.6 %

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::Just;
24
using v8::Local;
25
using v8::Maybe;
26
using v8::MaybeLocal;
27
using v8::Nothing;
28
using v8::Null;
29
using v8::Object;
30
using v8::ObjectTemplate;
31
using v8::Private;
32
using v8::PropertyDescriptor;
33
using v8::SealHandleScope;
34
using v8::String;
35
using v8::Value;
36
37
115
bool AllowWasmCodeGenerationCallback(Local<Context> context,
38
                                     Local<String>) {
39
  Local<Value> wasm_code_gen =
40
230
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
41

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

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

65189
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
78
2
    try_catch.ReThrow();
79
  }
80
65189
  return result;
81
}
82
83
198230
void* NodeArrayBufferAllocator::Allocate(size_t size) {
84
  void* ret;
85

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

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

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

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

3845
      !GetPerContextExports(context).ToLocal(&exports) ||
673

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