GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: env.cc Lines: 839 899 93.3 %
Date: 2022-11-08 04:21:23 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::HeapSpaceStatistics;
43
using v8::Integer;
44
using v8::Isolate;
45
using v8::Local;
46
using v8::MaybeLocal;
47
using v8::NewStringType;
48
using v8::Number;
49
using v8::Object;
50
using v8::Private;
51
using v8::Script;
52
using v8::SnapshotCreator;
53
using v8::StackTrace;
54
using v8::String;
55
using v8::Symbol;
56
using v8::TracingController;
57
using v8::TryCatch;
58
using v8::Undefined;
59
using v8::Value;
60
using worker::Worker;
61
62
int const ContextEmbedderTag::kNodeContextTag = 0x6e6f64;
63
void* const ContextEmbedderTag::kNodeContextTagPtr = const_cast<void*>(
64
    static_cast<const void*>(&ContextEmbedderTag::kNodeContextTag));
65
66
16392
void AsyncHooks::ResetPromiseHooks(Local<Function> init,
67
                                   Local<Function> before,
68
                                   Local<Function> after,
69
                                   Local<Function> resolve) {
70
16392
  js_promise_hooks_[0].Reset(env()->isolate(), init);
71
16392
  js_promise_hooks_[1].Reset(env()->isolate(), before);
72
16392
  js_promise_hooks_[2].Reset(env()->isolate(), after);
73
16392
  js_promise_hooks_[3].Reset(env()->isolate(), resolve);
74
16392
}
75
76
16392
void Environment::ResetPromiseHooks(Local<Function> init,
77
                                    Local<Function> before,
78
                                    Local<Function> after,
79
                                    Local<Function> resolve) {
80
16392
  async_hooks()->ResetPromiseHooks(init, before, after, resolve);
81
82
33129
  for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
83
16737
    if (it->IsEmpty()) {
84
      contexts_.erase(it--);
85
      continue;
86
    }
87
33474
    PersistentToLocal::Weak(isolate_, *it)
88
16737
        ->SetPromiseHooks(init, before, after, resolve);
89
  }
90
16392
}
91
92
// Remember to keep this code aligned with pushAsyncContext() in JS.
93
843727
void AsyncHooks::push_async_context(double async_id,
94
                                    double trigger_async_id,
95
                                    Local<Object> resource) {
96
  // Since async_hooks is experimental, do only perform the check
97
  // when async_hooks is enabled.
98
843727
  if (fields_[kCheck] > 0) {
99
843723
    CHECK_GE(async_id, -1);
100
843723
    CHECK_GE(trigger_async_id, -1);
101
  }
102
103
843727
  uint32_t offset = fields_[kStackLength];
104
843727
  if (offset * 2 >= async_ids_stack_.Length()) grow_async_ids_stack();
105
843727
  async_ids_stack_[2 * offset] = async_id_fields_[kExecutionAsyncId];
106
843727
  async_ids_stack_[2 * offset + 1] = async_id_fields_[kTriggerAsyncId];
107
843727
  fields_[kStackLength] += 1;
108
843727
  async_id_fields_[kExecutionAsyncId] = async_id;
109
843727
  async_id_fields_[kTriggerAsyncId] = trigger_async_id;
110
111
#ifdef DEBUG
112
  for (uint32_t i = offset; i < native_execution_async_resources_.size(); i++)
113
    CHECK(native_execution_async_resources_[i].IsEmpty());
114
#endif
115
116
  // When this call comes from JS (as a way of increasing the stack size),
117
  // `resource` will be empty, because JS caches these values anyway.
118
843727
  if (!resource.IsEmpty()) {
119
843723
    native_execution_async_resources_.resize(offset + 1);
120
    // Caveat: This is a v8::Local<> assignment, we do not keep a v8::Global<>!
121
843723
    native_execution_async_resources_[offset] = resource;
122
  }
123
843727
}
124
125
// Remember to keep this code aligned with popAsyncContext() in JS.
126
843277
bool AsyncHooks::pop_async_context(double async_id) {
127
  // In case of an exception then this may have already been reset, if the
128
  // stack was multiple MakeCallback()'s deep.
129
843277
  if (UNLIKELY(fields_[kStackLength] == 0)) return false;
130
131
  // Ask for the async_id to be restored as a check that the stack
132
  // hasn't been corrupted.
133
1684440
  if (UNLIKELY(fields_[kCheck] > 0 &&
134

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

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

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



















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



83790
  PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
350






139650
  PER_ISOLATE_SYMBOL_PROPERTIES(VY)
351










































































































































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












































































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

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



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

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

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

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

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

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

23446
  while (!cleanup_queue_.empty() || principal_realm_->HasCleanupHooks() ||
1015
11370
         native_immediates_.size() > 0 ||
1016

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

18484
  TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "AtExit");
1033
19154
  for (ExitCallback at_exit : at_exit_functions_) {
1034
12707
    at_exit.cb_(at_exit.arg_);
1035
  }
1036
6447
  at_exit_functions_.clear();
1037
6447
}
1038
1039
12735
void Environment::AtExit(void (*cb)(void* arg), void* arg) {
1040
12735
  at_exit_functions_.push_front(ExitCallback{cb, arg});
1041
12735
}
1042
1043
250425
void Environment::RunAndClearInterrupts() {
1044
250425
  while (native_immediates_interrupts_.size() > 0) {
1045
10654
    NativeImmediateQueue queue;
1046
    {
1047
21312
      Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
1048
10656
      queue.ConcatMove(std::move(native_immediates_interrupts_));
1049
    }
1050
10656
    DebugSealHandleScope seal_handle_scope(isolate());
1051
1052
21320
    while (auto head = queue.Shift())
1053
21330
      head->Call(this);
1054
  }
1055
239769
}
1056
1057
229392
void Environment::RunAndClearNativeImmediates(bool only_refed) {
1058

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

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

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

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

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

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

211730
  if (env->immediate_info()->count() == 0 || !env->can_call_into_js())
1238
156148
    return;
1239
1240
951
  do {
1241
56521
    MakeCallback(env->isolate(),
1242
                 env->process_object(),
1243
                 env->immediate_callback_function(),
1244
                 0,
1245
                 nullptr,
1246
56533
                 {0, 0}).ToLocalChecked();
1247

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

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

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

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

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

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