GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: api/environment.cc Lines: 339 389 87.1 %
Date: 2022-09-07 04:19:57 Branches: 109 190 57.4 %

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

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

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

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

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

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

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

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

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

423
      !GetPerContextExports(context).ToLocal(&exports) ||
692

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