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: 277 423 65.5 %
Date: 2019-02-01 22:03:38 Branches: 102 482 21.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
7537
  TraceEventScope(const char* category,
55
                  const char* name,
56
7537
                  void* id) : category_(category), name_(name), id_(id) {
57

7537
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_, name_, id_);
58
7537
  }
59
7536
  ~TraceEventScope() {
60

7536
    TRACE_EVENT_NESTABLE_ASYNC_END0(category_, name_, id_);
61
7536
  }
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
164
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
33784
    platform_(platform) {
81
164
  if (platform_ != nullptr)
82
164
    platform_->RegisterIsolate(isolate_, event_loop);
83
84
  options_.reset(
85
164
      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
2788
  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
1148
  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
63796
  PER_ISOLATE_STRING_PROPERTIES(V)
131
#undef V
132
164
}
133
134
308
IsolateData::~IsolateData() {
135
154
  if (platform_ != nullptr)
136
154
    platform_->UnregisterIsolate(isolate_);
137
154
}
138
139
140
164
void InitThreadLocalOnce() {
141
164
  CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));
142
164
}
143
144
void Environment::TrackingTraceStateObserver::UpdateTraceCategoryState() {
145
  if (!env_->is_main_thread()) {
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
    return;
153
  }
154
155
  env_->trace_category_state()[0] =
156
      *TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
157
          TRACING_CATEGORY_NODE1(async_hooks));
158
159
  Isolate* isolate = env_->isolate();
160
  HandleScope handle_scope(isolate);
161
  Local<Function> cb = env_->trace_category_state_function();
162
  if (cb.IsEmpty())
163
    return;
164
  TryCatchScope try_catch(env_);
165
  try_catch.SetVerbose(true);
166
  cb->Call(env_->context(), Undefined(isolate),
167
           0, nullptr).ToLocalChecked();
168
}
169
170
static std::atomic<uint64_t> next_thread_id{0};
171
172
164
Environment::Environment(IsolateData* isolate_data,
173
                         Local<Context> context,
174
                         Flags flags)
175
164
    : isolate_(context->GetIsolate()),
176
      isolate_data_(isolate_data),
177
      immediate_info_(context->GetIsolate()),
178
      tick_info_(context->GetIsolate()),
179
164
      timer_base_(uv_now(isolate_data->event_loop())),
180
      should_abort_on_uncaught_toggle_(isolate_, 1),
181
      trace_category_state_(isolate_, kTraceCategoryCount),
182
      stream_base_state_(isolate_, StreamBase::kNumStreamBaseStateFields),
183
      flags_(flags),
184
164
      thread_id_(next_thread_id++),
185
      fs_stats_field_array_(isolate_, kFsStatsBufferLength),
186
      fs_stats_field_bigint_array_(isolate_, kFsStatsBufferLength),
187
11480
      context_(context->GetIsolate(), context) {
188
  // We'll be creating new objects so make sure we've entered the context.
189
164
  HandleScope handle_scope(isolate());
190
  Context::Scope context_scope(context);
191
164
  set_as_external(External::New(isolate(), this));
192
193
  // We create new copies of the per-Environment option sets, so that it is
194
  // easier to modify them after Environment creation. The defaults are
195
  // part of the per-Isolate option set, for which in turn the defaults are
196
  // part of the per-process option set.
197
164
  options_.reset(new EnvironmentOptions(*isolate_data->options()->per_env));
198
164
  inspector_host_port_.reset(new HostPort(options_->debug_options().host_port));
199
200
#if HAVE_INSPECTOR
201
  // We can only create the inspector agent after having cloned the options.
202
492
  inspector_agent_ =
203
328
      std::unique_ptr<inspector::Agent>(new inspector::Agent(this));
204
#endif
205
206
164
  AssignToContext(context, ContextInfo(""));
207
208
164
  if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) {
209
164
    trace_state_observer_ = std::make_unique<TrackingTraceStateObserver>(this);
210
164
    TracingController* tracing_controller = writer->GetTracingController();
211
164
    if (tracing_controller != nullptr)
212
164
      tracing_controller->AddTraceStateObserver(trace_state_observer_.get());
213
  }
214
215
164
  destroy_async_id_list_.reserve(512);
216
  BeforeExit(
217
472
      [](void* arg) {
218
154
        Environment* env = static_cast<Environment*>(arg);
219
154
        if (!env->destroy_async_id_list()->empty())
220
1
          AsyncWrap::DestroyAsyncIdsCallback(env, nullptr);
221
472
      },
222
164
      this);
223
224
164
  performance_state_.reset(new performance::performance_state(isolate()));
225
  performance_state_->Mark(
226
164
      performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
227
  performance_state_->Mark(
228
      performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
229
164
      performance::performance_node_start);
230
  performance_state_->Mark(
231
      performance::NODE_PERFORMANCE_MILESTONE_V8_START,
232
164
      performance::performance_v8_start);
233
234
  // By default, always abort when --abort-on-uncaught-exception was passed.
235
164
  should_abort_on_uncaught_toggle_[0] = 1;
236
237
328
  std::string debug_cats;
238
164
  credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats);
239
164
  set_debug_categories(debug_cats, true);
240
241
  isolate()->GetHeapProfiler()->AddBuildEmbedderGraphCallback(
242
164
      BuildEmbedderGraph, this);
243
164
  if (options_->no_force_async_hooks_checks) {
244
    async_hooks_.no_force_checks();
245
  }
246
247
  // TODO(addaleax): the per-isolate state should not be controlled by
248
  // a single Environment.
249
328
  isolate()->SetPromiseRejectCallback(task_queue::PromiseRejectCallback);
250
164
}
251
252
10318
Environment::~Environment() {
253
  isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
254
154
      BuildEmbedderGraph, this);
255
256
  // Make sure there are no re-used libuv wrapper objects.
257
  // CleanupHandles() should have removed all of them.
258
154
  CHECK(file_handle_read_wrap_freelist_.empty());
259
260
154
  HandleScope handle_scope(isolate());
261
262
#if HAVE_INSPECTOR
263
  // Destroy inspector agent before erasing the context. The inspector
264
  // destructor depends on the context still being accessible.
265
154
  inspector_agent_.reset();
266
#endif
267
268
  context()->SetAlignedPointerInEmbedderData(
269
308
      ContextEmbedderIndex::kEnvironment, nullptr);
270
271
154
  if (trace_state_observer_) {
272
154
    tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
273
154
    CHECK_NOT_NULL(writer);
274
154
    TracingController* tracing_controller = writer->GetTracingController();
275
154
    if (tracing_controller != nullptr)
276
154
      tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get());
277
  }
278
279
154
  delete[] heap_statistics_buffer_;
280
154
  delete[] heap_space_statistics_buffer_;
281
154
  delete[] http_parser_buffer_;
282
283

154
  TRACE_EVENT_NESTABLE_ASYNC_END0(
284
    TRACING_CATEGORY_NODE1(environment), "Environment", this);
285
286
  // Do not unload addons on the main thread. Some addons need to retain memory
287
  // beyond the Environment's lifetime, and unloading them early would break
288
  // them; with Worker threads, we have the opportunity to be stricter.
289
  // Also, since the main thread usually stops just before the process exits,
290
  // this is far less relevant here.
291
154
  if (!is_main_thread()) {
292
    // Dereference all addons that were loaded into this environment.
293
    for (binding::DLib& addon : loaded_addons_) {
294
      addon.Close();
295
    }
296
154
  }
297
154
}
298
299
164
void Environment::Start(bool start_profiler_idle_notifier) {
300
164
  HandleScope handle_scope(isolate());
301
164
  Context::Scope context_scope(context());
302
303
164
  CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
304
164
  uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
305
306
164
  uv_check_init(event_loop(), immediate_check_handle());
307
164
  uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
308
309
164
  uv_idle_init(event_loop(), immediate_idle_handle());
310
311
164
  uv_check_start(immediate_check_handle(), CheckImmediate);
312
313
  // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
314
  // but not all samples are created equal; mark the wall clock time spent in
315
  // epoll_wait() and friends so profiling tools can filter it out.  The samples
316
  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
317
  // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
318
  // probably fortify in the API contract, namely that the last started prepare
319
  // or check watcher runs first.  It's not 100% foolproof; if an add-on starts
320
  // a prepare or check watcher after us, any samples attributed to its callback
321
  // will be recorded with state=IDLE.
322
164
  uv_prepare_init(event_loop(), &idle_prepare_handle_);
323
164
  uv_check_init(event_loop(), &idle_check_handle_);
324
164
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
325
164
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
326
327
  // Register clean-up cb to be called to clean up the handles
328
  // when the environment is freed, note that they are not cleaned in
329
  // the one environment per process setup, but will be called in
330
  // FreeEnvironment.
331
164
  RegisterHandleCleanups();
332
333
164
  if (start_profiler_idle_notifier) {
334
    StartProfilerIdleNotifier();
335
  }
336
337
  static uv_once_t init_once = UV_ONCE_INIT;
338
164
  uv_once(&init_once, InitThreadLocalOnce);
339
328
  uv_key_set(&thread_local_env, this);
340
164
}
341
342
164
MaybeLocal<Object> Environment::ProcessCliArgs(
343
    const std::vector<std::string>& args,
344
    const std::vector<std::string>& exec_args) {
345
164
  if (args.size() > 1) {
346
154
    std::string first_arg = args[1];
347
154
    if (first_arg == "inspect") {
348
      execution_mode_ = ExecutionMode::kInspect;
349
154
    } else if (first_arg == "debug") {
350
      execution_mode_ = ExecutionMode::kDebug;
351
154
    } else if (first_arg != "-") {
352
154
      execution_mode_ = ExecutionMode::kRunMainModule;
353
154
    }
354
  }
355
356
328
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
357
164
          TRACING_CATEGORY_NODE1(environment)) != 0) {
358
    auto traced_value = tracing::TracedValue::Create();
359
    traced_value->BeginArray("args");
360
    for (const std::string& arg : args) traced_value->AppendString(arg);
361
    traced_value->EndArray();
362
    traced_value->BeginArray("exec_args");
363
    for (const std::string& arg : exec_args) traced_value->AppendString(arg);
364
    traced_value->EndArray();
365
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
366
                                      "Environment",
367
                                      this,
368
                                      "args",
369
                                      std::move(traced_value));
370
  }
371
372
  Local<Object> process_object =
373
      node::CreateProcessObject(this, args, exec_args)
374
328
          .FromMaybe(Local<Object>());
375
164
  set_process_object(process_object);
376
164
  return process_object;
377
}
378
379
164
void Environment::RegisterHandleCleanups() {
380
  HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
381
1704
                                        void* arg) {
382
770
    handle->data = env;
383
384
1540
    env->CloseHandle(handle, [](uv_handle_t* handle) {});
385
1868
  };
386
387
  RegisterHandleCleanup(
388
164
      reinterpret_cast<uv_handle_t*>(timer_handle()),
389
      close_and_finish,
390
164
      nullptr);
391
  RegisterHandleCleanup(
392
164
      reinterpret_cast<uv_handle_t*>(immediate_check_handle()),
393
      close_and_finish,
394
164
      nullptr);
395
  RegisterHandleCleanup(
396
164
      reinterpret_cast<uv_handle_t*>(immediate_idle_handle()),
397
      close_and_finish,
398
164
      nullptr);
399
  RegisterHandleCleanup(
400
      reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_),
401
      close_and_finish,
402
164
      nullptr);
403
  RegisterHandleCleanup(
404
      reinterpret_cast<uv_handle_t*>(&idle_check_handle_),
405
      close_and_finish,
406
164
      nullptr);
407
164
}
408
409
308
void Environment::CleanupHandles() {
410
308
  for (ReqWrap<uv_req_t>* request : req_wrap_queue_)
411
    request->Cancel();
412
413
488
  for (HandleWrap* handle : handle_wrap_queue_)
414
360
    handle->Close();
415
416
1078
  for (HandleCleanup& hc : handle_cleanup_queue_)
417
770
    hc.cb_(this, hc.handle_, hc.arg_);
418
308
  handle_cleanup_queue_.clear();
419
420

1548
  while (handle_cleanup_waiting_ != 0 ||
421

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

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

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

1533
  } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
743
744
1532
  if (env->immediate_info()->ref_count() == 0)
745
2292
    env->ToggleImmediateRef(false);
746
}
747
748
2281
void Environment::ToggleImmediateRef(bool ref) {
749
2281
  if (ref) {
750
    // Idle handle is needed only to stop the event loop from blocking in poll.
751
4598
    uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
752
  } else {
753
760
    uv_idle_stop(immediate_idle_handle());
754
  }
755
2281
}
756
757
758
194
Local<Value> Environment::GetNow() {
759
194
  uv_update_time(event_loop());
760
194
  uint64_t now = uv_now(event_loop());
761
194
  CHECK_GE(now, timer_base());
762
194
  now -= timer_base();
763
194
  if (now <= 0xffffffff)
764
388
    return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
765
  else
766
    return Number::New(isolate(), static_cast<double>(now));
767
}
768
769
770
164
void Environment::set_debug_categories(const std::string& cats, bool enabled) {
771
164
  std::string debug_categories = cats;
772
164
  while (!debug_categories.empty()) {
773
    std::string::size_type comma_pos = debug_categories.find(',');
774
    std::string wanted = ToLower(debug_categories.substr(0, comma_pos));
775
776
#define V(name)                                                          \
777
    {                                                                    \
778
      static const std::string available_category = ToLower(#name);      \
779
      if (available_category.find(wanted) != std::string::npos)          \
780
        set_debug_enabled(DebugCategory::name, enabled);                 \
781
    }
782
783
    DEBUG_CATEGORY_NAMES(V)
784
785
    if (comma_pos == std::string::npos)
786
      break;
787
    // Use everything after the `,` as the list for the next iteration.
788
    debug_categories = debug_categories.substr(comma_pos + 1);
789
164
  }
790
164
}
791
792
void CollectExceptionInfo(Environment* env,
793
                          Local<Object> obj,
794
                          int errorno,
795
                          const char* err_string,
796
                          const char* syscall,
797
                          const char* message,
798
                          const char* path,
799
                          const char* dest) {
800
  obj->Set(env->context(),
801
           env->errno_string(),
802
           Integer::New(env->isolate(), errorno)).FromJust();
803
804
  obj->Set(env->context(), env->code_string(),
805
           OneByteString(env->isolate(), err_string)).FromJust();
806
807
  if (message != nullptr) {
808
    obj->Set(env->context(), env->message_string(),
809
             OneByteString(env->isolate(), message)).FromJust();
810
  }
811
812
  Local<Value> path_buffer;
813
  if (path != nullptr) {
814
    path_buffer =
815
      Buffer::Copy(env->isolate(), path, strlen(path)).ToLocalChecked();
816
    obj->Set(env->context(), env->path_string(), path_buffer).FromJust();
817
  }
818
819
  Local<Value> dest_buffer;
820
  if (dest != nullptr) {
821
    dest_buffer =
822
      Buffer::Copy(env->isolate(), dest, strlen(dest)).ToLocalChecked();
823
    obj->Set(env->context(), env->dest_string(), dest_buffer).FromJust();
824
  }
825
826
  if (syscall != nullptr) {
827
    obj->Set(env->context(), env->syscall_string(),
828
             OneByteString(env->isolate(), syscall)).FromJust();
829
  }
830
}
831
832
void Environment::CollectExceptionInfo(Local<Value> object,
833
                                       int errorno,
834
                                       const char* syscall,
835
                                       const char* message,
836
                                       const char* path) {
837
  if (!object->IsObject() || errorno == 0)
838
    return;
839
840
  Local<Object> obj = object.As<Object>();
841
  const char* err_string = errors::errno_string(errorno);
842
843
  if (message == nullptr || message[0] == '\0') {
844
    message = strerror(errorno);
845
  }
846
847
  node::CollectExceptionInfo(this, obj, errorno, err_string,
848
                             syscall, message, path, nullptr);
849
}
850
851
void Environment::CollectUVExceptionInfo(Local<Value> object,
852
                                         int errorno,
853
                                         const char* syscall,
854
                                         const char* message,
855
                                         const char* path,
856
                                         const char* dest) {
857
  if (!object->IsObject() || errorno == 0)
858
    return;
859
860
  Local<Object> obj = object.As<Object>();
861
  const char* err_string = uv_err_name(errorno);
862
863
  if (message == nullptr || message[0] == '\0') {
864
    message = uv_strerror(errorno);
865
  }
866
867
  node::CollectExceptionInfo(this, obj, errorno, err_string,
868
                             syscall, message, path, dest);
869
}
870
871
872
void Environment::AsyncHooks::grow_async_ids_stack() {
873
  async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
874
875
  env()->async_hooks_binding()->Set(
876
      env()->context(),
877
      env()->async_ids_stack_string(),
878
      async_ids_stack_.GetJSArray()).FromJust();
879
}
880
881
uv_key_t Environment::thread_local_env = {};
882
883
10
void Environment::Exit(int exit_code) {
884
10
  if (is_main_thread()) {
885
10
    stop_sub_worker_contexts();
886
10
    DisposePlatform();
887
10
    exit(exit_code);
888
  } else {
889
    worker_context_->Exit(exit_code);
890
  }
891
}
892
893
164
void Environment::stop_sub_worker_contexts() {
894
328
  while (!sub_worker_contexts_.empty()) {
895
    Worker* w = *sub_worker_contexts_.begin();
896
    remove_sub_worker_context(w);
897
    w->Exit(1);
898
    w->JoinThread();
899
  }
900
164
}
901
902
void Environment::BuildEmbedderGraph(Isolate* isolate,
903
                                     EmbedderGraph* graph,
904
                                     void* data) {
905
  MemoryTracker tracker(isolate, graph);
906
  static_cast<Environment*>(data)->ForEachBaseObject([&](BaseObject* obj) {
907
    tracker.Track(obj);
908
  });
909
}
910
911
912
// Not really any better place than env.cc at this moment.
913
7519
void BaseObject::DeleteMe(void* data) {
914
7519
  BaseObject* self = static_cast<BaseObject*>(data);
915
7519
  delete self;
916
7519
}
917
918
Local<Object> BaseObject::WrappedObject() const {
919
  return object();
920
}
921
922
bool BaseObject::IsRootNode() const {
923
  return !persistent_handle_.IsWeak();
924
}
925
926
}  // namespace node