GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/environment.cc Lines: 340 385 88.3 %
Date: 2022-03-17 03:14:58 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
116
bool AllowWasmCodeGenerationCallback(Local<Context> context,
38
                                     Local<String>) {
39
  Local<Value> wasm_code_gen =
40
232
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
41

348
  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
65267
MaybeLocal<Value> PrepareStackTraceCallback(Local<Context> context,
55
                                            Local<Value> exception,
56
                                            Local<Array> trace) {
57
65267
  Environment* env = Environment::GetCurrent(context);
58
65267
  if (env == nullptr) {
59
    return exception->ToString(context).FromMaybe(Local<Value>());
60
  }
61
65267
  Local<Function> prepare = env->prepare_stack_trace_callback();
62
65267
  if (prepare.IsEmpty()) {
63
    return exception->ToString(context).FromMaybe(Local<Value>());
64
  }
65
  Local<Value> args[] = {
66
      context->Global(),
67
      exception,
68
      trace,
69
130534
  };
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
65267
  TryCatchScope try_catch(env);
75
  MaybeLocal<Value> result = prepare->Call(
76
130534
      context, Undefined(env->isolate()), arraysize(args), args);
77

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

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

59925
  if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
105
59925
    total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
106
59925
  return ret;
107
}
108
109
328963
void NodeArrayBufferAllocator::Free(void* data, size_t size) {
110
328963
  total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
111
328963
  free(data);
112
328963
}
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
      UnregisterPointerInternal(data, old_size);
146
    return nullptr;
147
  }
148
149
  if (data != nullptr) {
150
    auto it = allocations_.find(data);
151
    CHECK_NE(it, allocations_.end());
152
    allocations_.erase(it);
153
  }
154
155
  RegisterPointerInternal(ret, size);
156
  return ret;
157
}
158
159
void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
160
  Mutex::ScopedLock lock(mutex_);
161
  NodeArrayBufferAllocator::RegisterPointer(data, size);
162
  RegisterPointerInternal(data, size);
163
}
164
165
void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
166
  Mutex::ScopedLock lock(mutex_);
167
  NodeArrayBufferAllocator::UnregisterPointer(data, size);
168
  UnregisterPointerInternal(data, size);
169
}
170
171
87
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
172
                                                              size_t size) {
173
87
  if (data == nullptr) return;
174
87
  auto it = allocations_.find(data);
175
87
  CHECK_NE(it, allocations_.end());
176
87
  if (size > 0) {
177
    // We allow allocations with size 1 for 0-length buffers to avoid having
178
    // to deal with nullptr values.
179
87
    CHECK_EQ(it->second, size);
180
  }
181
87
  allocations_.erase(it);
182
}
183
184
87
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
185
                                                            size_t size) {
186
87
  if (data == nullptr) return;
187
87
  CHECK_EQ(allocations_.count(data), 0);
188
87
  allocations_[data] = size;
189
}
190
191
5602
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
192

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

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

3827
      !GetPerContextExports(context).ToLocal(&exports) ||
669

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