1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #ifndef SRC_ENV_INL_H_
23 #define SRC_ENV_INL_H_
24 
25 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
26 
27 #include "aliased_buffer.h"
28 #include "env.h"
29 #include "node.h"
30 #include "util-inl.h"
31 #include "uv.h"
32 #include "v8.h"
33 #include "node_perf_common.h"
34 #include "node_context_data.h"
35 #include "node_worker.h"
36 
37 #include <stddef.h>
38 #include <stdint.h>
39 
40 namespace node {
41 
isolate()42 inline v8::Isolate* IsolateData::isolate() const {
43   return isolate_;
44 }
45 
event_loop()46 inline uv_loop_t* IsolateData::event_loop() const {
47   return event_loop_;
48 }
49 
zero_fill_field()50 inline uint32_t* IsolateData::zero_fill_field() const {
51   return zero_fill_field_;
52 }
53 
platform()54 inline MultiIsolatePlatform* IsolateData::platform() const {
55   return platform_;
56 }
57 
AsyncHooks()58 inline Environment::AsyncHooks::AsyncHooks()
59     : async_ids_stack_(env()->isolate(), 16 * 2),
60       fields_(env()->isolate(), kFieldsCount),
61       async_id_fields_(env()->isolate(), kUidFieldsCount) {
62   v8::HandleScope handle_scope(env()->isolate());
63 
64   // Always perform async_hooks checks, not just when async_hooks is enabled.
65   // TODO(AndreasMadsen): Consider removing this for LTS releases.
66   // See discussion in https://github.com/nodejs/node/pull/15454
67   // When removing this, do it by reverting the commit. Otherwise the test
68   // and flag changes won't be included.
69   fields_[kCheck] = 1;
70 
71   // kDefaultTriggerAsyncId should be -1, this indicates that there is no
72   // specified default value and it should fallback to the executionAsyncId.
73   // 0 is not used as the magic value, because that indicates a missing context
74   // which is different from a default context.
75   async_id_fields_[AsyncHooks::kDefaultTriggerAsyncId] = -1;
76 
77   // kAsyncIdCounter should start at 1 because that'll be the id the execution
78   // context during bootstrap (code that runs before entering uv_run()).
79   async_id_fields_[AsyncHooks::kAsyncIdCounter] = 1;
80 
81   // Create all the provider strings that will be passed to JS. Place them in
82   // an array so the array index matches the PROVIDER id offset. This way the
83   // strings can be retrieved quickly.
84 #define V(Provider)                                                           \
85   providers_[AsyncWrap::PROVIDER_ ## Provider].Set(                           \
86       env()->isolate(),                                                       \
87       v8::String::NewFromOneByte(                                             \
88         env()->isolate(),                                                     \
89         reinterpret_cast<const uint8_t*>(#Provider),                          \
90         v8::NewStringType::kInternalized,                                     \
91         sizeof(#Provider) - 1).ToLocalChecked());
92   NODE_ASYNC_PROVIDER_TYPES(V)
93 #undef V
94 }
95 
96 inline AliasedBuffer<uint32_t, v8::Uint32Array>&
fields()97 Environment::AsyncHooks::fields() {
98   return fields_;
99 }
100 
101 inline AliasedBuffer<double, v8::Float64Array>&
async_id_fields()102 Environment::AsyncHooks::async_id_fields() {
103   return async_id_fields_;
104 }
105 
106 inline AliasedBuffer<double, v8::Float64Array>&
async_ids_stack()107 Environment::AsyncHooks::async_ids_stack() {
108   return async_ids_stack_;
109 }
110 
provider_string(int idx)111 inline v8::Local<v8::String> Environment::AsyncHooks::provider_string(int idx) {
112   return providers_[idx].Get(env()->isolate());
113 }
114 
no_force_checks()115 inline void Environment::AsyncHooks::no_force_checks() {
116   fields_[kCheck] -= 1;
117 }
118 
env()119 inline Environment* Environment::AsyncHooks::env() {
120   return Environment::ForAsyncHooks(this);
121 }
122 
123 // Remember to keep this code aligned with pushAsyncIds() in JS.
push_async_ids(double async_id,double trigger_async_id)124 inline void Environment::AsyncHooks::push_async_ids(double async_id,
125                                                     double trigger_async_id) {
126   // Since async_hooks is experimental, do only perform the check
127   // when async_hooks is enabled.
128   if (fields_[kCheck] > 0) {
129     CHECK_GE(async_id, -1);
130     CHECK_GE(trigger_async_id, -1);
131   }
132 
133   uint32_t offset = fields_[kStackLength];
134   if (offset * 2 >= async_ids_stack_.Length())
135     grow_async_ids_stack();
136   async_ids_stack_[2 * offset] = async_id_fields_[kExecutionAsyncId];
137   async_ids_stack_[2 * offset + 1] = async_id_fields_[kTriggerAsyncId];
138   fields_[kStackLength] += 1;
139   async_id_fields_[kExecutionAsyncId] = async_id;
140   async_id_fields_[kTriggerAsyncId] = trigger_async_id;
141 }
142 
143 // Remember to keep this code aligned with popAsyncIds() in JS.
pop_async_id(double async_id)144 inline bool Environment::AsyncHooks::pop_async_id(double async_id) {
145   // In case of an exception then this may have already been reset, if the
146   // stack was multiple MakeCallback()'s deep.
147   if (fields_[kStackLength] == 0) return false;
148 
149   // Ask for the async_id to be restored as a check that the stack
150   // hasn't been corrupted.
151   // Since async_hooks is experimental, do only perform the check
152   // when async_hooks is enabled.
153   if (fields_[kCheck] > 0 && async_id_fields_[kExecutionAsyncId] != async_id) {
154     fprintf(stderr,
155             "Error: async hook stack has become corrupted ("
156             "actual: %.f, expected: %.f)\n",
157             async_id_fields_.GetValue(kExecutionAsyncId),
158             async_id);
159     DumpBacktrace(stderr);
160     fflush(stderr);
161     if (!env()->abort_on_uncaught_exception())
162       exit(1);
163     fprintf(stderr, "\n");
164     fflush(stderr);
165     ABORT_NO_BACKTRACE();
166   }
167 
168   uint32_t offset = fields_[kStackLength] - 1;
169   async_id_fields_[kExecutionAsyncId] = async_ids_stack_[2 * offset];
170   async_id_fields_[kTriggerAsyncId] = async_ids_stack_[2 * offset + 1];
171   fields_[kStackLength] = offset;
172 
173   return fields_[kStackLength] > 0;
174 }
175 
176 // Keep in sync with clearAsyncIdStack in lib/internal/async_hooks.js.
clear_async_id_stack()177 inline void Environment::AsyncHooks::clear_async_id_stack() {
178   async_id_fields_[kExecutionAsyncId] = 0;
179   async_id_fields_[kTriggerAsyncId] = 0;
180   fields_[kStackLength] = 0;
181 }
182 
183 // The DefaultTriggerAsyncIdScope(AsyncWrap*) constructor is defined in
184 // async_wrap-inl.h to avoid a circular dependency.
185 
186 inline Environment::AsyncHooks::DefaultTriggerAsyncIdScope
DefaultTriggerAsyncIdScope(Environment * env,double default_trigger_async_id)187   ::DefaultTriggerAsyncIdScope(Environment* env,
188                                double default_trigger_async_id)
189     : async_hooks_(env->async_hooks()) {
190   if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
191     CHECK_GE(default_trigger_async_id, 0);
192   }
193 
194   old_default_trigger_async_id_ =
195     async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
196   async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
197     default_trigger_async_id;
198 }
199 
200 inline Environment::AsyncHooks::DefaultTriggerAsyncIdScope
~DefaultTriggerAsyncIdScope()201   ::~DefaultTriggerAsyncIdScope() {
202   async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
203     old_default_trigger_async_id_;
204 }
205 
206 
ForAsyncHooks(AsyncHooks * hooks)207 Environment* Environment::ForAsyncHooks(AsyncHooks* hooks) {
208   return ContainerOf(&Environment::async_hooks_, hooks);
209 }
210 
211 
AsyncCallbackScope(Environment * env)212 inline Environment::AsyncCallbackScope::AsyncCallbackScope(Environment* env)
213     : env_(env) {
214   env_->makecallback_cntr_++;
215 }
216 
~AsyncCallbackScope()217 inline Environment::AsyncCallbackScope::~AsyncCallbackScope() {
218   env_->makecallback_cntr_--;
219 }
220 
makecallback_depth()221 inline size_t Environment::makecallback_depth() const {
222   return makecallback_cntr_;
223 }
224 
ImmediateInfo(v8::Isolate * isolate)225 inline Environment::ImmediateInfo::ImmediateInfo(v8::Isolate* isolate)
226     : fields_(isolate, kFieldsCount) {}
227 
228 inline AliasedBuffer<uint32_t, v8::Uint32Array>&
fields()229     Environment::ImmediateInfo::fields() {
230   return fields_;
231 }
232 
count()233 inline uint32_t Environment::ImmediateInfo::count() const {
234   return fields_[kCount];
235 }
236 
ref_count()237 inline uint32_t Environment::ImmediateInfo::ref_count() const {
238   return fields_[kRefCount];
239 }
240 
has_outstanding()241 inline bool Environment::ImmediateInfo::has_outstanding() const {
242   return fields_[kHasOutstanding] == 1;
243 }
244 
count_inc(uint32_t increment)245 inline void Environment::ImmediateInfo::count_inc(uint32_t increment) {
246   fields_[kCount] += increment;
247 }
248 
count_dec(uint32_t decrement)249 inline void Environment::ImmediateInfo::count_dec(uint32_t decrement) {
250   fields_[kCount] -= decrement;
251 }
252 
ref_count_inc(uint32_t increment)253 inline void Environment::ImmediateInfo::ref_count_inc(uint32_t increment) {
254   fields_[kRefCount] += increment;
255 }
256 
ref_count_dec(uint32_t decrement)257 inline void Environment::ImmediateInfo::ref_count_dec(uint32_t decrement) {
258   fields_[kRefCount] -= decrement;
259 }
260 
TickInfo(v8::Isolate * isolate)261 inline Environment::TickInfo::TickInfo(v8::Isolate* isolate)
262     : fields_(isolate, kFieldsCount) {}
263 
fields()264 inline AliasedBuffer<uint8_t, v8::Uint8Array>& Environment::TickInfo::fields() {
265   return fields_;
266 }
267 
has_scheduled()268 inline bool Environment::TickInfo::has_scheduled() const {
269   return fields_[kHasScheduled] == 1;
270 }
271 
has_thrown()272 inline bool Environment::TickInfo::has_thrown() const {
273   return fields_[kHasThrown] == 1;
274 }
275 
has_promise_rejections()276 inline bool Environment::TickInfo::has_promise_rejections() const {
277   return fields_[kHasPromiseRejections] == 1;
278 }
279 
promise_rejections_toggle_on()280 inline void Environment::TickInfo::promise_rejections_toggle_on() {
281   fields_[kHasPromiseRejections] = 1;
282 }
283 
set_has_thrown(bool state)284 inline void Environment::TickInfo::set_has_thrown(bool state) {
285   fields_[kHasThrown] = state ? 1 : 0;
286 }
287 
AssignToContext(v8::Local<v8::Context> context,const ContextInfo & info)288 inline void Environment::AssignToContext(v8::Local<v8::Context> context,
289                                          const ContextInfo& info) {
290   context->SetAlignedPointerInEmbedderData(
291       ContextEmbedderIndex::kEnvironment, this);
292   // Used by EnvPromiseHook to know that we are on a node context.
293   context->SetAlignedPointerInEmbedderData(
294     ContextEmbedderIndex::kContextTag, Environment::kNodeContextTagPtr);
295 #if HAVE_INSPECTOR
296   inspector_agent()->ContextCreated(context, info);
297 #endif  // HAVE_INSPECTOR
298 }
299 
GetCurrent(v8::Isolate * isolate)300 inline Environment* Environment::GetCurrent(v8::Isolate* isolate) {
301   return GetCurrent(isolate->GetCurrentContext());
302 }
303 
GetCurrent(v8::Local<v8::Context> context)304 inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) {
305   if (UNLIKELY(context.IsEmpty() ||
306       context->GetNumberOfEmbedderDataFields() <
307           ContextEmbedderIndex::kContextTag ||
308       context->GetAlignedPointerFromEmbedderData(
309           ContextEmbedderIndex::kContextTag) !=
310           Environment::kNodeContextTagPtr)) {
311     return nullptr;
312   }
313 
314   return static_cast<Environment*>(
315       context->GetAlignedPointerFromEmbedderData(
316           ContextEmbedderIndex::kEnvironment));
317 }
318 
GetCurrent(const v8::FunctionCallbackInfo<v8::Value> & info)319 inline Environment* Environment::GetCurrent(
320     const v8::FunctionCallbackInfo<v8::Value>& info) {
321   CHECK(info.Data()->IsExternal());
322   return static_cast<Environment*>(info.Data().As<v8::External>()->Value());
323 }
324 
325 template <typename T>
GetCurrent(const v8::PropertyCallbackInfo<T> & info)326 inline Environment* Environment::GetCurrent(
327     const v8::PropertyCallbackInfo<T>& info) {
328   CHECK(info.Data()->IsExternal());
329   return static_cast<Environment*>(
330       info.Data().template As<v8::External>()->Value());
331 }
332 
GetThreadLocalEnv()333 inline Environment* Environment::GetThreadLocalEnv() {
334   return static_cast<Environment*>(uv_key_get(&thread_local_env));
335 }
336 
profiler_idle_notifier_started()337 inline bool Environment::profiler_idle_notifier_started() const {
338   return profiler_idle_notifier_started_;
339 }
340 
isolate()341 inline v8::Isolate* Environment::isolate() const {
342   return isolate_;
343 }
344 
tracing_agent_writer()345 inline tracing::AgentWriterHandle* Environment::tracing_agent_writer() const {
346   return tracing_agent_writer_;
347 }
348 
from_immediate_check_handle(uv_check_t * handle)349 inline Environment* Environment::from_immediate_check_handle(
350     uv_check_t* handle) {
351   return ContainerOf(&Environment::immediate_check_handle_, handle);
352 }
353 
immediate_check_handle()354 inline uv_check_t* Environment::immediate_check_handle() {
355   return &immediate_check_handle_;
356 }
357 
immediate_idle_handle()358 inline uv_idle_t* Environment::immediate_idle_handle() {
359   return &immediate_idle_handle_;
360 }
361 
RegisterHandleCleanup(uv_handle_t * handle,HandleCleanupCb cb,void * arg)362 inline void Environment::RegisterHandleCleanup(uv_handle_t* handle,
363                                                HandleCleanupCb cb,
364                                                void* arg) {
365   handle_cleanup_queue_.push_back(HandleCleanup{handle, cb, arg});
366 }
367 
368 template <typename T, typename OnCloseCallback>
CloseHandle(T * handle,OnCloseCallback callback)369 inline void Environment::CloseHandle(T* handle, OnCloseCallback callback) {
370   handle_cleanup_waiting_++;
371   static_assert(sizeof(T) >= sizeof(uv_handle_t), "T is a libuv handle");
372   static_assert(offsetof(T, data) == offsetof(uv_handle_t, data),
373                 "T is a libuv handle");
374   static_assert(offsetof(T, close_cb) == offsetof(uv_handle_t, close_cb),
375                 "T is a libuv handle");
376   struct CloseData {
377     Environment* env;
378     OnCloseCallback callback;
379     void* original_data;
380   };
381   handle->data = new CloseData { this, callback, handle->data };
382   uv_close(reinterpret_cast<uv_handle_t*>(handle), [](uv_handle_t* handle) {
383     std::unique_ptr<CloseData> data { static_cast<CloseData*>(handle->data) };
384     data->env->handle_cleanup_waiting_--;
385     handle->data = data->original_data;
386     data->callback(reinterpret_cast<T*>(handle));
387   });
388 }
389 
IncreaseWaitingRequestCounter()390 void Environment::IncreaseWaitingRequestCounter() {
391   request_waiting_++;
392 }
393 
DecreaseWaitingRequestCounter()394 void Environment::DecreaseWaitingRequestCounter() {
395   request_waiting_--;
396   CHECK_GE(request_waiting_, 0);
397 }
398 
event_loop()399 inline uv_loop_t* Environment::event_loop() const {
400   return isolate_data()->event_loop();
401 }
402 
async_hooks()403 inline Environment::AsyncHooks* Environment::async_hooks() {
404   return &async_hooks_;
405 }
406 
immediate_info()407 inline Environment::ImmediateInfo* Environment::immediate_info() {
408   return &immediate_info_;
409 }
410 
tick_info()411 inline Environment::TickInfo* Environment::tick_info() {
412   return &tick_info_;
413 }
414 
timer_base()415 inline uint64_t Environment::timer_base() const {
416   return timer_base_;
417 }
418 
printed_error()419 inline bool Environment::printed_error() const {
420   return printed_error_;
421 }
422 
set_printed_error(bool value)423 inline void Environment::set_printed_error(bool value) {
424   printed_error_ = value;
425 }
426 
set_trace_sync_io(bool value)427 inline void Environment::set_trace_sync_io(bool value) {
428   options_->trace_sync_io = value;
429 }
430 
abort_on_uncaught_exception()431 inline bool Environment::abort_on_uncaught_exception() const {
432   return options_->abort_on_uncaught_exception;
433 }
434 
set_abort_on_uncaught_exception(bool value)435 inline void Environment::set_abort_on_uncaught_exception(bool value) {
436   options_->abort_on_uncaught_exception = value;
437 }
438 
439 inline AliasedBuffer<uint32_t, v8::Uint32Array>&
should_abort_on_uncaught_toggle()440 Environment::should_abort_on_uncaught_toggle() {
441   return should_abort_on_uncaught_toggle_;
442 }
443 
get_next_module_id()444 inline uint32_t Environment::get_next_module_id() {
445   return module_id_counter_++;
446 }
get_next_script_id()447 inline uint32_t Environment::get_next_script_id() {
448   return script_id_counter_++;
449 }
get_next_function_id()450 inline uint32_t Environment::get_next_function_id() {
451   return function_id_counter_++;
452 }
453 
ShouldNotAbortOnUncaughtScope(Environment * env)454 Environment::ShouldNotAbortOnUncaughtScope::ShouldNotAbortOnUncaughtScope(
455     Environment* env)
456     : env_(env) {
457   env_->should_not_abort_scope_counter_++;
458 }
459 
~ShouldNotAbortOnUncaughtScope()460 Environment::ShouldNotAbortOnUncaughtScope::~ShouldNotAbortOnUncaughtScope() {
461   Close();
462 }
463 
Close()464 void Environment::ShouldNotAbortOnUncaughtScope::Close() {
465   if (env_ != nullptr) {
466     env_->should_not_abort_scope_counter_--;
467     env_ = nullptr;
468   }
469 }
470 
inside_should_not_abort_on_uncaught_scope()471 bool Environment::inside_should_not_abort_on_uncaught_scope() const {
472   return should_not_abort_scope_counter_ > 0;
473 }
474 
destroy_async_id_list()475 inline std::vector<double>* Environment::destroy_async_id_list() {
476   return &destroy_async_id_list_;
477 }
478 
new_async_id()479 inline double Environment::new_async_id() {
480   async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter] += 1;
481   return async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter];
482 }
483 
execution_async_id()484 inline double Environment::execution_async_id() {
485   return async_hooks()->async_id_fields()[AsyncHooks::kExecutionAsyncId];
486 }
487 
trigger_async_id()488 inline double Environment::trigger_async_id() {
489   return async_hooks()->async_id_fields()[AsyncHooks::kTriggerAsyncId];
490 }
491 
get_default_trigger_async_id()492 inline double Environment::get_default_trigger_async_id() {
493   double default_trigger_async_id =
494     async_hooks()->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
495   // If defaultTriggerAsyncId isn't set, use the executionAsyncId
496   if (default_trigger_async_id < 0)
497     default_trigger_async_id = execution_async_id();
498   return default_trigger_async_id;
499 }
500 
heap_statistics_buffer()501 inline double* Environment::heap_statistics_buffer() const {
502   CHECK_NOT_NULL(heap_statistics_buffer_);
503   return heap_statistics_buffer_;
504 }
505 
set_heap_statistics_buffer(double * pointer)506 inline void Environment::set_heap_statistics_buffer(double* pointer) {
507   CHECK_NULL(heap_statistics_buffer_);  // Should be set only once.
508   heap_statistics_buffer_ = pointer;
509 }
510 
heap_space_statistics_buffer()511 inline double* Environment::heap_space_statistics_buffer() const {
512   CHECK_NOT_NULL(heap_space_statistics_buffer_);
513   return heap_space_statistics_buffer_;
514 }
515 
set_heap_space_statistics_buffer(double * pointer)516 inline void Environment::set_heap_space_statistics_buffer(double* pointer) {
517   CHECK_NULL(heap_space_statistics_buffer_);  // Should be set only once.
518   heap_space_statistics_buffer_ = pointer;
519 }
520 
http_parser_buffer()521 inline char* Environment::http_parser_buffer() const {
522   return http_parser_buffer_;
523 }
524 
set_http_parser_buffer(char * buffer)525 inline void Environment::set_http_parser_buffer(char* buffer) {
526   CHECK_NULL(http_parser_buffer_);  // Should be set only once.
527   http_parser_buffer_ = buffer;
528 }
529 
http_parser_buffer_in_use()530 inline bool Environment::http_parser_buffer_in_use() const {
531   return http_parser_buffer_in_use_;
532 }
533 
set_http_parser_buffer_in_use(bool in_use)534 inline void Environment::set_http_parser_buffer_in_use(bool in_use) {
535   http_parser_buffer_in_use_ = in_use;
536 }
537 
http2_state()538 inline http2::Http2State* Environment::http2_state() const {
539   return http2_state_.get();
540 }
541 
set_http2_state(std::unique_ptr<http2::Http2State> buffer)542 inline void Environment::set_http2_state(
543     std::unique_ptr<http2::Http2State> buffer) {
544   CHECK(!http2_state_);  // Should be set only once.
545   http2_state_ = std::move(buffer);
546 }
547 
debug_enabled(DebugCategory category)548 bool Environment::debug_enabled(DebugCategory category) const {
549 #ifdef DEBUG
550   CHECK_GE(static_cast<int>(category), 0);
551   CHECK_LT(static_cast<int>(category),
552            static_cast<int>(DebugCategory::CATEGORY_COUNT));
553 #endif
554   return debug_enabled_[static_cast<int>(category)];
555 }
556 
set_debug_enabled(DebugCategory category,bool enabled)557 void Environment::set_debug_enabled(DebugCategory category, bool enabled) {
558 #ifdef DEBUG
559   CHECK_GE(static_cast<int>(category), 0);
560   CHECK_LT(static_cast<int>(category),
561            static_cast<int>(DebugCategory::CATEGORY_COUNT));
562 #endif
563   debug_enabled_[static_cast<int>(category)] = enabled;
564 }
565 
566 inline AliasedBuffer<double, v8::Float64Array>*
fs_stats_field_array()567 Environment::fs_stats_field_array() {
568   return &fs_stats_field_array_;
569 }
570 
571 inline AliasedBuffer<uint64_t, v8::BigUint64Array>*
fs_stats_field_bigint_array()572 Environment::fs_stats_field_bigint_array() {
573   return &fs_stats_field_bigint_array_;
574 }
575 
576 inline std::vector<std::unique_ptr<fs::FileHandleReadWrap>>&
file_handle_read_wrap_freelist()577 Environment::file_handle_read_wrap_freelist() {
578   return file_handle_read_wrap_freelist_;
579 }
580 
options()581 inline std::shared_ptr<EnvironmentOptions> Environment::options() {
582   return options_;
583 }
584 
options()585 inline std::shared_ptr<PerIsolateOptions> IsolateData::options() {
586   return options_;
587 }
588 
CreateImmediate(native_immediate_callback cb,void * data,v8::Local<v8::Object> obj,bool ref)589 void Environment::CreateImmediate(native_immediate_callback cb,
590                                   void* data,
591                                   v8::Local<v8::Object> obj,
592                                   bool ref) {
593   native_immediate_callbacks_.push_back({
594     cb,
595     data,
596     v8::Global<v8::Object>(isolate_, obj),
597     ref
598   });
599   immediate_info()->count_inc(1);
600 }
601 
SetImmediate(native_immediate_callback cb,void * data,v8::Local<v8::Object> obj)602 void Environment::SetImmediate(native_immediate_callback cb,
603                                void* data,
604                                v8::Local<v8::Object> obj) {
605   CreateImmediate(cb, data, obj, true);
606 
607   if (immediate_info()->ref_count() == 0)
608     ToggleImmediateRef(true);
609   immediate_info()->ref_count_inc(1);
610 }
611 
SetUnrefImmediate(native_immediate_callback cb,void * data,v8::Local<v8::Object> obj)612 void Environment::SetUnrefImmediate(native_immediate_callback cb,
613                                     void* data,
614                                     v8::Local<v8::Object> obj) {
615   CreateImmediate(cb, data, obj, false);
616 }
617 
can_call_into_js()618 inline bool Environment::can_call_into_js() const {
619   return can_call_into_js_ && (is_main_thread() || !is_stopping_worker());
620 }
621 
set_can_call_into_js(bool can_call_into_js)622 inline void Environment::set_can_call_into_js(bool can_call_into_js) {
623   can_call_into_js_ = can_call_into_js;
624 }
625 
is_main_thread()626 inline bool Environment::is_main_thread() const {
627   return thread_id_ == 0;
628 }
629 
thread_id()630 inline uint64_t Environment::thread_id() const {
631   return thread_id_;
632 }
633 
set_thread_id(uint64_t id)634 inline void Environment::set_thread_id(uint64_t id) {
635   thread_id_ = id;
636 }
637 
worker_context()638 inline worker::Worker* Environment::worker_context() const {
639   return worker_context_;
640 }
641 
set_worker_context(worker::Worker * context)642 inline void Environment::set_worker_context(worker::Worker* context) {
643   CHECK_EQ(worker_context_, nullptr);  // Should be set only once.
644   worker_context_ = context;
645 }
646 
add_sub_worker_context(worker::Worker * context)647 inline void Environment::add_sub_worker_context(worker::Worker* context) {
648   sub_worker_contexts_.insert(context);
649 }
650 
remove_sub_worker_context(worker::Worker * context)651 inline void Environment::remove_sub_worker_context(worker::Worker* context) {
652   sub_worker_contexts_.erase(context);
653 }
654 
is_stopping_worker()655 inline bool Environment::is_stopping_worker() const {
656   CHECK(!is_main_thread());
657   return worker_context_->is_stopped();
658 }
659 
performance_state()660 inline performance::performance_state* Environment::performance_state() {
661   return performance_state_.get();
662 }
663 
664 inline std::unordered_map<std::string, uint64_t>*
performance_marks()665     Environment::performance_marks() {
666   return &performance_marks_;
667 }
668 
isolate_data()669 inline IsolateData* Environment::isolate_data() const {
670   return isolate_data_;
671 }
672 
ThrowError(const char * errmsg)673 inline void Environment::ThrowError(const char* errmsg) {
674   ThrowError(v8::Exception::Error, errmsg);
675 }
676 
ThrowTypeError(const char * errmsg)677 inline void Environment::ThrowTypeError(const char* errmsg) {
678   ThrowError(v8::Exception::TypeError, errmsg);
679 }
680 
ThrowRangeError(const char * errmsg)681 inline void Environment::ThrowRangeError(const char* errmsg) {
682   ThrowError(v8::Exception::RangeError, errmsg);
683 }
684 
ThrowError(v8::Local<v8::Value> (* fun)(v8::Local<v8::String>),const char * errmsg)685 inline void Environment::ThrowError(
686     v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
687     const char* errmsg) {
688   v8::HandleScope handle_scope(isolate());
689   isolate()->ThrowException(fun(OneByteString(isolate(), errmsg)));
690 }
691 
ThrowErrnoException(int errorno,const char * syscall,const char * message,const char * path)692 inline void Environment::ThrowErrnoException(int errorno,
693                                              const char* syscall,
694                                              const char* message,
695                                              const char* path) {
696   isolate()->ThrowException(
697       ErrnoException(isolate(), errorno, syscall, message, path));
698 }
699 
ThrowUVException(int errorno,const char * syscall,const char * message,const char * path,const char * dest)700 inline void Environment::ThrowUVException(int errorno,
701                                           const char* syscall,
702                                           const char* message,
703                                           const char* path,
704                                           const char* dest) {
705   isolate()->ThrowException(
706       UVException(isolate(), errorno, syscall, message, path, dest));
707 }
708 
709 inline v8::Local<v8::FunctionTemplate>
NewFunctionTemplate(v8::FunctionCallback callback,v8::Local<v8::Signature> signature,v8::ConstructorBehavior behavior,v8::SideEffectType side_effect_type)710     Environment::NewFunctionTemplate(v8::FunctionCallback callback,
711                                      v8::Local<v8::Signature> signature,
712                                      v8::ConstructorBehavior behavior,
713                                      v8::SideEffectType side_effect_type) {
714   v8::Local<v8::External> external = as_external();
715   return v8::FunctionTemplate::New(isolate(), callback, external,
716                                    signature, 0, behavior, side_effect_type);
717 }
718 
SetMethod(v8::Local<v8::Object> that,const char * name,v8::FunctionCallback callback)719 inline void Environment::SetMethod(v8::Local<v8::Object> that,
720                                    const char* name,
721                                    v8::FunctionCallback callback) {
722   v8::Local<v8::Context> context = isolate()->GetCurrentContext();
723   v8::Local<v8::Function> function =
724       NewFunctionTemplate(callback, v8::Local<v8::Signature>(),
725                           // TODO(TimothyGu): Investigate if SetMethod is ever
726                           // used for constructors.
727                           v8::ConstructorBehavior::kAllow,
728                           v8::SideEffectType::kHasSideEffect)
729           ->GetFunction(context)
730           .ToLocalChecked();
731   // kInternalized strings are created in the old space.
732   const v8::NewStringType type = v8::NewStringType::kInternalized;
733   v8::Local<v8::String> name_string =
734       v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
735   that->Set(name_string, function);
736   function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
737 }
738 
SetMethodNoSideEffect(v8::Local<v8::Object> that,const char * name,v8::FunctionCallback callback)739 inline void Environment::SetMethodNoSideEffect(v8::Local<v8::Object> that,
740                                                const char* name,
741                                                v8::FunctionCallback callback) {
742   v8::Local<v8::Context> context = isolate()->GetCurrentContext();
743   v8::Local<v8::Function> function =
744       NewFunctionTemplate(callback, v8::Local<v8::Signature>(),
745                           // TODO(TimothyGu): Investigate if SetMethod is ever
746                           // used for constructors.
747                           v8::ConstructorBehavior::kAllow,
748                           v8::SideEffectType::kHasNoSideEffect)
749           ->GetFunction(context)
750           .ToLocalChecked();
751   // kInternalized strings are created in the old space.
752   const v8::NewStringType type = v8::NewStringType::kInternalized;
753   v8::Local<v8::String> name_string =
754       v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
755   that->Set(name_string, function);
756   function->SetName(name_string);  // NODE_SET_METHOD() compatibility.
757 }
758 
SetProtoMethod(v8::Local<v8::FunctionTemplate> that,const char * name,v8::FunctionCallback callback)759 inline void Environment::SetProtoMethod(v8::Local<v8::FunctionTemplate> that,
760                                         const char* name,
761                                         v8::FunctionCallback callback) {
762   v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
763   v8::Local<v8::FunctionTemplate> t =
764       NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow,
765                           v8::SideEffectType::kHasSideEffect);
766   // kInternalized strings are created in the old space.
767   const v8::NewStringType type = v8::NewStringType::kInternalized;
768   v8::Local<v8::String> name_string =
769       v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
770   that->PrototypeTemplate()->Set(name_string, t);
771   t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
772 }
773 
SetProtoMethodNoSideEffect(v8::Local<v8::FunctionTemplate> that,const char * name,v8::FunctionCallback callback)774 inline void Environment::SetProtoMethodNoSideEffect(
775     v8::Local<v8::FunctionTemplate> that,
776     const char* name,
777     v8::FunctionCallback callback) {
778   v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
779   v8::Local<v8::FunctionTemplate> t =
780       NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow,
781                           v8::SideEffectType::kHasNoSideEffect);
782   // kInternalized strings are created in the old space.
783   const v8::NewStringType type = v8::NewStringType::kInternalized;
784   v8::Local<v8::String> name_string =
785       v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
786   that->PrototypeTemplate()->Set(name_string, t);
787   t->SetClassName(name_string);  // NODE_SET_PROTOTYPE_METHOD() compatibility.
788 }
789 
SetTemplateMethod(v8::Local<v8::FunctionTemplate> that,const char * name,v8::FunctionCallback callback)790 inline void Environment::SetTemplateMethod(v8::Local<v8::FunctionTemplate> that,
791                                            const char* name,
792                                            v8::FunctionCallback callback) {
793   v8::Local<v8::FunctionTemplate> t =
794       NewFunctionTemplate(callback, v8::Local<v8::Signature>(),
795                           v8::ConstructorBehavior::kAllow,
796                           v8::SideEffectType::kHasSideEffect);
797   // kInternalized strings are created in the old space.
798   const v8::NewStringType type = v8::NewStringType::kInternalized;
799   v8::Local<v8::String> name_string =
800       v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
801   that->Set(name_string, t);
802   t->SetClassName(name_string);  // NODE_SET_METHOD() compatibility.
803 }
804 
SetTemplateMethodNoSideEffect(v8::Local<v8::FunctionTemplate> that,const char * name,v8::FunctionCallback callback)805 inline void Environment::SetTemplateMethodNoSideEffect(
806     v8::Local<v8::FunctionTemplate> that,
807     const char* name,
808     v8::FunctionCallback callback) {
809   v8::Local<v8::FunctionTemplate> t =
810       NewFunctionTemplate(callback, v8::Local<v8::Signature>(),
811                           v8::ConstructorBehavior::kAllow,
812                           v8::SideEffectType::kHasNoSideEffect);
813   // kInternalized strings are created in the old space.
814   const v8::NewStringType type = v8::NewStringType::kInternalized;
815   v8::Local<v8::String> name_string =
816       v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
817   that->Set(name_string, t);
818   t->SetClassName(name_string);  // NODE_SET_METHOD() compatibility.
819 }
820 
AddCleanupHook(void (* fn)(void *),void * arg)821 void Environment::AddCleanupHook(void (*fn)(void*), void* arg) {
822   auto insertion_info = cleanup_hooks_.emplace(CleanupHookCallback {
823     fn, arg, cleanup_hook_counter_++
824   });
825   // Make sure there was no existing element with these values.
826   CHECK_EQ(insertion_info.second, true);
827 }
828 
RemoveCleanupHook(void (* fn)(void *),void * arg)829 void Environment::RemoveCleanupHook(void (*fn)(void*), void* arg) {
830   CleanupHookCallback search { fn, arg, 0 };
831   cleanup_hooks_.erase(search);
832 }
833 
operator()834 size_t Environment::CleanupHookCallback::Hash::operator()(
835     const CleanupHookCallback& cb) const {
836   return std::hash<void*>()(cb.arg_);
837 }
838 
operator()839 bool Environment::CleanupHookCallback::Equal::operator()(
840     const CleanupHookCallback& a, const CleanupHookCallback& b) const {
841   return a.fn_ == b.fn_ && a.arg_ == b.arg_;
842 }
843 
GetBaseObject()844 BaseObject* Environment::CleanupHookCallback::GetBaseObject() const {
845   if (fn_ == BaseObject::DeleteMe)
846     return static_cast<BaseObject*>(arg_);
847   else
848     return nullptr;
849 }
850 
851 template <typename T>
ForEachBaseObject(T && iterator)852 void Environment::ForEachBaseObject(T&& iterator) {
853   for (const auto& hook : cleanup_hooks_) {
854     BaseObject* obj = hook.GetBaseObject();
855     if (obj != nullptr)
856       iterator(obj);
857   }
858 }
859 
860 #define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
861 #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
862 #define VS(PropertyName, StringValue) V(v8::String, PropertyName)
863 #define V(TypeName, PropertyName)                                             \
864   inline                                                                      \
865   v8::Local<TypeName> IsolateData::PropertyName(v8::Isolate* isolate) const { \
866     /* Strings are immutable so casting away const-ness here is okay. */      \
867     return const_cast<IsolateData*>(this)->PropertyName ## _.Get(isolate);    \
868   }
869   PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
870   PER_ISOLATE_SYMBOL_PROPERTIES(VY)
871   PER_ISOLATE_STRING_PROPERTIES(VS)
872 #undef V
873 #undef VS
874 #undef VY
875 #undef VP
876 
877 #define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
878 #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
879 #define VS(PropertyName, StringValue) V(v8::String, PropertyName)
880 #define V(TypeName, PropertyName)                                             \
881   inline v8::Local<TypeName> Environment::PropertyName() const {              \
882     return isolate_data()->PropertyName(isolate());                           \
883   }
884   PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
885   PER_ISOLATE_SYMBOL_PROPERTIES(VY)
886   PER_ISOLATE_STRING_PROPERTIES(VS)
887 #undef V
888 #undef VS
889 #undef VY
890 #undef VP
891 
892 #define V(PropertyName, TypeName)                                             \
893   inline v8::Local<TypeName> Environment::PropertyName() const {              \
894     return StrongPersistentToLocal(PropertyName ## _);                        \
895   }                                                                           \
896   inline void Environment::set_ ## PropertyName(v8::Local<TypeName> value) {  \
897     PropertyName ## _.Reset(isolate(), value);                                \
898   }
899   ENVIRONMENT_STRONG_PERSISTENT_PROPERTIES(V)
900 #undef V
901 
902 }  // namespace node
903 
904 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
905 
906 #endif  // SRC_ENV_INL_H_
907