From f8da3628f0339a190c41e48e4355b164fb74aaa4 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 19 Aug 2026 17:14:22 +0200 Subject: [PATCH 1/4] [NativeAOT] Remove std::format from host compilation Keep the std::format logging surface available to CoreCLR while compiling it out of the NativeAOT host. Avoid pulling timing implementation headers into NativeAOT declarations and migrate the remaining shared call sites to printf or direct logging. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/native/clr/host/bridge-processing.cc | 4 ++-- src/native/clr/host/gc-bridge.cc | 2 +- .../clr/host/internal-pinvokes-shared.cc | 12 +++++------ src/native/clr/host/os-bridge.cc | 4 ++-- src/native/clr/include/host/host.hh | 6 ++++++ .../include/runtime-base/internal-pinvokes.hh | 6 ++++++ src/native/clr/include/shared/log_types.hh | 21 ++++++++++++------- 7 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/native/clr/host/bridge-processing.cc b/src/native/clr/host/bridge-processing.cc index 2489346b15e..03e1ad1fdea 100644 --- a/src/native/clr/host/bridge-processing.cc +++ b/src/native/clr/host/bridge-processing.cc @@ -463,7 +463,7 @@ void CrossReferenceTarget::mark_refs_added_if_needed () noexcept [[gnu::always_inline]] void BridgeProcessingShared::log_missing_add_references_method ([[maybe_unused]] jclass java_class) noexcept { - log_error (LOG_DEFAULT, "Failed to find monodroidAddReferences method"); + log_errorf (LOG_DEFAULT, "Failed to find monodroidAddReferences method"); #if DEBUG abort_if_invalid_pointer_argument (java_class, "java_class"); if (!Logger::gc_spew_enabled ()) [[likely]] { @@ -479,7 +479,7 @@ void BridgeProcessingShared::log_missing_add_references_method ([[maybe_unused]] [[gnu::always_inline]] void BridgeProcessingShared::log_missing_clear_references_method ([[maybe_unused]] jclass java_class) noexcept { - log_error (LOG_DEFAULT, "Failed to find monodroidClearReferences method"); + log_errorf (LOG_DEFAULT, "Failed to find monodroidClearReferences method"); #if DEBUG abort_if_invalid_pointer_argument (java_class, "java_class"); if (!Logger::gc_spew_enabled ()) [[likely]] { diff --git a/src/native/clr/host/gc-bridge.cc b/src/native/clr/host/gc-bridge.cc index b9dc2a06184..c40c31ba9af 100644 --- a/src/native/clr/host/gc-bridge.cc +++ b/src/native/clr/host/gc-bridge.cc @@ -85,7 +85,7 @@ void GCBridge::trigger_java_gc (JNIEnv *env) noexcept env->ExceptionDescribe (); env->ExceptionClear (); - log_error (LOG_DEFAULT, "Java GC failed"); + log_errorf (LOG_DEFAULT, "Java GC failed"); } void GCBridge::mark_cross_references (MarkCrossReferencesArgs *args) noexcept diff --git a/src/native/clr/host/internal-pinvokes-shared.cc b/src/native/clr/host/internal-pinvokes-shared.cc index 813e6c64f90..929cdd19cff 100644 --- a/src/native/clr/host/internal-pinvokes-shared.cc +++ b/src/native/clr/host/internal-pinvokes-shared.cc @@ -56,30 +56,30 @@ void monodroid_log (LogLevel level, LogCategories category, const char *message) switch (level) { case LogLevel::Verbose: case LogLevel::Debug: - log_debug_nocheck (category, std::string_view { message }); + log_write (category, LogLevel::Debug, message); break; case LogLevel::Info: - log_info_nocheck (category, std::string_view { message }); + log_write (category, LogLevel::Info, message); break; case LogLevel::Warn: case LogLevel::Silent: // warn is always printed - log_warn (category, std::string_view { message }); + log_write (category, LogLevel::Warn, message); break; case LogLevel::Error: - log_error (category, std::string_view { message }); + log_write (category, LogLevel::Error, message); break; case LogLevel::Fatal: - log_fatal (category, std::string_view { message }); + log_write (category, LogLevel::Fatal, message); break; default: case LogLevel::Unknown: case LogLevel::Default: - log_info_nocheck (category, std::string_view { message }); + log_write (category, LogLevel::Info, message); break; } } diff --git a/src/native/clr/host/os-bridge.cc b/src/native/clr/host/os-bridge.cc index 3a8152b37d6..c5d71a8c9d7 100644 --- a/src/native/clr/host/os-bridge.cc +++ b/src/native/clr/host/os-bridge.cc @@ -91,13 +91,13 @@ auto OSBridge::_monodroid_weak_gref_dec () noexcept -> int void OSBridge::_write_stack_trace (FILE *to, const char *const from, LogCategories category) noexcept { if (from == nullptr) [[unlikely]] { - log_warn (category, "Unable to write stack trace, managed runtime passed a NULL string."); + log_warnf (category, "Unable to write stack trace, managed runtime passed a NULL string."); return; } std::string_view trace { from }; if (trace.empty ()) [[unlikely]] { - log_warn (category, "Empty stack trace passed by the managed runtime."); + log_warnf (category, "Empty stack trace passed by the managed runtime."); return; } diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index a492ecf21b6..79c3c8fe6fa 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -8,7 +8,9 @@ #include "host-common.hh" #include +#if !defined (XA_HOST_NATIVEAOT) #include +#endif #include "../shared/log_types.hh" #include "managed-interface.hh" @@ -23,10 +25,12 @@ namespace xamarin::android { static void Java_mono_android_Runtime_registerNatives (JNIEnv *env, jclass nativeClass) noexcept; static void propagate_uncaught_exception (JNIEnv *env, jobject javaThread, jthrowable javaException) noexcept; +#if !defined (XA_HOST_NATIVEAOT) static auto get_timing () -> std::shared_ptr { return _timing; } +#endif static auto get_java_class_TimeZone () noexcept -> jclass { @@ -54,7 +58,9 @@ namespace xamarin::android { private: static inline void *clr_host = nullptr; static inline unsigned int domain_id = 0; +#if !defined (XA_HOST_NATIVEAOT) static inline std::shared_ptr _timing{}; +#endif static inline bool found_assembly_store = false; static inline jnienv_register_jni_natives_fn jnienv_register_jni_natives = nullptr; static inline jnienv_propagate_uncaught_exception_fn jnienv_propagate_uncaught_exception = nullptr; diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index a5408b45046..3913cfa2a0d 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -6,7 +6,13 @@ #include #include #include "logger.hh" +#if defined (XA_HOST_NATIVEAOT) +namespace xamarin::android { + struct managed_timing_sequence; +} +#else #include +#endif extern "C" { int _monodroid_gref_get () noexcept; diff --git a/src/native/clr/include/shared/log_types.hh b/src/native/clr/include/shared/log_types.hh index 54e164c87f8..24eaca7efd9 100644 --- a/src/native/clr/include/shared/log_types.hh +++ b/src/native/clr/include/shared/log_types.hh @@ -1,12 +1,24 @@ #pragma once #include +#include + +#if !defined (XA_HOST_NATIVEAOT) #include #include -#include +#endif #include +namespace xamarin::android { + [[gnu::always_inline]] + static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept + { + log_write (category, level, message.data ()); + } +} + +#if !defined (XA_HOST_NATIVEAOT) // We redeclare macros here #if defined(log_debug) #undef log_debug @@ -43,12 +55,6 @@ #define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) namespace xamarin::android { - [[gnu::always_inline]] - static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept - { - log_write (category, level, message.data ()); - } - template [[gnu::always_inline]] static inline constexpr void log_write_fmt (LogCategories category, LogLevel level, std::format_string fmt, Args&& ...args) { @@ -115,5 +121,6 @@ static inline constexpr void log_fatal_fmt (LogCategories category, std::string_ { log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); } +#endif extern unsigned int log_categories; From a88d4e8fd0873151b269bb9f2c298c8e5df3d320 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 19 Aug 2026 17:43:15 +0200 Subject: [PATCH 2/4] [Native] Remove std::format from shared CLR code Use the existing printf-style logging APIs throughout code shared by CoreCLR and NativeAOT. Keep timing implementation dependencies out of shared declarations so NativeAOT does not pull in libc++ formatting support. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 99f3f0fa-70d4-4920-a0e5-798643faac81 --- src/native/clr/host/assembly-store.cc | 180 ++++++++++-------- src/native/clr/host/fastdev-assemblies.cc | 59 +++--- src/native/clr/host/host.cc | 160 +++++++++------- src/native/clr/host/internal-pinvokes-clr.cc | 1 + src/native/clr/host/typemap.cc | 130 +++++++------ src/native/clr/include/host/host.hh | 11 +- .../clr/include/host/pinvoke-override-impl.hh | 20 +- .../include/runtime-base/android-system.hh | 2 +- .../include/runtime-base/internal-pinvokes.hh | 5 +- .../clr/include/runtime-base/monodroid-dl.hh | 45 ++++- src/native/clr/include/shared/log_types.hh | 110 ----------- .../clr/pinvoke-override/precompiled.cc | 23 ++- src/native/clr/runtime-base/android-system.cc | 49 ++--- .../common/include/runtime-base/dso-loader.hh | 46 ++++- .../runtime-base/mainthread-dso-loader.hh | 32 ++-- .../system-loadlibrary-wrapper.hh | 6 +- .../include/runtime-base/timing-internal.hh | 8 +- .../common/runtime-base/timing-internal.cc | 27 +-- 18 files changed, 464 insertions(+), 450 deletions(-) diff --git a/src/native/clr/host/assembly-store.cc b/src/native/clr/host/assembly-store.cc index 3b34cf87092..0397ca5182c 100644 --- a/src/native/clr/host/assembly-store.cc +++ b/src/native/clr/host/assembly-store.cc @@ -1,3 +1,6 @@ +#include +#include +#include #include #include #include @@ -116,7 +119,14 @@ namespace { void log_file_error (std::string_view operation, std::string const& path, int error) noexcept { - log_debug (LOG_ASSEMBLY, "Decompressed-assembly cache {} failed for '{}': {}"sv, operation, path, std::strerror (error)); + log_debugf ( + LOG_ASSEMBLY, + "Decompressed-assembly cache %.*s failed for '%s': %s", + static_cast(operation.length ()), + operation.data (), + path.c_str (), + std::strerror (error) + ); } auto write_cache_file (WriteRequest const& req) noexcept -> WriteResult @@ -197,7 +207,7 @@ namespace { writes_enabled = false; clear_write_queue_locked (); writer_running = false; - log_debug (LOG_ASSEMBLY, "Disabling decompressed-assembly cache writes after a persistence failure"sv); + log_debugf (LOG_ASSEMBLY, "Disabling decompressed-assembly cache writes after a persistence failure"); return nullptr; } } @@ -222,7 +232,7 @@ namespace { pthread_attr_destroy (&attributes); } if (result != 0) { - log_debug (LOG_ASSEMBLY, "Failed to start decompressed-assembly cache writer: {}"sv, std::strerror (result)); + log_debugf (LOG_ASSEMBLY, "Failed to start decompressed-assembly cache writer: %s", std::strerror (result)); return false; } @@ -324,7 +334,13 @@ namespace { store_id = assembly_store_id; cache_dir.append ("/"); - cache_dir.append (std::format ("{:x}", store_id)); + std::array store_id_hex {}; + int store_id_length = std::snprintf (store_id_hex.data (), store_id_hex.size (), "%" PRIx64, store_id); + abort_unless ( + store_id_length > 0 && static_cast(store_id_length) < store_id_hex.size (), + "Failed to format decompressed-assembly cache store ID" + ); + cache_dir.append (store_id_hex.data (), static_cast(store_id_length)); if (!ensure_directory (cache_dir)) { return; } @@ -345,10 +361,10 @@ namespace { writes_enabled = true; } - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Enabled decompressed-assembly cache at '{}'; store ID 0x{:x}; write queue limit {} bytes"sv, - cache_dir, + "Enabled decompressed-assembly cache at '%s'; store ID 0x%" PRIx64 "; write queue limit %zu bytes", + cache_dir.c_str (), store_id, MAX_QUEUED_BYTES ); @@ -401,7 +417,7 @@ namespace { footer.payload_size != expected_size || footer.payload_hash != hash_payload (static_cast(mapped), expected_size)) { munmap (mapped, map_size); - log_debug (LOG_ASSEMBLY, "Ignoring invalid decompressed-assembly cache entry for '{}'"sv, name); + log_debugf (LOG_ASSEMBLY, "Ignoring invalid decompressed-assembly cache entry for '%.*s'", static_cast(name.length ()), name.data ()); return nullptr; } @@ -436,18 +452,20 @@ namespace { if (queue_full) { if (total > MAX_QUEUED_BYTES) { - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Skipping decompressed-assembly cache write for '{}': {} bytes exceed the {}-byte queue limit"sv, - name, + "Skipping decompressed-assembly cache write for '%.*s': %zu bytes exceed the %zu-byte queue limit", + static_cast(name.length ()), + name.data (), total, MAX_QUEUED_BYTES ); } else { - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Skipping decompressed-assembly cache write for '{}': {} of {} queue bytes are in use"sv, - name, + "Skipping decompressed-assembly cache write for '%.*s': %zu of %zu queue bytes are in use", + static_cast(name.length ()), + name.data (), bytes_queued, MAX_QUEUED_BYTES ); @@ -517,7 +535,7 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co #if defined (RELEASE) auto header = reinterpret_cast(e.image_data); if (header->magic == COMPRESSED_DATA_MAGIC) { - log_debug (LOG_ASSEMBLY, "Resolving compressed assembly '{}' from the assembly store"sv, name); + log_debugf (LOG_ASSEMBLY, "Resolving compressed assembly '%.*s' from the assembly store", static_cast(name.length ()), name.data ()); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::AssemblyDecompression); @@ -527,12 +545,11 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co Helpers::abort_application (LOG_ASSEMBLY, "Compressed assembly found but no descriptor defined"sv); } if (header->descriptor_index >= compressed_assembly_count) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Invalid compressed assembly descriptor index {}"sv, - header->descriptor_index - ) + std::source_location::current (), + "Invalid compressed assembly descriptor index %" PRIu32, + header->descriptor_index ); } @@ -540,13 +557,12 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co assembly_data_size = e.descriptor->data_size - sizeof(CompressedAssemblyHeader); if (cad.buffer_offset >= uncompressed_assemblies_data_size) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Invalid compressed assembly buffer offset {}. Must be smaller than {}", - cad.buffer_offset, - uncompressed_assemblies_data_size - ) + std::source_location::current (), + "Invalid compressed assembly buffer offset %" PRIu32 ". Must be smaller than %" PRIu32, + cad.buffer_offset, + uncompressed_assemblies_data_size ); } @@ -555,14 +571,13 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co // that will cause the app to crash when one or the the other assembly is loaded, so it's // OK to accept that risk. The whole situation is very, very unlikely. if (cad.uncompressed_file_size > uncompressed_assemblies_data_size - cad.buffer_offset) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Invalid compressed assembly buffer size {} at offset {}. Must not exceed {}", - cad.uncompressed_file_size, - cad.buffer_offset, - uncompressed_assemblies_data_size - cad.buffer_offset - ) + std::source_location::current (), + "Invalid compressed assembly buffer size %" PRIu32 " at offset %" PRIu32 ". Must not exceed %" PRIu32, + cad.uncompressed_file_size, + cad.buffer_offset, + uncompressed_assemblies_data_size - cad.buffer_offset ); } @@ -602,17 +617,17 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co if (header->uncompressed_length != cad.uncompressed_file_size) { if (header->uncompressed_length > cad.uncompressed_file_size) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Compressed assembly '{}' is larger than when the application was built (expected at most {}, got {}). Assemblies don't grow just like that!"sv, - name, - cad.uncompressed_file_size, - header->uncompressed_length - ) + std::source_location::current (), + "Compressed assembly '%.*s' is larger than when the application was built (expected at most %" PRIu32 ", got %" PRIu32 "). Assemblies don't grow just like that!", + static_cast(name.length ()), + name.data (), + cad.uncompressed_file_size, + header->uncompressed_length ); } else { - log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly."sv, name); + log_debugf (LOG_ASSEMBLY, "Compressed assembly '%.*s' is smaller than when the application was built. Adjusting accordingly.", static_cast(name.length ()), name.data ()); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -623,34 +638,34 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co uint8_t *cached = asm_cache::try_load (descriptor_index, name, cad.uncompressed_file_size); if (cached != nullptr) { loaded_from_cache = true; - log_debug (LOG_ASSEMBLY, "Loaded decompressed assembly '{}' from the on-device cache"sv, name); + log_debugf (LOG_ASSEMBLY, "Loaded decompressed assembly '%.*s' from the on-device cache", static_cast(name.length ()), name.data ()); if (asm_cache::tracking != nullptr) { asm_cache::tracking[descriptor_index] = cached; } } else { - log_debug (LOG_ASSEMBLY, "Decompressing assembly '{}' from the assembly store"sv, name); + log_debugf (LOG_ASSEMBLY, "Decompressing assembly '%.*s' from the assembly store", static_cast(name.length ()), name.data ()); size_t ret = ZSTD_decompress (data_buffer, cad.uncompressed_file_size, data_start, assembly_data_size); if (ZSTD_isError (ret)) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Decompression of assembly {} failed: {}"sv, - name, - ZSTD_getErrorName (ret) - ) + std::source_location::current (), + "Decompression of assembly %.*s failed: %s", + static_cast(name.length ()), + name.data (), + ZSTD_getErrorName (ret) ); } if (ret != cad.uncompressed_file_size) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Decompression of assembly {} yielded a different size (expected {}, got {})"sv, - name, - cad.uncompressed_file_size, - static_cast(ret) - ) + std::source_location::current (), + "Decompression of assembly %.*s yielded a different size (expected %" PRIu32 ", got %zu)", + static_cast(name.length ()), + name.data (), + cad.uncompressed_file_size, + ret ); } @@ -674,12 +689,12 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co } else #endif // def RELEASE { - log_debug (LOG_ASSEMBLY, "Assembly '{}' is not compressed in the assembly store"sv, name); + log_debugf (LOG_ASSEMBLY, "Assembly '%.*s' is not compressed in the assembly store", static_cast(name.length ()), name.data ()); // HACK! START // Currently, MAUI crashes when we return a pointer to read-only data, so we must copy // the assembly data to a read-write area. - log_debug (LOG_ASSEMBLY, "Copying assembly data to an r/w memory area"sv); + log_debugf (LOG_ASSEMBLY, "Copying assembly data to an r/w memory area"); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::AssemblyLoad); @@ -733,7 +748,7 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) if constexpr (Constants::is_debug_build) { // In fastdev mode we might not have any assembly store. if (assembly_store_hashes == nullptr) { - log_warn (LOG_ASSEMBLY, "Assembly store not registered. Unable to look up assembly '{}'"sv, name); + log_warnf (LOG_ASSEMBLY, "Assembly store not registered. Unable to look up assembly '%.*s'", static_cast(name.length ()), name.data ()); return nullptr; } } @@ -741,24 +756,23 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name, name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) [[unlikely]] { size = 0; - log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash 0x{:x}) not found"sv, name, name_hash); + log_warnf (LOG_ASSEMBLY, "Assembly '%.*s' (hash 0x%" PRIx32 ") not found", static_cast(name.length ()), name.data (), name_hash); return nullptr; } if (hash_entry->ignore != 0) { size = 0; - log_debug (LOG_ASSEMBLY, "Assembly '{}' ignored"sv, name); + log_debugf (LOG_ASSEMBLY, "Assembly '%.*s' ignored", static_cast(name.length ()), name.data ()); return nullptr; } if (hash_entry->descriptor_index >= assembly_store.assembly_count) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Invalid assembly descriptor index {}, exceeds the maximum value of {}"sv, - hash_entry->descriptor_index, - assembly_store.assembly_count - 1 - ) + std::source_location::current (), + "Invalid assembly descriptor index %" PRIu32 ", exceeds the maximum value of %" PRIu32, + hash_entry->descriptor_index, + assembly_store.assembly_count - 1 ); } @@ -774,9 +788,9 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) assembly_runtime_info.debug_info_data = assembly_store.data_start + store_entry.debug_data_offset; } - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Mapped: image_data == {:p}; debug_info_data == {:p}; config_data == {:p}; descriptor == {:p}; data size == {}; debug data size == {}; config data size == {}; name == '{}'"sv, + "Mapped: image_data == %p; debug_info_data == %p; config_data == %p; descriptor == %p; data size == %" PRIu32 "; debug data size == %" PRIu32 "; config data size == %" PRIu32 "; name == '%.*s'", static_cast(assembly_runtime_info.image_data), static_cast(assembly_runtime_info.debug_info_data), static_cast(assembly_runtime_info.config_data), @@ -784,7 +798,8 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) assembly_runtime_info.descriptor->data_size, assembly_runtime_info.descriptor->debug_data_size, assembly_runtime_info.descriptor->config_data_size, - name + static_cast(name.length ()), + name.data () ); } @@ -796,26 +811,25 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) void AssemblyStore::configure_from_payload (const void *payload_start, const std::function& get_full_store_path) noexcept { auto header = static_cast(payload_start); + std::string full_store_path = get_full_store_path (); if (header->magic != ASSEMBLY_STORE_MAGIC) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Assembly store '{}' is not a valid .NET for Android assembly store file"sv, - get_full_store_path () - ) + std::source_location::current (), + "Assembly store '%s' is not a valid .NET for Android assembly store file", + full_store_path.c_str () ); } if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Assembly store '{}' uses format version {:x}, instead of the expected {:x}"sv, - get_full_store_path (), - header->version, - ASSEMBLY_STORE_FORMAT_VERSION - ) + std::source_location::current (), + "Assembly store '%s' uses format version %" PRIx32 ", instead of the expected %" PRIx32, + full_store_path.c_str (), + header->version, + ASSEMBLY_STORE_FORMAT_VERSION ); } @@ -845,5 +859,5 @@ void AssemblyStore::configure_from_payload (const void *payload_start, const std names_cursor += name_length; } - log_debug (LOG_ASSEMBLY, "Mapped assembly store {}; content ID 0x{:x}"sv, get_full_store_path (), assembly_store_content_id); + log_debugf (LOG_ASSEMBLY, "Mapped assembly store %s; content ID 0x%" PRIx64, full_store_path.c_str (), assembly_store_content_id); } diff --git a/src/native/clr/host/fastdev-assemblies.cc b/src/native/clr/host/fastdev-assemblies.cc index 88533da4967..248633a792c 100644 --- a/src/native/clr/host/fastdev-assemblies.cc +++ b/src/native/clr/host/fastdev-assemblies.cc @@ -38,7 +38,7 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si std::string const& override_dir_path = AndroidSystem::get_primary_override_dir (); if (!Util::dir_exists (override_dir_path)) [[unlikely]] { - log_debug (LOG_ASSEMBLY, "Override directory '{}' does not exist"sv, override_dir_path); + log_debugf (LOG_ASSEMBLY, "Override directory '%s' does not exist", override_dir_path.c_str ()); return nullptr; } @@ -49,51 +49,53 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si if (override_dir_fd < 0) [[likely]] { override_dir = opendir (override_dir_path.c_str ()); if (override_dir == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Failed to open override dir '{}'. {}"sv, override_dir_path, strerror (errno)); + log_warnf (LOG_ASSEMBLY, "Failed to open override dir '%s'. %s", override_dir_path.c_str (), strerror (errno)); return nullptr; } override_dir_fd = dirfd (override_dir); } } - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Attempting to load FastDev assembly '{}' from override directory '{}'"sv, - name, - override_dir_path + "Attempting to load FastDev assembly '%.*s' from override directory '%s'", + static_cast(name.length ()), + name.data (), + override_dir_path.c_str () ); if (!Util::file_exists (override_dir_fd, name)) { - log_warn (LOG_ASSEMBLY, "FastDev assembly '{}' not found."sv, name); + log_warnf (LOG_ASSEMBLY, "FastDev assembly '%.*s' not found.", static_cast(name.length ()), name.data ()); return nullptr; } - log_debug (LOG_ASSEMBLY, "Found FastDev assembly '{}'"sv, name); + log_debugf (LOG_ASSEMBLY, "Found FastDev assembly '%.*s'", static_cast(name.length ()), name.data ()); auto file_size = Util::get_file_size_at (override_dir_fd, name); if (!file_size) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to determine FastDev assembly '{}' file size"sv, name); + log_warnf (LOG_ASSEMBLY, "Unable to determine FastDev assembly '%.*s' file size", static_cast(name.length ()), name.data ()); return nullptr; } constexpr size_t MAX_SIZE = std::numeric_limits>::max (); if (file_size.value () > MAX_SIZE) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "FastDev assembly '{}' size exceeds the maximum supported value of {}"sv, - name, - MAX_SIZE - ) + std::source_location::current (), + "FastDev assembly '%.*s' size exceeds the maximum supported value of %zu", + static_cast(name.length ()), + name.data (), + MAX_SIZE ); } size = static_cast(file_size.value ()); int asm_fd = openat (override_dir_fd, name.data (), O_RDONLY); if (asm_fd < 0) { - log_warn ( + log_warnf ( LOG_ASSEMBLY, - "Failed to open FastDev assembly '{}' for reading. {}"sv, - name, + "Failed to open FastDev assembly '%.*s' for reading. %s", + static_cast(name.length ()), + name.data (), strerror (errno) ); @@ -115,17 +117,18 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si if (nread != size) [[unlikely]] { delete[] buffer; - log_warn ( + log_warnf ( LOG_ASSEMBLY, - "Failed to read FastDev assembly '{}' data. {}"sv, - name, + "Failed to read FastDev assembly '%.*s' data. %s", + static_cast(name.length ()), + name.data (), strerror (errno) ); size = 0; return nullptr; } - log_debug (LOG_ASSEMBLY, "Read {} bytes of FastDev assembly '{}'"sv, nread, name); + log_debugf (LOG_ASSEMBLY, "Read %zd bytes of FastDev assembly '%.*s'", nread, static_cast(name.length ()), name.data ()); return reinterpret_cast(buffer); } @@ -141,7 +144,7 @@ auto FastDevAssemblies::build_tpa_list (std::string &tpa_list) noexcept -> bool DIR *dir = opendir (override_dir_path.c_str ()); if (dir == nullptr) { - log_warn (LOG_ASSEMBLY, "FastDev: failed to open override dir '{}'. {}"sv, override_dir_path, std::strerror (errno)); + log_warnf (LOG_ASSEMBLY, "FastDev: failed to open override dir '%s'. %s", override_dir_path.c_str (), std::strerror (errno)); return false; } @@ -180,13 +183,13 @@ auto FastDevAssemblies::build_tpa_list (std::string &tpa_list) noexcept -> bool } closedir (dir); - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "FastDev: built TPA list with {} assemblies from '{}' (corelib={}, r2r={})"sv, + "FastDev: built TPA list with %zu assemblies from '%s' (corelib=%s, r2r=%s)", count, - override_dir_path, - found_corelib, - found_r2r + override_dir_path.c_str (), + found_corelib ? "true" : "false", + found_r2r ? "true" : "false" ); // We can only safely hand a TPA list to CoreCLR when it contains diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index acb571c38b4..33a2b136f15 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -29,20 +30,22 @@ #include #include #include -#include +#include #include using namespace xamarin::android; +std::shared_ptr Host::_timing{}; + void Host::clr_error_writer (const char *message) noexcept { - log_error (LOG_DEFAULT, "CLR error: {}", optional_string (message)); + log_errorf (LOG_DEFAULT, "CLR error: %s", optional_string (message)); } bool Host::clr_external_assembly_probe (const char *path, void **data_start, int64_t *size) noexcept { // TODO: `path` might be a full path, make sure it isn't - log_debug (LOG_DEFAULT, "clr_external_assembly_probe (\"{}\"...)"sv, path); + log_debugf (LOG_DEFAULT, "clr_external_assembly_probe (\"%s\"...)", optional_string (path)); if (data_start == nullptr || size == nullptr) { return false; // TODO: abort instead? } @@ -57,11 +60,11 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int internal_timing.add_more_info (name); } - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Assembly '{}' data {}mapped ({:p}, {} bytes)", + "Assembly '%s' data %smapped (%p, %" PRId64 " bytes)", optional_string (name), - data_start == nullptr ? "not "sv : ""sv, + data_start == nullptr ? "not " : "", data_start, size ); @@ -75,11 +78,7 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int return log_and_return (path, *data_start, *size); } - log_warn ( - LOG_ASSEMBLY, - "Assembly '{}' not found in FastDev override directory. Attempting to load from assembly store"sv, - optional_string (path) - ); + log_warnf (LOG_ASSEMBLY, "Assembly '%s' not found in FastDev override directory. Attempting to load from assembly store", optional_string (path)); } *data_start = AssemblyStore::open_assembly (path, *size); @@ -91,29 +90,27 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int void Host::scan_filesystem_for_assemblies_and_libraries () noexcept { std::string const& native_lib_dir = AndroidSystem::get_native_libraries_dir (); - log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'"sv, native_lib_dir); + log_debugf (LOG_ASSEMBLY, "Looking for assemblies in '%s'", native_lib_dir.c_str ()); DIR *lib_dir = opendir (native_lib_dir.c_str ()); if (lib_dir == nullptr) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Unable to open native library directory '{}'. {}"sv, - native_lib_dir, - std::strerror (errno) - ) + std::source_location::current (), + "Unable to open native library directory '%s'. %s", + native_lib_dir.c_str (), + std::strerror (errno) ); } int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Unable to obtain file descriptor for opened directory '{}'. {}"sv, - native_lib_dir, - std::strerror (errno) - ) + std::source_location::current (), + "Unable to obtain file descriptor for opened directory '%s'. %s", + native_lib_dir.c_str (), + std::strerror (errno) ); } @@ -122,7 +119,7 @@ void Host::scan_filesystem_for_assemblies_and_libraries () noexcept dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}"sv, native_lib_dir, std::strerror (errno)); + log_warnf (LOG_ASSEMBLY, "Failed to open a directory entry from '%s': %s", native_lib_dir.c_str (), std::strerror (errno)); continue; // No harm, keep going } break; // we're done @@ -139,7 +136,13 @@ void Host::scan_filesystem_for_assemblies_and_libraries () noexcept continue; } - log_debug (LOG_ASSEMBLY, "Found assembly store in '{}/{}'"sv, native_lib_dir, Constants::assembly_store_file_name); + log_debugf ( + LOG_ASSEMBLY, + "Found assembly store in '%s/%.*s'", + native_lib_dir.c_str (), + static_cast(Constants::assembly_store_file_name.length ()), + Constants::assembly_store_file_name.data () + ); std::string store_path = native_lib_dir; store_path.append ("/"sv); @@ -154,7 +157,7 @@ void Host::scan_filesystem_for_assemblies_and_libraries () noexcept void Host::gather_assemblies_and_libraries ([[maybe_unused]] jstring_array_wrapper& runtimeApks, [[maybe_unused]] bool have_split_apks) { if (!application_config.have_assembly_store) { - log_debug (LOG_ASSEMBLY, "No assembly store configured; skipping assembly store discovery"sv); + log_debugf (LOG_ASSEMBLY, "No assembly store configured; skipping assembly store discovery"); return; } @@ -176,22 +179,29 @@ void Host::map_assembly_store_via_dlopen (const char *store_path) noexcept // the global lookup scope (RTLD_GLOBAL would just add linker bookkeeping). void *handle = ::dlopen (store_path, RTLD_NOW | RTLD_LOCAL); if (handle == nullptr) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ("Unable to dlopen() assembly store '{}': {}"sv, optional_string (store_path), optional_string (::dlerror ())) + std::source_location::current (), + "Unable to dlopen() assembly store '%s': %s", + optional_string (store_path), + optional_string (::dlerror ()) ); } // NOTE: intentionally not calling dlclose() - we keep the store mapped for the lifetime of the app. void *payload = ::dlsym (handle, DLOPEN_ASSEMBLY_STORE_SYMBOL.data ()); if (payload == nullptr) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ("Assembly store '{}' does not export the '{}' symbol"sv, optional_string (store_path), DLOPEN_ASSEMBLY_STORE_SYMBOL) + std::source_location::current (), + "Assembly store '%s' does not export the '%.*s' symbol", + optional_string (store_path), + static_cast(DLOPEN_ASSEMBLY_STORE_SYMBOL.length ()), + DLOPEN_ASSEMBLY_STORE_SYMBOL.data () ); } - log_debug (LOG_ASSEMBLY, "Assembly store payload via dynamic symbol: {:p} ({})"sv, payload, optional_string (store_path)); + log_debugf (LOG_ASSEMBLY, "Assembly store payload via dynamic symbol: %p (%s)", payload, optional_string (store_path)); AssemblyStore::configure_from_payload (payload, [store_path]() -> std::string { return std::string { store_path }; }); found_assembly_store = true; } @@ -210,25 +220,32 @@ auto Host::create_delegate ( method_name.data (), &delegate ); - log_debug (LOG_ASSEMBLY, - "{}@{}.{} delegate creation result == {:x}; delegate == {:p}"sv, - assembly_name, - type_name, - method_name, - static_cast(hr), - delegate + log_debugf ( + LOG_ASSEMBLY, + "%.*s@%.*s.%.*s delegate creation result == %x; delegate == %p", + static_cast(assembly_name.length ()), + assembly_name.data (), + static_cast(type_name.length ()), + type_name.data (), + static_cast(method_name.length ()), + method_name.data (), + static_cast(hr), + delegate ); // TODO: make S_OK & friends known to us if (hr != 0 /* S_OK */) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_DEFAULT, - std::format ( - "Failed to create delegate for {}.{}.{} (result == {:x})"sv, - assembly_name, - type_name, - method_name, - hr) + std::source_location::current (), + "Failed to create delegate for %.*s.%.*s.%.*s (result == %x)", + static_cast(assembly_name.length ()), + assembly_name.data (), + static_cast(type_name.length ()), + type_name.data (), + static_cast(method_name.length ()), + method_name.data (), + static_cast(hr) ); } @@ -243,16 +260,15 @@ void Host::preload_jni_libraries () noexcept return; } - log_debug (LOG_ASSEMBLY, "DSO jni preloads index stride == {}", dso_jni_preloads_idx_stride); + log_debugf (LOG_ASSEMBLY, "DSO jni preloads index stride == %u", dso_jni_preloads_idx_stride); if ((dso_jni_preloads_idx_count % dso_jni_preloads_idx_stride) != 0) [[unlikely]] { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "DSO preload index is invalid, size ({}) is not a multiple of {}"sv, - dso_jni_preloads_idx_count, - dso_jni_preloads_idx_stride - ) + std::source_location::current (), + "DSO preload index is invalid, size (%u) is not a multiple of %u", + dso_jni_preloads_idx_count, + dso_jni_preloads_idx_stride ); } @@ -261,10 +277,11 @@ void Host::preload_jni_libraries () noexcept DSOCacheEntry &entry = dso_cache[entry_index]; const std::string_view dso_name = MonodroidDl::get_dso_name (&entry); - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Preloading JNI shared library: {} (entry's index: {}; name hash: {:x})", - dso_name, + "Preloading JNI shared library: %.*s (entry's index: %zu; name hash: %" PRIx32 ")", + static_cast(dso_name.length ()), + dso_name.data (), entry_index, entry.hash ); @@ -277,11 +294,12 @@ void Host::preload_jni_libraries () noexcept DSOCacheEntry &entry_alias = dso_cache[entry_alias_index]; const std::string_view entry_alias_name = MonodroidDl::get_dso_name (&entry); - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Putting JNI library handle in alias entry at index {}: {}", + "Putting JNI library handle in alias entry at index %zu: %.*s", entry_alias_index, - entry_alias_name + static_cast(entry_alias_name.length ()), + entry_alias_name.data () ); entry_alias.handle = handle; } @@ -421,12 +439,11 @@ void Host::Java_mono_android_Runtime_initInternal ( // TODO: make S_OK & friends known to us if (hr != 0 /* S_OK */) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_DEFAULT, - std::format ( - "Failed to initialize CoreCLR. Error code: {:x}"sv, - static_cast(hr) - ) + std::source_location::current (), + "Failed to initialize CoreCLR. Error code: %x", + static_cast(hr) ); } @@ -471,7 +488,7 @@ void Host::Java_mono_android_Runtime_initInternal ( init.grefIGCUserPeer = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer"sv, true); init.grefGCUserPeerable = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "net_dot_jni_GCUserPeerable"sv, true); - log_info (LOG_GC, "GREF GC Threshold: {}"sv, init.grefGcThreshold); + log_infof (LOG_GC, "GREF GC Threshold: %d", init.grefGcThreshold); OSBridge::initialize_on_runtime_init (env, runtimeClass); GCBridge::initialize_on_runtime_init (env, runtimeClass); @@ -480,7 +497,12 @@ void Host::Java_mono_android_Runtime_initInternal ( internal_timing.start_event (TimingEventKind::NativeToManagedTransition); } - log_debug (LOG_ASSEMBLY, "Creating UCO delegate to {}.Initialize"sv, Constants::JNIENVINIT_FULL_TYPE_NAME); + log_debugf ( + LOG_ASSEMBLY, + "Creating UCO delegate to %.*s.Initialize", + static_cast(Constants::JNIENVINIT_FULL_TYPE_NAME.length ()), + Constants::JNIENVINIT_FULL_TYPE_NAME.data () + ); void *delegate = nullptr; delegate = FastTiming::time_call ("create_delegate for Initialize"sv, create_delegate, Constants::MONO_ANDROID_ASSEMBLY_NAME, Constants::JNIENVINIT_FULL_TYPE_NAME, "Initialize"sv); auto initialize = reinterpret_cast (delegate); @@ -495,7 +517,7 @@ void Host::Java_mono_android_Runtime_initInternal ( } ); - log_debug (LOG_DEFAULT, "Calling into managed runtime init"sv); + log_debugf (LOG_DEFAULT, "Calling into managed runtime init"); FastTiming::time_call ("JNIEnv.Initialize UCO"sv, initialize, &init); // RegisterJniNatives and PropagateUncaughtException are returned from Initialize @@ -527,7 +549,7 @@ void Host::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, dynamic_local_string managed_type_name; const char *mt_ptr = env->GetStringUTFChars (managedType, nullptr); managed_type_name.assign (mt_ptr, strlen (mt_ptr)); - log_debug (LOG_ASSEMBLY, "Registering type: '{}'"sv, managed_type_name.get ()); + log_debugf (LOG_ASSEMBLY, "Registering type: '%s'", managed_type_name.get ()); env->ReleaseStringUTFChars (managedType, mt_ptr); // TODO: must attach thread to the runtime here @@ -573,7 +595,7 @@ auto HostCommon::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) n void Host::propagate_uncaught_exception (JNIEnv *env, jobject javaThread, jthrowable javaException) noexcept { if (jnienv_propagate_uncaught_exception == nullptr) { - log_warn (LOG_DEFAULT, "propagate_uncaught_exception called before JNIEnvInit.PropagateUncaughtException was initialized"sv); + log_warnf (LOG_DEFAULT, "propagate_uncaught_exception called before JNIEnvInit.PropagateUncaughtException was initialized"); return; } diff --git a/src/native/clr/host/internal-pinvokes-clr.cc b/src/native/clr/host/internal-pinvokes-clr.cc index 844f9b748f0..4e5f3495d10 100644 --- a/src/native/clr/host/internal-pinvokes-clr.cc +++ b/src/native/clr/host/internal-pinvokes-clr.cc @@ -6,6 +6,7 @@ #include #include #include +#include using namespace xamarin::android; diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 71748a13410..c45d152bbad 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -75,7 +76,14 @@ namespace { [[gnu::always_inline, gnu::flatten]] auto TypeMapper::find_index_by_name (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> ssize_t { - log_debug (LOG_ASSEMBLY, "typemap: map {} -> {} uses strings", from_name, to_name); + log_debugf ( + LOG_ASSEMBLY, + "typemap: map %.*s -> %.*s uses strings", + static_cast(from_name.length ()), + from_name.data (), + static_cast(to_name.length ()), + to_name.data () + ); auto equal = [](TypeMapEntry const& entry, const char *key, const char (&name_map)[]) -> bool { if (entry.from == std::numeric_limits::max ()) [[unlikely]] { @@ -101,7 +109,14 @@ auto TypeMapper::find_index_by_name (const char *typeName, const TypeMapEntry *m [[gnu::always_inline, gnu::flatten]] auto TypeMapper::find_index_by_hash (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> ssize_t { - log_debug (LOG_ASSEMBLY, "typemap: map {} -> {} uses hashes"sv, from_name, to_name); + log_debugf ( + LOG_ASSEMBLY, + "typemap: map %.*s -> %.*s uses hashes", + static_cast(from_name.length ()), + from_name.data (), + static_cast(to_name.length ()), + to_name.data () + ); size_t type_name_length = strlen (typeName); hash_t type_name_hash = crc32_hash (typeName, type_name_length); @@ -131,19 +146,29 @@ auto TypeMapper::find_index_by_hash (const char *typeName, const TypeMapEntry *m auto TypeMapper::index_to_name (ssize_t idx, const char* typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) -> const char* { if (idx < 0) [[unlikely]] { - log_debug (LOG_ASSEMBLY, "typemap: unable to map from {} type '{}' to {} type"sv, from_name, typeName, to_name); + log_debugf ( + LOG_ASSEMBLY, + "typemap: unable to map from %.*s type '%s' to %.*s type", + static_cast(from_name.length ()), + from_name.data (), + optional_string (typeName), + static_cast(to_name.length ()), + to_name.data () + ); return nullptr; } TypeMapEntry const& entry = map[idx]; const char *mapped_name = &name_map[entry.to]; - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "typemap: {} type '{}' maps to {} type '{}'"sv, - from_name, + "typemap: %.*s type '%s' maps to %.*s type '%s'", + static_cast(from_name.length ()), + from_name.data (), optional_string (typeName), - to_name, + static_cast(to_name.length ()), + to_name.data (), optional_string (mapped_name) ); return mapped_name; @@ -217,14 +242,14 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m const TypeMapModule *match = find_module_entry (mvid, managed_to_java_map, managed_to_java_map_module_count); if (match == nullptr) { if (mvid == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); + log_warnf (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"); } else { - log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found."sv, MonoGuidString (mvid).c_str ()); + log_infof (LOG_ASSEMBLY, "typemap: module matching MVID [%s] not found.", MonoGuidString (mvid).c_str ()); } return nullptr; } - log_debug (LOG_ASSEMBLY, "typemap: found module matching MVID [{}]"sv, MonoGuidString (mvid).c_str ()); + log_debugf (LOG_ASSEMBLY, "typemap: found module matching MVID [%s]", MonoGuidString (mvid).c_str ()); size_t type_name_length = strlen (typeName); hash_t name_hash = crc32_hash (typeName, type_name_length); @@ -234,9 +259,9 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m const TypeMapModuleEntry *entry = find_managed_to_java_map_entry (name_hash, typeName, type_name_length, map, match->entry_count); if (entry == nullptr) [[unlikely]] { if (match->duplicate_count > 0 && match->duplicate_map_index < std::numeric_limitsduplicate_map_index)>::max ()) { - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "typemap: searching module [{}] duplicate map for type '{}' (hash {:x})"sv, + "typemap: searching module [%s] duplicate map for type '%s' (hash %" PRIx32 ")", MonoGuidString (mvid).c_str (), optional_string (typeName), name_hash @@ -247,26 +272,28 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m } if (entry == nullptr) { - log_warn ( + log_warnf ( LOG_ASSEMBLY, - "typemap: managed type '{}' (hash {:x}) not found in module [{}] ({})."sv, + "typemap: managed type '%s' (hash %" PRIx32 ") not found in module [%s] (%.*s).", optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length) + static_cast(match->assembly_name_length), + &managed_assembly_names[match->assembly_name_index] ); return nullptr; } } if (entry->java_map_index >= java_type_count) [[unlikely]] { - log_warn ( + log_warnf ( LOG_ASSEMBLY, - "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) has invalid Java type index {}"sv, + "typemap: managed type '%s' (hash %" PRIx32 ") in module [%s] (%.*s) has invalid Java type index %" PRIu32, optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), + static_cast(match->assembly_name_length), + &managed_assembly_names[match->assembly_name_index], entry->java_map_index ); return nullptr; @@ -274,13 +301,14 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m TypeMapJava const& java_entry = java_to_managed_map[entry->java_map_index]; if (java_entry.java_name_index >= java_type_names_size) [[unlikely]] { - log_warn ( + log_warnf ( LOG_ASSEMBLY, - "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})"sv, + "typemap: managed type '%s' (hash %" PRIx32 ") in module [%s] (%.*s) points to invalid Java type at index %" PRIu32 " (invalid type name index %" PRIu32 ")", optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), + static_cast(match->assembly_name_length), + &managed_assembly_names[match->assembly_name_index], entry->java_map_index, java_entry.java_name_index ); @@ -290,16 +318,17 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m const char *ret = &java_type_names[java_entry.java_name_index]; if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index {}"sv, entry->java_map_index); + log_warnf (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index %" PRIu32, entry->java_map_index); } - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) corresponds to Java type '{}'"sv, + "typemap: managed type '%s' (hash %" PRIx32 ") in module [%s] (%.*s) corresponds to Java type '%s'", optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), + static_cast(match->assembly_name_length), + &managed_assembly_names[match->assembly_name_index], ret ); @@ -314,13 +343,13 @@ auto TypeMapper::managed_to_java (const char *typeName, const uint8_t *mvid) noe auto TypeMapper::managed_to_java (const char *typeName, const char *assemblyFullName) noexcept -> const char* #endif { - log_debug (LOG_ASSEMBLY, "managed_to_java: looking up type '{}'"sv, optional_string (typeName)); + log_debugf (LOG_ASSEMBLY, "managed_to_java: looking up type '%s'", optional_string (typeName)); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::ManagedToJava); } if (typeName == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: type name not specified in typemap_managed_to_java"sv); + log_warnf (LOG_ASSEMBLY, "typemap: type name not specified in typemap_managed_to_java"); return nullptr; } @@ -346,7 +375,7 @@ auto TypeMapper::managed_to_java (const char *typeName, const char *assemblyFull auto TypeMapper::java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { if (assembly_name == nullptr || managed_type_token_id == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Managed land called java-to-managed mapping function with invalid pointers"sv); + log_warnf (LOG_ASSEMBLY, "Managed land called java-to-managed mapping function with invalid pointers"); return false; } @@ -366,12 +395,12 @@ auto TypeMapper::java_to_managed_debug (const char *java_type_name, char const** *assembly_name = &type_map_assembly_names[type_info.assembly_name_index]; *managed_type_token_id = type_info.managed_type_token_id; - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Mapped Java type '{}' to managed type '{}' in assembly '{}' and with token '{:x}'"sv, + "Mapped Java type '%s' to managed type '%s' in assembly '%s' and with token '%" PRIx32 "'", optional_string (java_type_name), name, - *assembly_name, + optional_string (*assembly_name), *managed_type_token_id ); @@ -404,30 +433,15 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const { if (java_type_name == nullptr || assembly_name == nullptr || managed_type_token_id == nullptr) [[unlikely]] { if (java_type_name == nullptr) { - log_warn ( - LOG_ASSEMBLY, - "typemap: required parameter `{}` not passed to {}"sv, - "java_type_name"sv, - __PRETTY_FUNCTION__ - ); + log_warnf (LOG_ASSEMBLY, "typemap: required parameter `%s` not passed to %s", "java_type_name", __PRETTY_FUNCTION__); } if (assembly_name == nullptr) { - log_warn ( - LOG_ASSEMBLY, - "typemap: required parameter `{}` not passed to {}"sv, - "assembly_name"sv, - __PRETTY_FUNCTION__ - ); + log_warnf (LOG_ASSEMBLY, "typemap: required parameter `%s` not passed to %s", "assembly_name", __PRETTY_FUNCTION__); } if (managed_type_token_id == nullptr) { - log_warn ( - LOG_ASSEMBLY, - "typemap: required parameter `{}` not passed to {}"sv, - "managed_type_token_id"sv, - __PRETTY_FUNCTION__ - ); + log_warnf (LOG_ASSEMBLY, "typemap: required parameter `%s` not passed to %s", "managed_type_token_id", __PRETTY_FUNCTION__); } return false; @@ -437,9 +451,9 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const hash_t name_hash = crc32_hash (java_type_name, java_type_name_length); TypeMapJava const* java_entry = find_java_to_managed_entry (name_hash, java_type_name, java_type_name_length); if (java_entry == nullptr) { - log_info ( + log_infof ( LOG_ASSEMBLY, - "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})"sv, + "typemap: unable to find mapping to a managed type from Java type '%s' (hash %" PRIx32 ")", optional_string (java_type_name), name_hash ); @@ -451,13 +465,15 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const *assembly_name = &managed_assembly_names[module.assembly_name_index]; *managed_type_token_id = java_entry->managed_type_token_id; - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Java type '{}' corresponds to managed type '{}' (token 0x{:x} in assembly '{}')"sv, + "Java type '%s' corresponds to managed type '%.*s' (token 0x%" PRIx32 " in assembly '%.*s')", optional_string (java_type_name), - std::string_view (&managed_type_names[java_entry->managed_type_name_index], java_entry->managed_type_name_length), + static_cast(java_entry->managed_type_name_length), + &managed_type_names[java_entry->managed_type_name_index], *managed_type_token_id, - std::string_view (&managed_assembly_names[module.assembly_name_index], module.assembly_name_length) + static_cast(module.assembly_name_length), + &managed_assembly_names[module.assembly_name_index] ); return true; @@ -467,13 +483,13 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const [[gnu::flatten]] auto TypeMapper::java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { - log_debug (LOG_ASSEMBLY, "java_to_managed: looking up type '{}'"sv, optional_string (java_type_name)); + log_debugf (LOG_ASSEMBLY, "java_to_managed: looking up type '%s'", optional_string (java_type_name)); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::JavaToManaged); } if (java_type_name == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: type name not specified in typemap_java_to_managed"sv); + log_warnf (LOG_ASSEMBLY, "typemap: type name not specified in typemap_java_to_managed"); return false; } diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 79c3c8fe6fa..1b6eafb68c5 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -8,13 +8,12 @@ #include "host-common.hh" #include -#if !defined (XA_HOST_NATIVEAOT) -#include -#endif #include "../shared/log_types.hh" #include "managed-interface.hh" namespace xamarin::android { + class Timing; + class Host : public HostCommon { public: @@ -25,12 +24,10 @@ namespace xamarin::android { static void Java_mono_android_Runtime_registerNatives (JNIEnv *env, jclass nativeClass) noexcept; static void propagate_uncaught_exception (JNIEnv *env, jobject javaThread, jthrowable javaException) noexcept; -#if !defined (XA_HOST_NATIVEAOT) static auto get_timing () -> std::shared_ptr { return _timing; } -#endif static auto get_java_class_TimeZone () noexcept -> jclass { @@ -58,9 +55,7 @@ namespace xamarin::android { private: static inline void *clr_host = nullptr; static inline unsigned int domain_id = 0; -#if !defined (XA_HOST_NATIVEAOT) - static inline std::shared_ptr _timing{}; -#endif + static std::shared_ptr _timing; static inline bool found_assembly_store = false; static inline jnienv_register_jni_natives_fn jnienv_register_jni_natives = nullptr; static inline jnienv_propagate_uncaught_exception_fn jnienv_propagate_uncaught_exception = nullptr; diff --git a/src/native/clr/include/host/pinvoke-override-impl.hh b/src/native/clr/include/host/pinvoke-override-impl.hh index cb784e0cec2..f5b9b31a92b 100644 --- a/src/native/clr/include/host/pinvoke-override-impl.hh +++ b/src/native/clr/include/host/pinvoke-override-impl.hh @@ -26,7 +26,7 @@ namespace xamarin::android { short_library_name.append (Constants::dso_suffix); } - log_debug (LOG_ASSEMBLY, "Modified p/invoke library name to '{}'", short_library_name.get ()); + log_debugf (LOG_ASSEMBLY, "Modified p/invoke library name to '%s'", short_library_name.get ()); lib_handle = MonodroidDl::monodroid_dlopen (short_library_name.get (), microsoft::java_interop::JAVA_INTEROP_LIB_LOAD_LOCALLY); } @@ -35,13 +35,27 @@ namespace xamarin::android { } if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name); + log_warnf ( + LOG_ASSEMBLY, + "Shared library '%.*s' not loaded, p/invoke '%.*s' may fail", + static_cast(library_name.length ()), + library_name.data (), + static_cast(symbol_name.length ()), + symbol_name.data () + ); return nullptr; } void *entry_handle = MonodroidDl::monodroid_dlsym (lib_handle, symbol_name); if (entry_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name); + log_warnf ( + LOG_ASSEMBLY, + "Symbol '%.*s' not found in shared library '%.*s', p/invoke may fail", + static_cast(symbol_name.length ()), + symbol_name.data (), + static_cast(library_name.length ()), + library_name.data () + ); return nullptr; } diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index 3b4c0dedfb7..388b3e4db46 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -117,7 +117,7 @@ namespace xamarin::android { } } - log_debug (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); + log_debugf (LOG_DEFAULT, "Creating public update directory: `%s`", override_dir.c_str ()); Util::create_public_directory (override_dir); } #endif diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index 3913cfa2a0d..8be1634f49d 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -6,13 +6,10 @@ #include #include #include "logger.hh" -#if defined (XA_HOST_NATIVEAOT) + namespace xamarin::android { struct managed_timing_sequence; } -#else -#include -#endif extern "C" { int _monodroid_gref_get () noexcept; diff --git a/src/native/clr/include/runtime-base/monodroid-dl.hh b/src/native/clr/include/runtime-base/monodroid-dl.hh index 765e5746087..32c1264d71e 100644 --- a/src/native/clr/include/runtime-base/monodroid-dl.hh +++ b/src/native/clr/include/runtime-base/monodroid-dl.hh @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -118,7 +119,7 @@ namespace xamarin::android [[gnu::always_inline, gnu::flatten]] static auto find_dso_cache_entry (std::string_view const& name, hash_t hash) noexcept -> DSOCacheEntry* { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); + log_debugf (LOG_ASSEMBLY, "Looking for hash %" PRIx32 " in DSO cache", hash); auto less_than = [](DSOCacheEntry const& entry, hash_t key) -> bool { return entry.hash < key; }; size_t idx = Search::lower_bound (hash, dso_cache, application_config.number_of_dso_cache_entries); @@ -147,23 +148,40 @@ namespace xamarin::android static auto monodroid_dlopen (DSOCacheEntry *dso, std::string_view const& name, int flags) noexcept -> void* { - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, get_dso_name (dso)); + std::string_view dso_name = get_dso_name (dso); + log_debugf ( + LOG_ASSEMBLY, + "monodroid_dlopen: hash match %sfound, DSO name is '%.*s'", + dso == nullptr ? "not " : "", + static_cast(dso_name.length ()), + dso_name.data () + ); if (dso == nullptr) { // DSO not known at build time, try to load it. Since we don't know whether or not the library uses // JNI, we're going to assume it does and thus use System.loadLibrary eventually. return DsoLoader::load (name, flags, true /* is_jni */); } else if (dso->handle != nullptr) { - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: library {} already loaded, returning handle {:p}", name, dso->handle); + log_debugf ( + LOG_ASSEMBLY, + "monodroid_dlopen: library %.*s already loaded, returning handle %p", + static_cast(name.length ()), + name.data (), + dso->handle + ); return dso->handle; } if (dso->ignore) { - log_info (LOG_ASSEMBLY, "Request to load '{}' ignored, it is known not to exist", get_dso_name (dso)); + log_infof ( + LOG_ASSEMBLY, + "Request to load '%.*s' ignored, it is known not to exist", + static_cast(dso_name.length ()), + dso_name.data () + ); return nullptr; } - std::string_view dso_name = get_dso_name (dso); StartupAwareLock lock (dso_handle_write_lock); dso->handle = AndroidSystem::load_dso_from_any_directories (dso_name, flags, dso->is_jni_library); @@ -178,12 +196,18 @@ namespace xamarin::android static auto monodroid_dlopen (std::string_view const& name, int flags) noexcept -> void* { if (name.empty ()) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "monodroid_dlopen got a null name. This is not supported in NET+"sv); + log_warnf (LOG_ASSEMBLY, "monodroid_dlopen got a null name. This is not supported in NET+"); return nullptr; } hash_t name_hash = crc32_hash (name); - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash); + log_debugf ( + LOG_ASSEMBLY, + "monodroid_dlopen: hash for name '%.*s' is %" PRIx32, + static_cast(name.length ()), + name.data (), + name_hash + ); DSOCacheEntry *dso = find_dso_cache_entry (name, name_hash); return monodroid_dlopen (dso, name, flags); @@ -196,10 +220,11 @@ namespace xamarin::android void *s = microsoft::java_interop::java_interop_lib_symbol (handle, name.data (), &e); if (s == nullptr) { - log_error ( + log_errorf ( LOG_ASSEMBLY, - "Could not find symbol '{}': {}", - name, + "Could not find symbol '%.*s': %s", + static_cast(name.length ()), + name.data (), optional_string (e) ); } diff --git a/src/native/clr/include/shared/log_types.hh b/src/native/clr/include/shared/log_types.hh index 24eaca7efd9..a4e902e78d5 100644 --- a/src/native/clr/include/shared/log_types.hh +++ b/src/native/clr/include/shared/log_types.hh @@ -3,11 +3,6 @@ #include #include -#if !defined (XA_HOST_NATIVEAOT) -#include -#include -#endif - #include namespace xamarin::android { @@ -18,109 +13,4 @@ namespace xamarin::android { } } -#if !defined (XA_HOST_NATIVEAOT) -// We redeclare macros here -#if defined(log_debug) -#undef log_debug -#endif - -#if defined(log_info) -#undef log_info -#endif - -#define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ - do { \ - if ((log_categories & ((_category_))) != 0) { \ - ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ - } \ - } while (0) - -// -// For std::format spec, see https://en.cppreference.com/w/cpp/utility/format/spec -// - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_debug(_category_, _fmt_, ...) DO_LOG_FMT (debug, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_info(_category_, _fmt_, ...) DO_LOG_FMT (info, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_warn(_category_, _fmt_, ...) log_warn_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_error(_category_, _fmt_, ...) log_error_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style -#define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) - -namespace xamarin::android { - template [[gnu::always_inline]] - static inline constexpr void log_write_fmt (LogCategories category, LogLevel level, std::format_string fmt, Args&& ...args) - { - log_write (category, level, std::format (fmt, std::forward(args)...).c_str ()); - } -} - -template [[gnu::always_inline]] -static inline constexpr void log_debug_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) -{ - log_write (category, xamarin::android::LogLevel::Debug, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Debug, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_info_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) -{ - log_write (category, xamarin::android::LogLevel::Info, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Info, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_warn_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Warn, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Warn, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Error, message.data ()); -} - -template [[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept -{ - log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); -} - -[[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept -{ - log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); -} -#endif - extern unsigned int log_categories; diff --git a/src/native/clr/pinvoke-override/precompiled.cc b/src/native/clr/pinvoke-override/precompiled.cc index 2b47211b410..b0e8aaba5ad 100644 --- a/src/native/clr/pinvoke-override/precompiled.cc +++ b/src/native/clr/pinvoke-override/precompiled.cc @@ -1,6 +1,5 @@ #define PINVOKE_OVERRIDE_INLINE [[gnu::always_inline]] -#include #include #include @@ -15,13 +14,14 @@ namespace { [[noreturn]] void abort_missing_internal_symbol (std::string_view const& library_name, std::string_view const& entrypoint_name) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Internal p/invoke symbol '{}'@'{}' not found"sv, - entrypoint_name, - library_name - ) + std::source_location::current (), + "Internal p/invoke symbol '%.*s'@'%.*s' not found", + static_cast(entrypoint_name.length ()), + entrypoint_name.data (), + static_cast(library_name.length ()), + library_name.data () ); } @@ -167,8 +167,13 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept { - log_debug (LOG_ASSEMBLY, "[precompiled] clr_pinvoke_override (\"{}\", \"{}\")"sv, library_name, entry_point_name); + log_debugf ( + LOG_ASSEMBLY, + "[precompiled] clr_pinvoke_override (\"%s\", \"%s\")", + library_name == nullptr ? "" : library_name, + entry_point_name == nullptr ? "" : entry_point_name + ); void *ret = PinvokeOverride::monodroid_pinvoke_override (library_name, entry_point_name); - log_debug (LOG_DEFAULT, "[precompiled] p/invoke {}found"sv, ret == nullptr ? "not"sv : ""sv); + log_debugf (LOG_DEFAULT, "[precompiled] p/invoke %sfound", ret == nullptr ? "not " : ""); return ret; } diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index aee00900d55..2f27300d7b1 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -24,7 +25,7 @@ void AndroidSystem::add_system_property (const char *name, const char *value) noexcept { if (name == nullptr || *name == '\0') { - log_warn (LOG_DEFAULT, "Attempt to add a bundled system property without a valid name"); + log_warnf (LOG_DEFAULT, "Attempt to add a bundled system property without a valid name"); return; } @@ -49,7 +50,7 @@ AndroidSystem::setup_environment (const char *name, const char *value) noexcept if (isupper (name [0]) || name [0] == '_') { if (setenv (name, v, 1) < 0) { - log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); + log_warnf (LOG_DEFAULT, "(Debug) Failed to set environment variable: %s", strerror (errno)); } return; } @@ -64,13 +65,13 @@ AndroidSystem::setup_environment_from_override_file (dynamic_local_string::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: name width has invalid format", path.get ()); + log_warnf (LOG_DEFAULT, "Malformed header of the environment override file %s: name width has invalid format", path.get ()); return; } unsigned long value_width = strtoul (buf.get () + 11, &endptr, 16); if ((value_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: value width has invalid format", path.get ()); + log_warnf (LOG_DEFAULT, "Malformed header of the environment override file %s: value width has invalid format", path.get ()); return; } uint64_t data_width = name_width + value_width; if (data_width > file_size - Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path.get ()); + log_warnf (LOG_DEFAULT, "Malformed environment override file %s: invalid data size", path.get ()); return; } @@ -136,11 +137,11 @@ AndroidSystem::setup_environment_from_override_file (dynamic_local_string 0 && data_size >= data_width) { if (*name == '\0') { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path.get (), name - buf.get ()); + log_warnf (LOG_DEFAULT, "Malformed environment override file %s: name at offset %td is empty", path.get (), name - buf.get ()); return; } - log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path.get (), name, name + name_width); + log_debugf (LOG_DEFAULT, "Setting environment variable from the override file %s: '%s' = '%s'", path.get (), name, name + name_width); setup_environment (name, name + name_width); name += data_width; data_size -= data_width; @@ -161,7 +162,7 @@ AndroidSystem::add_apk_libdir (std::string_view const& apk, size_t &index, std:: dir.append (lib_prefix); dir.append (abi); app_lib_directories [index] = dir; - log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: {}", dir); + log_debugf (LOG_ASSEMBLY, "Added APK DSO lookup location: %s", dir.c_str ()); index++; } @@ -196,7 +197,7 @@ AndroidSystem::setup_apk_directories (unsigned short running_on_cpu, jstring_arr add_apk_libdir (base_apk, number_of_added_directories, abi); } - log_debug (LOG_DEFAULT, "Number of added dirs: {}", number_of_added_directories); + log_debugf (LOG_DEFAULT, "Number of added dirs: %zu", number_of_added_directories); if (app_lib_directories.size () == number_of_added_directories) [[likely]] { return; } @@ -209,15 +210,15 @@ void AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks) noexcept { if (!is_embedded_dso_mode_enabled ()) { - log_debug (LOG_DEFAULT, "Setting up for DSO lookup in app data directories"sv); + log_debugf (LOG_DEFAULT, "Setting up for DSO lookup in app data directories"); app_lib_directories = std::span (single_app_lib_directory); app_lib_directories [0] = std::string (appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: {}", app_lib_directories [0]); + log_debugf (LOG_ASSEMBLY, "Added filesystem DSO lookup location: %s", app_lib_directories [0].c_str ()); return; } - log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); + log_debugf (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"); if (have_split_apks) { // If split apks are used, then we will have just a single app library directory. Don't allocate any memory // dynamically in this case @@ -237,7 +238,7 @@ void AndroidSystem::setup_environment () noexcept { if (application_config.environment_variable_count > 0) { - log_debug (LOG_DEFAULT, "Setting environment variables ({})", application_config.environment_variable_count); + log_debugf (LOG_DEFAULT, "Setting environment variables (%" PRIu32 ")", application_config.environment_variable_count); HostEnvironment::set_values ( application_config.environment_variable_count, app_environment_variables, @@ -246,7 +247,7 @@ AndroidSystem::setup_environment () noexcept } if (application_config.system_property_count > 0) { - log_debug (LOG_DEFAULT, "Setting system properties ({})", application_config.system_property_count); + log_debugf (LOG_DEFAULT, "Setting system properties (%" PRIu32 ")", application_config.system_property_count); HostEnvironment::set_values ( application_config.system_property_count, app_system_properties, @@ -255,13 +256,13 @@ AndroidSystem::setup_environment () noexcept } #if defined(DEBUG) - log_debug (LOG_DEFAULT, "Loading environment from the override directory."sv); + log_debugf (LOG_DEFAULT, "Loading environment from the override directory."); dynamic_local_string env_override_file; Util::path_combine (env_override_file, std::string_view {primary_override_dir}, Constants::OVERRIDE_ENVIRONMENT_FILE_NAME); - log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); + log_debugf (LOG_DEFAULT, "%s", env_override_file.get ()); if (Util::file_exists (env_override_file)) { - log_debug (LOG_DEFAULT, "Loading {}"sv, env_override_file.get ()); + log_debugf (LOG_DEFAULT, "Loading %s", env_override_file.get ()); setup_environment_from_override_file (env_override_file); } #endif // def DEBUG @@ -274,12 +275,12 @@ AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcep dynamic_local_string libmonodroid_path; Util::path_combine (libmonodroid_path, appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_string_view (), "libmonodroid.so"sv); - log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ()); + log_debugf (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to %s", libmonodroid_path.get ()); if (!Util::file_exists (libmonodroid_path)) { - log_debug (LOG_ASSEMBLY, "{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); + log_debugf (LOG_ASSEMBLY, "%s not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); set_embedded_dso_mode_enabled (true); } else { - log_debug (LOG_ASSEMBLY, "Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debugf (LOG_ASSEMBLY, "Native libs extracted to %s, assuming application/android:extractNativeLibs == true", appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); set_embedded_dso_mode_enabled (false); native_libraries_dir.assign (appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); } diff --git a/src/native/common/include/runtime-base/dso-loader.hh b/src/native/common/include/runtime-base/dso-loader.hh index f44947453b4..c424d0113d2 100644 --- a/src/native/common/include/runtime-base/dso-loader.hh +++ b/src/native/common/include/runtime-base/dso-loader.hh @@ -41,10 +41,10 @@ namespace xamarin::android { return load_jni (path, true /* name_is_path */); } - log_info (LOG_ASSEMBLY, "[filesystem] Trying to load shared library '{}'", path); + log_infof (LOG_ASSEMBLY, "[filesystem] Trying to load shared library '%.*s'", static_cast(path.length ()), path.data ()); if constexpr (!SkipExistsCheck) { if (!AndroidSystem::is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { - log_info (LOG_ASSEMBLY, "Shared library '{}' not found", path); + log_infof (LOG_ASSEMBLY, "Shared library '%.*s' not found", static_cast(path.length ()), path.data ()); return nullptr; } } @@ -60,7 +60,13 @@ namespace xamarin::android { return load_jni (name, true /* name_is_path */); } - log_info (LOG_ASSEMBLY, "[apk] Trying to load shared library '{}', offset in the apk == {}", name, offset); + log_infof ( + LOG_ASSEMBLY, + "[apk] Trying to load shared library '%.*s', offset in the apk == %lld", + static_cast(name.length ()), + name.data (), + static_cast(offset) + ); android_dlextinfo dli; dli.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; @@ -75,7 +81,13 @@ namespace xamarin::android { static auto log_and_return (void *handle, std::string_view const& full_name) -> void* { if (handle != nullptr) [[likely]] { - log_debug (LOG_ASSEMBLY, "Shared library {} loaded (handle {:p})", full_name, handle); + log_debugf ( + LOG_ASSEMBLY, + "Shared library %.*s loaded (handle %p)", + static_cast(full_name.length ()), + full_name.data (), + handle + ); return handle; } @@ -83,10 +95,11 @@ namespace xamarin::android { if (load_error == nullptr) { load_error = "Unknown error"; } - log_error ( + log_errorf ( LOG_ASSEMBLY, - "Could not load library '{}'. {}"sv, - full_name, + "Could not load library '%.*s'. %s", + static_cast(full_name.length ()), + full_name.data (), load_error ); @@ -95,7 +108,12 @@ namespace xamarin::android { static auto load_jni (std::string_view const& name, bool name_is_path) -> void* { - log_debug (LOG_ASSEMBLY, "Trying to load loading shared JNI library {} with System.loadLibrary", name); + log_debugf ( + LOG_ASSEMBLY, + "Trying to load loading shared JNI library %.*s with System.loadLibrary", + static_cast(name.length ()), + name.data () + ); auto get_file_name = [](std::string_view const& full_name, bool is_path) -> std::string_view { if (!is_path) { @@ -175,8 +193,16 @@ namespace xamarin::android { // way :( // We must use full name of the library, because dlopen won't accept an undecorated one without kicking up // a fuss. - log_debug (LOG_ASSEMBLY, "Attempting to get library {} handle after System.loadLibrary. Will try to load using '{}'", name, get_file_name (name, name_is_path)); - return log_and_return (dlopen (get_file_name (name, name_is_path).data (), RTLD_NOLOAD), name); + std::string_view file_name = get_file_name (name, name_is_path); + log_debugf ( + LOG_ASSEMBLY, + "Attempting to get library %.*s handle after System.loadLibrary. Will try to load using '%.*s'", + static_cast(name.length ()), + name.data (), + static_cast(file_name.length ()), + file_name.data () + ); + return log_and_return (dlopen (file_name.data (), RTLD_NOLOAD), name); } private: diff --git a/src/native/common/include/runtime-base/mainthread-dso-loader.hh b/src/native/common/include/runtime-base/mainthread-dso-loader.hh index 144ad67db81..99437c83f2b 100644 --- a/src/native/common/include/runtime-base/mainthread-dso-loader.hh +++ b/src/native/common/include/runtime-base/mainthread-dso-loader.hh @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -26,12 +25,11 @@ namespace xamarin::android { explicit MainThreadDsoLoader () noexcept { if (pipe (pipe_fds) != 0) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Failed to create a pipe for main thread DSO loader. {}"sv, - strerror (errno) - ) + std::source_location::current (), + "Failed to create a pipe for main thread DSO loader. %s", + strerror (errno) ); } @@ -74,16 +72,16 @@ namespace xamarin::android { if (!undecorated_library_name.empty ()) [[unlikely]] { Helpers::abort_application ("Main thread DSO loader object reused! DO NOT DO THAT!"sv); } - log_debug (LOG_ASSEMBLY, "Running DSO loader on thread {}, dispatching to main thread"sv, gettid ()); + log_debugf (LOG_ASSEMBLY, "Running DSO loader on thread %d, dispatching to main thread", gettid ()); undecorated_library_name = undecorated_name; load_success = false; constexpr std::array payload { 0xFF }; ssize_t nbytes = write (pipe_fds[1], payload.data (), payload.size ()); if (nbytes == -1) { - log_warn ( + log_warnf ( LOG_ASSEMBLY, - "Write failure when posting a DSO load event to main thread. {}"sv, + "Write failure when posting a DSO load event to main thread. %s", strerror (errno) ); return false; @@ -95,7 +93,12 @@ namespace xamarin::android { // We'll wait for up to 3s, it should be more than enough time for the library to load bool success = load_complete_sem.try_acquire_for (3s); if (!success) { - log_warn (LOG_ASSEMBLY, "Timeout while waiting for shared library '{}' to load."sv, full_name); + log_warnf ( + LOG_ASSEMBLY, + "Timeout while waiting for shared library '%.*s' to load.", + static_cast(full_name.length ()), + full_name.data () + ); return false; } @@ -130,15 +133,16 @@ namespace xamarin::android { }; if (self->undecorated_library_name.empty ()) { - log_warn (LOG_ASSEMBLY, "Library name not specified in main thread looper callback."sv); + log_warnf (LOG_ASSEMBLY, "Library name not specified in main thread looper callback."); return over_and_out (); } - log_debug ( + log_debugf ( LOG_ASSEMBLY, - "Looper CB called on thread {}. Will attempt to load DSO '{}'"sv, + "Looper CB called on thread %d. Will attempt to load DSO '%.*s'", gettid (), - self->undecorated_library_name + static_cast(self->undecorated_library_name.length ()), + self->undecorated_library_name.data () ); self->load_success = SystemLoadLibraryWrapper::load (main_thread_jni_env /* RuntimeEnvironment::get_jnienv () */, self->undecorated_library_name); diff --git a/src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh b/src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh index 577d6ba8e6f..21625cec219 100644 --- a/src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh +++ b/src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh @@ -32,7 +32,7 @@ namespace xamarin::android { // std::string is needed because we must pass a NUL-terminated string to Java, otherwise // strange things happen (and std::string_view is not necessarily such a string) const std::string lib_name { undecorated_lib_name }; - log_debug (LOG_ASSEMBLY, "Undecorated library name: {}", lib_name); + log_debugf (LOG_ASSEMBLY, "Undecorated library name: %s", lib_name.c_str ()); jstring java_lib_name = jni_env->NewStringUTF (lib_name.c_str ()); if (java_lib_name == nullptr) [[unlikely]] { @@ -41,10 +41,10 @@ namespace xamarin::android { } jni_env->CallStaticVoidMethod (systemKlass, System_loadLibrary, java_lib_name); if (jni_env->ExceptionCheck ()) { - log_debug (LOG_ASSEMBLY, "System.loadLibrary threw a Java exception. Will attempt to log it."); + log_debugf (LOG_ASSEMBLY, "System.loadLibrary threw a Java exception. Will attempt to log it."); jni_env->ExceptionDescribe (); jni_env->ExceptionClear (); - log_debug (LOG_ASSEMBLY, "Java exception cleared"); + log_debugf (LOG_ASSEMBLY, "Java exception cleared"); return false; } diff --git a/src/native/common/include/runtime-base/timing-internal.hh b/src/native/common/include/runtime-base/timing-internal.hh index 25fdc20b3cd..e80fa94dde2 100644 --- a/src/native/common/include/runtime-base/timing-internal.hh +++ b/src/native/common/include/runtime-base/timing-internal.hh @@ -285,7 +285,7 @@ namespace xamarin::android { } if (!index.has_value ()) [[unlikely]] { - log_warn (LOG_TIMING, "FastTiming::end_event called without prior FastTiming::start_event called"sv); + log_warnf (LOG_TIMING, "FastTiming::end_event called without prior FastTiming::start_event called"); return; } @@ -301,7 +301,7 @@ namespace xamarin::android { { auto index = pop_valid_sequence_index (); if (!index.has_value ()) [[unlikely]] { - log_warn (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"sv); + log_warnf (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"); return; } @@ -314,7 +314,7 @@ namespace xamarin::android { { auto index = pop_valid_sequence_index (); if (!index.has_value ()) [[unlikely]] { - log_warn (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"sv); + log_warnf (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"); return; } @@ -327,7 +327,7 @@ namespace xamarin::android { { auto index = pop_valid_sequence_index (); if (!index.has_value ()) [[unlikely]] { - log_warn (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"sv); + log_warnf (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"); return; } diff --git a/src/native/common/runtime-base/timing-internal.cc b/src/native/common/runtime-base/timing-internal.cc index ebf8d111893..87d53974a09 100644 --- a/src/native/common/runtime-base/timing-internal.cc +++ b/src/native/common/runtime-base/timing-internal.cc @@ -63,7 +63,7 @@ void FastTiming::parse_options (dynamic_local_property_string const& value) noex if (param.starts_with (OPT_DURATION)) { if (!param.to_integer (duration_ms, OPT_DURATION.length ())) { - log_warn (LOG_TIMING, "Failed to parse duration in milliseconds from '%s'"sv, param.start ()); + log_warnf (LOG_TIMING, "Failed to parse duration in milliseconds from '%.*s'", static_cast(param.length ()), param.start ()); duration_ms = default_duration_milliseconds; } continue; @@ -147,15 +147,16 @@ void FastTiming::dump (size_t entries, bool indent, std::function (time_ns).count (), - chrono::duration_cast (time_ns).count (), - (time_ns % 1ms).count () - ); - line_writer (s); + dynamic_local_string message; + message.append (" ") + .append (msg) + .append (": ") + .append (static_cast(chrono::duration_cast (time_ns).count ())) + .append (":") + .append (static_cast(chrono::duration_cast (time_ns).count ())) + .append ("::") + .append (static_cast((time_ns % 1ms).count ())); + line_writer (message.as_string_view ()); }; // Do not change the sequence numbers. If a measurement is removed, its sequence number must not be reused. @@ -200,16 +201,16 @@ void FastTiming::dump_to_file (size_t entries) noexcept FILE *timing_log = Util::monodroid_fopen (timing_log_path.get (), "w"); if (timing_log == nullptr) { - log_error (LOG_TIMING, "[2/2] Unable to create the performance measurements file '{}'"sv, timing_log_path.get ()); + log_errorf (LOG_TIMING, "[2/2] Unable to create the performance measurements file '%s'", timing_log_path.get ()); return; } if (!Util::set_world_accessible (fileno (timing_log))) { - log_warn (LOG_TIMING, "[2/2] Failed to make performance measurements file '{}' world-readable"sv, timing_log_path.get ()); + log_warnf (LOG_TIMING, "[2/2] Failed to make performance measurements file '%s' world-readable", timing_log_path.get ()); return; } - log_info (LOG_TIMING, "[2/2] Performance measurement results logged to file: {}"sv, timing_log_path.get ()); + log_infof (LOG_TIMING, "[2/2] Performance measurement results logged to file: %s", timing_log_path.get ()); auto line_writer = [=](std::string_view const& msg) { if (!msg.empty ()) { From 0e1fedac0ff19f883d92740e1438732d67b0c746 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 19 Aug 2026 18:04:27 +0200 Subject: [PATCH 3/4] [NativeAOT] Narrow std::format removal scope Restore all CoreCLR-only implementation changes. Give NativeAOT lightweight logging and internal-pinvoke headers through its existing include-path precedence, and update only host code compiled by both runtimes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 99f3f0fa-70d4-4920-a0e5-798643faac81 --- src/native/clr/host/assembly-store.cc | 180 ++++++++---------- src/native/clr/host/bridge-processing.cc | 10 +- src/native/clr/host/fastdev-assemblies.cc | 59 +++--- src/native/clr/host/gc-bridge.cc | 4 +- src/native/clr/host/host-shared.cc | 2 +- src/native/clr/host/host.cc | 160 +++++++--------- src/native/clr/host/internal-pinvokes-clr.cc | 1 - .../clr/host/internal-pinvokes-shared.cc | 10 +- src/native/clr/host/typemap.cc | 130 ++++++------- src/native/clr/include/host/host.hh | 5 +- .../clr/include/host/pinvoke-override-impl.hh | 20 +- .../include/runtime-base/android-system.hh | 4 +- .../include/runtime-base/internal-pinvokes.hh | 5 +- .../clr/include/runtime-base/monodroid-dl.hh | 45 +---- src/native/clr/include/shared/log_types.hh | 103 ++++++++++ .../clr/pinvoke-override/precompiled.cc | 23 +-- src/native/clr/runtime-base/android-system.cc | 49 +++-- .../common/include/runtime-base/dso-loader.hh | 46 +---- .../runtime-base/mainthread-dso-loader.hh | 32 ++-- .../system-loadlibrary-wrapper.hh | 6 +- .../include/runtime-base/timing-internal.hh | 8 +- .../common/runtime-base/timing-internal.cc | 27 ++- .../include/runtime-base/internal-pinvokes.hh | 45 +++++ .../nativeaot/include/shared/log_types.hh | 15 ++ 24 files changed, 508 insertions(+), 481 deletions(-) create mode 100644 src/native/nativeaot/include/runtime-base/internal-pinvokes.hh create mode 100644 src/native/nativeaot/include/shared/log_types.hh diff --git a/src/native/clr/host/assembly-store.cc b/src/native/clr/host/assembly-store.cc index 0397ca5182c..3b34cf87092 100644 --- a/src/native/clr/host/assembly-store.cc +++ b/src/native/clr/host/assembly-store.cc @@ -1,6 +1,3 @@ -#include -#include -#include #include #include #include @@ -119,14 +116,7 @@ namespace { void log_file_error (std::string_view operation, std::string const& path, int error) noexcept { - log_debugf ( - LOG_ASSEMBLY, - "Decompressed-assembly cache %.*s failed for '%s': %s", - static_cast(operation.length ()), - operation.data (), - path.c_str (), - std::strerror (error) - ); + log_debug (LOG_ASSEMBLY, "Decompressed-assembly cache {} failed for '{}': {}"sv, operation, path, std::strerror (error)); } auto write_cache_file (WriteRequest const& req) noexcept -> WriteResult @@ -207,7 +197,7 @@ namespace { writes_enabled = false; clear_write_queue_locked (); writer_running = false; - log_debugf (LOG_ASSEMBLY, "Disabling decompressed-assembly cache writes after a persistence failure"); + log_debug (LOG_ASSEMBLY, "Disabling decompressed-assembly cache writes after a persistence failure"sv); return nullptr; } } @@ -232,7 +222,7 @@ namespace { pthread_attr_destroy (&attributes); } if (result != 0) { - log_debugf (LOG_ASSEMBLY, "Failed to start decompressed-assembly cache writer: %s", std::strerror (result)); + log_debug (LOG_ASSEMBLY, "Failed to start decompressed-assembly cache writer: {}"sv, std::strerror (result)); return false; } @@ -334,13 +324,7 @@ namespace { store_id = assembly_store_id; cache_dir.append ("/"); - std::array store_id_hex {}; - int store_id_length = std::snprintf (store_id_hex.data (), store_id_hex.size (), "%" PRIx64, store_id); - abort_unless ( - store_id_length > 0 && static_cast(store_id_length) < store_id_hex.size (), - "Failed to format decompressed-assembly cache store ID" - ); - cache_dir.append (store_id_hex.data (), static_cast(store_id_length)); + cache_dir.append (std::format ("{:x}", store_id)); if (!ensure_directory (cache_dir)) { return; } @@ -361,10 +345,10 @@ namespace { writes_enabled = true; } - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Enabled decompressed-assembly cache at '%s'; store ID 0x%" PRIx64 "; write queue limit %zu bytes", - cache_dir.c_str (), + "Enabled decompressed-assembly cache at '{}'; store ID 0x{:x}; write queue limit {} bytes"sv, + cache_dir, store_id, MAX_QUEUED_BYTES ); @@ -417,7 +401,7 @@ namespace { footer.payload_size != expected_size || footer.payload_hash != hash_payload (static_cast(mapped), expected_size)) { munmap (mapped, map_size); - log_debugf (LOG_ASSEMBLY, "Ignoring invalid decompressed-assembly cache entry for '%.*s'", static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Ignoring invalid decompressed-assembly cache entry for '{}'"sv, name); return nullptr; } @@ -452,20 +436,18 @@ namespace { if (queue_full) { if (total > MAX_QUEUED_BYTES) { - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Skipping decompressed-assembly cache write for '%.*s': %zu bytes exceed the %zu-byte queue limit", - static_cast(name.length ()), - name.data (), + "Skipping decompressed-assembly cache write for '{}': {} bytes exceed the {}-byte queue limit"sv, + name, total, MAX_QUEUED_BYTES ); } else { - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Skipping decompressed-assembly cache write for '%.*s': %zu of %zu queue bytes are in use", - static_cast(name.length ()), - name.data (), + "Skipping decompressed-assembly cache write for '{}': {} of {} queue bytes are in use"sv, + name, bytes_queued, MAX_QUEUED_BYTES ); @@ -535,7 +517,7 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co #if defined (RELEASE) auto header = reinterpret_cast(e.image_data); if (header->magic == COMPRESSED_DATA_MAGIC) { - log_debugf (LOG_ASSEMBLY, "Resolving compressed assembly '%.*s' from the assembly store", static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Resolving compressed assembly '{}' from the assembly store"sv, name); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::AssemblyDecompression); @@ -545,11 +527,12 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co Helpers::abort_application (LOG_ASSEMBLY, "Compressed assembly found but no descriptor defined"sv); } if (header->descriptor_index >= compressed_assembly_count) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Invalid compressed assembly descriptor index %" PRIu32, - header->descriptor_index + std::format ( + "Invalid compressed assembly descriptor index {}"sv, + header->descriptor_index + ) ); } @@ -557,12 +540,13 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co assembly_data_size = e.descriptor->data_size - sizeof(CompressedAssemblyHeader); if (cad.buffer_offset >= uncompressed_assemblies_data_size) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Invalid compressed assembly buffer offset %" PRIu32 ". Must be smaller than %" PRIu32, - cad.buffer_offset, - uncompressed_assemblies_data_size + std::format ( + "Invalid compressed assembly buffer offset {}. Must be smaller than {}", + cad.buffer_offset, + uncompressed_assemblies_data_size + ) ); } @@ -571,13 +555,14 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co // that will cause the app to crash when one or the the other assembly is loaded, so it's // OK to accept that risk. The whole situation is very, very unlikely. if (cad.uncompressed_file_size > uncompressed_assemblies_data_size - cad.buffer_offset) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Invalid compressed assembly buffer size %" PRIu32 " at offset %" PRIu32 ". Must not exceed %" PRIu32, - cad.uncompressed_file_size, - cad.buffer_offset, - uncompressed_assemblies_data_size - cad.buffer_offset + std::format ( + "Invalid compressed assembly buffer size {} at offset {}. Must not exceed {}", + cad.uncompressed_file_size, + cad.buffer_offset, + uncompressed_assemblies_data_size - cad.buffer_offset + ) ); } @@ -617,17 +602,17 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co if (header->uncompressed_length != cad.uncompressed_file_size) { if (header->uncompressed_length > cad.uncompressed_file_size) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Compressed assembly '%.*s' is larger than when the application was built (expected at most %" PRIu32 ", got %" PRIu32 "). Assemblies don't grow just like that!", - static_cast(name.length ()), - name.data (), - cad.uncompressed_file_size, - header->uncompressed_length + std::format ( + "Compressed assembly '{}' is larger than when the application was built (expected at most {}, got {}). Assemblies don't grow just like that!"sv, + name, + cad.uncompressed_file_size, + header->uncompressed_length + ) ); } else { - log_debugf (LOG_ASSEMBLY, "Compressed assembly '%.*s' is smaller than when the application was built. Adjusting accordingly.", static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly."sv, name); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -638,34 +623,34 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co uint8_t *cached = asm_cache::try_load (descriptor_index, name, cad.uncompressed_file_size); if (cached != nullptr) { loaded_from_cache = true; - log_debugf (LOG_ASSEMBLY, "Loaded decompressed assembly '%.*s' from the on-device cache", static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Loaded decompressed assembly '{}' from the on-device cache"sv, name); if (asm_cache::tracking != nullptr) { asm_cache::tracking[descriptor_index] = cached; } } else { - log_debugf (LOG_ASSEMBLY, "Decompressing assembly '%.*s' from the assembly store", static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Decompressing assembly '{}' from the assembly store"sv, name); size_t ret = ZSTD_decompress (data_buffer, cad.uncompressed_file_size, data_start, assembly_data_size); if (ZSTD_isError (ret)) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Decompression of assembly %.*s failed: %s", - static_cast(name.length ()), - name.data (), - ZSTD_getErrorName (ret) + std::format ( + "Decompression of assembly {} failed: {}"sv, + name, + ZSTD_getErrorName (ret) + ) ); } if (ret != cad.uncompressed_file_size) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Decompression of assembly %.*s yielded a different size (expected %" PRIu32 ", got %zu)", - static_cast(name.length ()), - name.data (), - cad.uncompressed_file_size, - ret + std::format ( + "Decompression of assembly {} yielded a different size (expected {}, got {})"sv, + name, + cad.uncompressed_file_size, + static_cast(ret) + ) ); } @@ -689,12 +674,12 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co } else #endif // def RELEASE { - log_debugf (LOG_ASSEMBLY, "Assembly '%.*s' is not compressed in the assembly store", static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Assembly '{}' is not compressed in the assembly store"sv, name); // HACK! START // Currently, MAUI crashes when we return a pointer to read-only data, so we must copy // the assembly data to a read-write area. - log_debugf (LOG_ASSEMBLY, "Copying assembly data to an r/w memory area"); + log_debug (LOG_ASSEMBLY, "Copying assembly data to an r/w memory area"sv); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::AssemblyLoad); @@ -748,7 +733,7 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) if constexpr (Constants::is_debug_build) { // In fastdev mode we might not have any assembly store. if (assembly_store_hashes == nullptr) { - log_warnf (LOG_ASSEMBLY, "Assembly store not registered. Unable to look up assembly '%.*s'", static_cast(name.length ()), name.data ()); + log_warn (LOG_ASSEMBLY, "Assembly store not registered. Unable to look up assembly '{}'"sv, name); return nullptr; } } @@ -756,23 +741,24 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name, name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) [[unlikely]] { size = 0; - log_warnf (LOG_ASSEMBLY, "Assembly '%.*s' (hash 0x%" PRIx32 ") not found", static_cast(name.length ()), name.data (), name_hash); + log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash 0x{:x}) not found"sv, name, name_hash); return nullptr; } if (hash_entry->ignore != 0) { size = 0; - log_debugf (LOG_ASSEMBLY, "Assembly '%.*s' ignored", static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Assembly '{}' ignored"sv, name); return nullptr; } if (hash_entry->descriptor_index >= assembly_store.assembly_count) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Invalid assembly descriptor index %" PRIu32 ", exceeds the maximum value of %" PRIu32, - hash_entry->descriptor_index, - assembly_store.assembly_count - 1 + std::format ( + "Invalid assembly descriptor index {}, exceeds the maximum value of {}"sv, + hash_entry->descriptor_index, + assembly_store.assembly_count - 1 + ) ); } @@ -788,9 +774,9 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) assembly_runtime_info.debug_info_data = assembly_store.data_start + store_entry.debug_data_offset; } - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Mapped: image_data == %p; debug_info_data == %p; config_data == %p; descriptor == %p; data size == %" PRIu32 "; debug data size == %" PRIu32 "; config data size == %" PRIu32 "; name == '%.*s'", + "Mapped: image_data == {:p}; debug_info_data == {:p}; config_data == {:p}; descriptor == {:p}; data size == {}; debug data size == {}; config data size == {}; name == '{}'"sv, static_cast(assembly_runtime_info.image_data), static_cast(assembly_runtime_info.debug_info_data), static_cast(assembly_runtime_info.config_data), @@ -798,8 +784,7 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) assembly_runtime_info.descriptor->data_size, assembly_runtime_info.descriptor->debug_data_size, assembly_runtime_info.descriptor->config_data_size, - static_cast(name.length ()), - name.data () + name ); } @@ -811,25 +796,26 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) void AssemblyStore::configure_from_payload (const void *payload_start, const std::function& get_full_store_path) noexcept { auto header = static_cast(payload_start); - std::string full_store_path = get_full_store_path (); if (header->magic != ASSEMBLY_STORE_MAGIC) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Assembly store '%s' is not a valid .NET for Android assembly store file", - full_store_path.c_str () + std::format ( + "Assembly store '{}' is not a valid .NET for Android assembly store file"sv, + get_full_store_path () + ) ); } if (header->version != ASSEMBLY_STORE_FORMAT_VERSION) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Assembly store '%s' uses format version %" PRIx32 ", instead of the expected %" PRIx32, - full_store_path.c_str (), - header->version, - ASSEMBLY_STORE_FORMAT_VERSION + std::format ( + "Assembly store '{}' uses format version {:x}, instead of the expected {:x}"sv, + get_full_store_path (), + header->version, + ASSEMBLY_STORE_FORMAT_VERSION + ) ); } @@ -859,5 +845,5 @@ void AssemblyStore::configure_from_payload (const void *payload_start, const std names_cursor += name_length; } - log_debugf (LOG_ASSEMBLY, "Mapped assembly store %s; content ID 0x%" PRIx64, full_store_path.c_str (), assembly_store_content_id); + log_debug (LOG_ASSEMBLY, "Mapped assembly store {}; content ID 0x{:x}"sv, get_full_store_path (), assembly_store_content_id); } diff --git a/src/native/clr/host/bridge-processing.cc b/src/native/clr/host/bridge-processing.cc index 03e1ad1fdea..ab8f43a65c7 100644 --- a/src/native/clr/host/bridge-processing.cc +++ b/src/native/clr/host/bridge-processing.cc @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include #include @@ -254,10 +254,10 @@ void BridgeProcessingShared::add_circular_references (const StronglyConnectedCom abort_unless (reference_added, [this, &prev, &next] { jclass prev_java_class = env->GetObjectClass (prev.handle); - const char *prev_class_name = Host::get_java_class_name_for_TypeManager (prev_java_class); + const char *prev_class_name = HostCommon::get_java_class_name_for_TypeManager (prev_java_class); jclass next_java_class = env->GetObjectClass (next.handle); - const char *next_class_name = Host::get_java_class_name_for_TypeManager (next_java_class); + const char *next_class_name = HostCommon::get_java_class_name_for_TypeManager (next_java_class); return detail::_format_message ( "Failed to add reference between objects in a strongly connected component: %s -> %s.", @@ -470,7 +470,7 @@ void BridgeProcessingShared::log_missing_add_references_method ([[maybe_unused]] return; } - char *class_name = Host::get_java_class_name_for_TypeManager (java_class); + char *class_name = HostCommon::get_java_class_name_for_TypeManager (java_class); log_errorf (LOG_GC, "Missing monodroidAddReferences method for object of class %s", optional_string (class_name)); free (class_name); #endif @@ -486,7 +486,7 @@ void BridgeProcessingShared::log_missing_clear_references_method ([[maybe_unused return; } - char *class_name = Host::get_java_class_name_for_TypeManager (java_class); + char *class_name = HostCommon::get_java_class_name_for_TypeManager (java_class); log_errorf (LOG_GC, "Missing monodroidClearReferences method for object of class %s", optional_string (class_name)); free (class_name); #endif diff --git a/src/native/clr/host/fastdev-assemblies.cc b/src/native/clr/host/fastdev-assemblies.cc index 248633a792c..88533da4967 100644 --- a/src/native/clr/host/fastdev-assemblies.cc +++ b/src/native/clr/host/fastdev-assemblies.cc @@ -38,7 +38,7 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si std::string const& override_dir_path = AndroidSystem::get_primary_override_dir (); if (!Util::dir_exists (override_dir_path)) [[unlikely]] { - log_debugf (LOG_ASSEMBLY, "Override directory '%s' does not exist", override_dir_path.c_str ()); + log_debug (LOG_ASSEMBLY, "Override directory '{}' does not exist"sv, override_dir_path); return nullptr; } @@ -49,53 +49,51 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si if (override_dir_fd < 0) [[likely]] { override_dir = opendir (override_dir_path.c_str ()); if (override_dir == nullptr) [[unlikely]] { - log_warnf (LOG_ASSEMBLY, "Failed to open override dir '%s'. %s", override_dir_path.c_str (), strerror (errno)); + log_warn (LOG_ASSEMBLY, "Failed to open override dir '{}'. {}"sv, override_dir_path, strerror (errno)); return nullptr; } override_dir_fd = dirfd (override_dir); } } - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Attempting to load FastDev assembly '%.*s' from override directory '%s'", - static_cast(name.length ()), - name.data (), - override_dir_path.c_str () + "Attempting to load FastDev assembly '{}' from override directory '{}'"sv, + name, + override_dir_path ); if (!Util::file_exists (override_dir_fd, name)) { - log_warnf (LOG_ASSEMBLY, "FastDev assembly '%.*s' not found.", static_cast(name.length ()), name.data ()); + log_warn (LOG_ASSEMBLY, "FastDev assembly '{}' not found."sv, name); return nullptr; } - log_debugf (LOG_ASSEMBLY, "Found FastDev assembly '%.*s'", static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Found FastDev assembly '{}'"sv, name); auto file_size = Util::get_file_size_at (override_dir_fd, name); if (!file_size) [[unlikely]] { - log_warnf (LOG_ASSEMBLY, "Unable to determine FastDev assembly '%.*s' file size", static_cast(name.length ()), name.data ()); + log_warn (LOG_ASSEMBLY, "Unable to determine FastDev assembly '{}' file size"sv, name); return nullptr; } constexpr size_t MAX_SIZE = std::numeric_limits>::max (); if (file_size.value () > MAX_SIZE) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "FastDev assembly '%.*s' size exceeds the maximum supported value of %zu", - static_cast(name.length ()), - name.data (), - MAX_SIZE + std::format ( + "FastDev assembly '{}' size exceeds the maximum supported value of {}"sv, + name, + MAX_SIZE + ) ); } size = static_cast(file_size.value ()); int asm_fd = openat (override_dir_fd, name.data (), O_RDONLY); if (asm_fd < 0) { - log_warnf ( + log_warn ( LOG_ASSEMBLY, - "Failed to open FastDev assembly '%.*s' for reading. %s", - static_cast(name.length ()), - name.data (), + "Failed to open FastDev assembly '{}' for reading. {}"sv, + name, strerror (errno) ); @@ -117,18 +115,17 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si if (nread != size) [[unlikely]] { delete[] buffer; - log_warnf ( + log_warn ( LOG_ASSEMBLY, - "Failed to read FastDev assembly '%.*s' data. %s", - static_cast(name.length ()), - name.data (), + "Failed to read FastDev assembly '{}' data. {}"sv, + name, strerror (errno) ); size = 0; return nullptr; } - log_debugf (LOG_ASSEMBLY, "Read %zd bytes of FastDev assembly '%.*s'", nread, static_cast(name.length ()), name.data ()); + log_debug (LOG_ASSEMBLY, "Read {} bytes of FastDev assembly '{}'"sv, nread, name); return reinterpret_cast(buffer); } @@ -144,7 +141,7 @@ auto FastDevAssemblies::build_tpa_list (std::string &tpa_list) noexcept -> bool DIR *dir = opendir (override_dir_path.c_str ()); if (dir == nullptr) { - log_warnf (LOG_ASSEMBLY, "FastDev: failed to open override dir '%s'. %s", override_dir_path.c_str (), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "FastDev: failed to open override dir '{}'. {}"sv, override_dir_path, std::strerror (errno)); return false; } @@ -183,13 +180,13 @@ auto FastDevAssemblies::build_tpa_list (std::string &tpa_list) noexcept -> bool } closedir (dir); - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "FastDev: built TPA list with %zu assemblies from '%s' (corelib=%s, r2r=%s)", + "FastDev: built TPA list with {} assemblies from '{}' (corelib={}, r2r={})"sv, count, - override_dir_path.c_str (), - found_corelib ? "true" : "false", - found_r2r ? "true" : "false" + override_dir_path, + found_corelib, + found_r2r ); // We can only safely hand a TPA list to CoreCLR when it contains diff --git a/src/native/clr/host/gc-bridge.cc b/src/native/clr/host/gc-bridge.cc index c40c31ba9af..2b1cfbfd40e 100644 --- a/src/native/clr/host/gc-bridge.cc +++ b/src/native/clr/host/gc-bridge.cc @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include @@ -161,7 +161,7 @@ void GCBridge::log_handle_context (JNIEnv *env, HandleContext *ctx) noexcept jobject handle = ctx->control_block->handle; jclass java_class = env->GetObjectClass (handle); if (java_class != nullptr) { - char *class_name = Host::get_java_class_name_for_TypeManager (java_class); + char *class_name = HostCommon::get_java_class_name_for_TypeManager (java_class); log_infof (LOG_GC, "gref 0x%" PRIxPTR " [%s]", reinterpret_cast (handle), optional_string (class_name)); free (class_name); env->DeleteLocalRef (java_class); diff --git a/src/native/clr/host/host-shared.cc b/src/native/clr/host/host-shared.cc index 9b6da9345b6..d1702f19b9c 100644 --- a/src/native/clr/host/host-shared.cc +++ b/src/native/clr/host/host-shared.cc @@ -1,4 +1,4 @@ -#include +#include #include using namespace xamarin::android; diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 33a2b136f15..acb571c38b4 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -30,22 +29,20 @@ #include #include #include -#include +#include #include using namespace xamarin::android; -std::shared_ptr Host::_timing{}; - void Host::clr_error_writer (const char *message) noexcept { - log_errorf (LOG_DEFAULT, "CLR error: %s", optional_string (message)); + log_error (LOG_DEFAULT, "CLR error: {}", optional_string (message)); } bool Host::clr_external_assembly_probe (const char *path, void **data_start, int64_t *size) noexcept { // TODO: `path` might be a full path, make sure it isn't - log_debugf (LOG_DEFAULT, "clr_external_assembly_probe (\"%s\"...)", optional_string (path)); + log_debug (LOG_DEFAULT, "clr_external_assembly_probe (\"{}\"...)"sv, path); if (data_start == nullptr || size == nullptr) { return false; // TODO: abort instead? } @@ -60,11 +57,11 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int internal_timing.add_more_info (name); } - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Assembly '%s' data %smapped (%p, %" PRId64 " bytes)", + "Assembly '{}' data {}mapped ({:p}, {} bytes)", optional_string (name), - data_start == nullptr ? "not " : "", + data_start == nullptr ? "not "sv : ""sv, data_start, size ); @@ -78,7 +75,11 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int return log_and_return (path, *data_start, *size); } - log_warnf (LOG_ASSEMBLY, "Assembly '%s' not found in FastDev override directory. Attempting to load from assembly store", optional_string (path)); + log_warn ( + LOG_ASSEMBLY, + "Assembly '{}' not found in FastDev override directory. Attempting to load from assembly store"sv, + optional_string (path) + ); } *data_start = AssemblyStore::open_assembly (path, *size); @@ -90,27 +91,29 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int void Host::scan_filesystem_for_assemblies_and_libraries () noexcept { std::string const& native_lib_dir = AndroidSystem::get_native_libraries_dir (); - log_debugf (LOG_ASSEMBLY, "Looking for assemblies in '%s'", native_lib_dir.c_str ()); + log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'"sv, native_lib_dir); DIR *lib_dir = opendir (native_lib_dir.c_str ()); if (lib_dir == nullptr) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Unable to open native library directory '%s'. %s", - native_lib_dir.c_str (), - std::strerror (errno) + std::format ( + "Unable to open native library directory '{}'. {}"sv, + native_lib_dir, + std::strerror (errno) + ) ); } int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Unable to obtain file descriptor for opened directory '%s'. %s", - native_lib_dir.c_str (), - std::strerror (errno) + std::format ( + "Unable to obtain file descriptor for opened directory '{}'. {}"sv, + native_lib_dir, + std::strerror (errno) + ) ); } @@ -119,7 +122,7 @@ void Host::scan_filesystem_for_assemblies_and_libraries () noexcept dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warnf (LOG_ASSEMBLY, "Failed to open a directory entry from '%s': %s", native_lib_dir.c_str (), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}"sv, native_lib_dir, std::strerror (errno)); continue; // No harm, keep going } break; // we're done @@ -136,13 +139,7 @@ void Host::scan_filesystem_for_assemblies_and_libraries () noexcept continue; } - log_debugf ( - LOG_ASSEMBLY, - "Found assembly store in '%s/%.*s'", - native_lib_dir.c_str (), - static_cast(Constants::assembly_store_file_name.length ()), - Constants::assembly_store_file_name.data () - ); + log_debug (LOG_ASSEMBLY, "Found assembly store in '{}/{}'"sv, native_lib_dir, Constants::assembly_store_file_name); std::string store_path = native_lib_dir; store_path.append ("/"sv); @@ -157,7 +154,7 @@ void Host::scan_filesystem_for_assemblies_and_libraries () noexcept void Host::gather_assemblies_and_libraries ([[maybe_unused]] jstring_array_wrapper& runtimeApks, [[maybe_unused]] bool have_split_apks) { if (!application_config.have_assembly_store) { - log_debugf (LOG_ASSEMBLY, "No assembly store configured; skipping assembly store discovery"); + log_debug (LOG_ASSEMBLY, "No assembly store configured; skipping assembly store discovery"sv); return; } @@ -179,29 +176,22 @@ void Host::map_assembly_store_via_dlopen (const char *store_path) noexcept // the global lookup scope (RTLD_GLOBAL would just add linker bookkeeping). void *handle = ::dlopen (store_path, RTLD_NOW | RTLD_LOCAL); if (handle == nullptr) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Unable to dlopen() assembly store '%s': %s", - optional_string (store_path), - optional_string (::dlerror ()) + std::format ("Unable to dlopen() assembly store '{}': {}"sv, optional_string (store_path), optional_string (::dlerror ())) ); } // NOTE: intentionally not calling dlclose() - we keep the store mapped for the lifetime of the app. void *payload = ::dlsym (handle, DLOPEN_ASSEMBLY_STORE_SYMBOL.data ()); if (payload == nullptr) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Assembly store '%s' does not export the '%.*s' symbol", - optional_string (store_path), - static_cast(DLOPEN_ASSEMBLY_STORE_SYMBOL.length ()), - DLOPEN_ASSEMBLY_STORE_SYMBOL.data () + std::format ("Assembly store '{}' does not export the '{}' symbol"sv, optional_string (store_path), DLOPEN_ASSEMBLY_STORE_SYMBOL) ); } - log_debugf (LOG_ASSEMBLY, "Assembly store payload via dynamic symbol: %p (%s)", payload, optional_string (store_path)); + log_debug (LOG_ASSEMBLY, "Assembly store payload via dynamic symbol: {:p} ({})"sv, payload, optional_string (store_path)); AssemblyStore::configure_from_payload (payload, [store_path]() -> std::string { return std::string { store_path }; }); found_assembly_store = true; } @@ -220,32 +210,25 @@ auto Host::create_delegate ( method_name.data (), &delegate ); - log_debugf ( - LOG_ASSEMBLY, - "%.*s@%.*s.%.*s delegate creation result == %x; delegate == %p", - static_cast(assembly_name.length ()), - assembly_name.data (), - static_cast(type_name.length ()), - type_name.data (), - static_cast(method_name.length ()), - method_name.data (), - static_cast(hr), - delegate + log_debug (LOG_ASSEMBLY, + "{}@{}.{} delegate creation result == {:x}; delegate == {:p}"sv, + assembly_name, + type_name, + method_name, + static_cast(hr), + delegate ); // TODO: make S_OK & friends known to us if (hr != 0 /* S_OK */) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_DEFAULT, - std::source_location::current (), - "Failed to create delegate for %.*s.%.*s.%.*s (result == %x)", - static_cast(assembly_name.length ()), - assembly_name.data (), - static_cast(type_name.length ()), - type_name.data (), - static_cast(method_name.length ()), - method_name.data (), - static_cast(hr) + std::format ( + "Failed to create delegate for {}.{}.{} (result == {:x})"sv, + assembly_name, + type_name, + method_name, + hr) ); } @@ -260,15 +243,16 @@ void Host::preload_jni_libraries () noexcept return; } - log_debugf (LOG_ASSEMBLY, "DSO jni preloads index stride == %u", dso_jni_preloads_idx_stride); + log_debug (LOG_ASSEMBLY, "DSO jni preloads index stride == {}", dso_jni_preloads_idx_stride); if ((dso_jni_preloads_idx_count % dso_jni_preloads_idx_stride) != 0) [[unlikely]] { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "DSO preload index is invalid, size (%u) is not a multiple of %u", - dso_jni_preloads_idx_count, - dso_jni_preloads_idx_stride + std::format ( + "DSO preload index is invalid, size ({}) is not a multiple of {}"sv, + dso_jni_preloads_idx_count, + dso_jni_preloads_idx_stride + ) ); } @@ -277,11 +261,10 @@ void Host::preload_jni_libraries () noexcept DSOCacheEntry &entry = dso_cache[entry_index]; const std::string_view dso_name = MonodroidDl::get_dso_name (&entry); - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Preloading JNI shared library: %.*s (entry's index: %zu; name hash: %" PRIx32 ")", - static_cast(dso_name.length ()), - dso_name.data (), + "Preloading JNI shared library: {} (entry's index: {}; name hash: {:x})", + dso_name, entry_index, entry.hash ); @@ -294,12 +277,11 @@ void Host::preload_jni_libraries () noexcept DSOCacheEntry &entry_alias = dso_cache[entry_alias_index]; const std::string_view entry_alias_name = MonodroidDl::get_dso_name (&entry); - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Putting JNI library handle in alias entry at index %zu: %.*s", + "Putting JNI library handle in alias entry at index {}: {}", entry_alias_index, - static_cast(entry_alias_name.length ()), - entry_alias_name.data () + entry_alias_name ); entry_alias.handle = handle; } @@ -439,11 +421,12 @@ void Host::Java_mono_android_Runtime_initInternal ( // TODO: make S_OK & friends known to us if (hr != 0 /* S_OK */) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_DEFAULT, - std::source_location::current (), - "Failed to initialize CoreCLR. Error code: %x", - static_cast(hr) + std::format ( + "Failed to initialize CoreCLR. Error code: {:x}"sv, + static_cast(hr) + ) ); } @@ -488,7 +471,7 @@ void Host::Java_mono_android_Runtime_initInternal ( init.grefIGCUserPeer = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_IGCUserPeer"sv, true); init.grefGCUserPeerable = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "net_dot_jni_GCUserPeerable"sv, true); - log_infof (LOG_GC, "GREF GC Threshold: %d", init.grefGcThreshold); + log_info (LOG_GC, "GREF GC Threshold: {}"sv, init.grefGcThreshold); OSBridge::initialize_on_runtime_init (env, runtimeClass); GCBridge::initialize_on_runtime_init (env, runtimeClass); @@ -497,12 +480,7 @@ void Host::Java_mono_android_Runtime_initInternal ( internal_timing.start_event (TimingEventKind::NativeToManagedTransition); } - log_debugf ( - LOG_ASSEMBLY, - "Creating UCO delegate to %.*s.Initialize", - static_cast(Constants::JNIENVINIT_FULL_TYPE_NAME.length ()), - Constants::JNIENVINIT_FULL_TYPE_NAME.data () - ); + log_debug (LOG_ASSEMBLY, "Creating UCO delegate to {}.Initialize"sv, Constants::JNIENVINIT_FULL_TYPE_NAME); void *delegate = nullptr; delegate = FastTiming::time_call ("create_delegate for Initialize"sv, create_delegate, Constants::MONO_ANDROID_ASSEMBLY_NAME, Constants::JNIENVINIT_FULL_TYPE_NAME, "Initialize"sv); auto initialize = reinterpret_cast (delegate); @@ -517,7 +495,7 @@ void Host::Java_mono_android_Runtime_initInternal ( } ); - log_debugf (LOG_DEFAULT, "Calling into managed runtime init"); + log_debug (LOG_DEFAULT, "Calling into managed runtime init"sv); FastTiming::time_call ("JNIEnv.Initialize UCO"sv, initialize, &init); // RegisterJniNatives and PropagateUncaughtException are returned from Initialize @@ -549,7 +527,7 @@ void Host::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, dynamic_local_string managed_type_name; const char *mt_ptr = env->GetStringUTFChars (managedType, nullptr); managed_type_name.assign (mt_ptr, strlen (mt_ptr)); - log_debugf (LOG_ASSEMBLY, "Registering type: '%s'", managed_type_name.get ()); + log_debug (LOG_ASSEMBLY, "Registering type: '{}'"sv, managed_type_name.get ()); env->ReleaseStringUTFChars (managedType, mt_ptr); // TODO: must attach thread to the runtime here @@ -595,7 +573,7 @@ auto HostCommon::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) n void Host::propagate_uncaught_exception (JNIEnv *env, jobject javaThread, jthrowable javaException) noexcept { if (jnienv_propagate_uncaught_exception == nullptr) { - log_warnf (LOG_DEFAULT, "propagate_uncaught_exception called before JNIEnvInit.PropagateUncaughtException was initialized"); + log_warn (LOG_DEFAULT, "propagate_uncaught_exception called before JNIEnvInit.PropagateUncaughtException was initialized"sv); return; } diff --git a/src/native/clr/host/internal-pinvokes-clr.cc b/src/native/clr/host/internal-pinvokes-clr.cc index 4e5f3495d10..844f9b748f0 100644 --- a/src/native/clr/host/internal-pinvokes-clr.cc +++ b/src/native/clr/host/internal-pinvokes-clr.cc @@ -6,7 +6,6 @@ #include #include #include -#include using namespace xamarin::android; diff --git a/src/native/clr/host/internal-pinvokes-shared.cc b/src/native/clr/host/internal-pinvokes-shared.cc index 929cdd19cff..18bffb5812e 100644 --- a/src/native/clr/host/internal-pinvokes-shared.cc +++ b/src/native/clr/host/internal-pinvokes-shared.cc @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -56,11 +56,11 @@ void monodroid_log (LogLevel level, LogCategories category, const char *message) switch (level) { case LogLevel::Verbose: case LogLevel::Debug: - log_write (category, LogLevel::Debug, message); + log_debugf (category, "%s", message); break; case LogLevel::Info: - log_write (category, LogLevel::Info, message); + log_infof (category, "%s", message); break; case LogLevel::Warn: @@ -79,14 +79,14 @@ void monodroid_log (LogLevel level, LogCategories category, const char *message) default: case LogLevel::Unknown: case LogLevel::Default: - log_write (category, LogLevel::Info, message); + log_infof (category, "%s", message); break; } } char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept { - return Host::get_java_class_name_for_TypeManager (klass); + return HostCommon::get_java_class_name_for_TypeManager (klass); } void monodroid_free (void *ptr) noexcept diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index c45d152bbad..71748a13410 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -1,5 +1,4 @@ #include -#include #include #include @@ -76,14 +75,7 @@ namespace { [[gnu::always_inline, gnu::flatten]] auto TypeMapper::find_index_by_name (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> ssize_t { - log_debugf ( - LOG_ASSEMBLY, - "typemap: map %.*s -> %.*s uses strings", - static_cast(from_name.length ()), - from_name.data (), - static_cast(to_name.length ()), - to_name.data () - ); + log_debug (LOG_ASSEMBLY, "typemap: map {} -> {} uses strings", from_name, to_name); auto equal = [](TypeMapEntry const& entry, const char *key, const char (&name_map)[]) -> bool { if (entry.from == std::numeric_limits::max ()) [[unlikely]] { @@ -109,14 +101,7 @@ auto TypeMapper::find_index_by_name (const char *typeName, const TypeMapEntry *m [[gnu::always_inline, gnu::flatten]] auto TypeMapper::find_index_by_hash (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> ssize_t { - log_debugf ( - LOG_ASSEMBLY, - "typemap: map %.*s -> %.*s uses hashes", - static_cast(from_name.length ()), - from_name.data (), - static_cast(to_name.length ()), - to_name.data () - ); + log_debug (LOG_ASSEMBLY, "typemap: map {} -> {} uses hashes"sv, from_name, to_name); size_t type_name_length = strlen (typeName); hash_t type_name_hash = crc32_hash (typeName, type_name_length); @@ -146,29 +131,19 @@ auto TypeMapper::find_index_by_hash (const char *typeName, const TypeMapEntry *m auto TypeMapper::index_to_name (ssize_t idx, const char* typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) -> const char* { if (idx < 0) [[unlikely]] { - log_debugf ( - LOG_ASSEMBLY, - "typemap: unable to map from %.*s type '%s' to %.*s type", - static_cast(from_name.length ()), - from_name.data (), - optional_string (typeName), - static_cast(to_name.length ()), - to_name.data () - ); + log_debug (LOG_ASSEMBLY, "typemap: unable to map from {} type '{}' to {} type"sv, from_name, typeName, to_name); return nullptr; } TypeMapEntry const& entry = map[idx]; const char *mapped_name = &name_map[entry.to]; - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "typemap: %.*s type '%s' maps to %.*s type '%s'", - static_cast(from_name.length ()), - from_name.data (), + "typemap: {} type '{}' maps to {} type '{}'"sv, + from_name, optional_string (typeName), - static_cast(to_name.length ()), - to_name.data (), + to_name, optional_string (mapped_name) ); return mapped_name; @@ -242,14 +217,14 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m const TypeMapModule *match = find_module_entry (mvid, managed_to_java_map, managed_to_java_map_module_count); if (match == nullptr) { if (mvid == nullptr) { - log_warnf (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"); + log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); } else { - log_infof (LOG_ASSEMBLY, "typemap: module matching MVID [%s] not found.", MonoGuidString (mvid).c_str ()); + log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found."sv, MonoGuidString (mvid).c_str ()); } return nullptr; } - log_debugf (LOG_ASSEMBLY, "typemap: found module matching MVID [%s]", MonoGuidString (mvid).c_str ()); + log_debug (LOG_ASSEMBLY, "typemap: found module matching MVID [{}]"sv, MonoGuidString (mvid).c_str ()); size_t type_name_length = strlen (typeName); hash_t name_hash = crc32_hash (typeName, type_name_length); @@ -259,9 +234,9 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m const TypeMapModuleEntry *entry = find_managed_to_java_map_entry (name_hash, typeName, type_name_length, map, match->entry_count); if (entry == nullptr) [[unlikely]] { if (match->duplicate_count > 0 && match->duplicate_map_index < std::numeric_limitsduplicate_map_index)>::max ()) { - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "typemap: searching module [%s] duplicate map for type '%s' (hash %" PRIx32 ")", + "typemap: searching module [{}] duplicate map for type '{}' (hash {:x})"sv, MonoGuidString (mvid).c_str (), optional_string (typeName), name_hash @@ -272,28 +247,26 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m } if (entry == nullptr) { - log_warnf ( + log_warn ( LOG_ASSEMBLY, - "typemap: managed type '%s' (hash %" PRIx32 ") not found in module [%s] (%.*s).", + "typemap: managed type '{}' (hash {:x}) not found in module [{}] ({})."sv, optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - static_cast(match->assembly_name_length), - &managed_assembly_names[match->assembly_name_index] + std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length) ); return nullptr; } } if (entry->java_map_index >= java_type_count) [[unlikely]] { - log_warnf ( + log_warn ( LOG_ASSEMBLY, - "typemap: managed type '%s' (hash %" PRIx32 ") in module [%s] (%.*s) has invalid Java type index %" PRIu32, + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) has invalid Java type index {}"sv, optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - static_cast(match->assembly_name_length), - &managed_assembly_names[match->assembly_name_index], + std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), entry->java_map_index ); return nullptr; @@ -301,14 +274,13 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m TypeMapJava const& java_entry = java_to_managed_map[entry->java_map_index]; if (java_entry.java_name_index >= java_type_names_size) [[unlikely]] { - log_warnf ( + log_warn ( LOG_ASSEMBLY, - "typemap: managed type '%s' (hash %" PRIx32 ") in module [%s] (%.*s) points to invalid Java type at index %" PRIu32 " (invalid type name index %" PRIu32 ")", + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})"sv, optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - static_cast(match->assembly_name_length), - &managed_assembly_names[match->assembly_name_index], + std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), entry->java_map_index, java_entry.java_name_index ); @@ -318,17 +290,16 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m const char *ret = &java_type_names[java_entry.java_name_index]; if (ret == nullptr) [[unlikely]] { - log_warnf (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index %" PRIu32, entry->java_map_index); + log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index {}"sv, entry->java_map_index); } - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "typemap: managed type '%s' (hash %" PRIx32 ") in module [%s] (%.*s) corresponds to Java type '%s'", + "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) corresponds to Java type '{}'"sv, optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - static_cast(match->assembly_name_length), - &managed_assembly_names[match->assembly_name_index], + std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), ret ); @@ -343,13 +314,13 @@ auto TypeMapper::managed_to_java (const char *typeName, const uint8_t *mvid) noe auto TypeMapper::managed_to_java (const char *typeName, const char *assemblyFullName) noexcept -> const char* #endif { - log_debugf (LOG_ASSEMBLY, "managed_to_java: looking up type '%s'", optional_string (typeName)); + log_debug (LOG_ASSEMBLY, "managed_to_java: looking up type '{}'"sv, optional_string (typeName)); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::ManagedToJava); } if (typeName == nullptr) [[unlikely]] { - log_warnf (LOG_ASSEMBLY, "typemap: type name not specified in typemap_managed_to_java"); + log_warn (LOG_ASSEMBLY, "typemap: type name not specified in typemap_managed_to_java"sv); return nullptr; } @@ -375,7 +346,7 @@ auto TypeMapper::managed_to_java (const char *typeName, const char *assemblyFull auto TypeMapper::java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { if (assembly_name == nullptr || managed_type_token_id == nullptr) [[unlikely]] { - log_warnf (LOG_ASSEMBLY, "Managed land called java-to-managed mapping function with invalid pointers"); + log_warn (LOG_ASSEMBLY, "Managed land called java-to-managed mapping function with invalid pointers"sv); return false; } @@ -395,12 +366,12 @@ auto TypeMapper::java_to_managed_debug (const char *java_type_name, char const** *assembly_name = &type_map_assembly_names[type_info.assembly_name_index]; *managed_type_token_id = type_info.managed_type_token_id; - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Mapped Java type '%s' to managed type '%s' in assembly '%s' and with token '%" PRIx32 "'", + "Mapped Java type '{}' to managed type '{}' in assembly '{}' and with token '{:x}'"sv, optional_string (java_type_name), name, - optional_string (*assembly_name), + *assembly_name, *managed_type_token_id ); @@ -433,15 +404,30 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const { if (java_type_name == nullptr || assembly_name == nullptr || managed_type_token_id == nullptr) [[unlikely]] { if (java_type_name == nullptr) { - log_warnf (LOG_ASSEMBLY, "typemap: required parameter `%s` not passed to %s", "java_type_name", __PRETTY_FUNCTION__); + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}"sv, + "java_type_name"sv, + __PRETTY_FUNCTION__ + ); } if (assembly_name == nullptr) { - log_warnf (LOG_ASSEMBLY, "typemap: required parameter `%s` not passed to %s", "assembly_name", __PRETTY_FUNCTION__); + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}"sv, + "assembly_name"sv, + __PRETTY_FUNCTION__ + ); } if (managed_type_token_id == nullptr) { - log_warnf (LOG_ASSEMBLY, "typemap: required parameter `%s` not passed to %s", "managed_type_token_id", __PRETTY_FUNCTION__); + log_warn ( + LOG_ASSEMBLY, + "typemap: required parameter `{}` not passed to {}"sv, + "managed_type_token_id"sv, + __PRETTY_FUNCTION__ + ); } return false; @@ -451,9 +437,9 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const hash_t name_hash = crc32_hash (java_type_name, java_type_name_length); TypeMapJava const* java_entry = find_java_to_managed_entry (name_hash, java_type_name, java_type_name_length); if (java_entry == nullptr) { - log_infof ( + log_info ( LOG_ASSEMBLY, - "typemap: unable to find mapping to a managed type from Java type '%s' (hash %" PRIx32 ")", + "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})"sv, optional_string (java_type_name), name_hash ); @@ -465,15 +451,13 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const *assembly_name = &managed_assembly_names[module.assembly_name_index]; *managed_type_token_id = java_entry->managed_type_token_id; - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Java type '%s' corresponds to managed type '%.*s' (token 0x%" PRIx32 " in assembly '%.*s')", + "Java type '{}' corresponds to managed type '{}' (token 0x{:x} in assembly '{}')"sv, optional_string (java_type_name), - static_cast(java_entry->managed_type_name_length), - &managed_type_names[java_entry->managed_type_name_index], + std::string_view (&managed_type_names[java_entry->managed_type_name_index], java_entry->managed_type_name_length), *managed_type_token_id, - static_cast(module.assembly_name_length), - &managed_assembly_names[module.assembly_name_index] + std::string_view (&managed_assembly_names[module.assembly_name_index], module.assembly_name_length) ); return true; @@ -483,13 +467,13 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const [[gnu::flatten]] auto TypeMapper::java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { - log_debugf (LOG_ASSEMBLY, "java_to_managed: looking up type '%s'", optional_string (java_type_name)); + log_debug (LOG_ASSEMBLY, "java_to_managed: looking up type '{}'"sv, optional_string (java_type_name)); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::JavaToManaged); } if (java_type_name == nullptr) [[unlikely]] { - log_warnf (LOG_ASSEMBLY, "typemap: type name not specified in typemap_java_to_managed"); + log_warn (LOG_ASSEMBLY, "typemap: type name not specified in typemap_java_to_managed"sv); return false; } diff --git a/src/native/clr/include/host/host.hh b/src/native/clr/include/host/host.hh index 1b6eafb68c5..a492ecf21b6 100644 --- a/src/native/clr/include/host/host.hh +++ b/src/native/clr/include/host/host.hh @@ -8,12 +8,11 @@ #include "host-common.hh" #include +#include #include "../shared/log_types.hh" #include "managed-interface.hh" namespace xamarin::android { - class Timing; - class Host : public HostCommon { public: @@ -55,7 +54,7 @@ namespace xamarin::android { private: static inline void *clr_host = nullptr; static inline unsigned int domain_id = 0; - static std::shared_ptr _timing; + static inline std::shared_ptr _timing{}; static inline bool found_assembly_store = false; static inline jnienv_register_jni_natives_fn jnienv_register_jni_natives = nullptr; static inline jnienv_propagate_uncaught_exception_fn jnienv_propagate_uncaught_exception = nullptr; diff --git a/src/native/clr/include/host/pinvoke-override-impl.hh b/src/native/clr/include/host/pinvoke-override-impl.hh index f5b9b31a92b..cb784e0cec2 100644 --- a/src/native/clr/include/host/pinvoke-override-impl.hh +++ b/src/native/clr/include/host/pinvoke-override-impl.hh @@ -26,7 +26,7 @@ namespace xamarin::android { short_library_name.append (Constants::dso_suffix); } - log_debugf (LOG_ASSEMBLY, "Modified p/invoke library name to '%s'", short_library_name.get ()); + log_debug (LOG_ASSEMBLY, "Modified p/invoke library name to '{}'", short_library_name.get ()); lib_handle = MonodroidDl::monodroid_dlopen (short_library_name.get (), microsoft::java_interop::JAVA_INTEROP_LIB_LOAD_LOCALLY); } @@ -35,27 +35,13 @@ namespace xamarin::android { } if (lib_handle == nullptr) { - log_warnf ( - LOG_ASSEMBLY, - "Shared library '%.*s' not loaded, p/invoke '%.*s' may fail", - static_cast(library_name.length ()), - library_name.data (), - static_cast(symbol_name.length ()), - symbol_name.data () - ); + log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name); return nullptr; } void *entry_handle = MonodroidDl::monodroid_dlsym (lib_handle, symbol_name); if (entry_handle == nullptr) { - log_warnf ( - LOG_ASSEMBLY, - "Symbol '%.*s' not found in shared library '%.*s', p/invoke may fail", - static_cast(symbol_name.length ()), - symbol_name.data (), - static_cast(library_name.length ()), - library_name.data () - ); + log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", symbol_name, library_name); return nullptr; } diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index 388b3e4db46..fe5be44035e 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -9,7 +9,7 @@ #include #include "../constants.hh" -#include "../shared/log_types.hh" +#include #include "../runtime-base/cpu-arch.hh" #include #include @@ -117,7 +117,7 @@ namespace xamarin::android { } } - log_debugf (LOG_DEFAULT, "Creating public update directory: `%s`", override_dir.c_str ()); + log_debug (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); Util::create_public_directory (override_dir); } #endif diff --git a/src/native/clr/include/runtime-base/internal-pinvokes.hh b/src/native/clr/include/runtime-base/internal-pinvokes.hh index 8be1634f49d..a5408b45046 100644 --- a/src/native/clr/include/runtime-base/internal-pinvokes.hh +++ b/src/native/clr/include/runtime-base/internal-pinvokes.hh @@ -6,10 +6,7 @@ #include #include #include "logger.hh" - -namespace xamarin::android { - struct managed_timing_sequence; -} +#include extern "C" { int _monodroid_gref_get () noexcept; diff --git a/src/native/clr/include/runtime-base/monodroid-dl.hh b/src/native/clr/include/runtime-base/monodroid-dl.hh index 32c1264d71e..765e5746087 100644 --- a/src/native/clr/include/runtime-base/monodroid-dl.hh +++ b/src/native/clr/include/runtime-base/monodroid-dl.hh @@ -1,6 +1,5 @@ #pragma once -#include #include #include @@ -119,7 +118,7 @@ namespace xamarin::android [[gnu::always_inline, gnu::flatten]] static auto find_dso_cache_entry (std::string_view const& name, hash_t hash) noexcept -> DSOCacheEntry* { - log_debugf (LOG_ASSEMBLY, "Looking for hash %" PRIx32 " in DSO cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); auto less_than = [](DSOCacheEntry const& entry, hash_t key) -> bool { return entry.hash < key; }; size_t idx = Search::lower_bound (hash, dso_cache, application_config.number_of_dso_cache_entries); @@ -148,40 +147,23 @@ namespace xamarin::android static auto monodroid_dlopen (DSOCacheEntry *dso, std::string_view const& name, int flags) noexcept -> void* { - std::string_view dso_name = get_dso_name (dso); - log_debugf ( - LOG_ASSEMBLY, - "monodroid_dlopen: hash match %sfound, DSO name is '%.*s'", - dso == nullptr ? "not " : "", - static_cast(dso_name.length ()), - dso_name.data () - ); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, get_dso_name (dso)); if (dso == nullptr) { // DSO not known at build time, try to load it. Since we don't know whether or not the library uses // JNI, we're going to assume it does and thus use System.loadLibrary eventually. return DsoLoader::load (name, flags, true /* is_jni */); } else if (dso->handle != nullptr) { - log_debugf ( - LOG_ASSEMBLY, - "monodroid_dlopen: library %.*s already loaded, returning handle %p", - static_cast(name.length ()), - name.data (), - dso->handle - ); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: library {} already loaded, returning handle {:p}", name, dso->handle); return dso->handle; } if (dso->ignore) { - log_infof ( - LOG_ASSEMBLY, - "Request to load '%.*s' ignored, it is known not to exist", - static_cast(dso_name.length ()), - dso_name.data () - ); + log_info (LOG_ASSEMBLY, "Request to load '{}' ignored, it is known not to exist", get_dso_name (dso)); return nullptr; } + std::string_view dso_name = get_dso_name (dso); StartupAwareLock lock (dso_handle_write_lock); dso->handle = AndroidSystem::load_dso_from_any_directories (dso_name, flags, dso->is_jni_library); @@ -196,18 +178,12 @@ namespace xamarin::android static auto monodroid_dlopen (std::string_view const& name, int flags) noexcept -> void* { if (name.empty ()) [[unlikely]] { - log_warnf (LOG_ASSEMBLY, "monodroid_dlopen got a null name. This is not supported in NET+"); + log_warn (LOG_ASSEMBLY, "monodroid_dlopen got a null name. This is not supported in NET+"sv); return nullptr; } hash_t name_hash = crc32_hash (name); - log_debugf ( - LOG_ASSEMBLY, - "monodroid_dlopen: hash for name '%.*s' is %" PRIx32, - static_cast(name.length ()), - name.data (), - name_hash - ); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash); DSOCacheEntry *dso = find_dso_cache_entry (name, name_hash); return monodroid_dlopen (dso, name, flags); @@ -220,11 +196,10 @@ namespace xamarin::android void *s = microsoft::java_interop::java_interop_lib_symbol (handle, name.data (), &e); if (s == nullptr) { - log_errorf ( + log_error ( LOG_ASSEMBLY, - "Could not find symbol '%.*s': %s", - static_cast(name.length ()), - name.data (), + "Could not find symbol '{}': {}", + name, optional_string (e) ); } diff --git a/src/native/clr/include/shared/log_types.hh b/src/native/clr/include/shared/log_types.hh index a4e902e78d5..54e164c87f8 100644 --- a/src/native/clr/include/shared/log_types.hh +++ b/src/native/clr/include/shared/log_types.hh @@ -1,16 +1,119 @@ #pragma once #include +#include +#include #include #include +// We redeclare macros here +#if defined(log_debug) +#undef log_debug +#endif + +#if defined(log_info) +#undef log_info +#endif + +#define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ + do { \ + if ((log_categories & ((_category_))) != 0) { \ + ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ + } \ + } while (0) + +// +// For std::format spec, see https://en.cppreference.com/w/cpp/utility/format/spec +// + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_debug(_category_, _fmt_, ...) DO_LOG_FMT (debug, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_info(_category_, _fmt_, ...) DO_LOG_FMT (info, (_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_warn(_category_, _fmt_, ...) log_warn_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_error(_category_, _fmt_, ...) log_error_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + +// NOTE: _fmt_ takes arguments in the std::format style not the POSIX printf style +#define log_fatal(_category_, _fmt_, ...) log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) + namespace xamarin::android { [[gnu::always_inline]] static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept { log_write (category, level, message.data ()); } + + template [[gnu::always_inline]] + static inline constexpr void log_write_fmt (LogCategories category, LogLevel level, std::format_string fmt, Args&& ...args) + { + log_write (category, level, std::format (fmt, std::forward(args)...).c_str ()); + } +} + +template [[gnu::always_inline]] +static inline constexpr void log_debug_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) +{ + log_write (category, xamarin::android::LogLevel::Debug, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Debug, message.data ()); +} + +template [[gnu::always_inline]] +static inline constexpr void log_info_nocheck_fmt (LogCategories category, std::format_string fmt, Args&& ...args) +{ + log_write (category, xamarin::android::LogLevel::Info, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Info, message.data ()); +} + +template [[gnu::always_inline]] +static inline constexpr void log_warn_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +{ + log_write (category, xamarin::android::LogLevel::Warn, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Warn, message.data ()); +} + +template [[gnu::always_inline]] +static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +{ + log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Error, message.data ()); +} + +template [[gnu::always_inline]] +static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +{ + log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); +} + +[[gnu::always_inline]] +static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept +{ + log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); } extern unsigned int log_categories; diff --git a/src/native/clr/pinvoke-override/precompiled.cc b/src/native/clr/pinvoke-override/precompiled.cc index b0e8aaba5ad..2b47211b410 100644 --- a/src/native/clr/pinvoke-override/precompiled.cc +++ b/src/native/clr/pinvoke-override/precompiled.cc @@ -1,5 +1,6 @@ #define PINVOKE_OVERRIDE_INLINE [[gnu::always_inline]] +#include #include #include @@ -14,14 +15,13 @@ namespace { [[noreturn]] void abort_missing_internal_symbol (std::string_view const& library_name, std::string_view const& entrypoint_name) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Internal p/invoke symbol '%.*s'@'%.*s' not found", - static_cast(entrypoint_name.length ()), - entrypoint_name.data (), - static_cast(library_name.length ()), - library_name.data () + std::format ( + "Internal p/invoke symbol '{}'@'{}' not found"sv, + entrypoint_name, + library_name + ) ); } @@ -167,13 +167,8 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept { - log_debugf ( - LOG_ASSEMBLY, - "[precompiled] clr_pinvoke_override (\"%s\", \"%s\")", - library_name == nullptr ? "" : library_name, - entry_point_name == nullptr ? "" : entry_point_name - ); + log_debug (LOG_ASSEMBLY, "[precompiled] clr_pinvoke_override (\"{}\", \"{}\")"sv, library_name, entry_point_name); void *ret = PinvokeOverride::monodroid_pinvoke_override (library_name, entry_point_name); - log_debugf (LOG_DEFAULT, "[precompiled] p/invoke %sfound", ret == nullptr ? "not " : ""); + log_debug (LOG_DEFAULT, "[precompiled] p/invoke {}found"sv, ret == nullptr ? "not"sv : ""sv); return ret; } diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index 2f27300d7b1..aee00900d55 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -1,5 +1,4 @@ #include -#include #include #include @@ -25,7 +24,7 @@ void AndroidSystem::add_system_property (const char *name, const char *value) noexcept { if (name == nullptr || *name == '\0') { - log_warnf (LOG_DEFAULT, "Attempt to add a bundled system property without a valid name"); + log_warn (LOG_DEFAULT, "Attempt to add a bundled system property without a valid name"); return; } @@ -50,7 +49,7 @@ AndroidSystem::setup_environment (const char *name, const char *value) noexcept if (isupper (name [0]) || name [0] == '_') { if (setenv (name, v, 1) < 0) { - log_warnf (LOG_DEFAULT, "(Debug) Failed to set environment variable: %s", strerror (errno)); + log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); } return; } @@ -65,13 +64,13 @@ AndroidSystem::setup_environment_from_override_file (dynamic_local_string::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warnf (LOG_DEFAULT, "Malformed header of the environment override file %s: name width has invalid format", path.get ()); + log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: name width has invalid format", path.get ()); return; } unsigned long value_width = strtoul (buf.get () + 11, &endptr, 16); if ((value_width == std::numeric_limits::max () && errno == ERANGE) || (buf[0] != '\0' && *endptr != '\0')) { - log_warnf (LOG_DEFAULT, "Malformed header of the environment override file %s: value width has invalid format", path.get ()); + log_warn (LOG_DEFAULT, "Malformed header of the environment override file {}: value width has invalid format", path.get ()); return; } uint64_t data_width = name_width + value_width; if (data_width > file_size - Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - Constants::OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { - log_warnf (LOG_DEFAULT, "Malformed environment override file %s: invalid data size", path.get ()); + log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path.get ()); return; } @@ -137,11 +136,11 @@ AndroidSystem::setup_environment_from_override_file (dynamic_local_string 0 && data_size >= data_width) { if (*name == '\0') { - log_warnf (LOG_DEFAULT, "Malformed environment override file %s: name at offset %td is empty", path.get (), name - buf.get ()); + log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path.get (), name - buf.get ()); return; } - log_debugf (LOG_DEFAULT, "Setting environment variable from the override file %s: '%s' = '%s'", path.get (), name, name + name_width); + log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path.get (), name, name + name_width); setup_environment (name, name + name_width); name += data_width; data_size -= data_width; @@ -162,7 +161,7 @@ AndroidSystem::add_apk_libdir (std::string_view const& apk, size_t &index, std:: dir.append (lib_prefix); dir.append (abi); app_lib_directories [index] = dir; - log_debugf (LOG_ASSEMBLY, "Added APK DSO lookup location: %s", dir.c_str ()); + log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: {}", dir); index++; } @@ -197,7 +196,7 @@ AndroidSystem::setup_apk_directories (unsigned short running_on_cpu, jstring_arr add_apk_libdir (base_apk, number_of_added_directories, abi); } - log_debugf (LOG_DEFAULT, "Number of added dirs: %zu", number_of_added_directories); + log_debug (LOG_DEFAULT, "Number of added dirs: {}", number_of_added_directories); if (app_lib_directories.size () == number_of_added_directories) [[likely]] { return; } @@ -210,15 +209,15 @@ void AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks, jstring_array_wrapper& appDirs, bool have_split_apks) noexcept { if (!is_embedded_dso_mode_enabled ()) { - log_debugf (LOG_DEFAULT, "Setting up for DSO lookup in app data directories"); + log_debug (LOG_DEFAULT, "Setting up for DSO lookup in app data directories"sv); app_lib_directories = std::span (single_app_lib_directory); app_lib_directories [0] = std::string (appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - log_debugf (LOG_ASSEMBLY, "Added filesystem DSO lookup location: %s", app_lib_directories [0].c_str ()); + log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: {}", app_lib_directories [0]); return; } - log_debugf (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"); + log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); if (have_split_apks) { // If split apks are used, then we will have just a single app library directory. Don't allocate any memory // dynamically in this case @@ -238,7 +237,7 @@ void AndroidSystem::setup_environment () noexcept { if (application_config.environment_variable_count > 0) { - log_debugf (LOG_DEFAULT, "Setting environment variables (%" PRIu32 ")", application_config.environment_variable_count); + log_debug (LOG_DEFAULT, "Setting environment variables ({})", application_config.environment_variable_count); HostEnvironment::set_values ( application_config.environment_variable_count, app_environment_variables, @@ -247,7 +246,7 @@ AndroidSystem::setup_environment () noexcept } if (application_config.system_property_count > 0) { - log_debugf (LOG_DEFAULT, "Setting system properties (%" PRIu32 ")", application_config.system_property_count); + log_debug (LOG_DEFAULT, "Setting system properties ({})", application_config.system_property_count); HostEnvironment::set_values ( application_config.system_property_count, app_system_properties, @@ -256,13 +255,13 @@ AndroidSystem::setup_environment () noexcept } #if defined(DEBUG) - log_debugf (LOG_DEFAULT, "Loading environment from the override directory."); + log_debug (LOG_DEFAULT, "Loading environment from the override directory."sv); dynamic_local_string env_override_file; Util::path_combine (env_override_file, std::string_view {primary_override_dir}, Constants::OVERRIDE_ENVIRONMENT_FILE_NAME); - log_debugf (LOG_DEFAULT, "%s", env_override_file.get ()); + log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); if (Util::file_exists (env_override_file)) { - log_debugf (LOG_DEFAULT, "Loading %s", env_override_file.get ()); + log_debug (LOG_DEFAULT, "Loading {}"sv, env_override_file.get ()); setup_environment_from_override_file (env_override_file); } #endif // def DEBUG @@ -275,12 +274,12 @@ AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcep dynamic_local_string libmonodroid_path; Util::path_combine (libmonodroid_path, appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_string_view (), "libmonodroid.so"sv); - log_debugf (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to %s", libmonodroid_path.get ()); + log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ()); if (!Util::file_exists (libmonodroid_path)) { - log_debugf (LOG_ASSEMBLY, "%s not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); + log_debug (LOG_ASSEMBLY, "{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); set_embedded_dso_mode_enabled (true); } else { - log_debugf (LOG_ASSEMBLY, "Native libs extracted to %s, assuming application/android:extractNativeLibs == true", appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, "Native libs extracted to {}, assuming application/android:extractNativeLibs == true", appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); set_embedded_dso_mode_enabled (false); native_libraries_dir.assign (appDirs[Constants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); } diff --git a/src/native/common/include/runtime-base/dso-loader.hh b/src/native/common/include/runtime-base/dso-loader.hh index c424d0113d2..f44947453b4 100644 --- a/src/native/common/include/runtime-base/dso-loader.hh +++ b/src/native/common/include/runtime-base/dso-loader.hh @@ -41,10 +41,10 @@ namespace xamarin::android { return load_jni (path, true /* name_is_path */); } - log_infof (LOG_ASSEMBLY, "[filesystem] Trying to load shared library '%.*s'", static_cast(path.length ()), path.data ()); + log_info (LOG_ASSEMBLY, "[filesystem] Trying to load shared library '{}'", path); if constexpr (!SkipExistsCheck) { if (!AndroidSystem::is_embedded_dso_mode_enabled () && !Util::file_exists (path)) { - log_infof (LOG_ASSEMBLY, "Shared library '%.*s' not found", static_cast(path.length ()), path.data ()); + log_info (LOG_ASSEMBLY, "Shared library '{}' not found", path); return nullptr; } } @@ -60,13 +60,7 @@ namespace xamarin::android { return load_jni (name, true /* name_is_path */); } - log_infof ( - LOG_ASSEMBLY, - "[apk] Trying to load shared library '%.*s', offset in the apk == %lld", - static_cast(name.length ()), - name.data (), - static_cast(offset) - ); + log_info (LOG_ASSEMBLY, "[apk] Trying to load shared library '{}', offset in the apk == {}", name, offset); android_dlextinfo dli; dli.flags = ANDROID_DLEXT_USE_LIBRARY_FD | ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET; @@ -81,13 +75,7 @@ namespace xamarin::android { static auto log_and_return (void *handle, std::string_view const& full_name) -> void* { if (handle != nullptr) [[likely]] { - log_debugf ( - LOG_ASSEMBLY, - "Shared library %.*s loaded (handle %p)", - static_cast(full_name.length ()), - full_name.data (), - handle - ); + log_debug (LOG_ASSEMBLY, "Shared library {} loaded (handle {:p})", full_name, handle); return handle; } @@ -95,11 +83,10 @@ namespace xamarin::android { if (load_error == nullptr) { load_error = "Unknown error"; } - log_errorf ( + log_error ( LOG_ASSEMBLY, - "Could not load library '%.*s'. %s", - static_cast(full_name.length ()), - full_name.data (), + "Could not load library '{}'. {}"sv, + full_name, load_error ); @@ -108,12 +95,7 @@ namespace xamarin::android { static auto load_jni (std::string_view const& name, bool name_is_path) -> void* { - log_debugf ( - LOG_ASSEMBLY, - "Trying to load loading shared JNI library %.*s with System.loadLibrary", - static_cast(name.length ()), - name.data () - ); + log_debug (LOG_ASSEMBLY, "Trying to load loading shared JNI library {} with System.loadLibrary", name); auto get_file_name = [](std::string_view const& full_name, bool is_path) -> std::string_view { if (!is_path) { @@ -193,16 +175,8 @@ namespace xamarin::android { // way :( // We must use full name of the library, because dlopen won't accept an undecorated one without kicking up // a fuss. - std::string_view file_name = get_file_name (name, name_is_path); - log_debugf ( - LOG_ASSEMBLY, - "Attempting to get library %.*s handle after System.loadLibrary. Will try to load using '%.*s'", - static_cast(name.length ()), - name.data (), - static_cast(file_name.length ()), - file_name.data () - ); - return log_and_return (dlopen (file_name.data (), RTLD_NOLOAD), name); + log_debug (LOG_ASSEMBLY, "Attempting to get library {} handle after System.loadLibrary. Will try to load using '{}'", name, get_file_name (name, name_is_path)); + return log_and_return (dlopen (get_file_name (name, name_is_path).data (), RTLD_NOLOAD), name); } private: diff --git a/src/native/common/include/runtime-base/mainthread-dso-loader.hh b/src/native/common/include/runtime-base/mainthread-dso-loader.hh index 99437c83f2b..144ad67db81 100644 --- a/src/native/common/include/runtime-base/mainthread-dso-loader.hh +++ b/src/native/common/include/runtime-base/mainthread-dso-loader.hh @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -25,11 +26,12 @@ namespace xamarin::android { explicit MainThreadDsoLoader () noexcept { if (pipe (pipe_fds) != 0) { - Helpers::abort_applicationf ( + Helpers::abort_application ( LOG_ASSEMBLY, - std::source_location::current (), - "Failed to create a pipe for main thread DSO loader. %s", - strerror (errno) + std::format ( + "Failed to create a pipe for main thread DSO loader. {}"sv, + strerror (errno) + ) ); } @@ -72,16 +74,16 @@ namespace xamarin::android { if (!undecorated_library_name.empty ()) [[unlikely]] { Helpers::abort_application ("Main thread DSO loader object reused! DO NOT DO THAT!"sv); } - log_debugf (LOG_ASSEMBLY, "Running DSO loader on thread %d, dispatching to main thread", gettid ()); + log_debug (LOG_ASSEMBLY, "Running DSO loader on thread {}, dispatching to main thread"sv, gettid ()); undecorated_library_name = undecorated_name; load_success = false; constexpr std::array payload { 0xFF }; ssize_t nbytes = write (pipe_fds[1], payload.data (), payload.size ()); if (nbytes == -1) { - log_warnf ( + log_warn ( LOG_ASSEMBLY, - "Write failure when posting a DSO load event to main thread. %s", + "Write failure when posting a DSO load event to main thread. {}"sv, strerror (errno) ); return false; @@ -93,12 +95,7 @@ namespace xamarin::android { // We'll wait for up to 3s, it should be more than enough time for the library to load bool success = load_complete_sem.try_acquire_for (3s); if (!success) { - log_warnf ( - LOG_ASSEMBLY, - "Timeout while waiting for shared library '%.*s' to load.", - static_cast(full_name.length ()), - full_name.data () - ); + log_warn (LOG_ASSEMBLY, "Timeout while waiting for shared library '{}' to load."sv, full_name); return false; } @@ -133,16 +130,15 @@ namespace xamarin::android { }; if (self->undecorated_library_name.empty ()) { - log_warnf (LOG_ASSEMBLY, "Library name not specified in main thread looper callback."); + log_warn (LOG_ASSEMBLY, "Library name not specified in main thread looper callback."sv); return over_and_out (); } - log_debugf ( + log_debug ( LOG_ASSEMBLY, - "Looper CB called on thread %d. Will attempt to load DSO '%.*s'", + "Looper CB called on thread {}. Will attempt to load DSO '{}'"sv, gettid (), - static_cast(self->undecorated_library_name.length ()), - self->undecorated_library_name.data () + self->undecorated_library_name ); self->load_success = SystemLoadLibraryWrapper::load (main_thread_jni_env /* RuntimeEnvironment::get_jnienv () */, self->undecorated_library_name); diff --git a/src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh b/src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh index 21625cec219..577d6ba8e6f 100644 --- a/src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh +++ b/src/native/common/include/runtime-base/system-loadlibrary-wrapper.hh @@ -32,7 +32,7 @@ namespace xamarin::android { // std::string is needed because we must pass a NUL-terminated string to Java, otherwise // strange things happen (and std::string_view is not necessarily such a string) const std::string lib_name { undecorated_lib_name }; - log_debugf (LOG_ASSEMBLY, "Undecorated library name: %s", lib_name.c_str ()); + log_debug (LOG_ASSEMBLY, "Undecorated library name: {}", lib_name); jstring java_lib_name = jni_env->NewStringUTF (lib_name.c_str ()); if (java_lib_name == nullptr) [[unlikely]] { @@ -41,10 +41,10 @@ namespace xamarin::android { } jni_env->CallStaticVoidMethod (systemKlass, System_loadLibrary, java_lib_name); if (jni_env->ExceptionCheck ()) { - log_debugf (LOG_ASSEMBLY, "System.loadLibrary threw a Java exception. Will attempt to log it."); + log_debug (LOG_ASSEMBLY, "System.loadLibrary threw a Java exception. Will attempt to log it."); jni_env->ExceptionDescribe (); jni_env->ExceptionClear (); - log_debugf (LOG_ASSEMBLY, "Java exception cleared"); + log_debug (LOG_ASSEMBLY, "Java exception cleared"); return false; } diff --git a/src/native/common/include/runtime-base/timing-internal.hh b/src/native/common/include/runtime-base/timing-internal.hh index e80fa94dde2..25fdc20b3cd 100644 --- a/src/native/common/include/runtime-base/timing-internal.hh +++ b/src/native/common/include/runtime-base/timing-internal.hh @@ -285,7 +285,7 @@ namespace xamarin::android { } if (!index.has_value ()) [[unlikely]] { - log_warnf (LOG_TIMING, "FastTiming::end_event called without prior FastTiming::start_event called"); + log_warn (LOG_TIMING, "FastTiming::end_event called without prior FastTiming::start_event called"sv); return; } @@ -301,7 +301,7 @@ namespace xamarin::android { { auto index = pop_valid_sequence_index (); if (!index.has_value ()) [[unlikely]] { - log_warnf (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"); + log_warn (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"sv); return; } @@ -314,7 +314,7 @@ namespace xamarin::android { { auto index = pop_valid_sequence_index (); if (!index.has_value ()) [[unlikely]] { - log_warnf (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"); + log_warn (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"sv); return; } @@ -327,7 +327,7 @@ namespace xamarin::android { { auto index = pop_valid_sequence_index (); if (!index.has_value ()) [[unlikely]] { - log_warnf (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"); + log_warn (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"sv); return; } diff --git a/src/native/common/runtime-base/timing-internal.cc b/src/native/common/runtime-base/timing-internal.cc index 87d53974a09..ebf8d111893 100644 --- a/src/native/common/runtime-base/timing-internal.cc +++ b/src/native/common/runtime-base/timing-internal.cc @@ -63,7 +63,7 @@ void FastTiming::parse_options (dynamic_local_property_string const& value) noex if (param.starts_with (OPT_DURATION)) { if (!param.to_integer (duration_ms, OPT_DURATION.length ())) { - log_warnf (LOG_TIMING, "Failed to parse duration in milliseconds from '%.*s'", static_cast(param.length ()), param.start ()); + log_warn (LOG_TIMING, "Failed to parse duration in milliseconds from '%s'"sv, param.start ()); duration_ms = default_duration_milliseconds; } continue; @@ -147,16 +147,15 @@ void FastTiming::dump (size_t entries, bool indent, std::function message; - message.append (" ") - .append (msg) - .append (": ") - .append (static_cast(chrono::duration_cast (time_ns).count ())) - .append (":") - .append (static_cast(chrono::duration_cast (time_ns).count ())) - .append ("::") - .append (static_cast((time_ns % 1ms).count ())); - line_writer (message.as_string_view ()); + // TODO: it's a bit wasteful... if dynamic_local_string is made an output iterator, we can use std::format_to + std::string s = std::format ( + " {}: {}:{}::{}", + msg, + chrono::duration_cast (time_ns).count (), + chrono::duration_cast (time_ns).count (), + (time_ns % 1ms).count () + ); + line_writer (s); }; // Do not change the sequence numbers. If a measurement is removed, its sequence number must not be reused. @@ -201,16 +200,16 @@ void FastTiming::dump_to_file (size_t entries) noexcept FILE *timing_log = Util::monodroid_fopen (timing_log_path.get (), "w"); if (timing_log == nullptr) { - log_errorf (LOG_TIMING, "[2/2] Unable to create the performance measurements file '%s'", timing_log_path.get ()); + log_error (LOG_TIMING, "[2/2] Unable to create the performance measurements file '{}'"sv, timing_log_path.get ()); return; } if (!Util::set_world_accessible (fileno (timing_log))) { - log_warnf (LOG_TIMING, "[2/2] Failed to make performance measurements file '%s' world-readable", timing_log_path.get ()); + log_warn (LOG_TIMING, "[2/2] Failed to make performance measurements file '{}' world-readable"sv, timing_log_path.get ()); return; } - log_infof (LOG_TIMING, "[2/2] Performance measurement results logged to file: %s", timing_log_path.get ()); + log_info (LOG_TIMING, "[2/2] Performance measurement results logged to file: {}"sv, timing_log_path.get ()); auto line_writer = [=](std::string_view const& msg) { if (!msg.empty ()) { diff --git a/src/native/nativeaot/include/runtime-base/internal-pinvokes.hh b/src/native/nativeaot/include/runtime-base/internal-pinvokes.hh new file mode 100644 index 00000000000..60ff24596fc --- /dev/null +++ b/src/native/nativeaot/include/runtime-base/internal-pinvokes.hh @@ -0,0 +1,45 @@ +#pragma once + +#include +#include + +#include +#include +#include + +namespace xamarin::android { + struct managed_timing_sequence; +} + +extern "C" { + int _monodroid_gref_get () noexcept; + int _monodroid_gref_inc () noexcept; + int _monodroid_gref_dec () noexcept; + void _monodroid_gref_log (const char *message) noexcept; + int _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept; + void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; + const char* clr_typemap_managed_to_java (const char *typeName, const char *assemblyFullName, const uint8_t *mvid) noexcept; + bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept; + BridgeProcessingFtn clr_initialize_gc_bridge ( + BridgeProcessingStartedFtn bridge_processing_started_callback, + BridgeProcessingFinishedFtn mark_cross_references_callback) noexcept; + void monodroid_log (xamarin::android::LogLevel level, LogCategories category, const char *message) noexcept; + char* monodroid_TypeManager_get_java_class_name (jclass klass) noexcept; + void monodroid_free (void *ptr) noexcept; + const char* _monodroid_lookup_replacement_type (const char *jniSimpleReference); + const JniRemappingReplacementMethod* _monodroid_lookup_replacement_method_info (const char *jniSourceType, const char *jniMethodName, const char *jniMethodSignature); + xamarin::android::managed_timing_sequence* monodroid_timing_start (const char *message); + void monodroid_timing_stop (xamarin::android::managed_timing_sequence *sequence, const char *message); + + void _monodroid_weak_gref_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from, int from_writable) noexcept; + int _monodroid_weak_gref_get () noexcept; + int _monodroid_weak_gref_inc () noexcept; + int _monodroid_weak_gref_dec () noexcept; + int _monodroid_max_gref_get () noexcept; + void _monodroid_weak_gref_delete (jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable) noexcept; + + void _monodroid_lref_log_new (int lrefc, jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable); + void _monodroid_lref_log_delete (int lrefc, jobject handle, char type, const char *threadName, int threadId, const char *from, int from_writable); + void _monodroid_gc_wait_for_bridge_processing (); + void _monodroid_detect_cpu_and_architecture (unsigned short *built_for_cpu, unsigned short *running_on_cpu, unsigned char *is64bit); +} diff --git a/src/native/nativeaot/include/shared/log_types.hh b/src/native/nativeaot/include/shared/log_types.hh new file mode 100644 index 00000000000..e42f5c331b4 --- /dev/null +++ b/src/native/nativeaot/include/shared/log_types.hh @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include + +namespace xamarin::android { + [[gnu::always_inline]] + static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept + { + log_write (category, level, message.data ()); + } +} + +extern unsigned int log_categories; From 3883914bb8abd95000f6ce1e23dc181b4fbe9a33 Mon Sep 17 00:00:00 2001 From: Simon Rozsival Date: Wed, 19 Aug 2026 18:37:53 +0200 Subject: [PATCH 4/4] [NativeAOT] Avoid string_view logging surface Keep the NativeAOT logging header limited to the printf-style declarations and log bounded shared messages directly with a precision specifier. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 99f3f0fa-70d4-4920-a0e5-798643faac81 --- src/native/clr/host/os-bridge.cc | 2 +- src/native/nativeaot/include/shared/log_types.hh | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/native/clr/host/os-bridge.cc b/src/native/clr/host/os-bridge.cc index c5d71a8c9d7..797316a9f7d 100644 --- a/src/native/clr/host/os-bridge.cc +++ b/src/native/clr/host/os-bridge.cc @@ -164,7 +164,7 @@ void OSBridge::_monodroid_gref_logf (const char *format, ...) noexcept [[gnu::always_inline, gnu::flatten]] void OSBridge::log_it (LogCategories category, std::string_view const& line, FILE *to, const char *const from, bool logcat_enabled) noexcept { - log_write (category, LogLevel::Info, line); + log_writef (category, LogLevel::Info, "%.*s", static_cast(line.length ()), line.data ()); // We skip logcat here when logging to file is enabled because _write_stack_trace will output to logcat as well, if enabled if (to == nullptr) { diff --git a/src/native/nativeaot/include/shared/log_types.hh b/src/native/nativeaot/include/shared/log_types.hh index e42f5c331b4..e4b75d6ea0e 100644 --- a/src/native/nativeaot/include/shared/log_types.hh +++ b/src/native/nativeaot/include/shared/log_types.hh @@ -1,15 +1,5 @@ #pragma once -#include - #include -namespace xamarin::android { - [[gnu::always_inline]] - static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept - { - log_write (category, level, message.data ()); - } -} - extern unsigned int log_categories;