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: 502 521 96.4 %
Date: 2020-06-24 22:13:30 Branches: 450 737 61.1 %

Line Branch Exec Source
1
#include "env.h"
2
#include "allocated_buffer-inl.h"
3
#include "async_wrap.h"
4
#include "base_object-inl.h"
5
#include "debug_utils-inl.h"
6
#include "memory_tracker-inl.h"
7
#include "node_buffer.h"
8
#include "node_context_data.h"
9
#include "node_errors.h"
10
#include "node_internals.h"
11
#include "node_options-inl.h"
12
#include "node_process.h"
13
#include "node_v8_platform-inl.h"
14
#include "node_worker.h"
15
#include "req_wrap-inl.h"
16
#include "stream_base.h"
17
#include "tracing/agent.h"
18
#include "tracing/traced_value.h"
19
#include "util-inl.h"
20
#include "v8-profiler.h"
21
22
#include <algorithm>
23
#include <atomic>
24
#include <cstdio>
25
#include <memory>
26
27
namespace node {
28
29
using errors::TryCatchScope;
30
using v8::ArrayBuffer;
31
using v8::Boolean;
32
using v8::Context;
33
using v8::EmbedderGraph;
34
using v8::Function;
35
using v8::FunctionTemplate;
36
using v8::HandleScope;
37
using v8::Integer;
38
using v8::Isolate;
39
using v8::Local;
40
using v8::MaybeLocal;
41
using v8::NewStringType;
42
using v8::Number;
43
using v8::Object;
44
using v8::Private;
45
using v8::Script;
46
using v8::SnapshotCreator;
47
using v8::StackTrace;
48
using v8::String;
49
using v8::Symbol;
50
using v8::TracingController;
51
using v8::TryCatch;
52
using v8::Undefined;
53
using v8::Value;
54
using worker::Worker;
55
56
int const Environment::kNodeContextTag = 0x6e6f64;
57
void* const Environment::kNodeContextTagPtr = const_cast<void*>(
58
    static_cast<const void*>(&Environment::kNodeContextTag));
59
60
1
std::vector<size_t> IsolateData::Serialize(SnapshotCreator* creator) {
61
1
  Isolate* isolate = creator->GetIsolate();
62
1
  std::vector<size_t> indexes;
63
2
  HandleScope handle_scope(isolate);
64
  // XXX(joyeecheung): technically speaking, the indexes here should be
65
  // consecutive and we could just return a range instead of an array,
66
  // but that's not part of the V8 API contract so we use an array
67
  // just to be safe.
68
69
#define VP(PropertyName, StringValue) V(Private, PropertyName)
70
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
71
#define VS(PropertyName, StringValue) V(String, PropertyName)
72
#define V(TypeName, PropertyName)                                              \
73
  indexes.push_back(creator->AddData(PropertyName##_.Get(isolate)));
74
8
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
75
13
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
76
232
  PER_ISOLATE_STRING_PROPERTIES(VS)
77
#undef V
78
#undef VY
79
#undef VS
80
#undef VP
81
54
  for (size_t i = 0; i < AsyncWrap::PROVIDERS_LENGTH; i++)
82
106
    indexes.push_back(creator->AddData(async_wrap_provider(i)));
83
84
2
  return indexes;
85
}
86
87
4330
void IsolateData::DeserializeProperties(const std::vector<size_t>* indexes) {
88
4330
  size_t i = 0;
89
8660
  HandleScope handle_scope(isolate_);
90
91
#define VP(PropertyName, StringValue) V(Private, PropertyName)
92
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
93
#define VS(PropertyName, StringValue) V(String, PropertyName)
94
#define V(TypeName, PropertyName)                                              \
95
  do {                                                                         \
96
    MaybeLocal<TypeName> field =                                               \
97
        isolate_->GetDataFromSnapshotOnce<TypeName>((*indexes)[i++]);          \
98
    if (field.IsEmpty()) {                                                     \
99
      fprintf(stderr, "Failed to deserialize " #PropertyName "\n");            \
100
    }                                                                          \
101
    PropertyName##_.Set(isolate_, field.ToLocalChecked());                     \
102
  } while (0);
103



121240
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
104






207840
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
105



















































































































4000920
  PER_ISOLATE_STRING_PROPERTIES(VS)
106
#undef V
107
#undef VY
108
#undef VS
109
#undef VP
110
111
233820
  for (size_t j = 0; j < AsyncWrap::PROVIDERS_LENGTH; j++) {
112
    MaybeLocal<String> field =
113
458980
        isolate_->GetDataFromSnapshotOnce<String>((*indexes)[i++]);
114
229490
    if (field.IsEmpty()) {
115
      fprintf(stderr, "Failed to deserialize AsyncWrap provider %zu\n", j);
116
    }
117
229490
    async_wrap_providers_[j].Set(isolate_, field.ToLocalChecked());
118
  }
119
4330
}
120
121
389
void IsolateData::CreateProperties() {
122
  // Create string and private symbol properties as internalized one byte
123
  // strings after the platform is properly initialized.
124
  //
125
  // Internalized because it makes property lookups a little faster and
126
  // because the string is created in the old space straight away.  It's going
127
  // to end up in the old space sooner or later anyway but now it doesn't go
128
  // through v8::Eternal's new space handling first.
129
  //
130
  // One byte because our strings are ASCII and we can safely skip V8's UTF-8
131
  // decoding step.
132
133
778
  HandleScope handle_scope(isolate_);
134
135
#define V(PropertyName, StringValue)                                           \
136
  PropertyName##_.Set(                                                         \
137
      isolate_,                                                                \
138
      Private::New(isolate_,                                                   \
139
                   String::NewFromOneByte(                                     \
140
                       isolate_,                                               \
141
                       reinterpret_cast<const uint8_t*>(StringValue),          \
142
                       NewStringType::kInternalized,                           \
143
                       sizeof(StringValue) - 1)                                \
144
                       .ToLocalChecked()));
145
5835
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
146
#undef V
147
#define V(PropertyName, StringValue)                                           \
148
  PropertyName##_.Set(                                                         \
149
      isolate_,                                                                \
150
      Symbol::New(isolate_,                                                    \
151
                  String::NewFromOneByte(                                      \
152
                      isolate_,                                                \
153
                      reinterpret_cast<const uint8_t*>(StringValue),           \
154
                      NewStringType::kInternalized,                            \
155
                      sizeof(StringValue) - 1)                                 \
156
                      .ToLocalChecked()));
157
9725
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
158
#undef V
159
#define V(PropertyName, StringValue)                                           \
160
  PropertyName##_.Set(                                                         \
161
      isolate_,                                                                \
162
      String::NewFromOneByte(isolate_,                                         \
163
                             reinterpret_cast<const uint8_t*>(StringValue),    \
164
                             NewStringType::kInternalized,                     \
165
                             sizeof(StringValue) - 1)                          \
166
          .ToLocalChecked());
167
180107
  PER_ISOLATE_STRING_PROPERTIES(V)
168
#undef V
169
170
  // Create all the provider strings that will be passed to JS. Place them in
171
  // an array so the array index matches the PROVIDER id offset. This way the
172
  // strings can be retrieved quickly.
173
#define V(Provider)                                                           \
174
  async_wrap_providers_[AsyncWrap::PROVIDER_ ## Provider].Set(                \
175
      isolate_,                                                               \
176
      String::NewFromOneByte(                                                 \
177
        isolate_,                                                             \
178
        reinterpret_cast<const uint8_t*>(#Provider),                          \
179
        NewStringType::kInternalized,                                         \
180
        sizeof(#Provider) - 1).ToLocalChecked());
181
41623
  NODE_ASYNC_PROVIDER_TYPES(V)
182
#undef V
183
389
}
184
185
4719
IsolateData::IsolateData(Isolate* isolate,
186
                         uv_loop_t* event_loop,
187
                         MultiIsolatePlatform* platform,
188
                         ArrayBufferAllocator* node_allocator,
189
4719
                         const std::vector<size_t>* indexes)
190
    : isolate_(isolate),
191
      event_loop_(event_loop),
192
4719
      allocator_(isolate->GetArrayBufferAllocator()),
193
9405
      node_allocator_(node_allocator == nullptr ? nullptr
194
4686
                                                : node_allocator->GetImpl()),
195
4719
      uses_node_allocator_(allocator_ == node_allocator_),
196
1198626
      platform_(platform) {
197
4719
  CHECK_NOT_NULL(allocator_);
198
199
9438
  options_.reset(
200
14157
      new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
201
202
4719
  if (indexes == nullptr) {
203
389
    CreateProperties();
204
  } else {
205
4330
    DeserializeProperties(indexes);
206
  }
207
4719
}
208
209
19
void IsolateData::MemoryInfo(MemoryTracker* tracker) const {
210
#define V(PropertyName, StringValue)                                           \
211
  tracker->TrackField(#PropertyName, PropertyName());
212
19
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
213
#undef V
214
215
#define V(PropertyName, StringValue)                                           \
216
  tracker->TrackField(#PropertyName, PropertyName());
217
19
  PER_ISOLATE_STRING_PROPERTIES(V)
218
#undef V
219
220
19
  tracker->TrackField("async_wrap_providers", async_wrap_providers_);
221
222
19
  if (node_allocator_ != nullptr) {
223
    tracker->TrackFieldWithSize(
224
19
        "node_allocator", sizeof(*node_allocator_), "NodeArrayBufferAllocator");
225
  } else {
226
    tracker->TrackFieldWithSize(
227
        "allocator", sizeof(*allocator_), "v8::ArrayBuffer::Allocator");
228
  }
229
  tracker->TrackFieldWithSize(
230
19
      "platform", sizeof(*platform_), "MultiIsolatePlatform");
231
  // TODO(joyeecheung): implement MemoryRetainer in the option classes.
232
19
}
233
234
4337
void InitThreadLocalOnce() {
235
4337
  CHECK_EQ(0, uv_key_create(&Environment::thread_local_env));
236
4337
}
237
238
119
void TrackingTraceStateObserver::UpdateTraceCategoryState() {
239

119
  if (!env_->owns_process_state() || !env_->can_call_into_js()) {
240
    // Ideally, we’d have a consistent story that treats all threads/Environment
241
    // instances equally here. However, tracing is essentially global, and this
242
    // callback is called from whichever thread calls `StartTracing()` or
243
    // `StopTracing()`. The only way to do this in a threadsafe fashion
244
    // seems to be only tracking this from the main thread, and only allowing
245
    // these state modifications from the main thread.
246
68
    return;
247
  }
248
249
111
  bool async_hooks_enabled = (*(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
250
111
                                 TRACING_CATEGORY_NODE1(async_hooks)))) != 0;
251
252
111
  Isolate* isolate = env_->isolate();
253
170
  HandleScope handle_scope(isolate);
254
111
  Local<Function> cb = env_->trace_category_state_function();
255
111
  if (cb.IsEmpty())
256
52
    return;
257
118
  TryCatchScope try_catch(env_);
258
59
  try_catch.SetVerbose(true);
259
118
  Local<Value> args[] = {Boolean::New(isolate, async_hooks_enabled)};
260
177
  USE(cb->Call(env_->context(), Undefined(isolate), arraysize(args), args));
261
}
262
263
4703
void Environment::CreateProperties() {
264
9406
  HandleScope handle_scope(isolate_);
265
4703
  Local<Context> ctx = context();
266
267
  {
268
    Context::Scope context_scope(ctx);
269
4703
    Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
270
14109
    templ->InstanceTemplate()->SetInternalFieldCount(
271
4703
        BaseObject::kInternalFieldCount);
272
9406
    templ->Inherit(BaseObject::GetConstructorTemplate(this));
273
274
4703
    set_binding_data_ctor_template(templ);
275
  }
276
277
  // Store primordials setup by the per-context script in the environment.
278
  Local<Object> per_context_bindings =
279
9406
      GetPerContextExports(ctx).ToLocalChecked();
280
  Local<Value> primordials =
281
14109
      per_context_bindings->Get(ctx, primordials_string()).ToLocalChecked();
282
4703
  CHECK(primordials->IsObject());
283
4703
  set_primordials(primordials.As<Object>());
284
285
  Local<Object> process_object =
286
9406
      node::CreateProcessObject(this).FromMaybe(Local<Object>());
287
4703
  set_process_object(process_object);
288
4703
}
289
290
4703
std::string GetExecPath(const std::vector<std::string>& argv) {
291
  char exec_path_buf[2 * PATH_MAX];
292
4703
  size_t exec_path_len = sizeof(exec_path_buf);
293
4703
  std::string exec_path;
294
4703
  if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
295
4703
    exec_path = std::string(exec_path_buf, exec_path_len);
296
  } else {
297
    exec_path = argv[0];
298
  }
299
300
  // On OpenBSD process.execPath will be relative unless we
301
  // get the full path before process.execPath is used.
302
#if defined(__OpenBSD__)
303
  uv_fs_t req;
304
  req.ptr = nullptr;
305
  if (0 ==
306
      uv_fs_realpath(nullptr, &req, exec_path.c_str(), nullptr)) {
307
    CHECK_NOT_NULL(req.ptr);
308
    exec_path = std::string(static_cast<char*>(req.ptr));
309
  }
310
  uv_fs_req_cleanup(&req);
311
#endif
312
313
4703
  return exec_path;
314
}
315
316
4703
Environment::Environment(IsolateData* isolate_data,
317
                         Local<Context> context,
318
                         const std::vector<std::string>& args,
319
                         const std::vector<std::string>& exec_args,
320
                         EnvironmentFlags::Flags flags,
321
4703
                         ThreadId thread_id)
322
4703
    : isolate_(context->GetIsolate()),
323
      isolate_data_(isolate_data),
324
      immediate_info_(context->GetIsolate()),
325
      tick_info_(context->GetIsolate()),
326
4703
      timer_base_(uv_now(isolate_data->event_loop())),
327
      exec_argv_(exec_args),
328
      argv_(args),
329
      exec_path_(GetExecPath(args)),
330
4703
      should_abort_on_uncaught_toggle_(isolate_, 1),
331
4703
      stream_base_state_(isolate_, StreamBase::kNumStreamBaseStateFields),
332
      flags_(flags),
333
9070
      thread_id_(thread_id.id == static_cast<uint64_t>(-1) ?
334
4367
          AllocateEnvironmentThreadId().id : thread_id.id),
335
418567
      context_(context->GetIsolate(), context) {
336
  // We'll be creating new objects so make sure we've entered the context.
337
9406
  HandleScope handle_scope(isolate());
338
  Context::Scope context_scope(context);
339
340
  // Set some flags if only kDefaultFlags was passed. This can make API version
341
  // transitions easier for embedders.
342
4703
  if (flags_ & EnvironmentFlags::kDefaultFlags) {
343
8732
    flags_ = flags_ |
344
4366
        EnvironmentFlags::kOwnsProcessState |
345
        EnvironmentFlags::kOwnsInspector;
346
  }
347
348
4703
  set_env_vars(per_process::system_environment);
349
4703
  enabled_debug_list_.Parse(this);
350
351
  // We create new copies of the per-Environment option sets, so that it is
352
  // easier to modify them after Environment creation. The defaults are
353
  // part of the per-Isolate option set, for which in turn the defaults are
354
  // part of the per-process option set.
355
4703
  options_.reset(new EnvironmentOptions(*isolate_data->options()->per_env));
356
9406
  inspector_host_port_.reset(
357
14109
      new ExclusiveAccess<HostPort>(options_->debug_options().host_port));
358
359
#if HAVE_INSPECTOR
360
  // We can only create the inspector agent after having cloned the options.
361
4703
  inspector_agent_ = std::make_unique<inspector::Agent>(this);
362
#endif
363
364
4703
  AssignToContext(context, ContextInfo(""));
365
366
  static uv_once_t init_once = UV_ONCE_INIT;
367
4703
  uv_once(&init_once, InitThreadLocalOnce);
368
4703
  uv_key_set(&thread_local_env, this);
369
370
4703
  if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) {
371
4703
    trace_state_observer_ = std::make_unique<TrackingTraceStateObserver>(this);
372
4703
    if (TracingController* tracing_controller = writer->GetTracingController())
373
4666
      tracing_controller->AddTraceStateObserver(trace_state_observer_.get());
374
  }
375
376
4703
  destroy_async_id_list_.reserve(512);
377
378
  performance_state_ =
379
4703
      std::make_unique<performance::PerformanceState>(isolate());
380
4703
  performance_state_->Mark(
381
4703
      performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT);
382
4703
  performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
383
9406
                           per_process::node_start_time);
384
4703
  performance_state_->Mark(
385
      performance::NODE_PERFORMANCE_MILESTONE_V8_START,
386
9406
      performance::performance_v8_start);
387
388
4703
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
389
          TRACING_CATEGORY_NODE1(environment)) != 0) {
390
16
    auto traced_value = tracing::TracedValue::Create();
391
8
    traced_value->BeginArray("args");
392
8
    for (const std::string& arg : args) traced_value->AppendString(arg);
393
8
    traced_value->EndArray();
394
8
    traced_value->BeginArray("exec_args");
395
8
    for (const std::string& arg : exec_args) traced_value->AppendString(arg);
396
8
    traced_value->EndArray();
397

16
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
398
                                      "Environment",
399
                                      this,
400
                                      "args",
401
                                      std::move(traced_value));
402
  }
403
404
  // By default, always abort when --abort-on-uncaught-exception was passed.
405
4703
  should_abort_on_uncaught_toggle_[0] = 1;
406
407
4703
  if (options_->no_force_async_hooks_checks) {
408
1
    async_hooks_.no_force_checks();
409
  }
410
411
  // TODO(joyeecheung): deserialize when the snapshot covers the environment
412
  // properties.
413
4703
  CreateProperties();
414
415
  // This adjusts the return value of base_object_count() so that tests that
416
  // check the count do not have to account for internally created BaseObjects.
417
4703
  initial_base_object_count_ = base_object_count();
418
4703
}
419
420
355491
Environment::~Environment() {
421
4233
  if (Environment** interrupt_data = interrupt_data_.load()) {
422
    // There are pending RequestInterrupt() callbacks. Tell them not to run,
423
    // then force V8 to run interrupts by compiling and running an empty script
424
    // so as not to leak memory.
425
10
    *interrupt_data = nullptr;
426
427
20
    Isolate::AllowJavascriptExecutionScope allow_js_here(isolate());
428
20
    HandleScope handle_scope(isolate());
429
20
    TryCatch try_catch(isolate());
430
10
    Context::Scope context_scope(context());
431
432
#ifdef DEBUG
433
    bool consistency_check = false;
434
    isolate()->RequestInterrupt([](Isolate*, void* data) {
435
      *static_cast<bool*>(data) = true;
436
    }, &consistency_check);
437
#endif
438
439
    Local<Script> script;
440
30
    if (Script::Compile(context(), String::Empty(isolate())).ToLocal(&script))
441
20
      USE(script->Run(context()));
442
443
    DCHECK(consistency_check);
444
  }
445
446
  // FreeEnvironment() should have set this.
447
4233
  CHECK(is_stopping());
448
449
4233
  isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
450
4233
      BuildEmbedderGraph, this);
451
452
8466
  HandleScope handle_scope(isolate());
453
454
#if HAVE_INSPECTOR
455
  // Destroy inspector agent before erasing the context. The inspector
456
  // destructor depends on the context still being accessible.
457
4233
  inspector_agent_.reset();
458
#endif
459
460
12699
  context()->SetAlignedPointerInEmbedderData(
461
4233
      ContextEmbedderIndex::kEnvironment, nullptr);
462
463
4233
  if (trace_state_observer_) {
464
4233
    tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
465
4233
    CHECK_NOT_NULL(writer);
466
4233
    if (TracingController* tracing_controller = writer->GetTracingController())
467
4198
      tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get());
468
  }
469
470

8466
  TRACE_EVENT_NESTABLE_ASYNC_END0(
471
    TRACING_CATEGORY_NODE1(environment), "Environment", this);
472
473
  // Do not unload addons on the main thread. Some addons need to retain memory
474
  // beyond the Environment's lifetime, and unloading them early would break
475
  // them; with Worker threads, we have the opportunity to be stricter.
476
  // Also, since the main thread usually stops just before the process exits,
477
  // this is far less relevant here.
478
4233
  if (!is_main_thread()) {
479
    // Dereference all addons that were loaded into this environment.
480
347
    for (binding::DLib& addon : loaded_addons_) {
481
12
      addon.Close();
482
    }
483
  }
484
485
4233
  CHECK_EQ(base_object_count_, 0);
486
8466
}
487
488
4679
void Environment::InitializeLibuv(bool start_profiler_idle_notifier) {
489
9358
  HandleScope handle_scope(isolate());
490
4679
  Context::Scope context_scope(context());
491
492
4679
  CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
493
4679
  uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
494
495
4679
  uv_check_init(event_loop(), immediate_check_handle());
496
4679
  uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
497
498
4679
  uv_idle_init(event_loop(), immediate_idle_handle());
499
500
4679
  uv_check_start(immediate_check_handle(), CheckImmediate);
501
502
  // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
503
  // but not all samples are created equal; mark the wall clock time spent in
504
  // epoll_wait() and friends so profiling tools can filter it out.  The samples
505
  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
506
  // TODO(bnoordhuis) Depends on a libuv implementation detail that we should
507
  // probably fortify in the API contract, namely that the last started prepare
508
  // or check watcher runs first.  It's not 100% foolproof; if an add-on starts
509
  // a prepare or check watcher after us, any samples attributed to its callback
510
  // will be recorded with state=IDLE.
511
4679
  uv_prepare_init(event_loop(), &idle_prepare_handle_);
512
4679
  uv_check_init(event_loop(), &idle_check_handle_);
513
9358
  uv_async_init(
514
      event_loop(),
515
      &task_queues_async_,
516
7189
      [](uv_async_t* async) {
517
2510
        Environment* env = ContainerOf(
518
1255
            &Environment::task_queues_async_, async);
519
1255
        env->RunAndClearNativeImmediates();
520
11864
      });
521
4679
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
522
4679
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
523
4679
  uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
524
525
  {
526
9358
    Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
527
4679
    task_queues_async_initialized_ = true;
528

9358
    if (native_immediates_threadsafe_.size() > 0 ||
529
4679
        native_immediates_interrupts_.size() > 0) {
530
      uv_async_send(&task_queues_async_);
531
    }
532
  }
533
534
  // Register clean-up cb to be called to clean up the handles
535
  // when the environment is freed, note that they are not cleaned in
536
  // the one environment per process setup, but will be called in
537
  // FreeEnvironment.
538
4679
  RegisterHandleCleanups();
539
540
4679
  if (start_profiler_idle_notifier) {
541
3
    StartProfilerIdleNotifier();
542
  }
543
4679
}
544
545
85
void Environment::ExitEnv() {
546
85
  set_can_call_into_js(false);
547
85
  set_stopping(true);
548
85
  isolate_->TerminateExecution();
549
170
  SetImmediateThreadsafe([](Environment* env) { uv_stop(env->event_loop()); });
550
85
}
551
552
4679
void Environment::RegisterHandleCleanups() {
553
  HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
554
55182
                                        void* arg) {
555
25251
    handle->data = env;
556
557
50505
    env->CloseHandle(handle, [](uv_handle_t* handle) {
558
#ifdef DEBUG
559
      memset(handle, 0xab, uv_handle_size(handle->type));
560
#endif
561
50504
    });
562
59862
  };
563
564
28074
  auto register_handle = [&](uv_handle_t* handle) {
565
28074
    RegisterHandleCleanup(handle, close_and_finish, nullptr);
566
32753
  };
567
4679
  register_handle(reinterpret_cast<uv_handle_t*>(timer_handle()));
568
4679
  register_handle(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
569
4679
  register_handle(reinterpret_cast<uv_handle_t*>(immediate_idle_handle()));
570
4679
  register_handle(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
571
4679
  register_handle(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
572
4679
  register_handle(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
573
4679
}
574
575
8464
void Environment::CleanupHandles() {
576
  {
577
16930
    Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
578
8466
    task_queues_async_initialized_ = false;
579
  }
580
581
  Isolate::DisallowJavascriptExecutionScope disallow_js(isolate(),
582
16932
      Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
583
584
8464
  RunAndClearNativeImmediates(true /* skip unrefed SetImmediate()s */);
585
586
8505
  for (ReqWrapBase* request : req_wrap_queue_)
587
39
    request->Cancel();
588
589
10720
  for (HandleWrap* handle : handle_wrap_queue_)
590
4502
    handle->Close();
591
592
33716
  for (HandleCleanup& hc : handle_cleanup_queue_)
593
25251
    hc.cb_(this, hc.handle_, hc.arg_);
594
8466
  handle_cleanup_queue_.clear();
595
596

49775
  while (handle_cleanup_waiting_ != 0 ||
597

25058
         request_waiting_ != 0 ||
598
8466
         !handle_wrap_queue_.IsEmpty()) {
599
8126
    uv_run(event_loop(), UV_RUN_ONCE);
600
  }
601
8466
}
602
603
3
void Environment::StartProfilerIdleNotifier() {
604
3
  if (profiler_idle_notifier_started_)
605
    return;
606
607
3
  profiler_idle_notifier_started_ = true;
608
609
231
  uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
610
111
    Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
611
111
    env->isolate()->SetIdle(true);
612
228
  });
613
614
229
  uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
615
110
    Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
616
110
    env->isolate()->SetIdle(false);
617
226
  });
618
}
619
620
void Environment::StopProfilerIdleNotifier() {
621
  profiler_idle_notifier_started_ = false;
622
  uv_prepare_stop(&idle_prepare_handle_);
623
  uv_check_stop(&idle_check_handle_);
624
}
625
626
317629
void Environment::PrintSyncTrace() const {
627
317629
  if (!trace_sync_io_) return;
628
629
2
  HandleScope handle_scope(isolate());
630
631
1
  fprintf(
632
1
      stderr, "(node:%d) WARNING: Detected use of sync API\n", uv_os_getpid());
633
1
  PrintStackTrace(isolate(),
634
                  StackTrace::CurrentStackTrace(
635
1
                      isolate(), stack_trace_limit(), StackTrace::kDetailed));
636
}
637
638
4232
void Environment::RunCleanup() {
639
4232
  started_cleanup_ = true;
640
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
641
8465
                              "RunCleanup", this);
642
4231
  bindings_.clear();
643
4233
  initial_base_object_count_ = 0;
644
4233
  CleanupHandles();
645
646
12698
  while (!cleanup_hooks_.empty()) {
647
    // Copy into a vector, since we can't sort an unordered_set in-place.
648
    std::vector<CleanupHookCallback> callbacks(
649
8465
        cleanup_hooks_.begin(), cleanup_hooks_.end());
650
    // We can't erase the copied elements from `cleanup_hooks_` yet, because we
651
    // need to be able to check whether they were un-scheduled by another hook.
652
653
8466
    std::sort(callbacks.begin(), callbacks.end(),
654
755247
              [](const CleanupHookCallback& a, const CleanupHookCallback& b) {
655
      // Sort in descending order so that the most recently inserted callbacks
656
      // are run first.
657
755247
      return a.insertion_order_counter_ > b.insertion_order_counter_;
658
759480
    });
659
660
98548
    for (const CleanupHookCallback& cb : callbacks) {
661
94315
      if (cleanup_hooks_.count(cb) == 0) {
662
        // This hook was removed from the `cleanup_hooks_` set during another
663
        // hook that was run earlier. Nothing to do here.
664
635
        continue;
665
      }
666
667
93680
      cb.fn_(cb.arg_);
668
93679
      cleanup_hooks_.erase(cb);
669
    }
670
4233
    CleanupHandles();
671
  }
672
4233
}
673
674
4761
void Environment::RunAtExitCallbacks() {
675
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
676
9523
                              "AtExit", this);
677
14149
  for (ExitCallback at_exit : at_exit_functions_) {
678
9389
    at_exit.cb_(at_exit.arg_);
679
  }
680
4762
  at_exit_functions_.clear();
681
4761
}
682
683
9409
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
684
9409
  at_exit_functions_.push_front(ExitCallback{cb, arg});
685
9409
}
686
687
423945
void Environment::RunAndClearInterrupts() {
688
430478
  while (native_immediates_interrupts_.size() > 0) {
689
13066
    NativeImmediateQueue queue;
690
    {
691
13066
      Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
692
6533
      queue.ConcatMove(std::move(native_immediates_interrupts_));
693
    }
694
6533
    DebugSealHandleScope seal_handle_scope(isolate());
695
696
19605
    while (auto head = queue.Shift())
697
13072
      head->Call(this);
698
  }
699
417417
}
700
701
411033
void Environment::RunAndClearNativeImmediates(bool only_refed) {
702
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
703
822067
                              "RunAndClearNativeImmediates", this);
704
411035
  size_t ref_count = 0;
705
706
  // Handle interrupts first. These functions are not allowed to throw
707
  // exceptions, so we do not need to handle that.
708
411035
  RunAndClearInterrupts();
709
710
822072
  auto drain_list = [&](NativeImmediateQueue* queue) {
711
1700486
    TryCatchScope try_catch(this);
712
822076
    DebugSealHandleScope seal_handle_scope(isolate());
713
935051
    while (auto head = queue->Shift()) {
714
56495
      bool is_refed = head->flags() & CallbackFlags::kRefed;
715
56495
      if (is_refed)
716
34140
        ref_count++;
717
718

56495
      if (is_refed || !only_refed)
719
112678
        head->Call(this);
720
721
56491
      head.reset();  // Destroy now so that this is also observed by try_catch.
722
723
56491
      if (UNLIKELY(try_catch.HasCaught())) {
724

3
        if (!try_catch.HasTerminated() && can_call_into_js())
725
1
          errors::TriggerUncaughtException(isolate(), try_catch);
726
727
2
        return true;
728
      }
729
56489
    }
730
822071
    return false;
731
411035
  };
732
411036
  while (drain_list(&native_immediates_)) {}
733
734
411035
  immediate_info()->ref_count_dec(ref_count);
735
736
411038
  if (immediate_info()->ref_count() == 0)
737
381214
    ToggleImmediateRef(false);
738
739
  // It is safe to check .size() first, because there is a causal relationship
740
  // between pushes to the threadsafe immediate list and this function being
741
  // called. For the common case, it's worth checking the size first before
742
  // establishing a mutex lock.
743
  // This is intentionally placed after the `ref_count` handling, because when
744
  // refed threadsafe immediates are created, they are not counted towards the
745
  // count in immediate_info() either.
746
822069
  NativeImmediateQueue threadsafe_immediates;
747
411035
  if (native_immediates_threadsafe_.size() > 0) {
748
1020
    Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
749
510
    threadsafe_immediates.ConcatMove(std::move(native_immediates_threadsafe_));
750
  }
751
411039
  while (drain_list(&threadsafe_immediates)) {}
752
411033
}
753
754
6539
void Environment::RequestInterruptFromV8() {
755
  // The Isolate may outlive the Environment, so some logic to handle the
756
  // situation in which the Environment is destroyed before the handler runs
757
  // is required.
758
759
  // We allocate a new pointer to a pointer to this Environment instance, and
760
  // try to set it as interrupt_data_. If interrupt_data_ was already set, then
761
  // callbacks are already scheduled to run and we can delete our own pointer
762
  // and just return. If it was nullptr previously, the Environment** is stored;
763
  // ~Environment sets the Environment* contained in it to nullptr, so that
764
  // the callback can check whether ~Environment has already run and it is thus
765
  // not safe to access the Environment instance itself.
766
6539
  Environment** interrupt_data = new Environment*(this);
767
6539
  Environment** dummy = nullptr;
768
6539
  if (!interrupt_data_.compare_exchange_strong(dummy, interrupt_data)) {
769
273
    delete interrupt_data;
770
273
    return;  // Already scheduled.
771
  }
772
773
31316
  isolate()->RequestInterrupt([](Isolate* isolate, void* data) {
774
12508
    std::unique_ptr<Environment*> env_ptr { static_cast<Environment**>(data) };
775
6259
    Environment* env = *env_ptr;
776
6259
    if (env == nullptr) {
777
      // The Environment has already been destroyed. That should be okay; any
778
      // callback added before the Environment shuts down would have been
779
      // handled during cleanup.
780
10
      return;
781
    }
782
6249
    env->interrupt_data_.store(nullptr);
783
6249
    env->RunAndClearInterrupts();
784
18791
  }, interrupt_data);
785
}
786
787
5678
void Environment::ScheduleTimer(int64_t duration_ms) {
788
5678
  if (started_cleanup_) return;
789
5678
  uv_timer_start(timer_handle(), RunTimers, duration_ms, 0);
790
}
791
792
1110
void Environment::ToggleTimerRef(bool ref) {
793
1110
  if (started_cleanup_) return;
794
795
1110
  if (ref) {
796
769
    uv_ref(reinterpret_cast<uv_handle_t*>(timer_handle()));
797
  } else {
798
341
    uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
799
  }
800
}
801
802
4601
void Environment::RunTimers(uv_timer_t* handle) {
803
4601
  Environment* env = Environment::from_timer_handle(handle);
804
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
805
9190
                              "RunTimers", env);
806
807
4601
  if (!env->can_call_into_js())
808
    return;
809
810
9190
  HandleScope handle_scope(env->isolate());
811
9190
  Context::Scope context_scope(env->context());
812
813
4601
  Local<Object> process = env->process_object();
814
9190
  InternalCallbackScope scope(env, process, {0, 0});
815
816
4601
  Local<Function> cb = env->timers_callback_function();
817
  MaybeLocal<Value> ret;
818
4601
  Local<Value> arg = env->GetNow();
819
  // This code will loop until all currently due timers will process. It is
820
  // impossible for us to end up in an infinite loop due to how the JS-side
821
  // is structured.
822
4623
  do {
823
9254
    TryCatchScope try_catch(env);
824
4632
    try_catch.SetVerbose(true);
825
9264
    ret = cb->Call(env->context(), process, 1, &arg);
826

4623
  } while (ret.IsEmpty() && env->can_call_into_js());
827
828
  // NOTE(apapirovski): If it ever becomes possible that `call_into_js` above
829
  // is reset back to `true` after being previously set to `false` then this
830
  // code becomes invalid and needs to be rewritten. Otherwise catastrophic
831
  // timers corruption will occur and all timers behaviour will become
832
  // entirely unpredictable.
833
4592
  if (ret.IsEmpty())
834
3
    return;
835
836
  // To allow for less JS-C++ boundary crossing, the value returned from JS
837
  // serves a few purposes:
838
  // 1. If it's 0, no more timers exist and the handle should be unrefed
839
  // 2. If it's > 0, the value represents the next timer's expiry and there
840
  //    is at least one timer remaining that is refed.
841
  // 3. If it's < 0, the absolute value represents the next timer's expiry
842
  //    and there are no timers that are refed.
843
  int64_t expiry_ms =
844
18356
      ret.ToLocalChecked()->IntegerValue(env->context()).FromJust();
845
846
4589
  uv_handle_t* h = reinterpret_cast<uv_handle_t*>(handle);
847
848
4589
  if (expiry_ms != 0) {
849
    int64_t duration_ms =
850
4260
        llabs(expiry_ms) - (uv_now(env->event_loop()) - env->timer_base());
851
852
4260
    env->ScheduleTimer(duration_ms > 0 ? duration_ms : 1);
853
854
4260
    if (expiry_ms > 0)
855
3808
      uv_ref(h);
856
    else
857
452
      uv_unref(h);
858
  } else {
859
329
    uv_unref(h);
860
  }
861
}
862
863
864
401316
void Environment::CheckImmediate(uv_check_t* handle) {
865
401316
  Environment* env = Environment::from_immediate_check_handle(handle);
866
  TraceEventScope trace_scope(TRACING_CATEGORY_NODE1(environment),
867
431070
                              "CheckImmediate", env);
868
869
431069
  HandleScope scope(env->isolate());
870
431069
  Context::Scope context_scope(env->context());
871
872
401317
  env->RunAndClearNativeImmediates();
873
874

401317
  if (env->immediate_info()->count() == 0 || !env->can_call_into_js())
875
371550
    return;
876
877
30309
  do {
878
60629
    MakeCallback(env->isolate(),
879
                 env->process_object(),
880
                 env->immediate_callback_function(),
881
                 0,
882
                 nullptr,
883
30323
                 {0, 0}).ToLocalChecked();
884

30309
  } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
885
886
29753
  if (env->immediate_info()->ref_count() == 0)
887
4308
    env->ToggleImmediateRef(false);
888
}
889
890
437574
void Environment::ToggleImmediateRef(bool ref) {
891
437574
  if (started_cleanup_) return;
892
893
429111
  if (ref) {
894
    // Idle handle is needed only to stop the event loop from blocking in poll.
895
156708
    uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
896
  } else {
897
377078
    uv_idle_stop(immediate_idle_handle());
898
  }
899
}
900
901
902
21046
Local<Value> Environment::GetNow() {
903
21046
  uv_update_time(event_loop());
904
21046
  uint64_t now = uv_now(event_loop());
905
21046
  CHECK_GE(now, timer_base());
906
21046
  now -= timer_base();
907
21046
  if (now <= 0xffffffff)
908
42091
    return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
909
  else
910
    return Number::New(isolate(), static_cast<double>(now));
911
}
912
913
28
void CollectExceptionInfo(Environment* env,
914
                          Local<Object> obj,
915
                          int errorno,
916
                          const char* err_string,
917
                          const char* syscall,
918
                          const char* message,
919
                          const char* path,
920
                          const char* dest) {
921
56
  obj->Set(env->context(),
922
           env->errno_string(),
923
140
           Integer::New(env->isolate(), errorno)).Check();
924
925
56
  obj->Set(env->context(), env->code_string(),
926
140
           OneByteString(env->isolate(), err_string)).Check();
927
928
28
  if (message != nullptr) {
929
56
    obj->Set(env->context(), env->message_string(),
930
140
             OneByteString(env->isolate(), message)).Check();
931
  }
932
933
  Local<Value> path_buffer;
934
28
  if (path != nullptr) {
935
    path_buffer =
936
      Buffer::Copy(env->isolate(), path, strlen(path)).ToLocalChecked();
937
    obj->Set(env->context(), env->path_string(), path_buffer).Check();
938
  }
939
940
  Local<Value> dest_buffer;
941
28
  if (dest != nullptr) {
942
    dest_buffer =
943
      Buffer::Copy(env->isolate(), dest, strlen(dest)).ToLocalChecked();
944
    obj->Set(env->context(), env->dest_string(), dest_buffer).Check();
945
  }
946
947
28
  if (syscall != nullptr) {
948
56
    obj->Set(env->context(), env->syscall_string(),
949
140
             OneByteString(env->isolate(), syscall)).Check();
950
  }
951
28
}
952
953
28
void Environment::CollectUVExceptionInfo(Local<Value> object,
954
                                         int errorno,
955
                                         const char* syscall,
956
                                         const char* message,
957
                                         const char* path,
958
                                         const char* dest) {
959

28
  if (!object->IsObject() || errorno == 0)
960
    return;
961
962
28
  Local<Object> obj = object.As<Object>();
963
28
  const char* err_string = uv_err_name(errorno);
964
965

28
  if (message == nullptr || message[0] == '\0') {
966
28
    message = uv_strerror(errorno);
967
  }
968
969
  node::CollectExceptionInfo(this, obj, errorno, err_string,
970
28
                             syscall, message, path, dest);
971
}
972
973
19
void ImmediateInfo::MemoryInfo(MemoryTracker* tracker) const {
974
19
  tracker->TrackField("fields", fields_);
975
19
}
976
977
19
void TickInfo::MemoryInfo(MemoryTracker* tracker) const {
978
19
  tracker->TrackField("fields", fields_);
979
19
}
980
981
19
void AsyncHooks::MemoryInfo(MemoryTracker* tracker) const {
982
19
  tracker->TrackField("async_ids_stack", async_ids_stack_);
983
19
  tracker->TrackField("fields", fields_);
984
19
  tracker->TrackField("async_id_fields", async_id_fields_);
985
19
}
986
987
4
void AsyncHooks::grow_async_ids_stack() {
988
4
  async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
989
990
12
  env()->async_hooks_binding()->Set(
991
      env()->context(),
992
      env()->async_ids_stack_string(),
993
20
      async_ids_stack_.GetJSArray()).Check();
994
4
}
995
996
uv_key_t Environment::thread_local_env = {};
997
998
509
void Environment::Exit(int exit_code) {
999
509
  if (options()->trace_exit) {
1000
4
    HandleScope handle_scope(isolate());
1001
1002
2
    if (is_main_thread()) {
1003
1
      fprintf(stderr, "(node:%d) ", uv_os_getpid());
1004
    } else {
1005
1
      fprintf(stderr, "(node:%d, thread:%" PRIu64 ") ",
1006
1
              uv_os_getpid(), thread_id());
1007
    }
1008
1009
    fprintf(
1010
2
        stderr, "WARNING: Exited the environment with code %d\n", exit_code);
1011
2
    PrintStackTrace(isolate(),
1012
                    StackTrace::CurrentStackTrace(
1013
2
                        isolate(), stack_trace_limit(), StackTrace::kDetailed));
1014
  }
1015
509
  process_exit_handler_(this, exit_code);
1016
44
}
1017
1018
4723
void Environment::stop_sub_worker_contexts() {
1019
  DCHECK_EQ(Isolate::GetCurrent(), isolate());
1020
1021
4749
  while (!sub_worker_contexts_.empty()) {
1022
26
    Worker* w = *sub_worker_contexts_.begin();
1023
26
    remove_sub_worker_context(w);
1024
26
    w->Exit(1);
1025
26
    w->JoinThread();
1026
  }
1027
4696
}
1028
1029
2
Environment* Environment::worker_parent_env() const {
1030
2
  if (worker_context() == nullptr) return nullptr;
1031
  return worker_context()->env();
1032
}
1033
1034
19
void Environment::BuildEmbedderGraph(Isolate* isolate,
1035
                                     EmbedderGraph* graph,
1036
                                     void* data) {
1037
38
  MemoryTracker tracker(isolate, graph);
1038
19
  Environment* env = static_cast<Environment*>(data);
1039
19
  tracker.Track(env);
1040
385
  env->ForEachBaseObject([&](BaseObject* obj) {
1041
347
    if (obj->IsDoneInitializing())
1042
344
      tracker.Track(obj);
1043
366
  });
1044
19
}
1045
1046
19
inline size_t Environment::SelfSize() const {
1047
19
  size_t size = sizeof(*this);
1048
  // Remove non pointer fields that will be tracked in MemoryInfo()
1049
  // TODO(joyeecheung): refactor the MemoryTracker interface so
1050
  // this can be done for common types within the Track* calls automatically
1051
  // if a certain scope is entered.
1052
19
  size -= sizeof(async_hooks_);
1053
19
  size -= sizeof(tick_info_);
1054
19
  size -= sizeof(immediate_info_);
1055
19
  return size;
1056
}
1057
1058
19
void Environment::MemoryInfo(MemoryTracker* tracker) const {
1059
  // Iteratable STLs have their own sizes subtracted from the parent
1060
  // by default.
1061
19
  tracker->TrackField("isolate_data", isolate_data_);
1062
19
  tracker->TrackField("native_modules_with_cache", native_modules_with_cache);
1063
19
  tracker->TrackField("native_modules_without_cache",
1064
19
                      native_modules_without_cache);
1065
19
  tracker->TrackField("destroy_async_id_list", destroy_async_id_list_);
1066
19
  tracker->TrackField("exec_argv", exec_argv_);
1067
19
  tracker->TrackField("should_abort_on_uncaught_toggle",
1068
19
                      should_abort_on_uncaught_toggle_);
1069
19
  tracker->TrackField("stream_base_state", stream_base_state_);
1070
19
  tracker->TrackFieldWithSize(
1071
38
      "cleanup_hooks", cleanup_hooks_.size() * sizeof(CleanupHookCallback));
1072
19
  tracker->TrackField("async_hooks", async_hooks_);
1073
19
  tracker->TrackField("immediate_info", immediate_info_);
1074
19
  tracker->TrackField("tick_info", tick_info_);
1075
1076
#define V(PropertyName, TypeName)                                              \
1077
  tracker->TrackField(#PropertyName, PropertyName());
1078
19
  ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
1079
#undef V
1080
1081
  // FIXME(joyeecheung): track other fields in Environment.
1082
  // Currently MemoryTracker is unable to track these
1083
  // correctly:
1084
  // - Internal types that do not implement MemoryRetainer yet
1085
  // - STL containers with MemoryRetainer* inside
1086
  // - STL containers with numeric types inside that should not have their
1087
  //   nodes elided e.g. numeric keys in maps.
1088
  // We also need to make sure that when we add a non-pointer field as its own
1089
  // node, we shift its sizeof() size out of the Environment node.
1090
19
}
1091
1092
600074
void Environment::RunWeakRefCleanup() {
1093
600074
  isolate()->ClearKeptObjects();
1094
600075
}
1095
1096
// Not really any better place than env.cc at this moment.
1097
88928
void BaseObject::DeleteMe(void* data) {
1098
88928
  BaseObject* self = static_cast<BaseObject*>(data);
1099

91330
  if (self->has_pointer_data() &&
1100
2402
      self->pointer_data()->strong_ptr_count > 0) {
1101
164
    return self->Detach();
1102
  }
1103
88765
  delete self;
1104
}
1105
1106
284
bool BaseObject::IsDoneInitializing() const { return true; }
1107
1108
344
Local<Object> BaseObject::WrappedObject() const {
1109
344
  return object();
1110
}
1111
1112
688
bool BaseObject::IsRootNode() const {
1113
1376
  return !persistent_handle_.IsWeak();
1114
}
1115
1116
62182
Local<FunctionTemplate> BaseObject::GetConstructorTemplate(Environment* env) {
1117
62182
  Local<FunctionTemplate> tmpl = env->base_object_ctor_template();
1118
62182
  if (tmpl.IsEmpty()) {
1119
4703
    tmpl = env->NewFunctionTemplate(nullptr);
1120
9406
    tmpl->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "BaseObject"));
1121
4703
    env->set_base_object_ctor_template(tmpl);
1122
  }
1123
62183
  return tmpl;
1124
}
1125
1126
}  // namespace node