GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/env.cc Lines: 387 426 90.8 %
Date: 2019-01-07 12:15:22 Branches: 282 474 59.5 %

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_worker.h"
11
#include "tracing/agent.h"
12
#include "tracing/traced_value.h"
13
#include "v8-profiler.h"
14
15
#include <stdio.h>
16
#include <algorithm>
17
18
namespace node {
19
20
using errors::TryCatchScope;
21
using v8::Context;
22
using v8::EmbedderGraph;
23
using v8::External;
24
using v8::Function;
25
using v8::FunctionTemplate;
26
using v8::HandleScope;
27
using v8::Integer;
28
using v8::Isolate;
29
using v8::Local;
30
using v8::Message;
31
using v8::NewStringType;
32
using v8::Number;
33
using v8::Object;
34
using v8::Private;
35
using v8::Promise;
36
using v8::PromiseHookType;
37
using v8::StackFrame;
38
using v8::StackTrace;
39
using v8::String;
40
using v8::Symbol;
41
using v8::TracingController;
42
using v8::Undefined;
43
using v8::Value;
44
using worker::Worker;
45
46
#define kTraceCategoryCount 1
47
48
// TODO(@jasnell): Likely useful to move this to util or node_internal to
49
// allow reuse. But since we're not reusing it yet...
50
class TraceEventScope {
51
 public:
52
548868
  TraceEventScope(const char* category,
53
                  const char* name,
54
548868
                  void* id) : category_(category), name_(name), id_(id) {
55

548868
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN0(category_, name_, id_);
56
548868
  }
57
548851
  ~TraceEventScope() {
58

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

3338
  TRACE_EVENT_NESTABLE_ASYNC_END0(
282
    TRACING_CATEGORY_NODE1(environment), "Environment", this);
283
284
  // Dereference all addons that were loaded into this environment.
285
3448
  for (binding::DLib& addon : loaded_addons_) {
286
110
    addon.Close();
287
3338
  }
288
3338
}
289
290
3685
void Environment::Start(const std::vector<std::string>& args,
291
                        const std::vector<std::string>& exec_args,
292
                        bool start_profiler_idle_notifier) {
293
3685
  HandleScope handle_scope(isolate());
294
3685
  Context::Scope context_scope(context());
295
296
7370
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
297
3685
      TRACING_CATEGORY_NODE1(environment)) != 0) {
298
8
    auto traced_value = tracing::TracedValue::Create();
299
8
    traced_value->BeginArray("args");
300
17
    for (const std::string& arg : args)
301
9
      traced_value->AppendString(arg);
302
8
    traced_value->EndArray();
303
8
    traced_value->BeginArray("exec_args");
304
30
    for (const std::string& arg : exec_args)
305
22
      traced_value->AppendString(arg);
306
8
    traced_value->EndArray();
307

8
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(
308
      TRACING_CATEGORY_NODE1(environment),
309
      "Environment", this,
310
8
      "args", std::move(traced_value));
311
  }
312
313
3685
  CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
314
3685
  uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
315
316
3685
  uv_check_init(event_loop(), immediate_check_handle());
317
3685
  uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
318
319
3685
  uv_idle_init(event_loop(), immediate_idle_handle());
320
321
3685
  uv_check_start(immediate_check_handle(), CheckImmediate);
322
323
  // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
324
  // but not all samples are created equal; mark the wall clock time spent in
325
  // epoll_wait() and friends so profiling tools can filter it out.  The samples
326
  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
327
  // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
328
  // probably fortify in the API contract, namely that the last started prepare
329
  // or check watcher runs first.  It's not 100% foolproof; if an add-on starts
330
  // a prepare or check watcher after us, any samples attributed to its callback
331
  // will be recorded with state=IDLE.
332
3685
  uv_prepare_init(event_loop(), &idle_prepare_handle_);
333
3685
  uv_check_init(event_loop(), &idle_check_handle_);
334
3685
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
335
3685
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
336
337
  // Register clean-up cb to be called to clean up the handles
338
  // when the environment is freed, note that they are not cleaned in
339
  // the one environment per process setup, but will be called in
340
  // FreeEnvironment.
341
3685
  RegisterHandleCleanups();
342
343
3685
  if (start_profiler_idle_notifier) {
344
1
    StartProfilerIdleNotifier();
345
  }
346
347
3685
  auto process_template = FunctionTemplate::New(isolate());
348
7370
  process_template->SetClassName(FIXED_ONE_BYTE_STRING(isolate(), "process"));
349
350
7370
  auto process_object = process_template->GetFunction(context())
351
7370
                            .ToLocalChecked()
352
14740
                            ->NewInstance(context())
353
7370
                            .ToLocalChecked();
354
3685
  set_process_object(process_object);
355
356
3685
  SetupProcessObject(this, args, exec_args);
357
358
  static uv_once_t init_once = UV_ONCE_INIT;
359
3685
  uv_once(&init_once, InitThreadLocalOnce);
360
3685
  uv_key_set(&thread_local_env, this);
361
362
#if HAVE_INSPECTOR
363
  // This needs to be set before we start the inspector
364
3685
  Local<Object> obj = Object::New(isolate());
365
14740
  CHECK(obj->SetPrototype(context(), Null(isolate())).FromJust());
366
7370
  set_inspector_console_api_object(obj);
367
#endif  // HAVE_INSPECTOR
368
3685
}
369
370
3685
void Environment::RegisterHandleCleanups() {
371
  HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
372
37055
                                        void* arg) {
373
16685
    handle->data = env;
374
375
33370
    env->CloseHandle(handle, [](uv_handle_t* handle) {});
376
40740
  };
377
378
  RegisterHandleCleanup(
379
3685
      reinterpret_cast<uv_handle_t*>(timer_handle()),
380
      close_and_finish,
381
3685
      nullptr);
382
  RegisterHandleCleanup(
383
3685
      reinterpret_cast<uv_handle_t*>(immediate_check_handle()),
384
      close_and_finish,
385
3685
      nullptr);
386
  RegisterHandleCleanup(
387
3685
      reinterpret_cast<uv_handle_t*>(immediate_idle_handle()),
388
      close_and_finish,
389
3685
      nullptr);
390
  RegisterHandleCleanup(
391
      reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_),
392
      close_and_finish,
393
3685
      nullptr);
394
  RegisterHandleCleanup(
395
      reinterpret_cast<uv_handle_t*>(&idle_check_handle_),
396
      close_and_finish,
397
3685
      nullptr);
398
3685
}
399
400
6793
void Environment::CleanupHandles() {
401
6825
  for (ReqWrap<uv_req_t>* request : req_wrap_queue_)
402
32
    request->Cancel();
403
404
8303
  for (HandleWrap* handle : handle_wrap_queue_)
405
3020
    handle->Close();
406
407
23478
  for (HandleCleanup& hc : handle_cleanup_queue_)
408
16685
    hc.cb_(this, hc.handle_, hc.arg_);
409
6793
  handle_cleanup_queue_.clear();
410
411

33857
  while (handle_cleanup_waiting_ != 0 ||
412

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

3
        return hook.cb_ == fn && hook.arg_ == arg;
552
245
      });
553
242
  if (it != promise_hooks_.end()) {
554
3
    it->enable_count_++;
555
245
    return;
556
  }
557
239
  promise_hooks_.push_back(PromiseHookCallback{fn, arg, 1});
558
559
239
  if (promise_hooks_.size() == 1) {
560
239
    isolate_->SetPromiseHook(EnvPromiseHook);
561
  }
562
}
563
564
62
bool Environment::RemovePromiseHook(promise_hook_func fn, void* arg) {
565
  auto it = std::find_if(
566
      promise_hooks_.begin(), promise_hooks_.end(),
567
62
      [&](const PromiseHookCallback& hook) {
568

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

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

52889
  } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
734
735
52873
  if (env->immediate_info()->ref_count() == 0)
736
78295
    env->ToggleImmediateRef(false);
737
}
738
739
75109
void Environment::ToggleImmediateRef(bool ref) {
740
75109
  if (ref) {
741
    // Idle handle is needed only to stop the event loop from blocking in poll.
742
155776
    uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
743
  } else {
744
25435
    uv_idle_stop(immediate_idle_handle());
745
  }
746
75109
}
747
748
749
105706
Local<Value> Environment::GetNow() {
750
105706
  uv_update_time(event_loop());
751
105706
  uint64_t now = uv_now(event_loop());
752
105706
  CHECK_GE(now, timer_base());
753
105706
  now -= timer_base();
754
105706
  if (now <= 0xffffffff)
755
211412
    return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
756
  else
757
    return Number::New(isolate(), static_cast<double>(now));
758
}
759
760
761
3685
void Environment::set_debug_categories(const std::string& cats, bool enabled) {
762
3685
  std::string debug_categories = cats;
763
3685
  while (!debug_categories.empty()) {
764
1
    std::string::size_type comma_pos = debug_categories.find(',');
765
1
    std::string wanted = ToLower(debug_categories.substr(0, comma_pos));
766
767
#define V(name)                                                          \
768
    {                                                                    \
769
      static const std::string available_category = ToLower(#name);      \
770
      if (available_category.find(wanted) != std::string::npos)          \
771
        set_debug_enabled(DebugCategory::name, enabled);                 \
772
    }
773
774































































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

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

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