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: 480 505 95.0 %
Date: 2019-07-27 22:37:30 Branches: 574 924 62.1 %

Line Branch Exec Source
1
#include "env.h"
2
3
#include "async_wrap.h"
4
#include "memory_tracker-inl.h"
5
#include "node_buffer.h"
6
#include "node_context_data.h"
7
#include "node_errors.h"
8
#include "node_file.h"
9
#include "node_internals.h"
10
#include "node_native_module.h"
11
#include "node_options-inl.h"
12
#include "node_process.h"
13
#include "node_v8_platform-inl.h"
14
#include "node_worker.h"
15
#include "tracing/agent.h"
16
#include "tracing/traced_value.h"
17
#include "util-inl.h"
18
#include "v8-profiler.h"
19
20
#include <algorithm>
21
#include <atomic>
22
#include <cstdio>
23
#include <memory>
24
25
namespace node {
26
27
using errors::TryCatchScope;
28
using v8::ArrayBuffer;
29
using v8::Boolean;
30
using v8::Context;
31
using v8::EmbedderGraph;
32
using v8::Function;
33
using v8::FunctionTemplate;
34
using v8::HandleScope;
35
using v8::Integer;
36
using v8::Isolate;
37
using v8::Local;
38
using v8::NewStringType;
39
using v8::Number;
40
using v8::Object;
41
using v8::Private;
42
using v8::SnapshotCreator;
43
using v8::StackTrace;
44
using v8::String;
45
using v8::Symbol;
46
using v8::TracingController;
47
using v8::Undefined;
48
using v8::Value;
49
using worker::Worker;
50
51
int const Environment::kNodeContextTag = 0x6e6f64;
52
void* const Environment::kNodeContextTagPtr = const_cast<void*>(
53
    static_cast<const void*>(&Environment::kNodeContextTag));
54
55
1
std::vector<size_t> IsolateData::Serialize(SnapshotCreator* creator) {
56
1
  Isolate* isolate = creator->GetIsolate();
57
1
  std::vector<size_t> indexes;
58
2
  HandleScope handle_scope(isolate);
59
  // XXX(joyeecheung): technically speaking, the indexes here should be
60
  // consecutive and we could just return a range instead of an array,
61
  // but that's not part of the V8 API contract so we use an array
62
  // just to be safe.
63
64
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
65
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
66
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
67
#define V(TypeName, PropertyName)                                              \
68
  indexes.push_back(creator->AddData(PropertyName##_.Get(isolate)));
69
8
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
70
5
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
71
207
  PER_ISOLATE_STRING_PROPERTIES(VS)
72
#undef V
73
#undef VY
74
#undef VS
75
#undef VP
76
77
2
  return indexes;
78
}
79
80
4771
void IsolateData::DeserializeProperties(const std::vector<size_t>* indexes) {
81
4771
  size_t i = 0;
82
4771
  HandleScope handle_scope(isolate_);
83
84
#define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
85
#define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
86
#define VS(PropertyName, StringValue) V(v8::String, PropertyName)
87
#define V(TypeName, PropertyName)                                              \
88
  do {                                                                         \
89
    MaybeLocal<TypeName> field =                                               \
90
        isolate_->GetDataFromSnapshotOnce<TypeName>((*indexes)[i++]);          \
91
    if (field.IsEmpty()) {                                                     \
92
      fprintf(stderr, "Failed to deserialize " #PropertyName "\n");            \
93
    }                                                                          \
94
    PropertyName##_.Set(isolate_, field.ToLocalChecked());                     \
95
  } while (0);
96



133588
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
97


76336
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
98







































































































3936075
  PER_ISOLATE_STRING_PROPERTIES(VS)
99
#undef V
100
#undef VY
101
#undef VS
102
#undef VP
103
4771
}
104
105
207
void IsolateData::CreateProperties() {
106
  // Create string and private symbol properties as internalized one byte
107
  // strings after the platform is properly initialized.
108
  //
109
  // Internalized because it makes property lookups a little faster and
110
  // because the string is created in the old space straight away.  It's going
111
  // to end up in the old space sooner or later anyway but now it doesn't go
112
  // through v8::Eternal's new space handling first.
113
  //
114
  // One byte because our strings are ASCII and we can safely skip V8's UTF-8
115
  // decoding step.
116
117
207
  HandleScope handle_scope(isolate_);
118
119
#define V(PropertyName, StringValue)                                           \
120
  PropertyName##_.Set(                                                         \
121
      isolate_,                                                                \
122
      Private::New(isolate_,                                                   \
123
                   String::NewFromOneByte(                                     \
124
                       isolate_,                                               \
125
                       reinterpret_cast<const uint8_t*>(StringValue),          \
126
                       NewStringType::kInternalized,                           \
127
                       sizeof(StringValue) - 1)                                \
128
                       .ToLocalChecked()));
129
3105
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
130
#undef V
131
#define V(PropertyName, StringValue)                                           \
132
  PropertyName##_.Set(                                                         \
133
      isolate_,                                                                \
134
      Symbol::New(isolate_,                                                    \
135
                  String::NewFromOneByte(                                      \
136
                      isolate_,                                                \
137
                      reinterpret_cast<const uint8_t*>(StringValue),           \
138
                      NewStringType::kInternalized,                            \
139
                      sizeof(StringValue) - 1)                                 \
140
                      .ToLocalChecked()));
141
1863
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
142
#undef V
143
#define V(PropertyName, StringValue)                                           \
144
  PropertyName##_.Set(                                                         \
145
      isolate_,                                                                \
146
      String::NewFromOneByte(isolate_,                                         \
147
                             reinterpret_cast<const uint8_t*>(StringValue),    \
148
                             NewStringType::kInternalized,                     \
149
                             sizeof(StringValue) - 1)                          \
150
          .ToLocalChecked());
151
85490
  PER_ISOLATE_STRING_PROPERTIES(V)
152
#undef V
153
207
}
154
155
4978
IsolateData::IsolateData(Isolate* isolate,
156
                         uv_loop_t* event_loop,
157
                         MultiIsolatePlatform* platform,
158
                         ArrayBufferAllocator* node_allocator,
159
                         const std::vector<size_t>* indexes)
160
    : isolate_(isolate),
161
      event_loop_(event_loop),
162
4978
      allocator_(isolate->GetArrayBufferAllocator()),
163
      node_allocator_(node_allocator == nullptr ? nullptr
164
4977
                                                : node_allocator->GetImpl()),
165
4978
      uses_node_allocator_(allocator_ == node_allocator_),
166
1100137
      platform_(platform) {
167
4978
  CHECK_NOT_NULL(allocator_);
168
169
  options_.reset(
170
4978
      new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
171
172
4978
  if (indexes == nullptr) {
173
207
    CreateProperties();
174
  } else {
175
4771
    DeserializeProperties(indexes);
176
  }
177
4978
}
178
179
51
void IsolateData::MemoryInfo(MemoryTracker* tracker) const {
180
#define V(PropertyName, StringValue)                                           \
181
  tracker->TrackField(#PropertyName, PropertyName(isolate()));
182
51
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
183
#undef V
184
185
#define V(PropertyName, StringValue)                                           \
186
  tracker->TrackField(#PropertyName, PropertyName(isolate()));
187
51
  PER_ISOLATE_STRING_PROPERTIES(V)
188
#undef V
189
190
51
  if (node_allocator_ != nullptr) {
191
    tracker->TrackFieldWithSize(
192
51
        "node_allocator", sizeof(*node_allocator_), "NodeArrayBufferAllocator");
193
  } else {
194
    tracker->TrackFieldWithSize(
195
        "allocator", sizeof(*allocator_), "v8::ArrayBuffer::Allocator");
196
  }
197
  tracker->TrackFieldWithSize(
198
51
      "platform", sizeof(*platform_), "MultiIsolatePlatform");
199
  // TODO(joyeecheung): implement MemoryRetainer in the option classes.
200
51
}
201
202
4772
void InitThreadLocalOnce() {
203
4772
  CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));
204
4772
}
205
206
134
void TrackingTraceStateObserver::UpdateTraceCategoryState() {
207
134
  if (!env_->owns_process_state()) {
208
    // Ideally, we’d have a consistent story that treats all threads/Environment
209
    // instances equally here. However, tracing is essentially global, and this
210
    // callback is called from whichever thread calls `StartTracing()` or
211
    // `StopTracing()`. The only way to do this in a threadsafe fashion
212
    // seems to be only tracking this from the main thread, and only allowing
213
    // these state modifications from the main thread.
214
71
    return;
215
  }
216
217
132
  bool async_hooks_enabled = (*(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
218
132
                                 TRACING_CATEGORY_NODE1(async_hooks)))) != 0;
219
220
132
  Isolate* isolate = env_->isolate();
221
132
  HandleScope handle_scope(isolate);
222
132
  Local<Function> cb = env_->trace_category_state_function();
223
132
  if (cb.IsEmpty())
224
67
    return;
225
130
  TryCatchScope try_catch(env_);
226
65
  try_catch.SetVerbose(true);
227
130
  Local<Value> args[] = {Boolean::New(isolate, async_hooks_enabled)};
228
260
  cb->Call(env_->context(), Undefined(isolate), arraysize(args), args)
229
195
      .ToLocalChecked();
230
}
231
232
static std::atomic<uint64_t> next_thread_id{0};
233
234
4978
uint64_t Environment::AllocateThreadId() {
235
4978
  return next_thread_id++;
236
}
237
238
4967
void Environment::CreateProperties() {
239
4967
  HandleScope handle_scope(isolate_);
240
4967
  Local<Context> ctx = context();
241
4967
  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
242
9934
  templ->InstanceTemplate()->SetInternalFieldCount(1);
243
4967
  Local<Object> obj = templ->GetFunction(ctx)
244
9934
                          .ToLocalChecked()
245
14899
                          ->NewInstance(ctx)
246
9933
                          .ToLocalChecked();
247
4967
  obj->SetAlignedPointerInInternalField(0, this);
248
4967
  set_as_callback_data(obj);
249
4966
  set_as_callback_data_template(templ);
250
251
  // Store primordials setup by the per-context script in the environment.
252
  Local<Object> per_context_bindings =
253
9933
      GetPerContextExports(ctx).ToLocalChecked();
254
  Local<Value> primordials =
255
14900
      per_context_bindings->Get(ctx, primordials_string()).ToLocalChecked();
256
4967
  CHECK(primordials->IsObject());
257
4966
  set_primordials(primordials.As<Object>());
258
259
  Local<Object> process_object =
260
9933
      node::CreateProcessObject(this).FromMaybe(Local<Object>());
261
4966
  set_process_object(process_object);
262
4967
}
263
264
4967
std::string GetExecPath(const std::vector<std::string>& argv) {
265
  char exec_path_buf[2 * PATH_MAX];
266
4967
  size_t exec_path_len = sizeof(exec_path_buf);
267
4967
  std::string exec_path;
268
4967
  if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
269
4967
    exec_path = std::string(exec_path_buf, exec_path_len);
270
  } else {
271
    exec_path = argv[0];
272
  }
273
274
  // On OpenBSD process.execPath will be relative unless we
275
  // get the full path before process.execPath is used.
276
#if defined(__OpenBSD__)
277
  uv_fs_t req;
278
  req.ptr = nullptr;
279
  if (0 ==
280
      uv_fs_realpath(env->event_loop(), &req, exec_path.c_str(), nullptr)) {
281
    CHECK_NOT_NULL(req.ptr);
282
    exec_path = std::string(static_cast<char*>(req.ptr));
283
  }
284
  uv_fs_req_cleanup(&req);
285
#endif
286
287
4967
  return exec_path;
288
}
289
290
4967
Environment::Environment(IsolateData* isolate_data,
291
                         Local<Context> context,
292
                         const std::vector<std::string>& args,
293
                         const std::vector<std::string>& exec_args,
294
                         Flags flags,
295
                         uint64_t thread_id)
296
4967
    : isolate_(context->GetIsolate()),
297
      isolate_data_(isolate_data),
298
      immediate_info_(context->GetIsolate()),
299
      tick_info_(context->GetIsolate()),
300
4967
      timer_base_(uv_now(isolate_data->event_loop())),
301
      exec_argv_(exec_args),
302
      argv_(args),
303
      exec_path_(GetExecPath(args)),
304
      should_abort_on_uncaught_toggle_(isolate_, 1),
305
      stream_base_state_(isolate_, StreamBase::kNumStreamBaseStateFields),
306
      flags_(flags),
307
      thread_id_(thread_id == kNoThreadId ? AllocateThreadId() : thread_id),
308
      fs_stats_field_array_(isolate_, kFsStatsBufferLength),
309
      fs_stats_field_bigint_array_(isolate_, kFsStatsBufferLength),
310
377421
      context_(context->GetIsolate(), context) {
311
  // We'll be creating new objects so make sure we've entered the context.
312
4967
  HandleScope handle_scope(isolate());
313
  Context::Scope context_scope(context);
314
315
4967
  set_env_vars(per_process::system_environment);
316
317
  // We create new copies of the per-Environment option sets, so that it is
318
  // easier to modify them after Environment creation. The defaults are
319
  // part of the per-Isolate option set, for which in turn the defaults are
320
  // part of the per-process option set.
321
4967
  options_.reset(new EnvironmentOptions(*isolate_data->options()->per_env));
322
4967
  inspector_host_port_.reset(new HostPort(options_->debug_options().host_port));
323
324
#if HAVE_INSPECTOR
325
  // We can only create the inspector agent after having cloned the options.
326
4966
  inspector_agent_ = std::make_unique<inspector::Agent>(this);
327
#endif
328
329
4967
  AssignToContext(context, ContextInfo(""));
330
331
4967
  if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) {
332
4966
    trace_state_observer_ = std::make_unique<TrackingTraceStateObserver>(this);
333
4967
    TracingController* tracing_controller = writer->GetTracingController();
334
4966
    tracing_controller->AddTraceStateObserver(trace_state_observer_.get());
335
  }
336
337
4967
  destroy_async_id_list_.reserve(512);
338
  BeforeExit(
339
13731
      [](void* arg) {
340
4382
        Environment* env = static_cast<Environment*>(arg);
341
4382
        if (!env->destroy_async_id_list()->empty())
342
149
          AsyncWrap::DestroyAsyncIdsCallback(env, nullptr);
343
13731
      },
344
4967
      this);
345
346
9934
  performance_state_ =
347
9934
      std::make_unique<performance::performance_state>(isolate());
348
  performance_state_->Mark(
349
4967
      performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
350
  performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
351
4967
                           per_process::node_start_time);
352
  performance_state_->Mark(
353
      performance::NODE_PERFORMANCE_MILESTONE_V8_START,
354
4967
      performance::performance_v8_start);
355
356
9933
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
357
4967
          TRACING_CATEGORY_NODE1(environment)) != 0) {
358
8
    auto traced_value = tracing::TracedValue::Create();
359
8
    traced_value->BeginArray("args");
360
8
    for (const std::string& arg : args) traced_value->AppendString(arg);
361
8
    traced_value->EndArray();
362
8
    traced_value->BeginArray("exec_args");
363
8
    for (const std::string& arg : exec_args) traced_value->AppendString(arg);
364
8
    traced_value->EndArray();
365

16
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
366
                                      "Environment",
367
                                      this,
368
                                      "args",
369
8
                                      std::move(traced_value));
370
  }
371
372
  // By default, always abort when --abort-on-uncaught-exception was passed.
373
4966
  should_abort_on_uncaught_toggle_[0] = 1;
374
375
9933
  std::string debug_cats;
376
4966
  credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats, this);
377
4967
  set_debug_categories(debug_cats, true);
378
379
4967
  if (options_->no_force_async_hooks_checks) {
380
1
    async_hooks_.no_force_checks();
381
  }
382
383
  // TODO(joyeecheung): deserialize when the snapshot covers the environment
384
  // properties.
385
9933
  CreateProperties();
386
4966
}
387
388
342900
Environment::~Environment() {
389
  isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
390
4572
      BuildEmbedderGraph, this);
391
392
  // Make sure there are no re-used libuv wrapper objects.
393
  // CleanupHandles() should have removed all of them.
394
4572
  CHECK(file_handle_read_wrap_freelist_.empty());
395
396
4572
  HandleScope handle_scope(isolate());
397
398
#if HAVE_INSPECTOR
399
  // Destroy inspector agent before erasing the context. The inspector
400
  // destructor depends on the context still being accessible.
401
4572
  inspector_agent_.reset();
402
#endif
403
404
  context()->SetAlignedPointerInEmbedderData(
405
9144
      ContextEmbedderIndex::kEnvironment, nullptr);
406
407
4572
  if (trace_state_observer_) {
408
4572
    tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
409
4572
    CHECK_NOT_NULL(writer);
410
4572
    TracingController* tracing_controller = writer->GetTracingController();
411
4572
    tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get());
412
  }
413
414
4572
  delete[] heap_statistics_buffer_;
415
4572
  delete[] heap_space_statistics_buffer_;
416
4572
  delete[] http_parser_buffer_;
417
418

9144
  TRACE_EVENT_NESTABLE_ASYNC_END0(
419
    TRACING_CATEGORY_NODE1(environment), "Environment", this);
420
421
  // Do not unload addons on the main thread. Some addons need to retain memory
422
  // beyond the Environment's lifetime, and unloading them early would break
423
  // them; with Worker threads, we have the opportunity to be stricter.
424
  // Also, since the main thread usually stops just before the process exits,
425
  // this is far less relevant here.
426
4572
  if (!is_main_thread()) {
427
    // Dereference all addons that were loaded into this environment.
428
204
    for (binding::DLib& addon : loaded_addons_) {
429
9
      addon.Close();
430
    }
431
4572
  }
432
9144
}
433
434
4966
void Environment::InitializeLibuv(bool start_profiler_idle_notifier) {
435
4966
  HandleScope handle_scope(isolate());
436
4966
  Context::Scope context_scope(context());
437
438
4967
  CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
439
4966
  uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
440
441
4966
  uv_check_init(event_loop(), immediate_check_handle());
442
4967
  uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
443
444
4967
  uv_idle_init(event_loop(), immediate_idle_handle());
445
446
4966
  uv_check_start(immediate_check_handle(), CheckImmediate);
447
448
  // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
449
  // but not all samples are created equal; mark the wall clock time spent in
450
  // epoll_wait() and friends so profiling tools can filter it out.  The samples
451
  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
452
  // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
453
  // probably fortify in the API contract, namely that the last started prepare
454
  // or check watcher runs first.  It's not 100% foolproof; if an add-on starts
455
  // a prepare or check watcher after us, any samples attributed to its callback
456
  // will be recorded with state=IDLE.
457
4966
  uv_prepare_init(event_loop(), &idle_prepare_handle_);
458
4966
  uv_check_init(event_loop(), &idle_check_handle_);
459
4967
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
460
4967
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
461
462
  thread_stopper()->Install(
463
5026
    this, static_cast<void*>(this), [](uv_async_t* handle) {
464
30
      Environment* env = static_cast<Environment*>(handle->data);
465
30
      uv_stop(env->event_loop());
466
9993
    });
467
4966
  thread_stopper()->set_stopped(false);
468
4967
  uv_unref(reinterpret_cast<uv_handle_t*>(thread_stopper()->GetHandle()));
469
470
  // Register clean-up cb to be called to clean up the handles
471
  // when the environment is freed, note that they are not cleaned in
472
  // the one environment per process setup, but will be called in
473
  // FreeEnvironment.
474
4967
  RegisterHandleCleanups();
475
476
4967
  if (start_profiler_idle_notifier) {
477
1
    StartProfilerIdleNotifier();
478
  }
479
480
  static uv_once_t init_once = UV_ONCE_INIT;
481
4967
  uv_once(&init_once, InitThreadLocalOnce);
482
9932
  uv_key_set(&thread_local_env, this);
483
4966
}
484
485
59
void Environment::ExitEnv() {
486
59
  set_can_call_into_js(false);
487
59
  thread_stopper()->Stop();
488
59
  isolate_->TerminateExecution();
489
59
}
490
491
4966
void Environment::RegisterHandleCleanups() {
492
  HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
493
50686
                                        void* arg) {
494
22860
    handle->data = env;
495
496
22860
    env->CloseHandle(handle, [](uv_handle_t* handle) {
497
#ifdef DEBUG
498
      memset(handle, 0xab, uv_handle_size(handle->type));
499
#endif
500
45720
    });
501
55652
  };
502
503
  RegisterHandleCleanup(
504
4967
      reinterpret_cast<uv_handle_t*>(timer_handle()),
505
      close_and_finish,
506
4967
      nullptr);
507
  RegisterHandleCleanup(
508
4966
      reinterpret_cast<uv_handle_t*>(immediate_check_handle()),
509
      close_and_finish,
510
4967
      nullptr);
511
  RegisterHandleCleanup(
512
4967
      reinterpret_cast<uv_handle_t*>(immediate_idle_handle()),
513
      close_and_finish,
514
4967
      nullptr);
515
  RegisterHandleCleanup(
516
      reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_),
517
      close_and_finish,
518
4967
      nullptr);
519
  RegisterHandleCleanup(
520
      reinterpret_cast<uv_handle_t*>(&idle_check_handle_),
521
      close_and_finish,
522
4967
      nullptr);
523
4967
}
524
525
9333
void Environment::CleanupHandles() {
526
9367
  for (ReqWrapBase* request : req_wrap_queue_)
527
34
    request->Cancel();
528
529
11966
  for (HandleWrap* handle : handle_wrap_queue_)
530
5266
    handle->Close();
531
532
32193
  for (HandleCleanup& hc : handle_cleanup_queue_)
533
22860
    hc.cb_(this, hc.handle_, hc.arg_);
534
9333
  handle_cleanup_queue_.clear();
535
536

46496
  while (handle_cleanup_waiting_ != 0 ||
537

23248
         request_waiting_ != 0 ||
538
9334
         !handle_wrap_queue_.IsEmpty()) {
539
4581
    uv_run(event_loop(), UV_RUN_ONCE);
540
  }
541
542
9333
  file_handle_read_wrap_freelist_.clear();
543
9333
}
544
545
1
void Environment::StartProfilerIdleNotifier() {
546
1
  if (profiler_idle_notifier_started_)
547
1
    return;
548
549
1
  profiler_idle_notifier_started_ = true;
550
551
1
  uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
552
    Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
553
    env->isolate()->SetIdle(true);
554
2
  });
555
556
1
  uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
557
    Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
558
    env->isolate()->SetIdle(false);
559
2
  });
560
}
561
562
void Environment::StopProfilerIdleNotifier() {
563
  profiler_idle_notifier_started_ = false;
564
  uv_prepare_stop(&idle_prepare_handle_);
565
  uv_check_stop(&idle_check_handle_);
566
}
567
568
562312
void Environment::PrintSyncTrace() const {
569
1124624
  if (!options_->trace_sync_io) return;
570
571
32
  HandleScope handle_scope(isolate());
572
573
  fprintf(
574
32
      stderr, "(node:%d) WARNING: Detected use of sync API\n", uv_os_getpid());
575
  PrintStackTrace(
576
      isolate(),
577
32
      StackTrace::CurrentStackTrace(isolate(), 10, StackTrace::kDetailed));
578
}
579
580
4767
void Environment::RunCleanup() {
581
4767
  started_cleanup_ = true;
582
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
583
4767
                              "RunCleanup", this);
584
4767
  thread_stopper()->Uninstall();
585
4767
  CleanupHandles();
586
587
14100
  while (!cleanup_hooks_.empty()) {
588
    // Copy into a vector, since we can't sort an unordered_set in-place.
589
    std::vector<CleanupHookCallback> callbacks(
590
4566
        cleanup_hooks_.begin(), cleanup_hooks_.end());
591
    // We can't erase the copied elements from `cleanup_hooks_` yet, because we
592
    // need to be able to check whether they were un-scheduled by another hook.
593
594
    std::sort(callbacks.begin(), callbacks.end(),
595
743429
              [](const CleanupHookCallback& a, const CleanupHookCallback& b) {
596
      // Sort in descending order so that the most recently inserted callbacks
597
      // are run first.
598
743429
      return a.insertion_order_counter_ > b.insertion_order_counter_;
599
747995
    });
600
601
80900
    for (const CleanupHookCallback& cb : callbacks) {
602
76334
      if (cleanup_hooks_.count(cb) == 0) {
603
        // This hook was removed from the `cleanup_hooks_` set during another
604
        // hook that was run earlier. Nothing to do here.
605
        continue;
606
      }
607
608
76334
      cb.fn_(cb.arg_);
609
76334
      cleanup_hooks_.erase(cb);
610
    }
611
4566
    CleanupHandles();
612
9333
  }
613
4767
}
614
615
4395
void Environment::RunBeforeExitCallbacks() {
616
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
617
4395
                              "BeforeExit", this);
618
8777
  for (ExitCallback before_exit : before_exit_functions_) {
619
4382
    before_exit.cb_(before_exit.arg_);
620
  }
621
4395
  before_exit_functions_.clear();
622
4395
}
623
624
4967
void Environment::BeforeExit(void (*cb)(void* arg), void* arg) {
625
4967
  before_exit_functions_.push_back(ExitCallback{cb, arg});
626
4967
}
627
628
4572
void Environment::RunAtExitCallbacks() {
629
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
630
4572
                              "AtExit", this);
631
4579
  for (ExitCallback at_exit : at_exit_functions_) {
632
7
    at_exit.cb_(at_exit.arg_);
633
  }
634
4572
  at_exit_functions_.clear();
635
4572
}
636
637
7
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
638
7
  at_exit_functions_.push_back(ExitCallback{cb, arg});
639
7
}
640
641
55747
void Environment::RunAndClearNativeImmediates() {
642
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
643
55747
                              "RunAndClearNativeImmediates", this);
644
55747
  size_t count = native_immediate_callbacks_.size();
645
55747
  if (count > 0) {
646
48457
    size_t ref_count = 0;
647
48457
    std::vector<NativeImmediateCallback> list;
648
48457
    native_immediate_callbacks_.swap(list);
649
48459
    auto drain_list = [&]() {
650
48459
      TryCatchScope try_catch(this);
651
102246
      for (auto it = list.begin(); it != list.end(); ++it) {
652
53790
        DebugSealHandleScope seal_handle_scope(isolate());
653
53790
        it->cb_(this, it->data_);
654
53789
        if (it->refed_)
655
31741
          ref_count++;
656
53789
        if (UNLIKELY(try_catch.HasCaught())) {
657
2
          if (!try_catch.HasTerminated())
658
1
            errors::TriggerUncaughtException(isolate(), try_catch);
659
660
          // We are done with the current callback. Increase the counter so that
661
          // the steps below make everything *after* the current item part of
662
          // the new list.
663
2
          it++;
664
665
          // Bail out, remove the already executed callbacks from list
666
          // and set up a new TryCatch for the other pending callbacks.
667
2
          std::move_backward(it, list.end(), list.begin() + (list.end() - it));
668
2
          list.resize(list.end() - it);
669
2
          return true;
670
        }
671
      }
672
48456
      return false;
673
96915
    };
674
48457
    while (drain_list()) {}
675
676
    DCHECK_GE(immediate_info()->count(), count);
677
48456
    immediate_info()->count_dec(count);
678
48456
    immediate_info()->ref_count_dec(ref_count);
679
55746
  }
680
55746
}
681
682
683
6156
void Environment::ScheduleTimer(int64_t duration_ms) {
684
12312
  if (started_cleanup_) return;
685
6156
  uv_timer_start(timer_handle(), RunTimers, duration_ms, 0);
686
}
687
688
1310
void Environment::ToggleTimerRef(bool ref) {
689
2620
  if (started_cleanup_) return;
690
691
1310
  if (ref) {
692
989
    uv_ref(reinterpret_cast<uv_handle_t*>(timer_handle()));
693
  } else {
694
321
    uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
695
  }
696
}
697
698
5037
void Environment::RunTimers(uv_timer_t* handle) {
699
5037
  Environment* env = Environment::from_timer_handle(handle);
700
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
701
5037
                              "RunTimers", env);
702
703
5037
  if (!env->can_call_into_js())
704
    return;
705
706
10045
  HandleScope handle_scope(env->isolate());
707
10045
  Context::Scope context_scope(env->context());
708
709
5037
  Local<Object> process = env->process_object();
710
10045
  InternalCallbackScope scope(env, process, {0, 0});
711
712
5037
  Local<Function> cb = env->timers_callback_function();
713
  MaybeLocal<Value> ret;
714
5037
  Local<Value> arg = env->GetNow();
715
  // This code will loop until all currently due timers will process. It is
716
  // impossible for us to end up in an infinite loop due to how the JS-side
717
  // is structured.
718
5041
  do {
719
5067
    TryCatchScope try_catch(env);
720
5067
    try_catch.SetVerbose(true);
721
10134
    ret = cb->Call(env->context(), process, 1, &arg);
722

5041
  } while (ret.IsEmpty() && env->can_call_into_js());
723
724
  // NOTE(apapirovski): If it ever becomes possible that `call_into_js` above
725
  // is reset back to `true` after being previously set to `false` then this
726
  // code becomes invalid and needs to be rewritten. Otherwise catastrophic
727
  // timers corruption will occur and all timers behaviour will become
728
  // entirely unpredictable.
729
5011
  if (ret.IsEmpty())
730
3
    return;
731
732
  // To allow for less JS-C++ boundary crossing, the value returned from JS
733
  // serves a few purposes:
734
  // 1. If it's 0, no more timers exist and the handle should be unrefed
735
  // 2. If it's > 0, the value represents the next timer's expiry and there
736
  //    is at least one timer remaining that is refed.
737
  // 3. If it's < 0, the absolute value represents the next timer's expiry
738
  //    and there are no timers that are refed.
739
  int64_t expiry_ms =
740
20032
      ret.ToLocalChecked()->IntegerValue(env->context()).FromJust();
741
742
5008
  uv_handle_t* h = reinterpret_cast<uv_handle_t*>(handle);
743
744
5008
  if (expiry_ms != 0) {
745
    int64_t duration_ms =
746
4461
        llabs(expiry_ms) - (uv_now(env->event_loop()) - env->timer_base());
747
748
4461
    env->ScheduleTimer(duration_ms > 0 ? duration_ms : 1);
749
750
4461
    if (expiry_ms > 0)
751
4038
      uv_ref(h);
752
    else
753
423
      uv_unref(h);
754
  } else {
755
547
    uv_unref(h);
756
5008
  }
757
}
758
759
760
435371
void Environment::CheckImmediate(uv_check_t* handle) {
761
435371
  Environment* env = Environment::from_immediate_check_handle(handle);
762
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
763
435373
                              "CheckImmediate", env);
764
765
435373
  if (env->immediate_info()->count() == 0)
766
379625
    return;
767
768
111483
  HandleScope scope(env->isolate());
769
111483
  Context::Scope context_scope(env->context());
770
771
55747
  env->RunAndClearNativeImmediates();
772
773
55746
  if (!env->can_call_into_js())
774
3
    return;
775
776
56257
  do {
777
    MakeCallback(env->isolate(),
778
                 env->process_object(),
779
                 env->immediate_callback_function(),
780
                 0,
781
                 nullptr,
782
112521
                 {0, 0}).ToLocalChecked();
783

56257
  } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
784
785
55736
  if (env->immediate_info()->ref_count() == 0)
786
84702
    env->ToggleImmediateRef(false);
787
}
788
789
80533
void Environment::ToggleImmediateRef(bool ref) {
790
161066
  if (started_cleanup_) return;
791
792
80533
  if (ref) {
793
    // Idle handle is needed only to stop the event loop from blocking in poll.
794
158662
    uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
795
  } else {
796
28980
    uv_idle_stop(immediate_idle_handle());
797
  }
798
}
799
800
801
155070
Local<Value> Environment::GetNow() {
802
155070
  uv_update_time(event_loop());
803
155070
  uint64_t now = uv_now(event_loop());
804
155070
  CHECK_GE(now, timer_base());
805
155070
  now -= timer_base();
806
155070
  if (now <= 0xffffffff)
807
310140
    return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
808
  else
809
    return Number::New(isolate(), static_cast<double>(now));
810
}
811
812
4967
void Environment::set_debug_categories(const std::string& cats, bool enabled) {
813
4967
  std::string debug_categories = cats;
814
4967
  while (!debug_categories.empty()) {
815
22
    std::string::size_type comma_pos = debug_categories.find(',');
816
22
    std::string wanted = ToLower(debug_categories.substr(0, comma_pos));
817
818
#define V(name)                                                          \
819
    {                                                                    \
820
      static const std::string available_category = ToLower(#name);      \
821
      if (available_category.find(wanted) != std::string::npos)          \
822
        set_debug_enabled(DebugCategory::name, enabled);                 \
823
    }
824
825



































































22
    DEBUG_CATEGORY_NAMES(V)
826
#undef V
827
828
22
    if (comma_pos == std::string::npos)
829
22
      break;
830
    // Use everything after the `,` as the list for the next iteration.
831
    debug_categories = debug_categories.substr(comma_pos + 1);
832
4967
  }
833
4967
}
834
835
28
void CollectExceptionInfo(Environment* env,
836
                          Local<Object> obj,
837
                          int errorno,
838
                          const char* err_string,
839
                          const char* syscall,
840
                          const char* message,
841
                          const char* path,
842
                          const char* dest) {
843
  obj->Set(env->context(),
844
           env->errno_string(),
845
140
           Integer::New(env->isolate(), errorno)).Check();
846
847
  obj->Set(env->context(), env->code_string(),
848
140
           OneByteString(env->isolate(), err_string)).Check();
849
850
28
  if (message != nullptr) {
851
    obj->Set(env->context(), env->message_string(),
852
140
             OneByteString(env->isolate(), message)).Check();
853
  }
854
855
  Local<Value> path_buffer;
856
28
  if (path != nullptr) {
857
    path_buffer =
858
      Buffer::Copy(env->isolate(), path, strlen(path)).ToLocalChecked();
859
    obj->Set(env->context(), env->path_string(), path_buffer).Check();
860
  }
861
862
  Local<Value> dest_buffer;
863
28
  if (dest != nullptr) {
864
    dest_buffer =
865
      Buffer::Copy(env->isolate(), dest, strlen(dest)).ToLocalChecked();
866
    obj->Set(env->context(), env->dest_string(), dest_buffer).Check();
867
  }
868
869
28
  if (syscall != nullptr) {
870
    obj->Set(env->context(), env->syscall_string(),
871
140
             OneByteString(env->isolate(), syscall)).Check();
872
  }
873
28
}
874
875
28
void Environment::CollectUVExceptionInfo(Local<Value> object,
876
                                         int errorno,
877
                                         const char* syscall,
878
                                         const char* message,
879
                                         const char* path,
880
                                         const char* dest) {
881

28
  if (!object->IsObject() || errorno == 0)
882
28
    return;
883
884
28
  Local<Object> obj = object.As<Object>();
885
28
  const char* err_string = uv_err_name(errorno);
886
887

28
  if (message == nullptr || message[0] == '\0') {
888
28
    message = uv_strerror(errorno);
889
  }
890
891
  node::CollectExceptionInfo(this, obj, errorno, err_string,
892
28
                             syscall, message, path, dest);
893
}
894
895
51
void ImmediateInfo::MemoryInfo(MemoryTracker* tracker) const {
896
51
  tracker->TrackField("fields", fields_);
897
51
}
898
899
51
void TickInfo::MemoryInfo(MemoryTracker* tracker) const {
900
51
  tracker->TrackField("fields", fields_);
901
51
}
902
903
51
void AsyncHooks::MemoryInfo(MemoryTracker* tracker) const {
904
51
  tracker->TrackField("providers", providers_);
905
51
  tracker->TrackField("async_ids_stack", async_ids_stack_);
906
51
  tracker->TrackField("fields", fields_);
907
51
  tracker->TrackField("async_id_fields", async_id_fields_);
908
51
}
909
910
8
void AsyncHooks::grow_async_ids_stack() {
911
8
  async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
912
913
8
  env()->async_hooks_binding()->Set(
914
      env()->context(),
915
      env()->async_ids_stack_string(),
916
48
      async_ids_stack_.GetJSArray()).Check();
917
8
}
918
919
uv_key_t Environment::thread_local_env = {};
920
921
415
void Environment::Exit(int exit_code) {
922
415
  if (is_main_thread()) {
923
392
    stop_sub_worker_contexts();
924
391
    DisposePlatform();
925
391
    exit(exit_code);
926
  } else {
927
23
    worker_context_->Exit(exit_code);
928
  }
929
23
}
930
931
4964
void Environment::stop_sub_worker_contexts() {
932
9951
  while (!sub_worker_contexts_.empty()) {
933
24
    Worker* w = *sub_worker_contexts_.begin();
934
24
    remove_sub_worker_context(w);
935
24
    w->Exit(1);
936
24
    w->JoinThread();
937
  }
938
4963
}
939
940
#if HAVE_INSPECTOR
941
942
#endif  // HAVE_INSPECTOR
943
944
349
void MemoryTracker::TrackField(const char* edge_name,
945
                               const CleanupHookCallback& value,
946
                               const char* node_name) {
947
349
  v8::HandleScope handle_scope(isolate_);
948
  // Here, we utilize the fact that CleanupHookCallback instances
949
  // are all unique and won't be tracked twice in one BuildEmbedderGraph
950
  // callback.
951
  MemoryRetainerNode* n =
952
349
      PushNode("CleanupHookCallback", sizeof(value), edge_name);
953
  // TODO(joyeecheung): at the moment only arguments of type BaseObject will be
954
  // identified and tracked here (based on their deleters),
955
  // but we may convert and track other known types here.
956
349
  BaseObject* obj = value.GetBaseObject();
957

349
  if (obj != nullptr && obj->IsDoneInitializing()) {
958
345
    TrackField("arg", obj);
959
  }
960
349
  CHECK_EQ(CurrentNode(), n);
961
349
  CHECK_NE(n->size_, 0);
962
349
  PopNode();
963
349
}
964
965
51
void Environment::BuildEmbedderGraph(Isolate* isolate,
966
                                     EmbedderGraph* graph,
967
                                     void* data) {
968
51
  MemoryTracker tracker(isolate, graph);
969
51
  Environment* env = static_cast<Environment*>(data);
970
51
  tracker.Track(env);
971
51
}
972
973
51
inline size_t Environment::SelfSize() const {
974
51
  size_t size = sizeof(*this);
975
  // Remove non pointer fields that will be tracked in MemoryInfo()
976
  // TODO(joyeecheung): refactor the MemoryTracker interface so
977
  // this can be done for common types within the Track* calls automatically
978
  // if a certain scope is entered.
979
51
  size -= sizeof(thread_stopper_);
980
51
  size -= sizeof(async_hooks_);
981
51
  size -= sizeof(tick_info_);
982
51
  size -= sizeof(immediate_info_);
983
51
  return size;
984
}
985
986
51
void Environment::MemoryInfo(MemoryTracker* tracker) const {
987
  // Iteratable STLs have their own sizes subtracted from the parent
988
  // by default.
989
51
  tracker->TrackField("isolate_data", isolate_data_);
990
51
  tracker->TrackField("native_modules_with_cache", native_modules_with_cache);
991
  tracker->TrackField("native_modules_without_cache",
992
51
                      native_modules_without_cache);
993
51
  tracker->TrackField("destroy_async_id_list", destroy_async_id_list_);
994
51
  tracker->TrackField("exec_argv", exec_argv_);
995
  tracker->TrackField("should_abort_on_uncaught_toggle",
996
51
                      should_abort_on_uncaught_toggle_);
997
51
  tracker->TrackField("stream_base_state", stream_base_state_);
998
51
  tracker->TrackField("fs_stats_field_array", fs_stats_field_array_);
999
  tracker->TrackField("fs_stats_field_bigint_array",
1000
51
                      fs_stats_field_bigint_array_);
1001
51
  tracker->TrackField("thread_stopper", thread_stopper_);
1002
51
  tracker->TrackField("cleanup_hooks", cleanup_hooks_);
1003
51
  tracker->TrackField("async_hooks", async_hooks_);
1004
51
  tracker->TrackField("immediate_info", immediate_info_);
1005
51
  tracker->TrackField("tick_info", tick_info_);
1006
1007
#define V(PropertyName, TypeName)                                              \
1008
  tracker->TrackField(#PropertyName, PropertyName());
1009
51
  ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
1010
#undef V
1011
1012
  // FIXME(joyeecheung): track other fields in Environment.
1013
  // Currently MemoryTracker is unable to track these
1014
  // correctly:
1015
  // - Internal types that do not implement MemoryRetainer yet
1016
  // - STL containers with MemoryRetainer* inside
1017
  // - STL containers with numeric types inside that should not have their
1018
  //   nodes elided e.g. numeric keys in maps.
1019
  // We also need to make sure that when we add a non-pointer field as its own
1020
  // node, we shift its sizeof() size out of the Environment node.
1021
51
}
1022
1023
341000
char* Environment::Reallocate(char* data, size_t old_size, size_t size) {
1024
341000
  if (old_size == size) return data;
1025
  // If we know that the allocator is our ArrayBufferAllocator, we can let
1026
  // if reallocate directly.
1027
323479
  if (isolate_data()->uses_node_allocator()) {
1028
    return static_cast<char*>(
1029
323479
        isolate_data()->node_allocator()->Reallocate(data, old_size, size));
1030
  }
1031
  // Generic allocators do not provide a reallocation method; we need to
1032
  // allocate a new chunk of memory and copy the data over.
1033
  char* new_data = AllocateUnchecked(size);
1034
  if (new_data == nullptr) return nullptr;
1035
  memcpy(new_data, data, std::min(size, old_size));
1036
  if (size > old_size)
1037
    memset(new_data + old_size, 0, size - old_size);
1038
  Free(data, old_size);
1039
  return new_data;
1040
}
1041
1042
5171
void AsyncRequest::Install(Environment* env, void* data, uv_async_cb target) {
1043
5171
  CHECK_NULL(async_);
1044
5171
  env_ = env;
1045
5171
  async_ = new uv_async_t;
1046
5172
  async_->data = data;
1047
5172
  CHECK_EQ(uv_async_init(env_->event_loop(), async_, target), 0);
1048
5171
}
1049
1050
4972
void AsyncRequest::Uninstall() {
1051
4972
  if (async_ != nullptr) {
1052
9530
    env_->CloseHandle(async_, [](uv_async_t* async) { delete async; });
1053
4777
    async_ = nullptr;
1054
  }
1055
4972
}
1056
1057
264
void AsyncRequest::Stop() {
1058
264
  set_stopped(true);
1059
264
  if (async_ != nullptr) uv_async_send(async_);
1060
264
}
1061
1062
4970
uv_async_t* AsyncRequest::GetHandle() {
1063
4970
  return async_;
1064
}
1065
1066
55
void AsyncRequest::MemoryInfo(MemoryTracker* tracker) const {
1067
55
  if (async_ != nullptr) tracker->TrackField("async_request", *async_);
1068
55
}
1069
1070
9508
AsyncRequest::~AsyncRequest() {
1071
4754
  CHECK_NULL(async_);
1072
4754
}
1073
1074
// Not really any better place than env.cc at this moment.
1075
75811
void BaseObject::DeleteMe(void* data) {
1076
75811
  BaseObject* self = static_cast<BaseObject*>(data);
1077
75811
  delete self;
1078
75811
}
1079
1080
195
bool BaseObject::IsDoneInitializing() const { return true; }
1081
1082
351
Local<Object> BaseObject::WrappedObject() const {
1083
351
  return object();
1084
}
1085
1086

14496
}  // namespace node