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: 399 421 94.8 %
Date: 2019-02-13 22:28:58 Branches: 297 470 63.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::Context;
25
using v8::EmbedderGraph;
26
using v8::External;
27
using v8::Function;
28
using v8::HandleScope;
29
using v8::Integer;
30
using v8::Isolate;
31
using v8::Local;
32
using v8::Message;
33
using v8::NewStringType;
34
using v8::Number;
35
using v8::Object;
36
using v8::Private;
37
using v8::Promise;
38
using v8::PromiseHookType;
39
using v8::StackFrame;
40
using v8::StackTrace;
41
using v8::String;
42
using v8::Symbol;
43
using v8::TracingController;
44
using v8::Undefined;
45
using v8::Value;
46
using worker::Worker;
47
48
#define kTraceCategoryCount 1
49
50
// TODO(@jasnell): Likely useful to move this to util or node_internal to
51
// allow reuse. But since we're not reusing it yet...
52
class TraceEventScope {
53
 public:
54
621688
  TraceEventScope(const char* category,
55
                  const char* name,
56
621688
                  void* id) : category_(category), name_(name), id_(id) {
57

621688
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_, name_, id_);
58
621688
  }
59
621656
  ~TraceEventScope() {
60

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

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

8
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
369
                                      "Environment",
370
                                      this,
371
                                      "args",
372
8
                                      std::move(traced_value));
373
  }
374
375
  Local<Object> process_object =
376
      node::CreateProcessObject(this, args, exec_args)
377
8834
          .FromMaybe(Local<Object>());
378
4417
  set_process_object(process_object);
379
4417
  return process_object;
380
}
381
382
4417
void Environment::RegisterHandleCleanups() {
383
  HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
384
44897
                                        void* arg) {
385
20240
    handle->data = env;
386
387
40480
    env->CloseHandle(handle, [](uv_handle_t* handle) {});
388
49314
  };
389
390
  RegisterHandleCleanup(
391
4417
      reinterpret_cast<uv_handle_t*>(timer_handle()),
392
      close_and_finish,
393
4417
      nullptr);
394
  RegisterHandleCleanup(
395
4417
      reinterpret_cast<uv_handle_t*>(immediate_check_handle()),
396
      close_and_finish,
397
4417
      nullptr);
398
  RegisterHandleCleanup(
399
4417
      reinterpret_cast<uv_handle_t*>(immediate_idle_handle()),
400
      close_and_finish,
401
4417
      nullptr);
402
  RegisterHandleCleanup(
403
      reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_),
404
      close_and_finish,
405
4417
      nullptr);
406
  RegisterHandleCleanup(
407
      reinterpret_cast<uv_handle_t*>(&idle_check_handle_),
408
      close_and_finish,
409
4417
      nullptr);
410
4417
}
411
412
8253
void Environment::CleanupHandles() {
413
8286
  for (ReqWrap<uv_req_t>* request : req_wrap_queue_)
414
33
    request->Cancel();
415
416
10466
  for (HandleWrap* handle : handle_wrap_queue_)
417
4426
    handle->Close();
418
419
28493
  for (HandleCleanup& hc : handle_cleanup_queue_)
420
20240
    hc.cb_(this, hc.handle_, hc.arg_);
421
8253
  handle_cleanup_queue_.clear();
422
423

41121
  while (handle_cleanup_waiting_ != 0 ||
424

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

3
        return hook.cb_ == fn && hook.arg_ == arg;
564
247
      });
565
244
  if (it != promise_hooks_.end()) {
566
3
    it->enable_count_++;
567
247
    return;
568
  }
569
241
  promise_hooks_.push_back(PromiseHookCallback{fn, arg, 1});
570
571
241
  if (promise_hooks_.size() == 1) {
572
241
    isolate_->SetPromiseHook(EnvPromiseHook);
573
  }
574
}
575
576
207
bool Environment::RemovePromiseHook(promise_hook_func fn, void* arg) {
577
  auto it = std::find_if(
578
      promise_hooks_.begin(), promise_hooks_.end(),
579
207
      [&](const PromiseHookCallback& hook) {
580

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

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

52513
  } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
746
747
51992
  if (env->immediate_info()->ref_count() == 0)
748
77984
    env->ToggleImmediateRef(false);
749
}
750
751
73893
void Environment::ToggleImmediateRef(bool ref) {
752
73893
  if (ref) {
753
    // Idle handle is needed only to stop the event loop from blocking in poll.
754
149556
    uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
755
  } else {
756
26006
    uv_idle_stop(immediate_idle_handle());
757
  }
758
73893
}
759
760
761
343136
Local<Value> Environment::GetNow() {
762
343136
  uv_update_time(event_loop());
763
343136
  uint64_t now = uv_now(event_loop());
764
343136
  CHECK_GE(now, timer_base());
765
343136
  now -= timer_base();
766
343136
  if (now <= 0xffffffff)
767
686272
    return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
768
  else
769
    return Number::New(isolate(), static_cast<double>(now));
770
}
771
772
773
4417
void Environment::set_debug_categories(const std::string& cats, bool enabled) {
774
4417
  std::string debug_categories = cats;
775
4417
  while (!debug_categories.empty()) {
776
1
    std::string::size_type comma_pos = debug_categories.find(',');
777
1
    std::string wanted = ToLower(debug_categories.substr(0, comma_pos));
778
779
#define V(name)                                                          \
780
    {                                                                    \
781
      static const std::string available_category = ToLower(#name);      \
782
      if (available_category.find(wanted) != std::string::npos)          \
783
        set_debug_enabled(DebugCategory::name, enabled);                 \
784
    }
785
786































































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

28
  if (!object->IsObject() || errorno == 0)
842
28
    return;
843
844
28
  Local<Object> obj = object.As<Object>();
845
28
  const char* err_string = uv_err_name(errorno);
846
847

28
  if (message == nullptr || message[0] == '\0') {
848
28
    message = uv_strerror(errorno);
849
  }
850
851
  node::CollectExceptionInfo(this, obj, errorno, err_string,
852
28
                             syscall, message, path, dest);
853
}
854
855
856
8
void Environment::AsyncHooks::grow_async_ids_stack() {
857
8
  async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
858
859
8
  env()->async_hooks_binding()->Set(
860
      env()->context(),
861
      env()->async_ids_stack_string(),
862
48
      async_ids_stack_.GetJSArray()).FromJust();
863
8
}
864
865
uv_key_t Environment::thread_local_env = {};
866
867
379
void Environment::Exit(int exit_code) {
868
379
  if (is_main_thread()) {
869
365
    stop_sub_worker_contexts();
870
364
    DisposePlatform();
871
364
    exit(exit_code);
872
  } else {
873
14
    worker_context_->Exit(exit_code);
874
  }
875
14
}
876
877
4413
void Environment::stop_sub_worker_contexts() {
878
8847
  while (!sub_worker_contexts_.empty()) {
879
22
    Worker* w = *sub_worker_contexts_.begin();
880
22
    remove_sub_worker_context(w);
881
22
    w->Exit(1);
882
22
    w->JoinThread();
883
  }
884
4412
}
885
886
33
void Environment::BuildEmbedderGraph(Isolate* isolate,
887
                                     EmbedderGraph* graph,
888
                                     void* data) {
889
33
  MemoryTracker tracker(isolate, graph);
890
97
  static_cast<Environment*>(data)->ForEachBaseObject([&](BaseObject* obj) {
891
97
    tracker.Track(obj);
892
130
  });
893
33
}
894
895
896
// Not really any better place than env.cc at this moment.
897
153371
void BaseObject::DeleteMe(void* data) {
898
153371
  BaseObject* self = static_cast<BaseObject*>(data);
899
153371
  delete self;
900
153371
}
901
902
97
Local<Object> BaseObject::WrappedObject() const {
903
97
  return object();
904
}
905
906
97
bool BaseObject::IsRootNode() const {
907
194
  return !persistent_handle_.IsWeak();
908
}
909
910
}  // namespace node