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: 332 372 89.2 %
Date: 2020-09-06 22:14:11 Branches: 108 176 61.4 %

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::SealHandleScope;
31
using v8::String;
32
using v8::Value;
33
34
54
static bool AllowWasmCodeGenerationCallback(Local<Context> context,
35
                                            Local<String>) {
36
  Local<Value> wasm_code_gen =
37
108
      context->GetEmbedderData(ContextEmbedderIndex::kAllowWasmCodeGeneration);
38

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

68
         (env->is_main_thread() || !env->is_stopping()) &&
46
63
         env->abort_on_uncaught_exception() &&
47

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

75726
  if (try_catch.HasCaught() && !try_catch.HasTerminated()) {
75
2
    try_catch.ReThrow();
76
  }
77
75726
  return result;
78
}
79
80
421410
void* NodeArrayBufferAllocator::Allocate(size_t size) {
81
  void* ret;
82

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

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

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

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

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

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

4655
  if (!primordials->SetPrototype(context, Null(isolate)).FromJust() ||
619

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

13419
}  // namespace node