GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: env.cc Lines: 842 902 93.3 %
Date: 2022-12-07 04:23:16 Branches: 805 1402 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
16464
void AsyncHooks::ResetPromiseHooks(Local<Function> init,
68
                                   Local<Function> before,
69
                                   Local<Function> after,
70
                                   Local<Function> resolve) {
71
16464
  js_promise_hooks_[0].Reset(env()->isolate(), init);
72
16464
  js_promise_hooks_[1].Reset(env()->isolate(), before);
73
16464
  js_promise_hooks_[2].Reset(env()->isolate(), after);
74
16464
  js_promise_hooks_[3].Reset(env()->isolate(), resolve);
75
16464
}
76
77
16464
void Environment::ResetPromiseHooks(Local<Function> init,
78
                                    Local<Function> before,
79
                                    Local<Function> after,
80
                                    Local<Function> resolve) {
81
16464
  async_hooks()->ResetPromiseHooks(init, before, after, resolve);
82
83
33279
  for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
84
16815
    if (it->IsEmpty()) {
85
      contexts_.erase(it--);
86
      continue;
87
    }
88
33630
    PersistentToLocal::Weak(isolate_, *it)
89
16815
        ->SetPromiseHooks(init, before, after, resolve);
90
  }
91
16464
}
92
93
// Remember to keep this code aligned with pushAsyncContext() in JS.
94
855435
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
855435
  if (fields_[kCheck] > 0) {
100
855431
    CHECK_GE(async_id, -1);
101
855431
    CHECK_GE(trigger_async_id, -1);
102
  }
103
104
855435
  uint32_t offset = fields_[kStackLength];
105
855435
  if (offset * 2 >= async_ids_stack_.Length()) grow_async_ids_stack();
106
855435
  async_ids_stack_[2 * offset] = async_id_fields_[kExecutionAsyncId];
107
855435
  async_ids_stack_[2 * offset + 1] = async_id_fields_[kTriggerAsyncId];
108
855435
  fields_[kStackLength] += 1;
109
855435
  async_id_fields_[kExecutionAsyncId] = async_id;
110
855435
  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
855435
  if (!resource.IsEmpty()) {
120
855431
    native_execution_async_resources_.resize(offset + 1);
121
    // Caveat: This is a v8::Local<> assignment, we do not keep a v8::Global<>!
122
855431
    native_execution_async_resources_[offset] = resource;
123
  }
124
855435
}
125
126
// Remember to keep this code aligned with popAsyncContext() in JS.
127
854989
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
854989
  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
1707864
  if (UNLIKELY(fields_[kCheck] > 0 &&
135

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

1707860
             !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
853930
    native_execution_async_resources_.resize(offset);
153
853930
    if (native_execution_async_resources_.size() <
154

1104988
            native_execution_async_resources_.capacity() / 2 &&
155
251058
        native_execution_async_resources_.size() > 16) {
156
      native_execution_async_resources_.shrink_to_fit();
157
    }
158
  }
159
160
1707860
  if (UNLIKELY(js_execution_async_resources()->Length() > offset)) {
161
47545
    HandleScope handle_scope(env()->isolate());
162
95090
    USE(js_execution_async_resources()->Set(
163
        env()->context(),
164
        env()->length_string(),
165
190180
        Integer::NewFromUnsigned(env()->isolate(), offset)));
166
  }
167
168
853930
  return fields_[kStackLength] > 0;
169
}
170
171
2325
void AsyncHooks::clear_async_id_stack() {
172
2325
  if (env()->can_call_into_js()) {
173
1366
    Isolate* isolate = env()->isolate();
174
2732
    HandleScope handle_scope(isolate);
175
1366
    if (!js_execution_async_resources_.IsEmpty()) {
176
2582
      USE(PersistentToLocal::Strong(js_execution_async_resources_)
177
2582
              ->Set(env()->context(),
178
                    env()->length_string(),
179
5164
                    Integer::NewFromUnsigned(isolate, 0)));
180
    }
181
  }
182
183
2325
  native_execution_async_resources_.clear();
184
2325
  native_execution_async_resources_.shrink_to_fit();
185
186
2325
  async_id_fields_[kExecutionAsyncId] = 0;
187
2325
  async_id_fields_[kTriggerAsyncId] = 0;
188
2325
  fields_[kStackLength] = 0;
189
2325
}
190
191
7051
void AsyncHooks::InstallPromiseHooks(Local<Context> ctx) {
192
21153
  ctx->SetPromiseHooks(js_promise_hooks_[0].IsEmpty()
193
7051
                           ? Local<Function>()
194
205
                           : PersistentToLocal::Strong(js_promise_hooks_[0]),
195
7051
                       js_promise_hooks_[1].IsEmpty()
196
7051
                           ? Local<Function>()
197
205
                           : PersistentToLocal::Strong(js_promise_hooks_[1]),
198
7051
                       js_promise_hooks_[2].IsEmpty()
199
7051
                           ? Local<Function>()
200
205
                           : PersistentToLocal::Strong(js_promise_hooks_[2]),
201
7051
                       js_promise_hooks_[3].IsEmpty()
202
7051
                           ? Local<Function>()
203
                           : PersistentToLocal::Strong(js_promise_hooks_[3]));
204
7051
}
205
206
7051
void Environment::TrackContext(Local<Context> context) {
207
7051
  size_t id = contexts_.size();
208
7051
  contexts_.resize(id + 1);
209
7051
  contexts_[id].Reset(isolate_, context);
210
7051
  contexts_[id].SetWeak();
211
7051
}
212
213
505
void Environment::UntrackContext(Local<Context> context) {
214
1010
  HandleScope handle_scope(isolate_);
215
505
  contexts_.erase(std::remove_if(contexts_.begin(),
216
                                 contexts_.end(),
217
2771
                                 [&](auto&& el) { return el.IsEmpty(); }),
218
1010
                  contexts_.end());
219
2266
  for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
220
2221
    Local<Context> saved_context = PersistentToLocal::Weak(isolate_, *it);
221
2221
    if (saved_context == context) {
222
460
      it->Reset();
223
460
      contexts_.erase(it);
224
460
      break;
225
    }
226
  }
227
505
}
228
229
221166
AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
230
221166
    Environment* env, double default_trigger_async_id)
231
221166
    : async_hooks_(env->async_hooks()) {
232
221166
  if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
233
221166
    CHECK_GE(default_trigger_async_id, 0);
234
  }
235
236
221166
  old_default_trigger_async_id_ =
237
221166
      async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
238
221166
  async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
239
221166
      default_trigger_async_id;
240
221166
}
241
242
442330
AsyncHooks::DefaultTriggerAsyncIdScope::~DefaultTriggerAsyncIdScope() {
243
221165
  async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
244
221165
      old_default_trigger_async_id_;
245
221165
}
246
247
221166
AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
248
221166
    AsyncWrap* async_wrap)
249
    : DefaultTriggerAsyncIdScope(async_wrap->env(),
250
221166
                                 async_wrap->get_async_id()) {}
251
252
12
std::ostream& operator<<(std::ostream& output,
253
                         const std::vector<SnapshotIndex>& v) {
254
12
  output << "{ ";
255
2136
  for (const SnapshotIndex i : v) {
256
2124
    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
1946
  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 V(PropertyName, TypeName)                                              \
318
  do {                                                                         \
319
    Local<TypeName> field = PropertyName();                                    \
320
    if (!field.IsEmpty()) {                                                    \
321
      size_t index = creator->AddData(field);                                  \
322
      info.template_values.push_back({#PropertyName, id, index});              \
323
    }                                                                          \
324
    id++;                                                                      \
325
  } while (0);
326



















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



84465
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
351






140775
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
352










































































































































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












































































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

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



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

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

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

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

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

16432
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "RunCleanup");
1011
5735
  bindings_.clear();
1012
  // Only BaseObject's cleanups are registered as per-realm cleanup hooks now.
1013
  // Defer the BaseObject cleanup after handles are cleaned up.
1014
5735
  CleanupHandles();
1015
1016

23658
  while (!cleanup_queue_.empty() || principal_realm_->HasCleanupHooks() ||
1017
11472
         native_immediates_.size() > 0 ||
1018

23656
         native_immediates_threadsafe_.size() > 0 ||
1019
5735
         native_immediates_interrupts_.size() > 0) {
1020
    // TODO(legendecas): cleanup handles in per-realm cleanup hooks as well.
1021
5727
    principal_realm_->RunCleanup();
1022
5727
    cleanup_queue_.Drain();
1023
5727
    CleanupHandles();
1024
  }
1025
1026
5738
  for (const int fd : unmanaged_fds_) {
1027
    uv_fs_t close_req;
1028
3
    uv_fs_close(nullptr, &close_req, fd, nullptr);
1029
3
    uv_fs_req_cleanup(&close_req);
1030
  }
1031
5735
}
1032
1033
6504
void Environment::RunAtExitCallbacks() {
1034

18643
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "AtExit");
1035
19325
  for (ExitCallback at_exit : at_exit_functions_) {
1036
12821
    at_exit.cb_(at_exit.arg_);
1037
  }
1038
6504
  at_exit_functions_.clear();
1039
6504
}
1040
1041
12849
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
1042
12849
  at_exit_functions_.push_front(ExitCallback{cb, arg});
1043
12849
}
1044
1045
254900
void Environment::RunAndClearInterrupts() {
1046
254900
  while (native_immediates_interrupts_.size() > 0) {
1047
10654
    NativeImmediateQueue queue;
1048
    {
1049
21312
      Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
1050
10656
      queue.ConcatMove(std::move(native_immediates_interrupts_));
1051
    }
1052
10656
    DebugSealHandleScope seal_handle_scope(isolate());
1053
1054
21319
    while (auto head = queue.Shift())
1055
21328
      head->Call(this);
1056
  }
1057
244244
}
1058
1059
233880
void Environment::RunAndClearNativeImmediates(bool only_refed) {
1060

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

72611
      if (is_refed || !only_refed)
1086
72324
        head->Call(this);
1087
1088
72606
      head.reset();  // Destroy now so that this is also observed by try_catch.
1089
1090
72606
      if (UNLIKELY(try_catch.HasCaught())) {
1091

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

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

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

219329
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "CheckImmediate");
1233
1234
216169
  HandleScope scope(env->isolate());
1235
216169
  Context::Scope context_scope(env->context());
1236
1237
216169
  env->RunAndClearNativeImmediates();
1238
1239

216169
  if (env->immediate_info()->count() == 0 || !env->can_call_into_js())
1240
156855
    return;
1241
1242
951
  do {
1243
60253
    MakeCallback(env->isolate(),
1244
                 env->process_object(),
1245
                 env->immediate_callback_function(),
1246
                 0,
1247
                 nullptr,
1248
60265
                 {0, 0}).ToLocalChecked();
1249

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

29
  if (!object->IsObject() || errorno == 0)
1325
    return;
1326
1327
29
  Local<Object> obj = object.As<Object>();
1328
29
  const char* err_string = uv_err_name(errorno);
1329
1330

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

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

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

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