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