GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/environment.cc Lines: 343 396 86.6 %
Date: 2022-12-07 04:23:16 Branches: 108 188 57.4 %

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
#ifdef NODE_ENABLE_VTUNE_PROFILING
16
#include "../deps/v8/src/third_party/vtune/v8-vtune.h"
17
#endif
18
#if HAVE_INSPECTOR
19
#include "inspector/worker_inspector.h"  // ParentInspectorHandle
20
#endif
21
22
namespace node {
23
using errors::TryCatchScope;
24
using v8::Array;
25
using v8::Context;
26
using v8::EscapableHandleScope;
27
using v8::Function;
28
using v8::FunctionCallbackInfo;
29
using v8::HandleScope;
30
using v8::Isolate;
31
using v8::Just;
32
using v8::Local;
33
using v8::Maybe;
34
using v8::MaybeLocal;
35
using v8::Nothing;
36
using v8::Null;
37
using v8::Object;
38
using v8::ObjectTemplate;
39
using v8::Private;
40
using v8::PropertyDescriptor;
41
using v8::SealHandleScope;
42
using v8::String;
43
using v8::Value;
44
45
386
bool AllowWasmCodeGenerationCallback(Local<Context> context,
46
                                     Local<String>) {
47
  Local<Value> wasm_code_gen =
48
772
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
49

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

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

68294
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
86
2
    try_catch.ReThrow();
87
  }
88
68294
  return result;
89
}
90
91
380666
void* NodeArrayBufferAllocator::Allocate(size_t size) {
92
  void* ret;
93

380666
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
94
64569
    ret = allocator_->Allocate(size);
95
  else
96
316097
    ret = allocator_->AllocateUninitialized(size);
97
380666
  if (LIKELY(ret != nullptr))
98
380666
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
99
380666
  return ret;
100
}
101
102
174178
void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
103
174178
  void* ret = allocator_->AllocateUninitialized(size);
104
174178
  if (LIKELY(ret != nullptr))
105
174178
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
106
174178
  return ret;
107
}
108
109
63290
void* NodeArrayBufferAllocator::Reallocate(
110
    void* data, size_t old_size, size_t size) {
111
63290
  void* ret = allocator_->Reallocate(data, old_size, size);
112

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

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

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

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

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

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