GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/environment.cc Lines: 339 384 88.3 %
Date: 2021-10-05 04:12:38 Branches: 113 186 60.8 %

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
95
bool AllowWasmCodeGenerationCallback(Local<Context> context,
38
                                     Local<String>) {
39
  Local<Value> wasm_code_gen =
40
190
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
41

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

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

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

60332
  if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
105
60332
    total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
106
60332
  return ret;
107
}
108
109
315183
void NodeArrayBufferAllocator::Free(void* data, size_t size) {
110
315183
  total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
111
315183
  free(data);
112
315183
}
113
114
12
DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
115
6
  CHECK(allocations_.empty());
116
12
}
117
118
45
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
119
45
  Mutex::ScopedLock lock(mutex_);
120
45
  void* data = NodeArrayBufferAllocator::Allocate(size);
121
45
  RegisterPointerInternal(data, size);
122
45
  return data;
123
}
124
125
39
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
126
39
  Mutex::ScopedLock lock(mutex_);
127
39
  void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
128
39
  RegisterPointerInternal(data, size);
129
39
  return data;
130
}
131
132
84
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
133
168
  Mutex::ScopedLock lock(mutex_);
134
84
  UnregisterPointerInternal(data, size);
135
84
  NodeArrayBufferAllocator::Free(data, size);
136
84
}
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
84
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
172
                                                              size_t size) {
173
84
  if (data == nullptr) return;
174
84
  auto it = allocations_.find(data);
175
84
  CHECK_NE(it, allocations_.end());
176
84
  if (size > 0) {
177
    // We allow allocations with size 1 for 0-length buffers to avoid having
178
    // to deal with nullptr values.
179
84
    CHECK_EQ(it->second, size);
180
  }
181
84
  allocations_.erase(it);
182
}
183
184
84
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
185
                                                            size_t size) {
186
84
  if (data == nullptr) return;
187
84
  CHECK_EQ(allocations_.count(data), 0);
188
84
  allocations_[data] = size;
189
}
190
191
5488
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
192

5488
  if (debug || per_process::cli_options->debug_arraybuffer_allocations)
193
3
    return std::make_unique<DebuggingArrayBufferAllocator>();
194
  else
195
5485
    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
5486
void SetIsolateCreateParamsForNode(Isolate::CreateParams* params) {
207
5486
  const uint64_t constrained_memory = uv_get_constrained_memory();
208
10970
  const uint64_t total_memory = constrained_memory > 0 ?
209
5484
      std::min(uv_get_total_memory(), constrained_memory) :
210
2
      uv_get_total_memory();
211
5486
  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
5486
    params->constraints.ConfigureDefaults(total_memory, 0);
216
  }
217
5486
  params->embedder_wrapper_object_index = BaseObject::InternalFields::kSlot;
218
5486
  params->embedder_wrapper_type_index = std::numeric_limits<int>::max();
219
5486
}
220
221
5486
void SetIsolateErrorHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
222
5486
  if (s.flags & MESSAGE_LISTENER_WITH_ERROR_LEVEL)
223
5486
    isolate->AddMessageListenerWithErrorLevel(
224
            errors::PerIsolateMessageListener,
225
            Isolate::MessageErrorLevel::kMessageError |
226
                Isolate::MessageErrorLevel::kMessageWarning);
227
228
5486
  auto* abort_callback = s.should_abort_on_uncaught_exception_callback ?
229
      s.should_abort_on_uncaught_exception_callback :
230
      ShouldAbortOnUncaughtException;
231
5486
  isolate->SetAbortOnUncaughtExceptionCallback(abort_callback);
232
233
5486
  auto* fatal_error_cb = s.fatal_error_callback ?
234
      s.fatal_error_callback : OnFatalError;
235
5486
  isolate->SetFatalErrorHandler(fatal_error_cb);
236
237
5486
  if ((s.flags & SHOULD_NOT_SET_PREPARE_STACK_TRACE_CALLBACK) == 0) {
238
5486
    auto* prepare_stack_trace_cb = s.prepare_stack_trace_callback ?
239
        s.prepare_stack_trace_callback : PrepareStackTraceCallback;
240
5486
    isolate->SetPrepareStackTraceCallback(prepare_stack_trace_cb);
241
  }
242
5486
}
243
244
5492
void SetIsolateMiscHandlers(v8::Isolate* isolate, const IsolateSettings& s) {
245
5492
  isolate->SetMicrotasksPolicy(s.policy);
246
247
5492
  auto* allow_wasm_codegen_cb = s.allow_wasm_code_generation_callback ?
248
    s.allow_wasm_code_generation_callback : AllowWasmCodeGenerationCallback;
249
5492
  isolate->SetAllowWasmCodeGenerationCallback(allow_wasm_codegen_cb);
250
251
5492
  if ((s.flags & SHOULD_NOT_SET_PROMISE_REJECTION_CALLBACK) == 0) {
252
5492
    auto* promise_reject_cb = s.promise_reject_callback ?
253
      s.promise_reject_callback : PromiseRejectCallback;
254
5492
    isolate->SetPromiseRejectCallback(promise_reject_cb);
255
  }
256
257
5492
  if (s.flags & DETAILED_SOURCE_POSITIONS_FOR_PROFILING)
258
5492
    v8::CpuProfiler::UseDetailedSourcePositionsForProfiling(isolate);
259
5492
}
260
261
638
void SetIsolateUpForNode(v8::Isolate* isolate,
262
                         const IsolateSettings& settings) {
263
638
  SetIsolateErrorHandlers(isolate, settings);
264
638
  SetIsolateMiscHandlers(isolate, settings);
265
638
}
266
267
638
void SetIsolateUpForNode(v8::Isolate* isolate) {
268
638
  IsolateSettings settings;
269
638
  SetIsolateUpForNode(isolate, settings);
270
638
}
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
623
IsolateData* CreateIsolateData(Isolate* isolate,
308
                               uv_loop_t* loop,
309
                               MultiIsolatePlatform* platform,
310
                               ArrayBufferAllocator* allocator) {
311
623
  return new IsolateData(isolate, loop, platform, allocator);
312
}
313
314
621
void FreeIsolateData(IsolateData* isolate_data) {
315
621
  delete isolate_data;
316
621
}
317
318
1612
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
806
  explicit InspectorParentHandleImpl(
326
      std::unique_ptr<inspector::ParentInspectorHandle>&& impl)
327
806
    : impl(std::move(impl)) {}
328
};
329
#endif
330
331
608
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
608
  Isolate* isolate = context->GetIsolate();
340
1216
  HandleScope handle_scope(isolate);
341
608
  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
608
      isolate_data, context, args, exec_args, nullptr, flags, thread_id);
346
#if HAVE_INSPECTOR
347
608
  if (inspector_parent_handle) {
348
561
    env->InitializeInspector(
349
        std::move(static_cast<InspectorParentHandleImpl*>(
350
561
            inspector_parent_handle.get())->impl));
351
  } else {
352
47
    env->InitializeInspector({});
353
  }
354
#endif
355
356
1216
  if (env->RunBootstrapping().IsEmpty()) {
357
    FreeEnvironment(env);
358
    return nullptr;
359
  }
360
361
608
  return env;
362
}
363
364
4978
void FreeEnvironment(Environment* env) {
365
4978
  Isolate* isolate = env->isolate();
366
  Isolate::DisallowJavascriptExecutionScope disallow_js(isolate,
367
9956
      Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
368
  {
369
9956
    HandleScope handle_scope(isolate);  // For env->context().
370
4978
    Context::Scope context_scope(env->context());
371
9956
    SealHandleScope seal_handle_scope(isolate);
372
373
4978
    env->set_stopping(true);
374
4978
    env->stop_sub_worker_contexts();
375
4978
    env->RunCleanup();
376
4978
    RunAtExit(env);
377
  }
378
379
  // This call needs to be made while the `Environment` is still alive
380
  // because we assume that it is available for async tracking in the
381
  // NodePlatform implementation.
382
4978
  MultiIsolatePlatform* platform = env->isolate_data()->platform();
383
4978
  if (platform != nullptr)
384
4978
    platform->DrainTasks(isolate);
385
386
4978
  delete env;
387
4978
}
388
389
806
NODE_EXTERN std::unique_ptr<InspectorParentHandle> GetInspectorParentHandle(
390
    Environment* env,
391
    ThreadId thread_id,
392
    const char* url) {
393
806
  CHECK_NOT_NULL(env);
394
806
  CHECK_NE(thread_id.id, static_cast<uint64_t>(-1));
395
#if HAVE_INSPECTOR
396
1612
  return std::make_unique<InspectorParentHandleImpl>(
397
2418
      env->inspector_agent()->GetParentHandle(thread_id.id, url));
398
#else
399
  return {};
400
#endif
401
}
402
403
5429
MaybeLocal<Value> LoadEnvironment(
404
    Environment* env,
405
    StartExecutionCallback cb) {
406
5429
  env->InitializeLibuv();
407
5429
  env->InitializeDiagnostics();
408
409
5429
  return StartExecution(env, cb);
410
}
411
412
17
MaybeLocal<Value> LoadEnvironment(
413
    Environment* env,
414
    const char* main_script_source_utf8) {
415
17
  CHECK_NOT_NULL(main_script_source_utf8);
416
17
  Isolate* isolate = env->isolate();
417
  return LoadEnvironment(
418
      env,
419
17
      [&](const StartExecutionCallbackInfo& info) -> MaybeLocal<Value> {
420
        // This is a slightly hacky way to convert UTF-8 to UTF-16.
421
        Local<String> str =
422
34
            String::NewFromUtf8(isolate,
423
17
                                main_script_source_utf8).ToLocalChecked();
424
32
        auto main_utf16 = std::make_unique<String::Value>(isolate, str);
425
426
        // TODO(addaleax): Avoid having a global table for all scripts.
427
32
        std::string name = "embedder_main_" + std::to_string(env->thread_id());
428
17
        native_module::NativeModuleEnv::Add(
429
            name.c_str(),
430
17
            UnionBytes(**main_utf16, main_utf16->length()));
431
17
        env->set_main_utf16(std::move(main_utf16));
432
        std::vector<Local<String>> params = {
433
17
            env->process_string(),
434
32
            env->require_string()};
435
        std::vector<Local<Value>> args = {
436
            env->process_object(),
437
66
            env->native_module_require()};
438
17
        return ExecuteBootstrapper(env, name.c_str(), &params, &args);
439
17
      });
440
}
441
442
5
Environment* GetCurrentEnvironment(Local<Context> context) {
443
5
  return Environment::GetCurrent(context);
444
}
445
446
1
IsolateData* GetEnvironmentIsolateData(Environment* env) {
447
1
  return env->isolate_data();
448
}
449
450
1
ArrayBufferAllocator* GetArrayBufferAllocator(IsolateData* isolate_data) {
451
1
  return isolate_data->node_allocator();
452
}
453
454
5131
MultiIsolatePlatform* GetMultiIsolatePlatform(Environment* env) {
455
5131
  return GetMultiIsolatePlatform(env->isolate_data());
456
}
457
458
5131
MultiIsolatePlatform* GetMultiIsolatePlatform(IsolateData* env) {
459
5131
  return env->platform();
460
}
461
462
MultiIsolatePlatform* CreatePlatform(
463
    int thread_pool_size,
464
    node::tracing::TracingController* tracing_controller) {
465
  return CreatePlatform(
466
      thread_pool_size,
467
      static_cast<v8::TracingController*>(tracing_controller));
468
}
469
470
MultiIsolatePlatform* CreatePlatform(
471
    int thread_pool_size,
472
    v8::TracingController* tracing_controller) {
473
  return MultiIsolatePlatform::Create(thread_pool_size,
474
                                      tracing_controller)
475
      .release();
476
}
477
478
void FreePlatform(MultiIsolatePlatform* platform) {
479
  delete platform;
480
}
481
482
7
std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
483
    int thread_pool_size,
484
    v8::TracingController* tracing_controller,
485
    v8::PageAllocator* page_allocator) {
486
14
  return std::make_unique<NodePlatform>(thread_pool_size,
487
                                        tracing_controller,
488
7
                                        page_allocator);
489
}
490
491
36331
MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
492
36331
  Isolate* isolate = context->GetIsolate();
493
36331
  EscapableHandleScope handle_scope(isolate);
494
495
36331
  Local<Object> global = context->Global();
496
  Local<Private> key = Private::ForApi(isolate,
497
36331
      FIXED_ONE_BYTE_STRING(isolate, "node:per_context_binding_exports"));
498
499
  Local<Value> existing_value;
500
72662
  if (!global->GetPrivate(context, key).ToLocal(&existing_value))
501
    return MaybeLocal<Object>();
502
36331
  if (existing_value->IsObject())
503
35705
    return handle_scope.Escape(existing_value.As<Object>());
504
505
626
  Local<Object> exports = Object::New(isolate);
506
2504
  if (context->Global()->SetPrivate(context, key, exports).IsNothing() ||
507

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

3737
      !GetPerContextExports(context).ToLocal(&exports) ||
667

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