• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ResetPromiseHooks(Local<Function> init,Local<Function> before,Local<Function> after,Local<Function> resolve)66 void AsyncHooks::ResetPromiseHooks(Local<Function> init,
67                                    Local<Function> before,
68                                    Local<Function> after,
69                                    Local<Function> resolve) {
70   js_promise_hooks_[0].Reset(env()->isolate(), init);
71   js_promise_hooks_[1].Reset(env()->isolate(), before);
72   js_promise_hooks_[2].Reset(env()->isolate(), after);
73   js_promise_hooks_[3].Reset(env()->isolate(), resolve);
74 }
75 
ResetPromiseHooks(Local<Function> init,Local<Function> before,Local<Function> after,Local<Function> resolve)76 void Environment::ResetPromiseHooks(Local<Function> init,
77                                     Local<Function> before,
78                                     Local<Function> after,
79                                     Local<Function> resolve) {
80   async_hooks()->ResetPromiseHooks(init, before, after, resolve);
81 
82   for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
83     if (it->IsEmpty()) {
84       contexts_.erase(it--);
85       continue;
86     }
87     PersistentToLocal::Weak(isolate_, *it)
88         ->SetPromiseHooks(init, before, after, resolve);
89   }
90 }
91 
92 // Remember to keep this code aligned with pushAsyncContext() in JS.
push_async_context(double async_id,double trigger_async_id,Local<Object> resource)93 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   if (fields_[kCheck] > 0) {
99     CHECK_GE(async_id, -1);
100     CHECK_GE(trigger_async_id, -1);
101   }
102 
103   uint32_t offset = fields_[kStackLength];
104   if (offset * 2 >= async_ids_stack_.Length()) grow_async_ids_stack();
105   async_ids_stack_[2 * offset] = async_id_fields_[kExecutionAsyncId];
106   async_ids_stack_[2 * offset + 1] = async_id_fields_[kTriggerAsyncId];
107   fields_[kStackLength] += 1;
108   async_id_fields_[kExecutionAsyncId] = async_id;
109   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   if (!resource.IsEmpty()) {
119     native_execution_async_resources_.resize(offset + 1);
120     // Caveat: This is a v8::Local<> assignment, we do not keep a v8::Global<>!
121     native_execution_async_resources_[offset] = resource;
122   }
123 }
124 
125 // Remember to keep this code aligned with popAsyncContext() in JS.
pop_async_context(double async_id)126 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   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   if (UNLIKELY(fields_[kCheck] > 0 &&
134                async_id_fields_[kExecutionAsyncId] != async_id)) {
135     FailWithCorruptedAsyncStack(async_id);
136   }
137 
138   uint32_t offset = fields_[kStackLength] - 1;
139   async_id_fields_[kExecutionAsyncId] = async_ids_stack_[2 * offset];
140   async_id_fields_[kTriggerAsyncId] = async_ids_stack_[2 * offset + 1];
141   fields_[kStackLength] = offset;
142 
143   if (LIKELY(offset < native_execution_async_resources_.size() &&
144              !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     native_execution_async_resources_.resize(offset);
152     if (native_execution_async_resources_.size() <
153             native_execution_async_resources_.capacity() / 2 &&
154         native_execution_async_resources_.size() > 16) {
155       native_execution_async_resources_.shrink_to_fit();
156     }
157   }
158 
159   if (UNLIKELY(js_execution_async_resources()->Length() > offset)) {
160     HandleScope handle_scope(env()->isolate());
161     USE(js_execution_async_resources()->Set(
162         env()->context(),
163         env()->length_string(),
164         Integer::NewFromUnsigned(env()->isolate(), offset)));
165   }
166 
167   return fields_[kStackLength] > 0;
168 }
169 
clear_async_id_stack()170 void AsyncHooks::clear_async_id_stack() {
171   if (!js_execution_async_resources_.IsEmpty() && env()->can_call_into_js()) {
172     Isolate* isolate = env()->isolate();
173     HandleScope handle_scope(isolate);
174     USE(PersistentToLocal::Strong(js_execution_async_resources_)
175             ->Set(env()->context(),
176                   env()->length_string(),
177                   Integer::NewFromUnsigned(isolate, 0)));
178   }
179 
180   native_execution_async_resources_.clear();
181   native_execution_async_resources_.shrink_to_fit();
182 
183   async_id_fields_[kExecutionAsyncId] = 0;
184   async_id_fields_[kTriggerAsyncId] = 0;
185   fields_[kStackLength] = 0;
186 }
187 
InstallPromiseHooks(Local<Context> ctx)188 void AsyncHooks::InstallPromiseHooks(Local<Context> ctx) {
189   ctx->SetPromiseHooks(js_promise_hooks_[0].IsEmpty()
190                            ? Local<Function>()
191                            : PersistentToLocal::Strong(js_promise_hooks_[0]),
192                        js_promise_hooks_[1].IsEmpty()
193                            ? Local<Function>()
194                            : PersistentToLocal::Strong(js_promise_hooks_[1]),
195                        js_promise_hooks_[2].IsEmpty()
196                            ? Local<Function>()
197                            : PersistentToLocal::Strong(js_promise_hooks_[2]),
198                        js_promise_hooks_[3].IsEmpty()
199                            ? Local<Function>()
200                            : PersistentToLocal::Strong(js_promise_hooks_[3]));
201 }
202 
TrackContext(Local<Context> context)203 void Environment::TrackContext(Local<Context> context) {
204   size_t id = contexts_.size();
205   contexts_.resize(id + 1);
206   contexts_[id].Reset(isolate_, context);
207   contexts_[id].SetWeak();
208 }
209 
UntrackContext(Local<Context> context)210 void Environment::UntrackContext(Local<Context> context) {
211   HandleScope handle_scope(isolate_);
212   contexts_.erase(std::remove_if(contexts_.begin(),
213                                  contexts_.end(),
214                                  [&](auto&& el) { return el.IsEmpty(); }),
215                   contexts_.end());
216   for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
217     Local<Context> saved_context = PersistentToLocal::Weak(isolate_, *it);
218     if (saved_context == context) {
219       it->Reset();
220       contexts_.erase(it);
221       break;
222     }
223   }
224 }
225 
DefaultTriggerAsyncIdScope(Environment * env,double default_trigger_async_id)226 AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
227     Environment* env, double default_trigger_async_id)
228     : async_hooks_(env->async_hooks()) {
229   if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
230     CHECK_GE(default_trigger_async_id, 0);
231   }
232 
233   old_default_trigger_async_id_ =
234       async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
235   async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
236       default_trigger_async_id;
237 }
238 
~DefaultTriggerAsyncIdScope()239 AsyncHooks::DefaultTriggerAsyncIdScope::~DefaultTriggerAsyncIdScope() {
240   async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
241       old_default_trigger_async_id_;
242 }
243 
DefaultTriggerAsyncIdScope(AsyncWrap * async_wrap)244 AsyncHooks::DefaultTriggerAsyncIdScope::DefaultTriggerAsyncIdScope(
245     AsyncWrap* async_wrap)
246     : DefaultTriggerAsyncIdScope(async_wrap->env(),
247                                  async_wrap->get_async_id()) {}
248 
operator <<(std::ostream & output,const std::vector<SnapshotIndex> & v)249 std::ostream& operator<<(std::ostream& output,
250                          const std::vector<SnapshotIndex>& v) {
251   output << "{ ";
252   for (const SnapshotIndex i : v) {
253     output << i << ", ";
254   }
255   output << " }";
256   return output;
257 }
258 
operator <<(std::ostream & output,const IsolateDataSerializeInfo & i)259 std::ostream& operator<<(std::ostream& output,
260                          const IsolateDataSerializeInfo& i) {
261   output << "{\n"
262          << "// -- primitive begins --\n"
263          << i.primitive_values << ",\n"
264          << "// -- primitive ends --\n"
265          << "// -- template_values begins --\n"
266          << i.template_values << ",\n"
267          << "// -- template_values ends --\n"
268          << "}";
269   return output;
270 }
271 
operator <<(std::ostream & output,const SnapshotMetadata & i)272 std::ostream& operator<<(std::ostream& output, const SnapshotMetadata& i) {
273   output << "{\n"
274          << "  "
275          << (i.type == SnapshotMetadata::Type::kDefault
276                  ? "SnapshotMetadata::Type::kDefault"
277                  : "SnapshotMetadata::Type::kFullyCustomized")
278          << ", // type\n"
279          << "  \"" << i.node_version << "\", // node_version\n"
280          << "  \"" << i.node_arch << "\", // node_arch\n"
281          << "  \"" << i.node_platform << "\", // node_platform\n"
282          << "  " << i.v8_cache_version_tag << ", // v8_cache_version_tag\n"
283          << "}";
284   return output;
285 }
286 
Serialize(SnapshotCreator * creator)287 IsolateDataSerializeInfo IsolateData::Serialize(SnapshotCreator* creator) {
288   Isolate* isolate = creator->GetIsolate();
289   IsolateDataSerializeInfo info;
290   HandleScope handle_scope(isolate);
291   // XXX(joyeecheung): technically speaking, the indexes here should be
292   // consecutive and we could just return a range instead of an array,
293   // but that's not part of the V8 API contract so we use an array
294   // just to be safe.
295 
296 #define VP(PropertyName, StringValue) V(Private, PropertyName)
297 #define VY(PropertyName, StringValue) V(Symbol, PropertyName)
298 #define VS(PropertyName, StringValue) V(String, PropertyName)
299 #define V(TypeName, PropertyName)                                              \
300   info.primitive_values.push_back(                                             \
301       creator->AddData(PropertyName##_.Get(isolate)));
302   PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
303   PER_ISOLATE_SYMBOL_PROPERTIES(VY)
304   PER_ISOLATE_STRING_PROPERTIES(VS)
305 #undef V
306 #undef VY
307 #undef VS
308 #undef VP
309 
310   for (size_t i = 0; i < AsyncWrap::PROVIDERS_LENGTH; i++)
311     info.primitive_values.push_back(creator->AddData(async_wrap_provider(i)));
312 
313   uint32_t id = 0;
314 #define VM(PropertyName) V(PropertyName##_binding, FunctionTemplate)
315 #define V(PropertyName, TypeName)                                              \
316   do {                                                                         \
317     Local<TypeName> field = PropertyName();                                    \
318     if (!field.IsEmpty()) {                                                    \
319       size_t index = creator->AddData(field);                                  \
320       info.template_values.push_back({#PropertyName, id, index});              \
321     }                                                                          \
322     id++;                                                                      \
323   } while (0);
324   PER_ISOLATE_TEMPLATE_PROPERTIES(V)
325   NODE_BINDINGS_WITH_PER_ISOLATE_INIT(VM)
326 #undef V
327 
328   return info;
329 }
330 
DeserializeProperties(const IsolateDataSerializeInfo * info)331 void IsolateData::DeserializeProperties(const IsolateDataSerializeInfo* info) {
332   size_t i = 0;
333   HandleScope handle_scope(isolate_);
334 
335   if (per_process::enabled_debug_list.enabled(DebugCategory::MKSNAPSHOT)) {
336     fprintf(stderr, "deserializing IsolateDataSerializeInfo...\n");
337     std::cerr << *info << "\n";
338   }
339 
340 #define VP(PropertyName, StringValue) V(Private, PropertyName)
341 #define VY(PropertyName, StringValue) V(Symbol, PropertyName)
342 #define VS(PropertyName, StringValue) V(String, PropertyName)
343 #define V(TypeName, PropertyName)                                              \
344   do {                                                                         \
345     MaybeLocal<TypeName> maybe_field =                                         \
346         isolate_->GetDataFromSnapshotOnce<TypeName>(                           \
347             info->primitive_values[i++]);                                      \
348     Local<TypeName> field;                                                     \
349     if (!maybe_field.ToLocal(&field)) {                                        \
350       fprintf(stderr, "Failed to deserialize " #PropertyName "\n");            \
351     }                                                                          \
352     PropertyName##_.Set(isolate_, field);                                      \
353   } while (0);
354   PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
355   PER_ISOLATE_SYMBOL_PROPERTIES(VY)
356   PER_ISOLATE_STRING_PROPERTIES(VS)
357 #undef V
358 #undef VY
359 #undef VS
360 #undef VP
361 
362   for (size_t j = 0; j < AsyncWrap::PROVIDERS_LENGTH; j++) {
363     MaybeLocal<String> maybe_field =
364         isolate_->GetDataFromSnapshotOnce<String>(info->primitive_values[i++]);
365     Local<String> field;
366     if (!maybe_field.ToLocal(&field)) {
367       fprintf(stderr, "Failed to deserialize AsyncWrap provider %zu\n", j);
368     }
369     async_wrap_providers_[j].Set(isolate_, field);
370   }
371 
372   const std::vector<PropInfo>& values = info->template_values;
373   i = 0;  // index to the array
374   uint32_t id = 0;
375 #define VM(PropertyName) V(PropertyName##_binding, FunctionTemplate)
376 #define V(PropertyName, TypeName)                                              \
377   do {                                                                         \
378     if (values.size() > i && id == values[i].id) {                             \
379       const PropInfo& d = values[i];                                           \
380       DCHECK_EQ(d.name, #PropertyName);                                        \
381       MaybeLocal<TypeName> maybe_field =                                       \
382           isolate_->GetDataFromSnapshotOnce<TypeName>(d.index);                \
383       Local<TypeName> field;                                                   \
384       if (!maybe_field.ToLocal(&field)) {                                      \
385         fprintf(stderr,                                                        \
386                 "Failed to deserialize isolate data template " #PropertyName   \
387                 "\n");                                                         \
388       }                                                                        \
389       set_##PropertyName(field);                                               \
390       i++;                                                                     \
391     }                                                                          \
392     id++;                                                                      \
393   } while (0);
394 
395   PER_ISOLATE_TEMPLATE_PROPERTIES(V);
396   NODE_BINDINGS_WITH_PER_ISOLATE_INIT(VM);
397 #undef V
398 }
399 
CreateProperties()400 void IsolateData::CreateProperties() {
401   // Create string and private symbol properties as internalized one byte
402   // strings after the platform is properly initialized.
403   //
404   // Internalized because it makes property lookups a little faster and
405   // because the string is created in the old space straight away.  It's going
406   // to end up in the old space sooner or later anyway but now it doesn't go
407   // through v8::Eternal's new space handling first.
408   //
409   // One byte because our strings are ASCII and we can safely skip V8's UTF-8
410   // decoding step.
411 
412   HandleScope handle_scope(isolate_);
413 
414 #define V(PropertyName, StringValue)                                           \
415   PropertyName##_.Set(                                                         \
416       isolate_,                                                                \
417       Private::New(isolate_,                                                   \
418                    String::NewFromOneByte(                                     \
419                        isolate_,                                               \
420                        reinterpret_cast<const uint8_t*>(StringValue),          \
421                        NewStringType::kInternalized,                           \
422                        sizeof(StringValue) - 1)                                \
423                        .ToLocalChecked()));
424   PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V)
425 #undef V
426 #define V(PropertyName, StringValue)                                           \
427   PropertyName##_.Set(                                                         \
428       isolate_,                                                                \
429       Symbol::New(isolate_,                                                    \
430                   String::NewFromOneByte(                                      \
431                       isolate_,                                                \
432                       reinterpret_cast<const uint8_t*>(StringValue),           \
433                       NewStringType::kInternalized,                            \
434                       sizeof(StringValue) - 1)                                 \
435                       .ToLocalChecked()));
436   PER_ISOLATE_SYMBOL_PROPERTIES(V)
437 #undef V
438 #define V(PropertyName, StringValue)                                           \
439   PropertyName##_.Set(                                                         \
440       isolate_,                                                                \
441       String::NewFromOneByte(isolate_,                                         \
442                              reinterpret_cast<const uint8_t*>(StringValue),    \
443                              NewStringType::kInternalized,                     \
444                              sizeof(StringValue) - 1)                          \
445           .ToLocalChecked());
446   PER_ISOLATE_STRING_PROPERTIES(V)
447 #undef V
448 
449   // Create all the provider strings that will be passed to JS. Place them in
450   // an array so the array index matches the PROVIDER id offset. This way the
451   // strings can be retrieved quickly.
452 #define V(Provider)                                                           \
453   async_wrap_providers_[AsyncWrap::PROVIDER_ ## Provider].Set(                \
454       isolate_,                                                               \
455       String::NewFromOneByte(                                                 \
456         isolate_,                                                             \
457         reinterpret_cast<const uint8_t*>(#Provider),                          \
458         NewStringType::kInternalized,                                         \
459         sizeof(#Provider) - 1).ToLocalChecked());
460   NODE_ASYNC_PROVIDER_TYPES(V)
461 #undef V
462 
463   Local<FunctionTemplate> templ = FunctionTemplate::New(isolate());
464   templ->InstanceTemplate()->SetInternalFieldCount(
465       BaseObject::kInternalFieldCount);
466   templ->Inherit(BaseObject::GetConstructorTemplate(this));
467   set_binding_data_ctor_template(templ);
468   binding::CreateInternalBindingTemplates(this);
469 
470   contextify::ContextifyContext::InitializeGlobalTemplates(this);
471 }
472 
IsolateData(Isolate * isolate,uv_loop_t * event_loop,MultiIsolatePlatform * platform,ArrayBufferAllocator * node_allocator,const IsolateDataSerializeInfo * isolate_data_info)473 IsolateData::IsolateData(Isolate* isolate,
474                          uv_loop_t* event_loop,
475                          MultiIsolatePlatform* platform,
476                          ArrayBufferAllocator* node_allocator,
477                          const IsolateDataSerializeInfo* isolate_data_info)
478     : isolate_(isolate),
479       event_loop_(event_loop),
480       node_allocator_(node_allocator == nullptr ? nullptr
481                                                 : node_allocator->GetImpl()),
482       platform_(platform) {
483   options_.reset(
484       new PerIsolateOptions(*(per_process::cli_options->per_isolate)));
485 
486   if (isolate_data_info == nullptr) {
487     CreateProperties();
488   } else {
489     DeserializeProperties(isolate_data_info);
490   }
491 }
492 
MemoryInfo(MemoryTracker * tracker) const493 void IsolateData::MemoryInfo(MemoryTracker* tracker) const {
494 #define V(PropertyName, StringValue)                                           \
495   tracker->TrackField(#PropertyName, PropertyName());
496   PER_ISOLATE_SYMBOL_PROPERTIES(V)
497 
498   PER_ISOLATE_STRING_PROPERTIES(V)
499 #undef V
500 
501   tracker->TrackField("async_wrap_providers", async_wrap_providers_);
502 
503   if (node_allocator_ != nullptr) {
504     tracker->TrackFieldWithSize(
505         "node_allocator", sizeof(*node_allocator_), "NodeArrayBufferAllocator");
506   }
507   tracker->TrackFieldWithSize(
508       "platform", sizeof(*platform_), "MultiIsolatePlatform");
509   // TODO(joyeecheung): implement MemoryRetainer in the option classes.
510 }
511 
UpdateTraceCategoryState()512 void TrackingTraceStateObserver::UpdateTraceCategoryState() {
513   if (!env_->owns_process_state() || !env_->can_call_into_js()) {
514     // Ideally, we’d have a consistent story that treats all threads/Environment
515     // instances equally here. However, tracing is essentially global, and this
516     // callback is called from whichever thread calls `StartTracing()` or
517     // `StopTracing()`. The only way to do this in a threadsafe fashion
518     // seems to be only tracking this from the main thread, and only allowing
519     // these state modifications from the main thread.
520     return;
521   }
522 
523   if (env_->principal_realm() == nullptr) {
524     return;
525   }
526 
527   bool async_hooks_enabled = (*(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
528                                  TRACING_CATEGORY_NODE1(async_hooks)))) != 0;
529 
530   Isolate* isolate = env_->isolate();
531   HandleScope handle_scope(isolate);
532   Local<Function> cb = env_->trace_category_state_function();
533   if (cb.IsEmpty())
534     return;
535   TryCatchScope try_catch(env_);
536   try_catch.SetVerbose(true);
537   Local<Value> args[] = {Boolean::New(isolate, async_hooks_enabled)};
538   USE(cb->Call(env_->context(), Undefined(isolate), arraysize(args), args));
539 }
540 
AssignToContext(Local<v8::Context> context,Realm * realm,const ContextInfo & info)541 void Environment::AssignToContext(Local<v8::Context> context,
542                                   Realm* realm,
543                                   const ContextInfo& info) {
544   context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment,
545                                            this);
546   context->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, realm);
547   // Used to retrieve bindings
548   context->SetAlignedPointerInEmbedderData(
549       ContextEmbedderIndex::kBindingDataStoreIndex,
550       realm != nullptr ? realm->binding_data_store() : nullptr);
551 
552   // ContextifyContexts will update this to a pointer to the native object.
553   context->SetAlignedPointerInEmbedderData(
554       ContextEmbedderIndex::kContextifyContext, nullptr);
555 
556   // This must not be done before other context fields are initialized.
557   ContextEmbedderTag::TagNodeContext(context);
558 
559 #if HAVE_INSPECTOR
560   inspector_agent()->ContextCreated(context, info);
561 #endif  // HAVE_INSPECTOR
562 
563   this->async_hooks()->InstallPromiseHooks(context);
564   TrackContext(context);
565 }
566 
TryLoadAddon(const char * filename,int flags,const std::function<bool (binding::DLib *)> & was_loaded)567 void Environment::TryLoadAddon(
568     const char* filename,
569     int flags,
570     const std::function<bool(binding::DLib*)>& was_loaded) {
571   loaded_addons_.emplace_back(filename, flags);
572   if (!was_loaded(&loaded_addons_.back())) {
573     loaded_addons_.pop_back();
574   }
575 }
576 
GetCwd()577 std::string Environment::GetCwd() {
578   char cwd[PATH_MAX_BYTES];
579   size_t size = PATH_MAX_BYTES;
580   const int err = uv_cwd(cwd, &size);
581 
582   if (err == 0) {
583     CHECK_GT(size, 0);
584     return cwd;
585   }
586 
587   // This can fail if the cwd is deleted. In that case, fall back to
588   // exec_path.
589   const std::string& exec_path = exec_path_;
590   return exec_path.substr(0, exec_path.find_last_of(kPathSeparator));
591 }
592 
add_refs(int64_t diff)593 void Environment::add_refs(int64_t diff) {
594   task_queues_async_refs_ += diff;
595   CHECK_GE(task_queues_async_refs_, 0);
596   if (task_queues_async_refs_ == 0)
597     uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
598   else
599     uv_ref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
600 }
601 
allocate_managed_buffer(const size_t suggested_size)602 uv_buf_t Environment::allocate_managed_buffer(const size_t suggested_size) {
603   NoArrayBufferZeroFillScope no_zero_fill_scope(isolate_data());
604   std::unique_ptr<v8::BackingStore> bs =
605       v8::ArrayBuffer::NewBackingStore(isolate(), suggested_size);
606   uv_buf_t buf = uv_buf_init(static_cast<char*>(bs->Data()), bs->ByteLength());
607   released_allocated_buffers_.emplace(buf.base, std::move(bs));
608   return buf;
609 }
610 
release_managed_buffer(const uv_buf_t & buf)611 std::unique_ptr<v8::BackingStore> Environment::release_managed_buffer(
612     const uv_buf_t& buf) {
613   std::unique_ptr<v8::BackingStore> bs;
614   if (buf.base != nullptr) {
615     auto it = released_allocated_buffers_.find(buf.base);
616     CHECK_NE(it, released_allocated_buffers_.end());
617     bs = std::move(it->second);
618     released_allocated_buffers_.erase(it);
619   }
620   return bs;
621 }
622 
GetExecPath(const std::vector<std::string> & argv)623 std::string GetExecPath(const std::vector<std::string>& argv) {
624   char exec_path_buf[2 * PATH_MAX];
625   size_t exec_path_len = sizeof(exec_path_buf);
626   std::string exec_path;
627   if (uv_exepath(exec_path_buf, &exec_path_len) == 0) {
628     exec_path = std::string(exec_path_buf, exec_path_len);
629   } else if (argv.size() > 0) {
630     exec_path = argv[0];
631   }
632 
633   // On OpenBSD process.execPath will be relative unless we
634   // get the full path before process.execPath is used.
635 #if defined(__OpenBSD__)
636   uv_fs_t req;
637   req.ptr = nullptr;
638   if (0 ==
639       uv_fs_realpath(nullptr, &req, exec_path.c_str(), nullptr)) {
640     CHECK_NOT_NULL(req.ptr);
641     exec_path = std::string(static_cast<char*>(req.ptr));
642   }
643   uv_fs_req_cleanup(&req);
644 #endif
645 
646   return exec_path;
647 }
648 
Environment(IsolateData * isolate_data,Isolate * isolate,const std::vector<std::string> & args,const std::vector<std::string> & exec_args,const EnvSerializeInfo * env_info,EnvironmentFlags::Flags flags,ThreadId thread_id)649 Environment::Environment(IsolateData* isolate_data,
650                          Isolate* isolate,
651                          const std::vector<std::string>& args,
652                          const std::vector<std::string>& exec_args,
653                          const EnvSerializeInfo* env_info,
654                          EnvironmentFlags::Flags flags,
655                          ThreadId thread_id)
656     : isolate_(isolate),
657       isolate_data_(isolate_data),
658       async_hooks_(isolate, MAYBE_FIELD_PTR(env_info, async_hooks)),
659       immediate_info_(isolate, MAYBE_FIELD_PTR(env_info, immediate_info)),
660       timeout_info_(isolate_, 1, MAYBE_FIELD_PTR(env_info, timeout_info)),
661       tick_info_(isolate, MAYBE_FIELD_PTR(env_info, tick_info)),
662       timer_base_(uv_now(isolate_data->event_loop())),
663       exec_argv_(exec_args),
664       argv_(args),
665       exec_path_(GetExecPath(args)),
666       exiting_(isolate_, 1, MAYBE_FIELD_PTR(env_info, exiting)),
667       should_abort_on_uncaught_toggle_(
668           isolate_,
669           1,
670           MAYBE_FIELD_PTR(env_info, should_abort_on_uncaught_toggle)),
671       stream_base_state_(isolate_,
672                          StreamBase::kNumStreamBaseStateFields,
673                          MAYBE_FIELD_PTR(env_info, stream_base_state)),
674       environment_start_time_(PERFORMANCE_NOW()),
675       flags_(flags),
676       thread_id_(thread_id.id == static_cast<uint64_t>(-1)
677                      ? AllocateEnvironmentThreadId().id
678                      : thread_id.id) {
679 #ifdef NODE_V8_SHARED_RO_HEAP
680   if (!is_main_thread()) {
681     CHECK_NOT_NULL(isolate_data->worker_context());
682     // TODO(addaleax): Adjust for the embedder API snapshot support changes
683     builtin_loader()->CopySourceAndCodeCacheReferenceFrom(
684         isolate_data->worker_context()->env()->builtin_loader());
685   }
686 #endif
687 
688   // We'll be creating new objects so make sure we've entered the context.
689   HandleScope handle_scope(isolate);
690 
691   // Set some flags if only kDefaultFlags was passed. This can make API version
692   // transitions easier for embedders.
693   if (flags_ & EnvironmentFlags::kDefaultFlags) {
694     flags_ = flags_ |
695         EnvironmentFlags::kOwnsProcessState |
696         EnvironmentFlags::kOwnsInspector;
697   }
698 
699   set_env_vars(per_process::system_environment);
700   enabled_debug_list_.Parse(env_vars(), isolate);
701 
702   // We create new copies of the per-Environment option sets, so that it is
703   // easier to modify them after Environment creation. The defaults are
704   // part of the per-Isolate option set, for which in turn the defaults are
705   // part of the per-process option set.
706   options_ = std::make_shared<EnvironmentOptions>(
707       *isolate_data->options()->per_env);
708   inspector_host_port_ = std::make_shared<ExclusiveAccess<HostPort>>(
709       options_->debug_options().host_port);
710 
711   heap_snapshot_near_heap_limit_ =
712       static_cast<uint32_t>(options_->heap_snapshot_near_heap_limit);
713 
714   if (!(flags_ & EnvironmentFlags::kOwnsProcessState)) {
715     set_abort_on_uncaught_exception(false);
716   }
717 
718 #if HAVE_INSPECTOR
719   // We can only create the inspector agent after having cloned the options.
720   inspector_agent_ = std::make_unique<inspector::Agent>(this);
721 #endif
722 
723   if (tracing::AgentWriterHandle* writer = GetTracingAgentWriter()) {
724     trace_state_observer_ = std::make_unique<TrackingTraceStateObserver>(this);
725     if (TracingController* tracing_controller = writer->GetTracingController())
726       tracing_controller->AddTraceStateObserver(trace_state_observer_.get());
727   }
728 
729   destroy_async_id_list_.reserve(512);
730 
731   performance_state_ = std::make_unique<performance::PerformanceState>(
732       isolate, MAYBE_FIELD_PTR(env_info, performance_state));
733 
734   if (*TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
735           TRACING_CATEGORY_NODE1(environment)) != 0) {
736     auto traced_value = tracing::TracedValue::Create();
737     traced_value->BeginArray("args");
738     for (const std::string& arg : args) traced_value->AppendString(arg);
739     traced_value->EndArray();
740     traced_value->BeginArray("exec_args");
741     for (const std::string& arg : exec_args) traced_value->AppendString(arg);
742     traced_value->EndArray();
743     TRACE_EVENT_NESTABLE_ASYNC_BEGIN1(TRACING_CATEGORY_NODE1(environment),
744                                       "Environment",
745                                       this,
746                                       "args",
747                                       std::move(traced_value));
748   }
749 }
750 
Environment(IsolateData * isolate_data,Local<Context> context,const std::vector<std::string> & args,const std::vector<std::string> & exec_args,const EnvSerializeInfo * env_info,EnvironmentFlags::Flags flags,ThreadId thread_id)751 Environment::Environment(IsolateData* isolate_data,
752                          Local<Context> context,
753                          const std::vector<std::string>& args,
754                          const std::vector<std::string>& exec_args,
755                          const EnvSerializeInfo* env_info,
756                          EnvironmentFlags::Flags flags,
757                          ThreadId thread_id)
758     : Environment(isolate_data,
759                   context->GetIsolate(),
760                   args,
761                   exec_args,
762                   env_info,
763                   flags,
764                   thread_id) {
765   InitializeMainContext(context, env_info);
766 }
767 
InitializeMainContext(Local<Context> context,const EnvSerializeInfo * env_info)768 void Environment::InitializeMainContext(Local<Context> context,
769                                         const EnvSerializeInfo* env_info) {
770   principal_realm_ = std::make_unique<Realm>(
771       this, context, MAYBE_FIELD_PTR(env_info, principal_realm));
772   AssignToContext(context, principal_realm_.get(), ContextInfo(""));
773   if (env_info != nullptr) {
774     DeserializeProperties(env_info);
775   }
776 
777   if (!options_->force_async_hooks_checks) {
778     async_hooks_.no_force_checks();
779   }
780 
781   // By default, always abort when --abort-on-uncaught-exception was passed.
782   should_abort_on_uncaught_toggle_[0] = 1;
783 
784   // The process is not exiting by default.
785   set_exiting(false);
786 
787   performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_ENVIRONMENT,
788                            environment_start_time_);
789   performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_NODE_START,
790                            per_process::node_start_time);
791 
792   if (per_process::v8_initialized) {
793     performance_state_->Mark(performance::NODE_PERFORMANCE_MILESTONE_V8_START,
794                             performance::performance_v8_start);
795   }
796 }
797 
~Environment()798 Environment::~Environment() {
799   HandleScope handle_scope(isolate());
800   Local<Context> ctx = context();
801 
802   if (Environment** interrupt_data = interrupt_data_.load()) {
803     // There are pending RequestInterrupt() callbacks. Tell them not to run,
804     // then force V8 to run interrupts by compiling and running an empty script
805     // so as not to leak memory.
806     *interrupt_data = nullptr;
807 
808     Isolate::AllowJavascriptExecutionScope allow_js_here(isolate());
809     TryCatch try_catch(isolate());
810     Context::Scope context_scope(ctx);
811 
812 #ifdef DEBUG
813     bool consistency_check = false;
814     isolate()->RequestInterrupt([](Isolate*, void* data) {
815       *static_cast<bool*>(data) = true;
816     }, &consistency_check);
817 #endif
818 
819     Local<Script> script;
820     if (Script::Compile(ctx, String::Empty(isolate())).ToLocal(&script))
821       USE(script->Run(ctx));
822 
823     DCHECK(consistency_check);
824   }
825 
826   // FreeEnvironment() should have set this.
827   CHECK(is_stopping());
828 
829   if (heapsnapshot_near_heap_limit_callback_added_) {
830     RemoveHeapSnapshotNearHeapLimitCallback(0);
831   }
832 
833   isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback(
834       BuildEmbedderGraph, this);
835 
836 #if HAVE_INSPECTOR
837   // Destroy inspector agent before erasing the context. The inspector
838   // destructor depends on the context still being accessible.
839   inspector_agent_.reset();
840 #endif
841 
842   ctx->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kEnvironment,
843                                        nullptr);
844   ctx->SetAlignedPointerInEmbedderData(ContextEmbedderIndex::kRealm, nullptr);
845 
846   if (trace_state_observer_) {
847     tracing::AgentWriterHandle* writer = GetTracingAgentWriter();
848     CHECK_NOT_NULL(writer);
849     if (TracingController* tracing_controller = writer->GetTracingController())
850       tracing_controller->RemoveTraceStateObserver(trace_state_observer_.get());
851   }
852 
853   TRACE_EVENT_NESTABLE_ASYNC_END0(
854     TRACING_CATEGORY_NODE1(environment), "Environment", this);
855 
856   // Do not unload addons on the main thread. Some addons need to retain memory
857   // beyond the Environment's lifetime, and unloading them early would break
858   // them; with Worker threads, we have the opportunity to be stricter.
859   // Also, since the main thread usually stops just before the process exits,
860   // this is far less relevant here.
861   if (!is_main_thread()) {
862     // Dereference all addons that were loaded into this environment.
863     for (binding::DLib& addon : loaded_addons_) {
864       addon.Close();
865     }
866   }
867 }
868 
InitializeLibuv()869 void Environment::InitializeLibuv() {
870   HandleScope handle_scope(isolate());
871   Context::Scope context_scope(context());
872 
873   CHECK_EQ(0, uv_timer_init(event_loop(), timer_handle()));
874   uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
875 
876   CHECK_EQ(0, uv_check_init(event_loop(), immediate_check_handle()));
877   uv_unref(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
878 
879   CHECK_EQ(0, uv_idle_init(event_loop(), immediate_idle_handle()));
880 
881   CHECK_EQ(0, uv_check_start(immediate_check_handle(), CheckImmediate));
882 
883   // Inform V8's CPU profiler when we're idle.  The profiler is sampling-based
884   // but not all samples are created equal; mark the wall clock time spent in
885   // epoll_wait() and friends so profiling tools can filter it out.  The samples
886   // still end up in v8.log but with state=IDLE rather than state=EXTERNAL.
887   CHECK_EQ(0, uv_prepare_init(event_loop(), &idle_prepare_handle_));
888   CHECK_EQ(0, uv_check_init(event_loop(), &idle_check_handle_));
889 
890   CHECK_EQ(0, uv_async_init(
891       event_loop(),
892       &task_queues_async_,
893       [](uv_async_t* async) {
894         Environment* env = ContainerOf(
895             &Environment::task_queues_async_, async);
896         HandleScope handle_scope(env->isolate());
897         Context::Scope context_scope(env->context());
898         env->RunAndClearNativeImmediates();
899       }));
900   uv_unref(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
901   uv_unref(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
902   uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
903 
904   {
905     Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
906     task_queues_async_initialized_ = true;
907     if (native_immediates_threadsafe_.size() > 0 ||
908         native_immediates_interrupts_.size() > 0) {
909       uv_async_send(&task_queues_async_);
910     }
911   }
912 
913   // Register clean-up cb to be called to clean up the handles
914   // when the environment is freed, note that they are not cleaned in
915   // the one environment per process setup, but will be called in
916   // FreeEnvironment.
917   RegisterHandleCleanups();
918 
919   StartProfilerIdleNotifier();
920 }
921 
ExitEnv(StopFlags::Flags flags)922 void Environment::ExitEnv(StopFlags::Flags flags) {
923   // Should not access non-thread-safe methods here.
924   set_stopping(true);
925   if ((flags & StopFlags::kDoNotTerminateIsolate) == 0)
926     isolate_->TerminateExecution();
927   SetImmediateThreadsafe([](Environment* env) {
928     env->set_can_call_into_js(false);
929     uv_stop(env->event_loop());
930   });
931 }
932 
RegisterHandleCleanups()933 void Environment::RegisterHandleCleanups() {
934   HandleCleanupCb close_and_finish = [](Environment* env, uv_handle_t* handle,
935                                         void* arg) {
936     handle->data = env;
937 
938     env->CloseHandle(handle, [](uv_handle_t* handle) {
939 #ifdef DEBUG
940       memset(handle, 0xab, uv_handle_size(handle->type));
941 #endif
942     });
943   };
944 
945   auto register_handle = [&](uv_handle_t* handle) {
946     RegisterHandleCleanup(handle, close_and_finish, nullptr);
947   };
948   register_handle(reinterpret_cast<uv_handle_t*>(timer_handle()));
949   register_handle(reinterpret_cast<uv_handle_t*>(immediate_check_handle()));
950   register_handle(reinterpret_cast<uv_handle_t*>(immediate_idle_handle()));
951   register_handle(reinterpret_cast<uv_handle_t*>(&idle_prepare_handle_));
952   register_handle(reinterpret_cast<uv_handle_t*>(&idle_check_handle_));
953   register_handle(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
954 }
955 
CleanupHandles()956 void Environment::CleanupHandles() {
957   {
958     Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
959     task_queues_async_initialized_ = false;
960   }
961 
962   Isolate::DisallowJavascriptExecutionScope disallow_js(isolate(),
963       Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
964 
965   RunAndClearNativeImmediates(true /* skip unrefed SetImmediate()s */);
966 
967   for (ReqWrapBase* request : req_wrap_queue_)
968     request->Cancel();
969 
970   for (HandleWrap* handle : handle_wrap_queue_)
971     handle->Close();
972 
973   for (HandleCleanup& hc : handle_cleanup_queue_)
974     hc.cb_(this, hc.handle_, hc.arg_);
975   handle_cleanup_queue_.clear();
976 
977   while (handle_cleanup_waiting_ != 0 ||
978          request_waiting_ != 0 ||
979          !handle_wrap_queue_.IsEmpty()) {
980     uv_run(event_loop(), UV_RUN_ONCE);
981   }
982 }
983 
StartProfilerIdleNotifier()984 void Environment::StartProfilerIdleNotifier() {
985   uv_prepare_start(&idle_prepare_handle_, [](uv_prepare_t* handle) {
986     Environment* env = ContainerOf(&Environment::idle_prepare_handle_, handle);
987     env->isolate()->SetIdle(true);
988   });
989   uv_check_start(&idle_check_handle_, [](uv_check_t* handle) {
990     Environment* env = ContainerOf(&Environment::idle_check_handle_, handle);
991     env->isolate()->SetIdle(false);
992   });
993 }
994 
PrintSyncTrace() const995 void Environment::PrintSyncTrace() const {
996   if (!trace_sync_io_) return;
997 
998   HandleScope handle_scope(isolate());
999 
1000   fprintf(
1001       stderr, "(node:%d) WARNING: Detected use of sync API\n", uv_os_getpid());
1002   PrintStackTrace(isolate(),
1003                   StackTrace::CurrentStackTrace(
1004                       isolate(), stack_trace_limit(), StackTrace::kDetailed));
1005 }
1006 
RunSnapshotSerializeCallback() const1007 MaybeLocal<Value> Environment::RunSnapshotSerializeCallback() const {
1008   EscapableHandleScope handle_scope(isolate());
1009   if (!snapshot_serialize_callback().IsEmpty()) {
1010     Context::Scope context_scope(context());
1011     return handle_scope.EscapeMaybe(snapshot_serialize_callback()->Call(
1012         context(), v8::Undefined(isolate()), 0, nullptr));
1013   }
1014   return handle_scope.Escape(Undefined(isolate()));
1015 }
1016 
RunSnapshotDeserializeMain() const1017 MaybeLocal<Value> Environment::RunSnapshotDeserializeMain() const {
1018   EscapableHandleScope handle_scope(isolate());
1019   if (!snapshot_deserialize_main().IsEmpty()) {
1020     Context::Scope context_scope(context());
1021     return handle_scope.EscapeMaybe(snapshot_deserialize_main()->Call(
1022         context(), v8::Undefined(isolate()), 0, nullptr));
1023   }
1024   return handle_scope.Escape(Undefined(isolate()));
1025 }
1026 
RunCleanup()1027 void Environment::RunCleanup() {
1028   started_cleanup_ = true;
1029   TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "RunCleanup");
1030   // Only BaseObject's cleanups are registered as per-realm cleanup hooks now.
1031   // Defer the BaseObject cleanup after handles are cleaned up.
1032   CleanupHandles();
1033 
1034   while (!cleanup_queue_.empty() || principal_realm_->HasCleanupHooks() ||
1035          native_immediates_.size() > 0 ||
1036          native_immediates_threadsafe_.size() > 0 ||
1037          native_immediates_interrupts_.size() > 0) {
1038     // TODO(legendecas): cleanup handles in per-realm cleanup hooks as well.
1039     principal_realm_->RunCleanup();
1040     cleanup_queue_.Drain();
1041     CleanupHandles();
1042   }
1043 
1044   for (const int fd : unmanaged_fds_) {
1045     uv_fs_t close_req;
1046     uv_fs_close(nullptr, &close_req, fd, nullptr);
1047     uv_fs_req_cleanup(&close_req);
1048   }
1049 }
1050 
RunAtExitCallbacks()1051 void Environment::RunAtExitCallbacks() {
1052   TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "AtExit");
1053   for (ExitCallback at_exit : at_exit_functions_) {
1054     at_exit.cb_(at_exit.arg_);
1055   }
1056   at_exit_functions_.clear();
1057 }
1058 
AtExit(void (* cb)(void * arg),void * arg)1059 void Environment::AtExit(void (*cb)(void* arg), void* arg) {
1060   at_exit_functions_.push_front(ExitCallback{cb, arg});
1061 }
1062 
RunAndClearInterrupts()1063 void Environment::RunAndClearInterrupts() {
1064   while (native_immediates_interrupts_.size() > 0) {
1065     NativeImmediateQueue queue;
1066     {
1067       Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
1068       queue.ConcatMove(std::move(native_immediates_interrupts_));
1069     }
1070     DebugSealHandleScope seal_handle_scope(isolate());
1071 
1072     while (auto head = queue.Shift())
1073       head->Call(this);
1074   }
1075 }
1076 
RunAndClearNativeImmediates(bool only_refed)1077 void Environment::RunAndClearNativeImmediates(bool only_refed) {
1078   TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment),
1079                "RunAndClearNativeImmediates");
1080   HandleScope handle_scope(isolate_);
1081   // In case the Isolate is no longer accessible just use an empty Local. This
1082   // is not an issue for InternalCallbackScope as this case is already handled
1083   // in its constructor but we avoid calls into v8 which can crash the process
1084   // in debug builds.
1085   Local<Object> obj =
1086       can_call_into_js() ? Object::New(isolate_) : Local<Object>();
1087   InternalCallbackScope cb_scope(this, obj, {0, 0});
1088 
1089   size_t ref_count = 0;
1090 
1091   // Handle interrupts first. These functions are not allowed to throw
1092   // exceptions, so we do not need to handle that.
1093   RunAndClearInterrupts();
1094 
1095   auto drain_list = [&](NativeImmediateQueue* queue) {
1096     TryCatchScope try_catch(this);
1097     DebugSealHandleScope seal_handle_scope(isolate());
1098     while (auto head = queue->Shift()) {
1099       bool is_refed = head->flags() & CallbackFlags::kRefed;
1100       if (is_refed)
1101         ref_count++;
1102 
1103       if (is_refed || !only_refed)
1104         head->Call(this);
1105 
1106       head.reset();  // Destroy now so that this is also observed by try_catch.
1107 
1108       if (UNLIKELY(try_catch.HasCaught())) {
1109         if (!try_catch.HasTerminated() && can_call_into_js())
1110           errors::TriggerUncaughtException(isolate(), try_catch);
1111 
1112         return true;
1113       }
1114     }
1115     return false;
1116   };
1117   while (drain_list(&native_immediates_)) {}
1118 
1119   immediate_info()->ref_count_dec(ref_count);
1120 
1121   if (immediate_info()->ref_count() == 0)
1122     ToggleImmediateRef(false);
1123 
1124   // It is safe to check .size() first, because there is a causal relationship
1125   // between pushes to the threadsafe immediate list and this function being
1126   // called. For the common case, it's worth checking the size first before
1127   // establishing a mutex lock.
1128   // This is intentionally placed after the `ref_count` handling, because when
1129   // refed threadsafe immediates are created, they are not counted towards the
1130   // count in immediate_info() either.
1131   NativeImmediateQueue threadsafe_immediates;
1132   if (native_immediates_threadsafe_.size() > 0) {
1133     Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
1134     threadsafe_immediates.ConcatMove(std::move(native_immediates_threadsafe_));
1135   }
1136   while (drain_list(&threadsafe_immediates)) {}
1137 }
1138 
RequestInterruptFromV8()1139 void Environment::RequestInterruptFromV8() {
1140   // The Isolate may outlive the Environment, so some logic to handle the
1141   // situation in which the Environment is destroyed before the handler runs
1142   // is required.
1143 
1144   // We allocate a new pointer to a pointer to this Environment instance, and
1145   // try to set it as interrupt_data_. If interrupt_data_ was already set, then
1146   // callbacks are already scheduled to run and we can delete our own pointer
1147   // and just return. If it was nullptr previously, the Environment** is stored;
1148   // ~Environment sets the Environment* contained in it to nullptr, so that
1149   // the callback can check whether ~Environment has already run and it is thus
1150   // not safe to access the Environment instance itself.
1151   Environment** interrupt_data = new Environment*(this);
1152   Environment** dummy = nullptr;
1153   if (!interrupt_data_.compare_exchange_strong(dummy, interrupt_data)) {
1154     delete interrupt_data;
1155     return;  // Already scheduled.
1156   }
1157 
1158   isolate()->RequestInterrupt([](Isolate* isolate, void* data) {
1159     std::unique_ptr<Environment*> env_ptr { static_cast<Environment**>(data) };
1160     Environment* env = *env_ptr;
1161     if (env == nullptr) {
1162       // The Environment has already been destroyed. That should be okay; any
1163       // callback added before the Environment shuts down would have been
1164       // handled during cleanup.
1165       return;
1166     }
1167     env->interrupt_data_.store(nullptr);
1168     env->RunAndClearInterrupts();
1169   }, interrupt_data);
1170 }
1171 
ScheduleTimer(int64_t duration_ms)1172 void Environment::ScheduleTimer(int64_t duration_ms) {
1173   if (started_cleanup_) return;
1174   uv_timer_start(timer_handle(), RunTimers, duration_ms, 0);
1175 }
1176 
ToggleTimerRef(bool ref)1177 void Environment::ToggleTimerRef(bool ref) {
1178   if (started_cleanup_) return;
1179 
1180   if (ref) {
1181     uv_ref(reinterpret_cast<uv_handle_t*>(timer_handle()));
1182   } else {
1183     uv_unref(reinterpret_cast<uv_handle_t*>(timer_handle()));
1184   }
1185 }
1186 
RunTimers(uv_timer_t * handle)1187 void Environment::RunTimers(uv_timer_t* handle) {
1188   Environment* env = Environment::from_timer_handle(handle);
1189   TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "RunTimers");
1190 
1191   if (!env->can_call_into_js())
1192     return;
1193 
1194   HandleScope handle_scope(env->isolate());
1195   Context::Scope context_scope(env->context());
1196 
1197   Local<Object> process = env->process_object();
1198   InternalCallbackScope scope(env, process, {0, 0});
1199 
1200   Local<Function> cb = env->timers_callback_function();
1201   MaybeLocal<Value> ret;
1202   Local<Value> arg = env->GetNow();
1203   // This code will loop until all currently due timers will process. It is
1204   // impossible for us to end up in an infinite loop due to how the JS-side
1205   // is structured.
1206   do {
1207     TryCatchScope try_catch(env);
1208     try_catch.SetVerbose(true);
1209     ret = cb->Call(env->context(), process, 1, &arg);
1210   } while (ret.IsEmpty() && env->can_call_into_js());
1211 
1212   // NOTE(apapirovski): If it ever becomes possible that `call_into_js` above
1213   // is reset back to `true` after being previously set to `false` then this
1214   // code becomes invalid and needs to be rewritten. Otherwise catastrophic
1215   // timers corruption will occur and all timers behaviour will become
1216   // entirely unpredictable.
1217   if (ret.IsEmpty())
1218     return;
1219 
1220   // To allow for less JS-C++ boundary crossing, the value returned from JS
1221   // serves a few purposes:
1222   // 1. If it's 0, no more timers exist and the handle should be unrefed
1223   // 2. If it's > 0, the value represents the next timer's expiry and there
1224   //    is at least one timer remaining that is refed.
1225   // 3. If it's < 0, the absolute value represents the next timer's expiry
1226   //    and there are no timers that are refed.
1227   int64_t expiry_ms =
1228       ret.ToLocalChecked()->IntegerValue(env->context()).FromJust();
1229 
1230   uv_handle_t* h = reinterpret_cast<uv_handle_t*>(handle);
1231 
1232   if (expiry_ms != 0) {
1233     int64_t duration_ms =
1234         llabs(expiry_ms) - (uv_now(env->event_loop()) - env->timer_base());
1235 
1236     env->ScheduleTimer(duration_ms > 0 ? duration_ms : 1);
1237 
1238     if (expiry_ms > 0)
1239       uv_ref(h);
1240     else
1241       uv_unref(h);
1242   } else {
1243     uv_unref(h);
1244   }
1245 }
1246 
1247 
CheckImmediate(uv_check_t * handle)1248 void Environment::CheckImmediate(uv_check_t* handle) {
1249   Environment* env = Environment::from_immediate_check_handle(handle);
1250   TRACE_EVENT0(TRACING_CATEGORY_NODE1(environment), "CheckImmediate");
1251 
1252   HandleScope scope(env->isolate());
1253   Context::Scope context_scope(env->context());
1254 
1255   env->RunAndClearNativeImmediates();
1256 
1257   if (env->immediate_info()->count() == 0 || !env->can_call_into_js())
1258     return;
1259 
1260   do {
1261     MakeCallback(env->isolate(),
1262                  env->process_object(),
1263                  env->immediate_callback_function(),
1264                  0,
1265                  nullptr,
1266                  {0, 0}).ToLocalChecked();
1267   } while (env->immediate_info()->has_outstanding() && env->can_call_into_js());
1268 
1269   if (env->immediate_info()->ref_count() == 0)
1270     env->ToggleImmediateRef(false);
1271 }
1272 
ToggleImmediateRef(bool ref)1273 void Environment::ToggleImmediateRef(bool ref) {
1274   if (started_cleanup_) return;
1275 
1276   if (ref) {
1277     // Idle handle is needed only to stop the event loop from blocking in poll.
1278     uv_idle_start(immediate_idle_handle(), [](uv_idle_t*){ });
1279   } else {
1280     uv_idle_stop(immediate_idle_handle());
1281   }
1282 }
1283 
1284 
GetNow()1285 Local<Value> Environment::GetNow() {
1286   uv_update_time(event_loop());
1287   uint64_t now = uv_now(event_loop());
1288   CHECK_GE(now, timer_base());
1289   now -= timer_base();
1290   if (now <= 0xffffffff)
1291     return Integer::NewFromUnsigned(isolate(), static_cast<uint32_t>(now));
1292   else
1293     return Number::New(isolate(), static_cast<double>(now));
1294 }
1295 
CollectExceptionInfo(Environment * env,Local<Object> obj,int errorno,const char * err_string,const char * syscall,const char * message,const char * path,const char * dest)1296 void CollectExceptionInfo(Environment* env,
1297                           Local<Object> obj,
1298                           int errorno,
1299                           const char* err_string,
1300                           const char* syscall,
1301                           const char* message,
1302                           const char* path,
1303                           const char* dest) {
1304   obj->Set(env->context(),
1305            env->errno_string(),
1306            Integer::New(env->isolate(), errorno)).Check();
1307 
1308   obj->Set(env->context(), env->code_string(),
1309            OneByteString(env->isolate(), err_string)).Check();
1310 
1311   if (message != nullptr) {
1312     obj->Set(env->context(), env->message_string(),
1313              OneByteString(env->isolate(), message)).Check();
1314   }
1315 
1316   Local<Value> path_buffer;
1317   if (path != nullptr) {
1318     path_buffer =
1319       Buffer::Copy(env->isolate(), path, strlen(path)).ToLocalChecked();
1320     obj->Set(env->context(), env->path_string(), path_buffer).Check();
1321   }
1322 
1323   Local<Value> dest_buffer;
1324   if (dest != nullptr) {
1325     dest_buffer =
1326       Buffer::Copy(env->isolate(), dest, strlen(dest)).ToLocalChecked();
1327     obj->Set(env->context(), env->dest_string(), dest_buffer).Check();
1328   }
1329 
1330   if (syscall != nullptr) {
1331     obj->Set(env->context(), env->syscall_string(),
1332              OneByteString(env->isolate(), syscall)).Check();
1333   }
1334 }
1335 
CollectUVExceptionInfo(Local<Value> object,int errorno,const char * syscall,const char * message,const char * path,const char * dest)1336 void Environment::CollectUVExceptionInfo(Local<Value> object,
1337                                          int errorno,
1338                                          const char* syscall,
1339                                          const char* message,
1340                                          const char* path,
1341                                          const char* dest) {
1342   if (!object->IsObject() || errorno == 0)
1343     return;
1344 
1345   Local<Object> obj = object.As<Object>();
1346   const char* err_string = uv_err_name(errorno);
1347 
1348   if (message == nullptr || message[0] == '\0') {
1349     message = uv_strerror(errorno);
1350   }
1351 
1352   node::CollectExceptionInfo(this, obj, errorno, err_string,
1353                              syscall, message, path, dest);
1354 }
1355 
ImmediateInfo(Isolate * isolate,const SerializeInfo * info)1356 ImmediateInfo::ImmediateInfo(Isolate* isolate, const SerializeInfo* info)
1357     : fields_(isolate, kFieldsCount, MAYBE_FIELD_PTR(info, fields)) {}
1358 
Serialize(Local<Context> context,SnapshotCreator * creator)1359 ImmediateInfo::SerializeInfo ImmediateInfo::Serialize(
1360     Local<Context> context, SnapshotCreator* creator) {
1361   return {fields_.Serialize(context, creator)};
1362 }
1363 
Deserialize(Local<Context> context)1364 void ImmediateInfo::Deserialize(Local<Context> context) {
1365   fields_.Deserialize(context);
1366 }
1367 
operator <<(std::ostream & output,const ImmediateInfo::SerializeInfo & i)1368 std::ostream& operator<<(std::ostream& output,
1369                          const ImmediateInfo::SerializeInfo& i) {
1370   output << "{ " << i.fields << " }";
1371   return output;
1372 }
1373 
MemoryInfo(MemoryTracker * tracker) const1374 void ImmediateInfo::MemoryInfo(MemoryTracker* tracker) const {
1375   tracker->TrackField("fields", fields_);
1376 }
1377 
Serialize(Local<Context> context,SnapshotCreator * creator)1378 TickInfo::SerializeInfo TickInfo::Serialize(Local<Context> context,
1379                                             SnapshotCreator* creator) {
1380   return {fields_.Serialize(context, creator)};
1381 }
1382 
Deserialize(Local<Context> context)1383 void TickInfo::Deserialize(Local<Context> context) {
1384   fields_.Deserialize(context);
1385 }
1386 
operator <<(std::ostream & output,const TickInfo::SerializeInfo & i)1387 std::ostream& operator<<(std::ostream& output,
1388                          const TickInfo::SerializeInfo& i) {
1389   output << "{ " << i.fields << " }";
1390   return output;
1391 }
1392 
MemoryInfo(MemoryTracker * tracker) const1393 void TickInfo::MemoryInfo(MemoryTracker* tracker) const {
1394   tracker->TrackField("fields", fields_);
1395 }
1396 
TickInfo(Isolate * isolate,const SerializeInfo * info)1397 TickInfo::TickInfo(Isolate* isolate, const SerializeInfo* info)
1398     : fields_(
1399           isolate, kFieldsCount, info == nullptr ? nullptr : &(info->fields)) {}
1400 
AsyncHooks(Isolate * isolate,const SerializeInfo * info)1401 AsyncHooks::AsyncHooks(Isolate* isolate, const SerializeInfo* info)
1402     : async_ids_stack_(isolate, 16 * 2, MAYBE_FIELD_PTR(info, async_ids_stack)),
1403       fields_(isolate, kFieldsCount, MAYBE_FIELD_PTR(info, fields)),
1404       async_id_fields_(
1405           isolate, kUidFieldsCount, MAYBE_FIELD_PTR(info, async_id_fields)),
1406       info_(info) {
1407   HandleScope handle_scope(isolate);
1408   if (info == nullptr) {
1409     clear_async_id_stack();
1410 
1411     // Always perform async_hooks checks, not just when async_hooks is enabled.
1412     // TODO(AndreasMadsen): Consider removing this for LTS releases.
1413     // See discussion in https://github.com/nodejs/node/pull/15454
1414     // When removing this, do it by reverting the commit. Otherwise the test
1415     // and flag changes won't be included.
1416     fields_[kCheck] = 1;
1417 
1418     // kDefaultTriggerAsyncId should be -1, this indicates that there is no
1419     // specified default value and it should fallback to the executionAsyncId.
1420     // 0 is not used as the magic value, because that indicates a missing
1421     // context which is different from a default context.
1422     async_id_fields_[AsyncHooks::kDefaultTriggerAsyncId] = -1;
1423 
1424     // kAsyncIdCounter should start at 1 because that'll be the id the execution
1425     // context during bootstrap (code that runs before entering uv_run()).
1426     async_id_fields_[AsyncHooks::kAsyncIdCounter] = 1;
1427   }
1428 }
1429 
Deserialize(Local<Context> context)1430 void AsyncHooks::Deserialize(Local<Context> context) {
1431   async_ids_stack_.Deserialize(context);
1432   fields_.Deserialize(context);
1433   async_id_fields_.Deserialize(context);
1434 
1435   Local<Array> js_execution_async_resources;
1436   if (info_->js_execution_async_resources != 0) {
1437     js_execution_async_resources =
1438         context->GetDataFromSnapshotOnce<Array>(
1439             info_->js_execution_async_resources).ToLocalChecked();
1440   } else {
1441     js_execution_async_resources = Array::New(context->GetIsolate());
1442   }
1443   js_execution_async_resources_.Reset(
1444       context->GetIsolate(), js_execution_async_resources);
1445 
1446   // The native_execution_async_resources_ field requires v8::Local<> instances
1447   // for async calls whose resources were on the stack as JS objects when they
1448   // were entered. We cannot recreate this here; however, storing these values
1449   // on the JS equivalent gives the same result, so we do that instead.
1450   for (size_t i = 0; i < info_->native_execution_async_resources.size(); ++i) {
1451     if (info_->native_execution_async_resources[i] == SIZE_MAX)
1452       continue;
1453     Local<Object> obj = context->GetDataFromSnapshotOnce<Object>(
1454                                    info_->native_execution_async_resources[i])
1455                                .ToLocalChecked();
1456     js_execution_async_resources->Set(context, i, obj).Check();
1457   }
1458   info_ = nullptr;
1459 }
1460 
operator <<(std::ostream & output,const AsyncHooks::SerializeInfo & i)1461 std::ostream& operator<<(std::ostream& output,
1462                          const AsyncHooks::SerializeInfo& i) {
1463   output << "{\n"
1464          << "  " << i.async_ids_stack << ",  // async_ids_stack\n"
1465          << "  " << i.fields << ",  // fields\n"
1466          << "  " << i.async_id_fields << ",  // async_id_fields\n"
1467          << "  " << i.js_execution_async_resources
1468          << ",  // js_execution_async_resources\n"
1469          << "  " << i.native_execution_async_resources
1470          << ",  // native_execution_async_resources\n"
1471          << "}";
1472   return output;
1473 }
1474 
Serialize(Local<Context> context,SnapshotCreator * creator)1475 AsyncHooks::SerializeInfo AsyncHooks::Serialize(Local<Context> context,
1476                                                 SnapshotCreator* creator) {
1477   SerializeInfo info;
1478   // TODO(joyeecheung): some of these probably don't need to be serialized.
1479   info.async_ids_stack = async_ids_stack_.Serialize(context, creator);
1480   info.fields = fields_.Serialize(context, creator);
1481   info.async_id_fields = async_id_fields_.Serialize(context, creator);
1482   if (!js_execution_async_resources_.IsEmpty()) {
1483     info.js_execution_async_resources = creator->AddData(
1484         context, js_execution_async_resources_.Get(context->GetIsolate()));
1485     CHECK_NE(info.js_execution_async_resources, 0);
1486   } else {
1487     info.js_execution_async_resources = 0;
1488   }
1489 
1490   info.native_execution_async_resources.resize(
1491       native_execution_async_resources_.size());
1492   for (size_t i = 0; i < native_execution_async_resources_.size(); i++) {
1493     info.native_execution_async_resources[i] =
1494         native_execution_async_resources_[i].IsEmpty() ? SIZE_MAX :
1495             creator->AddData(
1496                 context,
1497                 native_execution_async_resources_[i]);
1498   }
1499 
1500   // At the moment, promise hooks are not supported in the startup snapshot.
1501   // TODO(joyeecheung): support promise hooks in the startup snapshot.
1502   CHECK(js_promise_hooks_[0].IsEmpty());
1503   CHECK(js_promise_hooks_[1].IsEmpty());
1504   CHECK(js_promise_hooks_[2].IsEmpty());
1505   CHECK(js_promise_hooks_[3].IsEmpty());
1506 
1507   return info;
1508 }
1509 
MemoryInfo(MemoryTracker * tracker) const1510 void AsyncHooks::MemoryInfo(MemoryTracker* tracker) const {
1511   tracker->TrackField("async_ids_stack", async_ids_stack_);
1512   tracker->TrackField("fields", fields_);
1513   tracker->TrackField("async_id_fields", async_id_fields_);
1514   tracker->TrackField("js_promise_hooks", js_promise_hooks_);
1515 }
1516 
grow_async_ids_stack()1517 void AsyncHooks::grow_async_ids_stack() {
1518   async_ids_stack_.reserve(async_ids_stack_.Length() * 3);
1519 
1520   env()->async_hooks_binding()->Set(
1521       env()->context(),
1522       env()->async_ids_stack_string(),
1523       async_ids_stack_.GetJSArray()).Check();
1524 }
1525 
FailWithCorruptedAsyncStack(double expected_async_id)1526 void AsyncHooks::FailWithCorruptedAsyncStack(double expected_async_id) {
1527   fprintf(stderr,
1528           "Error: async hook stack has become corrupted ("
1529           "actual: %.f, expected: %.f)\n",
1530           async_id_fields_.GetValue(kExecutionAsyncId),
1531           expected_async_id);
1532   DumpBacktrace(stderr);
1533   fflush(stderr);
1534   if (!env()->abort_on_uncaught_exception())
1535     exit(1);
1536   fprintf(stderr, "\n");
1537   fflush(stderr);
1538   ABORT_NO_BACKTRACE();
1539 }
1540 
Exit(int exit_code)1541 void Environment::Exit(int exit_code) {
1542   if (options()->trace_exit) {
1543     HandleScope handle_scope(isolate());
1544     Isolate::DisallowJavascriptExecutionScope disallow_js(
1545         isolate(), Isolate::DisallowJavascriptExecutionScope::CRASH_ON_FAILURE);
1546 
1547     if (is_main_thread()) {
1548       fprintf(stderr, "(node:%d) ", uv_os_getpid());
1549     } else {
1550       fprintf(stderr, "(node:%d, thread:%" PRIu64 ") ",
1551               uv_os_getpid(), thread_id());
1552     }
1553 
1554     fprintf(
1555         stderr, "WARNING: Exited the environment with code %d\n", exit_code);
1556     PrintStackTrace(isolate(),
1557                     StackTrace::CurrentStackTrace(
1558                         isolate(), stack_trace_limit(), StackTrace::kDetailed));
1559   }
1560   process_exit_handler_(this, exit_code);
1561 }
1562 
stop_sub_worker_contexts()1563 void Environment::stop_sub_worker_contexts() {
1564   DCHECK_EQ(Isolate::GetCurrent(), isolate());
1565 
1566   while (!sub_worker_contexts_.empty()) {
1567     Worker* w = *sub_worker_contexts_.begin();
1568     remove_sub_worker_context(w);
1569     w->Exit(1);
1570     w->JoinThread();
1571   }
1572 }
1573 
worker_parent_env() const1574 Environment* Environment::worker_parent_env() const {
1575   if (worker_context() == nullptr) return nullptr;
1576   return worker_context()->env();
1577 }
1578 
AddUnmanagedFd(int fd)1579 void Environment::AddUnmanagedFd(int fd) {
1580   if (!tracks_unmanaged_fds()) return;
1581   auto result = unmanaged_fds_.insert(fd);
1582   if (!result.second) {
1583     ProcessEmitWarning(
1584         this, "File descriptor %d opened in unmanaged mode twice", fd);
1585   }
1586 }
1587 
RemoveUnmanagedFd(int fd)1588 void Environment::RemoveUnmanagedFd(int fd) {
1589   if (!tracks_unmanaged_fds()) return;
1590   size_t removed_count = unmanaged_fds_.erase(fd);
1591   if (removed_count == 0) {
1592     ProcessEmitWarning(
1593         this, "File descriptor %d closed but not opened in unmanaged mode", fd);
1594   }
1595 }
1596 
PrintInfoForSnapshotIfDebug()1597 void Environment::PrintInfoForSnapshotIfDebug() {
1598   if (enabled_debug_list()->enabled(DebugCategory::MKSNAPSHOT)) {
1599     fprintf(stderr, "At the exit of the Environment:\n");
1600     principal_realm()->PrintInfoForSnapshot();
1601   }
1602 }
1603 
Serialize(SnapshotCreator * creator)1604 EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) {
1605   EnvSerializeInfo info;
1606   Local<Context> ctx = context();
1607 
1608   info.async_hooks = async_hooks_.Serialize(ctx, creator);
1609   info.immediate_info = immediate_info_.Serialize(ctx, creator);
1610   info.timeout_info = timeout_info_.Serialize(ctx, creator);
1611   info.tick_info = tick_info_.Serialize(ctx, creator);
1612   info.performance_state = performance_state_->Serialize(ctx, creator);
1613   info.exiting = exiting_.Serialize(ctx, creator);
1614   info.stream_base_state = stream_base_state_.Serialize(ctx, creator);
1615   info.should_abort_on_uncaught_toggle =
1616       should_abort_on_uncaught_toggle_.Serialize(ctx, creator);
1617 
1618   info.principal_realm = principal_realm_->Serialize(creator);
1619   // For now we only support serialization of the main context.
1620   // TODO(joyeecheung): support de/serialization of vm contexts.
1621   CHECK_EQ(contexts_.size(), 1);
1622   CHECK_EQ(contexts_[0], context());
1623   return info;
1624 }
1625 
EnqueueDeserializeRequest(DeserializeRequestCallback cb,Local<Object> holder,int index,InternalFieldInfoBase * info)1626 void Environment::EnqueueDeserializeRequest(DeserializeRequestCallback cb,
1627                                             Local<Object> holder,
1628                                             int index,
1629                                             InternalFieldInfoBase* info) {
1630   DCHECK_EQ(index, BaseObject::kEmbedderType);
1631   DeserializeRequest request{cb, {isolate(), holder}, index, info};
1632   deserialize_requests_.push_back(std::move(request));
1633 }
1634 
RunDeserializeRequests()1635 void Environment::RunDeserializeRequests() {
1636   HandleScope scope(isolate());
1637   Local<Context> ctx = context();
1638   Isolate* is = isolate();
1639   while (!deserialize_requests_.empty()) {
1640     DeserializeRequest request(std::move(deserialize_requests_.front()));
1641     deserialize_requests_.pop_front();
1642     Local<Object> holder = request.holder.Get(is);
1643     request.cb(ctx, holder, request.index, request.info);
1644     request.holder.Reset();
1645     request.info->Delete();
1646   }
1647 }
1648 
DeserializeProperties(const EnvSerializeInfo * info)1649 void Environment::DeserializeProperties(const EnvSerializeInfo* info) {
1650   Local<Context> ctx = context();
1651 
1652   if (enabled_debug_list_.enabled(DebugCategory::MKSNAPSHOT)) {
1653     fprintf(stderr, "deserializing EnvSerializeInfo...\n");
1654     std::cerr << *info << "\n";
1655   }
1656 
1657   RunDeserializeRequests();
1658 
1659   async_hooks_.Deserialize(ctx);
1660   immediate_info_.Deserialize(ctx);
1661   timeout_info_.Deserialize(ctx);
1662   tick_info_.Deserialize(ctx);
1663   performance_state_->Deserialize(ctx);
1664   exiting_.Deserialize(ctx);
1665   stream_base_state_.Deserialize(ctx);
1666   should_abort_on_uncaught_toggle_.Deserialize(ctx);
1667 
1668   principal_realm_->DeserializeProperties(&info->principal_realm);
1669 }
1670 
GuessMemoryAvailableToTheProcess()1671 uint64_t GuessMemoryAvailableToTheProcess() {
1672   uint64_t free_in_system = uv_get_free_memory();
1673   size_t allowed = uv_get_constrained_memory();
1674   if (allowed == 0) {
1675     return free_in_system;
1676   }
1677   size_t rss;
1678   int err = uv_resident_set_memory(&rss);
1679   if (err) {
1680     return free_in_system;
1681   }
1682   if (allowed < rss) {
1683     // Something is probably wrong. Fallback to the free memory.
1684     return free_in_system;
1685   }
1686   // There may still be room for swap, but we will just leave it here.
1687   return allowed - rss;
1688 }
1689 
BuildEmbedderGraph(Isolate * isolate,EmbedderGraph * graph,void * data)1690 void Environment::BuildEmbedderGraph(Isolate* isolate,
1691                                      EmbedderGraph* graph,
1692                                      void* data) {
1693   MemoryTracker tracker(isolate, graph);
1694   Environment* env = static_cast<Environment*>(data);
1695   // Start traversing embedder objects from the root Environment object.
1696   tracker.Track(env);
1697 }
1698 
NearHeapLimitCallback(void * data,size_t current_heap_limit,size_t initial_heap_limit)1699 size_t Environment::NearHeapLimitCallback(void* data,
1700                                           size_t current_heap_limit,
1701                                           size_t initial_heap_limit) {
1702   Environment* env = static_cast<Environment*>(data);
1703 
1704   Debug(env,
1705         DebugCategory::DIAGNOSTICS,
1706         "Invoked NearHeapLimitCallback, processing=%d, "
1707         "current_limit=%" PRIu64 ", "
1708         "initial_limit=%" PRIu64 "\n",
1709         env->is_in_heapsnapshot_heap_limit_callback_,
1710         static_cast<uint64_t>(current_heap_limit),
1711         static_cast<uint64_t>(initial_heap_limit));
1712 
1713   size_t max_young_gen_size = env->isolate_data()->max_young_gen_size;
1714   size_t young_gen_size = 0;
1715   size_t old_gen_size = 0;
1716 
1717   HeapSpaceStatistics stats;
1718   size_t num_heap_spaces = env->isolate()->NumberOfHeapSpaces();
1719   for (size_t i = 0; i < num_heap_spaces; ++i) {
1720     env->isolate()->GetHeapSpaceStatistics(&stats, i);
1721     if (strcmp(stats.space_name(), "new_space") == 0 ||
1722         strcmp(stats.space_name(), "new_large_object_space") == 0) {
1723       young_gen_size += stats.space_used_size();
1724     } else {
1725       old_gen_size += stats.space_used_size();
1726     }
1727   }
1728 
1729   Debug(env,
1730         DebugCategory::DIAGNOSTICS,
1731         "max_young_gen_size=%" PRIu64 ", "
1732         "young_gen_size=%" PRIu64 ", "
1733         "old_gen_size=%" PRIu64 ", "
1734         "total_size=%" PRIu64 "\n",
1735         static_cast<uint64_t>(max_young_gen_size),
1736         static_cast<uint64_t>(young_gen_size),
1737         static_cast<uint64_t>(old_gen_size),
1738         static_cast<uint64_t>(young_gen_size + old_gen_size));
1739 
1740   uint64_t available = GuessMemoryAvailableToTheProcess();
1741   // TODO(joyeecheung): get a better estimate about the native memory
1742   // usage into the overhead, e.g. based on the count of objects.
1743   uint64_t estimated_overhead = max_young_gen_size;
1744   Debug(env,
1745         DebugCategory::DIAGNOSTICS,
1746         "Estimated available memory=%" PRIu64 ", "
1747         "estimated overhead=%" PRIu64 "\n",
1748         static_cast<uint64_t>(available),
1749         static_cast<uint64_t>(estimated_overhead));
1750 
1751   // This might be hit when the snapshot is being taken in another
1752   // NearHeapLimitCallback invocation.
1753   // When taking the snapshot, objects in the young generation may be
1754   // promoted to the old generation, result in increased heap usage,
1755   // but it should be no more than the young generation size.
1756   // Ideally, this should be as small as possible - the heap limit
1757   // can only be restored when the heap usage falls down below the
1758   // new limit, so in a heap with unbounded growth the isolate
1759   // may eventually crash with this new limit - effectively raising
1760   // the heap limit to the new one.
1761   size_t new_limit = current_heap_limit + max_young_gen_size;
1762   if (env->is_in_heapsnapshot_heap_limit_callback_) {
1763     Debug(env,
1764           DebugCategory::DIAGNOSTICS,
1765           "Not generating snapshots in nested callback. "
1766           "new_limit=%" PRIu64 "\n",
1767           static_cast<uint64_t>(new_limit));
1768     return new_limit;
1769   }
1770 
1771   // Estimate whether the snapshot is going to use up all the memory
1772   // available to the process. If so, just give up to prevent the system
1773   // from killing the process for a system OOM.
1774   if (estimated_overhead > available) {
1775     Debug(env,
1776           DebugCategory::DIAGNOSTICS,
1777           "Not generating snapshots because it's too risky.\n");
1778     env->RemoveHeapSnapshotNearHeapLimitCallback(0);
1779     // The new limit must be higher than current_heap_limit or V8 might
1780     // crash.
1781     return new_limit;
1782   }
1783 
1784   // Take the snapshot synchronously.
1785   env->is_in_heapsnapshot_heap_limit_callback_ = true;
1786 
1787   std::string dir = env->options()->diagnostic_dir;
1788   if (dir.empty()) {
1789     dir = env->GetCwd();
1790   }
1791   DiagnosticFilename name(env, "Heap", "heapsnapshot");
1792   std::string filename = dir + kPathSeparator + (*name);
1793 
1794   Debug(env, DebugCategory::DIAGNOSTICS, "Start generating %s...\n", *name);
1795 
1796   heap::WriteSnapshot(env, filename.c_str());
1797   env->heap_limit_snapshot_taken_ += 1;
1798 
1799   Debug(env,
1800         DebugCategory::DIAGNOSTICS,
1801         "%" PRIu32 "/%" PRIu32 " snapshots taken.\n",
1802         env->heap_limit_snapshot_taken_,
1803         env->heap_snapshot_near_heap_limit_);
1804 
1805   // Don't take more snapshots than the limit specified.
1806   if (env->heap_limit_snapshot_taken_ == env->heap_snapshot_near_heap_limit_) {
1807     Debug(env,
1808           DebugCategory::DIAGNOSTICS,
1809           "Removing the near heap limit callback");
1810     env->RemoveHeapSnapshotNearHeapLimitCallback(0);
1811   }
1812 
1813   FPrintF(stderr, "Wrote snapshot to %s\n", filename.c_str());
1814   // Tell V8 to reset the heap limit once the heap usage falls down to
1815   // 95% of the initial limit.
1816   env->isolate()->AutomaticallyRestoreInitialHeapLimit(0.95);
1817 
1818   env->is_in_heapsnapshot_heap_limit_callback_ = false;
1819 
1820   // The new limit must be higher than current_heap_limit or V8 might
1821   // crash.
1822   return new_limit;
1823 }
1824 
SelfSize() const1825 inline size_t Environment::SelfSize() const {
1826   size_t size = sizeof(*this);
1827   // Remove non pointer fields that will be tracked in MemoryInfo()
1828   // TODO(joyeecheung): refactor the MemoryTracker interface so
1829   // this can be done for common types within the Track* calls automatically
1830   // if a certain scope is entered.
1831   size -= sizeof(async_hooks_);
1832   size -= sizeof(cleanup_queue_);
1833   size -= sizeof(tick_info_);
1834   size -= sizeof(immediate_info_);
1835   return size;
1836 }
1837 
MemoryInfo(MemoryTracker * tracker) const1838 void Environment::MemoryInfo(MemoryTracker* tracker) const {
1839   // Iteratable STLs have their own sizes subtracted from the parent
1840   // by default.
1841   tracker->TrackField("isolate_data", isolate_data_);
1842   tracker->TrackField("destroy_async_id_list", destroy_async_id_list_);
1843   tracker->TrackField("exec_argv", exec_argv_);
1844   tracker->TrackField("exiting", exiting_);
1845   tracker->TrackField("should_abort_on_uncaught_toggle",
1846                       should_abort_on_uncaught_toggle_);
1847   tracker->TrackField("stream_base_state", stream_base_state_);
1848   tracker->TrackField("cleanup_queue", cleanup_queue_);
1849   tracker->TrackField("async_hooks", async_hooks_);
1850   tracker->TrackField("immediate_info", immediate_info_);
1851   tracker->TrackField("timeout_info", timeout_info_);
1852   tracker->TrackField("tick_info", tick_info_);
1853   tracker->TrackField("principal_realm", principal_realm_);
1854 
1855   // FIXME(joyeecheung): track other fields in Environment.
1856   // Currently MemoryTracker is unable to track these
1857   // correctly:
1858   // - Internal types that do not implement MemoryRetainer yet
1859   // - STL containers with MemoryRetainer* inside
1860   // - STL containers with numeric types inside that should not have their
1861   //   nodes elided e.g. numeric keys in maps.
1862   // We also need to make sure that when we add a non-pointer field as its own
1863   // node, we shift its sizeof() size out of the Environment node.
1864 }
1865 
RunWeakRefCleanup()1866 void Environment::RunWeakRefCleanup() {
1867   isolate()->ClearKeptObjects();
1868 }
1869 }  // namespace node
1870