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

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

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

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

393648
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
89
69741
    ret = allocator_->Allocate(size);
90
  else
91
323907
    ret = allocator_->AllocateUninitialized(size);
92
393648
  if (LIKELY(ret != nullptr))
93
393648
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
94
393648
  return ret;
95
}
96
97
161847
void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
98
161847
  void* ret = allocator_->AllocateUninitialized(size);
99
161847
  if (LIKELY(ret != nullptr))
100
161847
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
101
161847
  return ret;
102
}
103
104
63027
void* NodeArrayBufferAllocator::Reallocate(
105
    void* data, size_t old_size, size_t size) {
106
63027
  void* ret = allocator_->Reallocate(data, old_size, size);
107

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

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

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

393
      !GetPerContextExports(context).ToLocal(&exports) ||
694

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