GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/api/environment.cc Lines: 327 368 88.9 %
Date: 2020-05-27 22:15:15 Branches: 104 170 61.2 %

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

132
  return wasm_code_gen->IsUndefined() || wasm_code_gen->IsTrue();
38
}
39
40
32
static bool ShouldAbortOnUncaughtException(Isolate* isolate) {
41
32
  DebugSealHandleScope scope(isolate);
42
32
  Environment* env = Environment::GetCurrent(isolate);
43
32
  return env != nullptr &&
44

64
         (env->is_main_thread() || !env->is_stopping()) &&
45

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

72765
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
73
2
    try_catch.ReThrow();
74
  }
75
72765
  return result;
76
}
77
78
93594
void* NodeArrayBufferAllocator::Allocate(size_t size) {
79
  void* ret;
80

93594
  if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers)
81
60257
    ret = UncheckedCalloc(size);
82
  else
83
33337
    ret = UncheckedMalloc(size);
84
93594
  if (LIKELY(ret != nullptr))
85
93594
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
86
93594
  return ret;
87
}
88
89
378700
void* NodeArrayBufferAllocator::AllocateUninitialized(size_t size) {
90
378700
  void* ret = node::UncheckedMalloc(size);
91
378700
  if (LIKELY(ret != nullptr))
92
378700
    total_mem_usage_.fetch_add(size, std::memory_order_relaxed);
93
378700
  return ret;
94
}
95
96
293868
void* NodeArrayBufferAllocator::Reallocate(
97
    void* data, size_t old_size, size_t size) {
98
293868
  void* ret = UncheckedRealloc<char>(static_cast<char*>(data), size);
99

293868
  if (LIKELY(ret != nullptr) || UNLIKELY(size == 0))
100
293868
    total_mem_usage_.fetch_add(size - old_size, std::memory_order_relaxed);
101
293868
  return ret;
102
}
103
104
465287
void NodeArrayBufferAllocator::Free(void* data, size_t size) {
105
465287
  total_mem_usage_.fetch_sub(size, std::memory_order_relaxed);
106
465287
  free(data);
107
465287
}
108
109
9
DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() {
110
3
  CHECK(allocations_.empty());
111
6
}
112
113
42
void* DebuggingArrayBufferAllocator::Allocate(size_t size) {
114
84
  Mutex::ScopedLock lock(mutex_);
115
42
  void* data = NodeArrayBufferAllocator::Allocate(size);
116
42
  RegisterPointerInternal(data, size);
117
84
  return data;
118
}
119
120
8
void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) {
121
16
  Mutex::ScopedLock lock(mutex_);
122
8
  void* data = NodeArrayBufferAllocator::AllocateUninitialized(size);
123
8
  RegisterPointerInternal(data, size);
124
16
  return data;
125
}
126
127
50
void DebuggingArrayBufferAllocator::Free(void* data, size_t size) {
128
100
  Mutex::ScopedLock lock(mutex_);
129
50
  UnregisterPointerInternal(data, size);
130
50
  NodeArrayBufferAllocator::Free(data, size);
131
50
}
132
133
void* DebuggingArrayBufferAllocator::Reallocate(void* data,
134
                                                size_t old_size,
135
                                                size_t size) {
136
  Mutex::ScopedLock lock(mutex_);
137
  void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size);
138
  if (ret == nullptr) {
139
    if (size == 0)  // i.e. equivalent to free().
140
      UnregisterPointerInternal(data, old_size);
141
    return nullptr;
142
  }
143
144
  if (data != nullptr) {
145
    auto it = allocations_.find(data);
146
    CHECK_NE(it, allocations_.end());
147
    allocations_.erase(it);
148
  }
149
150
  RegisterPointerInternal(ret, size);
151
  return ret;
152
}
153
154
void DebuggingArrayBufferAllocator::RegisterPointer(void* data, size_t size) {
155
  Mutex::ScopedLock lock(mutex_);
156
  NodeArrayBufferAllocator::RegisterPointer(data, size);
157
  RegisterPointerInternal(data, size);
158
}
159
160
void DebuggingArrayBufferAllocator::UnregisterPointer(void* data, size_t size) {
161
  Mutex::ScopedLock lock(mutex_);
162
  NodeArrayBufferAllocator::UnregisterPointer(data, size);
163
  UnregisterPointerInternal(data, size);
164
}
165
166
50
void DebuggingArrayBufferAllocator::UnregisterPointerInternal(void* data,
167
                                                              size_t size) {
168
50
  if (data == nullptr) return;
169
50
  auto it = allocations_.find(data);
170
50
  CHECK_NE(it, allocations_.end());
171
50
  if (size > 0) {
172
    // We allow allocations with size 1 for 0-length buffers to avoid having
173
    // to deal with nullptr values.
174
50
    CHECK_EQ(it->second, size);
175
  }
176
50
  allocations_.erase(it);
177
}
178
179
50
void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data,
180
                                                            size_t size) {
181
50
  if (data == nullptr) return;
182
50
  CHECK_EQ(allocations_.count(data), 0);
183
50
  allocations_[data] = size;
184
}
185
186
4625
std::unique_ptr<ArrayBufferAllocator> ArrayBufferAllocator::Create(bool debug) {
187

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

1372
  if (context->Global()->SetPrivate(context, key, exports).IsNothing() ||
517
343
      !InitializePrimordials(context))
518
4
    return MaybeLocal<Object>();
519
339
  return handle_scope.Escape(exports);
520
}
521
522
// Any initialization logic should be performed in
523
// InitializeContext, because embedders don't necessarily
524
// call NewContext and so they will experience breakages.
525
342
Local<Context> NewContext(Isolate* isolate,
526
                          Local<ObjectTemplate> object_template) {
527
684
  auto context = Context::New(isolate, nullptr, object_template);
528
342
  if (context.IsEmpty()) return context;
529
530
342
  if (!InitializeContext(context)) {
531
4
    return Local<Context>();
532
  }
533
534
338
  return context;
535
}
536
537
8
void ProtoThrower(const FunctionCallbackInfo<Value>& info) {
538
8
  THROW_ERR_PROTO_ACCESS(info.GetIsolate());
539
8
}
540
541
// This runs at runtime, regardless of whether the context
542
// is created from a snapshot.
543
5173
void InitializeContextRuntime(Local<Context> context) {
544
5173
  Isolate* isolate = context->GetIsolate();
545
10346
  HandleScope handle_scope(isolate);
546
547
  // Delete `Intl.v8BreakIterator`
548
  // https://github.com/nodejs/node/issues/14909
549
5173
  Local<String> intl_string = FIXED_ONE_BYTE_STRING(isolate, "Intl");
550
  Local<String> break_iter_string =
551
5173
    FIXED_ONE_BYTE_STRING(isolate, "v8BreakIterator");
552
  Local<Value> intl_v;
553

20692
  if (context->Global()->Get(context, intl_string).ToLocal(&intl_v) &&
554
5173
      intl_v->IsObject()) {
555
5173
    Local<Object> intl = intl_v.As<Object>();
556
10346
    intl->Delete(context, break_iter_string).FromJust();
557
  }
558
559
  // Delete `Atomics.wake`
560
  // https://github.com/nodejs/node/issues/21219
561
5173
  Local<String> atomics_string = FIXED_ONE_BYTE_STRING(isolate, "Atomics");
562
5173
  Local<String> wake_string = FIXED_ONE_BYTE_STRING(isolate, "wake");
563
  Local<Value> atomics_v;
564

20692
  if (context->Global()->Get(context, atomics_string).ToLocal(&atomics_v) &&
565
5173
      atomics_v->IsObject()) {
566
5172
    Local<Object> atomics = atomics_v.As<Object>();
567
10344
    atomics->Delete(context, wake_string).FromJust();
568
  }
569
570
  // Remove __proto__
571
  // https://github.com/nodejs/node/issues/31951
572
5173
  Local<String> object_string = FIXED_ONE_BYTE_STRING(isolate, "Object");
573
5173
  Local<String> prototype_string = FIXED_ONE_BYTE_STRING(isolate, "prototype");
574
10346
  Local<Object> prototype = context->Global()
575
15519
                                ->Get(context, object_string)
576
10346
                                .ToLocalChecked()
577
10346
                                .As<Object>()
578
15519
                                ->Get(context, prototype_string)
579
10346
                                .ToLocalChecked()
580
5173
                                .As<Object>();
581
5173
  Local<String> proto_string = FIXED_ONE_BYTE_STRING(isolate, "__proto__");
582
5173
  if (per_process::cli_options->disable_proto == "delete") {
583
8
    prototype->Delete(context, proto_string).ToChecked();
584
5169
  } else if (per_process::cli_options->disable_proto == "throw") {
585
    Local<Value> thrower =
586
8
        Function::New(context, ProtoThrower).ToLocalChecked();
587
8
    PropertyDescriptor descriptor(thrower, thrower);
588
4
    descriptor.set_enumerable(false);
589
4
    descriptor.set_configurable(true);
590
8
    prototype->DefineProperty(context, proto_string, descriptor).ToChecked();
591
5165
  } else if (per_process::cli_options->disable_proto != "") {
592
    // Validated in ProcessGlobalArgs
593
    FatalError("InitializeContextRuntime()", "invalid --disable-proto mode");
594
  }
595
5173
}
596
597
342
bool InitializeContextForSnapshot(Local<Context> context) {
598
342
  Isolate* isolate = context->GetIsolate();
599
684
  HandleScope handle_scope(isolate);
600
601
684
  context->SetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration,
602
342
                           True(isolate));
603
684
  return InitializePrimordials(context);
604
}
605
606
685
bool InitializePrimordials(Local<Context> context) {
607
  // Run per-context JS files.
608
685
  Isolate* isolate = context->GetIsolate();
609
  Context::Scope context_scope(context);
610
  Local<Object> exports;
611
612
  Local<String> primordials_string =
613
685
      FIXED_ONE_BYTE_STRING(isolate, "primordials");
614
685
  Local<String> global_string = FIXED_ONE_BYTE_STRING(isolate, "global");
615
685
  Local<String> exports_string = FIXED_ONE_BYTE_STRING(isolate, "exports");
616
617
  // Create primordials first and make it available to per-context scripts.
618
685
  Local<Object> primordials = Object::New(isolate);
619

3422
  if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
620

2734
      !GetPerContextExports(context).ToLocal(&exports) ||
621
2046
      !exports->Set(context, primordials_string, primordials).FromJust()) {
622
4
    return false;
623
  }
624
625
  static const char* context_files[] = {"internal/per_context/primordials",
626
                                        "internal/per_context/domexception",
627
                                        "internal/per_context/messageport",
628
                                        nullptr};
629
630
2711
  for (const char** module = context_files; *module != nullptr; module++) {
631
    std::vector<Local<String>> parameters = {
632
4065
        global_string, exports_string, primordials_string};
633
10175
    Local<Value> arguments[] = {context->Global(), exports, primordials};
634
    MaybeLocal<Function> maybe_fn =
635
        native_module::NativeModuleEnv::LookupAndCompile(
636
2035
            context, *module, &parameters, nullptr);
637
2035
    if (maybe_fn.IsEmpty()) {
638
      return false;
639
    }
640
2035
    Local<Function> fn = maybe_fn.ToLocalChecked();
641
    MaybeLocal<Value> result =
642
4070
        fn->Call(context, Undefined(isolate), arraysize(arguments), arguments);
643
    // Execution failed during context creation.
644
    // TODO(joyeecheung): deprecate this signature and return a MaybeLocal.
645
2035
    if (result.IsEmpty()) {
646
4
      return false;
647
    }
648
  }
649
650
677
  return true;
651
}
652
653
342
bool InitializeContext(Local<Context> context) {
654
342
  if (!InitializeContextForSnapshot(context)) {
655
4
    return false;
656
  }
657
658
338
  InitializeContextRuntime(context);
659
338
  return true;
660
}
661
662
8
uv_loop_t* GetCurrentEventLoop(Isolate* isolate) {
663
16
  HandleScope handle_scope(isolate);
664
8
  Local<Context> context = isolate->GetCurrentContext();
665
8
  if (context.IsEmpty()) return nullptr;
666
8
  Environment* env = Environment::GetCurrent(context);
667
8
  if (env == nullptr) return nullptr;
668
8
  return env->event_loop();
669
}
670
671
1
void AddLinkedBinding(Environment* env, const node_module& mod) {
672
1
  CHECK_NOT_NULL(env);
673
2
  Mutex::ScopedLock lock(env->extra_linked_bindings_mutex());
674
675
1
  node_module* prev_head = env->extra_linked_bindings_head();
676
1
  env->extra_linked_bindings()->push_back(mod);
677
1
  if (prev_head != nullptr)
678
    prev_head->nm_link = &env->extra_linked_bindings()->back();
679
1
}
680
681
1
void AddLinkedBinding(Environment* env,
682
                      const char* name,
683
                      addon_context_register_func fn,
684
                      void* priv) {
685
  node_module mod = {
686
    NODE_MODULE_VERSION,
687
    NM_F_LINKED,
688
    nullptr,  // nm_dso_handle
689
    nullptr,  // nm_filename
690
    nullptr,  // nm_register_func
691
    fn,
692
    name,
693
    priv,
694
    nullptr   // nm_link
695
1
  };
696
1
  AddLinkedBinding(env, mod);
697
1
}
698
699
static std::atomic<uint64_t> next_thread_id{0};
700
701
4840
ThreadId AllocateEnvironmentThreadId() {
702
4840
  return ThreadId { next_thread_id++ };
703
}
704
705
426
void DefaultProcessExitHandler(Environment* env, int exit_code) {
706
426
  env->set_can_call_into_js(false);
707
426
  env->stop_sub_worker_contexts();
708
426
  DisposePlatform();
709
426
  exit(exit_code);
710
}
711
712
713
301
void SetProcessExitHandler(Environment* env,
714
                           std::function<void(Environment*, int)>&& handler) {
715
301
  env->set_process_exit_handler(std::move(handler));
716
301
}
717
718
}  // namespace node