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: 493 514 95.9 %
Date: 2019-09-26 22:31:05 Branches: 590 948 62.2 %

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
211
  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
4893
void IsolateData::DeserializeProperties(const std::vector<size_t>* indexes) {
81
4893
  size_t i = 0;
82
4893
  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



137004
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
97


78288
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
98









































































































4115013
  PER_ISOLATE_STRING_PROPERTIES(VS)
99
#undef V
100
#undef VY
101
#undef VS
102
#undef VP
103
4893
}
104
105
218
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
218
  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
3270
  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
1962
  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
91778
  PER_ISOLATE_STRING_PROPERTIES(V)
152
#undef V
153
218
}
154
155
5111
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
5111
      allocator_(isolate->GetArrayBufferAllocator()),
163
      node_allocator_(node_allocator == nullptr ? nullptr
164
5110
                                                : node_allocator->GetImpl()),
165
5111
      uses_node_allocator_(allocator_ == node_allocator_),
166
1149974
      platform_(platform) {
167
5111
  CHECK_NOT_NULL(allocator_);
168
169
  options_.reset(
170
5111
      new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
171
172
5111
  if (indexes == nullptr) {
173
218
    CreateProperties();
174
  } else {
175
4893
    DeserializeProperties(indexes);
176
  }
177
5111
}
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
4894
void InitThreadLocalOnce() {
203
4894
  CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));
204
4894
}
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
5111
uint64_t Environment::AllocateThreadId() {
235
5111
  return next_thread_id++;
236
}
237
238
5104
void Environment::CreateProperties() {
239
5104
  HandleScope handle_scope(isolate_);
240
5104
  Local<Context> ctx = context();
241
5104
  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
242
10208
  templ->InstanceTemplate()->SetInternalFieldCount(1);
243
5104
  Local<Object> obj = templ->GetFunction(ctx)
244
10208
                          .ToLocalChecked()
245
15312
                          ->NewInstance(ctx)
246
10208
                          .ToLocalChecked();
247
5104
  obj->SetAlignedPointerInInternalField(0, this);
248
5104
  set_as_callback_data(obj);
249
5104
  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
10208
      GetPerContextExports(ctx).ToLocalChecked();
254
  Local<Value> primordials =
255
15312
      per_context_bindings->Get(ctx, primordials_string()).ToLocalChecked();
256
5104
  CHECK(primordials->IsObject());
257
5104
  set_primordials(primordials.As<Object>());
258
259
  Local<Object> process_object =
260
10208
      node::CreateProcessObject(this).FromMaybe(Local<Object>());
261
5104
  set_process_object(process_object);
262
5104
}
263
264
5104
std::string GetExecPath(const std::vector<std::string>& argv) {
265
  char exec_path_buf[2 * PATH_MAX];
266
5104
  size_t exec_path_len = sizeof(exec_path_buf);
267
5104
  std::string exec_path;
268
5104
  if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
269
5104
    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(nullptr, &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
5104
  return exec_path;
288
}
289
290
5104
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
5104
    : isolate_(context->GetIsolate()),
297
      isolate_data_(isolate_data),
298
      immediate_info_(context->GetIsolate()),
299
      tick_info_(context->GetIsolate()),
300
5104
      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
387904
      context_(context->GetIsolate(), context) {
311
  // We'll be creating new objects so make sure we've entered the context.
312
5104
  HandleScope handle_scope(isolate());
313
  Context::Scope context_scope(context);
314
315
5104
  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
5104
  options_.reset(new EnvironmentOptions(*isolate_data->options()->per_env));
322
5104
  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
5104
  inspector_agent_ = std::make_unique<inspector::Agent>(this);
327
#endif
328
329
5104
  AssignToContext(context, ContextInfo(""));
330
331
5104
  if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) {
332
5104
    trace_state_observer_ = std::make_unique<TrackingTraceStateObserver>(this);
333
5104
    TracingController* tracing_controller = writer->GetTracingController();
334
5104
    tracing_controller->AddTraceStateObserver(trace_state_observer_.get());
335
  }
336
337
5104
  destroy_async_id_list_.reserve(512);
338
  BeforeExit(
339
14084
      [](void* arg) {
340
4490
        Environment* env = static_cast<Environment*>(arg);
341
4490
        if (!env->destroy_async_id_list()->empty())
342
150
          AsyncWrap::DestroyAsyncIdsCallback(env);
343
14084
      },
344
5104
      this);
345
346
10208
  performance_state_ =
347
10208
      std::make_unique<performance::performance_state>(isolate());
348
  performance_state_->Mark(
349
5104
      performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
350
  performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
351
5104
                           per_process::node_start_time);
352
  performance_state_->Mark(
353
      performance::NODE_PERFORMANCE_MILESTONE_V8_START,
354
5104
      performance::performance_v8_start);
355
356
10208
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
357
5104
          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
5104
  should_abort_on_uncaught_toggle_[0] = 1;
374
375
10208
  std::string debug_cats;
376
5104
  credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats, this);
377
5104
  set_debug_categories(debug_cats, true);
378
379
5104
  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
10208
  CreateProperties();
386
5104
}
387
388
352052
Environment::~Environment() {
389
  isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
390
4693
      BuildEmbedderGraph, this);
391
392
  // Make sure there are no re-used libuv wrapper objects.
393
  // CleanupHandles() should have removed all of them.
394
4695
  CHECK(file_handle_read_wrap_freelist_.empty());
395
396
4695
  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
4695
  inspector_agent_.reset();
402
#endif
403
404
  context()->SetAlignedPointerInEmbedderData(
405
9389
      ContextEmbedderIndex::kEnvironment, nullptr);
406
407
4695
  if (trace_state_observer_) {
408
4694
    tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
409
4694
    CHECK_NOT_NULL(writer);
410
4694
    TracingController* tracing_controller = writer->GetTracingController();
411
4694
    tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get());
412
  }
413
414
4695
  delete[] heap_statistics_buffer_;
415
4695
  delete[] heap_space_statistics_buffer_;
416
4695
  delete[] http_parser_buffer_;
417
4695
  delete[] heap_code_statistics_buffer_;
418
419

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

46717
  while (handle_cleanup_waiting_ != 0 ||
538

23359
         request_waiting_ != 0 ||
539
9328
         !handle_wrap_queue_.IsEmpty()) {
540
4703
    uv_run(event_loop(), UV_RUN_ONCE);
541
  }
542
543
9328
  file_handle_read_wrap_freelist_.clear();
544
9328
}
545
546
3
void Environment::StartProfilerIdleNotifier() {
547
3
  if (profiler_idle_notifier_started_)
548
3
    return;
549
550
3
  profiler_idle_notifier_started_ = true;
551
552
4119
  uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
553
2058
    Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
554
2058
    env->isolate()->SetIdle(true);
555
4122
  });
556
557
4117
  uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
558
2057
    Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
559
2057
    env->isolate()->SetIdle(false);
560
4120
  });
561
}
562
563
void Environment::StopProfilerIdleNotifier() {
564
  profiler_idle_notifier_started_ = false;
565
  uv_prepare_stop(&idle_prepare_handle_);
566
  uv_check_stop(&idle_check_handle_);
567
}
568
569
587644
void Environment::PrintSyncTrace() const {
570
1175288
  if (!trace_sync_io_) return;
571
572
1
  HandleScope handle_scope(isolate());
573
574
  fprintf(
575
1
      stderr, "(node:%d) WARNING: Detected use of sync API\n", uv_os_getpid());
576
  PrintStackTrace(
577
      isolate(),
578
1
      StackTrace::CurrentStackTrace(isolate(), 10, StackTrace::kDetailed));
579
}
580
581
4904
void Environment::RunCleanup() {
582
4904
  started_cleanup_ = true;
583
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
584
4904
                              "RunCleanup", this);
585
4904
  thread_stopper()->Uninstall();
586
4905
  CleanupHandles();
587
588
14233
  while (!cleanup_hooks_.empty()) {
589
    // Copy into a vector, since we can't sort an unordered_set in-place.
590
    std::vector<CleanupHookCallback> callbacks(
591
4423
        cleanup_hooks_.begin(), cleanup_hooks_.end());
592
    // We can't erase the copied elements from `cleanup_hooks_` yet, because we
593
    // need to be able to check whether they were un-scheduled by another hook.
594
595
    std::sort(callbacks.begin(), callbacks.end(),
596
678628
              [](const CleanupHookCallback& a, const CleanupHookCallback& b) {
597
      // Sort in descending order so that the most recently inserted callbacks
598
      // are run first.
599
678628
      return a.insertion_order_counter_ > b.insertion_order_counter_;
600
683051
    });
601
602
73982
    for (const CleanupHookCallback& cb : callbacks) {
603
69559
      if (cleanup_hooks_.count(cb) == 0) {
604
        // This hook was removed from the `cleanup_hooks_` set during another
605
        // hook that was run earlier. Nothing to do here.
606
        continue;
607
      }
608
609
69559
      cb.fn_(cb.arg_);
610
69559
      cleanup_hooks_.erase(cb);
611
    }
612
4423
    CleanupHandles();
613
9328
  }
614
4905
}
615
616
4504
void Environment::RunBeforeExitCallbacks() {
617
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
618
4504
                              "BeforeExit", this);
619
8994
  for (ExitCallback before_exit : before_exit_functions_) {
620
4490
    before_exit.cb_(before_exit.arg_);
621
  }
622
4504
  before_exit_functions_.clear();
623
4504
}
624
625
5104
void Environment::BeforeExit(void (*cb)(void* arg), void* arg) {
626
5104
  before_exit_functions_.push_back(ExitCallback{cb, arg});
627
5104
}
628
629
4695
void Environment::RunAtExitCallbacks() {
630
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
631
4695
                              "AtExit", this);
632
4702
  for (ExitCallback at_exit : at_exit_functions_) {
633
7
    at_exit.cb_(at_exit.arg_);
634
  }
635
4695
  at_exit_functions_.clear();
636
4695
}
637
638
7
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
639
7
  at_exit_functions_.push_back(ExitCallback{cb, arg});
640
7
}
641
642
55613
void Environment::RunAndClearNativeImmediates() {
643
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
644
55613
                              "RunAndClearNativeImmediates", this);
645
55613
  size_t ref_count = 0;
646
55613
  size_t count = 0;
647
111225
  std::unique_ptr<NativeImmediateCallback> head;
648
55613
  head.swap(native_immediate_callbacks_head_);
649
55613
  native_immediate_callbacks_tail_ = nullptr;
650
651
48657
  auto drain_list = [&]() {
652
48657
    TryCatchScope try_catch(this);
653
103333
    for (; head; head = head->get_next()) {
654
54679
      DebugSealHandleScope seal_handle_scope(isolate());
655
54679
      count++;
656
54679
      if (head->is_refed())
657
32614
        ref_count++;
658
659
54679
      head->Call(this);
660
54678
      if (UNLIKELY(try_catch.HasCaught())) {
661
2
        if (!try_catch.HasTerminated())
662
1
          errors::TriggerUncaughtException(isolate(), try_catch);
663
664
        // We are done with the current callback. Move one iteration along,
665
        // as if we had completed successfully.
666
2
        head = head->get_next();
667
2
        return true;
668
      }
669
    }
670
48654
    return false;
671
104269
  };
672

55613
  while (head && drain_list()) {}
673
674
  DCHECK_GE(immediate_info()->count(), count);
675
55612
  immediate_info()->count_dec(count);
676
111224
  immediate_info()->ref_count_dec(ref_count);
677
55612
}
678
679
680
6364
void Environment::ScheduleTimer(int64_t duration_ms) {
681
12728
  if (started_cleanup_) return;
682
6364
  uv_timer_start(timer_handle(), RunTimers, duration_ms, 0);
683
}
684
685
1296
void Environment::ToggleTimerRef(bool ref) {
686
2592
  if (started_cleanup_) return;
687
688
1296
  if (ref) {
689
987
    uv_ref(reinterpret_cast<uv_handle_t*>(timer_handle()));
690
  } else {
691
309
    uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
692
  }
693
}
694
695
5259
void Environment::RunTimers(uv_timer_t* handle) {
696
5259
  Environment* env = Environment::from_timer_handle(handle);
697
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
698
5260
                              "RunTimers", env);
699
700
5260
  if (!env->can_call_into_js())
701
    return;
702
703
10490
  HandleScope handle_scope(env->isolate());
704
10490
  Context::Scope context_scope(env->context());
705
706
5260
  Local<Object> process = env->process_object();
707
10490
  InternalCallbackScope scope(env, process, {0, 0});
708
709
5260
  Local<Function> cb = env->timers_callback_function();
710
  MaybeLocal<Value> ret;
711
5260
  Local<Value> arg = env->GetNow();
712
  // This code will loop until all currently due timers will process. It is
713
  // impossible for us to end up in an infinite loop due to how the JS-side
714
  // is structured.
715
5265
  do {
716
5291
    TryCatchScope try_catch(env);
717
5290
    try_catch.SetVerbose(true);
718
10582
    ret = cb->Call(env->context(), process, 1, &arg);
719

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

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





































































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

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

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

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

14862
}  // namespace node