GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/env.cc Lines: 459 495 92.7 %
Date: 2019-05-05 22:32:45 Branches: 349 908 38.4 %

Line Branch Exec Source
1
#include "env.h"
2
3
#include "async_wrap.h"
4
#include "node_buffer.h"
5
#include "node_context_data.h"
6
#include "node_errors.h"
7
#include "node_file.h"
8
#include "node_internals.h"
9
#include "node_native_module.h"
10
#include "node_options-inl.h"
11
#include "node_process.h"
12
#include "node_v8_platform-inl.h"
13
#include "node_worker.h"
14
#include "tracing/agent.h"
15
#include "tracing/traced_value.h"
16
#include "v8-profiler.h"
17
18
#include <algorithm>
19
#include <atomic>
20
#include <cstdio>
21
#include <memory>
22
23
namespace node {
24
25
using errors::TryCatchScope;
26
using v8::ArrayBuffer;
27
using v8::Boolean;
28
using v8::Context;
29
using v8::EmbedderGraph;
30
using v8::Function;
31
using v8::FunctionTemplate;
32
using v8::HandleScope;
33
using v8::Integer;
34
using v8::Isolate;
35
using v8::Local;
36
using v8::NewStringType;
37
using v8::Number;
38
using v8::Object;
39
using v8::Private;
40
using v8::SnapshotCreator;
41
using v8::StackTrace;
42
using v8::String;
43
using v8::Symbol;
44
using v8::TracingController;
45
using v8::Undefined;
46
using v8::Value;
47
using worker::Worker;
48
49
int const Environment::kNodeContextTag = 0x6e6f64;
50
void* const Environment::kNodeContextTagPtr = const_cast<void*>(
51
    static_cast<const void*>(&Environment::kNodeContextTag));
52
53
std::vector<size_t> IsolateData::Serialize(SnapshotCreator* creator) {
54
  Isolate* isolate = creator->GetIsolate();
55
  std::vector<size_t> indexes;
56
  HandleScope handle_scope(isolate);
57
  // XXX(joyeecheung): technically speaking, the indexes here should be
58
  // consecutive and we could just return a range instead of an array,
59
  // but that's not part of the V8 API contract so we use an array
60
  // just to be safe.
61
62
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
63
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
64
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
65
#define V(TypeName, PropertyName)                                              \
66
  indexes.push_back(creator->AddData(PropertyName##_.Get(isolate)));
67
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
68
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
69
  PER_ISOLATE_STRING_PROPERTIES(VS)
70
#undef V
71
#undef VY
72
#undef VS
73
#undef VP
74
75
  return indexes;
76
}
77
78
void IsolateData::DeserializeProperties(const std::vector<size_t>* indexes) {
79
  size_t i = 0;
80
  HandleScope handle_scope(isolate_);
81
82
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
83
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
84
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
85
#define V(TypeName, PropertyName)                                              \
86
  do {                                                                         \
87
    MaybeLocal<TypeName> field =                                               \
88
        isolate_->GetDataFromSnapshotOnce<TypeName>((*indexes)[i++]);          \
89
    if (field.IsEmpty()) {                                                     \
90
      fprintf(stderr, "Failed to deserialize " #PropertyName "\n");            \
91
    }                                                                          \
92
    PropertyName##_.Set(isolate_, field.ToLocalChecked());                     \
93
  } while (0);
94
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
95
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
96
  PER_ISOLATE_STRING_PROPERTIES(VS)
97
#undef V
98
#undef VY
99
#undef VS
100
#undef VP
101
}
102
103
4654
void IsolateData::CreateProperties() {
104
  // Create string and private symbol properties as internalized one byte
105
  // strings after the platform is properly initialized.
106
  //
107
  // Internalized because it makes property lookups a little faster and
108
  // because the string is created in the old space straight away.  It's going
109
  // to end up in the old space sooner or later anyway but now it doesn't go
110
  // through v8::Eternal's new space handling first.
111
  //
112
  // One byte because our strings are ASCII and we can safely skip V8's UTF-8
113
  // decoding step.
114
115
4654
  HandleScope handle_scope(isolate_);
116
117
#define V(PropertyName, StringValue)                                           \
118
  PropertyName##_.Set(                                                         \
119
      isolate_,                                                                \
120
      Private::New(isolate_,                                                   \
121
                   String::NewFromOneByte(                                     \
122
                       isolate_,                                               \
123
                       reinterpret_cast<const uint8_t*>(StringValue),          \
124
                       NewStringType::kInternalized,                           \
125
                       sizeof(StringValue) - 1)                                \
126
                       .ToLocalChecked()));
127
79118
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
128
#undef V
129
#define V(PropertyName, StringValue)                                           \
130
  PropertyName##_.Set(                                                         \
131
      isolate_,                                                                \
132
      Symbol::New(isolate_,                                                    \
133
                  String::NewFromOneByte(                                      \
134
                      isolate_,                                                \
135
                      reinterpret_cast<const uint8_t*>(StringValue),           \
136
                      NewStringType::kInternalized,                            \
137
                      sizeof(StringValue) - 1)                                 \
138
                      .ToLocalChecked()));
139
32578
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
140
#undef V
141
#define V(PropertyName, StringValue)                                           \
142
  PropertyName##_.Set(                                                         \
143
      isolate_,                                                                \
144
      String::NewFromOneByte(isolate_,                                         \
145
                             reinterpret_cast<const uint8_t*>(StringValue),    \
146
                             NewStringType::kInternalized,                     \
147
                             sizeof(StringValue) - 1)                          \
148
          .ToLocalChecked());
149
1894178
  PER_ISOLATE_STRING_PROPERTIES(V)
150
#undef V
151
4654
}
152
153
4654
IsolateData::IsolateData(Isolate* isolate,
154
                         uv_loop_t* event_loop,
155
                         MultiIsolatePlatform* platform,
156
                         ArrayBufferAllocator* node_allocator,
157
                         const std::vector<size_t>* indexes)
158
    : isolate_(isolate),
159
      event_loop_(event_loop),
160
4654
      allocator_(isolate->GetArrayBufferAllocator()),
161
      node_allocator_(node_allocator == nullptr ? nullptr
162
4654
                                                : node_allocator->GetImpl()),
163
4654
      uses_node_allocator_(allocator_ == node_allocator_),
164
1014572
      platform_(platform) {
165
4654
  CHECK_NOT_NULL(allocator_);
166
167
  options_.reset(
168
4654
      new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
169
170
4654
  if (indexes == nullptr) {
171
4654
    CreateProperties();
172
  } else {
173
    DeserializeProperties(indexes);
174
  }
175
4654
}
176
177
41
void IsolateData::MemoryInfo(MemoryTracker* tracker) const {
178
#define V(PropertyName, StringValue)                                           \
179
  tracker->TrackField(#PropertyName, PropertyName(isolate()));
180
41
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
181
#undef V
182
183
#define V(PropertyName, StringValue)                                           \
184
  tracker->TrackField(#PropertyName, PropertyName(isolate()));
185
41
  PER_ISOLATE_STRING_PROPERTIES(V)
186
#undef V
187
188
41
  if (node_allocator_ != nullptr) {
189
    tracker->TrackFieldWithSize(
190
41
        "node_allocator", sizeof(*node_allocator_), "NodeArrayBufferAllocator");
191
  } else {
192
    tracker->TrackFieldWithSize(
193
        "allocator", sizeof(*allocator_), "v8::ArrayBuffer::Allocator");
194
  }
195
  tracker->TrackFieldWithSize(
196
41
      "platform", sizeof(*platform_), "MultiIsolatePlatform");
197
  // TODO(joyeecheung): implement MemoryRetainer in the option classes.
198
41
}
199
200
4469
void InitThreadLocalOnce() {
201
4469
  CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));
202
4469
}
203
204
134
void TrackingTraceStateObserver::UpdateTraceCategoryState() {
205
134
  if (!env_->owns_process_state()) {
206
    // Ideally, we’d have a consistent story that treats all threads/Environment
207
    // instances equally here. However, tracing is essentially global, and this
208
    // callback is called from whichever thread calls `StartTracing()` or
209
    // `StopTracing()`. The only way to do this in a threadsafe fashion
210
    // seems to be only tracking this from the main thread, and only allowing
211
    // these state modifications from the main thread.
212
71
    return;
213
  }
214
215
132
  bool async_hooks_enabled = (*(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
216
132
                                 TRACING_CATEGORY_NODE1(async_hooks)))) != 0;
217
218
132
  Isolate* isolate = env_->isolate();
219
132
  HandleScope handle_scope(isolate);
220
132
  Local<Function> cb = env_->trace_category_state_function();
221
132
  if (cb.IsEmpty())
222
67
    return;
223
130
  TryCatchScope try_catch(env_);
224
65
  try_catch.SetVerbose(true);
225
130
  Local<Value> args[] = {Boolean::New(isolate, async_hooks_enabled)};
226
260
  cb->Call(env_->context(), Undefined(isolate), arraysize(args), args)
227
195
      .ToLocalChecked();
228
}
229
230
static std::atomic<uint64_t> next_thread_id{0};
231
232
4655
uint64_t Environment::AllocateThreadId() {
233
4655
  return next_thread_id++;
234
}
235
236
4651
Environment::Environment(IsolateData* isolate_data,
237
                         Local<Context> context,
238
                         Flags flags,
239
                         uint64_t thread_id)
240
4651
    : isolate_(context->GetIsolate()),
241
      isolate_data_(isolate_data),
242
      immediate_info_(context->GetIsolate()),
243
      tick_info_(context->GetIsolate()),
244
4651
      timer_base_(uv_now(isolate_data->event_loop())),
245
      should_abort_on_uncaught_toggle_(isolate_, 1),
246
      stream_base_state_(isolate_, StreamBase::kNumStreamBaseStateFields),
247
      flags_(flags),
248
      thread_id_(thread_id == kNoThreadId ? AllocateThreadId() : thread_id),
249
      fs_stats_field_array_(isolate_, kFsStatsBufferLength),
250
      fs_stats_field_bigint_array_(isolate_, kFsStatsBufferLength),
251
334872
      context_(context->GetIsolate(), context) {
252
  // We'll be creating new objects so make sure we've entered the context.
253
4651
  HandleScope handle_scope(isolate());
254
  Context::Scope context_scope(context);
255
  {
256
4651
    Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
257
9302
    templ->InstanceTemplate()->SetInternalFieldCount(1);
258
    Local<Object> obj =
259
9302
        templ->GetFunction(context).ToLocalChecked()->NewInstance(
260
13953
            context).ToLocalChecked();
261
4651
    obj->SetAlignedPointerInInternalField(0, this);
262
4651
    set_as_callback_data(obj);
263
4651
    set_as_callback_data_template(templ);
264
  }
265
266
4651
  set_env_vars(per_process::system_environment);
267
268
  // We create new copies of the per-Environment option sets, so that it is
269
  // easier to modify them after Environment creation. The defaults are
270
  // part of the per-Isolate option set, for which in turn the defaults are
271
  // part of the per-process option set.
272
4651
  options_.reset(new EnvironmentOptions(*isolate_data->options()->per_env));
273
4651
  inspector_host_port_.reset(new HostPort(options_->debug_options().host_port));
274
275
#if HAVE_INSPECTOR
276
  // We can only create the inspector agent after having cloned the options.
277
4651
  inspector_agent_ = std::make_unique<inspector::Agent>(this);
278
#endif
279
280
4651
  AssignToContext(context, ContextInfo(""));
281
282
4651
  if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) {
283
4651
    trace_state_observer_ = std::make_unique<TrackingTraceStateObserver>(this);
284
4651
    TracingController* tracing_controller = writer->GetTracingController();
285
4651
    tracing_controller->AddTraceStateObserver(trace_state_observer_.get());
286
  }
287
288
4651
  destroy_async_id_list_.reserve(512);
289
  BeforeExit(
290
12839
      [](void* arg) {
291
4094
        Environment* env = static_cast<Environment*>(arg);
292
4094
        if (!env->destroy_async_id_list()->empty())
293
143
          AsyncWrap::DestroyAsyncIdsCallback(env, nullptr);
294
12839
      },
295
4651
      this);
296
297
9302
  performance_state_ =
298
9302
      std::make_unique<performance::performance_state>(isolate());
299
  performance_state_->Mark(
300
4651
      performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
301
  performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
302
4651
                           per_process::node_start_time);
303
  performance_state_->Mark(
304
      performance::NODE_PERFORMANCE_MILESTONE_V8_START,
305
4651
      performance::performance_v8_start);
306
307
  // By default, always abort when --abort-on-uncaught-exception was passed.
308
4651
  should_abort_on_uncaught_toggle_[0] = 1;
309
310
9302
  std::string debug_cats;
311
4651
  credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats, this);
312
4651
  set_debug_categories(debug_cats, true);
313
314
  isolate()->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
315
4651
      BuildEmbedderGraph, this);
316
4651
  if (options_->no_force_async_hooks_checks) {
317
1
    async_hooks_.no_force_checks();
318
4651
  }
319
4651
}
320
321
43187
CompileFnEntry::CompileFnEntry(Environment* env, uint32_t id)
322
43187
    : env(env), id(id) {
323
43187
  env->compile_fn_entries.insert(this);
324
43187
}
325
326
303241
Environment::~Environment() {
327
  isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
328
4271
      BuildEmbedderGraph, this);
329
330
  // Make sure there are no re-used libuv wrapper objects.
331
  // CleanupHandles() should have removed all of them.
332
4271
  CHECK(file_handle_read_wrap_freelist_.empty());
333
334
  // dispose the Persistent references to the compileFunction
335
  // wrappers used in the dynamic import callback
336
34953
  for (auto& entry : compile_fn_entries) {
337
30682
    delete entry;
338
  }
339
340
4271
  HandleScope handle_scope(isolate());
341
342
#if HAVE_INSPECTOR
343
  // Destroy inspector agent before erasing the context. The inspector
344
  // destructor depends on the context still being accessible.
345
4271
  inspector_agent_.reset();
346
#endif
347
348
  context()->SetAlignedPointerInEmbedderData(
349
8542
      ContextEmbedderIndex::kEnvironment, nullptr);
350
351
4271
  if (trace_state_observer_) {
352
4271
    tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
353
4271
    CHECK_NOT_NULL(writer);
354
4271
    TracingController* tracing_controller = writer->GetTracingController();
355
4271
    tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get());
356
  }
357
358
4271
  delete[] heap_statistics_buffer_;
359
4271
  delete[] heap_space_statistics_buffer_;
360
4271
  delete[] http_parser_buffer_;
361
362

8542
  TRACE_EVENT_NESTABLE_ASYNC_END0(
363
    TRACING_CATEGORY_NODE1(environment), "Environment", this);
364
365
  // Do not unload addons on the main thread. Some addons need to retain memory
366
  // beyond the Environment's lifetime, and unloading them early would break
367
  // them; with Worker threads, we have the opportunity to be stricter.
368
  // Also, since the main thread usually stops just before the process exits,
369
  // this is far less relevant here.
370
4271
  if (!is_main_thread()) {
371
    // Dereference all addons that were loaded into this environment.
372
189
    for (binding::DLib& addon : loaded_addons_) {
373
7
      addon.Close();
374
    }
375
4271
  }
376
8542
}
377
378
4651
void Environment::InitializeLibuv(bool start_profiler_idle_notifier) {
379
4651
  HandleScope handle_scope(isolate());
380
4651
  Context::Scope context_scope(context());
381
382
4651
  CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
383
4651
  uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
384
385
4651
  uv_check_init(event_loop(), immediate_check_handle());
386
4651
  uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
387
388
4651
  uv_idle_init(event_loop(), immediate_idle_handle());
389
390
4651
  uv_check_start(immediate_check_handle(), CheckImmediate);
391
392
  // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
393
  // but not all samples are created equal; mark the wall clock time spent in
394
  // epoll_wait() and friends so profiling tools can filter it out.  The samples
395
  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
396
  // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
397
  // probably fortify in the API contract, namely that the last started prepare
398
  // or check watcher runs first.  It's not 100% foolproof; if an add-on starts
399
  // a prepare or check watcher after us, any samples attributed to its callback
400
  // will be recorded with state=IDLE.
401
4651
  uv_prepare_init(event_loop(), &idle_prepare_handle_);
402
4651
  uv_check_init(event_loop(), &idle_check_handle_);
403
4651
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
404
4651
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
405
406
  thread_stopper()->Install(
407
4711
    this, static_cast<void*>(this), [](uv_async_t* handle) {
408
30
      Environment* env = static_cast<Environment*>(handle->data);
409
30
      uv_stop(env->event_loop());
410
9362
    });
411
4651
  thread_stopper()->set_stopped(false);
412
4651
  uv_unref(reinterpret_cast<uv_handle_t*>(thread_stopper()->GetHandle()));
413
414
  // Register clean-up cb to be called to clean up the handles
415
  // when the environment is freed, note that they are not cleaned in
416
  // the one environment per process setup, but will be called in
417
  // FreeEnvironment.
418
4651
  RegisterHandleCleanups();
419
420
4651
  if (start_profiler_idle_notifier) {
421
3
    StartProfilerIdleNotifier();
422
  }
423
424
  static uv_once_t init_once = UV_ONCE_INIT;
425
4651
  uv_once(&init_once, InitThreadLocalOnce);
426
9302
  uv_key_set(&thread_local_env, this);
427
4651
}
428
429
63
void Environment::ExitEnv() {
430
63
  set_can_call_into_js(false);
431
63
  thread_stopper()->Stop();
432
63
  isolate_->TerminateExecution();
433
63
}
434
435
4651
MaybeLocal<Object> Environment::ProcessCliArgs(
436
    const std::vector<std::string>& args,
437
    const std::vector<std::string>& exec_args) {
438
4651
  argv_ = args;
439
4651
  exec_argv_ = exec_args;
440
441
9302
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
442
4651
          TRACING_CATEGORY_NODE1(environment)) != 0) {
443
8
    auto traced_value = tracing::TracedValue::Create();
444
8
    traced_value->BeginArray("args");
445
8
    for (const std::string& arg : args) traced_value->AppendString(arg);
446
8
    traced_value->EndArray();
447
8
    traced_value->BeginArray("exec_args");
448
8
    for (const std::string& arg : exec_args) traced_value->AppendString(arg);
449
8
    traced_value->EndArray();
450

16
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
451
                                      "Environment",
452
                                      this,
453
                                      "args",
454
8
                                      std::move(traced_value));
455
  }
456
457
  Local<Object> process_object =
458
      node::CreateProcessObject(this, args, exec_args)
459
9302
          .FromMaybe(Local<Object>());
460
4651
  set_process_object(process_object);
461
4651
  return process_object;
462
}
463
464
4651
void Environment::RegisterHandleCleanups() {
465
  HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
466
47361
                                        void* arg) {
467
21355
    handle->data = env;
468
469
21355
    env->CloseHandle(handle, [](uv_handle_t* handle) {
470
#ifdef DEBUG
471
      memset(handle, 0xab, uv_handle_size(handle->type));
472
#endif
473
42710
    });
474
52012
  };
475
476
  RegisterHandleCleanup(
477
4651
      reinterpret_cast<uv_handle_t*>(timer_handle()),
478
      close_and_finish,
479
4651
      nullptr);
480
  RegisterHandleCleanup(
481
4651
      reinterpret_cast<uv_handle_t*>(immediate_check_handle()),
482
      close_and_finish,
483
4651
      nullptr);
484
  RegisterHandleCleanup(
485
4651
      reinterpret_cast<uv_handle_t*>(immediate_idle_handle()),
486
      close_and_finish,
487
4651
      nullptr);
488
  RegisterHandleCleanup(
489
      reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_),
490
      close_and_finish,
491
4651
      nullptr);
492
  RegisterHandleCleanup(
493
      reinterpret_cast<uv_handle_t*>(&idle_check_handle_),
494
      close_and_finish,
495
4651
      nullptr);
496
4651
}
497
498
6482
void Environment::CleanupHandles() {
499
6516
  for (ReqWrapBase* request : req_wrap_queue_)
500
34
    request->Cancel();
501
502
8833
  for (HandleWrap* handle : handle_wrap_queue_)
503
4702
    handle->Close();
504
505
27837
  for (HandleCleanup& hc : handle_cleanup_queue_)
506
21355
    hc.cb_(this, hc.handle_, hc.arg_);
507
6482
  handle_cleanup_queue_.clear();
508
509

34490
  while (handle_cleanup_waiting_ != 0 ||
510

17245
         request_waiting_ != 0 ||
511
6483
         !handle_wrap_queue_.IsEmpty()) {
512
4280
    uv_run(event_loop(), UV_RUN_ONCE);
513
  }
514
515
6482
  file_handle_read_wrap_freelist_.clear();
516
6482
}
517
518
3
void Environment::StartProfilerIdleNotifier() {
519
3
  if (profiler_idle_notifier_started_)
520
3
    return;
521
522
3
  profiler_idle_notifier_started_ = true;
523
524
3929
  uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
525
1963
    Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
526
1963
    env->isolate()->SetIdle(true);
527
3932
  });
528
529
3927
  uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
530
1962
    Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
531
1962
    env->isolate()->SetIdle(false);
532
3930
  });
533
}
534
535
void Environment::StopProfilerIdleNotifier() {
536
  profiler_idle_notifier_started_ = false;
537
  uv_prepare_stop(&idle_prepare_handle_);
538
  uv_check_stop(&idle_check_handle_);
539
}
540
541
597725
void Environment::PrintSyncTrace() const {
542
1195450
  if (!options_->trace_sync_io) return;
543
544
32
  HandleScope handle_scope(isolate());
545
546
  fprintf(
547
32
      stderr, "(node:%d) WARNING: Detected use of sync API\n", uv_os_getpid());
548
  PrintStackTrace(
549
      isolate(),
550
32
      StackTrace::CurrentStackTrace(isolate(), 10, StackTrace::kDetailed));
551
}
552
553
4453
void Environment::RunCleanup() {
554
4453
  started_cleanup_ = true;
555
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
556
4453
                              "RunCleanup", this);
557
4453
  thread_stopper()->Uninstall();
558
4453
  CleanupHandles();
559
560
10935
  while (!cleanup_hooks_.empty()) {
561
    // Copy into a vector, since we can't sort an unordered_set in-place.
562
    std::vector<CleanupHookCallback> callbacks(
563
2029
        cleanup_hooks_.begin(), cleanup_hooks_.end());
564
    // We can't erase the copied elements from `cleanup_hooks_` yet, because we
565
    // need to be able to check whether they were un-scheduled by another hook.
566
567
    std::sort(callbacks.begin(), callbacks.end(),
568
477868
              [](const CleanupHookCallback& a, const CleanupHookCallback& b) {
569
      // Sort in descending order so that the most recently inserted callbacks
570
      // are run first.
571
477868
      return a.insertion_order_counter_ > b.insertion_order_counter_;
572
479897
    });
573
574
39379
    for (const CleanupHookCallback& cb : callbacks) {
575
37350
      if (cleanup_hooks_.count(cb) == 0) {
576
        // This hook was removed from the `cleanup_hooks_` set during another
577
        // hook that was run earlier. Nothing to do here.
578
        continue;
579
      }
580
581
37350
      cb.fn_(cb.arg_);
582
37350
      cleanup_hooks_.erase(cb);
583
    }
584
2029
    CleanupHandles();
585
6482
  }
586
4453
}
587
588
4107
void Environment::RunBeforeExitCallbacks() {
589
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
590
4107
                              "BeforeExit", this);
591
8201
  for (ExitCallback before_exit : before_exit_functions_) {
592
4094
    before_exit.cb_(before_exit.arg_);
593
  }
594
4107
  before_exit_functions_.clear();
595
4107
}
596
597
4651
void Environment::BeforeExit(void (*cb)(void* arg), void* arg) {
598
4651
  before_exit_functions_.push_back(ExitCallback{cb, arg});
599
4651
}
600
601
4271
void Environment::RunAtExitCallbacks() {
602
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
603
4271
                              "AtExit", this);
604
4278
  for (ExitCallback at_exit : at_exit_functions_) {
605
7
    at_exit.cb_(at_exit.arg_);
606
  }
607
4271
  at_exit_functions_.clear();
608
4271
}
609
610
7
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
611
7
  at_exit_functions_.push_back(ExitCallback{cb, arg});
612
7
}
613
614
53905
void Environment::RunAndClearNativeImmediates() {
615
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
616
53905
                              "RunAndClearNativeImmediates", this);
617
53905
  size_t count = native_immediate_callbacks_.size();
618
53905
  if (count > 0) {
619
46318
    size_t ref_count = 0;
620
46318
    std::vector<NativeImmediateCallback> list;
621
46318
    native_immediate_callbacks_.swap(list);
622
46319
    auto drain_list = [&]() {
623
46319
      TryCatchScope try_catch(this);
624
96967
      for (auto it = list.begin(); it != list.end(); ++it) {
625
50650
        DebugSealHandleScope seal_handle_scope(isolate());
626
50650
        it->cb_(this, it->data_);
627
50649
        if (it->refed_)
628
28615
          ref_count++;
629
50649
        if (UNLIKELY(try_catch.HasCaught())) {
630
1
          if (!try_catch.HasTerminated())
631
            FatalException(isolate(), try_catch);
632
633
          // Bail out, remove the already executed callbacks from list
634
          // and set up a new TryCatch for the other pending callbacks.
635
1
          std::move_backward(it, list.end(), list.begin() + (list.end() - it));
636
1
          list.resize(list.end() - it);
637
1
          return true;
638
        }
639
      }
640
46317
      return false;
641
92636
    };
642
46318
    while (drain_list()) {}
643
644
    DCHECK_GE(immediate_info()->count(), count);
645
46317
    immediate_info()->count_dec(count);
646
46317
    immediate_info()->ref_count_dec(ref_count);
647
53904
  }
648
53904
}
649
650
651
4401
void Environment::ScheduleTimer(int64_t duration_ms) {
652
8802
  if (started_cleanup_) return;
653
4401
  uv_timer_start(timer_handle(), RunTimers, duration_ms, 0);
654
}
655
656
1301
void Environment::ToggleTimerRef(bool ref) {
657
2602
  if (started_cleanup_) return;
658
659
1301
  if (ref) {
660
982
    uv_ref(reinterpret_cast<uv_handle_t*>(timer_handle()));
661
  } else {
662
319
    uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
663
  }
664
}
665
666
2851
void Environment::RunTimers(uv_timer_t* handle) {
667
2851
  Environment* env = Environment::from_timer_handle(handle);
668
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
669
2851
                              "RunTimers", env);
670
671
2851
  if (!env->can_call_into_js())
672
    return;
673
674
5674
  HandleScope handle_scope(env->isolate());
675
5674
  Context::Scope context_scope(env->context());
676
677
2851
  Local<Object> process = env->process_object();
678
5674
  InternalCallbackScope scope(env, process, {0, 0});
679
680
2851
  Local<Function> cb = env->timers_callback_function();
681
  MaybeLocal<Value> ret;
682
2851
  Local<Value> arg = env->GetNow();
683
  // This code will loop until all currently due timers will process. It is
684
  // impossible for us to end up in an infinite loop due to how the JS-side
685
  // is structured.
686
2855
  do {
687
2880
    TryCatchScope try_catch(env);
688
2880
    try_catch.SetVerbose(true);
689
5760
    ret = cb->Call(env->context(), process, 1, &arg);
690

2855
  } while (ret.IsEmpty() && env->can_call_into_js());
691
692
  // NOTE(apapirovski): If it ever becomes possible that `call_into_js` above
693
  // is reset back to `true` after being previously set to `false` then this
694
  // code becomes invalid and needs to be rewritten. Otherwise catastrophic
695
  // timers corruption will occur and all timers behaviour will become
696
  // entirely unpredictable.
697
2826
  if (ret.IsEmpty())
698
3
    return;
699
700
  // To allow for less JS-C++ boundary crossing, the value returned from JS
701
  // serves a few purposes:
702
  // 1. If it's 0, no more timers exist and the handle should be unrefed
703
  // 2. If it's > 0, the value represents the next timer's expiry and there
704
  //    is at least one timer remaining that is refed.
705
  // 3. If it's < 0, the absolute value represents the next timer's expiry
706
  //    and there are no timers that are refed.
707
  int64_t expiry_ms =
708
11292
      ret.ToLocalChecked()->IntegerValue(env->context()).FromJust();
709
710
2823
  uv_handle_t* h = reinterpret_cast<uv_handle_t*>(handle);
711
712
2823
  if (expiry_ms != 0) {
713
    int64_t duration_ms =
714
2312
        llabs(expiry_ms) - (uv_now(env->event_loop()) - env->timer_base());
715
716
2312
    env->ScheduleTimer(duration_ms > 0 ? duration_ms : 1);
717
718
2312
    if (expiry_ms > 0)
719
1856
      uv_ref(h);
720
    else
721
456
      uv_unref(h);
722
  } else {
723
511
    uv_unref(h);
724
2823
  }
725
}
726
727
728
399724
void Environment::CheckImmediate(uv_check_t* handle) {
729
399724
  Environment* env = Environment::from_immediate_check_handle(handle);
730
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
731
399726
                              "CheckImmediate", env);
732
733
399725
  if (env->immediate_info()->count() == 0)
734
345822
    return;
735
736
107800
  HandleScope scope(env->isolate());
737
107800
  Context::Scope context_scope(env->context());
738
739
53905
  env->RunAndClearNativeImmediates();
740
741
53904
  if (!env->can_call_into_js())
742
3
    return;
743
744
54416
  do {
745
    MakeCallback(env->isolate(),
746
                 env->process_object(),
747
                 env->immediate_callback_function(),
748
                 0,
749
                 nullptr,
750
108838
                 {0, 0}).ToLocalChecked();
751

54416
  } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
752
753
53895
  if (env->immediate_info()->ref_count() == 0)
754
80877
    env->ToggleImmediateRef(false);
755
}
756
757
76708
void Environment::ToggleImmediateRef(bool ref) {
758
153416
  if (started_cleanup_) return;
759
760
76707
  if (ref) {
761
    // Idle handle is needed only to stop the event loop from blocking in poll.
762
155166
    uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
763
  } else {
764
26996
    uv_idle_stop(immediate_idle_handle());
765
  }
766
}
767
768
769
325279
Local<Value> Environment::GetNow() {
770
325279
  uv_update_time(event_loop());
771
325279
  uint64_t now = uv_now(event_loop());
772
325279
  CHECK_GE(now, timer_base());
773
325279
  now -= timer_base();
774
325279
  if (now <= 0xffffffff)
775
650558
    return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
776
  else
777
    return Number::New(isolate(), static_cast<double>(now));
778
}
779
780
4651
void Environment::set_debug_categories(const std::string& cats, bool enabled) {
781
4651
  std::string debug_categories = cats;
782
4651
  while (!debug_categories.empty()) {
783
13
    std::string::size_type comma_pos = debug_categories.find(',');
784
13
    std::string wanted = ToLower(debug_categories.substr(0, comma_pos));
785
786
#define V(name)                                                          \
787
    {                                                                    \
788
      static const std::string available_category = ToLower(#name);      \
789
      if (available_category.find(wanted) != std::string::npos)          \
790
        set_debug_enabled(DebugCategory::name, enabled);                 \
791
    }
792
793



































































13
    DEBUG_CATEGORY_NAMES(V)
794
#undef V
795
796
13
    if (comma_pos == std::string::npos)
797
13
      break;
798
    // Use everything after the `,` as the list for the next iteration.
799
    debug_categories = debug_categories.substr(comma_pos + 1);
800
4651
  }
801
4651
}
802
803
28
void CollectExceptionInfo(Environment* env,
804
                          Local<Object> obj,
805
                          int errorno,
806
                          const char* err_string,
807
                          const char* syscall,
808
                          const char* message,
809
                          const char* path,
810
                          const char* dest) {
811
  obj->Set(env->context(),
812
           env->errno_string(),
813
140
           Integer::New(env->isolate(), errorno)).Check();
814
815
  obj->Set(env->context(), env->code_string(),
816
140
           OneByteString(env->isolate(), err_string)).Check();
817
818
28
  if (message != nullptr) {
819
    obj->Set(env->context(), env->message_string(),
820
140
             OneByteString(env->isolate(), message)).Check();
821
  }
822
823
  Local<Value> path_buffer;
824
28
  if (path != nullptr) {
825
    path_buffer =
826
      Buffer::Copy(env->isolate(), path, strlen(path)).ToLocalChecked();
827
    obj->Set(env->context(), env->path_string(), path_buffer).Check();
828
  }
829
830
  Local<Value> dest_buffer;
831
28
  if (dest != nullptr) {
832
    dest_buffer =
833
      Buffer::Copy(env->isolate(), dest, strlen(dest)).ToLocalChecked();
834
    obj->Set(env->context(), env->dest_string(), dest_buffer).Check();
835
  }
836
837
28
  if (syscall != nullptr) {
838
    obj->Set(env->context(), env->syscall_string(),
839
140
             OneByteString(env->isolate(), syscall)).Check();
840
  }
841
28
}
842
843
28
void Environment::CollectUVExceptionInfo(Local<Value> object,
844
                                         int errorno,
845
                                         const char* syscall,
846
                                         const char* message,
847
                                         const char* path,
848
                                         const char* dest) {
849

28
  if (!object->IsObject() || errorno == 0)
850
28
    return;
851
852
28
  Local<Object> obj = object.As<Object>();
853
28
  const char* err_string = uv_err_name(errorno);
854
855

28
  if (message == nullptr || message[0] == '\0') {
856
28
    message = uv_strerror(errorno);
857
  }
858
859
  node::CollectExceptionInfo(this, obj, errorno, err_string,
860
28
                             syscall, message, path, dest);
861
}
862
863
41
void ImmediateInfo::MemoryInfo(MemoryTracker* tracker) const {
864
41
  tracker->TrackField("fields", fields_);
865
41
}
866
867
41
void TickInfo::MemoryInfo(MemoryTracker* tracker) const {
868
41
  tracker->TrackField("fields", fields_);
869
41
}
870
871
41
void AsyncHooks::MemoryInfo(MemoryTracker* tracker) const {
872
41
  tracker->TrackField("providers", providers_);
873
41
  tracker->TrackField("async_ids_stack", async_ids_stack_);
874
41
  tracker->TrackField("fields", fields_);
875
41
  tracker->TrackField("async_id_fields", async_id_fields_);
876
41
}
877
878
8
void AsyncHooks::grow_async_ids_stack() {
879
8
  async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
880
881
8
  env()->async_hooks_binding()->Set(
882
      env()->context(),
883
      env()->async_ids_stack_string(),
884
48
      async_ids_stack_.GetJSArray()).Check();
885
8
}
886
887
uv_key_t Environment::thread_local_env = {};
888
889
400
void Environment::Exit(int exit_code) {
890
400
  if (is_main_thread()) {
891
377
    stop_sub_worker_contexts();
892
376
    DisposePlatform();
893
376
    exit(exit_code);
894
  } else {
895
23
    worker_context_->Exit(exit_code);
896
  }
897
23
}
898
899
4648
void Environment::stop_sub_worker_contexts() {
900
9318
  while (!sub_worker_contexts_.empty()) {
901
23
    Worker* w = *sub_worker_contexts_.begin();
902
23
    remove_sub_worker_context(w);
903
23
    w->Exit(1);
904
23
    w->JoinThread();
905
  }
906
4647
}
907
908
#if HAVE_INSPECTOR
909
910
#endif  // HAVE_INSPECTOR
911
912
130
void MemoryTracker::TrackField(const char* edge_name,
913
                               const CleanupHookCallback& value,
914
                               const char* node_name) {
915
130
  v8::HandleScope handle_scope(isolate_);
916
  // Here, we utilize the fact that CleanupHookCallback instances
917
  // are all unique and won't be tracked twice in one BuildEmbedderGraph
918
  // callback.
919
  MemoryRetainerNode* n =
920
130
      PushNode("CleanupHookCallback", sizeof(value), edge_name);
921
  // TODO(joyeecheung): at the moment only arguments of type BaseObject will be
922
  // identified and tracked here (based on their deleters),
923
  // but we may convert and track other known types here.
924
130
  BaseObject* obj = value.GetBaseObject();
925
130
  if (obj != nullptr) {
926
129
    this->TrackField("arg", obj);
927
  }
928
130
  CHECK_EQ(CurrentNode(), n);
929
130
  CHECK_NE(n->size_, 0);
930
130
  PopNode();
931
130
}
932
933
41
void Environment::BuildEmbedderGraph(Isolate* isolate,
934
                                     EmbedderGraph* graph,
935
                                     void* data) {
936
41
  MemoryTracker tracker(isolate, graph);
937
41
  Environment* env = static_cast<Environment*>(data);
938
41
  tracker.Track(env);
939
41
}
940
941
41
inline size_t Environment::SelfSize() const {
942
41
  size_t size = sizeof(*this);
943
  // Remove non pointer fields that will be tracked in MemoryInfo()
944
  // TODO(joyeecheung): refactor the MemoryTracker interface so
945
  // this can be done for common types within the Track* calls automatically
946
  // if a certain scope is entered.
947
41
  size -= sizeof(thread_stopper_);
948
41
  size -= sizeof(async_hooks_);
949
41
  size -= sizeof(tick_info_);
950
41
  size -= sizeof(immediate_info_);
951
41
  return size;
952
}
953
954
41
void Environment::MemoryInfo(MemoryTracker* tracker) const {
955
  // Iteratable STLs have their own sizes subtracted from the parent
956
  // by default.
957
41
  tracker->TrackField("isolate_data", isolate_data_);
958
41
  tracker->TrackField("native_modules_with_cache", native_modules_with_cache);
959
  tracker->TrackField("native_modules_without_cache",
960
41
                      native_modules_without_cache);
961
41
  tracker->TrackField("destroy_async_id_list", destroy_async_id_list_);
962
41
  tracker->TrackField("exec_argv", exec_argv_);
963
  tracker->TrackField("should_abort_on_uncaught_toggle",
964
41
                      should_abort_on_uncaught_toggle_);
965
41
  tracker->TrackField("stream_base_state", stream_base_state_);
966
41
  tracker->TrackField("fs_stats_field_array", fs_stats_field_array_);
967
  tracker->TrackField("fs_stats_field_bigint_array",
968
41
                      fs_stats_field_bigint_array_);
969
41
  tracker->TrackField("thread_stopper", thread_stopper_);
970
41
  tracker->TrackField("cleanup_hooks", cleanup_hooks_);
971
41
  tracker->TrackField("async_hooks", async_hooks_);
972
41
  tracker->TrackField("immediate_info", immediate_info_);
973
41
  tracker->TrackField("tick_info", tick_info_);
974
975
#define V(PropertyName, TypeName)                                              \
976
  tracker->TrackField(#PropertyName, PropertyName());
977
41
  ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
978
#undef V
979
980
  // FIXME(joyeecheung): track other fields in Environment.
981
  // Currently MemoryTracker is unable to track these
982
  // correctly:
983
  // - Internal types that do not implement MemoryRetainer yet
984
  // - STL containers with MemoryRetainer* inside
985
  // - STL containers with numeric types inside that should not have their
986
  //   nodes elided e.g. numeric keys in maps.
987
  // We also need to make sure that when we add a non-pointer field as its own
988
  // node, we shift its sizeof() size out of the Environment node.
989
41
}
990
991
360523
char* Environment::Reallocate(char* data, size_t old_size, size_t size) {
992
360523
  if (old_size == size) return data;
993
  // If we know that the allocator is our ArrayBufferAllocator, we can let
994
  // if reallocate directly.
995
327117
  if (isolate_data()->uses_node_allocator()) {
996
    return static_cast<char*>(
997
327117
        isolate_data()->node_allocator()->Reallocate(data, old_size, size));
998
  }
999
  // Generic allocators do not provide a reallocation method; we need to
1000
  // allocate a new chunk of memory and copy the data over.
1001
  char* new_data = AllocateUnchecked(size);
1002
  if (new_data == nullptr) return nullptr;
1003
  memcpy(new_data, data, std::min(size, old_size));
1004
  if (size > old_size)
1005
    memset(new_data + old_size, 0, size - old_size);
1006
  Free(data, old_size);
1007
  return new_data;
1008
}
1009
1010
4836
void AsyncRequest::Install(Environment* env, void* data, uv_async_cb target) {
1011
4836
  CHECK_NULL(async_);
1012
4836
  env_ = env;
1013
4836
  async_ = new uv_async_t;
1014
4836
  async_->data = data;
1015
4836
  CHECK_EQ(uv_async_init(env_->event_loop(), async_, target), 0);
1016
4836
}
1017
1018
4634
void AsyncRequest::Uninstall() {
1019
4634
  if (async_ != nullptr) {
1020
8884
    env_->CloseHandle(async_, [](uv_async_t* async) { delete async; });
1021
4452
    async_ = nullptr;
1022
  }
1023
4634
}
1024
1025
248
void AsyncRequest::Stop() {
1026
248
  set_stopped(true);
1027
248
  if (async_ != nullptr) uv_async_send(async_);
1028
248
}
1029
1030
4655
uv_async_t* AsyncRequest::GetHandle() {
1031
4655
  return async_;
1032
}
1033
1034
45
void AsyncRequest::MemoryInfo(MemoryTracker* tracker) const {
1035
45
  if (async_ != nullptr) tracker->TrackField("async_request", *async_);
1036
45
}
1037
1038
8866
AsyncRequest::~AsyncRequest() {
1039
4433
  CHECK_NULL(async_);
1040
4433
}
1041
1042
// Not really any better place than env.cc at this moment.
1043
37273
void BaseObject::DeleteMe(void* data) {
1044
37273
  BaseObject* self = static_cast<BaseObject*>(data);
1045
37273
  delete self;
1046
37273
}
1047
1048
129
Local<Object> BaseObject::WrappedObject() const {
1049
129
  return object();
1050
}
1051
1052
}  // namespace node