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 "callback_queue-inl.h"
29 #include "env.h"
30 #include "node.h"
31 #include "util-inl.h"
32 #include "uv.h"
33 #include "v8.h"
34 #include "node_perf_common.h"
35 #include "node_context_data.h"
36
37 #include <cstddef>
38 #include <cstdint>
39
40 #include <utility>
41
42 namespace node {
43
isolate()44 inline v8::Isolate* IsolateData::isolate() const {
45 return isolate_;
46 }
47
event_loop()48 inline uv_loop_t* IsolateData::event_loop() const {
49 return event_loop_;
50 }
51
node_allocator()52 inline NodeArrayBufferAllocator* IsolateData::node_allocator() const {
53 return node_allocator_;
54 }
55
platform()56 inline MultiIsolatePlatform* IsolateData::platform() const {
57 return platform_;
58 }
59
set_worker_context(worker::Worker * context)60 inline void IsolateData::set_worker_context(worker::Worker* context) {
61 CHECK_NULL(worker_context_); // Should be set only once.
62 worker_context_ = context;
63 }
64
worker_context()65 inline worker::Worker* IsolateData::worker_context() const {
66 return worker_context_;
67 }
68
async_wrap_provider(int index)69 inline v8::Local<v8::String> IsolateData::async_wrap_provider(int index) const {
70 return async_wrap_providers_[index].Get(isolate_);
71 }
72
AsyncHooks()73 inline AsyncHooks::AsyncHooks()
74 : async_ids_stack_(env()->isolate(), 16 * 2),
75 fields_(env()->isolate(), kFieldsCount),
76 async_id_fields_(env()->isolate(), kUidFieldsCount) {
77 clear_async_id_stack();
78
79 // Always perform async_hooks checks, not just when async_hooks is enabled.
80 // TODO(AndreasMadsen): Consider removing this for LTS releases.
81 // See discussion in https://github.com/nodejs/node/pull/15454
82 // When removing this, do it by reverting the commit. Otherwise the test
83 // and flag changes won't be included.
84 fields_[kCheck] = 1;
85
86 // kDefaultTriggerAsyncId should be -1, this indicates that there is no
87 // specified default value and it should fallback to the executionAsyncId.
88 // 0 is not used as the magic value, because that indicates a missing context
89 // which is different from a default context.
90 async_id_fields_[AsyncHooks::kDefaultTriggerAsyncId] = -1;
91
92 // kAsyncIdCounter should start at 1 because that'll be the id the execution
93 // context during bootstrap (code that runs before entering uv_run()).
94 async_id_fields_[AsyncHooks::kAsyncIdCounter] = 1;
95 }
fields()96 inline AliasedUint32Array& AsyncHooks::fields() {
97 return fields_;
98 }
99
async_id_fields()100 inline AliasedFloat64Array& AsyncHooks::async_id_fields() {
101 return async_id_fields_;
102 }
103
async_ids_stack()104 inline AliasedFloat64Array& AsyncHooks::async_ids_stack() {
105 return async_ids_stack_;
106 }
107
js_execution_async_resources()108 v8::Local<v8::Array> AsyncHooks::js_execution_async_resources() {
109 if (UNLIKELY(js_execution_async_resources_.IsEmpty())) {
110 js_execution_async_resources_.Reset(
111 env()->isolate(), v8::Array::New(env()->isolate()));
112 }
113 return PersistentToLocal::Strong(js_execution_async_resources_);
114 }
115
native_execution_async_resource(size_t i)116 v8::Local<v8::Object> AsyncHooks::native_execution_async_resource(size_t i) {
117 if (i >= native_execution_async_resources_.size()) return {};
118 return PersistentToLocal::Strong(native_execution_async_resources_[i]);
119 }
120
SetJSPromiseHooks(v8::Local<v8::Function> init,v8::Local<v8::Function> before,v8::Local<v8::Function> after,v8::Local<v8::Function> resolve)121 inline void AsyncHooks::SetJSPromiseHooks(v8::Local<v8::Function> init,
122 v8::Local<v8::Function> before,
123 v8::Local<v8::Function> after,
124 v8::Local<v8::Function> resolve) {
125 js_promise_hooks_[0].Reset(env()->isolate(), init);
126 js_promise_hooks_[1].Reset(env()->isolate(), before);
127 js_promise_hooks_[2].Reset(env()->isolate(), after);
128 js_promise_hooks_[3].Reset(env()->isolate(), resolve);
129 for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
130 if (it->IsEmpty()) {
131 it = contexts_.erase(it);
132 it--;
133 continue;
134 }
135 PersistentToLocal::Weak(env()->isolate(), *it)
136 ->SetPromiseHooks(init, before, after, resolve);
137 }
138 }
139
provider_string(int idx)140 inline v8::Local<v8::String> AsyncHooks::provider_string(int idx) {
141 return env()->isolate_data()->async_wrap_provider(idx);
142 }
143
no_force_checks()144 inline void AsyncHooks::no_force_checks() {
145 fields_[kCheck] -= 1;
146 }
147
env()148 inline Environment* AsyncHooks::env() {
149 return Environment::ForAsyncHooks(this);
150 }
151
152 // Remember to keep this code aligned with pushAsyncContext() in JS.
push_async_context(double async_id,double trigger_async_id,v8::Local<v8::Object> resource)153 inline void AsyncHooks::push_async_context(double async_id,
154 double trigger_async_id,
155 v8::Local<v8::Object> resource) {
156 // Since async_hooks is experimental, do only perform the check
157 // when async_hooks is enabled.
158 if (fields_[kCheck] > 0) {
159 CHECK_GE(async_id, -1);
160 CHECK_GE(trigger_async_id, -1);
161 }
162
163 uint32_t offset = fields_[kStackLength];
164 if (offset * 2 >= async_ids_stack_.Length())
165 grow_async_ids_stack();
166 async_ids_stack_[2 * offset] = async_id_fields_[kExecutionAsyncId];
167 async_ids_stack_[2 * offset + 1] = async_id_fields_[kTriggerAsyncId];
168 fields_[kStackLength] += 1;
169 async_id_fields_[kExecutionAsyncId] = async_id;
170 async_id_fields_[kTriggerAsyncId] = trigger_async_id;
171
172 #ifdef DEBUG
173 for (uint32_t i = offset; i < native_execution_async_resources_.size(); i++)
174 CHECK(native_execution_async_resources_[i].IsEmpty());
175 #endif
176
177 // When this call comes from JS (as a way of increasing the stack size),
178 // `resource` will be empty, because JS caches these values anyway, and
179 // we should avoid creating strong global references that might keep
180 // these JS resource objects alive longer than necessary.
181 if (!resource.IsEmpty()) {
182 native_execution_async_resources_.resize(offset + 1);
183 native_execution_async_resources_[offset].Reset(env()->isolate(), resource);
184 }
185 }
186
187 // Remember to keep this code aligned with popAsyncContext() in JS.
pop_async_context(double async_id)188 inline bool AsyncHooks::pop_async_context(double async_id) {
189 // In case of an exception then this may have already been reset, if the
190 // stack was multiple MakeCallback()'s deep.
191 if (fields_[kStackLength] == 0) return false;
192
193 // Ask for the async_id to be restored as a check that the stack
194 // hasn't been corrupted.
195 // Since async_hooks is experimental, do only perform the check
196 // when async_hooks is enabled.
197 if (fields_[kCheck] > 0 && async_id_fields_[kExecutionAsyncId] != async_id) {
198 fprintf(stderr,
199 "Error: async hook stack has become corrupted ("
200 "actual: %.f, expected: %.f)\n",
201 async_id_fields_.GetValue(kExecutionAsyncId),
202 async_id);
203 DumpBacktrace(stderr);
204 fflush(stderr);
205 if (!env()->abort_on_uncaught_exception())
206 exit(1);
207 fprintf(stderr, "\n");
208 fflush(stderr);
209 ABORT_NO_BACKTRACE();
210 }
211
212 uint32_t offset = fields_[kStackLength] - 1;
213 async_id_fields_[kExecutionAsyncId] = async_ids_stack_[2 * offset];
214 async_id_fields_[kTriggerAsyncId] = async_ids_stack_[2 * offset + 1];
215 fields_[kStackLength] = offset;
216
217 if (LIKELY(offset < native_execution_async_resources_.size() &&
218 !native_execution_async_resources_[offset].IsEmpty())) {
219 #ifdef DEBUG
220 for (uint32_t i = offset + 1;
221 i < native_execution_async_resources_.size();
222 i++) {
223 CHECK(native_execution_async_resources_[i].IsEmpty());
224 }
225 #endif
226 native_execution_async_resources_.resize(offset);
227 if (native_execution_async_resources_.size() <
228 native_execution_async_resources_.capacity() / 2 &&
229 native_execution_async_resources_.size() > 16) {
230 native_execution_async_resources_.shrink_to_fit();
231 }
232 }
233
234 if (UNLIKELY(js_execution_async_resources()->Length() > offset)) {
235 v8::HandleScope handle_scope(env()->isolate());
236 USE(js_execution_async_resources()->Set(
237 env()->context(),
238 env()->length_string(),
239 v8::Integer::NewFromUnsigned(env()->isolate(), offset)));
240 }
241
242 return fields_[kStackLength] > 0;
243 }
244
clear_async_id_stack()245 void AsyncHooks::clear_async_id_stack() {
246 v8::Isolate* isolate = env()->isolate();
247 v8::HandleScope handle_scope(isolate);
248 if (!js_execution_async_resources_.IsEmpty()) {
249 USE(PersistentToLocal::Strong(js_execution_async_resources_)->Set(
250 env()->context(),
251 env()->length_string(),
252 v8::Integer::NewFromUnsigned(isolate, 0)));
253 }
254 native_execution_async_resources_.clear();
255 native_execution_async_resources_.shrink_to_fit();
256
257 async_id_fields_[kExecutionAsyncId] = 0;
258 async_id_fields_[kTriggerAsyncId] = 0;
259 fields_[kStackLength] = 0;
260 }
261
AddContext(v8::Local<v8::Context> ctx)262 inline void AsyncHooks::AddContext(v8::Local<v8::Context> ctx) {
263 ctx->SetPromiseHooks(
264 js_promise_hooks_[0].IsEmpty() ?
265 v8::Local<v8::Function>() :
266 PersistentToLocal::Strong(js_promise_hooks_[0]),
267 js_promise_hooks_[1].IsEmpty() ?
268 v8::Local<v8::Function>() :
269 PersistentToLocal::Strong(js_promise_hooks_[1]),
270 js_promise_hooks_[2].IsEmpty() ?
271 v8::Local<v8::Function>() :
272 PersistentToLocal::Strong(js_promise_hooks_[2]),
273 js_promise_hooks_[3].IsEmpty() ?
274 v8::Local<v8::Function>() :
275 PersistentToLocal::Strong(js_promise_hooks_[3]));
276
277 size_t id = contexts_.size();
278 contexts_.resize(id + 1);
279 contexts_[id].Reset(env()->isolate(), ctx);
280 contexts_[id].SetWeak();
281 }
282
RemoveContext(v8::Local<v8::Context> ctx)283 inline void AsyncHooks::RemoveContext(v8::Local<v8::Context> ctx) {
284 v8::Isolate* isolate = env()->isolate();
285 v8::HandleScope handle_scope(isolate);
286 for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
287 if (it->IsEmpty()) {
288 it = contexts_.erase(it);
289 it--;
290 continue;
291 }
292 v8::Local<v8::Context> saved_context =
293 PersistentToLocal::Weak(isolate, *it);
294 if (saved_context == ctx) {
295 it->Reset();
296 contexts_.erase(it);
297 break;
298 }
299 }
300 }
301
302 // The DefaultTriggerAsyncIdScope(AsyncWrap*) constructor is defined in
303 // async_wrap-inl.h to avoid a circular dependency.
304
DefaultTriggerAsyncIdScope(Environment * env,double default_trigger_async_id)305 inline AsyncHooks::DefaultTriggerAsyncIdScope ::DefaultTriggerAsyncIdScope(
306 Environment* env, double default_trigger_async_id)
307 : async_hooks_(env->async_hooks()) {
308 if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
309 CHECK_GE(default_trigger_async_id, 0);
310 }
311
312 old_default_trigger_async_id_ =
313 async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
314 async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
315 default_trigger_async_id;
316 }
317
~DefaultTriggerAsyncIdScope()318 inline AsyncHooks::DefaultTriggerAsyncIdScope ::~DefaultTriggerAsyncIdScope() {
319 async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
320 old_default_trigger_async_id_;
321 }
322
ForAsyncHooks(AsyncHooks * hooks)323 Environment* Environment::ForAsyncHooks(AsyncHooks* hooks) {
324 return ContainerOf(&Environment::async_hooks_, hooks);
325 }
326
async_callback_scope_depth()327 inline size_t Environment::async_callback_scope_depth() const {
328 return async_callback_scope_depth_;
329 }
330
PushAsyncCallbackScope()331 inline void Environment::PushAsyncCallbackScope() {
332 async_callback_scope_depth_++;
333 }
334
PopAsyncCallbackScope()335 inline void Environment::PopAsyncCallbackScope() {
336 async_callback_scope_depth_--;
337 }
338
ImmediateInfo(v8::Isolate * isolate)339 inline ImmediateInfo::ImmediateInfo(v8::Isolate* isolate)
340 : fields_(isolate, kFieldsCount) {}
341
fields()342 inline AliasedUint32Array& ImmediateInfo::fields() {
343 return fields_;
344 }
345
count()346 inline uint32_t ImmediateInfo::count() const {
347 return fields_[kCount];
348 }
349
ref_count()350 inline uint32_t ImmediateInfo::ref_count() const {
351 return fields_[kRefCount];
352 }
353
has_outstanding()354 inline bool ImmediateInfo::has_outstanding() const {
355 return fields_[kHasOutstanding] == 1;
356 }
357
ref_count_inc(uint32_t increment)358 inline void ImmediateInfo::ref_count_inc(uint32_t increment) {
359 fields_[kRefCount] += increment;
360 }
361
ref_count_dec(uint32_t decrement)362 inline void ImmediateInfo::ref_count_dec(uint32_t decrement) {
363 fields_[kRefCount] -= decrement;
364 }
365
TickInfo(v8::Isolate * isolate)366 inline TickInfo::TickInfo(v8::Isolate* isolate)
367 : fields_(isolate, kFieldsCount) {}
368
fields()369 inline AliasedUint8Array& TickInfo::fields() {
370 return fields_;
371 }
372
has_tick_scheduled()373 inline bool TickInfo::has_tick_scheduled() const {
374 return fields_[kHasTickScheduled] == 1;
375 }
376
has_rejection_to_warn()377 inline bool TickInfo::has_rejection_to_warn() const {
378 return fields_[kHasRejectionToWarn] == 1;
379 }
380
AssignToContext(v8::Local<v8::Context> context,const ContextInfo & info)381 inline void Environment::AssignToContext(v8::Local<v8::Context> context,
382 const ContextInfo& info) {
383 context->SetAlignedPointerInEmbedderData(
384 ContextEmbedderIndex::kEnvironment, this);
385 // Used by Environment::GetCurrent to know that we are on a node context.
386 context->SetAlignedPointerInEmbedderData(
387 ContextEmbedderIndex::kContextTag, Environment::kNodeContextTagPtr);
388 // Used to retrieve bindings
389 context->SetAlignedPointerInEmbedderData(
390 ContextEmbedderIndex::kBindingListIndex, &(this->bindings_));
391
392 #if HAVE_INSPECTOR
393 inspector_agent()->ContextCreated(context, info);
394 #endif // HAVE_INSPECTOR
395
396 this->async_hooks()->AddContext(context);
397 }
398
GetCurrent(v8::Isolate * isolate)399 inline Environment* Environment::GetCurrent(v8::Isolate* isolate) {
400 if (UNLIKELY(!isolate->InContext())) return nullptr;
401 v8::HandleScope handle_scope(isolate);
402 return GetCurrent(isolate->GetCurrentContext());
403 }
404
GetCurrent(v8::Local<v8::Context> context)405 inline Environment* Environment::GetCurrent(v8::Local<v8::Context> context) {
406 if (UNLIKELY(context.IsEmpty())) {
407 return nullptr;
408 }
409 if (UNLIKELY(context->GetNumberOfEmbedderDataFields() <=
410 ContextEmbedderIndex::kContextTag)) {
411 return nullptr;
412 }
413 if (UNLIKELY(context->GetAlignedPointerFromEmbedderData(
414 ContextEmbedderIndex::kContextTag) !=
415 Environment::kNodeContextTagPtr)) {
416 return nullptr;
417 }
418 return static_cast<Environment*>(
419 context->GetAlignedPointerFromEmbedderData(
420 ContextEmbedderIndex::kEnvironment));
421 }
422
GetCurrent(const v8::FunctionCallbackInfo<v8::Value> & info)423 inline Environment* Environment::GetCurrent(
424 const v8::FunctionCallbackInfo<v8::Value>& info) {
425 return GetCurrent(info.GetIsolate()->GetCurrentContext());
426 }
427
428 template <typename T>
GetCurrent(const v8::PropertyCallbackInfo<T> & info)429 inline Environment* Environment::GetCurrent(
430 const v8::PropertyCallbackInfo<T>& info) {
431 return GetCurrent(info.GetIsolate()->GetCurrentContext());
432 }
433
434 template <typename T, typename U>
GetBindingData(const v8::PropertyCallbackInfo<U> & info)435 inline T* Environment::GetBindingData(const v8::PropertyCallbackInfo<U>& info) {
436 return GetBindingData<T>(info.GetIsolate()->GetCurrentContext());
437 }
438
439 template <typename T>
GetBindingData(const v8::FunctionCallbackInfo<v8::Value> & info)440 inline T* Environment::GetBindingData(
441 const v8::FunctionCallbackInfo<v8::Value>& info) {
442 return GetBindingData<T>(info.GetIsolate()->GetCurrentContext());
443 }
444
445 template <typename T>
GetBindingData(v8::Local<v8::Context> context)446 inline T* Environment::GetBindingData(v8::Local<v8::Context> context) {
447 BindingDataStore* map = static_cast<BindingDataStore*>(
448 context->GetAlignedPointerFromEmbedderData(
449 ContextEmbedderIndex::kBindingListIndex));
450 DCHECK_NOT_NULL(map);
451 auto it = map->find(T::type_name);
452 if (UNLIKELY(it == map->end())) return nullptr;
453 T* result = static_cast<T*>(it->second.get());
454 DCHECK_NOT_NULL(result);
455 DCHECK_EQ(result->env(), GetCurrent(context));
456 return result;
457 }
458
459 template <typename T>
AddBindingData(v8::Local<v8::Context> context,v8::Local<v8::Object> target)460 inline T* Environment::AddBindingData(
461 v8::Local<v8::Context> context,
462 v8::Local<v8::Object> target) {
463 DCHECK_EQ(GetCurrent(context), this);
464 // This won't compile if T is not a BaseObject subclass.
465 BaseObjectPtr<T> item = MakeDetachedBaseObject<T>(this, target);
466 BindingDataStore* map = static_cast<BindingDataStore*>(
467 context->GetAlignedPointerFromEmbedderData(
468 ContextEmbedderIndex::kBindingListIndex));
469 DCHECK_NOT_NULL(map);
470 auto result = map->emplace(T::type_name, item);
471 CHECK(result.second);
472 DCHECK_EQ(GetBindingData<T>(context), item.get());
473 return item.get();
474 }
475
GetThreadLocalEnv()476 inline Environment* Environment::GetThreadLocalEnv() {
477 return static_cast<Environment*>(uv_key_get(&thread_local_env));
478 }
479
isolate()480 inline v8::Isolate* Environment::isolate() const {
481 return isolate_;
482 }
483
from_timer_handle(uv_timer_t * handle)484 inline Environment* Environment::from_timer_handle(uv_timer_t* handle) {
485 return ContainerOf(&Environment::timer_handle_, handle);
486 }
487
timer_handle()488 inline uv_timer_t* Environment::timer_handle() {
489 return &timer_handle_;
490 }
491
from_immediate_check_handle(uv_check_t * handle)492 inline Environment* Environment::from_immediate_check_handle(
493 uv_check_t* handle) {
494 return ContainerOf(&Environment::immediate_check_handle_, handle);
495 }
496
immediate_check_handle()497 inline uv_check_t* Environment::immediate_check_handle() {
498 return &immediate_check_handle_;
499 }
500
immediate_idle_handle()501 inline uv_idle_t* Environment::immediate_idle_handle() {
502 return &immediate_idle_handle_;
503 }
504
RegisterHandleCleanup(uv_handle_t * handle,HandleCleanupCb cb,void * arg)505 inline void Environment::RegisterHandleCleanup(uv_handle_t* handle,
506 HandleCleanupCb cb,
507 void* arg) {
508 handle_cleanup_queue_.push_back(HandleCleanup{handle, cb, arg});
509 }
510
511 template <typename T, typename OnCloseCallback>
CloseHandle(T * handle,OnCloseCallback callback)512 inline void Environment::CloseHandle(T* handle, OnCloseCallback callback) {
513 handle_cleanup_waiting_++;
514 static_assert(sizeof(T) >= sizeof(uv_handle_t), "T is a libuv handle");
515 static_assert(offsetof(T, data) == offsetof(uv_handle_t, data),
516 "T is a libuv handle");
517 static_assert(offsetof(T, close_cb) == offsetof(uv_handle_t, close_cb),
518 "T is a libuv handle");
519 struct CloseData {
520 Environment* env;
521 OnCloseCallback callback;
522 void* original_data;
523 };
524 handle->data = new CloseData { this, callback, handle->data };
525 uv_close(reinterpret_cast<uv_handle_t*>(handle), [](uv_handle_t* handle) {
526 std::unique_ptr<CloseData> data { static_cast<CloseData*>(handle->data) };
527 data->env->handle_cleanup_waiting_--;
528 handle->data = data->original_data;
529 data->callback(reinterpret_cast<T*>(handle));
530 });
531 }
532
IncreaseWaitingRequestCounter()533 void Environment::IncreaseWaitingRequestCounter() {
534 request_waiting_++;
535 }
536
DecreaseWaitingRequestCounter()537 void Environment::DecreaseWaitingRequestCounter() {
538 request_waiting_--;
539 CHECK_GE(request_waiting_, 0);
540 }
541
event_loop()542 inline uv_loop_t* Environment::event_loop() const {
543 return isolate_data()->event_loop();
544 }
545
TryLoadAddon(const char * filename,int flags,const std::function<bool (binding::DLib *)> & was_loaded)546 inline void Environment::TryLoadAddon(
547 const char* filename,
548 int flags,
549 const std::function<bool(binding::DLib*)>& was_loaded) {
550 loaded_addons_.emplace_back(filename, flags);
551 if (!was_loaded(&loaded_addons_.back())) {
552 loaded_addons_.pop_back();
553 }
554 }
555
556 #if HAVE_INSPECTOR
is_in_inspector_console_call()557 inline bool Environment::is_in_inspector_console_call() const {
558 return is_in_inspector_console_call_;
559 }
560
set_is_in_inspector_console_call(bool value)561 inline void Environment::set_is_in_inspector_console_call(bool value) {
562 is_in_inspector_console_call_ = value;
563 }
564 #endif
565
async_hooks()566 inline AsyncHooks* Environment::async_hooks() {
567 return &async_hooks_;
568 }
569
immediate_info()570 inline ImmediateInfo* Environment::immediate_info() {
571 return &immediate_info_;
572 }
573
tick_info()574 inline TickInfo* Environment::tick_info() {
575 return &tick_info_;
576 }
577
timer_base()578 inline uint64_t Environment::timer_base() const {
579 return timer_base_;
580 }
581
env_vars()582 inline std::shared_ptr<KVStore> Environment::env_vars() {
583 return env_vars_;
584 }
585
set_env_vars(std::shared_ptr<KVStore> env_vars)586 inline void Environment::set_env_vars(std::shared_ptr<KVStore> env_vars) {
587 env_vars_ = env_vars;
588 }
589
printed_error()590 inline bool Environment::printed_error() const {
591 return printed_error_;
592 }
593
set_printed_error(bool value)594 inline void Environment::set_printed_error(bool value) {
595 printed_error_ = value;
596 }
597
set_trace_sync_io(bool value)598 inline void Environment::set_trace_sync_io(bool value) {
599 trace_sync_io_ = value;
600 }
601
abort_on_uncaught_exception()602 inline bool Environment::abort_on_uncaught_exception() const {
603 return options_->abort_on_uncaught_exception;
604 }
605
set_force_context_aware(bool value)606 inline void Environment::set_force_context_aware(bool value) {
607 options_->force_context_aware = value;
608 }
609
force_context_aware()610 inline bool Environment::force_context_aware() const {
611 return options_->force_context_aware;
612 }
613
set_abort_on_uncaught_exception(bool value)614 inline void Environment::set_abort_on_uncaught_exception(bool value) {
615 options_->abort_on_uncaught_exception = value;
616 }
617
should_abort_on_uncaught_toggle()618 inline AliasedUint32Array& Environment::should_abort_on_uncaught_toggle() {
619 return should_abort_on_uncaught_toggle_;
620 }
621
stream_base_state()622 inline AliasedInt32Array& Environment::stream_base_state() {
623 return stream_base_state_;
624 }
625
get_next_module_id()626 inline uint32_t Environment::get_next_module_id() {
627 return module_id_counter_++;
628 }
get_next_script_id()629 inline uint32_t Environment::get_next_script_id() {
630 return script_id_counter_++;
631 }
get_next_function_id()632 inline uint32_t Environment::get_next_function_id() {
633 return function_id_counter_++;
634 }
635
ShouldNotAbortOnUncaughtScope(Environment * env)636 ShouldNotAbortOnUncaughtScope::ShouldNotAbortOnUncaughtScope(
637 Environment* env)
638 : env_(env) {
639 env_->PushShouldNotAbortOnUncaughtScope();
640 }
641
~ShouldNotAbortOnUncaughtScope()642 ShouldNotAbortOnUncaughtScope::~ShouldNotAbortOnUncaughtScope() {
643 Close();
644 }
645
Close()646 void ShouldNotAbortOnUncaughtScope::Close() {
647 if (env_ != nullptr) {
648 env_->PopShouldNotAbortOnUncaughtScope();
649 env_ = nullptr;
650 }
651 }
652
PushShouldNotAbortOnUncaughtScope()653 inline void Environment::PushShouldNotAbortOnUncaughtScope() {
654 should_not_abort_scope_counter_++;
655 }
656
PopShouldNotAbortOnUncaughtScope()657 inline void Environment::PopShouldNotAbortOnUncaughtScope() {
658 should_not_abort_scope_counter_--;
659 }
660
inside_should_not_abort_on_uncaught_scope()661 inline bool Environment::inside_should_not_abort_on_uncaught_scope() const {
662 return should_not_abort_scope_counter_ > 0;
663 }
664
destroy_async_id_list()665 inline std::vector<double>* Environment::destroy_async_id_list() {
666 return &destroy_async_id_list_;
667 }
668
new_async_id()669 inline double Environment::new_async_id() {
670 async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter] += 1;
671 return async_hooks()->async_id_fields()[AsyncHooks::kAsyncIdCounter];
672 }
673
execution_async_id()674 inline double Environment::execution_async_id() {
675 return async_hooks()->async_id_fields()[AsyncHooks::kExecutionAsyncId];
676 }
677
trigger_async_id()678 inline double Environment::trigger_async_id() {
679 return async_hooks()->async_id_fields()[AsyncHooks::kTriggerAsyncId];
680 }
681
get_default_trigger_async_id()682 inline double Environment::get_default_trigger_async_id() {
683 double default_trigger_async_id =
684 async_hooks()->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
685 // If defaultTriggerAsyncId isn't set, use the executionAsyncId
686 if (default_trigger_async_id < 0)
687 default_trigger_async_id = execution_async_id();
688 return default_trigger_async_id;
689 }
690
options()691 inline std::shared_ptr<EnvironmentOptions> Environment::options() {
692 return options_;
693 }
694
argv()695 inline const std::vector<std::string>& Environment::argv() {
696 return argv_;
697 }
698
exec_argv()699 inline const std::vector<std::string>& Environment::exec_argv() {
700 return exec_argv_;
701 }
702
exec_path()703 inline const std::string& Environment::exec_path() const {
704 return exec_path_;
705 }
706
GetCwd()707 inline std::string Environment::GetCwd() {
708 char cwd[PATH_MAX_BYTES];
709 size_t size = PATH_MAX_BYTES;
710 const int err = uv_cwd(cwd, &size);
711
712 if (err == 0) {
713 CHECK_GT(size, 0);
714 return cwd;
715 }
716
717 // This can fail if the cwd is deleted. In that case, fall back to
718 // exec_path.
719 const std::string& exec_path = exec_path_;
720 return exec_path.substr(0, exec_path.find_last_of(kPathSeparator));
721 }
722
723 #if HAVE_INSPECTOR
set_coverage_directory(const char * dir)724 inline void Environment::set_coverage_directory(const char* dir) {
725 coverage_directory_ = std::string(dir);
726 }
727
set_coverage_connection(std::unique_ptr<profiler::V8CoverageConnection> connection)728 inline void Environment::set_coverage_connection(
729 std::unique_ptr<profiler::V8CoverageConnection> connection) {
730 CHECK_NULL(coverage_connection_);
731 std::swap(coverage_connection_, connection);
732 }
733
coverage_connection()734 inline profiler::V8CoverageConnection* Environment::coverage_connection() {
735 return coverage_connection_.get();
736 }
737
coverage_directory()738 inline const std::string& Environment::coverage_directory() const {
739 return coverage_directory_;
740 }
741
set_cpu_profiler_connection(std::unique_ptr<profiler::V8CpuProfilerConnection> connection)742 inline void Environment::set_cpu_profiler_connection(
743 std::unique_ptr<profiler::V8CpuProfilerConnection> connection) {
744 CHECK_NULL(cpu_profiler_connection_);
745 std::swap(cpu_profiler_connection_, connection);
746 }
747
748 inline profiler::V8CpuProfilerConnection*
cpu_profiler_connection()749 Environment::cpu_profiler_connection() {
750 return cpu_profiler_connection_.get();
751 }
752
set_cpu_prof_interval(uint64_t interval)753 inline void Environment::set_cpu_prof_interval(uint64_t interval) {
754 cpu_prof_interval_ = interval;
755 }
756
cpu_prof_interval()757 inline uint64_t Environment::cpu_prof_interval() const {
758 return cpu_prof_interval_;
759 }
760
set_cpu_prof_name(const std::string & name)761 inline void Environment::set_cpu_prof_name(const std::string& name) {
762 cpu_prof_name_ = name;
763 }
764
cpu_prof_name()765 inline const std::string& Environment::cpu_prof_name() const {
766 return cpu_prof_name_;
767 }
768
set_cpu_prof_dir(const std::string & dir)769 inline void Environment::set_cpu_prof_dir(const std::string& dir) {
770 cpu_prof_dir_ = dir;
771 }
772
cpu_prof_dir()773 inline const std::string& Environment::cpu_prof_dir() const {
774 return cpu_prof_dir_;
775 }
776
set_heap_profiler_connection(std::unique_ptr<profiler::V8HeapProfilerConnection> connection)777 inline void Environment::set_heap_profiler_connection(
778 std::unique_ptr<profiler::V8HeapProfilerConnection> connection) {
779 CHECK_NULL(heap_profiler_connection_);
780 std::swap(heap_profiler_connection_, connection);
781 }
782
783 inline profiler::V8HeapProfilerConnection*
heap_profiler_connection()784 Environment::heap_profiler_connection() {
785 return heap_profiler_connection_.get();
786 }
787
set_heap_prof_name(const std::string & name)788 inline void Environment::set_heap_prof_name(const std::string& name) {
789 heap_prof_name_ = name;
790 }
791
heap_prof_name()792 inline const std::string& Environment::heap_prof_name() const {
793 return heap_prof_name_;
794 }
795
set_heap_prof_dir(const std::string & dir)796 inline void Environment::set_heap_prof_dir(const std::string& dir) {
797 heap_prof_dir_ = dir;
798 }
799
heap_prof_dir()800 inline const std::string& Environment::heap_prof_dir() const {
801 return heap_prof_dir_;
802 }
803
set_heap_prof_interval(uint64_t interval)804 inline void Environment::set_heap_prof_interval(uint64_t interval) {
805 heap_prof_interval_ = interval;
806 }
807
heap_prof_interval()808 inline uint64_t Environment::heap_prof_interval() const {
809 return heap_prof_interval_;
810 }
811
812 #endif // HAVE_INSPECTOR
813
814 inline
inspector_host_port()815 std::shared_ptr<ExclusiveAccess<HostPort>> Environment::inspector_host_port() {
816 return inspector_host_port_;
817 }
818
options()819 inline std::shared_ptr<PerIsolateOptions> IsolateData::options() {
820 return options_;
821 }
822
set_options(std::shared_ptr<PerIsolateOptions> options)823 inline void IsolateData::set_options(
824 std::shared_ptr<PerIsolateOptions> options) {
825 options_ = std::move(options);
826 }
827
828 template <typename Fn>
SetImmediate(Fn && cb,CallbackFlags::Flags flags)829 void Environment::SetImmediate(Fn&& cb, CallbackFlags::Flags flags) {
830 auto callback = native_immediates_.CreateCallback(std::move(cb), flags);
831 native_immediates_.Push(std::move(callback));
832
833 if (flags & CallbackFlags::kRefed) {
834 if (immediate_info()->ref_count() == 0)
835 ToggleImmediateRef(true);
836 immediate_info()->ref_count_inc(1);
837 }
838 }
839
840 template <typename Fn>
SetImmediateThreadsafe(Fn && cb,CallbackFlags::Flags flags)841 void Environment::SetImmediateThreadsafe(Fn&& cb, CallbackFlags::Flags flags) {
842 auto callback = native_immediates_threadsafe_.CreateCallback(
843 std::move(cb), flags);
844 {
845 Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
846 native_immediates_threadsafe_.Push(std::move(callback));
847 if (task_queues_async_initialized_)
848 uv_async_send(&task_queues_async_);
849 }
850 }
851
852 template <typename Fn>
RequestInterrupt(Fn && cb)853 void Environment::RequestInterrupt(Fn&& cb) {
854 auto callback = native_immediates_interrupts_.CreateCallback(
855 std::move(cb), CallbackFlags::kRefed);
856 {
857 Mutex::ScopedLock lock(native_immediates_threadsafe_mutex_);
858 native_immediates_interrupts_.Push(std::move(callback));
859 if (task_queues_async_initialized_)
860 uv_async_send(&task_queues_async_);
861 }
862 RequestInterruptFromV8();
863 }
864
can_call_into_js()865 inline bool Environment::can_call_into_js() const {
866 return can_call_into_js_ && !is_stopping();
867 }
868
set_can_call_into_js(bool can_call_into_js)869 inline void Environment::set_can_call_into_js(bool can_call_into_js) {
870 can_call_into_js_ = can_call_into_js;
871 }
872
has_run_bootstrapping_code()873 inline bool Environment::has_run_bootstrapping_code() const {
874 return has_run_bootstrapping_code_;
875 }
876
set_has_run_bootstrapping_code(bool value)877 inline void Environment::set_has_run_bootstrapping_code(bool value) {
878 has_run_bootstrapping_code_ = value;
879 }
880
has_serialized_options()881 inline bool Environment::has_serialized_options() const {
882 return has_serialized_options_;
883 }
884
set_has_serialized_options(bool value)885 inline void Environment::set_has_serialized_options(bool value) {
886 has_serialized_options_ = value;
887 }
888
is_main_thread()889 inline bool Environment::is_main_thread() const {
890 return worker_context() == nullptr;
891 }
892
no_native_addons()893 inline bool Environment::no_native_addons() const {
894 return (flags_ & EnvironmentFlags::kNoNativeAddons) ||
895 !options_->allow_native_addons;
896 }
897
should_not_register_esm_loader()898 inline bool Environment::should_not_register_esm_loader() const {
899 return flags_ & EnvironmentFlags::kNoRegisterESMLoader;
900 }
901
owns_process_state()902 inline bool Environment::owns_process_state() const {
903 return flags_ & EnvironmentFlags::kOwnsProcessState;
904 }
905
owns_inspector()906 inline bool Environment::owns_inspector() const {
907 return flags_ & EnvironmentFlags::kOwnsInspector;
908 }
909
tracks_unmanaged_fds()910 inline bool Environment::tracks_unmanaged_fds() const {
911 return flags_ & EnvironmentFlags::kTrackUnmanagedFds;
912 }
913
hide_console_windows()914 inline bool Environment::hide_console_windows() const {
915 return flags_ & EnvironmentFlags::kHideConsoleWindows;
916 }
917
filehandle_close_warning()918 bool Environment::filehandle_close_warning() const {
919 return emit_filehandle_warning_;
920 }
921
set_filehandle_close_warning(bool on)922 void Environment::set_filehandle_close_warning(bool on) {
923 emit_filehandle_warning_ = on;
924 }
925
set_source_maps_enabled(bool on)926 void Environment::set_source_maps_enabled(bool on) {
927 source_maps_enabled_ = on;
928 }
929
source_maps_enabled()930 bool Environment::source_maps_enabled() const {
931 return source_maps_enabled_;
932 }
933
thread_id()934 inline uint64_t Environment::thread_id() const {
935 return thread_id_;
936 }
937
worker_context()938 inline worker::Worker* Environment::worker_context() const {
939 return isolate_data()->worker_context();
940 }
941
add_sub_worker_context(worker::Worker * context)942 inline void Environment::add_sub_worker_context(worker::Worker* context) {
943 sub_worker_contexts_.insert(context);
944 }
945
remove_sub_worker_context(worker::Worker * context)946 inline void Environment::remove_sub_worker_context(worker::Worker* context) {
947 sub_worker_contexts_.erase(context);
948 }
949
950 template <typename Fn>
ForEachWorker(Fn && iterator)951 inline void Environment::ForEachWorker(Fn&& iterator) {
952 for (worker::Worker* w : sub_worker_contexts_) iterator(w);
953 }
954
add_refs(int64_t diff)955 inline void Environment::add_refs(int64_t diff) {
956 task_queues_async_refs_ += diff;
957 CHECK_GE(task_queues_async_refs_, 0);
958 if (task_queues_async_refs_ == 0)
959 uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
960 else
961 uv_ref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
962 }
963
is_stopping()964 inline bool Environment::is_stopping() const {
965 return is_stopping_.load();
966 }
967
set_stopping(bool value)968 inline void Environment::set_stopping(bool value) {
969 is_stopping_.store(value);
970 }
971
extra_linked_bindings()972 inline std::list<node_module>* Environment::extra_linked_bindings() {
973 return &extra_linked_bindings_;
974 }
975
extra_linked_bindings_head()976 inline node_module* Environment::extra_linked_bindings_head() {
977 return extra_linked_bindings_.size() > 0 ?
978 &extra_linked_bindings_.front() : nullptr;
979 }
980
extra_linked_bindings_tail()981 inline node_module* Environment::extra_linked_bindings_tail() {
982 return extra_linked_bindings_.size() > 0 ?
983 &extra_linked_bindings_.back() : nullptr;
984 }
985
extra_linked_bindings_mutex()986 inline const Mutex& Environment::extra_linked_bindings_mutex() const {
987 return extra_linked_bindings_mutex_;
988 }
989
performance_state()990 inline performance::PerformanceState* Environment::performance_state() {
991 return performance_state_.get();
992 }
993
994 inline std::unordered_map<std::string, uint64_t>*
performance_marks()995 Environment::performance_marks() {
996 return &performance_marks_;
997 }
998
isolate_data()999 inline IsolateData* Environment::isolate_data() const {
1000 return isolate_data_;
1001 }
1002
1003 std::unordered_map<char*, std::unique_ptr<v8::BackingStore>>*
released_allocated_buffers()1004 Environment::released_allocated_buffers() {
1005 return &released_allocated_buffers_;
1006 }
1007
ThrowError(const char * errmsg)1008 inline void Environment::ThrowError(const char* errmsg) {
1009 ThrowError(v8::Exception::Error, errmsg);
1010 }
1011
ThrowTypeError(const char * errmsg)1012 inline void Environment::ThrowTypeError(const char* errmsg) {
1013 ThrowError(v8::Exception::TypeError, errmsg);
1014 }
1015
ThrowRangeError(const char * errmsg)1016 inline void Environment::ThrowRangeError(const char* errmsg) {
1017 ThrowError(v8::Exception::RangeError, errmsg);
1018 }
1019
ThrowError(v8::Local<v8::Value> (* fun)(v8::Local<v8::String>),const char * errmsg)1020 inline void Environment::ThrowError(
1021 v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
1022 const char* errmsg) {
1023 v8::HandleScope handle_scope(isolate());
1024 isolate()->ThrowException(fun(OneByteString(isolate(), errmsg)));
1025 }
1026
ThrowErrnoException(int errorno,const char * syscall,const char * message,const char * path)1027 inline void Environment::ThrowErrnoException(int errorno,
1028 const char* syscall,
1029 const char* message,
1030 const char* path) {
1031 isolate()->ThrowException(
1032 ErrnoException(isolate(), errorno, syscall, message, path));
1033 }
1034
ThrowUVException(int errorno,const char * syscall,const char * message,const char * path,const char * dest)1035 inline void Environment::ThrowUVException(int errorno,
1036 const char* syscall,
1037 const char* message,
1038 const char* path,
1039 const char* dest) {
1040 isolate()->ThrowException(
1041 UVException(isolate(), errorno, syscall, message, path, dest));
1042 }
1043
1044 inline v8::Local<v8::FunctionTemplate>
NewFunctionTemplate(v8::FunctionCallback callback,v8::Local<v8::Signature> signature,v8::ConstructorBehavior behavior,v8::SideEffectType side_effect_type)1045 Environment::NewFunctionTemplate(v8::FunctionCallback callback,
1046 v8::Local<v8::Signature> signature,
1047 v8::ConstructorBehavior behavior,
1048 v8::SideEffectType side_effect_type) {
1049 return v8::FunctionTemplate::New(isolate(), callback, v8::Local<v8::Value>(),
1050 signature, 0, behavior, side_effect_type);
1051 }
1052
SetMethod(v8::Local<v8::Object> that,const char * name,v8::FunctionCallback callback)1053 inline void Environment::SetMethod(v8::Local<v8::Object> that,
1054 const char* name,
1055 v8::FunctionCallback callback) {
1056 v8::Local<v8::Context> context = isolate()->GetCurrentContext();
1057 v8::Local<v8::Function> function =
1058 NewFunctionTemplate(callback, v8::Local<v8::Signature>(),
1059 v8::ConstructorBehavior::kThrow,
1060 v8::SideEffectType::kHasSideEffect)
1061 ->GetFunction(context)
1062 .ToLocalChecked();
1063 // kInternalized strings are created in the old space.
1064 const v8::NewStringType type = v8::NewStringType::kInternalized;
1065 v8::Local<v8::String> name_string =
1066 v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
1067 that->Set(context, name_string, function).Check();
1068 function->SetName(name_string); // NODE_SET_METHOD() compatibility.
1069 }
1070
SetMethodNoSideEffect(v8::Local<v8::Object> that,const char * name,v8::FunctionCallback callback)1071 inline void Environment::SetMethodNoSideEffect(v8::Local<v8::Object> that,
1072 const char* name,
1073 v8::FunctionCallback callback) {
1074 v8::Local<v8::Context> context = isolate()->GetCurrentContext();
1075 v8::Local<v8::Function> function =
1076 NewFunctionTemplate(callback, v8::Local<v8::Signature>(),
1077 v8::ConstructorBehavior::kThrow,
1078 v8::SideEffectType::kHasNoSideEffect)
1079 ->GetFunction(context)
1080 .ToLocalChecked();
1081 // kInternalized strings are created in the old space.
1082 const v8::NewStringType type = v8::NewStringType::kInternalized;
1083 v8::Local<v8::String> name_string =
1084 v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
1085 that->Set(context, name_string, function).Check();
1086 function->SetName(name_string); // NODE_SET_METHOD() compatibility.
1087 }
1088
SetProtoMethod(v8::Local<v8::FunctionTemplate> that,const char * name,v8::FunctionCallback callback)1089 inline void Environment::SetProtoMethod(v8::Local<v8::FunctionTemplate> that,
1090 const char* name,
1091 v8::FunctionCallback callback) {
1092 v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
1093 v8::Local<v8::FunctionTemplate> t =
1094 NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow,
1095 v8::SideEffectType::kHasSideEffect);
1096 // kInternalized strings are created in the old space.
1097 const v8::NewStringType type = v8::NewStringType::kInternalized;
1098 v8::Local<v8::String> name_string =
1099 v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
1100 that->PrototypeTemplate()->Set(name_string, t);
1101 t->SetClassName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility.
1102 }
1103
SetProtoMethodNoSideEffect(v8::Local<v8::FunctionTemplate> that,const char * name,v8::FunctionCallback callback)1104 inline void Environment::SetProtoMethodNoSideEffect(
1105 v8::Local<v8::FunctionTemplate> that,
1106 const char* name,
1107 v8::FunctionCallback callback) {
1108 v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
1109 v8::Local<v8::FunctionTemplate> t =
1110 NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow,
1111 v8::SideEffectType::kHasNoSideEffect);
1112 // kInternalized strings are created in the old space.
1113 const v8::NewStringType type = v8::NewStringType::kInternalized;
1114 v8::Local<v8::String> name_string =
1115 v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
1116 that->PrototypeTemplate()->Set(name_string, t);
1117 t->SetClassName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility.
1118 }
1119
SetInstanceMethod(v8::Local<v8::FunctionTemplate> that,const char * name,v8::FunctionCallback callback)1120 inline void Environment::SetInstanceMethod(v8::Local<v8::FunctionTemplate> that,
1121 const char* name,
1122 v8::FunctionCallback callback) {
1123 v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
1124 v8::Local<v8::FunctionTemplate> t =
1125 NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow,
1126 v8::SideEffectType::kHasSideEffect);
1127 // kInternalized strings are created in the old space.
1128 const v8::NewStringType type = v8::NewStringType::kInternalized;
1129 v8::Local<v8::String> name_string =
1130 v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
1131 that->InstanceTemplate()->Set(name_string, t);
1132 t->SetClassName(name_string);
1133 }
1134
SetConstructorFunction(v8::Local<v8::Object> that,const char * name,v8::Local<v8::FunctionTemplate> tmpl,SetConstructorFunctionFlag flag)1135 inline void Environment::SetConstructorFunction(
1136 v8::Local<v8::Object> that,
1137 const char* name,
1138 v8::Local<v8::FunctionTemplate> tmpl,
1139 SetConstructorFunctionFlag flag) {
1140 SetConstructorFunction(that, OneByteString(isolate(), name), tmpl, flag);
1141 }
1142
SetConstructorFunction(v8::Local<v8::Object> that,v8::Local<v8::String> name,v8::Local<v8::FunctionTemplate> tmpl,SetConstructorFunctionFlag flag)1143 inline void Environment::SetConstructorFunction(
1144 v8::Local<v8::Object> that,
1145 v8::Local<v8::String> name,
1146 v8::Local<v8::FunctionTemplate> tmpl,
1147 SetConstructorFunctionFlag flag) {
1148 if (LIKELY(flag == SetConstructorFunctionFlag::SET_CLASS_NAME))
1149 tmpl->SetClassName(name);
1150 that->Set(
1151 context(),
1152 name,
1153 tmpl->GetFunction(context()).ToLocalChecked()).Check();
1154 }
1155
AddCleanupHook(CleanupCallback fn,void * arg)1156 void Environment::AddCleanupHook(CleanupCallback fn, void* arg) {
1157 auto insertion_info = cleanup_hooks_.emplace(CleanupHookCallback {
1158 fn, arg, cleanup_hook_counter_++
1159 });
1160 // Make sure there was no existing element with these values.
1161 CHECK_EQ(insertion_info.second, true);
1162 }
1163
RemoveCleanupHook(CleanupCallback fn,void * arg)1164 void Environment::RemoveCleanupHook(CleanupCallback fn, void* arg) {
1165 CleanupHookCallback search { fn, arg, 0 };
1166 cleanup_hooks_.erase(search);
1167 }
1168
operator()1169 size_t CleanupHookCallback::Hash::operator()(
1170 const CleanupHookCallback& cb) const {
1171 return std::hash<void*>()(cb.arg_);
1172 }
1173
operator()1174 bool CleanupHookCallback::Equal::operator()(
1175 const CleanupHookCallback& a, const CleanupHookCallback& b) const {
1176 return a.fn_ == b.fn_ && a.arg_ == b.arg_;
1177 }
1178
GetBaseObject()1179 BaseObject* CleanupHookCallback::GetBaseObject() const {
1180 if (fn_ == BaseObject::DeleteMe)
1181 return static_cast<BaseObject*>(arg_);
1182 else
1183 return nullptr;
1184 }
1185
1186 template <typename T>
ForEachBaseObject(T && iterator)1187 void Environment::ForEachBaseObject(T&& iterator) {
1188 for (const auto& hook : cleanup_hooks_) {
1189 BaseObject* obj = hook.GetBaseObject();
1190 if (obj != nullptr)
1191 iterator(obj);
1192 }
1193 }
1194
modify_base_object_count(int64_t delta)1195 void Environment::modify_base_object_count(int64_t delta) {
1196 base_object_count_ += delta;
1197 }
1198
base_object_count()1199 int64_t Environment::base_object_count() const {
1200 return base_object_count_ - initial_base_object_count_;
1201 }
1202
set_main_utf16(std::unique_ptr<v8::String::Value> str)1203 void Environment::set_main_utf16(std::unique_ptr<v8::String::Value> str) {
1204 CHECK(!main_utf16_);
1205 main_utf16_ = std::move(str);
1206 }
1207
set_process_exit_handler(std::function<void (Environment *,int)> && handler)1208 void Environment::set_process_exit_handler(
1209 std::function<void(Environment*, int)>&& handler) {
1210 process_exit_handler_ = std::move(handler);
1211 }
1212
1213 #define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
1214 #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
1215 #define VS(PropertyName, StringValue) V(v8::String, PropertyName)
1216 #define V(TypeName, PropertyName) \
1217 inline \
1218 v8::Local<TypeName> IsolateData::PropertyName() const { \
1219 return PropertyName ## _ .Get(isolate_); \
1220 }
1221 PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
PER_ISOLATE_SYMBOL_PROPERTIES(VY)1222 PER_ISOLATE_SYMBOL_PROPERTIES(VY)
1223 PER_ISOLATE_STRING_PROPERTIES(VS)
1224 #undef V
1225 #undef VS
1226 #undef VY
1227 #undef VP
1228
1229 #define VP(PropertyName, StringValue) V(v8::Private, PropertyName)
1230 #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName)
1231 #define VS(PropertyName, StringValue) V(v8::String, PropertyName)
1232 #define V(TypeName, PropertyName) \
1233 inline v8::Local<TypeName> Environment::PropertyName() const { \
1234 return isolate_data()->PropertyName(); \
1235 }
1236 PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP)
1237 PER_ISOLATE_SYMBOL_PROPERTIES(VY)
1238 PER_ISOLATE_STRING_PROPERTIES(VS)
1239 #undef V
1240 #undef VS
1241 #undef VY
1242 #undef VP
1243
1244 #define V(PropertyName, TypeName) \
1245 inline v8::Local<TypeName> Environment::PropertyName() const { \
1246 return PersistentToLocal::Strong(PropertyName ## _); \
1247 } \
1248 inline void Environment::set_ ## PropertyName(v8::Local<TypeName> value) { \
1249 PropertyName ## _.Reset(isolate(), value); \
1250 }
1251 ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V)
1252 ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)
1253 #undef V
1254
1255 v8::Local<v8::Context> Environment::context() const {
1256 return PersistentToLocal::Strong(context_);
1257 }
1258
1259 } // namespace node
1260
1261 // These two files depend on each other. Including base_object-inl.h after this
1262 // file is the easiest way to avoid issues with that circular dependency.
1263 #include "base_object-inl.h"
1264
1265 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
1266
1267 #endif // SRC_ENV_INL_H_
1268