// Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to permit // persons to whom the Software is furnished to do so, subject to the // following conditions: // // The above copyright notice and this permission notice shall be included // in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef SRC_ENV_H_ #define SRC_ENV_H_ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "aliased_buffer.h" #if HAVE_INSPECTOR #include "inspector_agent.h" #include "inspector_profiler.h" #endif #include "handle_wrap.h" #include "node.h" #include "node_binding.h" #include "node_http2_state.h" #include "node_main_instance.h" #include "node_options.h" #include "req_wrap.h" #include "util.h" #include "uv.h" #include "v8.h" #include #include #include #include #include #include #include #include struct nghttp2_rcbuf; namespace node { namespace contextify { class ContextifyScript; class CompiledFnEntry; } namespace fs { class FileHandleReadWrap; } namespace performance { class performance_state; } namespace tracing { class AgentWriterHandle; } #if HAVE_INSPECTOR namespace profiler { class V8CoverageConnection; class V8CpuProfilerConnection; class V8HeapProfilerConnection; } // namespace profiler namespace inspector { class ParentInspectorHandle; } #endif // HAVE_INSPECTOR namespace worker { class Worker; } namespace loader { class ModuleWrap; struct PackageConfig { enum class Exists { Yes, No }; enum class IsValid { Yes, No }; enum class HasMain { Yes, No }; enum class HasName { Yes, No }; enum PackageType : uint32_t { None = 0, CommonJS, Module }; const Exists exists; const IsValid is_valid; const HasMain has_main; const std::string main; const HasName has_name; const std::string name; const PackageType type; v8::Global exports; }; } // namespace loader enum class FsStatsOffset { kDev = 0, kMode, kNlink, kUid, kGid, kRdev, kBlkSize, kIno, kSize, kBlocks, kATimeSec, kATimeNsec, kMTimeSec, kMTimeNsec, kCTimeSec, kCTimeNsec, kBirthTimeSec, kBirthTimeNsec, kFsStatsFieldsNumber }; // Stat fields buffers contain twice the number of entries in an uv_stat_t // because `fs.StatWatcher` needs room to store 2 `fs.Stats` instances. constexpr size_t kFsStatsBufferLength = static_cast(FsStatsOffset::kFsStatsFieldsNumber) * 2; // PER_ISOLATE_* macros: We have a lot of per-isolate properties // and adding and maintaining their getters and setters by hand would be // difficult so let's make the preprocessor generate them for us. // // In each macro, `V` is expected to be the name of a macro or function which // accepts the number of arguments provided in each tuple in the macro body, // typically two. The named function will be invoked against each tuple. // // Make sure that any macro V defined for use with the PER_ISOLATE_* macros is // undefined again after use. // Private symbols are per-isolate primitives but Environment proxies them // for the sake of convenience. Strings should be ASCII-only and have a // "node:" prefix to avoid name clashes with third-party code. #define PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(V) \ V(alpn_buffer_private_symbol, "node:alpnBuffer") \ V(arraybuffer_untransferable_private_symbol, "node:untransferableBuffer") \ V(arrow_message_private_symbol, "node:arrowMessage") \ V(contextify_context_private_symbol, "node:contextify:context") \ V(contextify_global_private_symbol, "node:contextify:global") \ V(decorated_private_symbol, "node:decorated") \ V(napi_wrapper, "node:napi:wrapper") \ // Symbols are per-isolate primitives but Environment proxies them // for the sake of convenience. #define PER_ISOLATE_SYMBOL_PROPERTIES(V) \ V(handle_onclose_symbol, "handle_onclose") \ V(no_message_symbol, "no_message_symbol") \ V(oninit_symbol, "oninit") \ V(owner_symbol, "owner") \ // Strings are per-isolate primitives but Environment proxies them // for the sake of convenience. Strings should be ASCII-only. #define PER_ISOLATE_STRING_PROPERTIES(V) \ V(address_string, "address") \ V(aliases_string, "aliases") \ V(args_string, "args") \ V(asn1curve_string, "asn1Curve") \ V(async_ids_stack_string, "async_ids_stack") \ V(bits_string, "bits") \ V(buffer_string, "buffer") \ V(bytes_parsed_string, "bytesParsed") \ V(bytes_read_string, "bytesRead") \ V(bytes_written_string, "bytesWritten") \ V(cached_data_produced_string, "cachedDataProduced") \ V(cached_data_rejected_string, "cachedDataRejected") \ V(cached_data_string, "cachedData") \ V(cache_key_string, "cacheKey") \ V(change_string, "change") \ V(channel_string, "channel") \ V(chunks_sent_since_last_write_string, "chunksSentSinceLastWrite") \ V(clone_unsupported_type_str, "Cannot transfer object of unsupported type.") \ V(code_string, "code") \ V(commonjs_string, "commonjs") \ V(config_string, "config") \ V(constants_string, "constants") \ V(crypto_dsa_string, "dsa") \ V(crypto_ec_string, "ec") \ V(crypto_ed25519_string, "ed25519") \ V(crypto_ed448_string, "ed448") \ V(crypto_x25519_string, "x25519") \ V(crypto_x448_string, "x448") \ V(crypto_rsa_string, "rsa") \ V(crypto_rsa_pss_string, "rsa-pss") \ V(cwd_string, "cwd") \ V(data_string, "data") \ V(default_string, "default") \ V(dest_string, "dest") \ V(destroyed_string, "destroyed") \ V(detached_string, "detached") \ V(dns_a_string, "A") \ V(dns_aaaa_string, "AAAA") \ V(dns_cname_string, "CNAME") \ V(dns_mx_string, "MX") \ V(dns_naptr_string, "NAPTR") \ V(dns_ns_string, "NS") \ V(dns_ptr_string, "PTR") \ V(dns_soa_string, "SOA") \ V(dns_srv_string, "SRV") \ V(dns_txt_string, "TXT") \ V(done_string, "done") \ V(dot_string, ".") \ V(duration_string, "duration") \ V(emit_warning_string, "emitWarning") \ V(empty_object_string, "{}") \ V(encoding_string, "encoding") \ V(entries_string, "entries") \ V(entry_type_string, "entryType") \ V(env_pairs_string, "envPairs") \ V(env_var_settings_string, "envVarSettings") \ V(errno_string, "errno") \ V(error_string, "error") \ V(exchange_string, "exchange") \ V(exit_code_string, "exitCode") \ V(expire_string, "expire") \ V(exponent_string, "exponent") \ V(exports_string, "exports") \ V(ext_key_usage_string, "ext_key_usage") \ V(external_stream_string, "_externalStream") \ V(family_string, "family") \ V(fatal_exception_string, "_fatalException") \ V(fd_string, "fd") \ V(fields_string, "fields") \ V(file_string, "file") \ V(fingerprint256_string, "fingerprint256") \ V(fingerprint_string, "fingerprint") \ V(flags_string, "flags") \ V(fragment_string, "fragment") \ V(function_string, "function") \ V(get_data_clone_error_string, "_getDataCloneError") \ V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \ V(gid_string, "gid") \ V(h2_string, "h2") \ V(handle_string, "handle") \ V(help_text_string, "helpText") \ V(homedir_string, "homedir") \ V(host_string, "host") \ V(hostmaster_string, "hostmaster") \ V(http_1_1_string, "http/1.1") \ V(ignore_string, "ignore") \ V(infoaccess_string, "infoAccess") \ V(inherit_string, "inherit") \ V(input_string, "input") \ V(internal_binding_string, "internalBinding") \ V(internal_string, "internal") \ V(ipv4_string, "IPv4") \ V(ipv6_string, "IPv6") \ V(isclosing_string, "isClosing") \ V(issuer_string, "issuer") \ V(issuercert_string, "issuerCertificate") \ V(kill_signal_string, "killSignal") \ V(kind_string, "kind") \ V(library_string, "library") \ V(mac_string, "mac") \ V(main_string, "main") \ V(max_buffer_string, "maxBuffer") \ V(message_port_constructor_string, "MessagePort") \ V(message_port_string, "messagePort") \ V(message_string, "message") \ V(minttl_string, "minttl") \ V(module_string, "module") \ V(modulus_string, "modulus") \ V(name_string, "name") \ V(netmask_string, "netmask") \ V(next_string, "next") \ V(nistcurve_string, "nistCurve") \ V(node_string, "node") \ V(nsname_string, "nsname") \ V(ocsp_request_string, "OCSPRequest") \ V(oncertcb_string, "oncertcb") \ V(onchange_string, "onchange") \ V(onclienthello_string, "onclienthello") \ V(oncomplete_string, "oncomplete") \ V(onconnection_string, "onconnection") \ V(ondone_string, "ondone") \ V(onerror_string, "onerror") \ V(onexit_string, "onexit") \ V(onhandshakedone_string, "onhandshakedone") \ V(onhandshakestart_string, "onhandshakestart") \ V(onkeylog_string, "onkeylog") \ V(onmessage_string, "onmessage") \ V(onnewsession_string, "onnewsession") \ V(onocspresponse_string, "onocspresponse") \ V(onreadstart_string, "onreadstart") \ V(onreadstop_string, "onreadstop") \ V(onshutdown_string, "onshutdown") \ V(onsignal_string, "onsignal") \ V(onunpipe_string, "onunpipe") \ V(onwrite_string, "onwrite") \ V(openssl_error_stack, "opensslErrorStack") \ V(options_string, "options") \ V(order_string, "order") \ V(output_string, "output") \ V(parse_error_string, "Parse Error") \ V(password_string, "password") \ V(path_string, "path") \ V(pending_handle_string, "pendingHandle") \ V(pid_string, "pid") \ V(pipe_source_string, "pipeSource") \ V(pipe_string, "pipe") \ V(pipe_target_string, "pipeTarget") \ V(port1_string, "port1") \ V(port2_string, "port2") \ V(port_string, "port") \ V(preference_string, "preference") \ V(primordials_string, "primordials") \ V(priority_string, "priority") \ V(process_string, "process") \ V(promise_string, "promise") \ V(pubkey_string, "pubkey") \ V(query_string, "query") \ V(raw_string, "raw") \ V(read_host_object_string, "_readHostObject") \ V(readable_string, "readable") \ V(reason_string, "reason") \ V(refresh_string, "refresh") \ V(regexp_string, "regexp") \ V(rename_string, "rename") \ V(replacement_string, "replacement") \ V(require_string, "require") \ V(retry_string, "retry") \ V(scheme_string, "scheme") \ V(scopeid_string, "scopeid") \ V(serial_number_string, "serialNumber") \ V(serial_string, "serial") \ V(servername_string, "servername") \ V(service_string, "service") \ V(session_id_string, "sessionId") \ V(shell_string, "shell") \ V(signal_string, "signal") \ V(sink_string, "sink") \ V(size_string, "size") \ V(sni_context_err_string, "Invalid SNI context") \ V(sni_context_string, "sni_context") \ V(source_string, "source") \ V(stack_string, "stack") \ V(standard_name_string, "standardName") \ V(start_time_string, "startTime") \ V(status_string, "status") \ V(stdio_string, "stdio") \ V(subject_string, "subject") \ V(subjectaltname_string, "subjectaltname") \ V(syscall_string, "syscall") \ V(target_string, "target") \ V(thread_id_string, "threadId") \ V(ticketkeycallback_string, "onticketkeycallback") \ V(timeout_string, "timeout") \ V(tls_ticket_string, "tlsTicket") \ V(transfer_string, "transfer") \ V(ttl_string, "ttl") \ V(type_string, "type") \ V(uid_string, "uid") \ V(unknown_string, "") \ V(url_string, "url") \ V(username_string, "username") \ V(valid_from_string, "valid_from") \ V(valid_to_string, "valid_to") \ V(value_string, "value") \ V(verify_error_string, "verifyError") \ V(version_string, "version") \ V(weight_string, "weight") \ V(windows_hide_string, "windowsHide") \ V(windows_verbatim_arguments_string, "windowsVerbatimArguments") \ V(wrap_string, "wrap") \ V(writable_string, "writable") \ V(write_host_object_string, "_writeHostObject") \ V(write_queue_size_string, "writeQueueSize") \ V(x_forwarded_string, "x-forwarded-for") \ V(zero_return_string, "ZERO_RETURN") #define ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) \ V(as_callback_data_template, v8::FunctionTemplate) \ V(async_wrap_ctor_template, v8::FunctionTemplate) \ V(async_wrap_object_ctor_template, v8::FunctionTemplate) \ V(compiled_fn_entry_template, v8::ObjectTemplate) \ V(dir_instance_template, v8::ObjectTemplate) \ V(fd_constructor_template, v8::ObjectTemplate) \ V(fdclose_constructor_template, v8::ObjectTemplate) \ V(filehandlereadwrap_template, v8::ObjectTemplate) \ V(fsreqpromise_constructor_template, v8::ObjectTemplate) \ V(handle_wrap_ctor_template, v8::FunctionTemplate) \ V(http2settings_constructor_template, v8::ObjectTemplate) \ V(http2stream_constructor_template, v8::ObjectTemplate) \ V(http2ping_constructor_template, v8::ObjectTemplate) \ V(libuv_stream_wrap_ctor_template, v8::FunctionTemplate) \ V(message_event_object_template, v8::ObjectTemplate) \ V(message_port_constructor_template, v8::FunctionTemplate) \ V(pipe_constructor_template, v8::FunctionTemplate) \ V(promise_wrap_template, v8::ObjectTemplate) \ V(sab_lifetimepartner_constructor_template, v8::FunctionTemplate) \ V(script_context_constructor_template, v8::FunctionTemplate) \ V(secure_context_constructor_template, v8::FunctionTemplate) \ V(shutdown_wrap_template, v8::ObjectTemplate) \ V(streambaseoutputstream_constructor_template, v8::ObjectTemplate) \ V(tcp_constructor_template, v8::FunctionTemplate) \ V(tty_constructor_template, v8::FunctionTemplate) \ V(write_wrap_template, v8::ObjectTemplate) #define ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) \ V(as_callback_data, v8::Object) \ V(async_hooks_after_function, v8::Function) \ V(async_hooks_before_function, v8::Function) \ V(async_hooks_binding, v8::Object) \ V(async_hooks_destroy_function, v8::Function) \ V(async_hooks_init_function, v8::Function) \ V(async_hooks_promise_resolve_function, v8::Function) \ V(buffer_prototype_object, v8::Object) \ V(crypto_key_object_constructor, v8::Function) \ V(domain_callback, v8::Function) \ V(domexception_function, v8::Function) \ V(enhance_fatal_stack_after_inspector, v8::Function) \ V(enhance_fatal_stack_before_inspector, v8::Function) \ V(fs_use_promises_symbol, v8::Symbol) \ V(host_import_module_dynamically_callback, v8::Function) \ V(host_initialize_import_meta_object_callback, v8::Function) \ V(http2session_on_altsvc_function, v8::Function) \ V(http2session_on_error_function, v8::Function) \ V(http2session_on_frame_error_function, v8::Function) \ V(http2session_on_goaway_data_function, v8::Function) \ V(http2session_on_headers_function, v8::Function) \ V(http2session_on_origin_function, v8::Function) \ V(http2session_on_ping_function, v8::Function) \ V(http2session_on_priority_function, v8::Function) \ V(http2session_on_settings_function, v8::Function) \ V(http2session_on_stream_close_function, v8::Function) \ V(http2session_on_stream_trailers_function, v8::Function) \ V(internal_binding_loader, v8::Function) \ V(immediate_callback_function, v8::Function) \ V(inspector_console_extension_installer, v8::Function) \ V(message_port, v8::Object) \ V(native_module_require, v8::Function) \ V(performance_entry_callback, v8::Function) \ V(performance_entry_template, v8::Function) \ V(prepare_stack_trace_callback, v8::Function) \ V(process_object, v8::Object) \ V(primordials, v8::Object) \ V(promise_reject_callback, v8::Function) \ V(script_data_constructor_function, v8::Function) \ V(source_map_cache_getter, v8::Function) \ V(tick_callback_function, v8::Function) \ V(timers_callback_function, v8::Function) \ V(tls_wrap_constructor_function, v8::Function) \ V(trace_category_state_function, v8::Function) \ V(udp_constructor_function, v8::Function) \ V(url_constructor_function, v8::Function) class Environment; class IsolateData : public MemoryRetainer { public: IsolateData(v8::Isolate* isolate, uv_loop_t* event_loop, MultiIsolatePlatform* platform = nullptr, ArrayBufferAllocator* node_allocator = nullptr, const std::vector* indexes = nullptr); SET_MEMORY_INFO_NAME(IsolateData) SET_SELF_SIZE(IsolateData) void MemoryInfo(MemoryTracker* tracker) const override; std::vector Serialize(v8::SnapshotCreator* creator); inline uv_loop_t* event_loop() const; inline MultiIsolatePlatform* platform() const; inline std::shared_ptr options(); inline void set_options(std::shared_ptr options); inline bool uses_node_allocator() const; inline v8::ArrayBuffer::Allocator* allocator() const; inline NodeArrayBufferAllocator* node_allocator() const; #define VP(PropertyName, StringValue) V(v8::Private, PropertyName) #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) #define VS(PropertyName, StringValue) V(v8::String, PropertyName) #define V(TypeName, PropertyName) \ inline v8::Local PropertyName(v8::Isolate* isolate) const; PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP) PER_ISOLATE_SYMBOL_PROPERTIES(VY) PER_ISOLATE_STRING_PROPERTIES(VS) #undef V #undef VY #undef VS #undef VP std::unordered_map> http2_static_strs; inline v8::Isolate* isolate() const; IsolateData(const IsolateData&) = delete; IsolateData& operator=(const IsolateData&) = delete; IsolateData(IsolateData&&) = delete; IsolateData& operator=(IsolateData&&) = delete; private: void DeserializeProperties(const std::vector* indexes); void CreateProperties(); #define VP(PropertyName, StringValue) V(v8::Private, PropertyName) #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) #define VS(PropertyName, StringValue) V(v8::String, PropertyName) #define V(TypeName, PropertyName) \ v8::Eternal PropertyName ## _; PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP) PER_ISOLATE_SYMBOL_PROPERTIES(VY) PER_ISOLATE_STRING_PROPERTIES(VS) #undef V #undef VY #undef VS #undef VP v8::Isolate* const isolate_; uv_loop_t* const event_loop_; v8::ArrayBuffer::Allocator* const allocator_; NodeArrayBufferAllocator* const node_allocator_; const bool uses_node_allocator_; MultiIsolatePlatform* platform_; std::shared_ptr options_; }; struct ContextInfo { explicit ContextInfo(const std::string& name) : name(name) {} const std::string name; std::string origin; bool is_default = false; }; // Listing the AsyncWrap provider types first enables us to cast directly // from a provider type to a debug category. #define DEBUG_CATEGORY_NAMES(V) \ NODE_ASYNC_PROVIDER_TYPES(V) \ V(INSPECTOR_SERVER) \ V(INSPECTOR_PROFILER) \ V(WASI) enum class DebugCategory { #define V(name) name, DEBUG_CATEGORY_NAMES(V) #undef V CATEGORY_COUNT }; // A unique-pointer-ish object that is compatible with the JS engine's // ArrayBuffer::Allocator. struct AllocatedBuffer { public: explicit inline AllocatedBuffer(Environment* env = nullptr); inline AllocatedBuffer(Environment* env, uv_buf_t buf); inline ~AllocatedBuffer(); inline void Resize(size_t len); inline uv_buf_t release(); inline char* data(); inline const char* data() const; inline size_t size() const; inline void clear(); inline v8::MaybeLocal ToBuffer(); inline v8::Local ToArrayBuffer(); inline AllocatedBuffer(AllocatedBuffer&& other); inline AllocatedBuffer& operator=(AllocatedBuffer&& other); AllocatedBuffer(const AllocatedBuffer& other) = delete; AllocatedBuffer& operator=(const AllocatedBuffer& other) = delete; private: Environment* env_; // We do not pass this to libuv directly, but uv_buf_t is a convenient way // to represent a chunk of memory, and plays nicely with other parts of core. uv_buf_t buffer_; friend class Environment; }; class AsyncRequest : public MemoryRetainer { public: AsyncRequest() = default; ~AsyncRequest(); AsyncRequest(const AsyncRequest&) = delete; AsyncRequest& operator=(const AsyncRequest&) = delete; AsyncRequest(AsyncRequest&&) = delete; AsyncRequest& operator=(AsyncRequest&&) = delete; void Install(Environment* env, void* data, uv_async_cb target); void Uninstall(); void Stop(); inline void set_stopped(bool flag); inline bool is_stopped() const; uv_async_t* GetHandle(); void MemoryInfo(MemoryTracker* tracker) const override; SET_MEMORY_INFO_NAME(AsyncRequest) SET_SELF_SIZE(AsyncRequest) private: Environment* env_; uv_async_t* async_ = nullptr; std::atomic_bool stopped_ {true}; }; class KVStore { public: KVStore() = default; virtual ~KVStore() = default; KVStore(const KVStore&) = delete; KVStore& operator=(const KVStore&) = delete; KVStore(KVStore&&) = delete; KVStore& operator=(KVStore&&) = delete; virtual v8::MaybeLocal Get(v8::Isolate* isolate, v8::Local key) const = 0; virtual void Set(v8::Isolate* isolate, v8::Local key, v8::Local value) = 0; virtual int32_t Query(v8::Isolate* isolate, v8::Local key) const = 0; virtual void Delete(v8::Isolate* isolate, v8::Local key) = 0; virtual v8::Local Enumerate(v8::Isolate* isolate) const = 0; virtual std::shared_ptr Clone(v8::Isolate* isolate) const; virtual v8::Maybe AssignFromObject(v8::Local context, v8::Local entries); static std::shared_ptr CreateMapKVStore(); }; namespace per_process { extern std::shared_ptr system_environment; } class AsyncHooks : public MemoryRetainer { public: SET_MEMORY_INFO_NAME(AsyncHooks) SET_SELF_SIZE(AsyncHooks) void MemoryInfo(MemoryTracker* tracker) const override; // Reason for both UidFields and Fields are that one is stored as a double* // and the other as a uint32_t*. enum Fields { kInit, kBefore, kAfter, kDestroy, kPromiseResolve, kTotals, kCheck, kStackLength, kFieldsCount, }; enum UidFields { kExecutionAsyncId, kTriggerAsyncId, kAsyncIdCounter, kDefaultTriggerAsyncId, kUidFieldsCount, }; inline AliasedUint32Array& fields(); inline AliasedFloat64Array& async_id_fields(); inline AliasedFloat64Array& async_ids_stack(); inline v8::Local provider_string(int idx); inline void no_force_checks(); inline Environment* env(); inline void push_async_ids(double async_id, double trigger_async_id); inline bool pop_async_id(double async_id); inline void clear_async_id_stack(); // Used in fatal exceptions. AsyncHooks(const AsyncHooks&) = delete; AsyncHooks& operator=(const AsyncHooks&) = delete; AsyncHooks(AsyncHooks&&) = delete; AsyncHooks& operator=(AsyncHooks&&) = delete; ~AsyncHooks() = default; // Used to set the kDefaultTriggerAsyncId in a scope. This is instead of // passing the trigger_async_id along with other constructor arguments. class DefaultTriggerAsyncIdScope { public: DefaultTriggerAsyncIdScope() = delete; explicit DefaultTriggerAsyncIdScope(Environment* env, double init_trigger_async_id); explicit DefaultTriggerAsyncIdScope(AsyncWrap* async_wrap); ~DefaultTriggerAsyncIdScope(); DefaultTriggerAsyncIdScope(const DefaultTriggerAsyncIdScope&) = delete; DefaultTriggerAsyncIdScope& operator=(const DefaultTriggerAsyncIdScope&) = delete; DefaultTriggerAsyncIdScope(DefaultTriggerAsyncIdScope&&) = delete; DefaultTriggerAsyncIdScope& operator=(DefaultTriggerAsyncIdScope&&) = delete; private: AsyncHooks* async_hooks_; double old_default_trigger_async_id_; }; private: friend class Environment; // So we can call the constructor. inline AsyncHooks(); // Keep a list of all Persistent strings used for Provider types. std::array, AsyncWrap::PROVIDERS_LENGTH> providers_; // Stores the ids of the current execution context stack. AliasedFloat64Array async_ids_stack_; // Attached to a Uint32Array that tracks the number of active hooks for // each type. AliasedUint32Array fields_; // Attached to a Float64Array that tracks the state of async resources. AliasedFloat64Array async_id_fields_; void grow_async_ids_stack(); }; class ImmediateInfo : public MemoryRetainer { public: inline AliasedUint32Array& fields(); inline uint32_t count() const; inline uint32_t ref_count() const; inline bool has_outstanding() const; inline void count_inc(uint32_t increment); inline void count_dec(uint32_t decrement); inline void ref_count_inc(uint32_t increment); inline void ref_count_dec(uint32_t decrement); ImmediateInfo(const ImmediateInfo&) = delete; ImmediateInfo& operator=(const ImmediateInfo&) = delete; ImmediateInfo(ImmediateInfo&&) = delete; ImmediateInfo& operator=(ImmediateInfo&&) = delete; ~ImmediateInfo() = default; SET_MEMORY_INFO_NAME(ImmediateInfo) SET_SELF_SIZE(ImmediateInfo) void MemoryInfo(MemoryTracker* tracker) const override; private: friend class Environment; // So we can call the constructor. inline explicit ImmediateInfo(v8::Isolate* isolate); enum Fields { kCount, kRefCount, kHasOutstanding, kFieldsCount }; AliasedUint32Array fields_; }; class TickInfo : public MemoryRetainer { public: inline AliasedUint8Array& fields(); inline bool has_tick_scheduled() const; inline bool has_rejection_to_warn() const; SET_MEMORY_INFO_NAME(TickInfo) SET_SELF_SIZE(TickInfo) void MemoryInfo(MemoryTracker* tracker) const override; TickInfo(const TickInfo&) = delete; TickInfo& operator=(const TickInfo&) = delete; TickInfo(TickInfo&&) = delete; TickInfo& operator=(TickInfo&&) = delete; ~TickInfo() = default; private: friend class Environment; // So we can call the constructor. inline explicit TickInfo(v8::Isolate* isolate); enum Fields { kHasTickScheduled = 0, kHasRejectionToWarn, kFieldsCount }; AliasedUint8Array fields_; }; class TrackingTraceStateObserver : public v8::TracingController::TraceStateObserver { public: explicit TrackingTraceStateObserver(Environment* env) : env_(env) {} void OnTraceEnabled() override { UpdateTraceCategoryState(); } void OnTraceDisabled() override { UpdateTraceCategoryState(); } private: void UpdateTraceCategoryState(); Environment* env_; }; class ShouldNotAbortOnUncaughtScope { public: explicit inline ShouldNotAbortOnUncaughtScope(Environment* env); inline void Close(); inline ~ShouldNotAbortOnUncaughtScope(); ShouldNotAbortOnUncaughtScope(const ShouldNotAbortOnUncaughtScope&) = delete; ShouldNotAbortOnUncaughtScope& operator=( const ShouldNotAbortOnUncaughtScope&) = delete; ShouldNotAbortOnUncaughtScope(ShouldNotAbortOnUncaughtScope&&) = delete; ShouldNotAbortOnUncaughtScope& operator=(ShouldNotAbortOnUncaughtScope&&) = delete; private: Environment* env_; }; class CleanupHookCallback { public: CleanupHookCallback(void (*fn)(void*), void* arg, uint64_t insertion_order_counter) : fn_(fn), arg_(arg), insertion_order_counter_(insertion_order_counter) {} // Only hashes `arg_`, since that is usually enough to identify the hook. struct Hash { inline size_t operator()(const CleanupHookCallback& cb) const; }; // Compares by `fn_` and `arg_` being equal. struct Equal { inline bool operator()(const CleanupHookCallback& a, const CleanupHookCallback& b) const; }; inline BaseObject* GetBaseObject() const; private: friend class Environment; void (*fn_)(void*); void* arg_; // We keep track of the insertion order for these objects, so that we can // call the callbacks in reverse order when we are cleaning up. uint64_t insertion_order_counter_; }; class Environment : public MemoryRetainer { public: Environment(const Environment&) = delete; Environment& operator=(const Environment&) = delete; Environment(Environment&&) = delete; Environment& operator=(Environment&&) = delete; SET_MEMORY_INFO_NAME(Environment) inline size_t SelfSize() const override; bool IsRootNode() const override { return true; } void MemoryInfo(MemoryTracker* tracker) const override; void CreateProperties(); // Should be called before InitializeInspector() void InitializeDiagnostics(); #if HAVE_INSPECTOR // If the environment is created for a worker, pass parent_handle and // the ownership if transferred into the Environment. int InitializeInspector( std::unique_ptr parent_handle); #endif v8::MaybeLocal BootstrapInternalLoaders(); v8::MaybeLocal BootstrapNode(); v8::MaybeLocal RunBootstrapping(); inline size_t async_callback_scope_depth() const; inline void PushAsyncCallbackScope(); inline void PopAsyncCallbackScope(); enum Flags { kNoFlags = 0, kIsMainThread = 1 << 0, kOwnsProcessState = 1 << 1, kOwnsInspector = 1 << 2, }; static inline Environment* GetCurrent(v8::Isolate* isolate); static inline Environment* GetCurrent(v8::Local context); static inline Environment* GetCurrent( const v8::FunctionCallbackInfo& info); template static inline Environment* GetCurrent( const v8::PropertyCallbackInfo& info); static inline Environment* GetFromCallbackData(v8::Local val); static uv_key_t thread_local_env; static inline Environment* GetThreadLocalEnv(); Environment(IsolateData* isolate_data, v8::Local context, const std::vector& args, const std::vector& exec_args, Flags flags = Flags(), uint64_t thread_id = kNoThreadId); ~Environment(); void InitializeLibuv(bool start_profiler_idle_notifier); inline const std::vector& exec_argv(); inline const std::vector& argv(); const std::string& exec_path() const; typedef void (*HandleCleanupCb)(Environment* env, uv_handle_t* handle, void* arg); struct HandleCleanup { uv_handle_t* handle_; HandleCleanupCb cb_; void* arg_; }; void RegisterHandleCleanups(); void CleanupHandles(); void Exit(int code); void ExitEnv(); // Register clean-up cb to be called on environment destruction. inline void RegisterHandleCleanup(uv_handle_t* handle, HandleCleanupCb cb, void* arg); template inline void CloseHandle(T* handle, OnCloseCallback callback); inline void AssignToContext(v8::Local context, const ContextInfo& info); void StartProfilerIdleNotifier(); void StopProfilerIdleNotifier(); inline bool profiler_idle_notifier_started() const; inline v8::Isolate* isolate() const; inline uv_loop_t* event_loop() const; inline void TryLoadAddon( const char* filename, int flags, const std::function& was_loaded); static inline Environment* from_timer_handle(uv_timer_t* handle); inline uv_timer_t* timer_handle(); static inline Environment* from_immediate_check_handle(uv_check_t* handle); inline uv_check_t* immediate_check_handle(); inline uv_idle_t* immediate_idle_handle(); inline void IncreaseWaitingRequestCounter(); inline void DecreaseWaitingRequestCounter(); inline AsyncHooks* async_hooks(); inline ImmediateInfo* immediate_info(); inline TickInfo* tick_info(); inline uint64_t timer_base() const; inline std::shared_ptr env_vars(); inline void set_env_vars(std::shared_ptr env_vars); inline IsolateData* isolate_data() const; // Utilities that allocate memory using the Isolate's ArrayBuffer::Allocator. // In particular, using AllocateManaged() will provide a RAII-style object // with easy conversion to `Buffer` and `ArrayBuffer` objects. inline AllocatedBuffer AllocateManaged(size_t size, bool checked = true); inline char* Allocate(size_t size); inline char* AllocateUnchecked(size_t size); char* Reallocate(char* data, size_t old_size, size_t size); inline void Free(char* data, size_t size); inline bool printed_error() const; inline void set_printed_error(bool value); void PrintSyncTrace() const; inline void set_trace_sync_io(bool value); // This stores whether the --abort-on-uncaught-exception flag was passed // to Node. inline bool abort_on_uncaught_exception() const; inline void set_abort_on_uncaught_exception(bool value); // This is a pseudo-boolean that keeps track of whether an uncaught exception // should abort the process or not if --abort-on-uncaught-exception was // passed to Node. If the flag was not passed, it is ignored. inline AliasedUint32Array& should_abort_on_uncaught_toggle(); inline AliasedInt32Array& stream_base_state(); // The necessary API for async_hooks. inline double new_async_id(); inline double execution_async_id(); inline double trigger_async_id(); inline double get_default_trigger_async_id(); // List of id's that have been destroyed and need the destroy() cb called. inline std::vector* destroy_async_id_list(); std::set native_modules_with_cache; std::set native_modules_without_cache; std::unordered_multimap hash_to_module_map; std::unordered_map id_to_module_map; std::unordered_map id_to_script_map; std::unordered_map id_to_function_map; inline uint32_t get_next_module_id(); inline uint32_t get_next_script_id(); inline uint32_t get_next_function_id(); std::unordered_map package_json_cache; inline double* heap_statistics_buffer() const; inline void set_heap_statistics_buffer(double* pointer); inline double* heap_space_statistics_buffer() const; inline void set_heap_space_statistics_buffer(double* pointer); inline double* heap_code_statistics_buffer() const; inline void set_heap_code_statistics_buffer(double* pointer); inline char* http_parser_buffer() const; inline void set_http_parser_buffer(char* buffer); inline bool http_parser_buffer_in_use() const; inline void set_http_parser_buffer_in_use(bool in_use); inline http2::Http2State* http2_state() const; inline void set_http2_state(std::unique_ptr state); inline bool debug_enabled(DebugCategory category) const; inline void set_debug_enabled(DebugCategory category, bool enabled); void set_debug_categories(const std::string& cats, bool enabled); inline AliasedFloat64Array* fs_stats_field_array(); inline AliasedBigUint64Array* fs_stats_field_bigint_array(); inline std::vector>& file_handle_read_wrap_freelist(); inline performance::performance_state* performance_state(); inline std::unordered_map* performance_marks(); void CollectUVExceptionInfo(v8::Local context, int errorno, const char* syscall = nullptr, const char* message = nullptr, const char* path = nullptr, const char* dest = nullptr); // If this flag is set, calls into JS (if they would be observable // from userland) must be avoided. This flag does not indicate whether // calling into JS is allowed from a VM perspective at this point. inline bool can_call_into_js() const; inline void set_can_call_into_js(bool can_call_into_js); inline bool has_run_bootstrapping_code() const; inline void set_has_run_bootstrapping_code(bool has_run_bootstrapping_code); inline bool has_serialized_options() const; inline void set_has_serialized_options(bool has_serialized_options); static uint64_t AllocateThreadId(); static constexpr uint64_t kNoThreadId = -1; inline bool is_main_thread() const; inline bool owns_process_state() const; inline bool owns_inspector() const; inline uint64_t thread_id() const; inline worker::Worker* worker_context() const; Environment* worker_parent_env() const; inline void set_worker_context(worker::Worker* context); inline void add_sub_worker_context(worker::Worker* context); inline void remove_sub_worker_context(worker::Worker* context); void stop_sub_worker_contexts(); inline bool is_stopping() const; inline std::list* extra_linked_bindings(); inline node_module* extra_linked_bindings_head(); inline const Mutex& extra_linked_bindings_mutex() const; inline void ThrowError(const char* errmsg); inline void ThrowTypeError(const char* errmsg); inline void ThrowRangeError(const char* errmsg); inline void ThrowErrnoException(int errorno, const char* syscall = nullptr, const char* message = nullptr, const char* path = nullptr); inline void ThrowUVException(int errorno, const char* syscall = nullptr, const char* message = nullptr, const char* path = nullptr, const char* dest = nullptr); inline v8::Local NewFunctionTemplate(v8::FunctionCallback callback, v8::Local signature = v8::Local(), v8::ConstructorBehavior behavior = v8::ConstructorBehavior::kAllow, v8::SideEffectType side_effect = v8::SideEffectType::kHasSideEffect); // Convenience methods for NewFunctionTemplate(). inline void SetMethod(v8::Local that, const char* name, v8::FunctionCallback callback); inline void SetProtoMethod(v8::Local that, const char* name, v8::FunctionCallback callback); inline void SetInstanceMethod(v8::Local that, const char* name, v8::FunctionCallback callback); // Safe variants denote the function has no side effects. inline void SetMethodNoSideEffect(v8::Local that, const char* name, v8::FunctionCallback callback); inline void SetProtoMethodNoSideEffect(v8::Local that, const char* name, v8::FunctionCallback callback); void BeforeExit(void (*cb)(void* arg), void* arg); void RunBeforeExitCallbacks(); void AtExit(void (*cb)(void* arg), void* arg); void RunAtExitCallbacks(); void RegisterFinalizationGroupForCleanup(v8::Local fg); void RunWeakRefCleanup(); void CleanupFinalizationGroups(); // Strings and private symbols are shared across shared contexts // The getters simply proxy to the per-isolate primitive. #define VP(PropertyName, StringValue) V(v8::Private, PropertyName) #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) #define VS(PropertyName, StringValue) V(v8::String, PropertyName) #define V(TypeName, PropertyName) \ inline v8::Local PropertyName() const; PER_ISOLATE_PRIVATE_SYMBOL_PROPERTIES(VP) PER_ISOLATE_SYMBOL_PROPERTIES(VY) PER_ISOLATE_STRING_PROPERTIES(VS) #undef V #undef VS #undef VY #undef VP #define V(PropertyName, TypeName) \ inline v8::Local PropertyName() const; \ inline void set_ ## PropertyName(v8::Local value); ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) #undef V inline v8::Local context() const; #if HAVE_INSPECTOR inline inspector::Agent* inspector_agent() const { return inspector_agent_.get(); } inline bool is_in_inspector_console_call() const; inline void set_is_in_inspector_console_call(bool value); #endif typedef ListHead HandleWrapQueue; typedef ListHead ReqWrapQueue; inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; } inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; } inline bool EmitProcessEnvWarning() { bool current_value = emit_env_nonstring_warning_; emit_env_nonstring_warning_ = false; return current_value; } inline bool EmitErrNameWarning() { bool current_value = emit_err_name_warning_; emit_err_name_warning_ = false; return current_value; } // cb will be called as cb(env) on the next event loop iteration. // keep_alive will be kept alive between now and after the callback has run. template inline void SetImmediate(Fn&& cb); template inline void SetUnrefImmediate(Fn&& cb); // This needs to be available for the JS-land setImmediate(). void ToggleImmediateRef(bool ref); inline void PushShouldNotAbortOnUncaughtScope(); inline void PopShouldNotAbortOnUncaughtScope(); inline bool inside_should_not_abort_on_uncaught_scope() const; static inline Environment* ForAsyncHooks(AsyncHooks* hooks); v8::Local GetNow(); void ScheduleTimer(int64_t duration); void ToggleTimerRef(bool ref); inline void AddCleanupHook(void (*fn)(void*), void* arg); inline void RemoveCleanupHook(void (*fn)(void*), void* arg); void RunCleanup(); static void BuildEmbedderGraph(v8::Isolate* isolate, v8::EmbedderGraph* graph, void* data); inline std::shared_ptr options(); inline std::shared_ptr inspector_host_port(); inline AsyncRequest* thread_stopper() { return &thread_stopper_; } // The BaseObject count is a debugging helper that makes sure that there are // no memory leaks caused by BaseObjects staying alive longer than expected // (in particular, no circular BaseObjectPtr references). inline void modify_base_object_count(int64_t delta); inline int64_t base_object_count() const; #if HAVE_INSPECTOR void set_coverage_connection( std::unique_ptr connection); profiler::V8CoverageConnection* coverage_connection(); inline void set_coverage_directory(const char* directory); inline const std::string& coverage_directory() const; void set_cpu_profiler_connection( std::unique_ptr connection); profiler::V8CpuProfilerConnection* cpu_profiler_connection(); inline void set_cpu_prof_name(const std::string& name); inline const std::string& cpu_prof_name() const; inline void set_cpu_prof_interval(uint64_t interval); inline uint64_t cpu_prof_interval() const; inline void set_cpu_prof_dir(const std::string& dir); inline const std::string& cpu_prof_dir() const; void set_heap_profiler_connection( std::unique_ptr connection); profiler::V8HeapProfilerConnection* heap_profiler_connection(); inline void set_heap_prof_name(const std::string& name); inline const std::string& heap_prof_name() const; inline void set_heap_prof_dir(const std::string& dir); inline const std::string& heap_prof_dir() const; inline void set_heap_prof_interval(uint64_t interval); inline uint64_t heap_prof_interval() const; #endif // HAVE_INSPECTOR private: template inline void CreateImmediate(Fn&& cb, bool ref); inline void ThrowError(v8::Local (*fun)(v8::Local), const char* errmsg); std::list loaded_addons_; v8::Isolate* const isolate_; IsolateData* const isolate_data_; uv_timer_t timer_handle_; uv_check_t immediate_check_handle_; uv_idle_t immediate_idle_handle_; uv_prepare_t idle_prepare_handle_; uv_check_t idle_check_handle_; uv_async_t cleanup_finalization_groups_async_; bool profiler_idle_notifier_started_ = false; AsyncHooks async_hooks_; ImmediateInfo immediate_info_; TickInfo tick_info_; const uint64_t timer_base_; std::shared_ptr env_vars_; bool printed_error_ = false; bool trace_sync_io_ = false; bool emit_env_nonstring_warning_ = true; bool emit_err_name_warning_ = true; size_t async_callback_scope_depth_ = 0; std::vector destroy_async_id_list_; #if HAVE_INSPECTOR std::unique_ptr coverage_connection_; std::unique_ptr cpu_profiler_connection_; std::string coverage_directory_; std::string cpu_prof_dir_; std::string cpu_prof_name_; uint64_t cpu_prof_interval_; std::unique_ptr heap_profiler_connection_; std::string heap_prof_dir_; std::string heap_prof_name_; uint64_t heap_prof_interval_; #endif // HAVE_INSPECTOR std::shared_ptr options_; // options_ contains debug options parsed from CLI arguments, // while inspector_host_port_ stores the actual inspector host // and port being used. For example the port is -1 by default // and can be specified as 0 (meaning any port allocated when the // server starts listening), but when the inspector server starts // the inspector_host_port_->port() will be the actual port being // used. std::shared_ptr inspector_host_port_; std::vector exec_argv_; std::vector argv_; std::string exec_path_; uint32_t module_id_counter_ = 0; uint32_t script_id_counter_ = 0; uint32_t function_id_counter_ = 0; AliasedUint32Array should_abort_on_uncaught_toggle_; int should_not_abort_scope_counter_ = 0; std::unique_ptr trace_state_observer_; AliasedInt32Array stream_base_state_; std::unique_ptr performance_state_; std::unordered_map performance_marks_; bool has_run_bootstrapping_code_ = false; bool has_serialized_options_ = false; bool can_call_into_js_ = true; Flags flags_; uint64_t thread_id_; std::unordered_set sub_worker_contexts_; std::deque> cleanup_finalization_groups_; static void* const kNodeContextTagPtr; static int const kNodeContextTag; #if HAVE_INSPECTOR std::unique_ptr inspector_agent_; bool is_in_inspector_console_call_ = false; #endif // handle_wrap_queue_ and req_wrap_queue_ needs to be at a fixed offset from // the start of the class because it is used by // src/node_postmortem_metadata.cc to calculate offsets and generate debug // symbols for Environment, which assumes that the position of members in // memory are predictable. For more information please refer to // `doc/guides/node-postmortem-support.md` friend int GenDebugSymbols(); HandleWrapQueue handle_wrap_queue_; ReqWrapQueue req_wrap_queue_; std::list handle_cleanup_queue_; int handle_cleanup_waiting_ = 0; int request_waiting_ = 0; double* heap_statistics_buffer_ = nullptr; double* heap_space_statistics_buffer_ = nullptr; double* heap_code_statistics_buffer_ = nullptr; char* http_parser_buffer_ = nullptr; bool http_parser_buffer_in_use_ = false; std::unique_ptr http2_state_; bool debug_enabled_[static_cast(DebugCategory::CATEGORY_COUNT)] = {0}; AliasedFloat64Array fs_stats_field_array_; AliasedBigUint64Array fs_stats_field_bigint_array_; std::vector> file_handle_read_wrap_freelist_; worker::Worker* worker_context_ = nullptr; std::list extra_linked_bindings_; Mutex extra_linked_bindings_mutex_; static void RunTimers(uv_timer_t* handle); struct ExitCallback { void (*cb_)(void* arg); void* arg_; }; std::list before_exit_functions_; std::list at_exit_functions_; class NativeImmediateCallback { public: explicit inline NativeImmediateCallback(bool refed); virtual ~NativeImmediateCallback() = default; virtual void Call(Environment* env) = 0; inline bool is_refed() const; inline std::unique_ptr get_next(); inline void set_next(std::unique_ptr next); private: bool refed_; std::unique_ptr next_; }; template class NativeImmediateCallbackImpl final : public NativeImmediateCallback { public: NativeImmediateCallbackImpl(Fn&& callback, bool refed); void Call(Environment* env) override; private: Fn callback_; }; std::unique_ptr native_immediate_callbacks_head_; NativeImmediateCallback* native_immediate_callbacks_tail_ = nullptr; void RunAndClearNativeImmediates(bool only_refed = false); static void CheckImmediate(uv_check_t* handle); // Use an unordered_set, so that we have efficient insertion and removal. std::unordered_set cleanup_hooks_; uint64_t cleanup_hook_counter_ = 0; bool started_cleanup_ = false; int64_t base_object_count_ = 0; // A custom async abstraction (a pair of async handle and a state variable) // Used by embedders to shutdown running Node instance. AsyncRequest thread_stopper_; template void ForEachBaseObject(T&& iterator); #define V(PropertyName, TypeName) v8::Global PropertyName ## _; ENVIRONMENT_STRONG_PERSISTENT_VALUES(V) ENVIRONMENT_STRONG_PERSISTENT_TEMPLATES(V) #undef V v8::Global context_; }; } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #endif // SRC_ENV_H_