GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: env.cc Lines: 840 892 94.2 %
Date: 2022-12-31 04:22:30 Branches: 824 1436 57.4 %

Line Branch Exec Source
1
#include "env.h"
2
#include "async_wrap.h"
3
#include "base_object-inl.h"
4
#include "debug_utils-inl.h"
5
#include "diagnosticfilename-inl.h"
6
#include "memory_tracker-inl.h"
7
#include "node_buffer.h"
8
#include "node_context_data.h"
9
#include "node_contextify.h"
10
#include "node_errors.h"
11
#include "node_internals.h"
12
#include "node_options-inl.h"
13
#include "node_process-inl.h"
14
#include "node_v8_platform-inl.h"
15
#include "node_worker.h"
16
#include "req_wrap-inl.h"
17
#include "stream_base.h"
18
#include "tracing/agent.h"
19
#include "tracing/traced_value.h"
20
#include "util-inl.h"
21
#include "v8-profiler.h"
22
23
#include <algorithm>
24
#include <atomic>
25
#include <cinttypes>
26
#include <cstdio>
27
#include <iostream>
28
#include <limits>
29
#include <memory>
30
31
namespace node {
32
33
using errors::TryCatchScope;
34
using v8::Array;
35
using v8::Boolean;
36
using v8::Context;
37
using v8::EmbedderGraph;
38
using v8::EscapableHandleScope;
39
using v8::Function;
40
using v8::FunctionTemplate;
41
using v8::HandleScope;
42
using v8::HeapProfiler;
43
using v8::HeapSpaceStatistics;
44
using v8::Integer;
45
using v8::Isolate;
46
using v8::Local;
47
using v8::MaybeLocal;
48
using v8::NewStringType;
49
using v8::Number;
50
using v8::Object;
51
using v8::Private;
52
using v8::Script;
53
using v8::SnapshotCreator;
54
using v8::StackTrace;
55
using v8::String;
56
using v8::Symbol;
57
using v8::TracingController;
58
using v8::TryCatch;
59
using v8::Undefined;
60
using v8::Value;
61
using worker::Worker;
62
63
int const ContextEmbedderTag::kNodeContextTag = 0x6e6f64;
64
void* const ContextEmbedderTag::kNodeContextTagPtr = const_cast<void*>(
65
    static_cast<const void*>(&ContextEmbedderTag::kNodeContextTag));
66
67
16638
void AsyncHooks::ResetPromiseHooks(Local<Function> init,
68
                                   Local<Function> before,
69
                                   Local<Function> after,
70
                                   Local<Function> resolve) {
71
16638
  js_promise_hooks_[0].Reset(env()->isolate(), init);
72
16638
  js_promise_hooks_[1].Reset(env()->isolate(), before);
73
16638
  js_promise_hooks_[2].Reset(env()->isolate(), after);
74
16638
  js_promise_hooks_[3].Reset(env()->isolate(), resolve);
75
16638
}
76
77
16638
void Environment::ResetPromiseHooks(Local<Function> init,
78
                                    Local<Function> before,
79
                                    Local<Function> after,
80
                                    Local<Function> resolve) {
81
16638
  async_hooks()->ResetPromiseHooks(init, before, after, resolve);
82
83
33720
  for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
84
17082
    if (it->IsEmpty()) {
85
      contexts_.erase(it--);
86
      continue;
87
    }
88
34164
    PersistentToLocal::Weak(isolate_, *it)
89
17082
        ->SetPromiseHooks(init, before, after, resolve);
90
  }
91
16638
}
92
93
// Remember to keep this code aligned with pushAsyncContext() in JS.
94
850401
void AsyncHooks::push_async_context(double async_id,
95
                                    double trigger_async_id,
96
                                    Local<Object> resource) {
97
  // Since async_hooks is experimental, do only perform the check
98
  // when async_hooks is enabled.
99
850401
  if (fields_[kCheck] > 0) {
100
850397
    CHECK_GE(async_id, -1);
101
850397
    CHECK_GE(trigger_async_id, -1);
102
  }
103
104
850401
  uint32_t offset = fields_[kStackLength];
105
850401
  if (offset * 2 >= async_ids_stack_.Length()) grow_async_ids_stack();
106
850401
  async_ids_stack_[2 * offset] = async_id_fields_[kExecutionAsyncId];
107
850401
  async_ids_stack_[2 * offset + 1] = async_id_fields_[kTriggerAsyncId];
108
850401
  fields_[kStackLength] += 1;
109
850401
  async_id_fields_[kExecutionAsyncId] = async_id;
110
850401
  async_id_fields_[kTriggerAsyncId] = trigger_async_id;
111
112
#ifdef DEBUG
113
  for (uint32_t i = offset; i < native_execution_async_resources_.size(); i++)
114
    CHECK(native_execution_async_resources_[i].IsEmpty());
115
#endif
116
117
  // When this call comes from JS (as a way of increasing the stack size),
118
  // `resource` will be empty, because JS caches these values anyway.
119
850401
  if (!resource.IsEmpty()) {
120
850397
    native_execution_async_resources_.resize(offset + 1);
121
    // Caveat: This is a v8::Local<> assignment, we do not keep a v8::Global<>!
122
850397
    native_execution_async_resources_[offset] = resource;
123
  }
124
850401
}
125
126
// Remember to keep this code aligned with popAsyncContext() in JS.
127
849952
bool AsyncHooks::pop_async_context(double async_id) {
128
  // In case of an exception then this may have already been reset, if the
129
  // stack was multiple MakeCallback()'s deep.
130
849952
  if (UNLIKELY(fields_[kStackLength] == 0)) return false;
131
132
  // Ask for the async_id to be restored as a check that the stack
133
  // hasn't been corrupted.
134
1697750
  if (UNLIKELY(fields_[kCheck] > 0 &&
135

1697750
               async_id_fields_[kExecutionAsyncId] != async_id)) {
136
4
    FailWithCorruptedAsyncStack(async_id);
137
  }
138
139
848873
  uint32_t offset = fields_[kStackLength] - 1;
140
848873
  async_id_fields_[kExecutionAsyncId] = async_ids_stack_[2 * offset];
141
848873
  async_id_fields_[kTriggerAsyncId] = async_ids_stack_[2 * offset + 1];
142
848873
  fields_[kStackLength] = offset;
143
144
1697746
  if (LIKELY(offset < native_execution_async_resources_.size() &&
145

1697746
             !native_execution_async_resources_[offset].IsEmpty())) {
146
#ifdef DEBUG
147
    for (uint32_t i = offset + 1; i < native_execution_async_resources_.size();
148
         i++) {
149
      CHECK(native_execution_async_resources_[i].IsEmpty());
150
    }
151
#endif
152
848873
    native_execution_async_resources_.resize(offset);
153
848873
    if (native_execution_async_resources_.size() <
154

1099619
            native_execution_async_resources_.capacity() / 2 &&
155
250746
        native_execution_async_resources_.size() > 16) {
156
      native_execution_async_resources_.shrink_to_fit();
157
    }
158
  }
159
160
1697746
  if (UNLIKELY(js_execution_async_resources()->Length() > offset)) {
161
44400
    HandleScope handle_scope(env()->isolate());
162
88800
    USE(js_execution_async_resources()->Set(
163
        env()->context(),
164
        env()->length_string(),
165
177600
        Integer::NewFromUnsigned(env()->isolate(), offset)));
166
  }
167
168
848873
  return fields_[kStackLength] > 0;
169
}
170
171
2378
void AsyncHooks::clear_async_id_stack() {
172
2378
  if (env()->can_call_into_js()) {
173
1373
    Isolate* isolate = env()->isolate();
174
2746
    HandleScope handle_scope(isolate);
175
1373
    if (!js_execution_async_resources_.IsEmpty()) {
176
2618
      USE(PersistentToLocal::Strong(js_execution_async_resources_)
177
2618
              ->Set(env()->context(),
178
                    env()->length_string(),
179
5236
                    Integer::NewFromUnsigned(isolate, 0)));
180
    }
181
  }
182
183
2378
  native_execution_async_resources_.clear();
184
2378
  native_execution_async_resources_.shrink_to_fit();
185
186
2378
  async_id_fields_[kExecutionAsyncId] = 0;
187
2378
  async_id_fields_[kTriggerAsyncId] = 0;
188
2378
  fields_[kStackLength] = 0;
189
2378
}
190
191
7208
void AsyncHooks::InstallPromiseHooks(Local<Context> ctx) {
192
21624
  ctx->SetPromiseHooks(js_promise_hooks_[0].IsEmpty()
193
7208
                           ? Local<Function>()
194
230
                           : PersistentToLocal::Strong(js_promise_hooks_[0]),
195
7208
                       js_promise_hooks_[1].IsEmpty()
196
7208
                           ? Local<Function>()
197
230
                           : PersistentToLocal::Strong(js_promise_hooks_[1]),
198
7208
                       js_promise_hooks_[2].IsEmpty()
199
7208
                           ? Local<Function>()
200
230
                           : PersistentToLocal::Strong(js_promise_hooks_[2]),
201
7208
                       js_promise_hooks_[3].IsEmpty()
202
7208
                           ? Local<Function>()
203
                           : PersistentToLocal::Strong(js_promise_hooks_[3]));
204
7208
}
205
206
7208
void Environment::TrackContext(Local<Context> context) {
207
7208
  size_t id = contexts_.size();
208
7208
  contexts_.resize(id + 1);
209
7208
  contexts_[id].Reset(isolate_, context);
210
7208
  contexts_[id].SetWeak();
211
7208
}
212
213
519
void Environment::UntrackContext(Local<Context> context) {
214
1038
  HandleScope handle_scope(isolate_);
215
519
  contexts_.erase(std::remove_if(contexts_.begin(),
216
                                 contexts_.end(),
217
2854
                                 [&](auto&& el) { return el.IsEmpty(); }),
218
1038
                  contexts_.end());
219
2335
  for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
220
2290
    Local<Context> saved_context = PersistentToLocal::Weak(isolate_, *it);
221
2290
    if (saved_context == context) {
222
474
      it->Reset();
223
474
      contexts_.erase(it);
224
474
      break;
225
    }
226
  }
227
519
}
228
229
222147
AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
230
222147
    Environment* env, double default_trigger_async_id)
231
222147
    : async_hooks_(env->async_hooks()) {
232
222147
  if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
233
222147
    CHECK_GE(default_trigger_async_id, 0);
234
  }
235
236
222147
  old_default_trigger_async_id_ =
237
222147
      async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
238
222147
  async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
239
222147
      default_trigger_async_id;
240
222147
}
241
242
444292
AsyncHooks::DefaultTriggerAsyncIdScope::~DefaultTriggerAsyncIdScope() {
243
222146
  async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
244
222146
      old_default_trigger_async_id_;
245
222146
}
246
247
222147
AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
248
222147
    AsyncWrap* async_wrap)
249
    : DefaultTriggerAsyncIdScope(async_wrap->env(),
250
222147
                                 async_wrap->get_async_id()) {}
251
252
12
std::ostream& operator<<(std::ostream& output,
253
                         const std::vector<SnapshotIndex>& v) {
254
12
  output << "{ ";
255
2130
  for (const SnapshotIndex i : v) {
256
2118
    output << i << ", ";
257
  }
258
12
  output << " }";
259
12
  return output;
260
}
261
262
6
std::ostream& operator<<(std::ostream& output,
263
                         const IsolateDataSerializeInfo& i) {
264
  output << "{\n"
265
6
         << "// -- primitive begins --\n"
266
6
         << i.primitive_values << ",\n"
267
         << "// -- primitive ends --\n"
268
6
         << "// -- template_values begins --\n"
269
6
         << i.template_values << ",\n"
270
         << "// -- template_values ends --\n"
271
6
         << "}";
272
6
  return output;
273
}
274
275
6
std::ostream& operator<<(std::ostream& output, const SnapshotMetadata& i) {
276
  output << "{\n"
277
         << "  "
278
6
         << (i.type == SnapshotMetadata::Type::kDefault
279
                 ? "SnapshotMetadata::Type::kDefault"
280
                 : "SnapshotMetadata::Type::kFullyCustomized")
281
         << ", // type\n"
282
6
         << "  \"" << i.node_version << "\", // node_version\n"
283
6
         << "  \"" << i.node_arch << "\", // node_arch\n"
284
6
         << "  \"" << i.node_platform << "\", // node_platform\n"
285
6
         << "  " << i.v8_cache_version_tag << ", // v8_cache_version_tag\n"
286
6
         << "}";
287
6
  return output;
288
}
289
290
7
IsolateDataSerializeInfo IsolateData::Serialize(SnapshotCreator* creator) {
291
7
  Isolate* isolate = creator->GetIsolate();
292
7
  IsolateDataSerializeInfo info;
293
14
  HandleScope handle_scope(isolate);
294
  // XXX(joyeecheung): technically speaking, the indexes here should be
295
  // consecutive and we could just return a range instead of an array,
296
  // but that's not part of the V8 API contract so we use an array
297
  // just to be safe.
298
299
#define VP(PropertyName, StringValue) V(Private, PropertyName)
300
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
301
#define VS(PropertyName, StringValue) V(String, PropertyName)
302
#define V(TypeName, PropertyName)                                              \
303
  info.primitive_values.push_back(                                             \
304
      creator->AddData(PropertyName##_.Get(isolate)));
305
56
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
306
91
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
307
1939
  PER_ISOLATE_STRING_PROPERTIES(VS)
308
#undef V
309
#undef VY
310
#undef VS
311
#undef VP
312
313
413
  for (size_t i = 0; i < AsyncWrap::PROVIDERS_LENGTH; i++)
314
812
    info.primitive_values.push_back(creator->AddData(async_wrap_provider(i)));
315
316
7
  uint32_t id = 0;
317
#define VM(PropertyName) V(PropertyName##_binding, FunctionTemplate)
318
#define V(PropertyName, TypeName)                                              \
319
  do {                                                                         \
320
    Local<TypeName> field = PropertyName();                                    \
321
    if (!field.IsEmpty()) {                                                    \
322
      size_t index = creator->AddData(field);                                  \
323
      info.template_values.push_back({#PropertyName, id, index});              \
324
    }                                                                          \
325
    id++;                                                                      \
326
  } while (0);
327




















420
  PER_ISOLATE_TEMPLATE_PROPERTIES(V)
328

35
  NODE_BINDINGS_WITH_PER_ISOLATE_INIT(VM)
329
#undef V
330
331
7
  return info;
332
}
333
334
5708
void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
335
5708
  size_t i = 0;
336
5708
  HandleScope handle_scope(isolate_);
337
338
#define VP(PropertyName, StringValue) V(Private, PropertyName)
339
#define VY(PropertyName, StringValue) V(Symbol, PropertyName)
340
#define VS(PropertyName, StringValue) V(String, PropertyName)
341
#define V(TypeName, PropertyName)                                              \
342
  do {                                                                         \
343
    MaybeLocal<TypeName> maybe_field =                                         \
344
        isolate_->GetDataFromSnapshotOnce<TypeName>(                           \
345
            info->primitive_values[i++]);                                      \
346
    Local<TypeName> field;                                                     \
347
    if (!maybe_field.ToLocal(&field)) {                                        \
348
      fprintf(stderr, "Failed to deserialize " #PropertyName "\n");            \
349
    }                                                                          \
350
    PropertyName##_.Set(isolate_, field);                                      \
351
  } while (0);
352



85620
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
353






142700
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
354










































































































































3156524
  PER_ISOLATE_STRING_PROPERTIES(VS)
355
#undef V
356
#undef VY
357
#undef VS
358
#undef VP
359
360
336772
  for (size_t j = 0; j < AsyncWrap::PROVIDERS_LENGTH; j++) {
361
    MaybeLocal<String> maybe_field =
362
662128
        isolate_->GetDataFromSnapshotOnce<String>(info->primitive_values[i++]);
363
    Local<String> field;
364
331064
    if (!maybe_field.ToLocal(&field)) {
365
      fprintf(stderr, "Failed to deserialize AsyncWrap provider %zu\n", j);
366
    }
367
331064
    async_wrap_providers_[j].Set(isolate_, field);
368
  }
369
370
5708
  const std::vector<PropInfo>& values = info->template_values;
371
5708
  i = 0;  // index to the array
372
5708
  uint32_t id = 0;
373
#define VM(PropertyName) V(PropertyName##_binding, FunctionTemplate)
374
#define V(PropertyName, TypeName)                                              \
375
  do {                                                                         \
376
    if (values.size() > i && id == values[i].id) {                             \
377
      const PropInfo& d = values[i];                                           \
378
      DCHECK_EQ(d.name, #PropertyName);                                        \
379
      MaybeLocal<TypeName> maybe_field =                                       \
380
          isolate_->GetDataFromSnapshotOnce<TypeName>(d.index);                \
381
      Local<TypeName> field;                                                   \
382
      if (!maybe_field.ToLocal(&field)) {                                      \
383
        fprintf(stderr,                                                        \
384
                "Failed to deserialize isolate data template " #PropertyName   \
385
                "\n");                                                         \
386
      }                                                                        \
387
      set_##PropertyName(field);                                               \
388
      i++;                                                                     \
389
    }                                                                          \
390
    id++;                                                                      \
391
  } while (0);
392
393
















































































222612
  PER_ISOLATE_TEMPLATE_PROPERTIES(V);
394




28540
  NODE_BINDINGS_WITH_PER_ISOLATE_INIT(VM);
395
#undef V
396
5708
}
397
398
831
void IsolateData::CreateProperties() {
399
  // Create string and private symbol properties as internalized one byte
400
  // strings after the platform is properly initialized.
401
  //
402
  // Internalized because it makes property lookups a little faster and
403
  // because the string is created in the old space straight away.  It's going
404
  // to end up in the old space sooner or later anyway but now it doesn't go
405
  // through v8::Eternal's new space handling first.
406
  //
407
  // One byte because our strings are ASCII and we can safely skip V8's UTF-8
408
  // decoding step.
409
410
1662
  HandleScope handle_scope(isolate_);
411
412
#define V(PropertyName, StringValue)                                           \
413
  PropertyName##_.Set(                                                         \
414
      isolate_,                                                                \
415
      Private::New(isolate_,                                                   \
416
                   String::NewFromOneByte(                                     \
417
                       isolate_,                                               \
418
                       reinterpret_cast<const uint8_t*>(StringValue),          \
419
                       NewStringType::kInternalized,                           \
420
                       sizeof(StringValue) - 1)                                \
421
                       .ToLocalChecked()));
422
6648
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
423
#undef V
424
#define V(PropertyName, StringValue)                                           \
425
  PropertyName##_.Set(                                                         \
426
      isolate_,                                                                \
427
      Symbol::New(isolate_,                                                    \
428
                  String::NewFromOneByte(                                      \
429
                      isolate_,                                                \
430
                      reinterpret_cast<const uint8_t*>(StringValue),           \
431
                      NewStringType::kInternalized,                            \
432
                      sizeof(StringValue) - 1)                                 \
433
                      .ToLocalChecked()));
434
10803
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
435
#undef V
436
#define V(PropertyName, StringValue)                                           \
437
  PropertyName##_.Set(                                                         \
438
      isolate_,                                                                \
439
      String::NewFromOneByte(isolate_,                                         \
440
                             reinterpret_cast<const uint8_t*>(StringValue),    \
441
                             NewStringType::kInternalized,                     \
442
                             sizeof(StringValue) - 1)                          \
443
          .ToLocalChecked());
444
230187
  PER_ISOLATE_STRING_PROPERTIES(V)
445
#undef V
446
447
  // Create all the provider strings that will be passed to JS. Place them in
448
  // an array so the array index matches the PROVIDER id offset. This way the
449
  // strings can be retrieved quickly.
450
#define V(Provider)                                                           \
451
  async_wrap_providers_[AsyncWrap::PROVIDER_ ## Provider].Set(                \
452
      isolate_,                                                               \
453
      String::NewFromOneByte(                                                 \
454
        isolate_,                                                             \
455
        reinterpret_cast<const uint8_t*>(#Provider),                          \
456
        NewStringType::kInternalized,                                         \
457
        sizeof(#Provider) - 1).ToLocalChecked());
458
49029
  NODE_ASYNC_PROVIDER_TYPES(V)
459
#undef V
460
461
831
  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
462
1662
  templ->InstanceTemplate()->SetInternalFieldCount(
463
      BaseObject::kInternalFieldCount);
464
831
  templ->Inherit(BaseObject::GetConstructorTemplate(this));
465
831
  set_binding_data_ctor_template(templ);
466
831
  binding::CreateInternalBindingTemplates(this);
467
468
831
  contextify::ContextifyContext::InitializeGlobalTemplates(this);
469
831
}
470
471
6539
IsolateData::IsolateData(Isolate* isolate,
472
                         uv_loop_t* event_loop,
473
                         MultiIsolatePlatform* platform,
474
                         ArrayBufferAllocator* node_allocator,
475
6539
                         const IsolateDataSerializeInfo* isolate_data_info)
476
    : isolate_(isolate),
477
      event_loop_(event_loop),
478
51
      node_allocator_(node_allocator == nullptr ? nullptr
479
6488
                                                : node_allocator->GetImpl()),
480
13078
      platform_(platform) {
481
6539
  options_.reset(
482
6539
      new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
483
484
6539
  if (isolate_data_info == nullptr) {
485
831
    CreateProperties();
486
  } else {
487
5708
    DeserializeProperties(isolate_data_info);
488
  }
489
6539
}
490
491
37
void IsolateData::MemoryInfo(MemoryTracker* tracker) const {
492
#define V(PropertyName, StringValue)                                           \
493
  tracker->TrackField(#PropertyName, PropertyName());
494
37
  PER_ISOLATE_SYMBOL_PROPERTIES(V)
495
496
37
  PER_ISOLATE_STRING_PROPERTIES(V)
497
#undef V
498
499
37
  tracker->TrackField("async_wrap_providers", async_wrap_providers_);
500
501
37
  if (node_allocator_ != nullptr) {
502
37
    tracker->TrackFieldWithSize(
503
        "node_allocator", sizeof(*node_allocator_), "NodeArrayBufferAllocator");
504
  }
505
37
  tracker->TrackFieldWithSize(
506
      "platform", sizeof(*platform_), "MultiIsolatePlatform");
507
  // TODO(joyeecheung): implement MemoryRetainer in the option classes.
508
37
}
509
510
155
void TrackingTraceStateObserver::UpdateTraceCategoryState() {
511

155
  if (!env_->owns_process_state() || !env_->can_call_into_js()) {
512
    // Ideally, we’d have a consistent story that treats all threads/Environment
513
    // instances equally here. However, tracing is essentially global, and this
514
    // callback is called from whichever thread calls `StartTracing()` or
515
    // `StopTracing()`. The only way to do this in a threadsafe fashion
516
    // seems to be only tracking this from the main thread, and only allowing
517
    // these state modifications from the main thread.
518
97
    return;
519
  }
520
521
144
  if (env_->principal_realm() == nullptr) {
522
86
    return;
523
  }
524
525
58
  bool async_hooks_enabled = (*(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
526
58
                                 TRACING_CATEGORY_NODE1(async_hooks)))) != 0;
527
528
58
  Isolate* isolate = env_->isolate();
529
58
  HandleScope handle_scope(isolate);
530
58
  Local<Function> cb = env_->trace_category_state_function();
531
58
  if (cb.IsEmpty())
532
    return;
533
58
  TryCatchScope try_catch(env_);
534
58
  try_catch.SetVerbose(true);
535
116
  Local<Value> args[] = {Boolean::New(isolate, async_hooks_enabled)};
536
116
  USE(cb->Call(env_->context(), Undefined(isolate), arraysize(args), args));
537
}
538
539
7208
void Environment::AssignToContext(Local<v8::Context> context,
540
                                  Realm* realm,
541
                                  const ContextInfo& info) {
542
7208
  context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment,
543
                                           this);
544
7208
  context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, realm);
545
  // Used to retrieve bindings
546
14416
  context->SetAlignedPointerInEmbedderData(
547
7208
      ContextEmbedderIndex::kBindingListIndex, &(this->bindings_));
548
549
  // ContextifyContexts will update this to a pointer to the native object.
550
7208
  context->SetAlignedPointerInEmbedderData(
551
      ContextEmbedderIndex::kContextifyContext, nullptr);
552
553
  // This must not be done before other context fields are initialized.
554
7208
  ContextEmbedderTag::TagNodeContext(context);
555
556
#if HAVE_INSPECTOR
557
7208
  inspector_agent()->ContextCreated(context, info);
558
#endif  // HAVE_INSPECTOR
559
560
7208
  this->async_hooks()->InstallPromiseHooks(context);
561
7208
  TrackContext(context);
562
7208
}
563
564
189
void Environment::TryLoadAddon(
565
    const char* filename,
566
    int flags,
567
    const std::function<bool(binding::DLib*)>& was_loaded) {
568
189
  loaded_addons_.emplace_back(filename, flags);
569
189
  if (!was_loaded(&loaded_addons_.back())) {
570
10
    loaded_addons_.pop_back();
571
  }
572
189
}
573
574
12
std::string Environment::GetCwd() {
575
  char cwd[PATH_MAX_BYTES];
576
12
  size_t size = PATH_MAX_BYTES;
577
12
  const int err = uv_cwd(cwd, &size);
578
579
12
  if (err == 0) {
580
12
    CHECK_GT(size, 0);
581
12
    return cwd;
582
  }
583
584
  // This can fail if the cwd is deleted. In that case, fall back to
585
  // exec_path.
586
  const std::string& exec_path = exec_path_;
587
  return exec_path.substr(0, exec_path.find_last_of(kPathSeparator));
588
}
589
590
1947
void Environment::add_refs(int64_t diff) {
591
1947
  task_queues_async_refs_ += diff;
592
1947
  CHECK_GE(task_queues_async_refs_, 0);
593
1947
  if (task_queues_async_refs_ == 0)
594
437
    uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
595
  else
596
1510
    uv_ref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
597
1947
}
598
599
67695
uv_buf_t Environment::allocate_managed_buffer(const size_t suggested_size) {
600
135390
  NoArrayBufferZeroFillScope no_zero_fill_scope(isolate_data());
601
  std::unique_ptr<v8::BackingStore> bs =
602
67695
      v8::ArrayBuffer::NewBackingStore(isolate(), suggested_size);
603
67695
  uv_buf_t buf = uv_buf_init(static_cast<char*>(bs->Data()), bs->ByteLength());
604
67695
  released_allocated_buffers_.emplace(buf.base, std::move(bs));
605
67695
  return buf;
606
}
607
608
83511
std::unique_ptr<v8::BackingStore> Environment::release_managed_buffer(
609
    const uv_buf_t& buf) {
610
83511
  std::unique_ptr<v8::BackingStore> bs;
611
83511
  if (buf.base != nullptr) {
612
67695
    auto it = released_allocated_buffers_.find(buf.base);
613
67695
    CHECK_NE(it, released_allocated_buffers_.end());
614
67695
    bs = std::move(it->second);
615
67695
    released_allocated_buffers_.erase(it);
616
  }
617
83511
  return bs;
618
}
619
620
6535
std::string GetExecPath(const std::vector<std::string>& argv) {
621
  char exec_path_buf[2 * PATH_MAX];
622
6535
  size_t exec_path_len = sizeof(exec_path_buf);
623
6535
  std::string exec_path;
624
6535
  if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
625
6535
    exec_path = std::string(exec_path_buf, exec_path_len);
626
  } else if (argv.size() > 0) {
627
    exec_path = argv[0];
628
  }
629
630
  // On OpenBSD process.execPath will be relative unless we
631
  // get the full path before process.execPath is used.
632
#if defined(__OpenBSD__)
633
  uv_fs_t req;
634
  req.ptr = nullptr;
635
  if (0 ==
636
      uv_fs_realpath(nullptr, &req, exec_path.c_str(), nullptr)) {
637
    CHECK_NOT_NULL(req.ptr);
638
    exec_path = std::string(static_cast<char*>(req.ptr));
639
  }
640
  uv_fs_req_cleanup(&req);
641
#endif
642
643
6535
  return exec_path;
644
}
645
646
6535
Environment::Environment(IsolateData* isolate_data,
647
                         Isolate* isolate,
648
                         const std::vector<std::string>& args,
649
                         const std::vector<std::string>& exec_args,
650
                         const EnvSerializeInfo* env_info,
651
                         EnvironmentFlags::Flags flags,
652
6535
                         ThreadId thread_id)
653
    : isolate_(isolate),
654
      isolate_data_(isolate_data),
655
      async_hooks_(isolate, MAYBE_FIELD_PTR(env_info, async_hooks)),
656
      immediate_info_(isolate, MAYBE_FIELD_PTR(env_info, immediate_info)),
657
      tick_info_(isolate, MAYBE_FIELD_PTR(env_info, tick_info)),
658
6535
      timer_base_(uv_now(isolate_data->event_loop())),
659
      exec_argv_(exec_args),
660
      argv_(args),
661
      exec_path_(GetExecPath(args)),
662
      exit_info_(
663
6535
          isolate_, kExitInfoFieldCount, MAYBE_FIELD_PTR(env_info, exit_info)),
664
      should_abort_on_uncaught_toggle_(
665
6535
          isolate_,
666
          1,
667
          MAYBE_FIELD_PTR(env_info, should_abort_on_uncaught_toggle)),
668
6535
      stream_base_state_(isolate_,
669
                         StreamBase::kNumStreamBaseStateFields,
670
                         MAYBE_FIELD_PTR(env_info, stream_base_state)),
671
6535
      time_origin_(PERFORMANCE_NOW()),
672
6535
      time_origin_timestamp_(GetCurrentTimeInMicroseconds()),
673
      flags_(flags),
674
6535
      thread_id_(thread_id.id == static_cast<uint64_t>(-1)
675
6535
                     ? AllocateEnvironmentThreadId().id
676



26140
                     : thread_id.id) {
677
  // We'll be creating new objects so make sure we've entered the context.
678
13070
  HandleScope handle_scope(isolate);
679
680
  // Set some flags if only kDefaultFlags was passed. This can make API version
681
  // transitions easier for embedders.
682
6535
  if (flags_ & EnvironmentFlags::kDefaultFlags) {
683
11532
    flags_ = flags_ |
684
5766
        EnvironmentFlags::kOwnsProcessState |
685
        EnvironmentFlags::kOwnsInspector;
686
  }
687
688
6535
  set_env_vars(per_process::system_environment);
689
6535
  enabled_debug_list_.Parse(env_vars(), isolate);
690
691
  // We create new copies of the per-Environment option sets, so that it is
692
  // easier to modify them after Environment creation. The defaults are
693
  // part of the per-Isolate option set, for which in turn the defaults are
694
  // part of the per-process option set.
695
13070
  options_ = std::make_shared<EnvironmentOptions>(
696
19605
      *isolate_data->options()->per_env);
697
6535
  inspector_host_port_ = std::make_shared<ExclusiveAccess<HostPort>>(
698
6535
      options_->debug_options().host_port);
699
700
6535
  heap_snapshot_near_heap_limit_ =
701
6535
      static_cast<uint32_t>(options_->heap_snapshot_near_heap_limit);
702
703
6535
  if (!(flags_ & EnvironmentFlags::kOwnsProcessState)) {
704
769
    set_abort_on_uncaught_exception(false);
705
  }
706
707
#if HAVE_INSPECTOR
708
  // We can only create the inspector agent after having cloned the options.
709
6535
  inspector_agent_ = std::make_unique<inspector::Agent>(this);
710
#endif
711
712
6535
  if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) {
713
6535
    trace_state_observer_ = std::make_unique<TrackingTraceStateObserver>(this);
714
6535
    if (TracingController* tracing_controller = writer->GetTracingController())
715
6485
      tracing_controller->AddTraceStateObserver(trace_state_observer_.get());
716
  }
717
718
6535
  destroy_async_id_list_.reserve(512);
719
720
6535
  performance_state_ = std::make_unique<performance::PerformanceState>(
721
6535
      isolate, MAYBE_FIELD_PTR(env_info, performance_state));
722
723
6535
  if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
724
6535
          TRACING_CATEGORY_NODE1(environment)) != 0) {
725
16
    auto traced_value = tracing::TracedValue::Create();
726
8
    traced_value->BeginArray("args");
727
18
    for (const std::string& arg : args) traced_value->AppendString(arg);
728
8
    traced_value->EndArray();
729
8
    traced_value->BeginArray("exec_args");
730
33
    for (const std::string& arg : exec_args) traced_value->AppendString(arg);
731
8
    traced_value->EndArray();
732

15
    TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
733
                                      "Environment",
734
                                      this,
735
                                      "args",
736
                                      std::move(traced_value));
737
  }
738
6535
}
739
740
827
Environment::Environment(IsolateData* isolate_data,
741
                         Local<Context> context,
742
                         const std::vector<std::string>& args,
743
                         const std::vector<std::string>& exec_args,
744
                         const EnvSerializeInfo* env_info,
745
                         EnvironmentFlags::Flags flags,
746
827
                         ThreadId thread_id)
747
    : Environment(isolate_data,
748
                  context->GetIsolate(),
749
                  args,
750
                  exec_args,
751
                  env_info,
752
                  flags,
753
827
                  thread_id) {
754
827
  InitializeMainContext(context, env_info);
755
827
}
756
757
6535
void Environment::InitializeMainContext(Local<Context> context,
758
                                        const EnvSerializeInfo* env_info) {
759
6535
  principal_realm_ = std::make_unique<Realm>(
760
6535
      this, context, MAYBE_FIELD_PTR(env_info, principal_realm));
761
6535
  AssignToContext(context, principal_realm_.get(), ContextInfo(""));
762
6535
  if (env_info != nullptr) {
763
5708
    DeserializeProperties(env_info);
764
  }
765
766
6535
  if (!options_->force_async_hooks_checks) {
767
1
    async_hooks_.no_force_checks();
768
  }
769
770
  // By default, always abort when --abort-on-uncaught-exception was passed.
771
6535
  should_abort_on_uncaught_toggle_[0] = 1;
772
773
  // The process is not exiting by default.
774
6535
  set_exiting(false);
775
776
6535
  performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT,
777
                           time_origin_);
778
6535
  performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
779
                           per_process::node_start_time);
780
781
6535
  if (per_process::v8_initialized) {
782
6492
    performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_V8_START,
783
                            performance::performance_v8_start);
784
  }
785
6535
}
786
787
23688
Environment::~Environment() {
788
23688
  HandleScope handle_scope(isolate());
789
11844
  Local<Context> ctx = context();
790
791
11844
  if (Environment** interrupt_data = interrupt_data_.load()) {
792
    // There are pending RequestInterrupt() callbacks. Tell them not to run,
793
    // then force V8 to run interrupts by compiling and running an empty script
794
    // so as not to leak memory.
795
22
    *interrupt_data = nullptr;
796
797
44
    Isolate::AllowJavascriptExecutionScope allow_js_here(isolate());
798
44
    TryCatch try_catch(isolate());
799
22
    Context::Scope context_scope(ctx);
800
801
#ifdef DEBUG
802
    bool consistency_check = false;
803
    isolate()->RequestInterrupt([](Isolate*, void* data) {
804
      *static_cast<bool*>(data) = true;
805
    }, &consistency_check);
806
#endif
807
808
    Local<Script> script;
809
66
    if (Script::Compile(ctx, String::Empty(isolate())).ToLocal(&script))
810
22
      USE(script->Run(ctx));
811
812
    DCHECK(consistency_check);
813
  }
814
815
  // FreeEnvironment() should have set this.
816
11844
  CHECK(is_stopping());
817
818
11844
  if (heapsnapshot_near_heap_limit_callback_added_) {
819
    RemoveHeapSnapshotNearHeapLimitCallback(0);
820
  }
821
822
11844
  isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
823
      BuildEmbedderGraph, this);
824
825
#if HAVE_INSPECTOR
826
  // Destroy inspector agent before erasing the context. The inspector
827
  // destructor depends on the context still being accessible.
828
11844
  inspector_agent_.reset();
829
#endif
830
831
11844
  ctx->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment,
832
                                       nullptr);
833
11844
  ctx->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, nullptr);
834
835
11844
  if (trace_state_observer_) {
836
11844
    tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
837
11844
    CHECK_NOT_NULL(writer);
838
11844
    if (TracingController* tracing_controller = writer->GetTracingController())
839
11748
      tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get());
840
  }
841
842

22090
  TRACE_EVENT_NESTABLE_ASYNC_END0(
843
    TRACING_CATEGORY_NODE1(environment), "Environment", this);
844
845
  // Do not unload addons on the main thread. Some addons need to retain memory
846
  // beyond the Environment's lifetime, and unloading them early would break
847
  // them; with Worker threads, we have the opportunity to be stricter.
848
  // Also, since the main thread usually stops just before the process exits,
849
  // this is far less relevant here.
850
11844
  if (!is_main_thread()) {
851
    // Dereference all addons that were loaded into this environment.
852
1556
    for (binding::DLib& addon : loaded_addons_) {
853
28
      addon.Close();
854
    }
855
  }
856
23688
}
857
858
6494
void Environment::InitializeLibuv() {
859
12988
  HandleScope handle_scope(isolate());
860
6494
  Context::Scope context_scope(context());
861
862
6494
  CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
863
6494
  uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
864
865
6494
  CHECK_EQ(0, uv_check_init(event_loop(), immediate_check_handle()));
866
6494
  uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
867
868
6494
  CHECK_EQ(0, uv_idle_init(event_loop(), immediate_idle_handle()));
869
870
6494
  CHECK_EQ(0, uv_check_start(immediate_check_handle(), CheckImmediate));
871
872
  // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
873
  // but not all samples are created equal; mark the wall clock time spent in
874
  // epoll_wait() and friends so profiling tools can filter it out.  The samples
875
  // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
876
6494
  CHECK_EQ(0, uv_prepare_init(event_loop(), &idle_prepare_handle_));
877
6494
  CHECK_EQ(0, uv_check_init(event_loop(), &idle_check_handle_));
878
879
25206
  CHECK_EQ(0, uv_async_init(
880
      event_loop(),
881
      &task_queues_async_,
882
      [](uv_async_t* async) {
883
        Environment* env = ContainerOf(
884
            &Environment::task_queues_async_, async);
885
        HandleScope handle_scope(env->isolate());
886
        Context::Scope context_scope(env->context());
887
        env->RunAndClearNativeImmediates();
888
      }));
889
6494
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
890
6494
  uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
891
6494
  uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
892
893
  {
894
12988
    Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
895
6494
    task_queues_async_initialized_ = true;
896

12988
    if (native_immediates_threadsafe_.size() > 0 ||
897
6494
        native_immediates_interrupts_.size() > 0) {
898
5703
      uv_async_send(&task_queues_async_);
899
    }
900
  }
901
902
  // Register clean-up cb to be called to clean up the handles
903
  // when the environment is freed, note that they are not cleaned in
904
  // the one environment per process setup, but will be called in
905
  // FreeEnvironment.
906
6494
  RegisterHandleCleanups();
907
908
6494
  StartProfilerIdleNotifier();
909
6494
}
910
911
359
void Environment::ExitEnv() {
912
359
  set_can_call_into_js(false);
913
359
  set_stopping(true);
914
359
  isolate_->TerminateExecution();
915
718
  SetImmediateThreadsafe([](Environment* env) { uv_stop(env->event_loop()); });
916
359
}
917
918
6494
void Environment::RegisterHandleCleanups() {
919
6494
  HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
920
35286
                                        void* arg) {
921
35286
    handle->data = env;
922
923
35286
    env->CloseHandle(handle, [](uv_handle_t* handle) {
924
#ifdef DEBUG
925
      memset(handle, 0xab, uv_handle_size(handle->type));
926
#endif
927
35286
    });
928
35286
  };
929
930
38964
  auto register_handle = [&](uv_handle_t* handle) {
931
38964
    RegisterHandleCleanup(handle, close_and_finish, nullptr);
932
45458
  };
933
6494
  register_handle(reinterpret_cast<uv_handle_t*>(timer_handle()));
934
6494
  register_handle(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
935
6494
  register_handle(reinterpret_cast<uv_handle_t*>(immediate_idle_handle()));
936
6494
  register_handle(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
937
6494
  register_handle(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
938
6494
  register_handle(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
939
6494
}
940
941
11828
void Environment::CleanupHandles() {
942
  {
943
11828
    Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
944
11828
    task_queues_async_initialized_ = false;
945
  }
946
947
  Isolate::DisallowJavascriptExecutionScope disallow_js(isolate(),
948
23656
      Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
949
950
11828
  RunAndClearNativeImmediates(true /* skip unrefed SetImmediate()s */);
951
952
11991
  for (ReqWrapBase* request : req_wrap_queue_)
953
163
    request->Cancel();
954
955
16702
  for (HandleWrap* handle : handle_wrap_queue_)
956
9748
    handle->Close();
957
958
47114
  for (HandleCleanup& hc : handle_cleanup_queue_)
959
35286
    hc.cb_(this, hc.handle_, hc.arg_);
960
11828
  handle_cleanup_queue_.clear();
961
962
11090
  while (handle_cleanup_waiting_ != 0 ||
963

34749
         request_waiting_ != 0 ||
964
11831
         !handle_wrap_queue_.IsEmpty()) {
965
11090
    uv_run(event_loop(), UV_RUN_ONCE);
966
  }
967
11828
}
968
969
6494
void Environment::StartProfilerIdleNotifier() {
970
6494
  uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
971
214922
    Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
972
214922
    env->isolate()->SetIdle(true);
973
214922
  });
974
6494
  uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
975
214716
    Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
976
214716
    env->isolate()->SetIdle(false);
977
214716
  });
978
6494
}
979
980
769460
void Environment::PrintSyncTrace() const {
981
769460
  if (!trace_sync_io_) return;
982
983
2
  HandleScope handle_scope(isolate());
984
985
1
  fprintf(
986
      stderr, "(node:%d) WARNING: Detected use of sync API\n", uv_os_getpid());
987
1
  PrintStackTrace(isolate(),
988
                  StackTrace::CurrentStackTrace(
989
                      isolate(), stack_trace_limit(), StackTrace::kDetailed));
990
}
991
992
5567
MaybeLocal<Value> Environment::RunSnapshotSerializeCallback() const {
993
5567
  EscapableHandleScope handle_scope(isolate());
994
11134
  if (!snapshot_serialize_callback().IsEmpty()) {
995
1
    Context::Scope context_scope(context());
996
1
    return handle_scope.EscapeMaybe(snapshot_serialize_callback()->Call(
997
3
        context(), v8::Undefined(isolate()), 0, nullptr));
998
  }
999
11132
  return handle_scope.Escape(Undefined(isolate()));
1000
}
1001
1002
MaybeLocal<Value> Environment::RunSnapshotDeserializeMain() const {
1003
  EscapableHandleScope handle_scope(isolate());
1004
  if (!snapshot_deserialize_main().IsEmpty()) {
1005
    Context::Scope context_scope(context());
1006
    return handle_scope.EscapeMaybe(snapshot_deserialize_main()->Call(
1007
        context(), v8::Undefined(isolate()), 0, nullptr));
1008
  }
1009
  return handle_scope.Escape(Undefined(isolate()));
1010
}
1011
1012
5922
void Environment::RunCleanup() {
1013
5922
  started_cleanup_ = true;
1014

16967
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "RunCleanup");
1015
5922
  bindings_.clear();
1016
  // Only BaseObject's cleanups are registered as per-realm cleanup hooks now.
1017
  // Defer the BaseObject cleanup after handles are cleaned up.
1018
5922
  CleanupHandles();
1019
1020

24418
  while (!cleanup_queue_.empty() || principal_realm_->HasCleanupHooks() ||
1021
11846
         native_immediates_.size() > 0 ||
1022

24416
         native_immediates_threadsafe_.size() > 0 ||
1023
5922
         native_immediates_interrupts_.size() > 0) {
1024
    // TODO(legendecas): cleanup handles in per-realm cleanup hooks as well.
1025
5906
    principal_realm_->RunCleanup();
1026
5906
    cleanup_queue_.Drain();
1027
5906
    CleanupHandles();
1028
  }
1029
1030
5925
  for (const int fd : unmanaged_fds_) {
1031
    uv_fs_t close_req;
1032
3
    uv_fs_close(nullptr, &close_req, fd, nullptr);
1033
3
    uv_fs_req_cleanup(&close_req);
1034
  }
1035
5922
}
1036
1037
6604
void Environment::RunAtExitCallbacks() {
1038

18916
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "AtExit");
1039
19623
  for (ExitCallback at_exit : at_exit_functions_) {
1040
13019
    at_exit.cb_(at_exit.arg_);
1041
  }
1042
6604
  at_exit_functions_.clear();
1043
6604
}
1044
1045
13057
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
1046
13057
  at_exit_functions_.push_front(ExitCallback{cb, arg});
1047
13057
}
1048
1049
254025
void Environment::RunAndClearInterrupts() {
1050
254025
  while (native_immediates_interrupts_.size() > 0) {
1051
10737
    NativeImmediateQueue queue;
1052
    {
1053
21478
      Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
1054
10739
      queue.ConcatMove(std::move(native_immediates_interrupts_));
1055
    }
1056
10739
    DebugSealHandleScope seal_handle_scope(isolate());
1057
1058
21484
    while (auto head = queue.Shift())
1059
21492
      head->Call(this);
1060
  }
1061
243286
}
1062
1063
232784
void Environment::RunAndClearNativeImmediates(bool only_refed) {
1064

470916
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment),
1065
               "RunAndClearNativeImmediates");
1066
465560
  HandleScope handle_scope(isolate_);
1067
  // In case the Isolate is no longer accessible just use an empty Local. This
1068
  // is not an issue for InternalCallbackScope as this case is already handled
1069
  // in its constructor but we avoid calls into v8 which can crash the process
1070
  // in debug builds.
1071
  Local<Object> obj =
1072
232784
      can_call_into_js() ? Object::New(isolate_) : Local<Object>();
1073
465560
  InternalCallbackScope cb_scope(this, obj, {0, 0});
1074
1075
232784
  size_t ref_count = 0;
1076
1077
  // Handle interrupts first. These functions are not allowed to throw
1078
  // exceptions, so we do not need to handle that.
1079
232784
  RunAndClearInterrupts();
1080
1081
465565
  auto drain_list = [&](NativeImmediateQueue* queue) {
1082
931123
    TryCatchScope try_catch(this);
1083
465565
    DebugSealHandleScope seal_handle_scope(isolate());
1084
537458
    while (auto head = queue->Shift()) {
1085
71902
      bool is_refed = head->flags() & CallbackFlags::kRefed;
1086
71902
      if (is_refed)
1087
47023
        ref_count++;
1088
1089

71902
      if (is_refed || !only_refed)
1090
71592
        head->Call(this);
1091
1092
71897
      head.reset();  // Destroy now so that this is also observed by try_catch.
1093
1094
71897
      if (UNLIKELY(try_catch.HasCaught())) {
1095

4
        if (!try_catch.HasTerminated() && can_call_into_js())
1096
3
          errors::TriggerUncaughtException(isolate(), try_catch);
1097
1098
2
        return true;
1099
      }
1100
71893
    }
1101
465556
    return false;
1102
232783
  };
1103
232784
  while (drain_list(&native_immediates_)) {}
1104
1105
232780
  immediate_info()->ref_count_dec(ref_count);
1106
1107
232780
  if (immediate_info()->ref_count() == 0)
1108
175650
    ToggleImmediateRef(false);
1109
1110
  // It is safe to check .size() first, because there is a causal relationship
1111
  // between pushes to the threadsafe immediate list and this function being
1112
  // called. For the common case, it's worth checking the size first before
1113
  // establishing a mutex lock.
1114
  // This is intentionally placed after the `ref_count` handling, because when
1115
  // refed threadsafe immediates are created, they are not counted towards the
1116
  // count in immediate_info() either.
1117
232776
  NativeImmediateQueue threadsafe_immediates;
1118
232780
  if (native_immediates_threadsafe_.size() > 0) {
1119
2176
    Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
1120
1088
    threadsafe_immediates.ConcatMove(std::move(native_immediates_threadsafe_));
1121
  }
1122
232781
  while (drain_list(&threadsafe_immediates)) {}
1123
232776
}
1124
1125
10751
void Environment::RequestInterruptFromV8() {
1126
  // The Isolate may outlive the Environment, so some logic to handle the
1127
  // situation in which the Environment is destroyed before the handler runs
1128
  // is required.
1129
1130
  // We allocate a new pointer to a pointer to this Environment instance, and
1131
  // try to set it as interrupt_data_. If interrupt_data_ was already set, then
1132
  // callbacks are already scheduled to run and we can delete our own pointer
1133
  // and just return. If it was nullptr previously, the Environment** is stored;
1134
  // ~Environment sets the Environment* contained in it to nullptr, so that
1135
  // the callback can check whether ~Environment has already run and it is thus
1136
  // not safe to access the Environment instance itself.
1137
10751
  Environment** interrupt_data = new Environment*(this);
1138
10751
  Environment** dummy = nullptr;
1139
10751
  if (!interrupt_data_.compare_exchange_strong(dummy, interrupt_data)) {
1140
344
    delete interrupt_data;
1141
344
    return;  // Already scheduled.
1142
  }
1143
1144
10407
  isolate()->RequestInterrupt([](Isolate* isolate, void* data) {
1145
10398
    std::unique_ptr<Environment*> env_ptr { static_cast<Environment**>(data) };
1146
10398
    Environment* env = *env_ptr;
1147
10398
    if (env == nullptr) {
1148
      // The Environment has already been destroyed. That should be okay; any
1149
      // callback added before the Environment shuts down would have been
1150
      // handled during cleanup.
1151
11
      return;
1152
    }
1153
10387
    env->interrupt_data_.store(nullptr);
1154
10387
    env->RunAndClearInterrupts();
1155
  }, interrupt_data);
1156
}
1157
1158
10529
void Environment::ScheduleTimer(int64_t duration_ms) {
1159
10529
  if (started_cleanup_) return;
1160
10529
  uv_timer_start(timer_handle(), RunTimers, duration_ms, 0);
1161
}
1162
1163
4081
void Environment::ToggleTimerRef(bool ref) {
1164
4081
  if (started_cleanup_) return;
1165
1166
4081
  if (ref) {
1167
2724
    uv_ref(reinterpret_cast<uv_handle_t*>(timer_handle()));
1168
  } else {
1169
1357
    uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
1170
  }
1171
}
1172
1173
8475
void Environment::RunTimers(uv_timer_t* handle) {
1174
8475
  Environment* env = Environment::from_timer_handle(handle);
1175

9010
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "RunTimers");
1176
1177
8475
  if (!env->can_call_into_js())
1178
    return;
1179
1180
8475
  HandleScope handle_scope(env->isolate());
1181
8475
  Context::Scope context_scope(env->context());
1182
1183
8475
  Local<Object> process = env->process_object();
1184
8475
  InternalCallbackScope scope(env, process, {0, 0});
1185
1186
8475
  Local<Function> cb = env->timers_callback_function();
1187
  MaybeLocal<Value> ret;
1188
8475
  Local<Value> arg = env->GetNow();
1189
  // This code will loop until all currently due timers will process. It is
1190
  // impossible for us to end up in an infinite loop due to how the JS-side
1191
  // is structured.
1192
38
  do {
1193
8513
    TryCatchScope try_catch(env);
1194
8513
    try_catch.SetVerbose(true);
1195
8513
    ret = cb->Call(env->context(), process, 1, &arg);
1196

8503
  } while (ret.IsEmpty() && env->can_call_into_js());
1197
1198
  // NOTE(apapirovski): If it ever becomes possible that `call_into_js` above
1199
  // is reset back to `true` after being previously set to `false` then this
1200
  // code becomes invalid and needs to be rewritten. Otherwise catastrophic
1201
  // timers corruption will occur and all timers behaviour will become
1202
  // entirely unpredictable.
1203
8465
  if (ret.IsEmpty())
1204
6
    return;
1205
1206
  // To allow for less JS-C++ boundary crossing, the value returned from JS
1207
  // serves a few purposes:
1208
  // 1. If it's 0, no more timers exist and the handle should be unrefed
1209
  // 2. If it's > 0, the value represents the next timer's expiry and there
1210
  //    is at least one timer remaining that is refed.
1211
  // 3. If it's < 0, the absolute value represents the next timer's expiry
1212
  //    and there are no timers that are refed.
1213
  int64_t expiry_ms =
1214
8459
      ret.ToLocalChecked()->IntegerValue(env->context()).FromJust();
1215
1216
8459
  uv_handle_t* h = reinterpret_cast<uv_handle_t*>(handle);
1217
1218
8459
  if (expiry_ms != 0) {
1219
    int64_t duration_ms =
1220
7278
        llabs(expiry_ms) - (uv_now(env->event_loop()) - env->timer_base());
1221
1222
7278
    env->ScheduleTimer(duration_ms > 0 ? duration_ms : 1);
1223
1224
7278
    if (expiry_ms > 0)
1225
6564
      uv_ref(h);
1226
    else
1227
714
      uv_unref(h);
1228
  } else {
1229
1181
    uv_unref(h);
1230
  }
1231
}
1232
1233
1234
214716
void Environment::CheckImmediate(uv_check_t* handle) {
1235
214716
  Environment* env = Environment::from_immediate_check_handle(handle);
1236

217906
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "CheckImmediate");
1237
1238
214716
  HandleScope scope(env->isolate());
1239
214716
  Context::Scope context_scope(env->context());
1240
1241
214716
  env->RunAndClearNativeImmediates();
1242
1243

214716
  if (env->immediate_info()->count() == 0 || !env->can_call_into_js())
1244
158163
    return;
1245
1246
967
  do {
1247
57508
    MakeCallback(env->isolate(),
1248
                 env->process_object(),
1249
                 env->immediate_callback_function(),
1250
                 0,
1251
                 nullptr,
1252
57520
                 {0, 0}).ToLocalChecked();
1253

57508
  } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
1254
1255
56541
  if (env->immediate_info()->ref_count() == 0)
1256
3753
    env->ToggleImmediateRef(false);
1257
}
1258
1259
258122
void Environment::ToggleImmediateRef(bool ref) {
1260
258122
  if (started_cleanup_) return;
1261
1262
246382
  if (ref) {
1263
    // Idle handle is needed only to stop the event loop from blocking in poll.
1264
78702
    uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
1265
  } else {
1266
167680
    uv_idle_stop(immediate_idle_handle());
1267
  }
1268
}
1269
1270
1271
48694
Local<Value> Environment::GetNow() {
1272
48694
  uv_update_time(event_loop());
1273
48694
  uint64_t now = uv_now(event_loop());
1274
48694
  CHECK_GE(now, timer_base());
1275
48694
  now -= timer_base();
1276
48694
  if (now <= 0xffffffff)
1277
97388
    return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
1278
  else
1279
    return Number::New(isolate(), static_cast<double>(now));
1280
}
1281
1282
29
void CollectExceptionInfo(Environment* env,
1283
                          Local<Object> obj,
1284
                          int errorno,
1285
                          const char* err_string,
1286
                          const char* syscall,
1287
                          const char* message,
1288
                          const char* path,
1289
                          const char* dest) {
1290
29
  obj->Set(env->context(),
1291
           env->errno_string(),
1292
116
           Integer::New(env->isolate(), errorno)).Check();
1293
1294
29
  obj->Set(env->context(), env->code_string(),
1295
87
           OneByteString(env->isolate(), err_string)).Check();
1296
1297
29
  if (message != nullptr) {
1298
29
    obj->Set(env->context(), env->message_string(),
1299
116
             OneByteString(env->isolate(), message)).Check();
1300
  }
1301
1302
  Local<Value> path_buffer;
1303
29
  if (path != nullptr) {
1304
    path_buffer =
1305
      Buffer::Copy(env->isolate(), path, strlen(path)).ToLocalChecked();
1306
    obj->Set(env->context(), env->path_string(), path_buffer).Check();
1307
  }
1308
1309
  Local<Value> dest_buffer;
1310
29
  if (dest != nullptr) {
1311
    dest_buffer =
1312
      Buffer::Copy(env->isolate(), dest, strlen(dest)).ToLocalChecked();
1313
    obj->Set(env->context(), env->dest_string(), dest_buffer).Check();
1314
  }
1315
1316
29
  if (syscall != nullptr) {
1317
29
    obj->Set(env->context(), env->syscall_string(),
1318
116
             OneByteString(env->isolate(), syscall)).Check();
1319
  }
1320
29
}
1321
1322
29
void Environment::CollectUVExceptionInfo(Local<Value> object,
1323
                                         int errorno,
1324
                                         const char* syscall,
1325
                                         const char* message,
1326
                                         const char* path,
1327
                                         const char* dest) {
1328

29
  if (!object->IsObject() || errorno == 0)
1329
    return;
1330
1331
29
  Local<Object> obj = object.As<Object>();
1332
29
  const char* err_string = uv_err_name(errorno);
1333
1334

29
  if (message == nullptr || message[0] == '\0') {
1335
29
    message = uv_strerror(errorno);
1336
  }
1337
1338
29
  node::CollectExceptionInfo(this, obj, errorno, err_string,
1339
                             syscall, message, path, dest);
1340
}
1341
1342
6535
ImmediateInfo::ImmediateInfo(Isolate* isolate, const SerializeInfo* info)
1343
6535
    : fields_(isolate, kFieldsCount, MAYBE_FIELD_PTR(info, fields)) {}
1344
1345
7
ImmediateInfo::SerializeInfo ImmediateInfo::Serialize(
1346
    Local<Context> context, SnapshotCreator* creator) {
1347
7
  return {fields_.Serialize(context, creator)};
1348
}
1349
1350
5708
void ImmediateInfo::Deserialize(Local<Context> context) {
1351
5708
  fields_.Deserialize(context);
1352
5708
}
1353
1354
6
std::ostream& operator<<(std::ostream& output,
1355
                         const ImmediateInfo::SerializeInfo& i) {
1356
6
  output << "{ " << i.fields << " }";
1357
6
  return output;
1358
}
1359
1360
37
void ImmediateInfo::MemoryInfo(MemoryTracker* tracker) const {
1361
37
  tracker->TrackField("fields", fields_);
1362
37
}
1363
1364
7
TickInfo::SerializeInfo TickInfo::Serialize(Local<Context> context,
1365
                                            SnapshotCreator* creator) {
1366
7
  return {fields_.Serialize(context, creator)};
1367
}
1368
1369
5708
void TickInfo::Deserialize(Local<Context> context) {
1370
5708
  fields_.Deserialize(context);
1371
5708
}
1372
1373
6
std::ostream& operator<<(std::ostream& output,
1374
                         const TickInfo::SerializeInfo& i) {
1375
6
  output << "{ " << i.fields << " }";
1376
6
  return output;
1377
}
1378
1379
37
void TickInfo::MemoryInfo(MemoryTracker* tracker) const {
1380
37
  tracker->TrackField("fields", fields_);
1381
37
}
1382
1383
6535
TickInfo::TickInfo(Isolate* isolate, const SerializeInfo* info)
1384
    : fields_(
1385
6535
          isolate, kFieldsCount, info == nullptr ? nullptr : &(info->fields)) {}
1386
1387
6535
AsyncHooks::AsyncHooks(Isolate* isolate, const SerializeInfo* info)
1388
    : async_ids_stack_(isolate, 16 * 2, MAYBE_FIELD_PTR(info, async_ids_stack)),
1389
      fields_(isolate, kFieldsCount, MAYBE_FIELD_PTR(info, fields)),
1390
      async_id_fields_(
1391
          isolate, kUidFieldsCount, MAYBE_FIELD_PTR(info, async_id_fields)),
1392

6535
      info_(info) {
1393
13070
  HandleScope handle_scope(isolate);
1394
6535
  if (info == nullptr) {
1395
827
    clear_async_id_stack();
1396
1397
    // Always perform async_hooks checks, not just when async_hooks is enabled.
1398
    // TODO(AndreasMadsen): Consider removing this for LTS releases.
1399
    // See discussion in https://github.com/nodejs/node/pull/15454
1400
    // When removing this, do it by reverting the commit. Otherwise the test
1401
    // and flag changes won't be included.
1402
827
    fields_[kCheck] = 1;
1403
1404
    // kDefaultTriggerAsyncId should be -1, this indicates that there is no
1405
    // specified default value and it should fallback to the executionAsyncId.
1406
    // 0 is not used as the magic value, because that indicates a missing
1407
    // context which is different from a default context.
1408
827
    async_id_fields_[AsyncHooks::kDefaultTriggerAsyncId] = -1;
1409
1410
    // kAsyncIdCounter should start at 1 because that'll be the id the execution
1411
    // context during bootstrap (code that runs before entering uv_run()).
1412
827
    async_id_fields_[AsyncHooks::kAsyncIdCounter] = 1;
1413
  }
1414
6535
}
1415
1416
5708
void AsyncHooks::Deserialize(Local<Context> context) {
1417
5708
  async_ids_stack_.Deserialize(context);
1418
5708
  fields_.Deserialize(context);
1419
5708
  async_id_fields_.Deserialize(context);
1420
1421
  Local<Array> js_execution_async_resources;
1422
5708
  if (info_->js_execution_async_resources != 0) {
1423
    js_execution_async_resources =
1424
5708
        context->GetDataFromSnapshotOnce<Array>(
1425
17124
            info_->js_execution_async_resources).ToLocalChecked();
1426
  } else {
1427
    js_execution_async_resources = Array::New(context->GetIsolate());
1428
  }
1429
5708
  js_execution_async_resources_.Reset(
1430
      context->GetIsolate(), js_execution_async_resources);
1431
1432
  // The native_execution_async_resources_ field requires v8::Local<> instances
1433
  // for async calls whose resources were on the stack as JS objects when they
1434
  // were entered. We cannot recreate this here; however, storing these values
1435
  // on the JS equivalent gives the same result, so we do that instead.
1436
5708
  for (size_t i = 0; i < info_->native_execution_async_resources.size(); ++i) {
1437
    if (info_->native_execution_async_resources[i] == SIZE_MAX)
1438
      continue;
1439
    Local<Object> obj = context->GetDataFromSnapshotOnce<Object>(
1440
                                   info_->native_execution_async_resources[i])
1441
                               .ToLocalChecked();
1442
    js_execution_async_resources->Set(context, i, obj).Check();
1443
  }
1444
5708
  info_ = nullptr;
1445
5708
}
1446
1447
6
std::ostream& operator<<(std::ostream& output,
1448
                         const AsyncHooks::SerializeInfo& i) {
1449
  output << "{\n"
1450
6
         << "  " << i.async_ids_stack << ",  // async_ids_stack\n"
1451
6
         << "  " << i.fields << ",  // fields\n"
1452
6
         << "  " << i.async_id_fields << ",  // async_id_fields\n"
1453
6
         << "  " << i.js_execution_async_resources
1454
         << ",  // js_execution_async_resources\n"
1455
6
         << "  " << i.native_execution_async_resources
1456
         << ",  // native_execution_async_resources\n"
1457
6
         << "}";
1458
6
  return output;
1459
}
1460
1461
7
AsyncHooks::SerializeInfo AsyncHooks::Serialize(Local<Context> context,
1462
                                                SnapshotCreator* creator) {
1463
7
  SerializeInfo info;
1464
  // TODO(joyeecheung): some of these probably don't need to be serialized.
1465
7
  info.async_ids_stack = async_ids_stack_.Serialize(context, creator);
1466
7
  info.fields = fields_.Serialize(context, creator);
1467
7
  info.async_id_fields = async_id_fields_.Serialize(context, creator);
1468
7
  if (!js_execution_async_resources_.IsEmpty()) {
1469
7
    info.js_execution_async_resources = creator->AddData(
1470
        context, js_execution_async_resources_.Get(context->GetIsolate()));
1471
7
    CHECK_NE(info.js_execution_async_resources, 0);
1472
  } else {
1473
    info.js_execution_async_resources = 0;
1474
  }
1475
1476
7
  info.native_execution_async_resources.resize(
1477
      native_execution_async_resources_.size());
1478
7
  for (size_t i = 0; i < native_execution_async_resources_.size(); i++) {
1479
    info.native_execution_async_resources[i] =
1480
        native_execution_async_resources_[i].IsEmpty() ? SIZE_MAX :
1481
            creator->AddData(
1482
                context,
1483
                native_execution_async_resources_[i]);
1484
  }
1485
1486
  // At the moment, promise hooks are not supported in the startup snapshot.
1487
  // TODO(joyeecheung): support promise hooks in the startup snapshot.
1488
7
  CHECK(js_promise_hooks_[0].IsEmpty());
1489
7
  CHECK(js_promise_hooks_[1].IsEmpty());
1490
7
  CHECK(js_promise_hooks_[2].IsEmpty());
1491
7
  CHECK(js_promise_hooks_[3].IsEmpty());
1492
1493
7
  return info;
1494
}
1495
1496
37
void AsyncHooks::MemoryInfo(MemoryTracker* tracker) const {
1497
37
  tracker->TrackField("async_ids_stack", async_ids_stack_);
1498
37
  tracker->TrackField("fields", fields_);
1499
37
  tracker->TrackField("async_id_fields", async_id_fields_);
1500
37
  tracker->TrackField("js_promise_hooks", js_promise_hooks_);
1501
37
}
1502
1503
4
void AsyncHooks::grow_async_ids_stack() {
1504
4
  async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
1505
1506
4
  env()->async_hooks_binding()->Set(
1507
      env()->context(),
1508
      env()->async_ids_stack_string(),
1509
12
      async_ids_stack_.GetJSArray()).Check();
1510
4
}
1511
1512
4
void AsyncHooks::FailWithCorruptedAsyncStack(double expected_async_id) {
1513
4
  fprintf(stderr,
1514
          "Error: async hook stack has become corrupted ("
1515
          "actual: %.f, expected: %.f)\n",
1516
          async_id_fields_.GetValue(kExecutionAsyncId),
1517
          expected_async_id);
1518
4
  DumpBacktrace(stderr);
1519
4
  fflush(stderr);
1520
  // TODO(joyeecheung): should this exit code be more specific?
1521
4
  if (!env()->abort_on_uncaught_exception()) Exit(ExitCode::kGenericUserError);
1522
  fprintf(stderr, "\n");
1523
  fflush(stderr);
1524
  ABORT_NO_BACKTRACE();
1525
}
1526
1527
669
void Environment::Exit(ExitCode exit_code) {
1528
669
  if (options()->trace_exit) {
1529
4
    HandleScope handle_scope(isolate());
1530
    Isolate::DisallowJavascriptExecutionScope disallow_js(
1531
4
        isolate(), Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
1532
1533
2
    if (is_main_thread()) {
1534
1
      fprintf(stderr, "(node:%d) ", uv_os_getpid());
1535
    } else {
1536
1
      fprintf(stderr, "(node:%d, thread:%" PRIu64 ") ",
1537
              uv_os_getpid(), thread_id());
1538
    }
1539
1540
2
    fprintf(stderr,
1541
            "WARNING: Exited the environment with code %d\n",
1542
            static_cast<int>(exit_code));
1543
2
    PrintStackTrace(isolate(),
1544
                    StackTrace::CurrentStackTrace(
1545
                        isolate(), stack_trace_limit(), StackTrace::kDetailed));
1546
  }
1547
669
  process_exit_handler_(this, exit_code);
1548
64
}
1549
1550
6554
void Environment::stop_sub_worker_contexts() {
1551
  DCHECK_EQ(Isolate::GetCurrent(), isolate());
1552
1553
6554
  while (!sub_worker_contexts_.empty()) {
1554
27
    Worker* w = *sub_worker_contexts_.begin();
1555
27
    remove_sub_worker_context(w);
1556
27
    w->Exit(ExitCode::kGenericUserError);
1557
27
    w->JoinThread();
1558
  }
1559
6527
}
1560
1561
10
Environment* Environment::worker_parent_env() const {
1562
10
  if (worker_context() == nullptr) return nullptr;
1563
  return worker_context()->env();
1564
}
1565
1566
69723
void Environment::AddUnmanagedFd(int fd) {
1567
69723
  if (!tracks_unmanaged_fds()) return;
1568
2787
  auto result = unmanaged_fds_.insert(fd);
1569
2787
  if (!result.second) {
1570
    ProcessEmitWarning(
1571
1
        this, "File descriptor %d opened in unmanaged mode twice", fd);
1572
  }
1573
}
1574
1575
69334
void Environment::RemoveUnmanagedFd(int fd) {
1576
69334
  if (!tracks_unmanaged_fds()) return;
1577
2784
  size_t removed_count = unmanaged_fds_.erase(fd);
1578
2784
  if (removed_count == 0) {
1579
    ProcessEmitWarning(
1580
1
        this, "File descriptor %d closed but not opened in unmanaged mode", fd);
1581
  }
1582
}
1583
1584
5543
void Environment::PrintInfoForSnapshotIfDebug() {
1585
11086
  if (enabled_debug_list()->enabled(DebugCategory::MKSNAPSHOT)) {
1586
    fprintf(stderr, "At the exit of the Environment:\n");
1587
    principal_realm()->PrintInfoForSnapshot();
1588
  }
1589
5543
}
1590
1591
7
EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) {
1592
7
  EnvSerializeInfo info;
1593
7
  Local<Context> ctx = context();
1594
1595
7
  info.async_hooks = async_hooks_.Serialize(ctx, creator);
1596
7
  info.immediate_info = immediate_info_.Serialize(ctx, creator);
1597
7
  info.tick_info = tick_info_.Serialize(ctx, creator);
1598
7
  info.performance_state = performance_state_->Serialize(ctx, creator);
1599
7
  info.exit_info = exit_info_.Serialize(ctx, creator);
1600
7
  info.stream_base_state = stream_base_state_.Serialize(ctx, creator);
1601
7
  info.should_abort_on_uncaught_toggle =
1602
7
      should_abort_on_uncaught_toggle_.Serialize(ctx, creator);
1603
1604
7
  info.principal_realm = principal_realm_->Serialize(creator);
1605
  // For now we only support serialization of the main context.
1606
  // TODO(joyeecheung): support de/serialization of vm contexts.
1607
7
  CHECK_EQ(contexts_.size(), 1);
1608

14
  CHECK_EQ(contexts_[0], context());
1609
7
  return info;
1610
}
1611
1612
17124
void Environment::EnqueueDeserializeRequest(DeserializeRequestCallback cb,
1613
                                            Local<Object> holder,
1614
                                            int index,
1615
                                            InternalFieldInfoBase* info) {
1616
  DCHECK_EQ(index, BaseObject::kEmbedderType);
1617
34248
  DeserializeRequest request{cb, {isolate(), holder}, index, info};
1618
17124
  deserialize_requests_.push_back(std::move(request));
1619
17124
}
1620
1621
5708
void Environment::RunDeserializeRequests() {
1622
11416
  HandleScope scope(isolate());
1623
5708
  Local<Context> ctx = context();
1624
5708
  Isolate* is = isolate();
1625
22832
  while (!deserialize_requests_.empty()) {
1626
34248
    DeserializeRequest request(std::move(deserialize_requests_.front()));
1627
17124
    deserialize_requests_.pop_front();
1628
17124
    Local<Object> holder = request.holder.Get(is);
1629
17124
    request.cb(ctx, holder, request.index, request.info);
1630
    request.holder.Reset();
1631
17124
    request.info->Delete();
1632
  }
1633
5708
}
1634
1635
5708
void Environment::DeserializeProperties(const EnvSerializeInfo* info) {
1636
5708
  Local<Context> ctx = context();
1637
1638
5708
  RunDeserializeRequests();
1639
1640
5708
  async_hooks_.Deserialize(ctx);
1641
5708
  immediate_info_.Deserialize(ctx);
1642
5708
  tick_info_.Deserialize(ctx);
1643
5708
  performance_state_->Deserialize(ctx);
1644
5708
  exit_info_.Deserialize(ctx);
1645
5708
  stream_base_state_.Deserialize(ctx);
1646
5708
  should_abort_on_uncaught_toggle_.Deserialize(ctx);
1647
1648
5708
  principal_realm_->DeserializeProperties(&info->principal_realm);
1649
1650
5708
  if (enabled_debug_list_.enabled(DebugCategory::MKSNAPSHOT)) {
1651
    fprintf(stderr, "deserializing...\n");
1652
    std::cerr << *info << "\n";
1653
  }
1654
5708
}
1655
1656
4
uint64_t GuessMemoryAvailableToTheProcess() {
1657
4
  uint64_t free_in_system = uv_get_free_memory();
1658
4
  size_t allowed = uv_get_constrained_memory();
1659
4
  if (allowed == 0) {
1660
    return free_in_system;
1661
  }
1662
  size_t rss;
1663
4
  int err = uv_resident_set_memory(&rss);
1664
4
  if (err) {
1665
    return free_in_system;
1666
  }
1667
4
  if (allowed < rss) {
1668
    // Something is probably wrong. Fallback to the free memory.
1669
    return free_in_system;
1670
  }
1671
  // There may still be room for swap, but we will just leave it here.
1672
4
  return allowed - rss;
1673
}
1674
1675
37
void Environment::BuildEmbedderGraph(Isolate* isolate,
1676
                                     EmbedderGraph* graph,
1677
                                     void* data) {
1678
74
  MemoryTracker tracker(isolate, graph);
1679
37
  Environment* env = static_cast<Environment*>(data);
1680
  // Start traversing embedder objects from the root Environment object.
1681
37
  tracker.Track(env);
1682
37
}
1683
1684
4
size_t Environment::NearHeapLimitCallback(void* data,
1685
                                          size_t current_heap_limit,
1686
                                          size_t initial_heap_limit) {
1687
4
  Environment* env = static_cast<Environment*>(data);
1688
1689
  Debug(env,
1690
        DebugCategory::DIAGNOSTICS,
1691
        "Invoked NearHeapLimitCallback, processing=%d, "
1692
        "current_limit=%" PRIu64 ", "
1693
        "initial_limit=%" PRIu64 "\n",
1694
4
        env->is_in_heapsnapshot_heap_limit_callback_,
1695
8
        static_cast<uint64_t>(current_heap_limit),
1696
4
        static_cast<uint64_t>(initial_heap_limit));
1697
1698
4
  size_t max_young_gen_size = env->isolate_data()->max_young_gen_size;
1699
4
  size_t young_gen_size = 0;
1700
4
  size_t old_gen_size = 0;
1701
1702
4
  HeapSpaceStatistics stats;
1703
4
  size_t num_heap_spaces = env->isolate()->NumberOfHeapSpaces();
1704
40
  for (size_t i = 0; i < num_heap_spaces; ++i) {
1705
36
    env->isolate()->GetHeapSpaceStatistics(&stats, i);
1706

68
    if (strcmp(stats.space_name(), "new_space") == 0 ||
1707
32
        strcmp(stats.space_name(), "new_large_object_space") == 0) {
1708
8
      young_gen_size += stats.space_used_size();
1709
    } else {
1710
28
      old_gen_size += stats.space_used_size();
1711
    }
1712
  }
1713
1714
  Debug(env,
1715
        DebugCategory::DIAGNOSTICS,
1716
        "max_young_gen_size=%" PRIu64 ", "
1717
        "young_gen_size=%" PRIu64 ", "
1718
        "old_gen_size=%" PRIu64 ", "
1719
        "total_size=%" PRIu64 "\n",
1720
8
        static_cast<uint64_t>(max_young_gen_size),
1721
8
        static_cast<uint64_t>(young_gen_size),
1722
8
        static_cast<uint64_t>(old_gen_size),
1723
4
        static_cast<uint64_t>(young_gen_size + old_gen_size));
1724
1725
4
  uint64_t available = GuessMemoryAvailableToTheProcess();
1726
  // TODO(joyeecheung): get a better estimate about the native memory
1727
  // usage into the overhead, e.g. based on the count of objects.
1728
4
  uint64_t estimated_overhead = max_young_gen_size;
1729
  Debug(env,
1730
        DebugCategory::DIAGNOSTICS,
1731
        "Estimated available memory=%" PRIu64 ", "
1732
        "estimated overhead=%" PRIu64 "\n",
1733
8
        static_cast<uint64_t>(available),
1734
4
        static_cast<uint64_t>(estimated_overhead));
1735
1736
  // This might be hit when the snapshot is being taken in another
1737
  // NearHeapLimitCallback invocation.
1738
  // When taking the snapshot, objects in the young generation may be
1739
  // promoted to the old generation, result in increased heap usage,
1740
  // but it should be no more than the young generation size.
1741
  // Ideally, this should be as small as possible - the heap limit
1742
  // can only be restored when the heap usage falls down below the
1743
  // new limit, so in a heap with unbounded growth the isolate
1744
  // may eventually crash with this new limit - effectively raising
1745
  // the heap limit to the new one.
1746
4
  size_t new_limit = current_heap_limit + max_young_gen_size;
1747
4
  if (env->is_in_heapsnapshot_heap_limit_callback_) {
1748
    Debug(env,
1749
          DebugCategory::DIAGNOSTICS,
1750
          "Not generating snapshots in nested callback. "
1751
          "new_limit=%" PRIu64 "\n",
1752
2
          static_cast<uint64_t>(new_limit));
1753
2
    return new_limit;
1754
  }
1755
1756
  // Estimate whether the snapshot is going to use up all the memory
1757
  // available to the process. If so, just give up to prevent the system
1758
  // from killing the process for a system OOM.
1759
2
  if (estimated_overhead > available) {
1760
    Debug(env,
1761
          DebugCategory::DIAGNOSTICS,
1762
          "Not generating snapshots because it's too risky.\n");
1763
    env->RemoveHeapSnapshotNearHeapLimitCallback(0);
1764
    // The new limit must be higher than current_heap_limit or V8 might
1765
    // crash.
1766
    return new_limit;
1767
  }
1768
1769
  // Take the snapshot synchronously.
1770
2
  env->is_in_heapsnapshot_heap_limit_callback_ = true;
1771
1772
4
  std::string dir = env->options()->diagnostic_dir;
1773
2
  if (dir.empty()) {
1774
2
    dir = env->GetCwd();
1775
  }
1776
4
  DiagnosticFilename name(env, "Heap", "heapsnapshot");
1777
2
  std::string filename = dir + kPathSeparator + (*name);
1778
1779
2
  Debug(env, DebugCategory::DIAGNOSTICS, "Start generating %s...\n", *name);
1780
1781
2
  HeapProfiler::HeapSnapshotOptions options;
1782
2
  options.numerics_mode = HeapProfiler::NumericsMode::kExposeNumericValues;
1783
2
  options.snapshot_mode = HeapProfiler::HeapSnapshotMode::kExposeInternals;
1784
2
  heap::WriteSnapshot(env, filename.c_str(), options);
1785
2
  env->heap_limit_snapshot_taken_ += 1;
1786
1787
  Debug(env,
1788
        DebugCategory::DIAGNOSTICS,
1789
        "%" PRIu32 "/%" PRIu32 " snapshots taken.\n",
1790
2
        env->heap_limit_snapshot_taken_,
1791
2
        env->heap_snapshot_near_heap_limit_);
1792
1793
  // Don't take more snapshots than the limit specified.
1794
2
  if (env->heap_limit_snapshot_taken_ == env->heap_snapshot_near_heap_limit_) {
1795
    Debug(env,
1796
          DebugCategory::DIAGNOSTICS,
1797
          "Removing the near heap limit callback");
1798
2
    env->RemoveHeapSnapshotNearHeapLimitCallback(0);
1799
  }
1800
1801
2
  FPrintF(stderr, "Wrote snapshot to %s\n", filename.c_str());
1802
  // Tell V8 to reset the heap limit once the heap usage falls down to
1803
  // 95% of the initial limit.
1804
2
  env->isolate()->AutomaticallyRestoreInitialHeapLimit(0.95);
1805
1806
2
  env->is_in_heapsnapshot_heap_limit_callback_ = false;
1807
1808
  // The new limit must be higher than current_heap_limit or V8 might
1809
  // crash.
1810
2
  return new_limit;
1811
}
1812
1813
37
inline size_t Environment::SelfSize() const {
1814
37
  size_t size = sizeof(*this);
1815
  // Remove non pointer fields that will be tracked in MemoryInfo()
1816
  // TODO(joyeecheung): refactor the MemoryTracker interface so
1817
  // this can be done for common types within the Track* calls automatically
1818
  // if a certain scope is entered.
1819
37
  size -= sizeof(async_hooks_);
1820
37
  size -= sizeof(cleanup_queue_);
1821
37
  size -= sizeof(tick_info_);
1822
37
  size -= sizeof(immediate_info_);
1823
37
  return size;
1824
}
1825
1826
37
void Environment::MemoryInfo(MemoryTracker* tracker) const {
1827
  // Iteratable STLs have their own sizes subtracted from the parent
1828
  // by default.
1829
37
  tracker->TrackField("isolate_data", isolate_data_);
1830
37
  tracker->TrackField("destroy_async_id_list", destroy_async_id_list_);
1831
37
  tracker->TrackField("exec_argv", exec_argv_);
1832
37
  tracker->TrackField("exit_info", exit_info_);
1833
37
  tracker->TrackField("should_abort_on_uncaught_toggle",
1834
37
                      should_abort_on_uncaught_toggle_);
1835
37
  tracker->TrackField("stream_base_state", stream_base_state_);
1836
37
  tracker->TrackField("cleanup_queue", cleanup_queue_);
1837
37
  tracker->TrackField("async_hooks", async_hooks_);
1838
37
  tracker->TrackField("immediate_info", immediate_info_);
1839
37
  tracker->TrackField("tick_info", tick_info_);
1840
37
  tracker->TrackField("principal_realm", principal_realm_);
1841
1842
  // FIXME(joyeecheung): track other fields in Environment.
1843
  // Currently MemoryTracker is unable to track these
1844
  // correctly:
1845
  // - Internal types that do not implement MemoryRetainer yet
1846
  // - STL containers with MemoryRetainer* inside
1847
  // - STL containers with numeric types inside that should not have their
1848
  //   nodes elided e.g. numeric keys in maps.
1849
  // We also need to make sure that when we add a non-pointer field as its own
1850
  // node, we shift its sizeof() size out of the Environment node.
1851
37
}
1852
1853
763341
void Environment::RunWeakRefCleanup() {
1854
763341
  isolate()->ClearKeptObjects();
1855
763341
}
1856
}  // namespace node