GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/environment.cc Lines: 342 396 86.4 %
Date: 2022-11-05 03:21:31 Branches: 107 188 56.9 %

Line Branch Exec Source
1
#include <cstdlib>
2
#include "node.h"
3
#include "node_builtins.h"
4
#include "node_context_data.h"
5
#include "node_errors.h"
6
#include "node_exit_code.h"
7
#include "node_internals.h"
8
#include "node_options-inl.h"
9
#include "node_platform.h"
10
#include "node_realm-inl.h"
11
#include "node_shadow_realm.h"
12
#include "node_v8_platform-inl.h"
13
#include "node_wasm_web_api.h"
14
#include "uv.h"
15
16
#if HAVE_INSPECTOR
17
#include "inspector/worker_inspector.h"  // ParentInspectorHandle
18
#endif
19
20
namespace node {
21
using errors::TryCatchScope;
22
using v8::Array;
23
using v8::Context;
24
using v8::EscapableHandleScope;
25
using v8::Function;
26
using v8::FunctionCallbackInfo;
27
using v8::HandleScope;
28
using v8::Isolate;
29
using v8::Just;
30
using v8::Local;
31
using v8::Maybe;
32
using v8::MaybeLocal;
33
using v8::Nothing;
34
using v8::Null;
35
using v8::Object;
36
using v8::ObjectTemplate;
37
using v8::Private;
38
using v8::PropertyDescriptor;
39
using v8::SealHandleScope;
40
using v8::String;
41
using v8::Value;
42
43
384
bool AllowWasmCodeGenerationCallback(Local<Context> context,
44
                                     Local<String>) {
45
  Local<Value> wasm_code_gen =
46
768
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
47

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

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

68012
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
84
2
    try_catch.ReThrow();
85
  }
86
68012
  return result;
87
}
88
89
376886
void* NodeArrayBufferAllocator::Allocate(size_t size) {
90
  void* ret;
91

376886
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
92
63213
    ret = allocator_->Allocate(size);
93
  else
94
313673
    ret = allocator_->AllocateUninitialized(size);
95
376886
  if (LIKELY(ret != nullptr))
96
376886
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
97
376886
  return ret;
98
}
99
100
172671
void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
101
172671
  void* ret = allocator_->AllocateUninitialized(size);
102
172671
  if (LIKELY(ret != nullptr))
103
172671
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
104
172671
  return ret;
105
}
106
107
61885
void* NodeArrayBufferAllocator::Reallocate(
108
    void* data, size_t old_size, size_t size) {
109
61885
  void* ret = allocator_->Reallocate(data, old_size, size);
110

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

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

225
      InitializePrimordials(context).IsNothing())
531
    return MaybeLocal<Object>();
532
75
  return handle_scope.Escape(exports);
533
}
534
535
// Any initialization logic should be performed in
536
// InitializeContext, because embedders don't necessarily
537
// call NewContext and so they will experience breakages.
538
69
Local<Context> NewContext(Isolate* isolate,
539
                          Local<ObjectTemplate> object_template) {
540
138
  auto context = Context::New(isolate, nullptr, object_template);
541
69
  if (context.IsEmpty()) return context;
542
543
138
  if (InitializeContext(context).IsNothing()) {
544
    return Local<Context>();
545
  }
546
547
69
  return context;
548
}
549
550
8
void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
551
8
  THROW_ERR_PROTO_ACCESS(info.GetIsolate());
552
8
}
553
554
// This runs at runtime, regardless of whether the context
555
// is created from a snapshot.
556
6998
Maybe<bool> InitializeContextRuntime(Local<Context> context) {
557
6998
  Isolate* isolate = context->GetIsolate();
558
13996
  HandleScope handle_scope(isolate);
559
560
  // When `IsCodeGenerationFromStringsAllowed` is true, V8 takes the fast path
561
  // and ignores the ModifyCodeGenerationFromStrings callback. Set it to false
562
  // to delegate the code generation validation to
563
  // node::ModifyCodeGenerationFromStrings.
564
  // The `IsCodeGenerationFromStringsAllowed` can be refreshed by V8 according
565
  // to the runtime flags, propagate the value to the embedder data.
566
  bool is_code_generation_from_strings_allowed =
567
6998
      context->IsCodeGenerationFromStringsAllowed();
568
6998
  context->AllowCodeGenerationFromStrings(false);
569
13996
  context->SetEmbedderData(
570
      ContextEmbedderIndex::kAllowCodeGenerationFromStrings,
571
      is_code_generation_from_strings_allowed ? True(isolate) : False(isolate));
572
573
6998
  if (per_process::cli_options->disable_proto == "") {
574
6990
    return Just(true);
575
  }
576
577
  // Remove __proto__
578
  // https://github.com/nodejs/node/issues/31951
579
  Local<Object> prototype;
580
  {
581
    Local<String> object_string =
582
8
      FIXED_ONE_BYTE_STRING(isolate, "Object");
583
    Local<String> prototype_string =
584
8
      FIXED_ONE_BYTE_STRING(isolate, "prototype");
585
586
    Local<Value> object_v;
587
8
    if (!context->Global()
588
8
        ->Get(context, object_string)
589
8
        .ToLocal(&object_v)) {
590
      return Nothing<bool>();
591
    }
592
593
    Local<Value> prototype_v;
594
8
    if (!object_v.As<Object>()
595
8
        ->Get(context, prototype_string)
596
8
        .ToLocal(&prototype_v)) {
597
      return Nothing<bool>();
598
    }
599
600
8
    prototype = prototype_v.As<Object>();
601
  }
602
603
  Local<String> proto_string =
604
8
    FIXED_ONE_BYTE_STRING(isolate, "__proto__");
605
606
8
  if (per_process::cli_options->disable_proto == "delete") {
607
4
    if (prototype
608
4
        ->Delete(context, proto_string)
609
4
        .IsNothing()) {
610
      return Nothing<bool>();
611
    }
612
4
  } else if (per_process::cli_options->disable_proto == "throw") {
613
    Local<Value> thrower;
614
4
    if (!Function::New(context, ProtoThrower)
615
4
        .ToLocal(&thrower)) {
616
      return Nothing<bool>();
617
    }
618
619
4
    PropertyDescriptor descriptor(thrower, thrower);
620
4
    descriptor.set_enumerable(false);
621
4
    descriptor.set_configurable(true);
622
4
    if (prototype
623
4
        ->DefineProperty(context, proto_string, descriptor)
624
4
        .IsNothing()) {
625
      return Nothing<bool>();
626
    }
627
  } else if (per_process::cli_options->disable_proto != "") {
628
    // Validated in ProcessGlobalArgs
629
    FatalError("InitializeContextRuntime()",
630
               "invalid --disable-proto mode");
631
  }
632
633
8
  return Just(true);
634
}
635
636
80
Maybe<bool> InitializeBaseContextForSnapshot(Local<Context> context) {
637
80
  Isolate* isolate = context->GetIsolate();
638
160
  HandleScope handle_scope(isolate);
639
640
  // Delete `Intl.v8BreakIterator`
641
  // https://github.com/nodejs/node/issues/14909
642
  {
643
80
    Context::Scope context_scope(context);
644
80
    Local<String> intl_string = FIXED_ONE_BYTE_STRING(isolate, "Intl");
645
    Local<String> break_iter_string =
646
80
        FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
647
648
    Local<Value> intl_v;
649
240
    if (!context->Global()->Get(context, intl_string).ToLocal(&intl_v)) {
650
      return Nothing<bool>();
651
    }
652
653
160
    if (intl_v->IsObject() &&
654

240
        intl_v.As<Object>()->Delete(context, break_iter_string).IsNothing()) {
655
      return Nothing<bool>();
656
    }
657
  }
658
80
  return Just(true);
659
}
660
661
70
Maybe<bool> InitializeMainContextForSnapshot(Local<Context> context) {
662
70
  Isolate* isolate = context->GetIsolate();
663
140
  HandleScope handle_scope(isolate);
664
665
  // Initialize the default values.
666
140
  context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
667
                           True(isolate));
668
140
  context->SetEmbedderData(
669
      ContextEmbedderIndex::kAllowCodeGenerationFromStrings, True(isolate));
670
671
140
  if (InitializeBaseContextForSnapshot(context).IsNothing()) {
672
    return Nothing<bool>();
673
  }
674
70
  return InitializePrimordials(context);
675
}
676
677
145
Maybe<bool> InitializePrimordials(Local<Context> context) {
678
  // Run per-context JS files.
679
145
  Isolate* isolate = context->GetIsolate();
680
145
  Context::Scope context_scope(context);
681
  Local<Object> exports;
682
683
  Local<String> primordials_string =
684
145
      FIXED_ONE_BYTE_STRING(isolate, "primordials");
685
686
  // Create primordials first and make it available to per-context scripts.
687
145
  Local<Object> primordials = Object::New(isolate);
688
290
  if (primordials->SetPrototype(context, Null(isolate)).IsNothing() ||
689

435
      !GetPerContextExports(context).ToLocal(&exports) ||
690

435
      exports->Set(context, primordials_string, primordials).IsNothing()) {
691
    return Nothing<bool>();
692
  }
693
694
  static const char* context_files[] = {"internal/per_context/primordials",
695
                                        "internal/per_context/domexception",
696
                                        "internal/per_context/messageport",
697
                                        nullptr};
698
699
580
  for (const char** module = context_files; *module != nullptr; module++) {
700
435
    Local<Value> arguments[] = {exports, primordials};
701
435
    if (builtins::BuiltinLoader::CompileAndCall(
702
435
            context, *module, arraysize(arguments), arguments, nullptr)
703
435
            .IsEmpty()) {
704
      // Execution failed during context creation.
705
      return Nothing<bool>();
706
    }
707
  }
708
709
145
  return Just(true);
710
}
711
712
// This initializes the main context (i.e. vm contexts are not included).
713
70
Maybe<bool> InitializeContext(Local<Context> context) {
714
140
  if (InitializeMainContextForSnapshot(context).IsNothing()) {
715
    return Nothing<bool>();
716
  }
717
718
70
  return InitializeContextRuntime(context);
719
}
720
721
10
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
722
20
  HandleScope handle_scope(isolate);
723
10
  Local<Context> context = isolate->GetCurrentContext();
724
10
  if (context.IsEmpty()) return nullptr;
725
10
  Environment* env = Environment::GetCurrent(context);
726
10
  if (env == nullptr) return nullptr;
727
10
  return env->event_loop();
728
}
729
730
9
void AddLinkedBinding(Environment* env, const node_module& mod) {
731
9
  CHECK_NOT_NULL(env);
732
18
  Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
733
734
9
  node_module* prev_tail = env->extra_linked_bindings_tail();
735
9
  env->extra_linked_bindings()->push_back(mod);
736
9
  if (prev_tail != nullptr)
737
5
    prev_tail->nm_link = &env->extra_linked_bindings()->back();
738
9
}
739
740
3
void AddLinkedBinding(Environment* env, const napi_module& mod) {
741
3
  AddLinkedBinding(env, napi_module_to_node_module(&mod));
742
3
}
743
744
6
void AddLinkedBinding(Environment* env,
745
                      const char* name,
746
                      addon_context_register_func fn,
747
                      void* priv) {
748
6
  node_module mod = {
749
    NODE_MODULE_VERSION,
750
    NM_F_LINKED,
751
    nullptr,  // nm_dso_handle
752
    nullptr,  // nm_filename
753
    nullptr,  // nm_register_func
754
    fn,
755
    name,
756
    priv,
757
    nullptr   // nm_link
758
6
  };
759
6
  AddLinkedBinding(env, mod);
760
6
}
761
762
static std::atomic<uint64_t> next_thread_id{0};
763
764
6608
ThreadId AllocateEnvironmentThreadId() {
765
6608
  return ThreadId { next_thread_id++ };
766
}
767
768
599
[[noreturn]] void Exit(ExitCode exit_code) {
769
599
  exit(static_cast<int>(exit_code));
770
}
771
772
595
void DefaultProcessExitHandlerInternal(Environment* env, ExitCode exit_code) {
773
595
  env->set_can_call_into_js(false);
774
595
  env->stop_sub_worker_contexts();
775
595
  env->isolate()->DumpAndResetStats();
776
  // When the process exits, the tasks in the thread pool may also need to
777
  // access the data of V8Platform, such as trace agent, or a field
778
  // added in the future. So make sure the thread pool exits first.
779
  // And make sure V8Platform don not call into Libuv threadpool, see Dispose
780
  // in node_v8_platform-inl.h
781
595
  uv_library_shutdown();
782
595
  DisposePlatform();
783
595
  Exit(exit_code);
784
}
785
786
void DefaultProcessExitHandler(Environment* env, int exit_code) {
787
  DefaultProcessExitHandlerInternal(env, static_cast<ExitCode>(exit_code));
788
}
789
790
void SetProcessExitHandler(
791
    Environment* env, std::function<void(Environment*, ExitCode)>&& handler) {
792
  env->set_process_exit_handler(std::move(handler));
793
}
794
795
726
void SetProcessExitHandler(Environment* env,
796
                           std::function<void(Environment*, int)>&& handler) {
797
726
  auto movedHandler = std::move(handler);
798
726
  env->set_process_exit_handler([=](Environment* env, ExitCode exit_code) {
799
63
    movedHandler(env, static_cast<int>(exit_code));
800
63
  });
801
726
}
802
803
}  // namespace node