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: 407 428 95.1 %
Date: 2019-02-23 22:23:05 Branches: 350 478 73.2 %

Line Branch Exec Source
1
#include "async_wrap.h"
2
#include "node_buffer.h"
3
#include "node_context_data.h"
4
#include "node_errors.h"
5
#include "node_file.h"
6
#include "node_internals.h"
7
#include "node_native_module.h"
8
#include "node_options-inl.h"
9
#include "node_platform.h"
10
#include "node_process.h"
11
#include "node_v8_platform-inl.h"
12
#include "node_worker.h"
13
#include "tracing/agent.h"
14
#include "tracing/traced_value.h"
15
#include "v8-profiler.h"
16
17
#include <stdio.h>
18
#include <algorithm>
19
#include <atomic>
20
21
namespace node {
22
23
using errors::TryCatchScope;
24
using v8::Boolean;
25
using v8::Context;
26
using v8::EmbedderGraph;
27
using v8::External;
28
using v8::Function;
29
using v8::HandleScope;
30
using v8::Integer;
31
using v8::Isolate;
32
using v8::Local;
33
using v8::Message;
34
using v8::NewStringType;
35
using v8::Number;
36
using v8::Object;
37
using v8::Private;
38
using v8::Promise;
39
using v8::PromiseHookType;
40
using v8::StackFrame;
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
#define kTraceCategoryCount 1
50
51
// TODO(@jasnell): Likely useful to move this to util or node_internal to
52
// allow reuse. But since we're not reusing it yet...
53
class TraceEventScope {
54
 public:
55
639555
  TraceEventScope(const char* category,
56
                  const char* name,
57
639555
                  void* id) : category_(category), name_(name), id_(id) {
58

1279108
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_, name_, id_);
59
639554
  }
60
639521
  ~TraceEventScope() {
61

1279042
    TRACE_EVENT_NESTABLE_ASYNC_END0(category_, name_, id_);
62
639521
  }
63
64
 private:
65
  const char* category_;
66
  const char* name_;
67
  void* id_;
68
};
69
70
int const Environment::kNodeContextTag = 0x6e6f64;
71
void* const Environment::kNodeContextTagPtr = const_cast<void*>(
72
    static_cast<const void*>(&Environment::kNodeContextTag));
73
74
4409
IsolateData::IsolateData(Isolate* isolate,
75
                         uv_loop_t* event_loop,
76
                         MultiIsolatePlatform* platform,
77
                         uint32_t* zero_fill_field) :
78
    isolate_(isolate),
79
    event_loop_(event_loop),
80
    zero_fill_field_(zero_fill_field),
81
917072
    platform_(platform) {
82
4409
  if (platform_ != nullptr)
83
4409
    platform_->RegisterIsolate(isolate_, event_loop);
84
85
  options_.reset(
86
4409
      new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
87
88
  // Create string and private symbol properties as internalized one byte
89
  // strings after the platform is properly initialized.
90
  //
91
  // Internalized because it makes property lookups a little faster and
92
  // because the string is created in the old space straight away.  It's going
93
  // to end up in the old space sooner or later anyway but now it doesn't go
94
  // through v8::Eternal's new space handling first.
95
  //
96
  // One byte because our strings are ASCII and we can safely skip V8's UTF-8
97
  // decoding step.
98
99
#define V(PropertyName, StringValue)                                        \
100
    PropertyName ## _.Set(                                                  \
101
        isolate,                                                            \
102
        Private::New(                                                       \
103
            isolate,                                                        \
104
            String::NewFromOneByte(                                         \
105
                isolate,                                                    \
106
                reinterpret_cast<const uint8_t*>(StringValue),              \
107
                NewStringType::kInternalized,                               \
108
                sizeof(StringValue) - 1).ToLocalChecked()));
109
74953
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
110
#undef V
111
#define V(PropertyName, StringValue)                                        \
112
    PropertyName ## _.Set(                                                  \
113
        isolate,                                                            \
114
        Symbol::New(                                                        \
115
            isolate,                                                        \
116
            String::NewFromOneByte(                                         \
117
                isolate,                                                    \
118
                reinterpret_cast<const uint8_t*>(StringValue),              \
119
                NewStringType::kInternalized,                               \
120
                sizeof(StringValue) - 1).ToLocalChecked()));
121
30863
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
122
#undef V
123
#define V(PropertyName, StringValue)                                        \
124
    PropertyName ## _.Set(                                                  \
125
        isolate,                                                            \
126
        String::NewFromOneByte(                                             \
127
            isolate,                                                        \
128
            reinterpret_cast<const uint8_t*>(StringValue),                  \
129
            NewStringType::kInternalized,                                   \
130
            sizeof(StringValue) - 1).ToLocalChecked());
131
1732737
  PER_ISOLATE_STRING_PROPERTIES(V)
132
#undef V
133
4409
}
134
135
8080
IsolateData::~IsolateData() {
136
4040
  if (platform_ != nullptr)
137
4040
    platform_->UnregisterIsolate(isolate_);
138
4040
}
139
140
141
4240
void InitThreadLocalOnce() {
142
4240
  CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));
143
4240
}
144
145
134
void Environment::TrackingTraceStateObserver::UpdateTraceCategoryState() {
146
134
  if (!env_->owns_process_state()) {
147
    // Ideally, we’d have a consistent story that treats all threads/Environment
148
    // instances equally here. However, tracing is essentially global, and this
149
    // callback is called from whichever thread calls `StartTracing()` or
150
    // `StopTracing()`. The only way to do this in a threadsafe fashion
151
    // seems to be only tracking this from the main thread, and only allowing
152
    // these state modifications from the main thread.
153
71
    return;
154
  }
155
156
132
  bool async_hooks_enabled = (*(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
157
132
                                 TRACING_CATEGORY_NODE1(async_hooks)))) != 0;
158
159
132
  Isolate* isolate = env_->isolate();
160
132
  HandleScope handle_scope(isolate);
161
132
  Local<Function> cb = env_->trace_category_state_function();
162
132
  if (cb.IsEmpty())
163
67
    return;
164
130
  TryCatchScope try_catch(env_);
165
65
  try_catch.SetVerbose(true);
166
130
  Local<Value> args[] = {Boolean::New(isolate, async_hooks_enabled)};
167
260
  cb->Call(env_->context(), Undefined(isolate), arraysize(args), args)
168
195
      .ToLocalChecked();
169
}
170
171
static std::atomic<uint64_t> next_thread_id{0};
172
173
4410
uint64_t Environment::AllocateThreadId() {
174
4410
  return next_thread_id++;
175
}
176
177
4405
Environment::Environment(IsolateData* isolate_data,
178
                         Local<Context> context,
179
                         Flags flags,
180
                         uint64_t thread_id)
181
4405
    : isolate_(context->GetIsolate()),
182
      isolate_data_(isolate_data),
183
      immediate_info_(context->GetIsolate()),
184
      tick_info_(context->GetIsolate()),
185
4405
      timer_base_(uv_now(isolate_data->event_loop())),
186
      should_abort_on_uncaught_toggle_(isolate_, 1),
187
      stream_base_state_(isolate_, StreamBase::kNumStreamBaseStateFields),
188
      flags_(flags),
189
      thread_id_(thread_id == kNoThreadId ? AllocateThreadId() : thread_id),
190
      fs_stats_field_array_(isolate_, kFsStatsBufferLength),
191
      fs_stats_field_bigint_array_(isolate_, kFsStatsBufferLength),
192
317160
      context_(context->GetIsolate(), context) {
193
  // We'll be creating new objects so make sure we've entered the context.
194
4405
  HandleScope handle_scope(isolate());
195
  Context::Scope context_scope(context);
196
4405
  set_as_external(External::New(isolate(), this));
197
198
  // We create new copies of the per-Environment option sets, so that it is
199
  // easier to modify them after Environment creation. The defaults are
200
  // part of the per-Isolate option set, for which in turn the defaults are
201
  // part of the per-process option set.
202
4405
  options_.reset(new EnvironmentOptions(*isolate_data->options()->per_env));
203
4405
  inspector_host_port_.reset(new HostPort(options_->debug_options().host_port));
204
205
#if HAVE_INSPECTOR
206
  // We can only create the inspector agent after having cloned the options.
207
13215
  inspector_agent_ =
208
8810
      std::unique_ptr<inspector::Agent>(new inspector::Agent(this));
209
#endif
210
211
4405
  AssignToContext(context, ContextInfo(""));
212
213
4405
  if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) {
214
4405
    trace_state_observer_ = std::make_unique<TrackingTraceStateObserver>(this);
215
4405
    TracingController* tracing_controller = writer->GetTracingController();
216
4405
    tracing_controller->AddTraceStateObserver(trace_state_observer_.get());
217
  }
218
219
4405
  destroy_async_id_list_.reserve(512);
220
  BeforeExit(
221
12157
      [](void* arg) {
222
3876
        Environment* env = static_cast<Environment*>(arg);
223
3876
        if (!env->destroy_async_id_list()->empty())
224
140
          AsyncWrap::DestroyAsyncIdsCallback(env, nullptr);
225
12157
      },
226
4405
      this);
227
228
4405
  performance_state_.reset(new performance::performance_state(isolate()));
229
  performance_state_->Mark(
230
4405
      performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
231
  performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
232
4405
                           per_process::node_start_time);
233
  performance_state_->Mark(
234
      performance::NODE_PERFORMANCE_MILESTONE_V8_START,
235
4405
      performance::performance_v8_start);
236
237
  // By default, always abort when --abort-on-uncaught-exception was passed.
238
4405
  should_abort_on_uncaught_toggle_[0] = 1;
239
240
8810
  std::string debug_cats;
241
4405
  credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats);
242
4405
  set_debug_categories(debug_cats, true);
243
244
  isolate()->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
245
4405
      BuildEmbedderGraph, this);
246
4405
  if (options_->no_force_async_hooks_checks) {
247
1
    async_hooks_.no_force_checks();
248
  }
249
250
  // TODO(addaleax): the per-isolate state should not be controlled by
251
  // a single Environment.
252
8810
  isolate()->SetPromiseRejectCallback(task_queue::PromiseRejectCallback);
253
4405
}
254
255
41446
CompileFnEntry::CompileFnEntry(Environment* env, uint32_t id)
256
41446
    : env(env), id(id) {
257
41446
  env->compile_fn_entries.insert(this);
258
41446
}
259
260
282520
Environment::~Environment() {
261
  isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
262
4036
      BuildEmbedderGraph, this);
263
264
  // Make sure there are no re-used libuv wrapper objects.
265
  // CleanupHandles() should have removed all of them.
266
4036
  CHECK(file_handle_read_wrap_freelist_.empty());
267
268
  // dispose the Persistent references to the compileFunction
269
  // wrappers used in the dynamic import callback
270
22862
  for (auto& entry : compile_fn_entries) {
271
18826
    delete entry;
272
  }
273
274
4036
  HandleScope handle_scope(isolate());
275
276
#if HAVE_INSPECTOR
277
  // Destroy inspector agent before erasing the context. The inspector
278
  // destructor depends on the context still being accessible.
279
4036
  inspector_agent_.reset();
280
#endif
281
282
  context()->SetAlignedPointerInEmbedderData(
283
8072
      ContextEmbedderIndex::kEnvironment, nullptr);
284
285
4036
  if (trace_state_observer_) {
286
4036
    tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
287
4036
    CHECK_NOT_NULL(writer);
288
4036
    TracingController* tracing_controller = writer->GetTracingController();
289
4036
    tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get());
290
  }
291
292
4036
  delete[] heap_statistics_buffer_;
293
4036
  delete[] heap_space_statistics_buffer_;
294
4036
  delete[] http_parser_buffer_;
295
296

8072
  TRACE_EVENT_NESTABLE_ASYNC_END0(
297
    TRACING_CATEGORY_NODE1(environment), "Environment", this);
298
299
  // Do not unload addons on the main thread. Some addons need to retain memory
300
  // beyond the Environment's lifetime, and unloading them early would break
301
  // them; with Worker threads, we have the opportunity to be stricter.
302
  // Also, since the main thread usually stops just before the process exits,
303
  // this is far less relevant here.
304
4036
  if (!is_main_thread()) {
305
    // Dereference all addons that were loaded into this environment.
306
172
    for (binding::DLib& addon : loaded_addons_) {
307
7
      addon.Close();
308
    }
309
4036
  }
310
4036
}
311
312
4405
void Environment::Start(bool start_profiler_idle_notifier) {
313
4405
  HandleScope handle_scope(isolate());
314
4405
  Context::Scope context_scope(context());
315
316
4405
  CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
317
4405
  uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
318
319
4405
  uv_check_init(event_loop(), immediate_check_handle());
320
4405
  uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
321
322
4405
  uv_idle_init(event_loop(), immediate_idle_handle());
323
324
4405
  uv_check_start(immediate_check_handle(), CheckImmediate);
325
326
  // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
327
  // but not all samples are created equal; mark the wall clock time spent in
328
  // epoll_wait() and friends so profiling tools can filter it out.  The samples
329
  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
330
  // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
331
  // probably fortify in the API contract, namely that the last started prepare
332
  // or check watcher runs first.  It's not 100% foolproof; if an add-on starts
333
  // a prepare or check watcher after us, any samples attributed to its callback
334
  // will be recorded with state=IDLE.
335
4405
  uv_prepare_init(event_loop(), &idle_prepare_handle_);
336
4405
  uv_check_init(event_loop(), &idle_check_handle_);
337
4405
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
338
4405
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
339
340
  // Register clean-up cb to be called to clean up the handles
341
  // when the environment is freed, note that they are not cleaned in
342
  // the one environment per process setup, but will be called in
343
  // FreeEnvironment.
344
4405
  RegisterHandleCleanups();
345
346
4405
  if (start_profiler_idle_notifier) {
347
3
    StartProfilerIdleNotifier();
348
  }
349
350
  static uv_once_t init_once = UV_ONCE_INIT;
351
4405
  uv_once(&init_once, InitThreadLocalOnce);
352
8810
  uv_key_set(&thread_local_env, this);
353
4405
}
354
355
4405
MaybeLocal<Object> Environment::ProcessCliArgs(
356
    const std::vector<std::string>& args,
357
    const std::vector<std::string>& exec_args) {
358
4405
  if (args.size() > 1) {
359
3938
    std::string first_arg = args[1];
360
3938
    if (first_arg == "inspect") {
361
2
      execution_mode_ = ExecutionMode::kInspect;
362
3936
    } else if (first_arg == "debug") {
363
2
      execution_mode_ = ExecutionMode::kDebug;
364
3934
    } else if (first_arg != "-") {
365
3932
      execution_mode_ = ExecutionMode::kRunMainModule;
366
3938
    }
367
  }
368
369
8810
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
370
4405
          TRACING_CATEGORY_NODE1(environment)) != 0) {
371
8
    auto traced_value = tracing::TracedValue::Create();
372
8
    traced_value->BeginArray("args");
373
8
    for (const std::string& arg : args) traced_value->AppendString(arg);
374
8
    traced_value->EndArray();
375
8
    traced_value->BeginArray("exec_args");
376
8
    for (const std::string& arg : exec_args) traced_value->AppendString(arg);
377
8
    traced_value->EndArray();
378

16
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
379
                                      "Environment",
380
                                      this,
381
                                      "args",
382
8
                                      std::move(traced_value));
383
  }
384
385
  Local<Object> process_object =
386
      node::CreateProcessObject(this, args, exec_args)
387
8810
          .FromMaybe(Local<Object>());
388
4405
  set_process_object(process_object);
389
4405
  return process_object;
390
}
391
392
4405
void Environment::RegisterHandleCleanups() {
393
  HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
394
44755
                                        void* arg) {
395
20175
    handle->data = env;
396
397
40350
    env->CloseHandle(handle, [](uv_handle_t* handle) {});
398
49160
  };
399
400
  RegisterHandleCleanup(
401
4405
      reinterpret_cast<uv_handle_t*>(timer_handle()),
402
      close_and_finish,
403
4405
      nullptr);
404
  RegisterHandleCleanup(
405
4405
      reinterpret_cast<uv_handle_t*>(immediate_check_handle()),
406
      close_and_finish,
407
4405
      nullptr);
408
  RegisterHandleCleanup(
409
4405
      reinterpret_cast<uv_handle_t*>(immediate_idle_handle()),
410
      close_and_finish,
411
4405
      nullptr);
412
  RegisterHandleCleanup(
413
      reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_),
414
      close_and_finish,
415
4405
      nullptr);
416
  RegisterHandleCleanup(
417
      reinterpret_cast<uv_handle_t*>(&idle_check_handle_),
418
      close_and_finish,
419
4405
      nullptr);
420
4405
}
421
422
8233
void Environment::CleanupHandles() {
423
8266
  for (ReqWrapBase* request : req_wrap_queue_)
424
33
    request->Cancel();
425
426
10426
  for (HandleWrap* handle : handle_wrap_queue_)
427
4386
    handle->Close();
428
429
28408
  for (HandleCleanup& hc : handle_cleanup_queue_)
430
20175
    hc.cb_(this, hc.handle_, hc.arg_);
431
8233
  handle_cleanup_queue_.clear();
432
433

41014
  while (handle_cleanup_waiting_ != 0 ||
434

20507
         request_waiting_ != 0 ||
435
8233
         !handle_wrap_queue_.IsEmpty()) {
436
4041
    uv_run(event_loop(), UV_RUN_ONCE);
437
  }
438
439
8233
  file_handle_read_wrap_freelist_.clear();
440
8233
}
441
442
3
void Environment::StartProfilerIdleNotifier() {
443
3
  if (profiler_idle_notifier_started_)
444
3
    return;
445
446
3
  profiler_idle_notifier_started_ = true;
447
448
15
  uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
449
6
    Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
450
6
    env->isolate()->SetIdle(true);
451
18
  });
452
453
15
  uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
454
6
    Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
455
6
    env->isolate()->SetIdle(false);
456
18
  });
457
}
458
459
void Environment::StopProfilerIdleNotifier() {
460
  profiler_idle_notifier_started_ = false;
461
  uv_prepare_stop(&idle_prepare_handle_);
462
  uv_check_stop(&idle_check_handle_);
463
}
464
465
511473
void Environment::PrintSyncTrace() const {
466
511473
  if (!options_->trace_sync_io)
467
1022906
    return;
468
469
40
  HandleScope handle_scope(isolate());
470
  Local<StackTrace> stack =
471
40
      StackTrace::CurrentStackTrace(isolate(), 10, StackTrace::kDetailed);
472
473
  fprintf(stderr, "(node:%d) WARNING: Detected use of sync API\n",
474
40
          uv_os_getpid());
475
476
640
  for (int i = 0; i < stack->GetFrameCount() - 1; i++) {
477
560
    Local<StackFrame> stack_frame = stack->GetFrame(isolate(), i);
478
560
    node::Utf8Value fn_name_s(isolate(), stack_frame->GetFunctionName());
479
840
    node::Utf8Value script_name(isolate(), stack_frame->GetScriptName());
480
280
    const int line_number = stack_frame->GetLineNumber();
481
280
    const int column = stack_frame->GetColumn();
482
483
280
    if (stack_frame->IsEval()) {
484
      if (stack_frame->GetScriptId() == Message::kNoScriptIdInfo) {
485
        fprintf(stderr, "    at [eval]:%i:%i\n", line_number, column);
486
      } else {
487
        fprintf(stderr,
488
                "    at [eval] (%s:%i:%i)\n",
489
                *script_name,
490
                line_number,
491
                column);
492
      }
493
      break;
494
    }
495
496
280
    if (fn_name_s.length() == 0) {
497
21
      fprintf(stderr, "    at %s:%i:%i\n", *script_name, line_number, column);
498
    } else {
499
      fprintf(stderr,
500
              "    at %s (%s:%i:%i)\n",
501
              *fn_name_s,
502
              *script_name,
503
              line_number,
504
259
              column);
505
    }
506
280
  }
507
40
  fflush(stderr);
508
}
509
510
4200
void Environment::RunCleanup() {
511
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
512
4200
                              "RunCleanup", this);
513
4200
  CleanupHandles();
514
515
12433
  while (!cleanup_hooks_.empty()) {
516
    // Copy into a vector, since we can't sort an unordered_set in-place.
517
    std::vector<CleanupHookCallback> callbacks(
518
4033
        cleanup_hooks_.begin(), cleanup_hooks_.end());
519
    // We can't erase the copied elements from `cleanup_hooks_` yet, because we
520
    // need to be able to check whether they were un-scheduled by another hook.
521
522
    std::sort(callbacks.begin(), callbacks.end(),
523
481636
              [](const CleanupHookCallback& a, const CleanupHookCallback& b) {
524
      // Sort in descending order so that the most recently inserted callbacks
525
      // are run first.
526
481636
      return a.insertion_order_counter_ > b.insertion_order_counter_;
527
485669
    });
528
529
44616
    for (const CleanupHookCallback& cb : callbacks) {
530
40583
      if (cleanup_hooks_.count(cb) == 0) {
531
        // This hook was removed from the `cleanup_hooks_` set during another
532
        // hook that was run earlier. Nothing to do here.
533
        continue;
534
      }
535
536
40583
      cb.fn_(cb.arg_);
537
40583
      cleanup_hooks_.erase(cb);
538
    }
539
4033
    CleanupHandles();
540
8233
  }
541
4200
}
542
543
3889
void Environment::RunBeforeExitCallbacks() {
544
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
545
3889
                              "BeforeExit", this);
546
7765
  for (ExitCallback before_exit : before_exit_functions_) {
547
3876
    before_exit.cb_(before_exit.arg_);
548
  }
549
3889
  before_exit_functions_.clear();
550
3889
}
551
552
4405
void Environment::BeforeExit(void (*cb)(void* arg), void* arg) {
553
4405
  before_exit_functions_.push_back(ExitCallback{cb, arg});
554
4405
}
555
556
4035
void Environment::RunAtExitCallbacks() {
557
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
558
4035
                              "AtExit", this);
559
4042
  for (ExitCallback at_exit : at_exit_functions_) {
560
7
    at_exit.cb_(at_exit.arg_);
561
  }
562
4035
  at_exit_functions_.clear();
563
4035
}
564
565
7
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
566
7
  at_exit_functions_.push_back(ExitCallback{cb, arg});
567
7
}
568
569
249
void Environment::AddPromiseHook(promise_hook_func fn, void* arg) {
570
  auto it = std::find_if(
571
      promise_hooks_.begin(), promise_hooks_.end(),
572
3
      [&](const PromiseHookCallback& hook) {
573

3
        return hook.cb_ == fn && hook.arg_ == arg;
574
252
      });
575
249
  if (it != promise_hooks_.end()) {
576
3
    it->enable_count_++;
577
252
    return;
578
  }
579
246
  promise_hooks_.push_back(PromiseHookCallback{fn, arg, 1});
580
581
246
  if (promise_hooks_.size() == 1) {
582
246
    isolate_->SetPromiseHook(EnvPromiseHook);
583
  }
584
}
585
586
211
bool Environment::RemovePromiseHook(promise_hook_func fn, void* arg) {
587
  auto it = std::find_if(
588
      promise_hooks_.begin(), promise_hooks_.end(),
589
211
      [&](const PromiseHookCallback& hook) {
590

211
        return hook.cb_ == fn && hook.arg_ == arg;
591
422
      });
592
593
211
  if (it == promise_hooks_.end()) return false;
594
595
211
  if (--it->enable_count_ > 0) return true;
596
597
208
  promise_hooks_.erase(it);
598
208
  if (promise_hooks_.empty()) {
599
208
    isolate_->SetPromiseHook(nullptr);
600
  }
601
602
208
  return true;
603
}
604
605
4007
void Environment::EnvPromiseHook(PromiseHookType type,
606
                                 Local<Promise> promise,
607
                                 Local<Value> parent) {
608
4007
  Local<Context> context = promise->CreationContext();
609
610
4007
  Environment* env = Environment::GetCurrent(context);
611
8014
  if (env == nullptr) return;
612
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
613
4007
                              "EnvPromiseHook", env);
614
8014
  for (const PromiseHookCallback& hook : env->promise_hooks_) {
615
4007
    hook.cb_(type, promise, parent, hook.arg_);
616
4007
  }
617
}
618
619
52638
void Environment::RunAndClearNativeImmediates() {
620
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
621
52638
                              "RunAndClearNativeImmediates", this);
622
52638
  size_t count = native_immediate_callbacks_.size();
623
52638
  if (count > 0) {
624
46333
    size_t ref_count = 0;
625
46333
    std::vector<NativeImmediateCallback> list;
626
46333
    native_immediate_callbacks_.swap(list);
627
46333
    auto drain_list = [&]() {
628
46333
      TryCatchScope try_catch(this);
629
95857
      for (auto it = list.begin(); it != list.end(); ++it) {
630
#ifdef DEBUG
631
        v8::SealHandleScope seal_handle_scope(isolate());
632
#endif
633
49525
        it->cb_(this, it->data_);
634
49524
        if (it->refed_)
635
27500
          ref_count++;
636
49524
        if (UNLIKELY(try_catch.HasCaught())) {
637
          if (!try_catch.HasTerminated())
638
            FatalException(isolate(), try_catch);
639
640
          // Bail out, remove the already executed callbacks from list
641
          // and set up a new TryCatch for the other pending callbacks.
642
          std::move_backward(it, list.end(), list.begin() + (list.end() - it));
643
          list.resize(list.end() - it);
644
          return true;
645
        }
646
      }
647
46332
      return false;
648
92665
    };
649
46333
    while (drain_list()) {}
650
651
    DCHECK_GE(immediate_info()->count(), count);
652
46332
    immediate_info()->count_dec(count);
653
46332
    immediate_info()->ref_count_dec(ref_count);
654
52637
  }
655
52637
}
656
657
658
7392
void Environment::ScheduleTimer(int64_t duration_ms) {
659
7392
  uv_timer_start(timer_handle(), RunTimers, duration_ms, 0);
660
7392
}
661
662
1269
void Environment::ToggleTimerRef(bool ref) {
663
1269
  if (ref) {
664
956
    uv_ref(reinterpret_cast<uv_handle_t*>(timer_handle()));
665
  } else {
666
313
    uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
667
  }
668
1269
}
669
670
5891
void Environment::RunTimers(uv_timer_t* handle) {
671
5891
  Environment* env = Environment::from_timer_handle(handle);
672
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
673
5891
                              "RunTimers", env);
674
675
5891
  if (!env->can_call_into_js())
676
    return;
677
678
11754
  HandleScope handle_scope(env->isolate());
679
11754
  Context::Scope context_scope(env->context());
680
681
5891
  Local<Object> process = env->process_object();
682
11754
  InternalCallbackScope scope(env, process, {0, 0});
683
684
5891
  Local<Function> cb = env->timers_callback_function();
685
  MaybeLocal<Value> ret;
686
5891
  Local<Value> arg = env->GetNow();
687
  // This code will loop until all currently due timers will process. It is
688
  // impossible for us to end up in an infinite loop due to how the JS-side
689
  // is structured.
690
5895
  do {
691
5920
    TryCatchScope try_catch(env);
692
5920
    try_catch.SetVerbose(true);
693
11840
    ret = cb->Call(env->context(), process, 1, &arg);
694

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

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
































































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

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

28
  if (message == nullptr || message[0] == '\0') {
858
28
    message = uv_strerror(errorno);
859
  }
860
861
  node::CollectExceptionInfo(this, obj, errorno, err_string,
862
28
                             syscall, message, path, dest);
863
}
864
865
866
8
void Environment::AsyncHooks::grow_async_ids_stack() {
867
8
  async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
868
869
8
  env()->async_hooks_binding()->Set(
870
      env()->context(),
871
      env()->async_ids_stack_string(),
872
48
      async_ids_stack_.GetJSArray()).FromJust();
873
8
}
874
875
uv_key_t Environment::thread_local_env = {};
876
877
385
void Environment::Exit(int exit_code) {
878
385
  if (is_main_thread()) {
879
366
    stop_sub_worker_contexts();
880
365
    DisposePlatform();
881
365
    exit(exit_code);
882
  } else {
883
19
    worker_context_->Exit(exit_code);
884
  }
885
19
}
886
887
4401
void Environment::stop_sub_worker_contexts() {
888
8824
  while (!sub_worker_contexts_.empty()) {
889
23
    Worker* w = *sub_worker_contexts_.begin();
890
23
    remove_sub_worker_context(w);
891
23
    w->Exit(1);
892
23
    w->JoinThread();
893
  }
894
4400
}
895
896
32
void Environment::BuildEmbedderGraph(Isolate* isolate,
897
                                     EmbedderGraph* graph,
898
                                     void* data) {
899
32
  MemoryTracker tracker(isolate, graph);
900
95
  static_cast<Environment*>(data)->ForEachBaseObject([&](BaseObject* obj) {
901
95
    tracker.Track(obj);
902
127
  });
903
32
}
904
905
906
// Not really any better place than env.cc at this moment.
907
40508
void BaseObject::DeleteMe(void* data) {
908
40508
  BaseObject* self = static_cast<BaseObject*>(data);
909
40508
  delete self;
910
40508
}
911
912
95
Local<Object> BaseObject::WrappedObject() const {
913
95
  return object();
914
}
915
916
95
bool BaseObject::IsRootNode() const {
917
190
  return !persistent_handle_.IsWeak();
918
}
919
920
}  // namespace node