GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: env.cc Lines: 843 902 93.5 %
Date: 2022-11-09 04:21:35 Branches: 806 1402 57.5 %

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
16392
void AsyncHooks::ResetPromiseHooks(Local<Function> init,
68
                                   Local<Function> before,
69
                                   Local<Function> after,
70
                                   Local<Function> resolve) {
71
16392
  js_promise_hooks_[0].Reset(env()->isolate(), init);
72
16392
  js_promise_hooks_[1].Reset(env()->isolate(), before);
73
16392
  js_promise_hooks_[2].Reset(env()->isolate(), after);
74
16392
  js_promise_hooks_[3].Reset(env()->isolate(), resolve);
75
16392
}
76
77
16392
void Environment::ResetPromiseHooks(Local<Function> init,
78
                                    Local<Function> before,
79
                                    Local<Function> after,
80
                                    Local<Function> resolve) {
81
16392
  async_hooks()->ResetPromiseHooks(init, before, after, resolve);
82
83
33129
  for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
84
16737
    if (it->IsEmpty()) {
85
      contexts_.erase(it--);
86
      continue;
87
    }
88
33474
    PersistentToLocal::Weak(isolate_, *it)
89
16737
        ->SetPromiseHooks(init, before, after, resolve);
90
  }
91
16392
}
92
93
// Remember to keep this code aligned with pushAsyncContext() in JS.
94
851044
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
851044
  if (fields_[kCheck] > 0) {
100
851040
    CHECK_GE(async_id, -1);
101
851040
    CHECK_GE(trigger_async_id, -1);
102
  }
103
104
851044
  uint32_t offset = fields_[kStackLength];
105
851044
  if (offset * 2 >= async_ids_stack_.Length()) grow_async_ids_stack();
106
851044
  async_ids_stack_[2 * offset] = async_id_fields_[kExecutionAsyncId];
107
851044
  async_ids_stack_[2 * offset + 1] = async_id_fields_[kTriggerAsyncId];
108
851044
  fields_[kStackLength] += 1;
109
851044
  async_id_fields_[kExecutionAsyncId] = async_id;
110
851044
  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
851044
  if (!resource.IsEmpty()) {
120
851040
    native_execution_async_resources_.resize(offset + 1);
121
    // Caveat: This is a v8::Local<> assignment, we do not keep a v8::Global<>!
122
851040
    native_execution_async_resources_[offset] = resource;
123
  }
124
851044
}
125
126
// Remember to keep this code aligned with popAsyncContext() in JS.
127
850598
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
850598
  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
1699082
  if (UNLIKELY(fields_[kCheck] > 0 &&
135

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

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

1100219
            native_execution_async_resources_.capacity() / 2 &&
155
250680
        native_execution_async_resources_.size() > 16) {
156
      native_execution_async_resources_.shrink_to_fit();
157
    }
158
  }
159
160
1699078
  if (UNLIKELY(js_execution_async_resources()->Length() > offset)) {
161
46824
    HandleScope handle_scope(env()->isolate());
162
93648
    USE(js_execution_async_resources()->Set(
163
        env()->context(),
164
        env()->length_string(),
165
187296
        Integer::NewFromUnsigned(env()->isolate(), offset)));
166
  }
167
168
849539
  return fields_[kStackLength] > 0;
169
}
170
171
2319
void AsyncHooks::clear_async_id_stack() {
172
2319
  if (env()->can_call_into_js()) {
173
1353
    Isolate* isolate = env()->isolate();
174
2706
    HandleScope handle_scope(isolate);
175
1353
    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
2319
  native_execution_async_resources_.clear();
184
2319
  native_execution_async_resources_.shrink_to_fit();
185
186
2319
  async_id_fields_[kExecutionAsyncId] = 0;
187
2319
  async_id_fields_[kTriggerAsyncId] = 0;
188
2319
  fields_[kStackLength] = 0;
189
2319
}
190
191
7009
void AsyncHooks::InstallPromiseHooks(Local<Context> ctx) {
192
21027
  ctx->SetPromiseHooks(js_promise_hooks_[0].IsEmpty()
193
7009
                           ? Local<Function>()
194
205
                           : PersistentToLocal::Strong(js_promise_hooks_[0]),
195
7009
                       js_promise_hooks_[1].IsEmpty()
196
7009
                           ? Local<Function>()
197
205
                           : PersistentToLocal::Strong(js_promise_hooks_[1]),
198
7009
                       js_promise_hooks_[2].IsEmpty()
199
7009
                           ? Local<Function>()
200
205
                           : PersistentToLocal::Strong(js_promise_hooks_[2]),
201
7009
                       js_promise_hooks_[3].IsEmpty()
202
7009
                           ? Local<Function>()
203
                           : PersistentToLocal::Strong(js_promise_hooks_[3]));
204
7009
}
205
206
7009
void Environment::TrackContext(Local<Context> context) {
207
7009
  size_t id = contexts_.size();
208
7009
  contexts_.resize(id + 1);
209
7009
  contexts_[id].Reset(isolate_, context);
210
7009
  contexts_[id].SetWeak();
211
7009
}
212
213
511
void Environment::UntrackContext(Local<Context> context) {
214
1022
  HandleScope handle_scope(isolate_);
215
511
  contexts_.erase(std::remove_if(contexts_.begin(),
216
                                 contexts_.end(),
217
2846
                                 [&](auto&& el) { return el.IsEmpty(); }),
218
1022
                  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
466
      it->Reset();
223
466
      contexts_.erase(it);
224
466
      break;
225
    }
226
  }
227
511
}
228
229
219643
AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
230
219643
    Environment* env, double default_trigger_async_id)
231
219643
    : async_hooks_(env->async_hooks()) {
232
219643
  if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
233
219643
    CHECK_GE(default_trigger_async_id, 0);
234
  }
235
236
219643
  old_default_trigger_async_id_ =
237
219643
      async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
238
219643
  async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
239
219643
      default_trigger_async_id;
240
219643
}
241
242
439284
AsyncHooks::DefaultTriggerAsyncIdScope::~DefaultTriggerAsyncIdScope() {
243
219642
  async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
244
219642
      old_default_trigger_async_id_;
245
219642
}
246
247
219643
AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
248
219643
    AsyncWrap* async_wrap)
249
    : DefaultTriggerAsyncIdScope(async_wrap->env(),
250
219643
                                 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
5593
void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
333
5593
  size_t i = 0;
334
5593
  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



83895
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
351






139825
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
352










































































































































3104115
  PER_ISOLATE_STRING_PROPERTIES(VS)
353
#undef V
354
#undef VY
355
#undef VS
356
#undef VP
357
358
329987
  for (size_t j = 0; j < AsyncWrap::PROVIDERS_LENGTH; j++) {
359
    MaybeLocal<String> maybe_field =
360
648788
        isolate_->GetDataFromSnapshotOnce<String>(info->primitive_values[i++]);
361
    Local<String> field;
362
324394
    if (!maybe_field.ToLocal(&field)) {
363
      fprintf(stderr, "Failed to deserialize AsyncWrap provider %zu\n", j);
364
    }
365
324394
    async_wrap_providers_[j].Set(isolate_, field);
366
  }
367
368
5593
  const std::vector<PropInfo>& values = info->template_values;
369
5593
  i = 0;  // index to the array
370
5593
  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












































































240499
  PER_ISOLATE_TEMPLATE_PROPERTIES(V);
391
#undef V
392
5593
}
393
394
799
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
1598
  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
6392
  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
10387
  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
222122
  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
47141
  NODE_ASYNC_PROVIDER_TYPES(V)
455
#undef V
456
457
  // TODO(legendecas): eagerly create per isolate templates.
458
799
  Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
459
1598
  templ->InstanceTemplate()->SetInternalFieldCount(
460
      BaseObject::kInternalFieldCount);
461
799
  templ->Inherit(BaseObject::GetConstructorTemplate(this));
462
799
  set_binding_data_ctor_template(templ);
463
464
799
  contextify::ContextifyContext::InitializeGlobalTemplates(this);
465
799
}
466
467
6392
IsolateData::IsolateData(Isolate* isolate,
468
                         uv_loop_t* event_loop,
469
                         MultiIsolatePlatform* platform,
470
                         ArrayBufferAllocator* node_allocator,
471
6392
                         const IsolateDataSerializeInfo* isolate_data_info)
472
    : isolate_(isolate),
473
      event_loop_(event_loop),
474
52
      node_allocator_(node_allocator == nullptr ? nullptr
475
6340
                                                : node_allocator->GetImpl()),
476
12784
      platform_(platform) {
477
6392
  options_.reset(
478
6392
      new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
479
480
6392
  if (isolate_data_info == nullptr) {
481
799
    CreateProperties();
482
  } else {
483
5593
    DeserializeProperties(isolate_data_info);
484
  }
485
6392
}
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
7009
void Environment::AssignToContext(Local<v8::Context> context,
536
                                  Realm* realm,
537
                                  const ContextInfo& info) {
538
7009
  context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment,
539
                                           this);
540
7009
  context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, realm);
541
  // Used to retrieve bindings
542
14018
  context->SetAlignedPointerInEmbedderData(
543
7009
      ContextEmbedderIndex::kBindingListIndex, &(this->bindings_));
544
545
  // ContextifyContexts will update this to a pointer to the native object.
546
7009
  context->SetAlignedPointerInEmbedderData(
547
      ContextEmbedderIndex::kContextifyContext, nullptr);
548
549
  // This must not be done before other context fields are initialized.
550
7009
  ContextEmbedderTag::TagNodeContext(context);
551
552
#if HAVE_INSPECTOR
553
7009
  inspector_agent()->ContextCreated(context, info);
554
#endif  // HAVE_INSPECTOR
555
556
7009
  this->async_hooks()->InstallPromiseHooks(context);
557
7009
  TrackContext(context);
558
7009
}
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
1919
void Environment::add_refs(int64_t diff) {
587
1919
  task_queues_async_refs_ += diff;
588
1919
  CHECK_GE(task_queues_async_refs_, 0);
589
1919
  if (task_queues_async_refs_ == 0)
590
428
    uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
591
  else
592
1491
    uv_ref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
593
1919
}
594
595
67135
uv_buf_t Environment::allocate_managed_buffer(const size_t suggested_size) {
596
134270
  NoArrayBufferZeroFillScope no_zero_fill_scope(isolate_data());
597
  std::unique_ptr<v8::BackingStore> bs =
598
67135
      v8::ArrayBuffer::NewBackingStore(isolate(), suggested_size);
599
67135
  uv_buf_t buf = uv_buf_init(static_cast<char*>(bs->Data()), bs->ByteLength());
600
67135
  released_allocated_buffers_.emplace(buf.base, std::move(bs));
601
67135
  return buf;
602
}
603
604
82917
std::unique_ptr<v8::BackingStore> Environment::release_managed_buffer(
605
    const uv_buf_t& buf) {
606
82917
  std::unique_ptr<v8::BackingStore> bs;
607
82917
  if (buf.base != nullptr) {
608
67135
    auto it = released_allocated_buffers_.find(buf.base);
609
67135
    CHECK_NE(it, released_allocated_buffers_.end());
610
67135
    bs = std::move(it->second);
611
67135
    released_allocated_buffers_.erase(it);
612
  }
613
82917
  return bs;
614
}
615
616
6385
std::string GetExecPath(const std::vector<std::string>& argv) {
617
  char exec_path_buf[2 * PATH_MAX];
618
6385
  size_t exec_path_len = sizeof(exec_path_buf);
619
6385
  std::string exec_path;
620
6385
  if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
621
6385
    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
6385
  return exec_path;
640
}
641
642
6385
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
6385
                         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
6385
      timer_base_(uv_now(isolate_data->event_loop())),
655
      exec_argv_(exec_args),
656
      argv_(args),
657
      exec_path_(GetExecPath(args)),
658
6385
      exiting_(isolate_, 1, MAYBE_FIELD_PTR(env_info, exiting)),
659
      should_abort_on_uncaught_toggle_(
660
6385
          isolate_,
661
          1,
662
          MAYBE_FIELD_PTR(env_info, should_abort_on_uncaught_toggle)),
663
6385
      stream_base_state_(isolate_,
664
                         StreamBase::kNumStreamBaseStateFields,
665
                         MAYBE_FIELD_PTR(env_info, stream_base_state)),
666
6385
      time_origin_(PERFORMANCE_NOW()),
667
6385
      time_origin_timestamp_(GetCurrentTimeInMicroseconds()),
668
      flags_(flags),
669
6385
      thread_id_(thread_id.id == static_cast<uint64_t>(-1)
670
6385
                     ? AllocateEnvironmentThreadId().id
671



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

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

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

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

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

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

23486
  while (!cleanup_queue_.empty() || principal_realm_->HasCleanupHooks() ||
1016
11392
         native_immediates_.size() > 0 ||
1017

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

18513
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "AtExit");
1034
19187
  for (ExitCallback at_exit : at_exit_functions_) {
1035
12729
    at_exit.cb_(at_exit.arg_);
1036
  }
1037
6458
  at_exit_functions_.clear();
1038
6458
}
1039
1040
12757
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
1041
12757
  at_exit_functions_.push_front(ExitCallback{cb, arg});
1042
12757
}
1043
1044
252948
void Environment::RunAndClearInterrupts() {
1045
252948
  while (native_immediates_interrupts_.size() > 0) {
1046
10629
    NativeImmediateQueue queue;
1047
    {
1048
21262
      Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
1049
10631
      queue.ConcatMove(std::move(native_immediates_interrupts_));
1050
    }
1051
10631
    DebugSealHandleScope seal_handle_scope(isolate());
1052
1053
21271
    while (auto head = queue.Shift())
1054
21282
      head->Call(this);
1055
  }
1056
242317
}
1057
1058
231969
void Environment::RunAndClearNativeImmediates(bool only_refed) {
1059

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

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

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

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

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

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

214326
  if (env->immediate_info()->count() == 0 || !env->can_call_into_js())
1239
156513
    return;
1240
1241
951
  do {
1242
58752
    MakeCallback(env->isolate(),
1243
                 env->process_object(),
1244
                 env->immediate_callback_function(),
1245
                 0,
1246
                 nullptr,
1247
58764
                 {0, 0}).ToLocalChecked();
1248

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

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

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

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

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

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