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