diff --git a/node.gyp b/node.gyp index 8c7911732b944c..7f9ead5aed698e 100644 --- a/node.gyp +++ b/node.gyp @@ -1225,6 +1225,16 @@ ], 'conditions': [ + [ 'node_use_openssl=="true"', { + 'defines': [ + 'HAVE_OPENSSL=1', + ], + }], + ['v8_enable_inspector==1', { + 'defines': [ + 'HAVE_INSPECTOR=1', + ], + }], ['OS=="win"', { 'libraries': [ 'dbghelp.lib', @@ -1269,6 +1279,16 @@ ], 'conditions': [ + [ 'node_use_openssl=="true"', { + 'defines': [ + 'HAVE_OPENSSL=1', + ], + }], + ['v8_enable_inspector==1', { + 'defines': [ + 'HAVE_INSPECTOR=1', + ], + }], ['OS=="win"', { 'libraries': [ 'Dbghelp.lib', diff --git a/src/aliased_buffer.h b/src/aliased_buffer.h index b083fb68e69bd2..281c8fed581645 100644 --- a/src/aliased_buffer.h +++ b/src/aliased_buffer.h @@ -4,7 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include -#include "util.h" +#include "util-inl.h" #include "v8.h" namespace node { diff --git a/src/debug_utils-inl.h b/src/debug_utils-inl.h index 2f6137700d8a37..ae2d2046486466 100644 --- a/src/debug_utils-inl.h +++ b/src/debug_utils-inl.h @@ -4,6 +4,7 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "debug_utils.h" +#include "env.h" #include @@ -90,6 +91,93 @@ void COLD_NOINLINE FPrintF(FILE* file, const char* format, Args&&... args) { FWrite(file, SPrintF(format, std::forward(args)...)); } +template +inline void FORCE_INLINE Debug(EnabledDebugList* list, + DebugCategory cat, + const char* format, + Args&&... args) { + if (!UNLIKELY(list->enabled(cat))) return; + FPrintF(stderr, format, std::forward(args)...); +} + +inline void FORCE_INLINE Debug(EnabledDebugList* list, + DebugCategory cat, + const char* message) { + if (!UNLIKELY(list->enabled(cat))) return; + FPrintF(stderr, "%s", message); +} + +template +inline void FORCE_INLINE +Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args) { + Debug(env->enabled_debug_list(), cat, format, std::forward(args)...); +} + +inline void FORCE_INLINE Debug(Environment* env, + DebugCategory cat, + const char* message) { + Debug(env->enabled_debug_list(), cat, message); +} + +template +inline void Debug(Environment* env, + DebugCategory cat, + const std::string& format, + Args&&... args) { + Debug(env->enabled_debug_list(), + cat, + format.c_str(), + std::forward(args)...); +} + +// Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that +// the FORCE_INLINE flag on them doesn't apply to the contents of this function +// as well. +// We apply COLD_NOINLINE to tell the compiler that it's not worth optimizing +// this function for speed and it should rather focus on keeping it out of +// hot code paths. In particular, we want to keep the string concatenating code +// out of the function containing the original `Debug()` call. +template +void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap, + const char* format, + Args&&... args) { + Debug(async_wrap->env(), + static_cast(async_wrap->provider_type()), + async_wrap->diagnostic_name() + " " + format + "\n", + std::forward(args)...); +} + +template +inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, + const char* format, + Args&&... args) { + DCHECK_NOT_NULL(async_wrap); + DebugCategory cat = static_cast(async_wrap->provider_type()); + if (!UNLIKELY(async_wrap->env()->enabled_debug_list()->enabled(cat))) return; + UnconditionalAsyncWrapDebug(async_wrap, format, std::forward(args)...); +} + +template +inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, + const std::string& format, + Args&&... args) { + Debug(async_wrap, format.c_str(), std::forward(args)...); +} + +namespace per_process { + +template +inline void FORCE_INLINE Debug(DebugCategory cat, + const char* format, + Args&&... args) { + Debug(&enabled_debug_list, cat, format, std::forward(args)...); +} + +inline void FORCE_INLINE Debug(DebugCategory cat, const char* message) { + Debug(&enabled_debug_list, cat, message); +} + +} // namespace per_process } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/debug_utils.cc b/src/debug_utils.cc index 4553b642b65837..a601c5ecf40ea9 100644 --- a/src/debug_utils.cc +++ b/src/debug_utils.cc @@ -1,5 +1,6 @@ #include "debug_utils-inl.h" // NOLINT(build/include) #include "env-inl.h" +#include "node_internals.h" #ifdef __POSIX__ #if defined(__linux__) @@ -53,6 +54,37 @@ #endif // _WIN32 namespace node { +namespace per_process { +EnabledDebugList enabled_debug_list; +} + +void EnabledDebugList::Parse(Environment* env) { + std::string cats; + credentials::SafeGetenv("NODE_DEBUG_NATIVE", &cats, env); + Parse(cats, true); +} + +void EnabledDebugList::Parse(const std::string& cats, bool enabled) { + std::string debug_categories = cats; + while (!debug_categories.empty()) { + std::string::size_type comma_pos = debug_categories.find(','); + std::string wanted = ToLower(debug_categories.substr(0, comma_pos)); + +#define V(name) \ + { \ + static const std::string available_category = ToLower(#name); \ + if (available_category.find(wanted) != std::string::npos) \ + set_enabled(DebugCategory::name, enabled); \ + } + + DEBUG_CATEGORY_NAMES(V) +#undef V + + if (comma_pos == std::string::npos) break; + // Use everything after the `,` as the list for the next iteration. + debug_categories = debug_categories.substr(comma_pos + 1); + } +} #ifdef __POSIX__ #if HAVE_EXECINFO_H diff --git a/src/debug_utils.h b/src/debug_utils.h index c745cbe0a1a74b..b654159ac2a24e 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -4,7 +4,6 @@ #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS #include "async_wrap.h" -#include "env.h" #include #include @@ -21,6 +20,7 @@ #endif namespace node { +class Environment; template inline std::string ToString(const T& value); @@ -36,31 +36,72 @@ template inline void FPrintF(FILE* file, const char* format, Args&&... args); void FWrite(FILE* file, const std::string& str); +// 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(CODE_CACHE) \ + V(WASI) + +enum class DebugCategory { +#define V(name) name, + DEBUG_CATEGORY_NAMES(V) +#undef V + CATEGORY_COUNT +}; + +class EnabledDebugList { + public: + bool enabled(DebugCategory category) const { + DCHECK_GE(static_cast(category), 0); + DCHECK_LT(static_cast(category), + static_cast(DebugCategory::CATEGORY_COUNT)); + return enabled_[static_cast(category)]; + } + + // Uses NODE_DEBUG_NATIVE to initialize the categories. When env is not a + // nullptr, the environment variables set in the Environment are used. + // Otherwise the system environment variables are used. + void Parse(Environment* env); + + private: + // Set all categories matching cats to the value of enabled. + void Parse(const std::string& cats, bool enabled); + void set_enabled(DebugCategory category, bool enabled) { + DCHECK_GE(static_cast(category), 0); + DCHECK_LT(static_cast(category), + static_cast(DebugCategory::CATEGORY_COUNT)); + enabled_[static_cast(category)] = true; + } + + bool enabled_[static_cast(DebugCategory::CATEGORY_COUNT)] = {false}; +}; + template -inline void FORCE_INLINE Debug(Environment* env, +inline void FORCE_INLINE Debug(EnabledDebugList* list, DebugCategory cat, const char* format, - Args&&... args) { - if (!UNLIKELY(env->debug_enabled(cat))) - return; - FPrintF(stderr, format, std::forward(args)...); -} + Args&&... args); + +inline void FORCE_INLINE Debug(EnabledDebugList* list, + DebugCategory cat, + const char* message); + +template +inline void FORCE_INLINE +Debug(Environment* env, DebugCategory cat, const char* format, Args&&... args); inline void FORCE_INLINE Debug(Environment* env, DebugCategory cat, - const char* message) { - if (!UNLIKELY(env->debug_enabled(cat))) - return; - FPrintF(stderr, "%s", message); -} + const char* message); template inline void Debug(Environment* env, DebugCategory cat, const std::string& format, - Args&&... args) { - Debug(env, cat, format.c_str(), std::forward(args)...); -} + Args&&... args); // Used internally by the 'real' Debug(AsyncWrap*, ...) functions below, so that // the FORCE_INLINE flag on them doesn't apply to the contents of this function @@ -72,31 +113,17 @@ inline void Debug(Environment* env, template void COLD_NOINLINE UnconditionalAsyncWrapDebug(AsyncWrap* async_wrap, const char* format, - Args&&... args) { - Debug(async_wrap->env(), - static_cast(async_wrap->provider_type()), - async_wrap->diagnostic_name() + " " + format + "\n", - std::forward(args)...); -} + Args&&... args); template inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, const char* format, - Args&&... args) { - DCHECK_NOT_NULL(async_wrap); - DebugCategory cat = - static_cast(async_wrap->provider_type()); - if (!UNLIKELY(async_wrap->env()->debug_enabled(cat))) - return; - UnconditionalAsyncWrapDebug(async_wrap, format, std::forward(args)...); -} + Args&&... args); template inline void FORCE_INLINE Debug(AsyncWrap* async_wrap, const std::string& format, - Args&&... args) { - Debug(async_wrap, format.c_str(), std::forward(args)...); -} + Args&&... args); // Debug helper for inspecting the currently running `node` executable. class NativeSymbolDebuggingContext { @@ -135,6 +162,16 @@ class NativeSymbolDebuggingContext { void CheckedUvLoopClose(uv_loop_t* loop); void PrintLibuvHandleInformation(uv_loop_t* loop, FILE* stream); +namespace per_process { +extern EnabledDebugList enabled_debug_list; + +template +inline void FORCE_INLINE Debug(DebugCategory cat, + const char* format, + Args&&... args); + +inline void FORCE_INLINE Debug(DebugCategory cat, const char* message); +} // namespace per_process } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/src/env-inl.h b/src/env-inl.h index 7f29b93cc12a97..69b7316e405d41 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -609,20 +609,6 @@ inline void Environment::set_http2_state( http2_state_ = std::move(buffer); } -bool Environment::debug_enabled(DebugCategory category) const { - DCHECK_GE(static_cast(category), 0); - DCHECK_LT(static_cast(category), - static_cast(DebugCategory::CATEGORY_COUNT)); - return debug_enabled_[static_cast(category)]; -} - -void Environment::set_debug_enabled(DebugCategory category, bool enabled) { - DCHECK_GE(static_cast(category), 0); - DCHECK_LT(static_cast(category), - static_cast(DebugCategory::CATEGORY_COUNT)); - debug_enabled_[static_cast(category)] = enabled; -} - inline AliasedFloat64Array* Environment::fs_stats_field_array() { return &fs_stats_field_array_; } diff --git a/src/env.cc b/src/env.cc index e54e367f0be579..a3ee9158c49d49 100644 --- a/src/env.cc +++ b/src/env.cc @@ -1,6 +1,7 @@ #include "env.h" #include "async_wrap.h" +#include "debug_utils-inl.h" #include "memory_tracker-inl.h" #include "node_buffer.h" #include "node_context_data.h" @@ -315,6 +316,7 @@ Environment::Environment(IsolateData* isolate_data, Context::Scope context_scope(context); set_env_vars(per_process::system_environment); + enabled_debug_list_.Parse(this); // We create new copies of the per-Environment option sets, so that it is // easier to modify them after Environment creation. The defaults are @@ -375,10 +377,6 @@ Environment::Environment(IsolateData* isolate_data, // By default, always abort when --abort-on-uncaught-exception was passed. should_abort_on_uncaught_toggle_[0] = 1; - std::string debug_cats; - credentials::SafeGetenv("NODE_DEBUG_NATIVE", &debug_cats, this); - set_debug_categories(debug_cats, true); - if (options_->no_force_async_hooks_checks) { async_hooks_.no_force_checks(); } @@ -864,29 +862,6 @@ Local Environment::GetNow() { return Number::New(isolate(), static_cast(now)); } -void Environment::set_debug_categories(const std::string& cats, bool enabled) { - std::string debug_categories = cats; - while (!debug_categories.empty()) { - std::string::size_type comma_pos = debug_categories.find(','); - std::string wanted = ToLower(debug_categories.substr(0, comma_pos)); - -#define V(name) \ - { \ - static const std::string available_category = ToLower(#name); \ - if (available_category.find(wanted) != std::string::npos) \ - set_debug_enabled(DebugCategory::name, enabled); \ - } - - DEBUG_CATEGORY_NAMES(V) -#undef V - - if (comma_pos == std::string::npos) - break; - // Use everything after the `,` as the list for the next iteration. - debug_categories = debug_categories.substr(comma_pos + 1); - } -} - void CollectExceptionInfo(Environment* env, Local obj, int errorno, diff --git a/src/env.h b/src/env.h index 3b577e40307640..08f1cf38c6fb60 100644 --- a/src/env.h +++ b/src/env.h @@ -29,6 +29,7 @@ #include "inspector_agent.h" #include "inspector_profiler.h" #endif +#include "debug_utils.h" #include "handle_wrap.h" #include "node.h" #include "node_binding.h" @@ -547,20 +548,7 @@ struct ContextInfo { 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 -}; +class EnabledDebugList; // A unique-pointer-ish object that is compatible with the JS engine's // ArrayBuffer::Allocator. @@ -1022,9 +1010,7 @@ class Environment : public MemoryRetainer { 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); + EnabledDebugList* enabled_debug_list() { return &enabled_debug_list_; } inline AliasedFloat64Array* fs_stats_field_array(); inline AliasedBigUint64Array* fs_stats_field_bigint_array(); @@ -1384,9 +1370,7 @@ class Environment : public MemoryRetainer { bool http_parser_buffer_in_use_ = false; std::unique_ptr http2_state_; - bool debug_enabled_[static_cast(DebugCategory::CATEGORY_COUNT)] = { - false}; - + EnabledDebugList enabled_debug_list_; AliasedFloat64Array fs_stats_field_array_; AliasedBigUint64Array fs_stats_field_bigint_array_; diff --git a/src/node.cc b/src/node.cc index a0398b1a4f8d2c..37812f0b900446 100644 --- a/src/node.cc +++ b/src/node.cc @@ -912,6 +912,10 @@ void Init(int* argc, } InitializationResult InitializeOncePerProcess(int argc, char** argv) { + // Initialized the enabled list for Debug() calls with system + // environment variables. + per_process::enabled_debug_list.Parse(nullptr); + atexit(ResetStdio); PlatformInit(); diff --git a/src/node_env_var.cc b/src/node_env_var.cc index 02f24fff205ce6..5318b44cb5d59a 100644 --- a/src/node_env_var.cc +++ b/src/node_env_var.cc @@ -1,3 +1,4 @@ +#include "debug_utils-inl.h" #include "env-inl.h" #include "node_errors.h" #include "node_process.h" diff --git a/tools/code_cache/cache_builder.cc b/tools/code_cache/cache_builder.cc index 8210355c4c37e2..28d61a6c70c467 100644 --- a/tools/code_cache/cache_builder.cc +++ b/tools/code_cache/cache_builder.cc @@ -1,4 +1,5 @@ #include "cache_builder.h" +#include "debug_utils-inl.h" #include "node_native_module.h" #include "util.h" @@ -67,8 +68,7 @@ static void GetInitializer(const std::string& id, std::stringstream& ss) { } static std::string GenerateCodeCache( - const std::map& data, - bool log_progress) { + const std::map& data) { std::stringstream ss; ss << R"(#include #include "node_native_module_env.h" @@ -89,11 +89,13 @@ const bool has_code_cache = true; total += cached_data->length; std::string def = GetDefinition(id, cached_data->length, cached_data->data); ss << def << "\n\n"; - if (log_progress) { - std::cout << "Generated cache for " << id - << ", size = " << FormatSize(cached_data->length) - << ", total = " << FormatSize(total) << "\n"; - } + std::string size_str = FormatSize(cached_data->length); + std::string total_str = FormatSize(total); + per_process::Debug(DebugCategory::CODE_CACHE, + "Generated cache for %s, size = %s, total = %s\n", + id.c_str(), + size_str.c_str(), + total_str.c_str()); } ss << R"(void NativeModuleEnv::InitializeCodeCache() { @@ -142,14 +144,7 @@ std::string CodeCacheBuilder::Generate(Local context) { } } - char env_buf[32]; - size_t env_size = sizeof(env_buf); - int ret = uv_os_getenv("NODE_DEBUG", env_buf, &env_size); - bool log_progress = false; - if (ret == 0 && strcmp(env_buf, "mkcodecache") == 0) { - log_progress = true; - } - return GenerateCodeCache(data, log_progress); + return GenerateCodeCache(data); } } // namespace native_module diff --git a/tools/code_cache/mkcodecache.cc b/tools/code_cache/mkcodecache.cc index e5b43a44b8d0d6..34af7bc61ba374 100644 --- a/tools/code_cache/mkcodecache.cc +++ b/tools/code_cache/mkcodecache.cc @@ -6,6 +6,7 @@ #include #include "cache_builder.h" +#include "debug_utils-inl.h" #include "libplatform/libplatform.h" #include "v8.h" @@ -40,6 +41,8 @@ int main(int argc, char* argv[]) { return 1; } + node::per_process::enabled_debug_list.Parse(nullptr); + std::unique_ptr platform = v8::platform::NewDefaultPlatform(); v8::V8::InitializePlatform(platform.get()); v8::V8::Initialize();