diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index e145c311485..a6f5b0f65ec 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets @@ -132,7 +132,8 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. $(_NdkAbi)-linux-android$(_NDKApiLevel)-clang$(_NdkWrapperScriptExt) llvm-objcopy - + false @@ -197,13 +198,9 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. <_NdkLibs Include="@(RuntimePackAsset->WithMetadataValue('Filename', 'libnaot-android.$(Configuration.ToLower())-static-$(Configuration.ToLower())'))" /> - - <_NdkLibs Include="$(_NdkSysrootDir)libc++_static.a" /> - <_NdkLibs Include="$(_NdkSysrootDir)libc++abi.a" /> - - + @@ -362,12 +359,10 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. <_NativeAotSystemLibraries Include="c" /> - <_NativeAotLinkLibraries Include="@(RuntimePackAsset->WithMetadataValue('Filename', 'libnaot-android.$(Configuration.ToLower())-static-$(Configuration.ToLower())'))" /> - <_NativeAotLinkLibraries Include="$(_NativeAotRuntimePackNativeDir)libc++_static.a" /> - <_NativeAotLinkLibraries Include="$(_NativeAotRuntimePackNativeDir)libc++abi.a" /> <_NativeAotLinkLibraries Include="@(_NdkLibs)" /> diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc index 15e3aae8ee9..135a71476c5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.CoreCLR.apkdesc @@ -5,19 +5,19 @@ "Size": 3036 }, "classes.dex": { - "Size": 400044 + "Size": 405624 }, "lib/arm64-v8a/libassembly-store.so": { - "Size": 3098192 + "Size": 3124888 }, "lib/arm64-v8a/libclrjit.so": { - "Size": 3223752 + "Size": 3222704 }, "lib/arm64-v8a/libcoreclr.so": { - "Size": 5771784 + "Size": 5757272 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1366648 + "Size": 1279264 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 72344 @@ -26,22 +26,13 @@ "Size": 1280336 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 100552 + "Size": 101872 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { "Size": 162000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 20424 - }, - "META-INF/BNDLTOOL.RSA": { - "Size": 1223 - }, - "META-INF/BNDLTOOL.SF": { - "Size": 2091 - }, - "META-INF/MANIFEST.MF": { - "Size": 1964 + "Size": 20776 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -68,5 +59,5 @@ "Size": 1904 } }, - "PackageSize": 7632514 -} + "PackageSize": 7620027 +} \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc index 42c7d46617e..20aeaa019a6 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.MonoVM.apkdesc @@ -8,31 +8,31 @@ "Size": 22384 }, "lib/arm64-v8a/lib__Microsoft.Android.Resource.Designer.dll.so": { - "Size": 18232 + "Size": 18224 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 87720 + "Size": 88144 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 118392 + "Size": 118312 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 26848 + "Size": 26864 }, "lib/arm64-v8a/lib_System.Console.dll.so": { "Size": 24360 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 25432 + "Size": 25448 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 638568 + "Size": 638000 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { "Size": 20224 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 19752 + "Size": 19760 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 19968 @@ -44,10 +44,10 @@ "Size": 36416 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1385800 + "Size": 1294440 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3111840 + "Size": 3111632 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 72344 @@ -62,7 +62,7 @@ "Size": 162000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 19832 + "Size": 19680 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -89,5 +89,5 @@ "Size": 1904 } }, - "PackageSize": 3254606 + "PackageSize": 3221838 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc index 75e2332c446..305a7566aa0 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64SimpleDotNet.NativeAOT.apkdesc @@ -5,19 +5,10 @@ "Size": 3124 }, "classes.dex": { - "Size": 25400 + "Size": 25304 }, "lib/arm64-v8a/libUnnamedProject.so": { - "Size": 5072296 - }, - "META-INF/BNDLTOOL.RSA": { - "Size": 1221 - }, - "META-INF/BNDLTOOL.SF": { - "Size": 1211 - }, - "META-INF/MANIFEST.MF": { - "Size": 1084 + "Size": 4446712 }, "res/drawable-hdpi-v4/icon.png": { "Size": 2178 @@ -44,5 +35,5 @@ "Size": 1904 } }, - "PackageSize": 2126818 + "PackageSize": 1897243 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc index 3e9a925186f..a43a6641838 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.CoreCLR.apkdesc @@ -5,10 +5,10 @@ "Size": 6652 }, "classes.dex": { - "Size": 9444112 + "Size": 9411640 }, "classes2.dex": { - "Size": 156448 + "Size": 157320 }, "kotlin/annotation/annotation.kotlin_builtins": { "Size": 928 @@ -32,16 +32,16 @@ "Size": 2396 }, "lib/arm64-v8a/libassembly-store.so": { - "Size": 14076232 + "Size": 14100448 }, "lib/arm64-v8a/libclrjit.so": { - "Size": 3223752 + "Size": 3222704 }, "lib/arm64-v8a/libcoreclr.so": { - "Size": 5771784 + "Size": 5757272 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1366648 + "Size": 1279264 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 72344 @@ -50,13 +50,13 @@ "Size": 1280336 }, "lib/arm64-v8a/libSystem.Native.so": { - "Size": 100552 + "Size": 101872 }, "lib/arm64-v8a/libSystem.Security.Cryptography.Native.Android.so": { "Size": 162000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 147264 + "Size": 147608 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -208,12 +208,6 @@ "META-INF/androidx.viewpager2_viewpager2.version": { "Size": 6 }, - "META-INF/BNDLTOOL.RSA": { - "Size": 1221 - }, - "META-INF/BNDLTOOL.SF": { - "Size": 90142 - }, "META-INF/com.android.tools/proguard/coroutines.pro": { "Size": 1345 }, @@ -238,9 +232,6 @@ "META-INF/kotlinx_coroutines_core.version": { "Size": 5 }, - "META-INF/MANIFEST.MF": { - "Size": 90015 - }, "META-INF/maven/com.google.guava/listenablefuture/pom.properties": { "Size": 96 }, @@ -478,9 +469,6 @@ "res/color-night-v8/material_timepicker_modebutton_tint.xml": { "Size": 340 }, - "res/color-v21/abc_btn_colored_borderless_text_material.xml": { - "Size": 464 - }, "res/color-v23/abc_btn_colored_borderless_text_material.xml": { "Size": 500 }, @@ -514,9 +502,6 @@ "res/color/abc_background_cache_hint_selector_material_light.xml": { "Size": 468 }, - "res/color/abc_btn_colored_text_material.xml": { - "Size": 604 - }, "res/color/abc_hint_foreground_material_dark.xml": { "Size": 564 }, @@ -544,24 +529,6 @@ "res/color/abc_secondary_text_material_light.xml": { "Size": 464 }, - "res/color/abc_tint_btn_checkable.xml": { - "Size": 728 - }, - "res/color/abc_tint_default.xml": { - "Size": 1224 - }, - "res/color/abc_tint_edittext.xml": { - "Size": 772 - }, - "res/color/abc_tint_seek_thumb.xml": { - "Size": 604 - }, - "res/color/abc_tint_spinner.xml": { - "Size": 772 - }, - "res/color/abc_tint_switch_track.xml": { - "Size": 768 - }, "res/color/checkbox_themeable_attribute_color.xml": { "Size": 464 }, @@ -1699,9 +1666,6 @@ "res/drawable/mtrl_ic_error.xml": { "Size": 644 }, - "res/drawable/mtrl_popupmenu_background_dark.xml": { - "Size": 740 - }, "res/drawable/mtrl_popupmenu_background.xml": { "Size": 740 }, @@ -1798,15 +1762,6 @@ "res/layout-v21/notification_template_icon_group.xml": { "Size": 988 }, - "res/layout-v22/abc_alert_dialog_button_bar_material.xml": { - "Size": 1584 - }, - "res/layout-v22/material_timepicker_dialog.xml": { - "Size": 3184 - }, - "res/layout-v22/mtrl_alert_dialog_actions.xml": { - "Size": 1764 - }, "res/layout-v26/abc_screen_toolbar.xml": { "Size": 1560 }, @@ -1844,7 +1799,7 @@ "Size": 1684 }, "res/layout/abc_alert_dialog_button_bar_material.xml": { - "Size": 1536 + "Size": 1584 }, "res/layout/abc_alert_dialog_material.xml": { "Size": 2648 @@ -2009,7 +1964,7 @@ "Size": 1208 }, "res/layout/material_timepicker_dialog.xml": { - "Size": 3132 + "Size": 3184 }, "res/layout/material_timepicker_textinput_display.xml": { "Size": 684 @@ -2018,7 +1973,7 @@ "Size": 1136 }, "res/layout/mtrl_alert_dialog_actions.xml": { - "Size": 1620 + "Size": 1764 }, "res/layout/mtrl_alert_dialog_title.xml": { "Size": 956 @@ -2276,8 +2231,8 @@ "Size": 268 }, "resources.arsc": { - "Size": 812848 + "Size": 794696 } }, - "PackageSize": 21263139 -} + "PackageSize": 21151309 +} \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc index 043500537a1..5a802f51b13 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Resources/Base/BuildReleaseArm64XFormsDotNet.MonoVM.apkdesc @@ -35,91 +35,91 @@ "Size": 25360 }, "lib/arm64-v8a/lib_Java.Interop.dll.so": { - "Size": 96344 + "Size": 96784 }, "lib/arm64-v8a/lib_Mono.Android.dll.so": { - "Size": 542848 + "Size": 542448 }, "lib/arm64-v8a/lib_Mono.Android.Runtime.dll.so": { - "Size": 26848 + "Size": 26864 }, "lib/arm64-v8a/lib_mscorlib.dll.so": { "Size": 21408 }, "lib/arm64-v8a/lib_netstandard.dll.so": { - "Size": 23048 + "Size": 23056 }, "lib/arm64-v8a/lib_System.Collections.dll.so": { - "Size": 33944 + "Size": 33952 }, "lib/arm64-v8a/lib_System.Collections.NonGeneric.dll.so": { - "Size": 25608 + "Size": 25624 }, "lib/arm64-v8a/lib_System.Collections.Specialized.dll.so": { - "Size": 23800 + "Size": 23816 }, "lib/arm64-v8a/lib_System.ComponentModel.dll.so": { - "Size": 19560 + "Size": 19568 }, "lib/arm64-v8a/lib_System.ComponentModel.Primitives.dll.so": { "Size": 21296 }, "lib/arm64-v8a/lib_System.ComponentModel.TypeConverter.dll.so": { - "Size": 43600 + "Size": 43608 }, "lib/arm64-v8a/lib_System.Console.dll.so": { - "Size": 24392 + "Size": 24400 }, "lib/arm64-v8a/lib_System.Core.dll.so": { - "Size": 19424 + "Size": 19432 }, "lib/arm64-v8a/lib_System.Diagnostics.TraceSource.dll.so": { - "Size": 24584 + "Size": 24592 }, "lib/arm64-v8a/lib_System.dll.so": { - "Size": 19784 + "Size": 19792 }, "lib/arm64-v8a/lib_System.Drawing.dll.so": { "Size": 19400 }, "lib/arm64-v8a/lib_System.Drawing.Primitives.dll.so": { - "Size": 30016 + "Size": 30032 }, "lib/arm64-v8a/lib_System.Formats.Asn1.dll.so": { - "Size": 50968 + "Size": 50976 }, "lib/arm64-v8a/lib_System.IO.Compression.Brotli.dll.so": { - "Size": 29536 + "Size": 29552 }, "lib/arm64-v8a/lib_System.IO.Compression.dll.so": { - "Size": 34600 + "Size": 34616 }, "lib/arm64-v8a/lib_System.IO.IsolatedStorage.dll.so": { - "Size": 28232 + "Size": 28240 }, "lib/arm64-v8a/lib_System.Linq.dll.so": { - "Size": 47912 + "Size": 47920 }, "lib/arm64-v8a/lib_System.Linq.Expressions.dll.so": { - "Size": 185968 + "Size": 185976 }, "lib/arm64-v8a/lib_System.Net.Http.dll.so": { - "Size": 86680 + "Size": 86688 }, "lib/arm64-v8a/lib_System.Net.Primitives.dll.so": { - "Size": 42280 + "Size": 42288 }, "lib/arm64-v8a/lib_System.Net.Requests.dll.so": { - "Size": 21520 + "Size": 21528 }, "lib/arm64-v8a/lib_System.ObjectModel.dll.so": { - "Size": 26968 + "Size": 26984 }, "lib/arm64-v8a/lib_System.Private.CoreLib.dll.so": { - "Size": 999864 + "Size": 1000432 }, "lib/arm64-v8a/lib_System.Private.DataContractSerialization.dll.so": { - "Size": 217808 + "Size": 217816 }, "lib/arm64-v8a/lib_System.Private.Uri.dll.so": { "Size": 62216 @@ -128,25 +128,25 @@ "Size": 236968 }, "lib/arm64-v8a/lib_System.Private.Xml.Linq.dll.so": { - "Size": 35464 + "Size": 35480 }, "lib/arm64-v8a/lib_System.Runtime.dll.so": { - "Size": 20352 + "Size": 20360 }, "lib/arm64-v8a/lib_System.Runtime.InteropServices.dll.so": { - "Size": 19752 + "Size": 19760 }, "lib/arm64-v8a/lib_System.Runtime.Numerics.dll.so": { "Size": 63312 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.dll.so": { - "Size": 19328 + "Size": 19336 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Formatters.dll.so": { - "Size": 20296 + "Size": 20304 }, "lib/arm64-v8a/lib_System.Runtime.Serialization.Primitives.dll.so": { - "Size": 21424 + "Size": 21432 }, "lib/arm64-v8a/lib_System.Security.Cryptography.dll.so": { "Size": 82024 @@ -155,10 +155,10 @@ "Size": 194176 }, "lib/arm64-v8a/lib_System.Xml.dll.so": { - "Size": 19216 + "Size": 19224 }, "lib/arm64-v8a/lib_System.Xml.Linq.dll.so": { - "Size": 19240 + "Size": 19248 }, "lib/arm64-v8a/lib_UnnamedProject.dll.so": { "Size": 22040 @@ -239,10 +239,10 @@ "Size": 36416 }, "lib/arm64-v8a/libmonodroid.so": { - "Size": 1385800 + "Size": 1294440 }, "lib/arm64-v8a/libmonosgen-2.0.so": { - "Size": 3111840 + "Size": 3111632 }, "lib/arm64-v8a/libSystem.Globalization.Native.so": { "Size": 72344 @@ -257,7 +257,7 @@ "Size": 162000 }, "lib/arm64-v8a/libxamarin-app.so": { - "Size": 350616 + "Size": 350464 }, "META-INF/androidx.activity_activity.version": { "Size": 6 @@ -2435,5 +2435,5 @@ "Size": 794696 } }, - "PackageSize": 11024231 + "PackageSize": 10991463 } \ No newline at end of file diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/NativeRuntimeComponents.cs b/src/Xamarin.Android.Build.Tasks/Utilities/NativeRuntimeComponents.cs index 4773d0cd1c1..cf5e40120ea 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/NativeRuntimeComponents.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/NativeRuntimeComponents.cs @@ -129,10 +129,6 @@ public NativeRuntimeComponents (ITaskItem[]? monoComponents) new AndroidArchive ("libxa-shared-bits-release.a"), new AndroidArchive ("libxamarin-startup-release.a"), - // C++ standard library - new CplusPlusArchive ("libc++_static.a"), - new CplusPlusArchive ("libc++abi.a"), - // LLVM clang built-ins archives new ClangBuiltinsArchive ("aarch64"), new ClangBuiltinsArchive ("arm"), diff --git a/src/native/clr/host/assembly-store.cc b/src/native/clr/host/assembly-store.cc index bc79b646596..4121f0d1be4 100644 --- a/src/native/clr/host/assembly-store.cc +++ b/src/native/clr/host/assembly-store.cc @@ -1,3 +1,4 @@ +#include #include #if defined (HAVE_LZ4) @@ -29,7 +30,7 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co #if defined (HAVE_LZ4) && defined (RELEASE) auto header = reinterpret_cast(e.image_data); if (header->magic == COMPRESSED_DATA_MAGIC) { - log_debug (LOG_ASSEMBLY, "Decompressing assembly '{}' from the assembly store"sv, name); + log_debug (LOG_ASSEMBLY, "Decompressing assembly '%.*s' from the assembly store", static_cast(name.length ()), name.data ()); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::AssemblyDecompression); @@ -108,7 +109,7 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co ) ); } else { - log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly."sv, name); + log_debug (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; } @@ -149,7 +150,7 @@ auto AssemblyStore::get_assembly_data (AssemblyStoreSingleAssemblyRuntimeData co } else #endif // def HAVE_LZ4 && def RELEASE { - log_debug (LOG_ASSEMBLY, "Assembly '{}' is not compressed in the assembly store"sv, name); + log_debug (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 @@ -199,7 +200,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_warn (LOG_ASSEMBLY, "Assembly store not registered. Unable to look up assembly '%.*s'", static_cast(name.length ()), name.data ()); return nullptr; } } @@ -207,13 +208,13 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (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_warn (LOG_ASSEMBLY, "Assembly '%.*s' (hash 0x%zx) not found", static_cast(name.length ()), name.data (), static_cast(name_hash)); return nullptr; } if (hash_entry->ignore != 0) { size = 0; - log_debug (LOG_ASSEMBLY, "Assembly '{}' ignored"sv, name); + log_debug (LOG_ASSEMBLY, "Assembly '%.*s' ignored", static_cast(name.length ()), name.data ()); return nullptr; } @@ -242,7 +243,7 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) log_debug ( 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 == %u; debug data size == %u; config data size == %u; name == '%.*s'", static_cast(assembly_runtime_info.image_data), static_cast(assembly_runtime_info.debug_info_data), static_cast(assembly_runtime_info.config_data), @@ -250,7 +251,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 () ); } @@ -264,7 +266,7 @@ void AssemblyStore::map (int fd, std::string_view const& apk_path, std::string_v detail::mmap_info assembly_store_map = Util::mmap_file (fd, offset, size, store_path); auto [payload_start, payload_size] = Util::get_wrapper_dso_payload_pointer_and_size (assembly_store_map, store_path); - log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}"sv, payload_start, payload_size); + log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: %p; size: %zu", payload_start, payload_size); auto header = static_cast(payload_start); auto get_full_store_path = [&apk_path, &store_path]() -> std::string { @@ -312,5 +314,5 @@ void AssemblyStore::map (int fd, std::string_view const& apk_path, std::string_v assembly_store.assemblies = reinterpret_cast(assembly_store.data_start + header_size + header->index_size); assembly_store_hashes = reinterpret_cast(assembly_store.data_start + header_size); - log_debug (LOG_ASSEMBLY, "Mapped assembly store {}"sv, get_full_store_path ()); + log_debug (LOG_ASSEMBLY, "Mapped assembly store %s", get_full_store_path ().c_str ()); } diff --git a/src/native/clr/host/bridge-processing.cc b/src/native/clr/host/bridge-processing.cc index b4ea077a081..0d06315c7bb 100644 --- a/src/native/clr/host/bridge-processing.cc +++ b/src/native/clr/host/bridge-processing.cc @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -6,20 +8,114 @@ using namespace xamarin::android; -void BridgeProcessingShared::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept +TemporaryPeerMap::TemporaryPeerMap (JNIEnv *jni_env, MarkCrossReferencesArgs *args) noexcept + : env{ jni_env }, + cross_refs{ args } +{ + size_t map_capacity = 0; + for (size_t i = 0; i < cross_refs->ComponentCount; i++) { + const StronglyConnectedComponent &scc = cross_refs->Components [i]; + abort_unless (!is_temporary_peer_index (scc.Count), "SCC count must not use the temporary peer marker bit"); + if (scc.Count == 0) { + map_capacity++; + } + } + + if (map_capacity == 0) { + return; + } + + capacity = map_capacity; + peers = static_cast (std::calloc (capacity, sizeof (jobject))); + abort_unless (peers != nullptr, "Failed to allocate GC bridge temporary peer map"); +} + +TemporaryPeerMap::~TemporaryPeerMap () noexcept +{ + if (peers == nullptr) { + return; + } + + for (size_t i = 0; i < count; i++) { + jobject temporary_peer = peers [i]; + if (temporary_peer != nullptr) { + env->DeleteLocalRef (temporary_peer); + peers [i] = nullptr; + } + } + + for (size_t i = 0; i < cross_refs->ComponentCount; i++) { + StronglyConnectedComponent &scc = cross_refs->Components [i]; + if (is_temporary_peer_index (scc.Count)) { + scc.Count = 0; + } + } + + count = 0; + std::free (peers); + peers = nullptr; + capacity = 0; +} + +void TemporaryPeerMap::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept { abort_if_invalid_pointer_argument (env, "env"); abort_if_invalid_pointer_argument (runtimeClass, "runtimeClass"); - GCUserPeer_class = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_GCUserPeer", true); - GCUserPeer_ctor = env->GetMethodID (GCUserPeer_class, "", "()V"); + peer_class = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "mono_android_GCUserPeer", true); + abort_unless (peer_class != nullptr, "Failed to load mono.android.GCUserPeer!"); + + peer_ctor = env->GetMethodID (peer_class, "", "()V"); + abort_unless (peer_ctor != nullptr, "Failed to load mono.android.GCUserPeer constructor!"); +} + +void TemporaryPeerMap::add (StronglyConnectedComponent &scc) noexcept +{ + abort_unless (peers != nullptr, "Temporary peer map must not be null"); + abort_unless (count < capacity, "Temporary peer map must not be full"); + + jobject temporary_peer = env->NewObject (peer_class, peer_ctor); + abort_unless (temporary_peer != nullptr, "Failed to create GC bridge temporary peer"); + + size_t temporary_peer_index = count++; + peers [temporary_peer_index] = temporary_peer; + scc.Count = encode_temporary_peer_index (temporary_peer_index); +} + +bool TemporaryPeerMap::has_temporary_peer (const StronglyConnectedComponent &scc) const noexcept +{ + return is_temporary_peer_index (scc.Count); +} + +jobject TemporaryPeerMap::get (const StronglyConnectedComponent &scc) const noexcept +{ + size_t temporary_peer_index = decode_temporary_peer_index (scc.Count); + abort_unless (temporary_peer_index < count, "Temporary peer index must be in range"); + + return peers [temporary_peer_index]; +} + +bool TemporaryPeerMap::is_temporary_peer_index (size_t count) noexcept +{ + return (count & temporary_peer_index_sign_bit) != 0; +} + +size_t TemporaryPeerMap::encode_temporary_peer_index (size_t index) noexcept +{ + abort_unless (!is_temporary_peer_index (index), "Temporary peer index is too large"); + return ~index; +} - abort_unless (GCUserPeer_class != nullptr && GCUserPeer_ctor != nullptr, "Failed to load mono.android.GCUserPeer!"); +size_t TemporaryPeerMap::decode_temporary_peer_index (size_t count) noexcept +{ + abort_unless (is_temporary_peer_index (count), "Temporary peer index must be negative"); + return ~count; } -BridgeProcessingShared::BridgeProcessingShared (MarkCrossReferencesArgs *args) noexcept +BridgeProcessingShared::BridgeProcessingShared (MarkCrossReferencesArgs *args, const BridgeProcessingCallbacks *host_callbacks) noexcept : env{ OSBridge::ensure_jnienv () }, - cross_refs{ args } + cross_refs{ args }, + callbacks{ host_callbacks != nullptr ? *host_callbacks : BridgeProcessingCallbacks {} } { if (args == nullptr) [[unlikely]] { Helpers::abort_application (LOG_GC, "Cross references argument is a NULL pointer"sv); @@ -44,25 +140,9 @@ void BridgeProcessingShared::process () noexcept void BridgeProcessingShared::prepare_for_java_collection () noexcept { - // Before looking at xrefs, scan the SCCs. During collection, an SCC has to behave like a - // single object. If the number of objects in the SCC is anything other than 1, the SCC - // must be doctored to mimic that one-object nature. - for (size_t i = 0; i < cross_refs->ComponentCount; i++) { - const StronglyConnectedComponent &scc = cross_refs->Components [i]; - prepare_scc_for_java_collection (i, scc); - } - - // Add the cross scc refs - for (size_t i = 0; i < cross_refs->CrossReferenceCount; i++) { - const ComponentCrossReference &xref = cross_refs->CrossReferences [i]; - add_cross_reference (xref.SourceGroupIndex, xref.DestinationGroupIndex); - } - - // With cross references processed, the temporary peer list can be released - for (const auto& [scc, temporary_peer] : temporary_peers) { - env->DeleteLocalRef (temporary_peer); - } + prepare_sccs_and_cross_references_for_java_collection (); + // Temporary peer indexes have been reset, so SCC counts are safe to use normally again. // Switch global to weak references for (size_t i = 0; i < cross_refs->ComponentCount; i++) { const StronglyConnectedComponent &scc = cross_refs->Components [i]; @@ -75,11 +155,32 @@ void BridgeProcessingShared::prepare_for_java_collection () noexcept } } -void BridgeProcessingShared::prepare_scc_for_java_collection (size_t scc_index, const StronglyConnectedComponent &scc) noexcept +void BridgeProcessingShared::prepare_sccs_and_cross_references_for_java_collection () noexcept +{ + TemporaryPeerMap temporary_peers { env, cross_refs }; + + // Before looking at xrefs, scan the SCCs. During collection, an SCC has to behave like a + // single object. If the number of objects in the SCC is anything other than 1, the SCC + // must be doctored to mimic that one-object nature. + for (size_t i = 0; i < cross_refs->ComponentCount; i++) { + const StronglyConnectedComponent &scc = cross_refs->Components [i]; + prepare_scc_for_java_collection (i, scc, temporary_peers); + } + + // Add the cross scc refs + for (size_t i = 0; i < cross_refs->CrossReferenceCount; i++) { + const ComponentCrossReference &xref = cross_refs->CrossReferences [i]; + add_cross_reference (xref.SourceGroupIndex, xref.DestinationGroupIndex, temporary_peers); + } +} + +void BridgeProcessingShared::prepare_scc_for_java_collection (size_t scc_index, const StronglyConnectedComponent &scc, TemporaryPeerMap &temporary_peers) noexcept { - // Count == 0 case: Some SCCs might have no IGCUserPeers associated with them, so we must create one + // Before looking at xrefs, scan the SCCs. During collection, an SCC has to behave like a + // single object. If the number of objects in the SCC is anything other than 1, the SCC + // must be doctored to mimic that one-object nature. if (scc.Count == 0) { - temporary_peers [scc_index] = env->NewObject (GCUserPeer_class, GCUserPeer_ctor); + temporary_peers.add (cross_refs->Components [scc_index]); return; } @@ -93,14 +194,14 @@ void BridgeProcessingShared::prepare_scc_for_java_collection (size_t scc_index, add_circular_references (scc); } -CrossReferenceTarget BridgeProcessingShared::select_cross_reference_target (size_t scc_index) noexcept +CrossReferenceTarget BridgeProcessingShared::select_cross_reference_target (size_t scc_index, TemporaryPeerMap &temporary_peers) noexcept { const StronglyConnectedComponent &scc = cross_refs->Components [scc_index]; - if (scc.Count == 0) { - const auto temporary_peer = temporary_peers.find (scc_index); - abort_unless (temporary_peer != temporary_peers.end(), "Temporary peer must be found in the map"); - return { .is_temporary_peer = true, .temporary_peer = temporary_peer->second }; + if (temporary_peers.has_temporary_peer (scc)) { + jobject temporary_peer = temporary_peers.get (scc); + abort_unless (temporary_peer != nullptr, "Temporary peer must not be null"); + return { .is_temporary_peer = true, .temporary_peer = temporary_peer }; } abort_unless (scc.Contexts [0] != nullptr, "SCC must have at least one context"); @@ -142,10 +243,10 @@ void BridgeProcessingShared::add_circular_references (const StronglyConnectedCom } } -void BridgeProcessingShared::add_cross_reference (size_t source_index, size_t dest_index) noexcept +void BridgeProcessingShared::add_cross_reference (size_t source_index, size_t dest_index, TemporaryPeerMap &temporary_peers) noexcept { - CrossReferenceTarget from = select_cross_reference_target (source_index); - CrossReferenceTarget to = select_cross_reference_target (dest_index); + CrossReferenceTarget from = select_cross_reference_target (source_index, temporary_peers); + CrossReferenceTarget to = select_cross_reference_target (dest_index, temporary_peers); if (add_reference (from.get_handle(), to.get_handle())) { from.mark_refs_added_if_needed (); @@ -219,6 +320,24 @@ void BridgeProcessingShared::clear_references (jobject handle) noexcept env->CallVoidMethod (handle, clear_method_id); } +bool BridgeProcessingShared::maybe_call_gc_user_peerable_add_managed_reference (JNIEnv *jni_env, jobject from, jobject to) noexcept +{ + if (callbacks.maybe_call_gc_user_peerable_add_managed_reference == nullptr) { + return false; + } + + return callbacks.maybe_call_gc_user_peerable_add_managed_reference (jni_env, from, to); +} + +bool BridgeProcessingShared::maybe_call_gc_user_peerable_clear_managed_references (JNIEnv *jni_env, jobject handle) noexcept +{ + if (callbacks.maybe_call_gc_user_peerable_clear_managed_references == nullptr) { + return false; + } + + return callbacks.maybe_call_gc_user_peerable_clear_managed_references (jni_env, handle); +} + void BridgeProcessingShared::take_global_ref (HandleContext &context) noexcept { abort_unless (context.control_block != nullptr, "Control block must not be null"); @@ -317,7 +436,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_error) (LOG_DEFAULT, "Failed to find monodroidAddReferences method"); #if DEBUG abort_if_invalid_pointer_argument (java_class, "java_class"); if (!Logger::gc_spew_enabled ()) [[likely]] { @@ -325,7 +444,7 @@ void BridgeProcessingShared::log_missing_add_references_method ([[maybe_unused]] } char *class_name = Host::get_java_class_name_for_TypeManager (java_class); - log_error (LOG_GC, "Missing monodroidAddReferences method for object of class {}", optional_string (class_name)); + (log_error) (LOG_GC, "Missing monodroidAddReferences method for object of class %s", optional_string (class_name)); free (class_name); #endif } @@ -333,7 +452,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_error) (LOG_DEFAULT, "Failed to find monodroidClearReferences method"); #if DEBUG abort_if_invalid_pointer_argument (java_class, "java_class"); if (!Logger::gc_spew_enabled ()) [[likely]] { @@ -341,7 +460,7 @@ void BridgeProcessingShared::log_missing_clear_references_method ([[maybe_unused } char *class_name = Host::get_java_class_name_for_TypeManager (java_class); - log_error (LOG_GC, "Missing monodroidClearReferences method for object of class {}", optional_string (class_name)); + (log_error) (LOG_GC, "Missing monodroidClearReferences method for object of class %s", optional_string (class_name)); free (class_name); #endif } @@ -364,10 +483,7 @@ void BridgeProcessingShared::log_weak_to_gref (jobject weak, jobject handle) noe return; } - OSBridge::_monodroid_gref_log ( - std::format ("take_global_ref wref={:#x} -> handle={:#x}\n"sv, - reinterpret_cast (weak), - reinterpret_cast (handle)).data ()); + OSBridge::_monodroid_gref_log ("take_global_ref wref=%p -> handle=%p\n", reinterpret_cast(weak), reinterpret_cast(handle)); } [[gnu::always_inline]] @@ -377,8 +493,7 @@ void BridgeProcessingShared::log_weak_ref_collected (jobject weak) noexcept return; } - OSBridge::_monodroid_gref_log ( - std::format ("handle {:#x}/W; was collected by a Java GC"sv, reinterpret_cast (weak)).data ()); + OSBridge::_monodroid_gref_log ("handle %p/W; was collected by a Java GC", reinterpret_cast(weak)); } [[gnu::always_inline]] @@ -388,7 +503,7 @@ void BridgeProcessingShared::log_take_weak_global_ref (jobject handle) noexcept return; } - OSBridge::_monodroid_gref_log (std::format ("take_weak_global_ref handle={:#x}\n"sv, reinterpret_cast (handle)).data ()); + OSBridge::_monodroid_gref_log ("take_weak_global_ref handle=%p\n", reinterpret_cast(handle)); } [[gnu::always_inline]] @@ -449,5 +564,5 @@ void BridgeProcessingShared::log_gc_summary () noexcept } } - log_info (LOG_GC, "GC cleanup summary: {} objects tested - resurrecting {}.", total, alive); + log_info_fmt (LOG_GC, "GC cleanup summary: %zu objects tested - resurrecting %zu.", total, alive); } diff --git a/src/native/clr/host/fastdev-assemblies.cc b/src/native/clr/host/fastdev-assemblies.cc index dea16523aaf..00c351d515e 100644 --- a/src/native/clr/host/fastdev-assemblies.cc +++ b/src/native/clr/host/fastdev-assemblies.cc @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -18,9 +19,9 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si { size = 0; - std::string const& override_dir_path = AndroidSystem::get_primary_override_dir (); + const char *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_debug (LOG_ASSEMBLY, "Override directory '%s' does not exist", optional_string (override_dir_path)); return nullptr; } @@ -29,9 +30,9 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si if (override_dir_fd < 0) [[unlikely]] { std::lock_guard dir_lock { override_dir_lock }; if (override_dir_fd < 0) [[likely]] { - override_dir = opendir (override_dir_path.c_str ()); + override_dir = opendir (override_dir_path); if (override_dir == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Failed to open override dir '{}'. {}"sv, override_dir_path, strerror (errno)); + log_warn (LOG_ASSEMBLY, "Failed to open override dir '%s'. %s", optional_string (override_dir_path), strerror (errno)); return nullptr; } override_dir_fd = dirfd (override_dir); @@ -40,20 +41,21 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si log_debug ( 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 (), + optional_string (override_dir_path) ); if (!Util::file_exists (override_dir_fd, name)) { - log_warn (LOG_ASSEMBLY, "FastDev assembly '{}' not found."sv, name); + log_warn (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_debug (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_warn (LOG_ASSEMBLY, "Unable to determine FastDev assembly '%.*s' file size", static_cast(name.length ()), name.data ()); return nullptr; } @@ -74,8 +76,9 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si if (asm_fd < 0) { log_warn ( 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) ); @@ -99,15 +102,16 @@ auto FastDevAssemblies::open_assembly (std::string_view const& name, int64_t &si log_warn ( 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_debug (LOG_ASSEMBLY, "Read %zd bytes of FastDev assembly '%.*s'", nread, static_cast(name.length ()), name.data ()); return reinterpret_cast(buffer); } diff --git a/src/native/clr/host/gc-bridge.cc b/src/native/clr/host/gc-bridge.cc index efd8f502ae4..6d2077ea7ce 100644 --- a/src/native/clr/host/gc-bridge.cc +++ b/src/native/clr/host/gc-bridge.cc @@ -1,3 +1,7 @@ +#include +#include +#include + #include #include #include @@ -31,7 +35,7 @@ void GCBridge::initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noe abort_if_invalid_pointer_argument (env, "env"); abort_if_invalid_pointer_argument (runtimeClass, "runtimeClass"); - BridgeProcessing::initialize_on_runtime_init (env, runtimeClass); + TemporaryPeerMap::initialize_on_runtime_init (env, runtimeClass); } void GCBridge::trigger_java_gc (JNIEnv *env) noexcept @@ -45,7 +49,7 @@ void GCBridge::trigger_java_gc (JNIEnv *env) noexcept env->ExceptionDescribe (); env->ExceptionClear (); - log_error (LOG_DEFAULT, "Java GC failed"); + (log_error) (LOG_DEFAULT, "Java GC failed"); } void GCBridge::mark_cross_references (MarkCrossReferencesArgs *args) noexcept @@ -55,8 +59,34 @@ void GCBridge::mark_cross_references (MarkCrossReferencesArgs *args) noexcept abort_unless (args->CrossReferences != nullptr || args->CrossReferenceCount == 0, "CrossReferences must not be null if CrossReferenceCount is greater than 0"); log_mark_cross_references_args_if_enabled (args); - shared_args.store (args); - shared_args_semaphore.release (); + send_and_signal (args); +} + +void GCBridge::send_and_signal (MarkCrossReferencesArgs *args) noexcept +{ + __atomic_store_n (&shared_args, args, __ATOMIC_RELEASE); + int ret = sem_post (&shared_args_semaphore); + abort_unless (ret == 0, "Failed to release GC bridge semaphore"); +} + +auto GCBridge::enter_bridge_processing () noexcept -> MarkCrossReferencesArgs* +{ + // wait until mark cross references args are set by the GC callback + int ret; + do { + ret = sem_wait (&shared_args_semaphore); + } while (ret == -1 && errno == EINTR); + abort_unless (ret == 0, "Failed to acquire GC bridge semaphore"); + + return __atomic_load_n (&shared_args, __ATOMIC_ACQUIRE); +} + +void GCBridge::process_bridge_args (MarkCrossReferencesArgs *args) noexcept +{ + // Bridge processing temporarily mutates args while it owns them. Make sure any + // changes are reverted before returning args to the GC bridge finish callback. + BridgeProcessing bridge_processing {args}; + bridge_processing.process (); } void GCBridge::bridge_processing () noexcept @@ -65,19 +95,19 @@ void GCBridge::bridge_processing () noexcept abort_unless (bridge_processing_finished_callback != nullptr, "GC bridge processing finished callback is not set"); while (true) { - // wait until mark cross references args are set by the GC callback - shared_args_semaphore.acquire (); - MarkCrossReferencesArgs *args = shared_args.load (); - + MarkCrossReferencesArgs *args = enter_bridge_processing (); bridge_processing_started_callback (args); - - BridgeProcessing bridge_processing {args}; - bridge_processing.process (); - + process_bridge_args (args); bridge_processing_finished_callback (java_marshal_value_manager_handle, args); } } +auto GCBridge::bridge_processing_thread_entry ([[maybe_unused]] void *arg) noexcept -> void* +{ + bridge_processing (); + return nullptr; +} + [[gnu::always_inline]] void GCBridge::log_mark_cross_references_args_if_enabled (MarkCrossReferencesArgs *args) noexcept { @@ -85,13 +115,13 @@ void GCBridge::log_mark_cross_references_args_if_enabled (MarkCrossReferencesArg return; } - log_info (LOG_GC, "cross references callback invoked with {} sccs and {} xrefs.", args->ComponentCount, args->CrossReferenceCount); + log_info_fmt (LOG_GC, "cross references callback invoked with %zu sccs and %zu xrefs.", args->ComponentCount, args->CrossReferenceCount); JNIEnv *env = OSBridge::ensure_jnienv (); for (size_t i = 0; i < args->ComponentCount; ++i) { const StronglyConnectedComponent &scc = args->Components [i]; - log_info (LOG_GC, "group {} with {} objects", i, scc.Count); + log_info_fmt (LOG_GC, "group %zu with %zu objects", i, scc.Count); for (size_t j = 0; j < scc.Count; ++j) { log_handle_context (env, scc.Contexts [j]); } @@ -104,7 +134,7 @@ void GCBridge::log_mark_cross_references_args_if_enabled (MarkCrossReferencesArg for (size_t i = 0; i < args->CrossReferenceCount; ++i) { size_t source_index = args->CrossReferences [i].SourceGroupIndex; size_t dest_index = args->CrossReferences [i].DestinationGroupIndex; - log_info_nocheck_fmt (LOG_GC, "xref [{}] {} -> {}", i, source_index, dest_index); + log_info_fmt (LOG_GC, "xref [%zu] %zu -> %zu", i, source_index, dest_index); } } @@ -118,9 +148,9 @@ void GCBridge::log_handle_context (JNIEnv *env, HandleContext *ctx) noexcept jclass java_class = env->GetObjectClass (handle); if (java_class != nullptr) { char *class_name = Host::get_java_class_name_for_TypeManager (java_class); - log_info (LOG_GC, "gref {:#x} [{}]", reinterpret_cast (handle), class_name); + log_info_fmt (LOG_GC, "gref %p [%s]", reinterpret_cast(handle), optional_string (class_name)); free (class_name); } else { - log_info (LOG_GC, "gref {:#x} [unknown class]", reinterpret_cast (handle)); + log_info_fmt (LOG_GC, "gref %p [unknown class]", reinterpret_cast(handle)); } } diff --git a/src/native/clr/host/host-shared.cc b/src/native/clr/host/host-shared.cc index 5015a7a7a34..5909283a498 100644 --- a/src/native/clr/host/host-shared.cc +++ b/src/native/clr/host/host-shared.cc @@ -1,3 +1,5 @@ +#include + #include #include @@ -12,13 +14,13 @@ auto HostCommon::get_java_class_name_for_TypeManager (jclass klass) noexcept -> JNIEnv *env = OSBridge::ensure_jnienv (); jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); if (name == nullptr) { - log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass)); + log_write_fmt (LOG_DEFAULT, LogLevel::Error, "Failed to obtain Java class name for object at %p", reinterpret_cast(klass)); return nullptr; } const char *mutf8 = env->GetStringUTFChars (name, nullptr); if (mutf8 == nullptr) { - log_error (LOG_DEFAULT, "Failed to convert Java class name to UTF8 (out of memory?)"sv); + log_write (LOG_DEFAULT, LogLevel::Error, "Failed to convert Java class name to UTF8 (out of memory?)"); env->DeleteLocalRef (name); return nullptr; } @@ -34,4 +36,4 @@ auto HostCommon::get_java_class_name_for_TypeManager (jclass klass) noexcept -> } return ret; -} \ No newline at end of file +} diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 3e84ef930d8..f98b3180f92 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -35,14 +36,14 @@ using namespace xamarin::android; void Host::clr_error_writer (const char *message) noexcept { - log_error (LOG_DEFAULT, "CLR error: {}", optional_string (message)); + log_error (LOG_DEFAULT, "CLR error: %s", optional_string (message)); } size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size_t value_buffer_size, [[maybe_unused]] void *contract_context) noexcept { // NOTE: this code was tested locally, but it's **not** used by CoreCLR yet, so there's been no // "live" testing. - log_debug (LOG_DEFAULT, "clr_get_runtime_property (\"{}\"...)"sv, optional_string (key)); + log_debug (LOG_DEFAULT, "clr_get_runtime_property (\"%s\"...)", optional_string (key)); if (application_config.number_of_runtime_properties == 0) [[unlikely]] { log_debug (LOG_DEFAULT, "No runtime properties defined"sv); return 0; @@ -52,7 +53,7 @@ size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size if (key == nullptr || value_buffer == nullptr || value_buffer_size <= 1) [[unlikely]] { log_warn ( LOG_DEFAULT, - "runtime property retrieval API called with invalid arguments. key == {:p}; value_buffer == {:p}; value_buffer_size == {}"sv, + "runtime property retrieval API called with invalid arguments. key == %p; value_buffer == %p; value_buffer_size == %zu", static_cast(key), static_cast(value_buffer), value_buffer_size @@ -66,7 +67,7 @@ size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size auto less_than = [](RuntimePropertyIndexEntry const& entry, hash_t key) -> bool { return entry.key_hash < key; }; ssize_t idx = Search::binary_search (key_hash, runtime_property_index, application_config.number_of_runtime_properties); if (idx < 0) { - log_debug (LOG_DEFAULT, "Runtime property '{}' not found"sv, key); + log_debug (LOG_DEFAULT, "Runtime property '%s' not found", key); return 0; } @@ -77,7 +78,7 @@ size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size if (prop.value_size > value_buffer_size) { log_warn ( LOG_DEFAULT, - "Value of property '{}' is longer than available buffer space. Need {}b, available {}b"sv, + "Value of property '%s' is longer than available buffer space. Need %u b, available %zu b", key, prop.value_size, value_buffer_size @@ -91,7 +92,7 @@ size_t Host::clr_get_runtime_property (const char *key, char *value_buffer, size 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_debug (LOG_DEFAULT, "clr_external_assembly_probe (\"%s\"...)", optional_string (path)); if (data_start == nullptr || size == nullptr) { return false; // TODO: abort instead? } @@ -108,11 +109,11 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int log_debug ( LOG_ASSEMBLY, - "Assembly '{}' data {}mapped ({:p}, {} bytes)", + "Assembly '%s' data %smapped (%p, %lld bytes)", optional_string (name), - data_start == nullptr ? "not "sv : ""sv, + data_start == nullptr ? "not " : "", data_start, - size + static_cast(size) ); return data_start != nullptr && size > 0; @@ -126,7 +127,7 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int log_warn ( LOG_ASSEMBLY, - "Assembly '{}' not found in FastDev override directory. Attempting to load from assembly store"sv, + "Assembly '%s' not found in FastDev override directory. Attempting to load from assembly store", optional_string (path) ); } @@ -138,11 +139,11 @@ bool Host::clr_external_assembly_probe (const char *path, void **data_start, int auto Host::zip_scan_callback (std::string_view const& apk_path, int apk_fd, dynamic_local_string const& entry_name, uint32_t offset, uint32_t size) -> bool { - log_debug (LOG_ASSEMBLY, "zip entry: {}"sv, entry_name.get ()); + log_debug (LOG_ASSEMBLY, "zip entry: %s", entry_name.get ()); if (!found_assembly_store) { found_assembly_store = Zip::assembly_store_file_path.compare (0, entry_name.length (), entry_name.get ()) == 0; if (found_assembly_store) { - log_debug (LOG_ASSEMBLY, "Found assembly store in '{}': {}"sv, apk_path, Zip::assembly_store_file_path); + log_debug (LOG_ASSEMBLY, "Found assembly store in '%.*s': %.*s", static_cast(apk_path.length ()), apk_path.data (), static_cast(Zip::assembly_store_file_path.length ()), Zip::assembly_store_file_path.data ()); AssemblyStore::map (apk_fd, apk_path, Zip::assembly_store_file_path, offset, size); return false; // This will make the scanner keep the APK open } @@ -152,10 +153,10 @@ auto Host::zip_scan_callback (std::string_view const& apk_path, int apk_fd, dyna return false; } - log_debug (LOG_ASSEMBLY, "Found shared library in '{}': {}"sv, apk_path, entry_name.get ()); + log_debug (LOG_ASSEMBLY, "Found shared library in '%.*s': %s", static_cast(apk_path.length ()), apk_path.data (), entry_name.get ()); std::string_view lib_name { entry_name.get () + Zip::lib_prefix.length () }; hash_t name_hash = xxhash::hash (lib_name.data (), lib_name.length ()); - log_debug (LOG_ASSEMBLY, "Library name is: {}; hash == 0x{:x}", lib_name, name_hash); + log_debug (LOG_ASSEMBLY, "Library name is: %.*s; hash == 0x%zx", static_cast(lib_name.length ()), lib_name.data (), static_cast(name_hash)); DSOApkEntry *apk_entry = MonodroidDl::find_dso_apk_entry (name_hash); if (apk_entry == nullptr) { @@ -172,7 +173,7 @@ auto Host::zip_scan_callback (std::string_view const& apk_path, int apk_fd, dyna 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_debug (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]] { @@ -203,7 +204,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_warn (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 @@ -220,7 +221,7 @@ 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_debug (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 ()); int store_fd = openat (dir_fd, cur->d_name, O_RDONLY); if (store_fd < 0) { Helpers::abort_application ( @@ -312,10 +313,13 @@ auto Host::create_delegate ( &delegate ); log_debug (LOG_ASSEMBLY, - "{}@{}.{} delegate creation result == {:x}; delegate == {:p}"sv, - assembly_name, - type_name, - method_name, + "%.*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 ); @@ -344,7 +348,7 @@ void Host::preload_jni_libraries () noexcept return; } - log_debug (LOG_ASSEMBLY, "DSO jni preloads index stride == {}", dso_jni_preloads_idx_stride); + log_debug (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 ( @@ -364,11 +368,12 @@ void Host::preload_jni_libraries () noexcept log_debug ( LOG_ASSEMBLY, - "Preloading JNI shared library: {} (entry's index: {}; real name hash: {:x}; name hash: {:x})", - dso_name, + "Preloading JNI shared library: %.*s (entry's index: %zu; real name hash: %zx; name hash: %zx)", + static_cast(dso_name.length ()), + dso_name.data (), entry_index, - entry.real_name_hash, - entry.hash + static_cast(entry.real_name_hash), + static_cast(entry.hash) ); void *handle = MonodroidDl::monodroid_dlopen (&entry, dso_name, RTLD_NOW); @@ -381,9 +386,10 @@ void Host::preload_jni_libraries () noexcept log_debug ( 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; } @@ -519,7 +525,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_info (LOG_GC, "GREF GC Threshold: %d", init.grefGcThreshold); OSBridge::initialize_on_runtime_init (env, runtimeClass); GCBridge::initialize_on_runtime_init (env, runtimeClass); @@ -528,7 +534,7 @@ 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_debug (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); @@ -573,7 +579,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_debug (LOG_ASSEMBLY, "Registering type: '%s'", managed_type_name.get ()); env->ReleaseStringUTFChars (managedType, mt_ptr); // TODO: must attach thread to the runtime here diff --git a/src/native/clr/host/internal-pinvokes-shared.cc b/src/native/clr/host/internal-pinvokes-shared.cc index b828fdcfe15..9d19ce3d23f 100644 --- a/src/native/clr/host/internal-pinvokes-shared.cc +++ b/src/native/clr/host/internal-pinvokes-shared.cc @@ -57,30 +57,36 @@ 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 }); + if ((log_categories & category) != 0) { + log_write (category, LogLevel::Debug, message); + } break; case LogLevel::Info: - log_info_nocheck (category, std::string_view { message }); + if ((log_categories & category) != 0) { + 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 }); + if ((log_categories & category) != 0) { + 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 cc2122e317e..e089afd767e 100644 --- a/src/native/clr/host/os-bridge.cc +++ b/src/native/clr/host/os-bridge.cc @@ -1,4 +1,7 @@ -#include +#include +#include +#include +#include #include #include @@ -8,6 +11,46 @@ using namespace xamarin::android; +namespace { + constexpr size_t LOG_LINE_BUFFER_SIZE = 512; + + void write_logcat_line (LogCategories category, const char *line, size_t line_len) noexcept + { + char local_buffer[LOG_LINE_BUFFER_SIZE]; + char *buffer = local_buffer; + + if (line_len >= sizeof (local_buffer)) { + buffer = static_cast(malloc (line_len + 1)); + if (buffer == nullptr) { + log_write (category, LogLevel::Debug, ""); + return; + } + } + + memcpy (buffer, line, line_len); + buffer[line_len] = '\0'; + log_write (category, LogLevel::Debug, buffer); + + if (buffer != local_buffer) { + free (buffer); + } + } + + void write_gref_message (const char *message, FILE *gref_log) noexcept + { + if (Logger::gref_to_logcat ()) { + log_write (LOG_GREF, LogLevel::Debug, optional_string (message)); + } + + if (gref_log == nullptr) { + return; + } + + fputs (optional_string (message), gref_log); + fflush (gref_log); + } +} + void OSBridge::initialize_on_onload (JavaVM *vm, JNIEnv *env) noexcept { abort_if_invalid_pointer_argument (env, "env"); @@ -90,50 +133,66 @@ 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_write (category, LogLevel::Warn, "Unable to write stack trace, managed runtime passed a NULL string."); return; } - const std::string_view trace { from }; - if (trace.empty ()) [[unlikely]] { - log_warn (category, "Empty stack trace passed by the managed runtime."); + if (*from == '\0') [[unlikely]] { + log_write (category, LogLevel::Warn, "Empty stack trace passed by the managed runtime."); return; } - for (const auto segment : std::views::split (trace, '\n')) { - const std::string_view line { segment }; + const char *line = from; + while (line != nullptr && *line != '\0') { + const char *newline = strchr (line, '\n'); + size_t line_len = newline == nullptr ? strlen (line) : static_cast(newline - line); if ((category == LOG_GREF && Logger::gref_to_logcat ()) || (category == LOG_LREF && Logger::lref_to_logcat ())) { - log_debug (category, "{}"sv, line); + write_logcat_line (category, line, line_len); } - if (to == nullptr) { - continue; + if (to != nullptr) { + fwrite (line, sizeof (char), line_len, to); + fputc ('\n', to); + fflush (to); } - fwrite (line.data (), sizeof (std::string_view::value_type), line.length (), to); - fputc ('\n', to); - fflush (to); + if (newline == nullptr) { + break; + } + line = newline + 1; } } void OSBridge::_monodroid_gref_log (const char *message) noexcept { - if (Logger::gref_to_logcat ()) { - log_debug (LOG_GREF, "{}"sv, optional_string (message)); + FILE *gref_log = Logger::gref_log (); + if (!Logger::gref_to_logcat () && gref_log == nullptr) { + return; } - if (Logger::gref_log () == nullptr) { + write_gref_message (message, gref_log); +} + +void OSBridge::_monodroid_gref_log_fmt (const char *format, ...) noexcept +{ + FILE *gref_log = Logger::gref_log (); + if (!Logger::gref_to_logcat () && gref_log == nullptr) { return; } - fprintf (Logger::gref_log (), "%s", optional_string (message)); - fflush (Logger::gref_log ()); + char message[LOG_LINE_BUFFER_SIZE]; + va_list args; + va_start (args, format); + vsnprintf (message, sizeof (message), optional_string (format), args); + va_end (args); + + write_gref_message (message, gref_log); } [[gnu::always_inline, gnu::flatten]] -void OSBridge::log_it (LogCategories category, std::string const& line, FILE *to, const char *const from, bool logcat_enabled) noexcept +void OSBridge::log_it (LogCategories category, const char *line, FILE *to, const char *const from, bool logcat_enabled) noexcept { log_write (category, LogLevel::Info, line); @@ -146,13 +205,28 @@ void OSBridge::log_it (LogCategories category, std::string const& line, FILE *to return; } - fwrite (line.c_str (), sizeof (std::string::value_type), line.length (), to); + fwrite (line, sizeof (char), strlen (line), to); fputc ('\n', to); _write_stack_trace (to, from, category); fflush (to); } +void OSBridge::log_itf (LogCategories category, FILE *to, const char *from, bool logcat_enabled, const char *format, ...) noexcept +{ + if (!logcat_enabled && to == nullptr) { + return; + } + + char log_line[LOG_LINE_BUFFER_SIZE]; + va_list args; + va_start (args, format); + vsnprintf (log_line, sizeof (log_line), optional_string (format), args); + va_end (args); + + log_it (category, log_line, to, from, logcat_enabled); +} + auto OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from) noexcept -> int { int c = _monodroid_gref_inc (); @@ -161,8 +235,12 @@ auto OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject } int wc = __atomic_load_n (&gc_weak_gref_count, __ATOMIC_RELAXED); - const std::string log_line = std::format ( - "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})"sv, + log_itf ( + LOG_GREF, + Logger::gref_log (), + from, + Logger::gref_to_logcat (), + "+g+ grefc %d gwrefc %d obj-handle %p/%c -> new-handle %p/%c from thread '%s'(%d)", c, wc, reinterpret_cast(curHandle), @@ -173,7 +251,6 @@ auto OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject threadId ); - log_it (LOG_GREF, log_line, Logger::gref_log (), from, Logger::gref_to_logcat ()); return c; } @@ -185,8 +262,12 @@ void OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char } int wc = __atomic_load_n (&gc_weak_gref_count, __ATOMIC_RELAXED); - const std::string log_line = std::format ( - "-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})"sv, + log_itf ( + LOG_GREF, + Logger::gref_log (), + from, + Logger::gref_to_logcat (), + "-g- grefc %d gwrefc %d handle %p/%c from thread '%s'(%d)", c, wc, reinterpret_cast(handle), @@ -194,8 +275,6 @@ void OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char optional_string (threadName), threadId ); - - log_it (LOG_GREF, log_line, Logger::gref_log (), from, Logger::gref_to_logcat ()); } void OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from) @@ -206,8 +285,12 @@ void OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobjec } int gc = __atomic_load_n (&gc_gref_count, __ATOMIC_RELAXED); - const std::string log_line = std::format ( - "+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})"sv, + log_itf ( + LOG_GREF, + Logger::gref_log (), + from, + Logger::gref_to_logcat (), + "+w+ grefc %d gwrefc %d obj-handle %p/%c -> new-handle %p/%c from thread '%s'(%d)", gc, c, reinterpret_cast(curHandle), @@ -217,8 +300,6 @@ void OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobjec optional_string (threadName), threadId ); - - log_it (LOG_GREF, log_line, Logger::gref_log (), from, Logger::gref_to_logcat ()); } void @@ -228,16 +309,18 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c return; } - const std::string log_line = std::format ( - "+l+ lrefc {} handle {:p}/{} from thread '{}'({})"sv, + log_itf ( + LOG_LREF, + Logger::lref_log (), + from, + Logger::lref_to_logcat (), + "+l+ lrefc %d handle %p/%c from thread '%s'(%d)", lrefc, reinterpret_cast(handle), type, optional_string (threadName), threadId ); - - log_it (LOG_LREF, log_line, Logger::lref_log (), from, Logger::lref_to_logcat ()); } void OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *threadName, int threadId, const char *from) @@ -248,8 +331,12 @@ void OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const cha } int gc = __atomic_load_n (&gc_gref_count, __ATOMIC_RELAXED); - const std::string log_line = std::format ( - "-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})"sv, + log_itf ( + LOG_GREF, + Logger::gref_log (), + from, + Logger::gref_to_logcat (), + "-w- grefc %d gwrefc %d handle %p/%c from thread '%s'(%d)", gc, c, reinterpret_cast(handle), @@ -257,8 +344,6 @@ void OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const cha optional_string (threadName), threadId ); - - log_it (LOG_GREF, log_line, Logger::gref_log (), from, Logger::gref_to_logcat ()); } void OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, const char *threadName, int threadId, const char *from) @@ -267,14 +352,16 @@ void OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, return; } - const std::string log_line = std::format ( - "-l- lrefc {} handle {:p}/{} from thread '{}'({})"sv, + log_itf ( + LOG_LREF, + Logger::lref_log (), + from, + Logger::lref_to_logcat (), + "-l- lrefc %d handle %p/%c from thread '%s'(%d)", lrefc, reinterpret_cast(handle), type, optional_string (threadName), threadId ); - - log_it (LOG_LREF, log_line, Logger::lref_log (), from, Logger::lref_to_logcat ()); } diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 85e5a37a3a5..3bfd47b58db 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -67,7 +67,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_debug (LOG_ASSEMBLY, "typemap: map {} -> {} uses strings", from_name, to_name); + log_debug (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]] { @@ -97,7 +97,7 @@ auto TypeMapper::find_index_by_hash (const char *typeName, const TypeMapEntry *m return find_index_by_name (typeName, map, name_map, from_name, to_name); } - log_debug (LOG_ASSEMBLY, "typemap: map {} -> {} uses hashes"sv, from_name, to_name); + log_debug (LOG_ASSEMBLY, "typemap: map %.*s -> %.*s uses hashes", static_cast(from_name.length ()), from_name.data (), static_cast(to_name.length ()), to_name.data ()); auto equal = [](TypeMapEntry const& entry, hash_t key) -> bool { if (entry.from == std::numeric_limits::max ()) [[unlikely]] { @@ -122,7 +122,7 @@ 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_debug (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; } @@ -131,10 +131,12 @@ auto TypeMapper::index_to_name (ssize_t idx, const char* typeName, const TypeMap log_debug ( 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; @@ -159,7 +161,7 @@ auto TypeMapper::managed_to_java_debug (const char *typeName, const uint8_t *mvi // We explicitly trust the build process here, with regards to validity of offsets full_type_name.append (&type_map_assembly_names[assm.name_offset], assm.name_length); } else { - log_warn (LOG_ASSEMBLY, "typemap: unable to look up assembly name for type '{}', trying without it."sv, typeName); + log_warn (LOG_ASSEMBLY, "typemap: unable to look up assembly name for type '%s', trying without it.", optional_string (typeName)); } // If hashes are used for matching, the type names array is not used. If, however, string-based matching is in @@ -220,12 +222,12 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m if (mvid == nullptr) { log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); } else { - log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found."sv, MonoGuidString (mvid).c_str ()); + log_info (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_debug (LOG_ASSEMBLY, "typemap: found module matching MVID [%s]", MonoGuidString (mvid).c_str ()); hash_t name_hash = xxhash::hash (typeName, strlen (typeName)); // We implicitly trust the build process that the indexes are correct. This is by design, the libxamarin-app.so built @@ -236,10 +238,10 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m if (match->duplicate_count > 0 && match->duplicate_map_index < std::numeric_limitsduplicate_map_index)>::max ()) { log_debug ( LOG_ASSEMBLY, - "typemap: searching module [{}] duplicate map for type '{}' (hash {:x})"sv, + "typemap: searching module [%s] duplicate map for type '%s' (hash %zx)", MonoGuidString (mvid).c_str (), optional_string (typeName), - name_hash + static_cast(name_hash) ); const TypeMapModuleEntry *const duplicate_map = &modules_duplicates_data[match->duplicate_map_index]; @@ -249,11 +251,12 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m if (entry == nullptr) { log_warn ( LOG_ASSEMBLY, - "typemap: managed type '{}' (hash {:x}) not found in module [{}] ({})."sv, + "typemap: managed type '%s' (hash %zx) not found in module [%s] (%.*s).", optional_string (typeName), - name_hash, + static_cast(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; } @@ -262,11 +265,12 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m if (entry->java_map_index >= java_type_count) [[unlikely]] { log_warn ( LOG_ASSEMBLY, - "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) has invalid Java type index {}"sv, + "typemap: managed type '%s' (hash %zx) in module [%s] (%.*s) has invalid Java type index %u", optional_string (typeName), - name_hash, + static_cast(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; @@ -276,11 +280,12 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m if (java_entry.java_name_index >= java_type_names_size) [[unlikely]] { log_warn ( 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 %zx) in module [%s] (%.*s) points to invalid Java type at index %u (invalid type name index %u)", optional_string (typeName), - name_hash, + static_cast(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,17 +295,18 @@ 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_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index %u", entry->java_map_index); } log_debug ( LOG_ASSEMBLY, - "typemap: managed type '{}' (hash {:x}) in module [{}] ({}) corresponds to Java type '{}'"sv, + "typemap: managed type '%s' (hash %zx) in module [%s] (%.*s) corresponds to Java type '%s'", optional_string (typeName), - name_hash, + static_cast(name_hash), MonoGuidString (mvid).c_str (), - std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), - ret + static_cast(match->assembly_name_length), + &managed_assembly_names[match->assembly_name_index], + optional_string (ret) ); return ret; @@ -310,7 +316,7 @@ auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *m [[gnu::flatten]] auto TypeMapper::managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char* { - log_debug (LOG_ASSEMBLY, "managed_to_java: looking up type '{}'"sv, optional_string (typeName)); + log_debug (LOG_ASSEMBLY, "managed_to_java: looking up type '%s'", optional_string (typeName)); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::ManagedToJava); } @@ -363,10 +369,10 @@ auto TypeMapper::java_to_managed_debug (const char *java_type_name, char const** log_debug ( 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 '%x'", optional_string (java_type_name), - name, - *assembly_name, + optional_string (name), + optional_string (*assembly_name), *managed_type_token_id ); @@ -392,8 +398,8 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const if (java_type_name == nullptr) { log_warn ( LOG_ASSEMBLY, - "typemap: required parameter `{}` not passed to {}"sv, - "java_type_name"sv, + "typemap: required parameter `%s` not passed to %s", + "java_type_name", __PRETTY_FUNCTION__ ); } @@ -401,8 +407,8 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const if (assembly_name == nullptr) { log_warn ( LOG_ASSEMBLY, - "typemap: required parameter `{}` not passed to {}"sv, - "assembly_name"sv, + "typemap: required parameter `%s` not passed to %s", + "assembly_name", __PRETTY_FUNCTION__ ); } @@ -410,8 +416,8 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const if (managed_type_token_id == nullptr) { log_warn ( LOG_ASSEMBLY, - "typemap: required parameter `{}` not passed to {}"sv, - "managed_type_token_id"sv, + "typemap: required parameter `%s` not passed to %s", + "managed_type_token_id", __PRETTY_FUNCTION__ ); } @@ -424,9 +430,9 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const if (java_entry == nullptr) { log_info ( 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 %zx)", optional_string (java_type_name), - name_hash + static_cast(name_hash) ); return false; @@ -438,11 +444,13 @@ auto TypeMapper::java_to_managed_release (const char *java_type_name, char const log_debug ( LOG_ASSEMBLY, - "Java type '{}' corresponds to managed type '{}' (token 0x{:x} in assembly '{}')"sv, + "Java type '%s' corresponds to managed type '%.*s' (token 0x%x 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; @@ -452,7 +460,7 @@ 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_debug (LOG_ASSEMBLY, "java_to_managed: looking up type '%s'", optional_string (java_type_name)); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::JavaToManaged); } diff --git a/src/native/clr/include/host/bridge-processing-shared.hh b/src/native/clr/include/host/bridge-processing-shared.hh index 0e0a9a6244c..35863ca4e26 100644 --- a/src/native/clr/include/host/bridge-processing-shared.hh +++ b/src/native/clr/include/host/bridge-processing-shared.hh @@ -1,7 +1,8 @@ #pragma once +#include + #include -#include #include #include @@ -20,27 +21,65 @@ struct CrossReferenceTarget void mark_refs_added_if_needed () noexcept; }; +struct BridgeProcessingCallbacks +{ + bool (*maybe_call_gc_user_peerable_add_managed_reference) (JNIEnv *env, jobject from, jobject to) noexcept; + bool (*maybe_call_gc_user_peerable_clear_managed_references) (JNIEnv *env, jobject handle) noexcept; +}; + +class TemporaryPeerMap +{ +public: + explicit TemporaryPeerMap (JNIEnv *env, MarkCrossReferencesArgs *cross_refs) noexcept; + ~TemporaryPeerMap () noexcept; + + static void initialize_on_runtime_init (JNIEnv *env, jclass runtimeClass) noexcept; + + void add (StronglyConnectedComponent &scc) noexcept; + bool has_temporary_peer (const StronglyConnectedComponent &scc) const noexcept; + jobject get (const StronglyConnectedComponent &scc) const noexcept; + +private: + // Count is unsigned, so encode the temporary peer index as ~index. This stores the same bit + // pattern as -(index + 1), giving us a sign bit marker while preserving index 0. + // The .NET 11 GC bridge implementation appears safe to temporarily mutate here: once it + // hands us MarkCrossReferencesArgs, it does not inspect Count again before freeing the data. + // The destructor always resets temporary markers before returning cross_refs to the runtime. + static constexpr size_t temporary_peer_index_sign_bit = ~(~size_t { 0 } >> 1); + + static bool is_temporary_peer_index (size_t count) noexcept; + static size_t encode_temporary_peer_index (size_t index) noexcept; + static size_t decode_temporary_peer_index (size_t count) noexcept; + + static inline jclass peer_class = nullptr; + static inline jmethodID peer_ctor = nullptr; + + JNIEnv *env; + MarkCrossReferencesArgs *cross_refs; + jobject *peers {}; + size_t count {}; + size_t capacity {}; +}; + class BridgeProcessingShared { public: - explicit BridgeProcessingShared (MarkCrossReferencesArgs *args) noexcept; - static void initialize_on_runtime_init (JNIEnv *jniEnv, jclass runtimeClass) noexcept; + explicit BridgeProcessingShared (MarkCrossReferencesArgs *args, const BridgeProcessingCallbacks *callbacks = nullptr) noexcept; + void process () noexcept; private: JNIEnv* env; MarkCrossReferencesArgs *cross_refs; - std::unordered_map temporary_peers; - - static inline jclass GCUserPeer_class = nullptr; - static inline jmethodID GCUserPeer_ctor = nullptr; + BridgeProcessingCallbacks callbacks; void prepare_for_java_collection () noexcept; - void prepare_scc_for_java_collection (size_t scc_index, const StronglyConnectedComponent &scc) noexcept; + void prepare_sccs_and_cross_references_for_java_collection () noexcept; + void prepare_scc_for_java_collection (size_t scc_index, const StronglyConnectedComponent &scc, TemporaryPeerMap &temporary_peers) noexcept; void take_weak_global_ref (const HandleContext &context) noexcept; void add_circular_references (const StronglyConnectedComponent &scc) noexcept; - void add_cross_reference (size_t source_index, size_t dest_index) noexcept; - CrossReferenceTarget select_cross_reference_target (size_t scc_index) noexcept; + void add_cross_reference (size_t source_index, size_t dest_index, TemporaryPeerMap &temporary_peers) noexcept; + CrossReferenceTarget select_cross_reference_target (size_t scc_index, TemporaryPeerMap &temporary_peers) noexcept; bool add_reference (jobject from, jobject to) noexcept; void cleanup_after_java_collection () noexcept; @@ -50,6 +89,8 @@ private: void clear_references_if_needed (const HandleContext &context) noexcept; void clear_references (jobject handle) noexcept; + bool maybe_call_gc_user_peerable_add_managed_reference (JNIEnv *env, jobject from, jobject to) noexcept; + bool maybe_call_gc_user_peerable_clear_managed_references (JNIEnv *env, jobject handle) noexcept; void log_missing_add_references_method (jclass java_class) noexcept; void log_missing_clear_references_method (jclass java_class) noexcept; @@ -60,9 +101,4 @@ private: void log_gref_delete (jobject handle) noexcept; void log_weak_ref_delete (jobject weak) noexcept; void log_gc_summary () noexcept; - - // These methods must be implemented by every host individually - // Both methods below return `true` if they processed the call - virtual auto maybe_call_gc_user_peerable_add_managed_reference (JNIEnv *env, jobject from, jobject to) noexcept -> bool = 0; - virtual auto maybe_call_gc_user_peerable_clear_managed_references (JNIEnv *env, jobject handle) noexcept -> bool = 0; }; diff --git a/src/native/clr/include/host/bridge-processing.hh b/src/native/clr/include/host/bridge-processing.hh index 2d638c0e6ba..1a2ab64dd1d 100644 --- a/src/native/clr/include/host/bridge-processing.hh +++ b/src/native/clr/include/host/bridge-processing.hh @@ -10,15 +10,4 @@ public: explicit BridgeProcessing (MarkCrossReferencesArgs *args) noexcept : BridgeProcessingShared (args) {} - -private: - auto maybe_call_gc_user_peerable_add_managed_reference ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject from, [[maybe_unused]] jobject to) noexcept -> bool override final - { - return false; // no-op for CoreCLR, we didn't process the call - } - - auto maybe_call_gc_user_peerable_clear_managed_references ([[maybe_unused]] JNIEnv *env, [[maybe_unused]] jobject handle) noexcept -> bool override final - { - return false; // no-op for CoreCLR, we didn't process the call - } }; diff --git a/src/native/clr/include/host/gc-bridge.hh b/src/native/clr/include/host/gc-bridge.hh index 6430e6f237a..ce1e7844b59 100644 --- a/src/native/clr/include/host/gc-bridge.hh +++ b/src/native/clr/include/host/gc-bridge.hh @@ -1,11 +1,9 @@ #pragma once -#include +#include +#include + #include -#include -#include -#include -#include #include @@ -74,8 +72,14 @@ namespace xamarin::android { GCBridge::bridge_processing_started_callback = bridge_processing_started; GCBridge::bridge_processing_finished_callback = bridge_processing_finished; - bridge_processing_thread = std::thread { GCBridge::bridge_processing }; - bridge_processing_thread.detach (); + int ret = sem_init (&shared_args_semaphore, 0, 0); + abort_unless (ret == 0, "Failed to initialize GC bridge semaphore"); + + ret = pthread_create (&bridge_processing_thread, nullptr, GCBridge::bridge_processing_thread_entry, nullptr); + abort_unless (ret == 0, "Failed to create GC bridge processing thread"); + + ret = pthread_detach (bridge_processing_thread); + abort_unless (ret == 0, "Failed to detach GC bridge processing thread"); return mark_cross_references; } @@ -83,10 +87,9 @@ namespace xamarin::android { static void trigger_java_gc (JNIEnv *env) noexcept; private: - static inline std::thread bridge_processing_thread {}; - - static inline std::binary_semaphore shared_args_semaphore{0}; - static inline std::atomic shared_args; + static inline pthread_t bridge_processing_thread {}; + static inline sem_t shared_args_semaphore {}; + static inline MarkCrossReferencesArgs *shared_args = nullptr; static inline jobject Runtime_instance = nullptr; static inline jmethodID Runtime_gc = nullptr; @@ -96,7 +99,11 @@ namespace xamarin::android { static inline BridgeProcessingFinishedFtn bridge_processing_finished_callback = nullptr; static void bridge_processing () noexcept; + static auto bridge_processing_thread_entry (void *arg) noexcept -> void*; static void mark_cross_references (MarkCrossReferencesArgs *args) noexcept; + static MarkCrossReferencesArgs* enter_bridge_processing () noexcept; + static void send_and_signal (MarkCrossReferencesArgs *args) noexcept; + static void process_bridge_args (MarkCrossReferencesArgs *args) noexcept; static void log_mark_cross_references_args_if_enabled (MarkCrossReferencesArgs *args) noexcept; static void log_handle_context (JNIEnv *env, HandleContext *ctx) noexcept; diff --git a/src/native/clr/include/host/host-environment.hh b/src/native/clr/include/host/host-environment.hh index 2c4dc95252d..7ef13ba5835 100644 --- a/src/native/clr/include/host/host-environment.hh +++ b/src/native/clr/include/host/host-environment.hh @@ -42,7 +42,9 @@ namespace xamarin::android { static void set_system_property (const char *name, const char *value) noexcept { // TODO: should we **actually** try to set the system property here? Would that even work? Needs testing - log_debug (LOG_DEFAULT, " System property {} = '{}'", optional_string (name), optional_string (value)); + if ((log_categories & LOG_DEFAULT) != 0) { + log_write_fmt (LOG_DEFAULT, LogLevel::Debug, " System property %s = '%s'", optional_string (name), optional_string (value)); + } } [[gnu::flatten, gnu::always_inline]] @@ -88,10 +90,12 @@ namespace xamarin::android { static_local_string dir (home_len + relative_path.length ()); Util::path_combine (dir, home.get_string_view (), relative_path); - log_debug (LOG_DEFAULT, "Creating XDG directory: {}"sv, optional_string (dir.get ())); + if ((log_categories & LOG_DEFAULT) != 0) { + log_write_fmt (LOG_DEFAULT, LogLevel::Debug, "Creating XDG directory: %s", optional_string (dir.get ())); + } int rv = Util::create_directory (dir.get (), Constants::DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) { - log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}"sv, optional_string (dir.get ()), strerror (errno)); + log_write_fmt (LOG_DEFAULT, LogLevel::Warn, "Failed to create XDG directory %s. %s", optional_string (dir.get ()), strerror (errno)); } if (!environment_variable_name.empty ()) { diff --git a/src/native/clr/include/host/os-bridge.hh b/src/native/clr/include/host/os-bridge.hh index ee96c220671..a7324f52d47 100644 --- a/src/native/clr/include/host/os-bridge.hh +++ b/src/native/clr/include/host/os-bridge.hh @@ -31,6 +31,13 @@ namespace xamarin::android { static auto _monodroid_weak_gref_dec () noexcept -> int; static void _monodroid_gref_log (const char *message) noexcept; + + template + static void _monodroid_gref_log (const char *format, Arg arg, Args... args) noexcept + { + _monodroid_gref_log_fmt (format, arg, args...); + } + static auto _monodroid_gref_log_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from) noexcept -> int; static void _monodroid_gref_log_delete (jobject handle, char type, const char *threadName, int threadId, const char *from) noexcept; static void _monodroid_weak_gref_new (jobject curHandle, char curType, jobject newHandle, char newType, const char *threadName, int threadId, const char *from); @@ -57,7 +64,9 @@ namespace xamarin::android { private: static void _write_stack_trace (FILE *to, const char *const from, LogCategories = LOG_NONE) noexcept; - static void log_it (LogCategories category, std::string const& line, FILE *to, const char *const from, bool logcat_enabled) noexcept; + static void _monodroid_gref_log_fmt (const char *format, ...) noexcept __attribute__ ((format (printf, 1, 2))); + static void log_it (LogCategories category, const char *line, FILE *to, const char *const from, bool logcat_enabled) noexcept; + static void log_itf (LogCategories category, FILE *to, const char *from, bool logcat_enabled, const char *format, ...) noexcept __attribute__ ((format (printf, 5, 6))); private: static inline JavaVM *jvm = nullptr; diff --git a/src/native/clr/include/host/pinvoke-override-impl.hh b/src/native/clr/include/host/pinvoke-override-impl.hh index 97608211f37..5301cfbe470 100644 --- a/src/native/clr/include/host/pinvoke-override-impl.hh +++ b/src/native/clr/include/host/pinvoke-override-impl.hh @@ -34,7 +34,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_debug (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); } @@ -43,21 +43,21 @@ namespace xamarin::android { } if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", library_name, symbol_name); + log_warn (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; } if (dso_handle != nullptr) { void *expected_null = nullptr; if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { - log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", library_name); + log_debug (LOG_ASSEMBLY, "Library '%.*s' handle already cached by another thread", static_cast(library_name.length ()), library_name.data ()); } } } 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_warn (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; } @@ -79,7 +79,7 @@ namespace xamarin::android { return nullptr; } - log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); + log_debug (LOG_ASSEMBLY, "Caching p/invoke entry %s @ %s", library_name.c_str (), entrypoint_name.c_str ()); (*api_map)[entrypoint_name] = entry_handle; return entry_handle; } @@ -100,7 +100,7 @@ namespace xamarin::android { ); if (already_loaded) { - log_debug (LOG_ASSEMBLY, "Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name); + log_debug (LOG_ASSEMBLY, "Entry '%.*s' from library '%.*s' already loaded by another thread", static_cast(entrypoint_name.length ()), entrypoint_name.data (), static_cast(library_name.length ()), library_name.data ()); } } @@ -165,7 +165,7 @@ namespace xamarin::android { handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); } else { if (iter->second == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", library_name); + log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '%.*s'", static_cast(library_name.length ()), library_name.data ()); return nullptr; // fall back to `monodroid_dlopen` } diff --git a/src/native/clr/include/runtime-base/android-system.hh b/src/native/clr/include/runtime-base/android-system.hh index b60871a93c4..3de8138522d 100644 --- a/src/native/clr/include/runtime-base/android-system.hh +++ b/src/native/clr/include/runtime-base/android-system.hh @@ -1,7 +1,9 @@ #pragma once #include +#include #include +#include #include #include #include @@ -18,6 +20,7 @@ struct BundledProperty; namespace xamarin::android { class AndroidSystem { +#if !defined(XA_HOST_NATIVEAOT) // This optimizes things a little bit. The array is allocated at build time, so we pay no cost for its // allocation and at run time it allows us to skip dynamic memory allocation. inline static std::array single_app_lib_directory{}; @@ -35,6 +38,7 @@ namespace xamarin::android { std::string_view { "x86_64" }, // CPU_KIND_X86_64 std::string_view { "riscv" }, // CPU_KIND_RISCV }; +#endif public: static auto get_gref_gc_threshold () noexcept -> long @@ -60,22 +64,23 @@ namespace xamarin::android { running_in_emulator = yesno; } - static auto get_primary_override_dir () noexcept -> std::string const& + static auto get_primary_override_dir () noexcept -> const char* { return primary_override_dir; } static void set_primary_override_dir (jstring_wrapper& home) noexcept { - primary_override_dir = determine_primary_override_dir (home); + determine_primary_override_dir (home, primary_override_dir, sizeof (primary_override_dir)); } +#if !defined(XA_HOST_NATIVEAOT) static auto get_native_libraries_dir () noexcept -> std::string const& { return native_libraries_dir; } - static void create_update_dir (std::string const& override_dir) noexcept + static void create_update_dir (const char *override_dir) noexcept { if constexpr (Constants::is_release_build) { /* @@ -91,9 +96,10 @@ namespace xamarin::android { } } - log_debug (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); + log_debug (LOG_DEFAULT, "Creating public update directory: `%s`", optional_string (override_dir)); Util::create_public_directory (override_dir); } +#endif static auto is_embedded_dso_mode_enabled () noexcept -> bool { @@ -129,7 +135,7 @@ namespace xamarin::android { embedded_dso_mode_enabled = yesno; } - static auto determine_primary_override_dir (jstring_wrapper &home) noexcept -> std::string + static void determine_primary_override_dir (jstring_wrapper &home, char *buffer, size_t buffer_size) noexcept { dynamic_local_string name { home.get_cstr () }; name.append ("/") @@ -137,18 +143,20 @@ namespace xamarin::android { .append ("/") .append (Constants::android_lib_abi); - return {name.get (), name.length ()}; + snprintf (buffer, buffer_size, "%s", name.get ()); } private: static inline long max_gref_count = 0; static inline bool running_in_emulator = false; static inline bool embedded_dso_mode_enabled = false; - static inline std::string primary_override_dir; + static inline char primary_override_dir[SENSIBLE_PATH_MAX] {}; +#if !defined(XA_HOST_NATIVEAOT) static inline std::string native_libraries_dir; #if defined (DEBUG) static inline std::unordered_map bundled_properties; +#endif #endif }; } diff --git a/src/native/clr/include/runtime-base/monodroid-dl.hh b/src/native/clr/include/runtime-base/monodroid-dl.hh index cc2973b4515..5f39aed3d24 100644 --- a/src/native/clr/include/runtime-base/monodroid-dl.hh +++ b/src/native/clr/include/runtime-base/monodroid-dl.hh @@ -41,11 +41,11 @@ namespace xamarin::android size_t arr_size; if constexpr (WhichCache == CacheKind::AOT) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in AOT cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash %zx in AOT cache", static_cast(hash)); arr = aot_dso_cache; arr_size = application_config.number_of_aot_cache_entries; } else if constexpr (WhichCache == CacheKind::DSO) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash %zx in DSO cache", static_cast(hash)); arr = dso_cache; arr_size = application_config.number_of_dso_cache_entries; } @@ -104,23 +104,24 @@ namespace xamarin::android [[gnu::flatten]] 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); + std::string_view match_status = dso == nullptr ? "not "sv : ""sv; + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match %.*sfound, DSO name is '%.*s'", static_cast(match_status.length ()), match_status.data (), 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_debug (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_info (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); #if defined (RELEASE) if (AndroidSystem::is_embedded_dso_mode_enabled ()) { @@ -153,7 +154,7 @@ namespace xamarin::android } hash_t name_hash = xxhash::hash (name.data (), name.size ()); - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '{}' is {:x}", name, name_hash); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '%.*s' is %zx", static_cast(name.length ()), name.data (), static_cast(name_hash)); DSOCacheEntry *dso = nullptr; if constexpr (PREFER_AOT_CACHE) { @@ -194,8 +195,9 @@ namespace xamarin::android if (s == nullptr) { log_error ( 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/runtime-base/util.hh b/src/native/clr/include/runtime-base/util.hh index 656a3d4a68a..718b4f5d2e8 100644 --- a/src/native/clr/include/runtime-base/util.hh +++ b/src/native/clr/include/runtime-base/util.hh @@ -6,8 +6,10 @@ #include #include +#include #include #include +#include #include #include @@ -41,6 +43,17 @@ namespace xamarin::android { void *area; size_t size; }; + + static constexpr auto printf_precision (std::string_view const& value) noexcept -> int + { + constexpr size_t max_precision = static_cast(std::numeric_limits::max ()); + return value.length () > max_precision ? std::numeric_limits::max () : static_cast(value.length ()); + } + + static constexpr auto printf_string (std::string_view const& value) noexcept -> const char* + { + return value.data () == nullptr ? "" : value.data (); + } } class Util @@ -139,7 +152,7 @@ namespace xamarin::android { { struct stat sbuf; if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { - log_warn (LOG_ASSEMBLY, "Failed to stat file '{}': {}", file_name, std::strerror (errno)); + log_write_fmt (LOG_ASSEMBLY, LogLevel::Warn, "Failed to stat file '%s': %s", file_name, std::strerror (errno)); return std::nullopt; } @@ -154,9 +167,11 @@ namespace xamarin::android { [[gnu::flatten, gnu::always_inline]] static void set_environment_variable (const char *name, const char *value) noexcept { - log_debug (LOG_DEFAULT, "Setting environment variable {} = '{}'", optional_string (name), optional_string (value)); + if (should_log (LOG_DEFAULT)) { + log_write_fmt (LOG_DEFAULT, LogLevel::Debug, "Setting environment variable %s = '%s'", optional_string (name), optional_string (value)); + } if (::setenv (name, value, 1) < 0) { - log_warn (LOG_DEFAULT, "Failed to set environment variable '{}': {}", name, ::strerror (errno)); + log_write_fmt (LOG_DEFAULT, LogLevel::Warn, "Failed to set environment variable '%s': %s", optional_string (name), ::strerror (errno)); } } @@ -178,7 +193,7 @@ namespace xamarin::android { if (createDirectory) { int rv = create_directory (value.get_cstr (), mode); if (rv < 0 && errno != EEXIST) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}' for environment variable '{}'. {}", value.get_string_view (), name, strerror (errno)); + log_write_fmt (LOG_DEFAULT, LogLevel::Warn, "Failed to create directory '%s' for environment variable '%s'. %s", optional_string (value.get_cstr ()), name.data (), strerror (errno)); } } set_environment_variable (name, value); @@ -208,14 +223,14 @@ namespace xamarin::android { mmap_info.area = mmap (nullptr, offsetSize, PROT_READ, MAP_PRIVATE, fd, static_cast(offsetPage)); if (mmap_info.area == MAP_FAILED) { - Helpers::abort_application ( + Helpers::abort_applicationf ( LOG_ASSEMBLY, - std::format ( - "Could not mmap APK fd {}: {}; File={}", - fd, - strerror (errno), - filename - ) + std::source_location::current (), + "Could not mmap APK fd %d: %s; File=%.*s", + fd, + strerror (errno), + detail::printf_precision (filename), + detail::printf_string (filename) ); } @@ -223,18 +238,22 @@ namespace xamarin::android { file_info.area = pointer_add (mmap_info.area, offsetFromPage); file_info.size = size; - log_info ( - LOG_ASSEMBLY, - " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", - mmap_info.area, - pointer_add (mmap_info.area, mmap_info.size), - mmap_info.size, - file_info.area, - pointer_add (file_info.area, file_info.size), - file_info.size, - fd, - filename - ); + if (should_log (LOG_ASSEMBLY)) { + log_write_fmt ( + LOG_ASSEMBLY, + LogLevel::Info, + " mmap_start: %-8p; mmap_end: %-8p mmap_len: %-12zu file_start: %-8p file_end: %-8p file_len: %-12zu apk descriptor: %d file: %.*s", + mmap_info.area, + pointer_add (mmap_info.area, mmap_info.size), + mmap_info.size, + file_info.area, + pointer_add (file_info.area, file_info.size), + file_info.size, + fd, + detail::printf_precision (filename), + detail::printf_string (filename) + ); + } return file_info; } @@ -256,7 +275,9 @@ namespace xamarin::android { elf_header->e_ident[EI_MAG1] != ELFMAG1 || elf_header->e_ident[EI_MAG2] != ELFMAG2 || elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", file_name); + if (should_log (LOG_ASSEMBLY)) { + log_write_fmt (LOG_ASSEMBLY, LogLevel::Debug, "Not an ELF image: %.*s", detail::printf_precision (file_name), detail::printf_string (file_name)); + } // Not an ELF image, just return what we mmapped before return { map_info.area, map_info.size }; } diff --git a/src/native/clr/include/shared/log_types.hh b/src/native/clr/include/shared/log_types.hh index 7aef6e20456..7b5d32b76e4 100644 --- a/src/native/clr/include/shared/log_types.hh +++ b/src/native/clr/include/shared/log_types.hh @@ -1,7 +1,7 @@ #pragma once +#include #include -#include #include #include @@ -20,33 +20,31 @@ #define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ do { \ if ((log_categories & ((_category_))) != 0) { \ - ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ + ::xamarin::android::log_ ## _level ## _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 +// NOTE: _fmt_ takes arguments in 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 +// NOTE: _fmt_ takes arguments in 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 POSIX printf style. +#define log_warn(_category_, _fmt_, ...) ::xamarin::android::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 POSIX printf style. +#define log_error(_category_, _fmt_, ...) ::xamarin::android::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__) +// NOTE: _fmt_ takes arguments in POSIX printf style. +#define log_fatal(_category_, _fmt_, ...) ::xamarin::android::log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) namespace xamarin::android { // A slightly faster alternative to other log functions as it doesn't parse the message // for format placeholders nor it uses variable arguments void log_write (LogCategories category, LogLevel level, const char *message) noexcept; + void log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept; + void log_write_fmt (LogCategories category, LogLevel level, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4))); [[gnu::always_inline]] static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept @@ -54,71 +52,101 @@ namespace xamarin::android { 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) + void log_debug_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_info_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_warn_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_error_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_fatal_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + + [[gnu::always_inline]] + static inline void log_debug_fmt (LogCategories category, std::string_view const& message) noexcept { - log_write (category, level, std::format (fmt, std::forward(args)...).c_str ()); + log_write (category, LogLevel::Debug, message); } -} -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 void log_info_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Info, message); + } -[[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 ()); -} + [[gnu::always_inline]] + static inline void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Warn, message); + } -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 void log_error_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Error, message); + } -[[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 ()); -} + [[gnu::always_inline]] + static inline void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Fatal, message); + } -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 void log_debug_fmt (LogCategories category, std::string const& message) noexcept + { + log_debug_fmt (category, std::string_view { message }); + } -[[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 ()); + [[gnu::always_inline]] + static inline void log_info_fmt (LogCategories category, std::string const& message) noexcept + { + log_info_fmt (category, std::string_view { message }); + } + + [[gnu::always_inline]] + static inline void log_warn_fmt (LogCategories category, std::string const& message) noexcept + { + log_warn_fmt (category, std::string_view { message }); + } + + [[gnu::always_inline]] + static inline void log_error_fmt (LogCategories category, std::string const& message) noexcept + { + log_error_fmt (category, std::string_view { message }); + } + + [[gnu::always_inline]] + static inline void log_fatal_fmt (LogCategories category, std::string const& message) noexcept + { + log_fatal_fmt (category, std::string_view { message }); + } } -template [[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +[[gnu::always_inline]] +static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept { - log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); + xamarin::android::log_write (category, xamarin::android::LogLevel::Debug, message.data ()); } [[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept +static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept { - log_write (category, xamarin::android::LogLevel::Error, message.data ()); + xamarin::android::log_write (category, xamarin::android::LogLevel::Info, message.data ()); } -template [[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +static inline void log_debug_nocheck_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); +static inline void log_debug_nocheck_fmt (LogCategories category, const char *format, ...) noexcept { - log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); + va_list args; + va_start (args, format); + xamarin::android::log_writev (category, xamarin::android::LogLevel::Debug, format, args); + va_end (args); } -[[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept +static inline void log_info_nocheck_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); +static inline void log_info_nocheck_fmt (LogCategories category, const char *format, ...) noexcept { - log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); + va_list args; + va_start (args, format); + xamarin::android::log_writev (category, xamarin::android::LogLevel::Info, format, args); + va_end (args); } extern unsigned int log_categories; diff --git a/src/native/clr/pinvoke-override/dynamic.cc b/src/native/clr/pinvoke-override/dynamic.cc index 5352aacab68..6633baeef24 100644 --- a/src/native/clr/pinvoke-override/dynamic.cc +++ b/src/native/clr/pinvoke-override/dynamic.cc @@ -24,7 +24,7 @@ extern "C" { [[gnu::flatten]] auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const char *entrypoint_name) noexcept -> void* { - log_debug (LOG_ASSEMBLY, "library_name == '{}'; entrypoint_name == '{}'"sv, optional_string (library_name), optional_string (entrypoint_name)); + log_debug (LOG_ASSEMBLY, "library_name == '%s'; entrypoint_name == '%s'", optional_string (library_name), optional_string (entrypoint_name)); if (library_name == nullptr || entrypoint_name == nullptr) [[unlikely]] { Helpers::abort_application ( @@ -39,12 +39,12 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons hash_t library_name_hash = xxhash::hash (library_name, strlen (library_name)); hash_t entrypoint_hash = xxhash::hash (entrypoint_name, strlen (entrypoint_name)); - log_debug (LOG_ASSEMBLY, "library_name_hash == 0x{:x}; entrypoint_hash == 0x{:x}"sv, library_name_hash, entrypoint_hash); + log_debug (LOG_ASSEMBLY, "library_name_hash == 0x%zx; entrypoint_hash == 0x%zx", static_cast(library_name_hash), static_cast(entrypoint_hash)); bool known_library = true; void *pinvoke_ptr = find_pinvoke (library_name_hash, entrypoint_hash, known_library); if (pinvoke_ptr != nullptr) [[likely]] { - log_debug (LOG_ASSEMBLY, "pinvoke_ptr == {:p}"sv, pinvoke_ptr); + log_debug (LOG_ASSEMBLY, "pinvoke_ptr == %p", pinvoke_ptr); return pinvoke_ptr; } @@ -70,7 +70,7 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons log_debug (LOG_ASSEMBLY, "p/invoke not from a known library, slow path taken."sv); pinvoke_ptr = handle_other_pinvoke_request (library_name, library_name_hash, entrypoint_name, entrypoint_hash); - log_debug (LOG_ASSEMBLY, "foreign library pinvoke_ptr == {:p}"sv, pinvoke_ptr); + log_debug (LOG_ASSEMBLY, "foreign library pinvoke_ptr == %p", pinvoke_ptr); return pinvoke_ptr; } @@ -96,8 +96,8 @@ void PinvokeOverride::handle_jni_on_load (JavaVM *vm, void *reserved) noexcept const void* Host::clr_pinvoke_override (const char *library_name, const char *entry_point_name) noexcept { - log_debug (LOG_ASSEMBLY, "[dynamic] clr_pinvoke_override (\"{}\", \"{}\")"sv, optional_string (library_name), optional_string (entry_point_name)); + log_debug (LOG_ASSEMBLY, "[dynamic] clr_pinvoke_override (\"%s\", \"%s\")", optional_string (library_name), optional_string (entry_point_name)); void *ret = PinvokeOverride::monodroid_pinvoke_override (library_name, entry_point_name); - log_debug (LOG_DEFAULT, "[dynamic] p/invoke {}found", ret == nullptr ? "not "sv : ""sv); + log_debug (LOG_DEFAULT, "[dynamic] p/invoke %sfound", ret == nullptr ? "not " : ""); return ret; } diff --git a/src/native/clr/pinvoke-override/precompiled.cc b/src/native/clr/pinvoke-override/precompiled.cc index 25c63b53d45..c4c48615ff3 100644 --- a/src/native/clr/pinvoke-override/precompiled.cc +++ b/src/native/clr/pinvoke-override/precompiled.cc @@ -1,3 +1,5 @@ +#include + #define PINVOKE_OVERRIDE_INLINE [[gnu::always_inline]] #include @@ -22,12 +24,12 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { - log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map."sv, - optional_string (library_name), optional_string (entrypoint_name), entrypoint_hash); + log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '%s @ %s' (hash: %zx) not found in compile-time map.", + optional_string (library_name), optional_string (entrypoint_name), static_cast(entrypoint_hash)); log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); for (size_t i = 0uz; i < internal_pinvokes_count; i++) { PinvokeEntry const& e = internal_pinvokes[i]; - log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})"sv, optional_string (e.name), e.func, e.hash); + log_fatal (LOG_ASSEMBLY, "\t'%s'=%p (hash: %zx)", optional_string (e.name), e.func, static_cast(e.hash)); } Helpers::abort_application ( LOG_ASSEMBLY, @@ -68,7 +70,7 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); if (entry->func == nullptr) { - log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'"sv, + log_fatal (LOG_ASSEMBLY, "Failed to load symbol '%s' from shared library '%s'", optional_string (entrypoint_name), optional_string (library_name)); return nullptr; // let Mono deal with the fallout } @@ -79,7 +81,7 @@ auto PinvokeOverride::monodroid_pinvoke_override (const char *library_name, cons // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below log_debug ( LOG_ASSEMBLY, - "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path"sv, + "Symbol '%s' in library '%s' not found in the generated tables, falling back to slow path", optional_string (entrypoint_name), optional_string (library_name) ); @@ -100,8 +102,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_debug (LOG_ASSEMBLY, "[precompiled] clr_pinvoke_override (\"{}\", \"{}\")"sv, library_name, entry_point_name); + log_debug (LOG_ASSEMBLY, "[precompiled] clr_pinvoke_override (\"%s\", \"%s\")", optional_string (library_name), optional_string (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_debug (LOG_DEFAULT, "[precompiled] p/invoke %sfound", ret == nullptr ? "not" : ""); return ret; } diff --git a/src/native/clr/runtime-base/android-system-shared.cc b/src/native/clr/runtime-base/android-system-shared.cc index 2aa1d54b001..ed0c30b982a 100644 --- a/src/native/clr/runtime-base/android-system-shared.cc +++ b/src/native/clr/runtime-base/android-system-shared.cc @@ -1,3 +1,6 @@ +#include +#include +#include #include #include @@ -36,15 +39,16 @@ AndroidSystem::monodroid__system_property_get (std::string_view const& name, cha char *buf = nullptr; if (sp_value_len < Constants::PROPERTY_VALUE_BUFFER_LEN) { size_t alloc_size = Helpers::add_with_overflow_check (Constants::PROPERTY_VALUE_BUFFER_LEN, 1uz); - log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only {} bytes", sp_value_len); - buf = new char [alloc_size]; + log_write_fmt (LOG_DEFAULT, LogLevel::Warn, "Buffer to store system property may be too small, will copy only %zu bytes", sp_value_len); + buf = static_cast (std::malloc (alloc_size)); + abort_unless (buf != nullptr, "Failed to allocate system property buffer"); } int len = __system_property_get (name.data (), buf ? buf : sp_value); if (buf != nullptr) { strncpy (sp_value, buf, sp_value_len); sp_value [sp_value_len] = '\0'; - delete[] buf; + std::free (buf); } return len; @@ -81,10 +85,10 @@ AndroidSystem::get_max_gref_count_from_system () noexcept -> long } if (*e) { - log_warn (LOG_GC, "Unsupported '{}' value '{}'.", Constants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); + log_write_fmt (LOG_GC, LogLevel::Warn, "Unsupported '%s' value '%s'.", Constants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); } - log_warn (LOG_GC, "Overriding max JNI Global Reference count to {}", max); + log_write_fmt (LOG_GC, LogLevel::Warn, "Overriding max JNI Global Reference count to %ld", max); } return max; diff --git a/src/native/clr/runtime-base/android-system.cc b/src/native/clr/runtime-base/android-system.cc index aee00900d55..b6c06e90a70 100644 --- a/src/native/clr/runtime-base/android-system.cc +++ b/src/native/clr/runtime-base/android-system.cc @@ -49,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_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: {}", strerror (errno)); + log_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: %s", strerror (errno)); } return; } @@ -64,13 +64,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_warn (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_warn (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_warn (LOG_DEFAULT, "Malformed environment override file %s: invalid data size", path.get ()); return; } @@ -136,11 +136,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_warn (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_debug (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 +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_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: {}", dir); + log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: %s", dir.c_str ()); index++; } @@ -196,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_debug (LOG_DEFAULT, "Number of added dirs: {}", number_of_added_directories); + log_debug (LOG_DEFAULT, "Number of added dirs: %zu", number_of_added_directories); if (app_lib_directories.size () == number_of_added_directories) [[likely]] { return; } @@ -213,7 +213,7 @@ AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks 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_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: %s", app_lib_directories [0].c_str ()); return; } @@ -237,7 +237,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_debug (LOG_DEFAULT, "Setting environment variables (%u)", application_config.environment_variable_count); HostEnvironment::set_values ( application_config.environment_variable_count, app_environment_variables, @@ -246,7 +246,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_debug (LOG_DEFAULT, "Setting system properties (%u)", application_config.system_property_count); HostEnvironment::set_values ( application_config.system_property_count, app_system_properties, @@ -259,9 +259,9 @@ AndroidSystem::setup_environment () noexcept 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_debug (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_debug (LOG_DEFAULT, "Loading %s", env_override_file.get ()); setup_environment_from_override_file (env_override_file); } #endif // def DEBUG @@ -274,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_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ()); + log_debug (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_debug (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_debug (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/clr/runtime-base/logger.cc b/src/native/clr/runtime-base/logger.cc index a61b68d4a76..0078aa7fe6a 100644 --- a/src/native/clr/runtime-base/logger.cc +++ b/src/native/clr/runtime-base/logger.cc @@ -1,10 +1,10 @@ #include #include #include +#include #include #include #include -#include #include #include @@ -22,10 +22,17 @@ using namespace xamarin::android; using std::operator""sv; namespace { - std::string gref_file{}; - std::string lref_file{}; + char *gref_file = nullptr; + char *lref_file = nullptr; bool light_gref = false; bool light_lref = false; + + void set_log_file (char *&log_file, const char *path) noexcept + { + std::free (log_file); + log_file = path == nullptr ? nullptr : strdup (path); + abort_unless (path == nullptr || log_file != nullptr, "Failed to allocate reference log file path"); + } } [[gnu::always_inline]] @@ -52,7 +59,9 @@ auto Logger::open_file (LogCategories category, std::string_view const& custom_p { auto log_and_return = [&category](FILE *f, std::string_view const& path) -> FILE* { if (f != nullptr) { - log_debug (category, "Opened file '{}' for logging.", path); + if ((log_categories & category) != 0) { + log_write_fmt (category, LogLevel::Debug, "Opened file '%s' for logging.", path.data ()); + } } return f; }; @@ -62,28 +71,28 @@ auto Logger::open_file (LogCategories category, std::string_view const& custom_p return log_and_return (ret, custom_path); } - std::string p{}; Util::create_public_directory (override_dir); - p.assign (override_dir); - p.append ("/"); - p.append (fallback_filename); + dynamic_local_string p; + p.append (override_dir) + .append ("/") + .append (fallback_filename); - return log_and_return (open_file (p), p); + return log_and_return (open_file (p.get ()), p.get ()); } void Logger::init_reference_logging (std::string_view const& override_dir) noexcept { if ((log_categories & LOG_GREF) != 0 && !light_gref) { - _gref_log = open_file (LOG_GREF, gref_file, override_dir, "grefs.txt"sv); + _gref_log = open_file (LOG_GREF, gref_file == nullptr ? std::string_view {} : std::string_view { gref_file }, override_dir, "grefs.txt"sv); } if ((log_categories & LOG_LREF) != 0 && !light_lref) { // if both lref & gref have files specified, and they're the same path, reuse the FILE*. - if (!lref_file.empty () && strcmp (lref_file.c_str (), !gref_file.empty () ? gref_file.c_str () : "") == 0) { + if (lref_file != nullptr && strcmp (lref_file, gref_file != nullptr ? gref_file : "") == 0) { _lref_log = _gref_log; } else { - _lref_log = open_file (LOG_LREF, lref_file, override_dir, "lrefs.txt"sv); + _lref_log = open_file (LOG_LREF, lref_file == nullptr ? std::string_view {} : std::string_view { lref_file }, override_dir, "lrefs.txt"sv); } } } @@ -162,7 +171,16 @@ Logger::init_logging_categories () noexcept auto file_name = segment.at (offset); if (!file_name.has_value ()) { - log_warn (LOG_DEFAULT, "Unable to set path to {} log file: {}", file_kind, to_string (file_name.error ())); + std::string_view error = to_string (file_name.error ()); + log_write_fmt ( + LOG_DEFAULT, + LogLevel::Warn, + "Unable to set path to %.*s log file: %.*s", + static_cast(file_kind.length ()), + file_kind.data (), + static_cast(error.length ()), + error.data () + ); return nullptr; } @@ -171,7 +189,7 @@ Logger::init_logging_categories () noexcept constexpr std::string_view CAT_GREF_EQUALS { "gref=" }; if (set_category (CAT_GREF_EQUALS, param, LOG_GREF, true /* arg_starts_with_name */)) { - gref_file = get_log_file_name ("gref"sv, param, CAT_GREF_EQUALS.length ()); + set_log_file (gref_file, get_log_file_name ("gref"sv, param, CAT_GREF_EQUALS.length ())); continue; } @@ -187,7 +205,7 @@ Logger::init_logging_categories () noexcept constexpr std::string_view CAT_LREF_EQUALS { "lref=" }; if (set_category (CAT_LREF_EQUALS, param, LOG_LREF, true /* arg_starts_with_name */)) { - lref_file = get_log_file_name ("lref"sv, param, CAT_LREF_EQUALS.length ()); + set_log_file (lref_file, get_log_file_name ("lref"sv, param, CAT_LREF_EQUALS.length ())); continue; } diff --git a/src/native/clr/runtime-base/util.cc b/src/native/clr/runtime-base/util.cc index 8f59681a55f..6b568921294 100644 --- a/src/native/clr/runtime-base/util.cc +++ b/src/native/clr/runtime-base/util.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -58,7 +59,7 @@ Util::create_public_directory (std::string_view const& dir) // Try to change the mode, just in case chmod (dir.data (), 0777); } else { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}"sv, dir, std::strerror (errno)); + log_write_fmt (LOG_DEFAULT, LogLevel::Warn, "Failed to create directory '%s'. %s", dir.data (), std::strerror (errno)); } } umask (m); @@ -72,7 +73,7 @@ Util::monodroid_fopen (std::string_view const& filename, std::string_view const& */ FILE *ret = fopen (filename.data (), mode.data ()); if (ret == nullptr) { - log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); + log_write_fmt (LOG_DEFAULT, LogLevel::Error, "fopen failed for file %s: %s", filename.data (), strerror (errno)); return nullptr; } @@ -87,7 +88,7 @@ void Util::set_world_accessable (std::string_view const& path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); + log_write_fmt (LOG_DEFAULT, LogLevel::Error, "chmod(\"%s\", 0664) failed: %s", path.data (), strerror (errno)); } } @@ -99,7 +100,7 @@ auto Util::set_world_accessible (int fd) noexcept -> bool } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "fchmod() failed: {}"sv, strerror (errno)); + log_write_fmt (LOG_DEFAULT, LogLevel::Error, "fchmod() failed: %s", strerror (errno)); return false; } diff --git a/src/native/clr/shared/helpers.cc b/src/native/clr/shared/helpers.cc index 7850592af5a..e7d62723880 100644 --- a/src/native/clr/shared/helpers.cc +++ b/src/native/clr/shared/helpers.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,11 +8,24 @@ using namespace xamarin::android; +[[noreturn]] void +Helpers::abort_applicationf (LogCategories category, std::source_location sloc, const char *format, ...) noexcept +{ + char message[512]; + va_list args; + const char *safe_format = format == nullptr ? "" : format; + va_start (args, format); + vsnprintf (message, sizeof (message), safe_format, args); + va_end (args); + + abort_application (category, message, true, sloc); +} + [[noreturn]] void Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept { // Log it, but also... - log_fatal (category, "{}", message); + log_write (category, LogLevel::Fatal, message); // ...let android include it in the tombstone, debuggerd output, stack trace etc android_set_abort_message (message); @@ -33,9 +47,10 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo } } - log_fatal ( + log_write_fmt ( category, - "Abort at {}:{}:{} ('{}')", + LogLevel::Fatal, + "Abort at %s:%u:%u ('%s')", file_name, sloc.line (), sloc.column (), diff --git a/src/native/clr/shared/log_functions.cc b/src/native/clr/shared/log_functions.cc index acd5e705c06..ea94cf9016b 100644 --- a/src/native/clr/shared/log_functions.cc +++ b/src/native/clr/shared/log_functions.cc @@ -128,4 +128,74 @@ namespace xamarin::android { __android_log_write (priority, category_name (category), message); } + + void + log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept + { + size_t map_index = static_cast(level); + android_LogPriority priority; + + if (map_index > loglevel_map_max_index) { + priority = DEFAULT_PRIORITY; + } else { + priority = loglevel_map[map_index]; + } + + const char *safe_format = format == nullptr ? "" : format; + __android_log_vprint (priority, category_name (category), safe_format, args); + } + + void + log_write_fmt (LogCategories category, LogLevel level, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, level, format, args); + va_end (args); + } + + void + log_debug_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Debug, format, args); + va_end (args); + } + + void + log_info_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Info, format, args); + va_end (args); + } + + void + log_warn_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Warn, format, args); + va_end (args); + } + + void + log_error_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Error, format, args); + va_end (args); + } + + void + log_fatal_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Fatal, format, args); + va_end (args); + } } diff --git a/src/native/clr/startup/zip.cc b/src/native/clr/startup/zip.cc index 0c5413fb2d6..9dc2bf1eb1f 100644 --- a/src/native/clr/startup/zip.cc +++ b/src/native/clr/startup/zip.cc @@ -28,8 +28,8 @@ bool Zip::zip_adjust_data_offset (int fd, zip_scan_state &state) noexcept if (result < 0) { log_error ( LOG_ASSEMBLY, - "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", - state.local_header_offset, std::strerror (errno), result, errno + "Failed to seek to archive entry local header at offset %u. %s (result: %lld; errno: %d)", + state.local_header_offset, std::strerror (errno), static_cast(result), errno ); return false; } @@ -39,32 +39,32 @@ bool Zip::zip_adjust_data_offset (int fd, zip_scan_state &state) noexcept ssize_t nread = ::read (fd, local_header.data (), local_header.size ()); if (nread < 0 || nread != ZIP_LOCAL_LEN) { - log_error (LOG_ASSEMBLY, "Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, "Failed to read local header at offset %u: %s (nread: %zd; errno: %d)", state.local_header_offset, std::strerror (errno), nread, errno); return false; } size_t index = 0; if (!zip_read_field (local_header, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset {}", state.local_header_offset); + log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset %u", state.local_header_offset); return false; } if (memcmp (signature.data (), ZIP_LOCAL_MAGIC.data (), signature.size ()) != 0) { - log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset {}", state.local_header_offset); + log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset %u", state.local_header_offset); return false; } uint16_t file_name_length; index = LH_FILE_NAME_LENGTH_OFFSET; if (!zip_read_field (local_header, index, file_name_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index)); + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset %zu", (state.local_header_offset + index)); return false; } uint16_t extra_field_length; index = LH_EXTRA_LENGTH_OFFSET; if (!zip_read_field (local_header, index, extra_field_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index)); + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset %zu", (state.local_header_offset + index)); return false; } @@ -154,7 +154,7 @@ bool Zip::zip_load_entry_common (size_t entry_index, std::vector const& bool result = zip_read_entry_info (buf, entry_name, state); - log_debug (LOG_ASSEMBLY, "{} entry: {}", state.file_name, optional_string (entry_name.get (), "unknown")); + log_debug (LOG_ASSEMBLY, "%.*s entry: %s", static_cast(state.file_name.length ()), state.file_name.data (), optional_string (entry_name.get (), "unknown")); if (!result || entry_name.empty ()) { Helpers::abort_application ( LOG_ASSEMBLY, @@ -177,7 +177,7 @@ bool Zip::zip_load_entry_common (size_t entry_index, std::vector const& ); } - log_debug (LOG_ASSEMBLY, " ZIP: local header offset: {}; data offset: {}; file size: {}", state.local_header_offset, state.data_offset, state.file_size); + log_debug (LOG_ASSEMBLY, " ZIP: local header offset: %u; data offset: %u; file size: %u", state.local_header_offset, state.data_offset, state.file_size); if (state.compression_method != 0) { return false; } @@ -249,7 +249,7 @@ template [[gnu::always_inline]] bool Zip::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept { if (index + to_read > buf.size ()) { - log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); + log_error (LOG_ASSEMBLY, "Buffer too short to read %zu bytes of data", to_read); return false; } @@ -311,14 +311,14 @@ bool Zip::zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, // The simplest case - no file comment off_t ret = ::lseek (apk_fd, -ZIP_EOCD_LEN, SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: %s (ret: %lld; errno: %d)", std::strerror (errno), static_cast(ret), errno); return false; } std::array eocd; ssize_t nread = ::read (apk_fd, eocd.data (), eocd.size ()); if (nread < 0 || nread != eocd.size ()) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: %s (nread: %zd; errno: %d)", std::strerror (errno), nread, errno); return false; } @@ -338,7 +338,7 @@ bool Zip::zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, constexpr size_t alloc_size = 65535uz + ZIP_EOCD_LEN; // 64k is the biggest comment size allowed ret = ::lseek (apk_fd, static_cast(-alloc_size), SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: %s (ret: %lld; errno: %d)", std::strerror (errno), static_cast(ret), errno); return false; } @@ -347,7 +347,7 @@ bool Zip::zip_read_cd_info (int apk_fd, uint32_t& cd_offset, uint32_t& cd_size, nread = ::read (apk_fd, buf.data (), buf.size ()); if (nread < 0 || static_cast(nread) != alloc_size) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: %s (nread: %zd; errno: %d)", std::strerror (errno), nread, errno); return false; } @@ -388,9 +388,9 @@ bool Zip::zip_scan_entries (int apk_fd, std::string_view const& apk_path, ScanCa ); } - log_debug (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); - log_debug (LOG_ASSEMBLY, "Central directory size: {}", cd_size); - log_debug (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); + log_debug (LOG_ASSEMBLY, "Central directory offset: %u", cd_offset); + log_debug (LOG_ASSEMBLY, "Central directory size: %u", cd_size); + log_debug (LOG_ASSEMBLY, "Central directory entries: %u", cd_entries); off_t retval = ::lseek (apk_fd, static_cast(cd_offset), SEEK_SET); if (retval < 0) { @@ -472,7 +472,7 @@ void Zip::scan_archive (std::string_view const& apk_path, ScanCallbackFn entry_c ) ); } - log_debug (LOG_ASSEMBLY, "APK {} FD: {}", apk_path, fd); + log_debug (LOG_ASSEMBLY, "APK %.*s FD: %d", static_cast(apk_path.length ()), apk_path.data (), fd); if (!zip_scan_entries (fd, apk_path, entry_cb)) { return; } @@ -480,8 +480,9 @@ void Zip::scan_archive (std::string_view const& apk_path, ScanCallbackFn entry_c if (close (fd) < 0) { log_warn ( LOG_ASSEMBLY, - "Failed to close file descriptor for {}. {}", - apk_path, + "Failed to close file descriptor for %.*s. %s", + static_cast(apk_path.length ()), + apk_path.data (), strerror (errno) ); } diff --git a/src/native/common/include/runtime-base/dso-loader.hh b/src/native/common/include/runtime-base/dso-loader.hh index f44947453b4..753d91361bb 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_info (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_info (LOG_ASSEMBLY, "Shared library '%.*s' not found", static_cast(path.length ()), path.data ()); return nullptr; } } @@ -60,7 +60,7 @@ 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_info (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 +75,7 @@ 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_debug (LOG_ASSEMBLY, "Shared library %.*s loaded (handle %p)", static_cast(full_name.length ()), full_name.data (), handle); return handle; } @@ -85,8 +85,9 @@ namespace xamarin::android { } log_error ( 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 +96,7 @@ 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_debug (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 +176,9 @@ 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_debug (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/jni-wrappers.hh b/src/native/common/include/runtime-base/jni-wrappers.hh index 679aed3df59..2978e6e1d33 100644 --- a/src/native/common/include/runtime-base/jni-wrappers.hh +++ b/src/native/common/include/runtime-base/jni-wrappers.hh @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -162,7 +163,11 @@ namespace xamarin::android if (_arr != nullptr) { len = static_cast(_env->GetArrayLength (_arr)); if (len > sizeof (static_wrappers) / sizeof (jstring_wrapper)) { - wrappers = new jstring_wrapper [len]; + wrappers = static_cast (std::malloc (len * sizeof (jstring_wrapper))); + abort_unless (wrappers != nullptr, "Failed to allocate jstring array wrappers"); + for (size_t i = 0; i < len; i++) { + ::new (static_cast(&wrappers [i])) jstring_wrapper (); + } } else { wrappers = static_wrappers; } @@ -175,7 +180,10 @@ namespace xamarin::android ~jstring_array_wrapper () noexcept { if (wrappers != nullptr && wrappers != static_wrappers) { - delete[] wrappers; + for (size_t i = 0; i < len; i++) { + wrappers [i].~jstring_wrapper (); + } + std::free (wrappers); } } 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..fe7e9d635b0 100644 --- a/src/native/common/include/runtime-base/mainthread-dso-loader.hh +++ b/src/native/common/include/runtime-base/mainthread-dso-loader.hh @@ -74,7 +74,7 @@ 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_debug (LOG_ASSEMBLY, "Running DSO loader on thread %d, dispatching to main thread", gettid ()); undecorated_library_name = undecorated_name; load_success = false; @@ -83,7 +83,7 @@ namespace xamarin::android { if (nbytes == -1) { log_warn ( 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 +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_warn (LOG_ASSEMBLY, "Timeout while waiting for shared library '{}' to load."sv, full_name); + log_warn (LOG_ASSEMBLY, "Timeout while waiting for shared library '%.*s' to load.", static_cast(full_name.length ()), full_name.data ()); return false; } @@ -136,9 +136,10 @@ namespace xamarin::android { log_debug ( 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/strings.hh b/src/native/common/include/runtime-base/strings.hh index 8e6bf8cbaea..91e7fddf070 100644 --- a/src/native/common/include/runtime-base/strings.hh +++ b/src/native/common/include/runtime-base/strings.hh @@ -1,16 +1,18 @@ #pragma once -#include #include #include #include #include +#include #include #include #include #include +#include "java-interop-logger.h" #include +#include #if defined(XA_HOST_MONOVM) #include @@ -21,6 +23,8 @@ using Constants = xamarin::android::internal::SharedConstants; #endif namespace xamarin::android { + void log_write_fmt (LogCategories category, LogLevel level, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4))); + static constexpr size_t SENSIBLE_TYPE_NAME_LENGTH = 128uz; static constexpr size_t SENSIBLE_PATH_MAX = 256uz; @@ -205,7 +209,7 @@ namespace xamarin::android { } if (!can_access (start_index)) { - log_error (LOG_DEFAULT, "Cannot convert string to integer, index {} is out of range", start_index); + log_write_fmt (LOG_DEFAULT, LogLevel::Error, "Cannot convert string to integer, index %zu is out of range", start_index); return false; } @@ -229,17 +233,24 @@ namespace xamarin::android { } if (out_of_range || errno == ERANGE) { - log_error (LOG_DEFAULT, "Value {} is out of range of this type ({}..{})", reinterpret_cast(s), static_cast(min), static_cast(max)); + log_write_fmt ( + LOG_DEFAULT, + LogLevel::Error, + "Value %s is out of range of this type (%lld..%llu)", + reinterpret_cast(s), + static_cast(min), + static_cast(max) + ); return false; } if (endp == s) { - log_error (LOG_DEFAULT, "Value {} does not represent a base {} integer", reinterpret_cast(s), base); + log_write_fmt (LOG_DEFAULT, LogLevel::Error, "Value %s does not represent a base %d integer", reinterpret_cast(s), base); return false; } if (*endp != '\0') { - log_error (LOG_DEFAULT, "Value {} has non-numeric characters at the end", reinterpret_cast(s)); + log_write_fmt (LOG_DEFAULT, LogLevel::Error, "Value %s has non-numeric characters at the end", reinterpret_cast(s)); return false; } @@ -274,9 +285,6 @@ namespace xamarin::android { template class local_storage { - protected: - using LocalStoreArray = std::array; - public: static constexpr bool has_resize = HasResize; @@ -287,19 +295,19 @@ namespace xamarin::android { init_store (size < MaxStackSize ? MaxStackSize : size); } - virtual ~local_storage () + ~local_storage () { free_store (); } auto get () noexcept -> T* { - return allocated_store == nullptr ? local_store.data () : allocated_store; + return allocated_store == nullptr ? local_store : allocated_store; } auto get () const noexcept -> const T* { - return allocated_store == nullptr ? local_store.data () : allocated_store; + return allocated_store == nullptr ? local_store : allocated_store; } auto size () const noexcept -> size_t @@ -312,7 +320,8 @@ namespace xamarin::android { void init_store (size_t new_size) noexcept { if (new_size > MaxStackSize) { - allocated_store = new T[new_size]; + allocated_store = static_cast (std::malloc (new_size * sizeof (T))); + abort_unless (allocated_store != nullptr, "Failed to allocate local string storage"); } else { allocated_store = nullptr; } @@ -326,11 +335,12 @@ namespace xamarin::android { return; } - delete[] allocated_store; + std::free (allocated_store); + allocated_store = nullptr; } [[gnu::always_inline]] - auto get_local_store () noexcept -> LocalStoreArray& + auto get_local_store () noexcept -> T* { return local_store; } @@ -343,7 +353,7 @@ namespace xamarin::android { private: size_t store_size; - LocalStoreArray local_store; + T local_store[MaxStackSize]; T* allocated_store; }; @@ -416,11 +426,11 @@ namespace xamarin::android { T* new_allocated_store = base::get_allocated_store (); if (old_allocated_store != nullptr) { std::memcpy (new_allocated_store, old_allocated_store, old_size); - delete[] old_allocated_store; + std::free (old_allocated_store); return; } - std::memcpy (new_allocated_store, base::get_local_store ().data (), MaxStackSize); + std::memcpy (new_allocated_store, base::get_local_store (), MaxStackSize); } }; 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..44ba4d34092 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_debug (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]] { diff --git a/src/native/common/include/runtime-base/timing-internal.hh b/src/native/common/include/runtime-base/timing-internal.hh index 31099b86322..113388a952b 100644 --- a/src/native/common/include/runtime-base/timing-internal.hh +++ b/src/native/common/include/runtime-base/timing-internal.hh @@ -260,7 +260,7 @@ namespace xamarin::android { // likely we'll run out of memory way, way, way before that happens size_t old_size = events.capacity (); events.reserve (old_size << 1); - log_warn (LOG_TIMING, "Reallocated timing event buffer from {} to {}"sv, old_size, events.size ()); + log_write_fmt (LOG_TIMING, LogLevel::Warn, "Reallocated timing event buffer from %zu to %zu", old_size, events.size ()); } } @@ -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_warn (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_warn (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_warn (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_warn (LOG_TIMING, "FastTiming::add_more_info called without prior FastTiming::start_event called"); return; } @@ -378,7 +378,7 @@ namespace xamarin::android { { struct timespec t; if (clock_gettime (CLOCK_MONOTONIC_RAW, &t) != 0) [[unlikely]] { - log_warn (LOG_TIMING, "clock_gettime failed for CLOCK_MONOTONIC_RAW: {}"sv, optional_string (strerror (errno))); + log_write_fmt (LOG_TIMING, LogLevel::Warn, "clock_gettime failed for CLOCK_MONOTONIC_RAW: %s", optional_string (strerror (errno))); return {}; // Results will be nonsensical, but no point in aborting the app } return time_point (chrono::seconds (t.tv_sec) + chrono::nanoseconds (t.tv_nsec)); @@ -494,11 +494,7 @@ namespace xamarin::android { return; } - log_warn ( - LOG_TIMING, - "Unknown event kind '{}' logged"sv, - static_cast>(kind) - ); + log_write_fmt (LOG_TIMING, LogLevel::Warn, "Unknown event kind '%u' logged", static_cast(kind)); append_desc ("unknown event kind"sv); } @@ -510,7 +506,7 @@ namespace xamarin::android { auto is_valid_event_index (size_t index, std::source_location sloc = std::source_location::current ()) const noexcept -> bool { if (index >= events.capacity ()) [[unlikely]] { - log_warn (LOG_TIMING, "Invalid event index passed to method '{}'"sv, sloc.function_name ()); + log_write_fmt (LOG_TIMING, LogLevel::Warn, "Invalid event index passed to method '%s'", sloc.function_name ()); return false; } diff --git a/src/native/common/include/runtime-base/timing.hh b/src/native/common/include/runtime-base/timing.hh index 6e883c240f8..584d69c266e 100644 --- a/src/native/common/include/runtime-base/timing.hh +++ b/src/native/common/include/runtime-base/timing.hh @@ -83,17 +83,19 @@ namespace xamarin::android return; } - using namespace std::literals; auto interval = seq->end - seq->start; // nanoseconds - auto text = std::format ( - "{}; elapsed: {}:{}::{}"sv, - message == nullptr ? ""sv : message, - static_cast((std::chrono::duration_cast(interval).count ())), - static_cast((std::chrono::duration_cast(interval)).count ()), - static_cast((interval % 1ms).count ()) + auto seconds = static_cast((std::chrono::duration_cast(interval).count ())); + auto milliseconds = static_cast((std::chrono::duration_cast(interval)).count ()); + auto nanoseconds = static_cast((interval % std::chrono::milliseconds (1)).count ()); + log_write_fmt ( + LOG_TIMING, + level, + "%s; elapsed: %llu:%llu::%llu", + message == nullptr ? "" : message, + static_cast(seconds), + static_cast(milliseconds), + static_cast(nanoseconds) ); - - log_write (LOG_TIMING, level, text.c_str ()); } private: diff --git a/src/native/common/include/shared/cpp-util.hh b/src/native/common/include/shared/cpp-util.hh index 6693ac69793..13e6d915218 100644 --- a/src/native/common/include/shared/cpp-util.hh +++ b/src/native/common/include/shared/cpp-util.hh @@ -6,17 +6,19 @@ #include #include #include -#include #include -#include #include #include -#include #include -#include +#include "java-interop-logger.h" #include +#include + +namespace xamarin::android { + void log_write_fmt (LogCategories category, LogLevel level, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4))); +} namespace xamarin::android::detail { [[gnu::always_inline, gnu::flatten]] @@ -33,49 +35,6 @@ namespace xamarin::android::detail { return ret == -1 ? "Out of memory" : message; } - [[gnu::always_inline]] - static inline std::string get_function_name (const char *signature) - { - using std::operator""sv; - - std::string_view sig { signature }; - if (sig.length () == 0) { - return ""; - } - - auto splitSignature = sig | std::views::split ("::"sv) | std::ranges::to> (); - - std::string ret; - if (splitSignature.size () > 1) { - ret.append (splitSignature [splitSignature.size () - 2]); - ret.append ("::"sv); - } - std::string_view func_name { splitSignature[splitSignature.size () - 1] }; - std::string_view::size_type args_pos = func_name.find ('('); - std::string_view::size_type name_start_pos = func_name.find (' '); - - if (name_start_pos == std::string_view::npos) { - name_start_pos = 0; - } else { - name_start_pos++; // point to after the space which separates return type from name - if (name_start_pos >= func_name.length ()) [[unlikely]] { - name_start_pos = 0; - } - } - - if (args_pos == std::string_view::npos) { - ret.append (func_name.substr (name_start_pos)); - } else { - // If there's a snafu with positions, start from 0 - if (name_start_pos >= args_pos || name_start_pos > func_name.length ()) [[unlikely]] { - name_start_pos = 0; - } - - ret.append (func_name.substr (name_start_pos, args_pos - name_start_pos)); - } - - return ret; - } } template F> @@ -110,11 +69,11 @@ abort_if_invalid_pointer_argument (T *ptr, const char *ptr_name, std::source_loc abort_unless ( ptr != nullptr, [&ptr_name, &sloc] { - return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a valid pointer", - xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), - ptr_name - ); + return xamarin::android::detail::_format_message ( + "%s: parameter '%s' must be a valid pointer", + sloc.function_name (), + ptr_name + ); }, sloc ); @@ -127,11 +86,11 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l abort_unless ( arg > 0, [&arg_name, &sloc] { - return xamarin::android::detail::_format_message ( - "%s: parameter '%s' must be a positive integer", - xamarin::android::detail::get_function_name (sloc.function_name ()).c_str (), - arg_name - ); + return xamarin::android::detail::_format_message ( + "%s: parameter '%s' must be a positive integer", + sloc.function_name (), + arg_name + ); }, sloc ); @@ -142,7 +101,7 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l [[gnu::always_inline]] inline void pd_log_location (std::source_location sloc = std::source_location::current ()) noexcept { - log_warn (LOG_DEFAULT, "loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ()); + xamarin::android::log_write_fmt (LOG_DEFAULT, xamarin::android::LogLevel::Warn, "loc: %s:%u ('%s')", sloc.file_name (), sloc.line (), sloc.function_name ()); } namespace xamarin::android diff --git a/src/native/common/include/shared/helpers.hh b/src/native/common/include/shared/helpers.hh index 22e29b40f25..f1ec1fb6ab4 100644 --- a/src/native/common/include/shared/helpers.hh +++ b/src/native/common/include/shared/helpers.hh @@ -56,6 +56,9 @@ namespace xamarin::android [[noreturn]] static void abort_application (LogCategories category, const char *message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept; + [[noreturn]] + static void abort_applicationf (LogCategories category, std::source_location sloc, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4))); + [[noreturn]] static void abort_application (LogCategories category, std::string const& message, bool log_location = true, std::source_location sloc = std::source_location::current ()) noexcept { diff --git a/src/native/common/runtime-base/timing-internal.cc b/src/native/common/runtime-base/timing-internal.cc index ebf8d111893..818c08b8ba1 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_warn (LOG_TIMING, "Failed to parse duration in milliseconds from '%s'", param.start ()); duration_ms = default_duration_milliseconds; } continue; @@ -200,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_error (LOG_TIMING, "[2/2] Unable to create the performance measurements file '{}'"sv, timing_log_path.get ()); + log_error (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_warn (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_info (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 ()) { diff --git a/src/native/mono/monodroid/debug.cc b/src/native/mono/monodroid/debug.cc index d37ad8cf5ff..67ec1838970 100644 --- a/src/native/mono/monodroid/debug.cc +++ b/src/native/mono/monodroid/debug.cc @@ -99,7 +99,7 @@ Debug::monodroid_profiler_load (const char *libmono_path, const char *desc, cons if (!found) log_warn (LOG_DEFAULT, - "The '{}' profiler wasn't found in the main executable nor could it be loaded from '{}'.", + "The '%s' profiler wasn't found in the main executable nor could it be loaded from '%s'.", optional_string (mname.get ()), optional_string (libname.get ()) ); @@ -113,7 +113,7 @@ bool Debug::load_profiler (void *handle, const char *desc, const char *symbol) { ProfilerInitializer func = reinterpret_cast (java_interop_lib_symbol (handle, symbol, nullptr)); - log_warn (LOG_DEFAULT, "Looking for profiler init symbol '{}'? {:p}", optional_string (symbol), reinterpret_cast(func)); + log_warn (LOG_DEFAULT, "Looking for profiler init symbol '%s'? %p", optional_string (symbol), reinterpret_cast(func)); if (func != nullptr) { func (desc); @@ -143,7 +143,7 @@ Debug::parse_options (char *options, ConnOptions *opts) { char **args, **ptr; - log_info (LOG_DEFAULT, "Connection options: '{}'", optional_string (options)); + log_info (LOG_DEFAULT, "Connection options: '%s'", optional_string (options)); args = Util::monodroid_strsplit (options, ",", 0); @@ -153,12 +153,12 @@ Debug::parse_options (char *options, ConnOptions *opts) if (strstr (arg, "port=") == arg) { int port = atoi (arg + strlen ("port=")); if (port < 0 || port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid debug port value {}", port); + log_error (LOG_DEFAULT, "Invalid debug port value %u", port); continue; } conn_port = static_cast(port); - log_info (LOG_DEFAULT, "XS port = {}", conn_port); + log_info (LOG_DEFAULT, "XS port = %u", conn_port); } else if (strstr (arg, "timeout=") == arg) { char *endp; @@ -167,7 +167,7 @@ Debug::parse_options (char *options, ConnOptions *opts) if ((endp == arg) || (*endp != '\0')) log_error (LOG_DEFAULT, "Invalid --timeout argument."sv); } else { - log_info (LOG_DEFAULT, "Unknown connection option: '{}'", optional_string (arg)); + log_info (LOG_DEFAULT, "Unknown connection option: '%s'", optional_string (arg)); } } } @@ -191,7 +191,7 @@ Debug::start_connection (char *options) cur_time = time (nullptr); if (opts.timeout_time && cur_time > opts.timeout_time) { - log_warn (LOG_DEBUGGER, "Not connecting to IDE as the timeout value has been reached; current-time: {} timeout: {}", cur_time, opts.timeout_time); + log_warn (LOG_DEBUGGER, "Not connecting to IDE as the timeout value has been reached; current-time: %lld timeout: %lld", static_cast(cur_time), static_cast(opts.timeout_time)); return DebuggerConnectionStatus::Unconnected; } @@ -202,7 +202,7 @@ Debug::start_connection (char *options) res = pthread_create (&conn_thread_id, nullptr, xamarin::android::conn_thread, this); if (res) { - log_error (LOG_DEFAULT, "Failed to create connection thread: {}", strerror (errno)); + log_error (LOG_DEFAULT, "Failed to create connection thread: %s", strerror (errno)); return DebuggerConnectionStatus::Error; } @@ -265,20 +265,20 @@ Debug::process_connection (int fd) return false; } if (rv <= 0) { - log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); + log_info (LOG_DEFAULT, "Error while receiving command from XS (%s)", strerror (errno)); return false; } rv = Util::recv_uninterrupted (fd, command, cmd_len); if (rv <= 0) { - log_info (LOG_DEFAULT, "Error while receiving command from XS ({})", strerror (errno)); + log_info (LOG_DEFAULT, "Error while receiving command from XS (%s)", strerror (errno)); return false; } // null-terminate command [cmd_len] = 0; - log_info (LOG_DEFAULT, "Received cmd: '{}'.", optional_string (command)); + log_info (LOG_DEFAULT, "Received cmd: '%s'.", optional_string (command)); if (process_cmd (fd, command)) return true; @@ -290,14 +290,14 @@ Debug::handle_server_connection (void) { int listen_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); if (listen_socket == -1) { - log_info (LOG_DEFAULT, "Could not create socket for XS to connect to: {}", strerror (errno)); + log_info (LOG_DEFAULT, "Could not create socket for XS to connect to: %s", strerror (errno)); return 1; } int flags = 1; int rv = setsockopt (listen_socket, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof (flags)); if (rv == -1 && Util::should_log (LOG_DEFAULT)) { - log_info_nocheck_fmt (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket ({})", strerror (errno)); + log_info_nocheck_fmt (LOG_DEFAULT, "Could not set SO_REUSEADDR on the listening socket (%s)", strerror (errno)); // not a fatal failure } @@ -311,7 +311,7 @@ Debug::handle_server_connection (void) listen_addr.sin_addr.s_addr = INADDR_ANY; rv = bind (listen_socket, (struct sockaddr *) &listen_addr, sizeof (listen_addr)); if (rv == -1) { - log_info (LOG_DEFAULT, "Could not bind to address: {}", strerror (errno)); + log_info (LOG_DEFAULT, "Could not bind to address: %s", strerror (errno)); rv = 2; goto cleanup; } @@ -323,7 +323,7 @@ Debug::handle_server_connection (void) rv = listen (listen_socket, 1); if (rv == -1) { - log_info (LOG_DEFAULT, "Could not listen for XS: {}", strerror (errno)); + log_info (LOG_DEFAULT, "Could not listen for XS: %s", strerror (errno)); rv = 2; goto cleanup; } @@ -373,7 +373,7 @@ Debug::handle_server_connection (void) } while (rv == -1 && errno == EINTR); if (rv == -1) { - log_info (LOG_DEFAULT, "Failed while waiting for XS to connect: {}", strerror (errno)); + log_info (LOG_DEFAULT, "Failed while waiting for XS to connect: %s", strerror (errno)); rv = 2; goto cleanup; } @@ -381,18 +381,18 @@ Debug::handle_server_connection (void) socklen_t len = sizeof (struct sockaddr_in); int fd = accept (listen_socket, (struct sockaddr *) &listen_addr, &len); if (fd == -1) { - log_info (LOG_DEFAULT, "Failed to accept connection from XS: {}", strerror (errno)); + log_info (LOG_DEFAULT, "Failed to accept connection from XS: %s", strerror (errno)); rv = 3; goto cleanup; } flags = 1; if (setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &flags, sizeof (flags)) < 0) { - log_info (LOG_DEFAULT, "Could not set TCP_NODELAY on socket ({})", strerror (errno)); + log_info (LOG_DEFAULT, "Could not set TCP_NODELAY on socket (%s)", strerror (errno)); // not a fatal failure } - log_info (LOG_DEFAULT, "Successfully received connection from XS on port {}, fd: {}", listen_port, fd); + log_info (LOG_DEFAULT, "Successfully received connection from XS on port %u, fd: %d", listen_port, fd); need_new_conn = process_connection (fd); } @@ -444,7 +444,7 @@ Debug::process_cmd (int fd, char *cmd) constexpr std::string_view PONG_REPLY { "pong" }; if (strcmp (cmd, PING_CMD.data ()) == 0) { if (!Util::send_uninterrupted (fd, const_cast (reinterpret_cast (PONG_REPLY.data ())), 5)) - log_error (LOG_DEFAULT, "Got keepalive request from XS, but could not send response back ({})", strerror (errno)); + log_error (LOG_DEFAULT, "Got keepalive request from XS, but could not send response back (%s)", strerror (errno)); return false; } @@ -490,7 +490,7 @@ Debug::process_cmd (int fd, char *cmd) profiler_fd = fd; profiler_description = Util::monodroid_strdup_printf ("%s,output=#%i", prof, profiler_fd); } else { - log_error (LOG_DEFAULT, "Unknown profiler: '{}'", optional_string (prof)); + log_error (LOG_DEFAULT, "Unknown profiler: '%s'", optional_string (prof)); } /* Notify the main thread (start_profiling ()) */ profiler_configured = true; @@ -499,7 +499,7 @@ Debug::process_cmd (int fd, char *cmd) pthread_mutex_unlock (&process_cmd_mutex); return use_fd; } else { - log_error (LOG_DEFAULT, "Unsupported command: '{}'", optional_string (cmd)); + log_error (LOG_DEFAULT, "Unsupported command: '%s'", optional_string (cmd)); } return false; @@ -529,7 +529,7 @@ Debug::start_debugging (void) // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: %s", optional_string (debug_arg)); if (enable_soft_breakpoints ()) { constexpr std::string_view soft_breakpoints { "--soft-breakpoints" }; @@ -556,7 +556,7 @@ Debug::start_profiling () if (!profiler_description) return; - log_info (LOG_DEFAULT, "Loading profiler: '{}'", profiler_description); + log_info (LOG_DEFAULT, "Loading profiler: '%s'", profiler_description); monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), profiler_description, nullptr); } @@ -576,7 +576,7 @@ Debug::enable_soft_breakpoints (void) uname (&name); for (const char** ptr = soft_breakpoint_kernel_list; *ptr; ptr++) { if (strcmp (name.release, *ptr) == 0) { - log_info (LOG_DEBUGGER, "soft breakpoints enabled due to kernel version match ({})", name.release); + log_info (LOG_DEBUGGER, "soft breakpoints enabled due to kernel version match (%s)", name.release); return 1; } } @@ -584,17 +584,17 @@ Debug::enable_soft_breakpoints (void) char *value; /* Soft breakpoints are enabled by default */ if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS, &value) <= 0) { - log_info (LOG_DEBUGGER, "soft breakpoints enabled by default ({} property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ()); + log_info (LOG_DEBUGGER, "soft breakpoints enabled by default (%s property not defined)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data ()); return 1; } bool ret; if (strcmp ("0", value) == 0) { ret = false; - log_info (LOG_DEBUGGER, "soft breakpoints disabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); + log_info (LOG_DEBUGGER, "soft breakpoints disabled (%s property set to %s)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); } else { ret = true; - log_info (LOG_DEBUGGER, "soft breakpoints enabled ({} property set to {})", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); + log_info (LOG_DEBUGGER, "soft breakpoints enabled (%s property set to %s)", SharedConstants::DEBUG_MONO_SOFT_BREAKPOINTS.data (), optional_string (value)); } delete[] value; return ret; diff --git a/src/native/mono/monodroid/embedded-assemblies-zip.cc b/src/native/mono/monodroid/embedded-assemblies-zip.cc index 2453f599b08..d3618cc9911 100644 --- a/src/native/mono/monodroid/embedded-assemblies-zip.cc +++ b/src/native/mono/monodroid/embedded-assemblies-zip.cc @@ -22,7 +22,7 @@ EmbeddedAssemblies::zip_load_entry_common (size_t entry_index, std::vector } auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (assembly_store_map, entry_name.get ()); - log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: {:p}; size: {}", payload_start, payload_size); + log_debug (LOG_ASSEMBLY, "Adjusted assembly store pointer: %p; size: %zu", payload_start, payload_size); auto header = static_cast(payload_start); if (header->magic != ASSEMBLY_STORE_MAGIC) { @@ -267,7 +267,7 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& dynamic_local_string entry_name; bool assembly_store_found = false; - log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('{}')", assembly_store_file_path.data ()); + log_debug (LOG_ASSEMBLY, "Looking for assembly stores in APK ('%s')", assembly_store_file_path.data ()); for (size_t i = 0uz; i < num_entries; i++) { if (all_required_zip_entries_found ()) { need_to_scan_more_apks = false; @@ -303,11 +303,11 @@ EmbeddedAssemblies::zip_load_assembly_store_entries (std::vector const& log_debug ( LOG_ASSEMBLY, - "Found a shared library entry {} (index: {}; name: {}; hash: {:x}; apk offset: {})", + "Found a shared library entry %s (index: %u; name: %s; hash: %zx; apk offset: %u)", optional_string (entry_name.get ()), number_of_zip_dso_entries, optional_string (name), - apk_entry->name_hash, + static_cast(apk_entry->name_hash), apk_entry->offset ); number_of_zip_dso_entries++; @@ -332,9 +332,9 @@ EmbeddedAssemblies::zip_load_entries (int fd, const char *apk_name, [[maybe_unus ); } #ifdef DEBUG - log_info (LOG_ASSEMBLY, "Central directory offset: {}", cd_offset); - log_info (LOG_ASSEMBLY, "Central directory size: {}", cd_size); - log_info (LOG_ASSEMBLY, "Central directory entries: {}", cd_entries); + log_info (LOG_ASSEMBLY, "Central directory offset: %u", cd_offset); + log_info (LOG_ASSEMBLY, "Central directory size: %u", cd_size); + log_info (LOG_ASSEMBLY, "Central directory entries: %u", cd_entries); #endif off_t retval = ::lseek (fd, static_cast(cd_offset), SEEK_SET); if (retval < 0) { @@ -412,7 +412,7 @@ EmbeddedAssemblies::set_entry_data (XamarinAndroidBundledAssembly &entry, ZipEnt log_debug ( LOG_ASSEMBLY, - "Set bundled assembly entry data. file name: '{}'; entry name: '{}'; data size: {}", + "Set bundled assembly entry data. file name: '%s'; entry name: '%s'; data size: %u", optional_string (entry.file_name), optional_string (entry.name), entry.data_size @@ -437,14 +437,14 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ // The simplest case - no file comment off_t ret = ::lseek (fd, -ZIP_EOCD_LEN, SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + log_error (LOG_ASSEMBLY, "Unable to seek into the APK to find ECOD: %s (ret: %lld; errno: %d)", std::strerror (errno), static_cast(ret), errno); return false; } std::array eocd; ssize_t nread = ::read (fd, eocd.data (), eocd.size ()); if (nread < 0 || nread != eocd.size ()) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, "Failed to read EOCD from the APK: %s (nread: %zd; errno: %d)", std::strerror (errno), nread, errno); return false; } @@ -464,7 +464,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ constexpr size_t alloc_size = 65535uz + ZIP_EOCD_LEN; // 64k is the biggest comment size allowed ret = ::lseek (fd, static_cast(-alloc_size), SEEK_END); if (ret < 0) { - log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: {} (ret: {}; errno: {})", std::strerror (errno), ret, errno); + log_error (LOG_ASSEMBLY, "Unable to seek into the file to find ECOD before APK comment: %s (ret: %lld; errno: %d)", std::strerror (errno), static_cast(ret), errno); return false; } @@ -473,7 +473,7 @@ EmbeddedAssemblies::zip_read_cd_info (int fd, uint32_t& cd_offset, uint32_t& cd_ nread = ::read (fd, buf.data (), buf.size ()); if (nread < 0 || static_cast(nread) != alloc_size) { - log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: {} (nread: {}; errno: {})", std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, "Failed to read EOCD and comment from the APK: %s (nread: %zd; errno: %d)", std::strerror (errno), nread, errno); return false; } @@ -507,8 +507,8 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no if (result < 0) { log_error ( LOG_ASSEMBLY, - "Failed to seek to archive entry local header at offset {}. {} (result: {}; errno: {})", - state.local_header_offset, std::strerror (errno), result, errno + "Failed to seek to archive entry local header at offset %u. %s (result: %lld; errno: %d)", + state.local_header_offset, std::strerror (errno), static_cast(result), errno ); return false; } @@ -518,32 +518,32 @@ EmbeddedAssemblies::zip_adjust_data_offset (int fd, ZipEntryLoadState &state) no ssize_t nread = ::read (fd, local_header.data (), local_header.size ()); if (nread < 0 || nread != ZIP_LOCAL_LEN) { - log_error (LOG_ASSEMBLY, "Failed to read local header at offset {}: {} (nread: {}; errno: {})", state.local_header_offset, std::strerror (errno), nread, errno); + log_error (LOG_ASSEMBLY, "Failed to read local header at offset %u: %s (nread: %zd; errno: %d)", state.local_header_offset, std::strerror (errno), nread, errno); return false; } size_t index = 0; if (!zip_read_field (local_header, index, signature)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset {}", state.local_header_offset); + log_error (LOG_ASSEMBLY, "Failed to read Local Header entry signature at offset %u", state.local_header_offset); return false; } if (memcmp (signature.data (), ZIP_LOCAL_MAGIC.data (), signature.size ()) != 0) { - log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset {}", state.local_header_offset); + log_error (LOG_ASSEMBLY, "Invalid Local Header entry signature at offset %u", state.local_header_offset); return false; } uint16_t file_name_length; index = LH_FILE_NAME_LENGTH_OFFSET; if (!zip_read_field (local_header, index, file_name_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset {}", (state.local_header_offset + index)); + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'file name length' field at offset %zu", (state.local_header_offset + index)); return false; } uint16_t extra_field_length; index = LH_EXTRA_LENGTH_OFFSET; if (!zip_read_field (local_header, index, extra_field_length)) { - log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset {}", (state.local_header_offset + index)); + log_error (LOG_ASSEMBLY, "Failed to read Local Header 'extra field length' field at offset %zu", (state.local_header_offset + index)); return false; } @@ -585,7 +585,7 @@ template EmbeddedAssemblies::zip_ensure_valid_params (T const& buf, size_t index, size_t to_read) noexcept { if (index + to_read > buf.size ()) { - log_error (LOG_ASSEMBLY, "Buffer too short to read {} bytes of data", to_read); + log_error (LOG_ASSEMBLY, "Buffer too short to read %zu bytes of data", to_read); return false; } diff --git a/src/native/mono/monodroid/embedded-assemblies.cc b/src/native/mono/monodroid/embedded-assemblies.cc index c3aa3488aa8..dfb4899136b 100644 --- a/src/native/mono/monodroid/embedded-assemblies.cc +++ b/src/native/mono/monodroid/embedded-assemblies.cc @@ -150,7 +150,7 @@ EmbeddedAssemblies::get_assembly_data (uint8_t *data, uint32_t data_size, [[mayb ) ); } else { - log_debug (LOG_ASSEMBLY, "Compressed assembly '{}' is smaller than when the application was built. Adjusting accordingly.", optional_string (name)); + log_debug (LOG_ASSEMBLY, "Compressed assembly '%s' is smaller than when the application was built. Adjusting accordingly.", optional_string (name)); } cad.uncompressed_file_size = header->uncompressed_length; } @@ -248,7 +248,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc ); if (already_mapped) { - log_debug (LOG_ASSEMBLY, "Assembly {} already mmapped by another thread, unmapping our copy", optional_string (file.name)); + log_debug (LOG_ASSEMBLY, "Assembly %s already mmapped by another thread, unmapping our copy", optional_string (file.name)); munmap (map_info.area, file.data_size); map_info.area = nullptr; } @@ -265,7 +265,7 @@ EmbeddedAssemblies::map_runtime_file (XamarinAndroidBundledAssembly& file) noexc log_info_nocheck_fmt ( LOG_ASSEMBLY, - "file-offset: {:<8x} start: {:<8p} end: {:<8p} len: {:<12} zip-entry: {} name: {} [{}]", + "file-offset: %-8x start: %-8p end: %-8p len: %-12u zip-entry: %s name: %s [%s]", file.data_offset, static_cast(file.data), pointer_add (file.data, file.data_size), @@ -307,7 +307,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (strcmp (assembly.name, abi_name.get ()) != 0) { return nullptr; } else { - log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '{}'", optional_string (abi_name.get ())); + log_debug (LOG_ASSEMBLY, "open_from_bundles: found architecture-specific: '%s'", optional_string (abi_name.get ())); } } @@ -341,7 +341,7 @@ EmbeddedAssemblies::load_bundled_assembly ( if (debug_file.data != nullptr) { if (debug_file.data_size > std::numeric_limits::max ()) { - log_warn (LOG_ASSEMBLY, "Debug info file '{}' is too big for Mono to consume", optional_string (debug_file.name)); + log_warn (LOG_ASSEMBLY, "Debug info file '%s' is too big for Mono to consume", optional_string (debug_file.name)); } else { mono_debug_open_image_from_memory (image, reinterpret_cast(debug_file.data), static_cast(debug_file.data_size)); } @@ -353,7 +353,7 @@ EmbeddedAssemblies::load_bundled_assembly ( MonoImageOpenStatus status; MonoAssembly *a = mono_assembly_load_from_full (image, name.get (), &status, ref_only); if (a == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (name.get ()), optional_string (mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '%s'. %s", optional_string (name.get ()), optional_string (mono_image_strerror (status))); return nullptr; } @@ -368,7 +368,7 @@ EmbeddedAssemblies::individual_assemblies_open_from_bundles (dynamic_local_strin name.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '{}'", optional_string (name.get ())); + log_debug (LOG_ASSEMBLY, "individual_assemblies_open_from_bundles: looking for bundled name: '%s'", optional_string (name.get ())); dynamic_local_string abi_name; abi_name @@ -415,16 +415,16 @@ template EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string& name, TLoaderData loader_data, bool ref_only) noexcept { hash_t name_hash = xxhash::hash (name.get (), name.length ()); - log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '{}' (hash {:x})", optional_string (name.get ()), name_hash); + log_debug (LOG_ASSEMBLY, "assembly_store_open_from_bundles: looking for bundled name: '%s' (hash %zx)", optional_string (name.get ()), static_cast(name_hash)); const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count); if (hash_entry == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash {:x}) not found", optional_string (name.get ()), name_hash); + log_warn (LOG_ASSEMBLY, "Assembly '%s' (hash %zx) not found", optional_string (name.get ()), static_cast(name_hash)); return nullptr; } if (hash_entry->ignore != 0) { - log_debug (LOG_ASSEMBLY, "Assembly '{}' ignored"sv, optional_string (name.get ())); + log_debug (LOG_ASSEMBLY, "Assembly '%s' ignored", optional_string (name.get ())); return nullptr; } @@ -453,7 +453,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string(assembly_runtime_info.image_data), static_cast(assembly_runtime_info.debug_info_data), static_cast(assembly_runtime_info.config_data), @@ -471,7 +471,7 @@ EmbeddedAssemblies::assembly_store_open_from_bundles (dynamic_local_string 0) { @@ -645,26 +645,26 @@ EmbeddedAssemblies::typemap_java_to_managed ([[maybe_unused]] hash_t hash, const entry = binary_search (java_type_name.get (), type_map.java_to_managed, type_map.entry_count); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}'", java_type_name.get ()); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '%s'", java_type_name.get ()); return nullptr; } const char *managed_type_name = entry->to; if (managed_type_name == nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: Java type '{}' maps either to an open generic type or an interface type.", java_type_name.get ()); + log_debug (LOG_ASSEMBLY, "typemap: Java type '%s' maps either to an open generic type or an interface type.", java_type_name.get ()); return nullptr; } - log_debug (LOG_DEFAULT, "typemap: Java type '{}' corresponds to managed type '{}'", java_type_name.get (), optional_string (managed_type_name)); + log_debug (LOG_DEFAULT, "typemap: Java type '%s' corresponds to managed type '%s'", java_type_name.get (), optional_string (managed_type_name)); MonoType *type = mono_reflection_type_from_name (const_cast(managed_type_name), nullptr); if (type == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: managed type '{}' (mapped from Java type '{}') could not be loaded", optional_string (managed_type_name), java_type_name.get ()); + log_info (LOG_ASSEMBLY, "typemap: managed type '%s' (mapped from Java type '%s') could not be loaded", optional_string (managed_type_name), java_type_name.get ()); return nullptr; } MonoReflectionType *ret = mono_type_get_object (Util::get_current_domain (), type); if (ret == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type '{}'", optional_string (managed_type_name)); + log_warn (LOG_ASSEMBLY, "typemap: unable to instantiate managed type '%s'", optional_string (managed_type_name)); return nullptr; } @@ -684,16 +684,16 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java TypeMapModule *module = java_entry != nullptr && java_entry->module_index < map_module_count ? &map_modules[java_entry->module_index] : nullptr; if (module == nullptr) { if (java_entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '{}' (hash {:x})", to_utf8 (java_type_name).get (), hash); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a managed type from Java type '%s' (hash %zx)", to_utf8 (java_type_name).get (), static_cast(hash)); } else { - log_warn (LOG_ASSEMBLY, "typemap: mapping from Java type '{}' to managed type has invalid module index {}", to_utf8 (java_type_name).get (), java_entry->module_index); + log_warn (LOG_ASSEMBLY, "typemap: mapping from Java type '%s' to managed type has invalid module index %u", to_utf8 (java_type_name).get (), java_entry->module_index); } return nullptr; } const TypeMapModuleEntry *entry = binary_search (java_entry->type_token_id, module->map, module->entry_count); if (entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping from Java type '{}' to managed type with token ID {} in module [{}]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ()); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping from Java type '%s' to managed type with token ID %u in module [%s]", to_utf8 (java_type_name).get (), java_entry->type_token_id, MonoGuidString (module->module_uuid).get ()); return nullptr; } @@ -701,14 +701,14 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java module->image = mono_image_loaded (module->assembly_name); if (module->image == nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: assembly '{}' hasn't been loaded yet, attempting a full load", optional_string (module->assembly_name)); + log_debug (LOG_ASSEMBLY, "typemap: assembly '%s' hasn't been loaded yet, attempting a full load", optional_string (module->assembly_name)); // Fake a request from MonoVM to load the assembly. MonoAssemblyName *assembly_name = mono_assembly_name_new (module->assembly_name); MonoAssembly *assm; if (assembly_name == nullptr) { - log_error (LOG_ASSEMBLY, "typemap: failed to create Mono assembly name for '{}'", optional_string (module->assembly_name)); + log_error (LOG_ASSEMBLY, "typemap: failed to create Mono assembly name for '%s'", optional_string (module->assembly_name)); assm = nullptr; } else { MonoAssemblyLoadContextGCHandle alc_gchandle = mono_alc_get_default_gchandle (); @@ -717,24 +717,24 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java } if (assm == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: failed to load managed assembly '{}'", optional_string (module->assembly_name)); + log_warn (LOG_ASSEMBLY, "typemap: failed to load managed assembly '%s'", optional_string (module->assembly_name)); } else { module->image = mono_assembly_get_image (assm); } } if (module->image == nullptr) { - log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '{}' when looking up managed type corresponding to Java type '{}'", optional_string (module->assembly_name), to_utf8 (java_type_name).get ()); + log_error (LOG_ASSEMBLY, "typemap: unable to load assembly '%s' when looking up managed type corresponding to Java type '%s'", optional_string (module->assembly_name), to_utf8 (java_type_name).get ()); return nullptr; } } - log_debug (LOG_ASSEMBLY, "typemap: java type '{}' corresponds to managed token id {} ({:x})", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id); + log_debug (LOG_ASSEMBLY, "typemap: java type '%s' corresponds to managed token id %u (%x)", to_utf8 (java_type_name).get (), java_entry->type_token_id, java_entry->type_token_id); MonoClass *klass = mono_class_get (module->image, java_entry->type_token_id); if (klass == nullptr) [[unlikely]] { log_error ( LOG_ASSEMBLY, - "typemap: unable to find managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", + "typemap: unable to find managed type with token ID %u in assembly '%s', corresponding to Java type '%s'", java_entry->type_token_id, optional_string (module->assembly_name), to_utf8 (java_type_name).get () @@ -750,7 +750,7 @@ EmbeddedAssemblies::typemap_java_to_managed (hash_t hash, const MonoString *java MonoReflectionType *ret = mono_type_get_object (domain, mono_class_get_type (klass)); if (ret == nullptr) { log_warn (LOG_ASSEMBLY, - "typemap: unable to instantiate managed type with token ID {} in assembly '{}', corresponding to Java type '{}'", + "typemap: unable to instantiate managed type with token ID %u in assembly '%s', corresponding to Java type '%s'", java_entry->type_token_id, optional_string (module->assembly_name), to_utf8 (java_type_name).get () @@ -818,7 +818,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo const TypeMapEntry *entry = typemap_managed_to_java (full_name.get ()); if (entry == nullptr) [[unlikely]] { - log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '{}'", optional_string (full_name.get ())); + log_info (LOG_ASSEMBLY, "typemap: unable to find mapping to a Java type from managed type '%s'", optional_string (full_name.get ())); return nullptr; } @@ -839,28 +839,28 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo if (mvid == nullptr) { log_warn (LOG_ASSEMBLY, "typemap: no mvid specified in call to typemap_managed_to_java"sv); } else { - log_info (LOG_ASSEMBLY, "typemap: module matching MVID [{}] not found.", MonoGuidString (mvid).get ()); + log_info (LOG_ASSEMBLY, "typemap: module matching MVID [%s] not found.", MonoGuidString (mvid).get ()); } return nullptr; } uint32_t token = mono_class_get_type_token (klass); - log_debug (LOG_ASSEMBLY, "typemap: MVID [{}] maps to assembly {}, looking for token {} ({:x}), table index {}", MonoGuidString (mvid).get (), match->assembly_name, token, token, token & 0x00FFFFFF); + log_debug (LOG_ASSEMBLY, "typemap: MVID [%s] maps to assembly %s, looking for token %u (%x), table index %u", MonoGuidString (mvid).get (), optional_string (match->assembly_name), token, token, token & 0x00FFFFFF); // Each map entry is a pair of 32-bit integers: [TypeTokenID][JavaMapArrayIndex] const TypeMapModuleEntry *entry = match->map != nullptr ? binary_search (token, match->map, match->entry_count) : nullptr; if (entry == nullptr) { if (match->map == nullptr) { - log_warn (LOG_ASSEMBLY, "typemap: module with MVID [{}] has no associated type map.", MonoGuidString (mvid).get ()); + log_warn (LOG_ASSEMBLY, "typemap: module with MVID [%s] has no associated type map.", MonoGuidString (mvid).get ()); return nullptr; } if (match->duplicate_count > 0 && match->duplicate_map != nullptr) { - log_debug (LOG_ASSEMBLY, "typemap: searching module [{}] duplicate map for token {} ({:x})", MonoGuidString (mvid).get (), token, token); + log_debug (LOG_ASSEMBLY, "typemap: searching module [%s] duplicate map for token %u (%x)", MonoGuidString (mvid).get (), token, token); entry = binary_search (token, match->duplicate_map, match->duplicate_count); } if (entry == nullptr) { - log_info (LOG_ASSEMBLY, "typemap: type with token {} ({:x}) in module [{}] ({}) not found.", token, token, MonoGuidString (mvid).get (), match->assembly_name); + log_info (LOG_ASSEMBLY, "typemap: type with token %u (%x) in module [%s] (%s) not found.", token, token, MonoGuidString (mvid).get (), optional_string (match->assembly_name)); return nullptr; } } @@ -868,7 +868,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo if (entry->java_map_index >= java_type_count) [[unlikely]] { log_warn ( LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) has invalid Java type index {}", + "typemap: type with token %u (%x) in module [%s] (%s) has invalid Java type index %u", token, token, MonoGuidString (mvid).get (), @@ -882,7 +882,7 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo if (java_entry.java_name_index >= java_type_count) [[unlikely]] { log_warn ( LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) points to invalid Java type at index {} (invalid type name index {})", + "typemap: type with token %u (%x) in module [%s] (%s) points to invalid Java type at index %u (invalid type name index %u)", token, token, MonoGuidString (mvid).get (), @@ -895,12 +895,12 @@ EmbeddedAssemblies::typemap_managed_to_java ([[maybe_unused]] MonoType *type, Mo 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 {}", entry->java_map_index); + log_warn (LOG_ASSEMBLY, "typemap: empty Java type name returned for entry at index %u", entry->java_map_index); } log_debug ( LOG_ASSEMBLY, - "typemap: type with token {} ({:x}) in module [{}] ({}) corresponds to Java type '{}'", + "typemap: type with token %u (%x) in module [%s] (%s) corresponds to Java type '%s'", token, token, MonoGuidString (mvid).get (), @@ -966,7 +966,7 @@ EmbeddedAssemblies::md_mmap_apk_file (int fd, uint32_t offset, size_t size, cons log_info ( LOG_ASSEMBLY, - " mmap_start: {:<8p}; mmap_end: {:<8p} mmap_len: {:<12} file_start: {:<8p} file_end: {:<8p} file_len: {:<12} apk descriptor: {} file: {}", + " mmap_start: %-8p; mmap_end: %-8p mmap_len: %-12zu file_start: %-8p file_end: %-8p file_len: %-12zu apk descriptor: %d file: %s", mmap_info.area, pointer_add (mmap_info.area, mmap_info.size), mmap_info.size, @@ -994,7 +994,7 @@ EmbeddedAssemblies::gather_bundled_assemblies_from_apk (const char* apk, monodro ) ); } - log_debug (LOG_ASSEMBLY, "APK {} FD: {}", optional_string (apk), fd); + log_debug (LOG_ASSEMBLY, "APK %s FD: %d", optional_string (apk), fd); zip_load_entries (fd, apk, should_register); } @@ -1023,7 +1023,7 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char if (res < 0) { log_error ( LOG_ASSEMBLY, - "typemap: failed to stat {} file '{}/{}': {}", + "typemap: failed to stat %s file '%s/%s': %s", optional_string (file_type), optional_string (dir_path), optional_string (file_path), @@ -1036,7 +1036,7 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char if (file_size < sizeof (header)) { log_error ( LOG_ASSEMBLY, - "typemap: {} file '{}/{}' is too small (must be at least {} bytes)", + "typemap: %s file '%s/%s' is too small (must be at least %zu bytes)", optional_string (file_type), optional_string (dir_path), optional_string (file_path), @@ -1049,7 +1049,7 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char if (fd < 0) { log_error ( LOG_ASSEMBLY, - "typemap: failed to open {} file {}/{} for reading: {}", + "typemap: failed to open %s file %s/%s for reading: %s", optional_string (file_type), optional_string (dir_path), optional_string (file_path), @@ -1063,7 +1063,7 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char if (nread < 0) { log_error ( LOG_ASSEMBLY, - "typemap: failed to read {} file header from '{}/{}': {}", + "typemap: failed to read %s file header from '%s/%s': %s", optional_string (file_type), optional_string (dir_path), optional_string (file_path), @@ -1072,7 +1072,7 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char } else { log_error ( LOG_ASSEMBLY, - "typemap: end of file while reading {} file header from '{}/{}'", + "typemap: end of file while reading %s file header from '%s/%s'", optional_string (file_type), optional_string (dir_path), optional_string (file_path) @@ -1085,7 +1085,7 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char if (header.magic != expected_magic) { log_error ( LOG_ASSEMBLY, - "typemap: invalid magic value in the {} file header from '{}/{}': expected {:x}, got {:x}", + "typemap: invalid magic value in the %s file header from '%s/%s': expected %x, got %x", optional_string (file_type), optional_string (dir_path), optional_string (file_path), @@ -1098,7 +1098,7 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char if (header.version != MODULE_FORMAT_VERSION) { log_error ( LOG_ASSEMBLY, - "typemap: incompatible {} format version. This build supports only version {}, file '{}/{}' uses version {}", + "typemap: incompatible %s format version. This build supports only version %u, file '%s/%s' uses version %u", optional_string (file_type), MODULE_FORMAT_VERSION, optional_string (dir_path), @@ -1117,14 +1117,14 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ size_t entry_size = header.module_file_name_width; size_t data_size = entry_size * type_map_count; if (sizeof(header) + data_size > file_size) { - log_error (LOG_ASSEMBLY, "typemap: index file is too small, expected {}, found {} bytes", data_size + sizeof(header), file_size); + log_error (LOG_ASSEMBLY, "typemap: index file is too small, expected %zu, found %zu bytes", data_size + sizeof(header), file_size); return nullptr; } auto data = std::make_unique (data_size); ssize_t nread = do_read (index_fd, data.get (), data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read {} bytes from index file. {}", data_size, strerror (errno)); + log_error (LOG_ASSEMBLY, "typemap: failed to read %zu bytes from index file. %s", data_size, strerror (errno)); return nullptr; } @@ -1140,7 +1140,7 @@ EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_ std::unique_ptr EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '{}/{}'", optional_string (dir_path), optional_string (index_path)); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap index file '%s/%s'", optional_string (dir_path), optional_string (index_path)); TypeMapIndexHeader header; size_t file_size; @@ -1169,7 +1169,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * if (nread != static_cast(header.assembly_name_length)) { log_error ( LOG_ASSEMBLY, - "typemap: failed to read map assembly name from '{}/{}': {}", + "typemap: failed to read map assembly name from '%s/%s': %s", optional_string (dir_path), optional_string (file_path), strerror (errno) @@ -1182,7 +1182,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * log_debug ( LOG_ASSEMBLY, - "typemap: '{}/{}':: entry count == {}; Java name field width == {}; Managed name width == {}; assembly name length == {}; assembly name == {}", + "typemap: '%s/%s':: entry count == %u; Java name field width == %u; Managed name width == %u; assembly name length == %u; assembly name == %s", optional_string (dir_path), optional_string (file_path), header.entry_count, @@ -1203,7 +1203,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * module.data = new uint8_t [data_size]; nread = do_read (file_fd, module.data, data_size); if (nread != static_cast(data_size)) { - log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '{}/{}': {}", optional_string (dir_path), optional_string (file_path), strerror (errno)); + log_error (LOG_ASSEMBLY, "typemap: failed to read map data from '%s/%s': %s", optional_string (dir_path), optional_string (file_path), strerror (errno)); return false; } @@ -1247,7 +1247,7 @@ EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char * bool EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMap &module) { - log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '{}/{}'", optional_string (dir_path), optional_string (file_path)); + log_debug (LOG_ASSEMBLY, "typemap: loading TypeMap file '%s/%s'", optional_string (dir_path), optional_string (file_path)); bool ret = true; BinaryTypeMapHeader header; @@ -1286,7 +1286,7 @@ EmbeddedAssemblies::register_from_apk (const char *apk_file, monodroid_should_re gather_bundled_assemblies_from_apk (apk_file, should_register); - log_info (LOG_ASSEMBLY, "Package '{}' contains {} assemblies", optional_string (apk_file), number_of_found_assemblies - prev); + log_info (LOG_ASSEMBLY, "Package '%s' contains %zu assemblies", optional_string (apk_file), number_of_found_assemblies - prev); return number_of_found_assemblies; } @@ -1390,10 +1390,10 @@ EmbeddedAssemblies::maybe_register_blob_from_filesystem ( [[gnu::always_inline]] size_t EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look_for_mangled_names, monodroid_should_register should_register) noexcept { - log_debug (LOG_ASSEMBLY, "Looking for assemblies in '{}'", optional_string (lib_dir_path)); + log_debug (LOG_ASSEMBLY, "Looking for assemblies in '%s'", optional_string (lib_dir_path)); DIR *lib_dir = opendir (lib_dir_path); // TODO: put it in a scope guard at some point if (lib_dir == nullptr) { - log_warn (LOG_ASSEMBLY, "Unable to open app library directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to open app library directory '%s': %s", optional_string (lib_dir_path), std::strerror (errno)); return 0; } @@ -1402,14 +1402,14 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look int dir_fd = dirfd (lib_dir); if (dir_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to obtain file descriptor for directory '%s': %s", optional_string (lib_dir_path), std::strerror (errno)); closedir (lib_dir); return 0; } state.file_fd = dup (dir_fd); if (state.file_fd < 0) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor {} for directory '{}': {}", dir_fd, optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Unable to duplicate file descriptor %d for directory '%s': %s", dir_fd, optional_string (lib_dir_path), std::strerror (errno)); closedir (lib_dir); return 0; } @@ -1426,7 +1426,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look dirent *cur = readdir (lib_dir); if (cur == nullptr) { if (errno != 0) { - log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '{}': {}", optional_string (lib_dir_path), std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Failed to open a directory entry from '%s': %s", optional_string (lib_dir_path), std::strerror (errno)); continue; // keep going, no harm } break; // No more entries, we're done @@ -1446,7 +1446,7 @@ EmbeddedAssemblies::register_from_filesystem (const char *lib_dir_path,bool look // ...and we can handle the runtime config entry if (!runtime_config_blob_found && std::strncmp (cur->d_name, SharedConstants::RUNTIME_CONFIG_BLOB_NAME.data (), SharedConstants::RUNTIME_CONFIG_BLOB_NAME.size ()) == 0) { - log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '{}'", optional_string (cur->d_name)); + log_debug (LOG_ASSEMBLY, "Mapping runtime config blob from '%s'", optional_string (cur->d_name)); auto file_size = Util::get_file_size_at (state.file_fd, cur->d_name); if (!file_size) { continue; @@ -1493,6 +1493,6 @@ EmbeddedAssemblies::register_from_filesystem (monodroid_should_register should_r ); #endif - log_debug (LOG_ASSEMBLY, "Found {} assemblies on the filesystem", assembly_count); + log_debug (LOG_ASSEMBLY, "Found %zu assemblies on the filesystem", assembly_count); return assembly_count; } diff --git a/src/native/mono/monodroid/embedded-assemblies.hh b/src/native/mono/monodroid/embedded-assemblies.hh index 5c48f92b400..7bfb28a5d67 100644 --- a/src/native/mono/monodroid/embedded-assemblies.hh +++ b/src/native/mono/monodroid/embedded-assemblies.hh @@ -304,7 +304,7 @@ namespace xamarin::android::internal { elf_header->e_ident[EI_MAG1] != ELFMAG1 || elf_header->e_ident[EI_MAG2] != ELFMAG2 || elf_header->e_ident[EI_MAG3] != ELFMAG3) { - log_debug (LOG_ASSEMBLY, "Not an ELF image: {}", optional_string (file_name)); + log_debug (LOG_ASSEMBLY, "Not an ELF image: %s", optional_string (file_name)); // Not an ELF image, just return what we mmapped before return { map_info.area, map_info.size }; } @@ -323,7 +323,7 @@ namespace xamarin::android::internal { static void store_mapped_runtime_config_data (md_mmap_info const& map_info, const char *file_name) noexcept { auto [payload_start, payload_size] = get_wrapper_dso_payload_pointer_and_size (map_info, file_name); - log_debug (LOG_ASSEMBLY, "Runtime config: payload pointer {:p} ; size {}", payload_start, payload_size); + log_debug (LOG_ASSEMBLY, "Runtime config: payload pointer %p ; size %zu", payload_start, payload_size); runtime_config_data = payload_start; runtime_config_data_size = payload_size; runtime_config_blob_found = true; @@ -430,7 +430,7 @@ namespace xamarin::android::internal { } } } - log_debug (LOG_ASSEMBLY, "Unmangled name to '{}'", optional_string (name.get ())); + log_debug (LOG_ASSEMBLY, "Unmangled name to '%s'", optional_string (name.get ())); }; private: diff --git a/src/native/mono/monodroid/mono-image-loader.hh b/src/native/mono/monodroid/mono-image-loader.hh index ac33fe53588..e997d1196dc 100644 --- a/src/native/mono/monodroid/mono-image-loader.hh +++ b/src/native/mono/monodroid/mono-image-loader.hh @@ -110,7 +110,7 @@ namespace xamarin::android::internal { force_inline static MonoImage* stash_and_return (MonoImage *image, MonoImageOpenStatus status, [[maybe_unused]] hash_t hash) noexcept { if (image == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, "Failed to open assembly image. {}", optional_string (mono_image_strerror (status))); + log_warn (LOG_ASSEMBLY, "Failed to open assembly image. %s", optional_string (mono_image_strerror (status))); return nullptr; } diff --git a/src/native/mono/monodroid/monodroid-glue-internal.hh b/src/native/mono/monodroid/monodroid-glue-internal.hh index e1d1f446d07..8272a3c73ab 100644 --- a/src/native/mono/monodroid/monodroid-glue-internal.hh +++ b/src/native/mono/monodroid/monodroid-glue-internal.hh @@ -127,7 +127,7 @@ namespace xamarin::android::internal void *symptr = MonodroidDl::monodroid_dlsym (handle, name, &err, nullptr); if (symptr == nullptr) { - log_warn (LOG_DEFAULT, "Failed to load symbol '{}' library with handle {}. {}", name, handle, err == nullptr ? "Unknown error"sv : err); + log_warn (LOG_DEFAULT, "Failed to load symbol '%s' library with handle %p. %s", optional_string (name), handle, err == nullptr ? "Unknown error" : err); fnptr = nullptr; return; } diff --git a/src/native/mono/monodroid/monodroid-glue.cc b/src/native/mono/monodroid/monodroid-glue.cc index 99c81025e37..f49551b84c0 100644 --- a/src/native/mono/monodroid/monodroid-glue.cc +++ b/src/native/mono/monodroid/monodroid-glue.cc @@ -186,12 +186,12 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] fullpath.append (SharedConstants::DLL_EXTENSION); } - log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: {}", optional_string (fullpath.get ())); + log_debug (LOG_ASSEMBLY, "open_from_update_dir: trying to open assembly: %s", optional_string (fullpath.get ())); if (Util::file_exists (fullpath.get ())) { MonoImageOpenStatus status{}; result = mono_assembly_open_full (fullpath.get (), &status, 0); if (result == nullptr || status != MonoImageOpenStatus::MONO_IMAGE_OK) { - log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '{}'. {}", optional_string (fullpath.get ()), mono_image_strerror (status)); + log_warn (LOG_ASSEMBLY, "Failed to load managed assembly '%s'. %s", optional_string (fullpath.get ()), mono_image_strerror (status)); } } else { log_warn (LOG_ASSEMBLY, "open_from_update_dir: assembly file DOES NOT EXIST"sv); @@ -203,7 +203,7 @@ MonodroidRuntime::open_from_update_dir (MonoAssemblyName *aname, [[maybe_unused] } if (result != nullptr && Util::should_log (LOG_ASSEMBLY)) { - log_info_nocheck_fmt (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: {:p}", reinterpret_cast(result)); + log_info_nocheck_fmt (LOG_ASSEMBLY, "open_from_update_dir: loaded assembly: %p", reinterpret_cast(result)); } return result; } @@ -390,7 +390,7 @@ MonodroidRuntime::parse_gdb_options () noexcept time_t secs = time (nullptr); if (v + 10 < secs) { - log_warn (LOG_DEFAULT, "Found stale {} property with value '{}', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ()); + log_warn (LOG_DEFAULT, "Found stale %s property with value '%s', not waiting.", SharedConstants::DEBUG_MONO_GDB_PROPERTY.data (), val.get ()); do_wait = false; } } @@ -461,13 +461,13 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid SDB port value {}", sdb_port); + log_error (LOG_DEFAULT, "Invalid SDB port value %u", sdb_port); ret = false; continue; } if (out_port > std::numeric_limits::max ()) { - log_error (LOG_DEFAULT, "Invalid output port value {}", out_port); + log_error (LOG_DEFAULT, "Invalid output port value %u", out_port); ret = false; continue; } @@ -492,7 +492,7 @@ MonodroidRuntime::parse_runtime_args (dynamic_local_string arg (token); - log_error (LOG_DEFAULT, "Unknown runtime argument: '{}'", optional_string (arg.get ())); + log_error (LOG_DEFAULT, "Unknown runtime argument: '%s'", optional_string (arg.get ())); ret = false; } } @@ -521,9 +521,9 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse cur_time = time (nullptr); if (!parse_runtime_args (runtime_args, &options)) { - log_error (LOG_DEFAULT, "Failed to parse runtime args: '{}'", optional_string (runtime_args.get ())); + log_error (LOG_DEFAULT, "Failed to parse runtime args: '%s'", optional_string (runtime_args.get ())); } else if (options.debug && cur_time > options.timeout_time) { - log_warn (LOG_DEBUGGER, "Not starting the debugger as the timeout value has been reached; current-time: {}; timeout: {}", cur_time, options.timeout_time); + log_warn (LOG_DEBUGGER, "Not starting the debugger as the timeout value has been reached; current-time: %lld; timeout: %lld", static_cast(cur_time), static_cast(options.timeout_time)); } else if (options.debug && cur_time <= options.timeout_time) { EmbeddedAssemblies::set_register_debug_symbols (true); @@ -548,7 +548,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse // this text is used in unit tests to check the debugger started // do not change it without updating the test. - log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: {}", optional_string (debug_arg)); + log_warn (LOG_DEBUGGER, "Trying to initialize the debugger with options: %s", optional_string (debug_arg)); if (options.out_port > 0) { int sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -581,7 +581,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (options.server) { int accepted = monodroid_debug_accept (sock, addr); - log_warn (LOG_DEBUGGER, "Accepted stdout connection: {}", accepted); + log_warn (LOG_DEBUGGER, "Accepted stdout connection: %d", accepted); if (accepted < 0) { Helpers::abort_application ( LOG_DEBUGGER, @@ -673,7 +673,7 @@ MonodroidRuntime::mono_runtime_init ([[maybe_unused]] JNIEnv *env, [[maybe_unuse if (AndroidSystem::monodroid_get_system_property (SharedConstants::DEBUG_MONO_RUNTIME_ARGS_PROPERTY, prop_val) > 0) { char **ptr; - log_warn (LOG_DEBUGGER, "passing '{}' as extra arguments to the runtime.", optional_string (prop_val.get ())); + log_warn (LOG_DEBUGGER, "passing '%s' as extra arguments to the runtime.", optional_string (prop_val.get ())); char **args = Util::monodroid_strsplit (prop_val.get (), " ", 0); int argc = 0; @@ -746,7 +746,7 @@ MonodroidRuntime::create_domain (JNIEnv *env, jstring_array_wrapper &runtimeApks if (user_assemblies_count == 0 && AndroidSystem::count_override_assemblies () == 0) { #if defined (DEBUG) log_fatal (LOG_DEFAULT, - "No assemblies found in '{}' or '{}'. Assuming this is part of Fast Deployment. Exiting...", + "No assemblies found in '%s' or '%s'. Assuming this is part of Fast Deployment. Exiting...", optional_string (AndroidSystem::override_dirs [0]), (AndroidSystem::override_dirs.size () > 1 && AndroidSystem::override_dirs [1] != nullptr) ? optional_string (AndroidSystem::override_dirs [1]) : "" ); @@ -840,7 +840,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec // GC threshold is 90% of the max GREF count init.grefGcThreshold = static_cast(AndroidSystem::get_gref_gc_threshold ()); - log_info (LOG_GC, "GREF GC Threshold: {}", init.grefGcThreshold); + log_info (LOG_GC, "GREF GC Threshold: %d", init.grefGcThreshold); init.grefClass = RuntimeUtil::get_class_from_runtime_field (env, runtimeClass, "java_lang_Class", true); Class_getName = env->GetMethodID (init.grefClass, "getName", "()Ljava/lang/String;"); @@ -913,7 +913,7 @@ MonodroidRuntime::init_android_runtime (JNIEnv *env, jclass runtimeClass, jobjec auto initialize = reinterpret_cast (mono_method_get_unmanaged_callers_only_ftnptr (method, &error)); if (initialize == nullptr) { - log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: {}", optional_string (mono_error_get_message (&error))); + log_fatal (LOG_DEFAULT, "Failed to get pointer to Initialize. Mono error: %s", optional_string (mono_error_get_message (&error))); } abort_unless ( @@ -969,7 +969,7 @@ MonodroidRuntime::set_environment_variable_for_directory (const char *name, jstr if (createDirectory) { int rv = Util::create_directory (value.get_cstr (), mode); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, "Failed to create directory for environment variable {}. {}", optional_string (name), strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory for environment variable %s. %s", optional_string (name), strerror (errno)); } setenv (name, value.get_cstr (), 1); } @@ -979,10 +979,10 @@ MonodroidRuntime::create_xdg_directory (jstring_wrapper& home, size_t home_len, { static_local_string dir (home_len + relative_path.length ()); Util::path_combine (dir, home.get_cstr (), home_len, relative_path.data (), relative_path.length ()); - log_debug (LOG_DEFAULT, "Creating XDG directory: {}", optional_string (dir.get ())); + log_debug (LOG_DEFAULT, "Creating XDG directory: %s", optional_string (dir.get ())); int rv = Util::create_directory (dir.get (), DEFAULT_DIRECTORY_MODE); if (rv < 0 && errno != EEXIST) - log_warn (LOG_DEFAULT, "Failed to create XDG directory {}. {}", optional_string (dir.get ()), strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create XDG directory %s. %s", optional_string (dir.get ()), strerror (errno)); if (!environment_variable_name.empty ()) { setenv (environment_variable_name.data (), dir.get (), 1); } @@ -1011,7 +1011,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept return; auto log_envvar = [](const char *name, const char *v) { - log_debug (LOG_DEFAULT, "Env variable '{}' set to '{}'.", optional_string (name), optional_string (v)); + log_debug (LOG_DEFAULT, "Env variable '%s' set to '%s'.", optional_string (name), optional_string (v)); }; string_segment arg_token; @@ -1031,7 +1031,7 @@ MonodroidRuntime::set_debug_env_vars (void) noexcept log_envvar (arg.get (), one.data ()); } else if (index == 0) { // ’=value’ - log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '{}'", optional_string (arg.get ())); + log_warn (LOG_DEFAULT, "Attempt to set environment variable without specifying name: '%s'", optional_string (arg.get ())); } else { // ’name=value’ arg[index] = '\0'; @@ -1111,10 +1111,10 @@ MonodroidRuntime::set_profile_options () noexcept .append (output_path.get (), output_path.length ()); } if (Util::create_directory (AndroidSystem::override_dirs[0], 0) < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", optional_string (AndroidSystem::override_dirs[0]), std::strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory '%s'. %s", optional_string (AndroidSystem::override_dirs[0]), std::strerror (errno)); } - log_warn (LOG_DEFAULT, "Initializing profiler with options: {}", optional_string (value.get ())); + log_warn (LOG_DEFAULT, "Initializing profiler with options: %s", optional_string (value.get ())); debug.monodroid_profiler_load (AndroidSystem::get_runtime_libdir (), value.get (), output_path.get ()); } @@ -1226,7 +1226,7 @@ MonodroidRuntime::preload_jni_libraries () noexcept return; } - log_debug (LOG_ASSEMBLY, "DSO jni preloads index stride == {}", dso_jni_preloads_idx_stride); + log_debug (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 ( @@ -1245,11 +1245,11 @@ MonodroidRuntime::preload_jni_libraries () noexcept log_debug ( LOG_ASSEMBLY, - "Preloading JNI shared library: {} (entry's index: {}; real name hash: {:x}; name hash: {:x})", + "Preloading JNI shared library: %s (entry's index: %zu; real name hash: %zx; name hash: %zx)", optional_string (entry.name), entry_index, - entry.real_name_hash, - entry.hash + static_cast(entry.real_name_hash), + static_cast(entry.hash) ); char *err = nullptr; @@ -1262,7 +1262,7 @@ MonodroidRuntime::preload_jni_libraries () noexcept log_debug ( 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 ); @@ -1493,7 +1493,7 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; AndroidSystem::set_runtime_libdir (strdup (jstr.get_cstr ())); - log_debug (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); + log_debug (LOG_DEFAULT, "Using runtime path: %s", optional_string (AndroidSystem::get_runtime_libdir ())); } @@ -1552,13 +1552,13 @@ MonodroidRuntime::Java_mono_android_Runtime_initInternal (JNIEnv *env, jclass kl if (Util::should_log (LOG_DEFAULT)) [[unlikely]] { log_info_nocheck_fmt ( LOG_DEFAULT, - ".NET for Android version: {} ({}; {}); built on {}; NDK version: {}; API level: {}; MonoVM version: {}", - BuildInfo::xa_version.data (), - BuildInfo::architecture.data (), - BuildInfo::kind.data (), - BuildInfo::date.data (), - BuildInfo::ndk_version.data (), - BuildInfo::ndk_api_level.data (), + ".NET for Android version: %.*s (%.*s; %.*s); built on %.*s; NDK version: %.*s; API level: %.*s; MonoVM version: %s", + static_cast(BuildInfo::xa_version.length ()), BuildInfo::xa_version.data (), + static_cast(BuildInfo::architecture.length ()), BuildInfo::architecture.data (), + static_cast(BuildInfo::kind.length ()), BuildInfo::kind.data (), + static_cast(BuildInfo::date.length ()), BuildInfo::date.data (), + static_cast(BuildInfo::ndk_version.length ()), BuildInfo::ndk_version.data (), + static_cast(BuildInfo::ndk_api_level.length ()), BuildInfo::ndk_api_level.data (), mono_get_runtime_build_info () ); } @@ -1679,7 +1679,7 @@ MonodroidRuntime::get_java_class_name_for_TypeManager (jclass klass) noexcept JNIEnv *env = osBridge.ensure_jnienv (); jstring name = reinterpret_cast (env->CallObjectMethod (klass, Class_getName)); if (name == nullptr) { - log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at {:p}", reinterpret_cast(klass)); + log_error (LOG_DEFAULT, "Failed to obtain Java class name for object at %p", reinterpret_cast(klass)); return nullptr; } diff --git a/src/native/mono/monodroid/monodroid-tracing.cc b/src/native/mono/monodroid/monodroid-tracing.cc index adb9f0db1d6..a83288f7450 100644 --- a/src/native/mono/monodroid/monodroid-tracing.cc +++ b/src/native/mono/monodroid/monodroid-tracing.cc @@ -27,7 +27,7 @@ MonodroidRuntime::log_traces (JNIEnv *env, TraceKind kind, const char *first_lin char *err = nullptr; void *handle = MonodroidDl::monodroid_dlopen (SharedConstants::xamarin_native_tracing_name.data (), MONO_DL_EAGER, &err, nullptr); if (handle == nullptr) { - log_warn (LOG_DEFAULT, "Failed to load native tracing library '{}'. {}", SharedConstants::xamarin_native_tracing_name, err == nullptr ? "Unknown error"sv : err); + log_warn (LOG_DEFAULT, "Failed to load native tracing library '%.*s'. %s", static_cast(SharedConstants::xamarin_native_tracing_name.length ()), SharedConstants::xamarin_native_tracing_name.data (), err == nullptr ? "Unknown error" : err); } else { load_symbol (handle, "xa_get_native_backtrace", _xa_get_native_backtrace); load_symbol (handle, "xa_get_managed_backtrace", _xa_get_managed_backtrace); diff --git a/src/native/mono/monodroid/osbridge.cc b/src/native/mono/monodroid/osbridge.cc index d0ea6af8547..f62e13d2fd8 100644 --- a/src/native/mono/monodroid/osbridge.cc +++ b/src/native/mono/monodroid/osbridge.cc @@ -213,7 +213,7 @@ OSBridge::_write_stack_trace (FILE *to, char *from, LogCategories category) *end = '\0'; if ((category == LOG_GREF && gref_to_logcat) || (category == LOG_LREF && lref_to_logcat)) { - log_debug (category, "{}", optional_string (m)); + log_debug (category, "%s", optional_string (m)); } if (to != nullptr) { fprintf (to, "%s\n", optional_string (m)); @@ -227,7 +227,7 @@ void OSBridge::_monodroid_gref_log (const char *message) { if (gref_to_logcat) { - log_debug (LOG_GREF, "{}", optional_string (message)); + log_debug (LOG_GREF, "%s", optional_string (message)); } if (!gref_log) return; @@ -243,7 +243,7 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH return c; log_info (LOG_GREF, - "+g+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + "+g+ grefc %d gwrefc %d obj-handle %p/%c -> new-handle %p/%c from thread '%s'(%d)", c, gc_weak_gref_count, reinterpret_cast(curHandle), @@ -257,7 +257,7 @@ OSBridge::_monodroid_gref_log_new (jobject curHandle, char curType, jobject newH if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, "%s", optional_string (from)); } } if (!gref_log) @@ -288,7 +288,7 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "-g- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + "-g- grefc %d gwrefc %d handle %p/%c from thread '%s'(%d)", c, gc_weak_gref_count, reinterpret_cast(handle), @@ -300,7 +300,7 @@ OSBridge::_monodroid_gref_log_delete (jobject handle, char type, const char *thr if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, "%s", optional_string (from)); } } if (!gref_log) @@ -327,7 +327,7 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "+w+ grefc {} gwrefc {} obj-handle {:p}/{} -> new-handle {:p}/{} from thread '{}'({})", + "+w+ grefc %d gwrefc %d obj-handle %p/%c -> new-handle %p/%c from thread '%s'(%d)", gc_gref_count, c, reinterpret_cast(curHandle), @@ -341,7 +341,7 @@ OSBridge::_monodroid_weak_gref_new (jobject curHandle, char curType, jobject new if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, "%s", optional_string (from)); } } if (!gref_log) @@ -370,7 +370,7 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th if ((log_categories & LOG_GREF) == 0) return; log_info (LOG_GREF, - "-w- grefc {} gwrefc {} handle {:p}/{} from thread '{}'({})", + "-w- grefc %d gwrefc %d handle %p/%c from thread '%s'(%d)", gc_gref_count, c, reinterpret_cast(handle), @@ -382,7 +382,7 @@ OSBridge::_monodroid_weak_gref_delete (jobject handle, char type, const char *th if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, "%s", optional_string (from)); } } if (!gref_log) @@ -408,7 +408,7 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - "+l+ lrefc {} handle {:p}/{} from thread '{}'({})", + "+l+ lrefc %d handle %p/%c from thread '%s'(%d)", lrefc, reinterpret_cast(handle), type, @@ -419,7 +419,7 @@ OSBridge::_monodroid_lref_log_new (int lrefc, jobject handle, char type, const c if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, "%s", optional_string (from)); } } if (!lref_log) @@ -444,7 +444,7 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons if ((log_categories & LOG_LREF) == 0) return; log_info (LOG_LREF, - "-l- lrefc {} handle {:p}/{} from thread '{}'({})", + "-l- lrefc %d handle %p/%c from thread '%s'(%d)", lrefc, reinterpret_cast(handle), type, @@ -455,7 +455,7 @@ OSBridge::_monodroid_lref_log_delete (int lrefc, jobject handle, char type, cons if (from_writable) { _write_stack_trace (nullptr, const_cast(from), LOG_GREF); } else { - log_info (LOG_GREF, "{}", optional_string (from)); + log_info (LOG_GREF, "%s", optional_string (from)); } } if (!lref_log) @@ -584,7 +584,7 @@ OSBridge::gc_bridge_class_kind (MonoClass *klass) i = get_gc_bridge_index (klass); if (i == static_cast (-NUM_GC_BRIDGE_TYPES)) { log_info (LOG_GC, - "asked if a class {}.{} is a bridge before we inited java.lang.Object", + "asked if a class %s.%s is a bridge before we inited java.lang.Object", optional_string (mono_class_get_namespace (klass)), optional_string (mono_class_get_name (klass)) ); @@ -620,7 +620,7 @@ OSBridge::gc_is_bridge_object (MonoObject *object) #if DEBUG MonoClass *mclass = mono_object_get_class (object); log_info (LOG_GC, - "object of class {}.{} with null handle", + "object of class %s.%s with null handle", optional_string (mono_class_get_namespace (mclass)), optional_string (mono_class_get_name (mclass)) ); @@ -718,9 +718,9 @@ OSBridge::add_reference (JNIEnv *env, OSBridge::AddReferenceTarget target, OSBri *reffed_description = describe_target (reffed_target); if (success) - log_warn (LOG_GC, "Added reference for {} to {}", optional_string (description), optional_string (reffed_description)); + log_warn (LOG_GC, "Added reference for %s to %s", optional_string (description), optional_string (reffed_description)); else - log_error (LOG_GC, "Missing monodroidAddReference method for {}", optional_string (description)); + log_error (LOG_GC, "Missing monodroidAddReference method for %s", optional_string (description)); free (description); free (reffed_description); @@ -957,7 +957,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri if (Logger::gc_spew_enabled ()) { klass = mono_object_get_class (obj); log_error (LOG_GC, - "Missing monodroidClearReferences method for object of class {}.{}", + "Missing monodroidClearReferences method for object of class %s.%s", optional_string (mono_class_get_namespace (klass)), optional_string (mono_class_get_name (klass)) ); @@ -974,7 +974,7 @@ OSBridge::gc_cleanup_after_java_collection (JNIEnv *env, int num_sccs, MonoGCBri } } #if DEBUG - log_info (LOG_GC, "GC cleanup summary: {} objects tested - resurrecting {}.", total, alive); + log_info (LOG_GC, "GC cleanup summary: %d objects tested - resurrecting %d.", total, alive); #endif } @@ -1004,10 +1004,10 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre if (Logger::gc_spew_enabled ()) { int i, j; - log_info (LOG_GC, "cross references callback invoked with {} sccs and {} xrefs.", num_sccs, num_xrefs); + log_info (LOG_GC, "cross references callback invoked with %d sccs and %d xrefs.", num_sccs, num_xrefs); for (i = 0; i < num_sccs; ++i) { - log_info (LOG_GC, "group {} with {} objects", i, sccs [i]->num_objs); + log_info (LOG_GC, "group %d with %d objects", i, sccs [i]->num_objs); for (j = 0; j < sccs [i]->num_objs; ++j) { MonoObject *obj = sccs [i]->objs [j]; @@ -1022,7 +1022,7 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre } MonoClass *klass = mono_object_get_class (obj); log_info (LOG_GC, - "\tobj {:p} [{}::{}] handle {:p} key_handle {:p}", + "\tobj %p [%s::%s] handle %p key_handle %p", reinterpret_cast(obj), optional_string (mono_class_get_namespace (klass)), optional_string (mono_class_get_name (klass)), @@ -1034,7 +1034,7 @@ OSBridge::gc_cross_references (int num_sccs, MonoGCBridgeSCC **sccs, int num_xre if (Util::should_log (LOG_GC)) { for (i = 0; i < num_xrefs; ++i) - log_info_nocheck_fmt (LOG_GC, "xref [{}] {} -> {}", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); + log_info_nocheck_fmt (LOG_GC, "xref [%d] %d -> %d", i, xrefs [i].src_scc_index, xrefs [i].dst_scc_index); } } diff --git a/src/native/mono/monodroid/xamarin-android-app-context.cc b/src/native/mono/monodroid/xamarin-android-app-context.cc index 33e3a023f37..fb7ce2b260b 100644 --- a/src/native/mono/monodroid/xamarin-android-app-context.cc +++ b/src/native/mono/monodroid/xamarin-android-app-context.cc @@ -15,7 +15,7 @@ MonodroidRuntime::get_method_name (uint32_t mono_image_index, uint32_t method_to { uint64_t id = (static_cast(mono_image_index) << 32) | method_token; - log_debug (LOG_ASSEMBLY, "MM: looking for name of method with id {:x}, in mono image at index {}", id, mono_image_index); + log_debug (LOG_ASSEMBLY, "MM: looking for name of method with id %llx, in mono image at index %u", static_cast(id), mono_image_index); size_t i = 0uz; while (mm_method_names[i].id != 0) { if (mm_method_names[i].id == id) { @@ -43,7 +43,7 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas { log_debug ( LOG_ASSEMBLY, - "MM: Trying to look up pointer to method '{}' (token {:x}) in class '{}' (index {})", + "MM: Trying to look up pointer to method '%s' (token %x) in class '%s' (index %u)", optional_string (get_method_name (mono_image_index, method_token)), method_token, optional_string (get_class_name (class_index)), class_index ); @@ -80,7 +80,7 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_debug ( LOG_ASSEMBLY, - "Loaded pointer to method {} ({:p}) (mono_image_index == {}; class_index == {}; method_token == {:x})", + "Loaded pointer to method %s (%p) (mono_image_index == %u; class_index == %u; method_token == %x)", optional_string (mono_method_full_name (method, true)), ret, mono_image_index, @@ -92,14 +92,14 @@ MonodroidRuntime::get_function_pointer (uint32_t mono_image_index, uint32_t clas log_fatal ( LOG_DEFAULT, - "Failed to obtain function pointer to method '{}' in class '{}'", + "Failed to obtain function pointer to method '%s' in class '%s'", optional_string (get_method_name (mono_image_index, method_token)), optional_string (get_class_name (class_index)) ); log_fatal ( LOG_DEFAULT, - "Looked for image index {}, class index {}, method token {:x}", + "Looked for image index %u, class index %u, method token %x", mono_image_index, class_index, method_token diff --git a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh index 393101d6017..918c4804c7b 100644 --- a/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh +++ b/src/native/mono/pinvoke-override/pinvoke-override-api-impl.hh @@ -23,21 +23,21 @@ namespace xamarin::android { constexpr bool PREFER_AOT_CACHE = false; lib_handle = internal::MonodroidDl::monodroid_dlopen (library_name, MONO_DL_LOCAL, nullptr, PREFER_AOT_CACHE); if (lib_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Shared library '{}' not loaded, p/invoke '{}' may fail", optional_string (library_name), optional_string (symbol_name)); + log_warn (LOG_ASSEMBLY, "Shared library '%s' not loaded, p/invoke '%s' may fail", optional_string (library_name), optional_string (symbol_name)); return nullptr; } if (dso_handle != nullptr) { void *expected_null = nullptr; if (!__atomic_compare_exchange (dso_handle, &expected_null, &lib_handle, false /* weak */, __ATOMIC_ACQUIRE /* success_memorder */, __ATOMIC_RELAXED /* xxxfailure_memorder */)) { - log_debug (LOG_ASSEMBLY, "Library '{}' handle already cached by another thread", optional_string (library_name)); + log_debug (LOG_ASSEMBLY, "Library '%s' handle already cached by another thread", optional_string (library_name)); } } } void *entry_handle = internal::MonodroidDl::monodroid_dlsym (lib_handle, symbol_name, nullptr, nullptr); if (entry_handle == nullptr) { - log_warn (LOG_ASSEMBLY, "Symbol '{}' not found in shared library '{}', p/invoke may fail", optional_string (symbol_name), optional_string (library_name)); + log_warn (LOG_ASSEMBLY, "Symbol '%s' not found in shared library '%s', p/invoke may fail", optional_string (symbol_name), optional_string (library_name)); return nullptr; } @@ -60,7 +60,7 @@ namespace xamarin::android { return nullptr; } - log_debug (LOG_ASSEMBLY, "Caching p/invoke entry {} @ {}", library_name, entrypoint_name); + log_debug (LOG_ASSEMBLY, "Caching p/invoke entry %s @ %s", library_name.c_str (), entrypoint_name.c_str ()); (*api_map)[entrypoint_name] = entry_handle; return entry_handle; } @@ -81,7 +81,7 @@ namespace xamarin::android { ); if (already_loaded) { - log_debug (LOG_ASSEMBLY, "Entry '{}' from library '{}' already loaded by another thread", entrypoint_name, library_name); + log_debug (LOG_ASSEMBLY, "Entry '%s' from library '%s' already loaded by another thread", entrypoint_name, library_name); } } @@ -147,7 +147,7 @@ namespace xamarin::android { handle = fetch_or_create_pinvoke_map_entry (lib_name, entry_name, entrypoint_name_hash, lib_map, /* need_lock */ false); } else { if (iter->second == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '{}'", optional_string (library_name)); + log_warn (LOG_ASSEMBLY, "Internal error: null entry in p/invoke map for key '%s'", optional_string (library_name)); return nullptr; // fall back to `monodroid_dlopen` } diff --git a/src/native/mono/pinvoke-override/precompiled.cc b/src/native/mono/pinvoke-override/precompiled.cc index 29ac736e433..a82cdb79669 100644 --- a/src/native/mono/pinvoke-override/precompiled.cc +++ b/src/native/mono/pinvoke-override/precompiled.cc @@ -22,12 +22,12 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha PinvokeEntry *entry = find_pinvoke_address (entrypoint_hash, internal_pinvokes.data (), internal_pinvokes_count); if (entry == nullptr) [[unlikely]] { - log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '{} @ {}' (hash: {:x}) not found in compile-time map.", - optional_string (library_name), optional_string (entrypoint_name), entrypoint_hash); + log_fatal (LOG_ASSEMBLY, "Internal p/invoke symbol '%s @ %s' (hash: %zx) not found in compile-time map.", + optional_string (library_name), optional_string (entrypoint_name), static_cast(entrypoint_hash)); log_fatal (LOG_ASSEMBLY, "compile-time map contents:"sv); for (size_t i = 0uz; i < internal_pinvokes_count; i++) { PinvokeEntry const& e = internal_pinvokes[i]; - log_fatal (LOG_ASSEMBLY, "\t'{}'={:p} (hash: {:x})", optional_string (e.name), e.func, e.hash); + log_fatal (LOG_ASSEMBLY, "\t'%s'=%p (hash: %zx)", optional_string (e.name), reinterpret_cast(e.func), static_cast(e.hash)); } Helpers::abort_application ( LOG_ASSEMBLY, @@ -68,7 +68,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha load_library_entry (library_name, entrypoint_name, *entry, dotnet_dso_handle); if (entry->func == nullptr) { - log_fatal (LOG_ASSEMBLY, "Failed to load symbol '{}' from shared library '{}'", + log_fatal (LOG_ASSEMBLY, "Failed to load symbol '%s' from shared library '%s'", optional_string (entrypoint_name), optional_string (library_name)); return nullptr; // let Mono deal with the fallout } @@ -77,7 +77,7 @@ PinvokeOverride::monodroid_pinvoke_override (const char *library_name, const cha } // It's possible we don't have an entry for some `dotnet` p/invoke, fall back to the slow path below - log_debug (LOG_ASSEMBLY, "Symbol '{}' in library '{}' not found in the generated tables, falling back to slow path", + log_debug (LOG_ASSEMBLY, "Symbol '%s' in library '%s' not found in the generated tables, falling back to slow path", optional_string (entrypoint_name), optional_string (library_name)); } diff --git a/src/native/mono/runtime-base/android-system.cc b/src/native/mono/runtime-base/android-system.cc index 94a5d39a63d..24c88b2c238 100644 --- a/src/native/mono/runtime-base/android-system.cc +++ b/src/native/mono/runtime-base/android-system.cc @@ -66,7 +66,7 @@ AndroidSystem::lookup_system_property (const char *name, size_t &value_len) noex return nullptr; if (application_config.system_property_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.system_property_count); + log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries (%u)", application_config.system_property_count); return nullptr; } @@ -139,7 +139,7 @@ AndroidSystem::_monodroid__system_property_get (const char *name, char *sp_value char *buf = nullptr; if (sp_value_len < PROPERTY_VALUE_BUFFER_LEN) { size_t alloc_size = Helpers::add_with_overflow_check (PROPERTY_VALUE_BUFFER_LEN, 1uz); - log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only {} bytes", sp_value_len); + log_warn (LOG_DEFAULT, "Buffer to store system property may be too small, will copy only %zu bytes", sp_value_len); buf = new char [alloc_size]; } @@ -251,12 +251,12 @@ AndroidSystem::monodroid_get_system_property_from_overrides ([[maybe_unused]] co } std::unique_ptr override_file {Util::path_combine (od, name)}; - log_info (LOG_DEFAULT, "Trying to get property from {}", override_file.get ()); + log_info (LOG_DEFAULT, "Trying to get property from %s", override_file.get ()); size_t result = _monodroid_get_system_property_from_file (override_file.get (), value); if (result == 0 || value == nullptr || (*value) == nullptr || **value == '\0') { continue; } - log_info (LOG_DEFAULT, "Property '{}' from {} has value '{}'.", name, od, *value); + log_info (LOG_DEFAULT, "Property '%s' from %s has value '%s'.", name, od, *value); return result; } #endif // def DEBUG @@ -282,7 +282,7 @@ AndroidSystem::create_update_dir (char *override_dir) noexcept override_dirs [0] = override_dir; Util::create_public_directory (override_dir); - log_warn (LOG_DEFAULT, "Creating public update directory: `{}`", override_dir); + log_warn (LOG_DEFAULT, "Creating public update directory: `%s`", override_dir); } bool @@ -431,9 +431,9 @@ AndroidSystem::get_max_gref_count_from_system (void) noexcept if (max < 0) max = std::numeric_limits::max (); if (*e) { - log_warn (LOG_GC, "Unsupported '{}' value '{}'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); + log_warn (LOG_GC, "Unsupported '%s' value '%s'.", SharedConstants::DEBUG_MONO_MAX_GREFC.data (), override.get ()); } - log_warn (LOG_GC, "Overriding max JNI Global Reference count to {}", max); + log_warn (LOG_GC, "Overriding max JNI Global Reference count to %ld", max); } return max; } @@ -459,7 +459,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_warn (LOG_DEFAULT, "(Debug) Failed to set environment variable: %s", strerror (errno)); return; } @@ -473,13 +473,13 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept struct stat sbuf; if (::stat (path, &sbuf) < 0) { - log_warn (LOG_DEFAULT, "Failed to stat the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to stat the environment override file %s: %s", path, strerror (errno)); return; } int fd = open (path, O_RDONLY); if (fd < 0) { - log_warn (LOG_DEFAULT, "Failed to open the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to open the environment override file %s: %s", path, strerror (errno)); return; } @@ -496,7 +496,7 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept } while (r < 0 && errno == EINTR); if (nread == 0) { - log_warn (LOG_DEFAULT, "Failed to read the environment override file {}: {}", path, strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to read the environment override file %s: %s", path, strerror (errno)); return; } @@ -517,26 +517,26 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept // # Variable value, terminated with NUL and padded to [value width] with NUL characters // value\0 if (nread < OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) { - log_warn (LOG_DEFAULT, "Invalid format of the environment override file {}: malformatted header", path); + log_warn (LOG_DEFAULT, "Invalid format of the environment override file %s: malformatted header", path); return; } char *endptr; unsigned long name_width = strtoul (buf.get (), &endptr, 16); if ((name_width == std::numeric_limits::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); + log_warn (LOG_DEFAULT, "Malformed header of the environment override file %s: name width has invalid format", path); 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); + log_warn (LOG_DEFAULT, "Malformed header of the environment override file %s: value width has invalid format", path); return; } uint64_t data_width = name_width + value_width; if (data_width > file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE || (file_size - OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE) % data_width != 0) { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: invalid data size", path); + log_warn (LOG_DEFAULT, "Malformed environment override file %s: invalid data size", path); return; } @@ -544,11 +544,11 @@ AndroidSystem::setup_environment_from_override_file (const char *path) noexcept char *name = buf.get () + OVERRIDE_ENVIRONMENT_FILE_HEADER_SIZE; while (data_size > 0 && data_size >= data_width) { if (*name == '\0') { - log_warn (LOG_DEFAULT, "Malformed environment override file {}: name at offset {} is empty", path, name - buf.get ()); + log_warn (LOG_DEFAULT, "Malformed environment override file %s: name at offset %zd is empty", path, name - buf.get ()); return; } - log_debug (LOG_DEFAULT, "Setting environment variable from the override file {}: '{}' = '{}'", path, name, name + name_width); + log_debug (LOG_DEFAULT, "Setting environment variable from the override file %s: '%s' = '%s'", path, name, name + name_width); setup_environment (name, name + name_width); name += data_width; data_size -= data_width; @@ -583,10 +583,10 @@ AndroidSystem::setup_environment () noexcept } if (aotMode != MonoAotMode::MONO_AOT_MODE_LAST) { - log_debug (LOG_DEFAULT, "Mono AOT mode: {}", mono_aot_mode_name); + log_debug (LOG_DEFAULT, "Mono AOT mode: %s", mono_aot_mode_name); } else { if (!is_interpreter_enabled ()) { - log_warn (LOG_DEFAULT, "Unknown Mono AOT mode: {}", mono_aot_mode_name); + log_warn (LOG_DEFAULT, "Unknown Mono AOT mode: %s", mono_aot_mode_name); } else { log_warn (LOG_DEFAULT, "Mono AOT mode: interpreter"sv); } @@ -594,7 +594,7 @@ AndroidSystem::setup_environment () noexcept } if (application_config.environment_variable_count % 2 != 0) { - log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries ({})", application_config.environment_variable_count); + log_warn (LOG_DEFAULT, "Corrupted environment variable array: does not contain an even number of entries (%u)", application_config.environment_variable_count); return; } @@ -610,10 +610,10 @@ AndroidSystem::setup_environment () noexcept var_value = ""; #if defined (DEBUG) - log_info (LOG_DEFAULT, "Setting environment variable '{}' to '{}'", var_name, var_value); + log_info (LOG_DEFAULT, "Setting environment variable '%s' to '%s'", var_name, var_value); #endif // def DEBUG if (setenv (var_name, var_value, 1) < 0) - log_warn (LOG_DEFAULT, "Failed to set environment variable: {}", strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to set environment variable: %s", strerror (errno)); } #if defined (DEBUG) log_debug (LOG_DEFAULT, "Loading environment from override directories."sv); @@ -622,9 +622,9 @@ AndroidSystem::setup_environment () noexcept continue; } std::unique_ptr env_override_file {Util::path_combine (od, OVERRIDE_ENVIRONMENT_FILE_NAME.data ())}; - log_debug (LOG_DEFAULT, "{}", env_override_file.get ()); + log_debug (LOG_DEFAULT, "%s", env_override_file.get ()); if (Util::file_exists (env_override_file.get ())) { - log_debug (LOG_DEFAULT, "Loading {}", env_override_file.get ()); + log_debug (LOG_DEFAULT, "Loading %s", env_override_file.get ()); setup_environment_from_override_file (env_override_file.get ()); } } @@ -652,12 +652,12 @@ AndroidSystem::detect_embedded_dso_mode (jstring_array_wrapper& appDirs) noexcep { // appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX] points to the native library directory std::unique_ptr libmonodroid_path {Util::path_combine (appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr (), "libmonodroid.so")}; - log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to {}", libmonodroid_path.get ()); + log_debug (LOG_ASSEMBLY, "Checking if libmonodroid was unpacked to %s", libmonodroid_path.get ()); if (!Util::file_exists (libmonodroid_path.get ())) { - log_debug (LOG_ASSEMBLY, "{} not found, assuming application/android:extractNativeLibs == false", libmonodroid_path.get ()); + log_debug (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[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, "Native libs extracted to %s, assuming application/android:extractNativeLibs == true", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); set_embedded_dso_mode_enabled (false); } } @@ -670,7 +670,7 @@ AndroidSystem::setup_app_library_directories (jstring_array_wrapper& runtimeApks AndroidSystem::app_lib_directories = std::span (single_app_lib_directory); AndroidSystem::app_lib_directories [0] = Util::strdup_new (appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); - log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: {}", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); + log_debug (LOG_ASSEMBLY, "Added filesystem DSO lookup location: %s", appDirs[SharedConstants::APP_DIRS_DATA_DIR_INDEX].get_cstr ()); } else { log_debug (LOG_DEFAULT, "Setting up for DSO lookup directly in the APK"sv); @@ -706,7 +706,7 @@ AndroidSystem::add_apk_libdir (const char *apk, size_t &index, const char *abi) { abort_unless (index < app_lib_directories.size (), "Index out of range"); app_lib_directories [index] = Util::string_concat (apk, "!/lib/", abi); - log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: {}", app_lib_directories[index]); + log_debug (LOG_ASSEMBLY, "Added APK DSO lookup location: %s", app_lib_directories[index]); index++; } diff --git a/src/native/mono/runtime-base/logger.cc b/src/native/mono/runtime-base/logger.cc index 256f6f2b030..8cb89af3386 100644 --- a/src/native/mono/runtime-base/logger.cc +++ b/src/native/mono/runtime-base/logger.cc @@ -29,7 +29,7 @@ namespace { if (path && access (path, W_OK) < 0) { log_warn (category, - "Could not open path '{}' for logging (\"{}\"). Using '{}/{}' instead.", + "Could not open path '%s' for logging (\"%s\"). Using '%s/%s' instead.", optional_string (path), strerror (errno), optional_string (override_dir), @@ -51,7 +51,7 @@ namespace { if (f) { Util::set_world_accessable (path); } else { - log_warn (category, "Could not open path '{}' for logging: {}", optional_string (path), strerror (errno)); + log_warn (category, "Could not open path '%s' for logging: %s", optional_string (path), strerror (errno)); } free (p); @@ -77,12 +77,12 @@ Logger::set_debugger_log_level (const char *level) noexcept unsigned long v = strtoul (level, nullptr, 0); if (v == std::numeric_limits::max () && errno == ERANGE) { - log_error (LOG_DEFAULT, "Invalid debugger log level value '{}', expecting a positive integer or zero", level); + log_error (LOG_DEFAULT, "Invalid debugger log level value '%s', expecting a positive integer or zero", level); return; } if (v > std::numeric_limits::max ()) { - log_warn (LOG_DEFAULT, "Debugger log level value is higher than the maximum of {}, resetting to the maximum value.", std::numeric_limits::max ()); + log_warn (LOG_DEFAULT, "Debugger log level value is higher than the maximum of %d, resetting to the maximum value.", std::numeric_limits::max ()); v = std::numeric_limits::max (); } diff --git a/src/native/mono/runtime-base/monodroid-dl.hh b/src/native/mono/runtime-base/monodroid-dl.hh index 3e2cfe62402..5a9511ba96f 100644 --- a/src/native/mono/runtime-base/monodroid-dl.hh +++ b/src/native/mono/runtime-base/monodroid-dl.hh @@ -46,11 +46,11 @@ namespace xamarin::android::internal size_t arr_size; if constexpr (WhichCache == CacheKind::AOT) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in AOT cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash %zx in AOT cache", static_cast(hash)); arr = aot_dso_cache; arr_size = application_config.number_of_aot_cache_entries; } else if constexpr (WhichCache == CacheKind::DSO) { - log_debug (LOG_ASSEMBLY, "Looking for hash {:x} in DSO cache", hash); + log_debug (LOG_ASSEMBLY, "Looking for hash %zx in DSO cache", static_cast(hash)); arr = dso_cache; arr_size = application_config.number_of_dso_cache_entries; } @@ -60,7 +60,7 @@ namespace xamarin::android::internal ssize_t idx = Search::binary_search (hash, arr, arr_size); if (idx >= 0) { - log_debug (LOG_ASSEMBLY, "Found hash 0x{:x} entry at index {} of the cache", hash, idx); + log_debug (LOG_ASSEMBLY, "Found hash 0x%zx entry at index %zd of the cache", static_cast(hash), idx); return &arr[idx]; } @@ -101,7 +101,7 @@ namespace xamarin::android::internal if (MonodroidState::is_startup_in_progress ()) { auto ignore_component = [&](const char *label, MonoComponent component) -> bool { if ((application_config.mono_components_mask & component) != component) { - log_info (LOG_ASSEMBLY, "Mono '{}' component requested but not packaged, ignoring", label); + log_info (LOG_ASSEMBLY, "Mono '%s' component requested but not packaged, ignoring", label); return true; } @@ -146,7 +146,7 @@ namespace xamarin::android::internal [[gnu::flatten]] static void* monodroid_dlopen (DSOCacheEntry *dso, hash_t name_hash, const char *name, int flags, char **err) noexcept { - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match {}found, DSO name is '{}'", dso == nullptr ? "not "sv : ""sv, dso == nullptr ? ""sv : dso->name); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash match %sfound, DSO name is '%s'", dso == nullptr ? "not " : "", dso == nullptr ? "" : dso->name); if (dso == nullptr) { // DSO not known at build time, try to load it @@ -154,11 +154,11 @@ namespace xamarin::android::internal } else if (dso->handle != nullptr) { return monodroid_dlopen_log_and_return (dso->handle, err, dso->name, false /* name_needs_free */); } - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: cache entry's real name hash == 0x{:x}; name hash == 0x{:x}", - dso->real_name_hash, dso->hash); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: cache entry's real name hash == 0x%zx; name hash == 0x%zx", + static_cast(dso->real_name_hash), static_cast(dso->hash)); if (dso->ignore) { - log_info (LOG_ASSEMBLY, "Request to load '{}' ignored, it is known not to exist", dso->name); + log_info (LOG_ASSEMBLY, "Request to load '%s' ignored, it is known not to exist", optional_string (dso->name)); return nullptr; } @@ -200,7 +200,7 @@ namespace xamarin::android::internal } hash_t name_hash = xxhash::hash (name, strlen (name)); - log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '{}' is 0x{:x}", name, name_hash); + log_debug (LOG_ASSEMBLY, "monodroid_dlopen: hash for name '%s' is 0x%zx", name, static_cast(name_hash)); DSOCacheEntry *dso = nullptr; if (prefer_aot_cache) { diff --git a/src/native/mono/runtime-base/util.cc b/src/native/mono/runtime-base/util.cc index fda41ecfd88..3b2f8712592 100644 --- a/src/native/mono/runtime-base/util.cc +++ b/src/native/mono/runtime-base/util.cc @@ -149,7 +149,7 @@ Util::create_public_directory (const char *dir) { int ret = create_directory (dir, 0777); if (ret < 0) { - log_warn (LOG_DEFAULT, "Failed to create directory '{}'. {}", dir, std::strerror (errno)); + log_warn (LOG_DEFAULT, "Failed to create directory '%s'. %s", dir, std::strerror (errno)); } } @@ -196,7 +196,7 @@ Util::set_world_accessable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"{}\", 0664) failed: {}", path, strerror (errno)); + log_error (LOG_DEFAULT, "chmod(\"%s\", 0664) failed: %s", path, strerror (errno)); } } @@ -209,7 +209,7 @@ Util::set_world_accessible (int fd) noexcept -> bool } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "fchmod() failed: {}", strerror (errno)); + log_error (LOG_DEFAULT, "fchmod() failed: %s", strerror (errno)); return false; } @@ -225,7 +225,7 @@ Util::set_user_executable ([[maybe_unused]] const char *path) } while (r == -1 && errno == EINTR); if (r == -1) { - log_error (LOG_DEFAULT, "chmod(\"{}\") failed: {}", path, strerror (errno)); + log_error (LOG_DEFAULT, "chmod(\"%s\") failed: %s", path, strerror (errno)); } } @@ -312,7 +312,7 @@ Util::monodroid_fopen (const char *filename, const char *mode) */ ret = fopen (filename, mode); if (ret == nullptr) { - log_error (LOG_DEFAULT, "fopen failed for file {}: {}", filename, strerror (errno)); + log_error (LOG_DEFAULT, "fopen failed for file %s: %s", filename, strerror (errno)); return nullptr; } diff --git a/src/native/mono/runtime-base/util.hh b/src/native/mono/runtime-base/util.hh index 8f4e6882bfe..700dd9c89ca 100644 --- a/src/native/mono/runtime-base/util.hh +++ b/src/native/mono/runtime-base/util.hh @@ -89,7 +89,7 @@ namespace xamarin::android { struct stat sbuf; if (fstatat (dirfd, file_name, &sbuf, 0) == -1) { - log_warn (LOG_ASSEMBLY, "Failed to stat file '{}': {}", file_name, std::strerror (errno)); + log_warn (LOG_ASSEMBLY, "Failed to stat file '%s': %s", optional_string (file_name), std::strerror (errno)); return std::nullopt; } @@ -100,7 +100,7 @@ namespace xamarin::android { int fd = openat (dirfd, file_name, O_RDONLY); if (fd < 0) { - log_error (LOG_ASSEMBLY, "Failed to open file '{}' for reading: {}", file_name, std::strerror (errno)); + log_error (LOG_ASSEMBLY, "Failed to open file '%s' for reading: %s", optional_string (file_name), std::strerror (errno)); return std::nullopt; } diff --git a/src/native/mono/shared/cpp-util.hh b/src/native/mono/shared/cpp-util.hh index cf4cb16bf5a..a3ba5688f54 100644 --- a/src/native/mono/shared/cpp-util.hh +++ b/src/native/mono/shared/cpp-util.hh @@ -142,7 +142,7 @@ abort_if_negative_integer_argument (int arg, const char *arg_name, std::source_l // of the calls present. force_inline inline void pd_log_location (std::source_location sloc = std::source_location::current ()) noexcept { - log_warn (LOG_DEFAULT, "loc: {}:{} ('{}')", sloc.file_name (), sloc.line (), sloc.function_name ()); + log_warn (LOG_DEFAULT, "loc: %s:%u ('%s')", sloc.file_name (), sloc.line (), sloc.function_name ()); } namespace xamarin::android diff --git a/src/native/mono/shared/helpers.cc b/src/native/mono/shared/helpers.cc index 510665cbaa3..d997f7ff4d8 100644 --- a/src/native/mono/shared/helpers.cc +++ b/src/native/mono/shared/helpers.cc @@ -11,7 +11,7 @@ using namespace xamarin::android; Helpers::abort_application (LogCategories category, const char *message, bool log_location, std::source_location sloc) noexcept { // Log it, but also... - log_fatal (category, "{}", message); + log_fatal (category, "%s", message); // ...let android include it in the tombstone, debuggerd output, stack trace etc android_set_abort_message (message); @@ -35,7 +35,7 @@ Helpers::abort_application (LogCategories category, const char *message, bool lo log_fatal ( category, - "Abort at {}:{}:{} ('{}')", + "Abort at %s:%u:%u ('%s')", file_name, sloc.line (), sloc.column (), diff --git a/src/native/mono/shared/log_functions.cc b/src/native/mono/shared/log_functions.cc index 394ba2a1927..ea3d4b2609d 100644 --- a/src/native/mono/shared/log_functions.cc +++ b/src/native/mono/shared/log_functions.cc @@ -1,4 +1,5 @@ #include +#include #include #include @@ -117,4 +118,74 @@ namespace xamarin::android { __android_log_write (priority, CATEGORY_NAME (category), message); } + + void + log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept + { + size_t map_index = static_cast(level); + android_LogPriority priority; + + if (map_index > loglevel_map_max_index) { + priority = DEFAULT_PRIORITY; + } else { + priority = loglevel_map[map_index]; + } + + const char *safe_format = format == nullptr ? "" : format; + __android_log_vprint (priority, CATEGORY_NAME (category), safe_format, args); + } + + void + log_write_fmt (LogCategories category, LogLevel level, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, level, format, args); + va_end (args); + } + + void + log_debug_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Debug, format, args); + va_end (args); + } + + void + log_info_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Info, format, args); + va_end (args); + } + + void + log_warn_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Warn, format, args); + va_end (args); + } + + void + log_error_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Error, format, args); + va_end (args); + } + + void + log_fatal_fmt (LogCategories category, const char *format, ...) noexcept + { + va_list args; + va_start (args, format); + log_writev (category, LogLevel::Fatal, format, args); + va_end (args); + } } diff --git a/src/native/mono/shared/log_types.hh b/src/native/mono/shared/log_types.hh index 0821ef59077..265d5625e6e 100644 --- a/src/native/mono/shared/log_types.hh +++ b/src/native/mono/shared/log_types.hh @@ -1,7 +1,7 @@ #pragma once +#include #include -#include #include #include @@ -20,99 +20,132 @@ #define DO_LOG_FMT(_level, _category_, _fmt_, ...) \ do { \ if ((log_categories & ((_category_))) != 0) { \ - ::log_ ## _level ## _nocheck_fmt ((_category_), _fmt_ __VA_OPT__(,) __VA_ARGS__); \ + ::xamarin::android::log_ ## _level ## _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 +// NOTE: _fmt_ takes arguments in 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 +// NOTE: _fmt_ takes arguments in 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 POSIX printf style. +#define log_warn(_category_, _fmt_, ...) ::xamarin::android::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 POSIX printf style. +#define log_error(_category_, _fmt_, ...) ::xamarin::android::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__) +// NOTE: _fmt_ takes arguments in POSIX printf style. +#define log_fatal(_category_, _fmt_, ...) ::xamarin::android::log_fatal_fmt ((_category_), (_fmt_) __VA_OPT__(,) __VA_ARGS__) namespace xamarin::android { // A slightly faster alternative to other log functions as it doesn't parse the message // for format placeholders nor it uses variable arguments void log_write (LogCategories category, LogLevel level, const char *message) noexcept; + void log_writev (LogCategories category, LogLevel level, const char *format, va_list args) noexcept; + void log_write_fmt (LogCategories category, LogLevel level, const char *format, ...) noexcept __attribute__ ((format (printf, 3, 4))); + void log_debug_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_info_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_warn_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_error_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); + void log_fatal_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); [[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_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 void log_debug_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Debug, message); + } -[[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 ()); -} + [[gnu::always_inline]] + static inline void log_info_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Info, message); + } -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 void log_warn_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Warn, message); + } -[[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 ()); -} + [[gnu::always_inline]] + static inline void log_error_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Error, message); + } -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 void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept + { + log_write (category, LogLevel::Fatal, message); + } -[[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 ()); + [[gnu::always_inline]] + static inline void log_debug_fmt (LogCategories category, std::string const& message) noexcept + { + log_debug_fmt (category, std::string_view { message }); + } + + [[gnu::always_inline]] + static inline void log_info_fmt (LogCategories category, std::string const& message) noexcept + { + log_info_fmt (category, std::string_view { message }); + } + + [[gnu::always_inline]] + static inline void log_warn_fmt (LogCategories category, std::string const& message) noexcept + { + log_warn_fmt (category, std::string_view { message }); + } + + [[gnu::always_inline]] + static inline void log_error_fmt (LogCategories category, std::string const& message) noexcept + { + log_error_fmt (category, std::string_view { message }); + } + + [[gnu::always_inline]] + static inline void log_fatal_fmt (LogCategories category, std::string const& message) noexcept + { + log_fatal_fmt (category, std::string_view { message }); + } } -template [[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +[[gnu::always_inline]] +static inline constexpr void log_debug_nocheck (LogCategories category, std::string_view const& message) noexcept { - log_write (category, xamarin::android::LogLevel::Error, std::format (fmt, std::forward(args)...).c_str ()); + xamarin::android::log_write (category, xamarin::android::LogLevel::Debug, message.data ()); } [[gnu::always_inline]] -static inline constexpr void log_error_fmt (LogCategories category, std::string_view const& message) noexcept +static inline constexpr void log_info_nocheck (LogCategories category, std::string_view const& message) noexcept { - log_write (category, xamarin::android::LogLevel::Error, message.data ()); + xamarin::android::log_write (category, xamarin::android::LogLevel::Info, message.data ()); } -template [[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::format_string fmt, Args&& ...args) noexcept +static inline void log_debug_nocheck_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); +static inline void log_debug_nocheck_fmt (LogCategories category, const char *format, ...) noexcept { - log_write (category, xamarin::android::LogLevel::Fatal, std::format (fmt, std::forward(args)...).c_str ()); + va_list args; + va_start (args, format); + xamarin::android::log_writev (category, xamarin::android::LogLevel::Debug, format, args); + va_end (args); } -[[gnu::always_inline]] -static inline constexpr void log_fatal_fmt (LogCategories category, std::string_view const& message) noexcept +static inline void log_info_nocheck_fmt (LogCategories category, const char *format, ...) noexcept __attribute__ ((format (printf, 2, 3))); +static inline void log_info_nocheck_fmt (LogCategories category, const char *format, ...) noexcept { - log_write (category, xamarin::android::LogLevel::Fatal, message.data ()); + va_list args; + va_start (args, format); + xamarin::android::log_writev (category, xamarin::android::LogLevel::Info, format, args); + va_end (args); } extern unsigned int log_categories; diff --git a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc index 85de1c000ed..b7fce6c2e5d 100644 --- a/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc +++ b/src/native/mono/xamarin-debug-app-helper/debug-app-helper.cc @@ -48,7 +48,7 @@ Java_mono_android_DebugRuntime_init (JNIEnv *env, [[maybe_unused]] jclass klass, if (runtimeNativeLibDir != nullptr) { jstr = runtimeNativeLibDir; AndroidSystem::set_runtime_libdir (Util::strdup_new (jstr.get_cstr ())); - log_warn (LOG_DEFAULT, "Using runtime path: {}", optional_string (AndroidSystem::get_runtime_libdir ())); + log_warn (LOG_DEFAULT, "Using runtime path: %s", optional_string (AndroidSystem::get_runtime_libdir ())); } const char *monosgen_path = get_libmonosgen_path (); @@ -74,7 +74,7 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) break; log_warn (LOG_DEFAULT, - "Copying file `{}` from external location `{}` to internal location `{}`", + "Copying file `%s` from external location `%s` to internal location `%s`", optional_string (file), optional_string (from_dir), optional_string (to_dir) @@ -86,12 +86,12 @@ copy_file_to_internal_location (char *to_dir, char *from_dir, char *file) int r = unlink (to_file); if (r < 0 && errno != ENOENT) { - log_warn (LOG_DEFAULT, "Unable to delete file `{}`: {}", optional_string (to_file), strerror (errno)); + log_warn (LOG_DEFAULT, "Unable to delete file `%s`: %s", optional_string (to_file), strerror (errno)); break; } if (!Util::file_copy (to_file, from_file)) { - log_warn (LOG_DEFAULT, "Copy failed from `{}` to `{}`: {}", optional_string (from_file), optional_string (to_file), strerror (errno)); + log_warn (LOG_DEFAULT, "Copy failed from `%s` to `%s`: %s", optional_string (from_file), optional_string (to_file), strerror (errno)); break; } @@ -110,22 +110,22 @@ copy_native_libraries_to_internal_location () dirent *e; char *dir_path = Util::path_combine (od, "lib"); - log_warn (LOG_DEFAULT, "checking directory: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, "checking directory: `%s`", optional_string (dir_path)); if (dir_path == nullptr || !Util::directory_exists (dir_path)) { - log_warn (LOG_DEFAULT, "directory does not exist: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, "directory does not exist: `%s`", optional_string (dir_path)); delete[] dir_path; continue; } if ((dir = ::opendir (dir_path)) == nullptr) { - log_warn (LOG_DEFAULT, "could not open directory: `{}`", optional_string (dir_path)); + log_warn (LOG_DEFAULT, "could not open directory: `%s`", optional_string (dir_path)); delete[] dir_path; continue; } while ((e = readdir (dir)) != nullptr) { - log_warn (LOG_DEFAULT, "checking file: `{}`", optional_string (e->d_name)); + log_warn (LOG_DEFAULT, "checking file: `%s`", optional_string (e->d_name)); if (Util::monodroid_dirent_hasextension (e, ".so")) { copy_file_to_internal_location (AndroidSystem::get_primary_override_dir (), dir_path, e->d_name); } @@ -142,9 +142,9 @@ runtime_exists (const char *dir, char*& libmonoso) return false; libmonoso = Util::path_combine (dir, SharedConstants::MONO_SGEN_SO); - log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: {}", optional_string (libmonoso)); + log_warn (LOG_DEFAULT, "Checking whether Mono runtime exists at: %s", optional_string (libmonoso)); if (Util::file_exists (libmonoso)) { - log_info (LOG_DEFAULT, "Mono runtime found at: {}", optional_string (libmonoso)); + log_info (LOG_DEFAULT, "Mono runtime found at: %s", optional_string (libmonoso)); return true; } delete[] libmonoso; @@ -196,34 +196,34 @@ get_libmonosgen_path () if (!Util::file_exists (link)) { int result = symlink (libmonoso, link); if (result != 0 && errno == EEXIST) { - log_warn (LOG_DEFAULT, "symlink exists, recreating: {} -> {}", optional_string (link), optional_string (libmonoso)); + log_warn (LOG_DEFAULT, "symlink exists, recreating: %s -> %s", optional_string (link), optional_string (libmonoso)); unlink (link); result = symlink (libmonoso, link); } if (result != 0) - log_warn (LOG_DEFAULT, "symlink failed with errno={} {}", errno, strerror (errno)); + log_warn (LOG_DEFAULT, "symlink failed with errno=%d %s", errno, strerror (errno)); } delete[] libmonoso; libmonoso = link; } - log_warn (LOG_DEFAULT, "Trying to load sgen from: {}", optional_string (libmonoso)); + log_warn (LOG_DEFAULT, "Trying to load sgen from: %s", optional_string (libmonoso)); if (libmonoso != nullptr && Util::file_exists (libmonoso)) return libmonoso; delete[] libmonoso; if (runtime_exists (AndroidSystem::SYSTEM_LIB_PATH.data (), libmonoso)) return libmonoso; - log_fatal (LOG_DEFAULT, "Cannot find '{}'. Looked in the following locations:", SharedConstants::MONO_SGEN_SO); + log_fatal (LOG_DEFAULT, "Cannot find '%.*s'. Looked in the following locations:", static_cast(SharedConstants::MONO_SGEN_SO.length ()), SharedConstants::MONO_SGEN_SO.data ()); for (const char *od : AndroidSystem::override_dirs) { if (od == nullptr) continue; - log_fatal (LOG_DEFAULT, " {}", optional_string (od)); + log_fatal (LOG_DEFAULT, " %s", optional_string (od)); } for (const char *app_lib_dir : AndroidSystem::app_lib_directories) { - log_fatal (LOG_DEFAULT, " {}", optional_string (app_lib_dir)); + log_fatal (LOG_DEFAULT, " %s", optional_string (app_lib_dir)); } Helpers::abort_application ( diff --git a/src/native/nativeaot/host/CMakeLists.txt b/src/native/nativeaot/host/CMakeLists.txt index 9f4ce16fb25..e072da41620 100644 --- a/src/native/nativeaot/host/CMakeLists.txt +++ b/src/native/nativeaot/host/CMakeLists.txt @@ -28,6 +28,7 @@ set(CLR_SOURCES_PATH "../../clr") set(XAMARIN_MONODROID_SOURCES bridge-processing.cc + cxx-shims.cc host.cc host-environment.cc host-jni.cc diff --git a/src/native/nativeaot/host/bridge-processing.cc b/src/native/nativeaot/host/bridge-processing.cc index b87a49b431b..dafb38dc403 100644 --- a/src/native/nativeaot/host/bridge-processing.cc +++ b/src/native/nativeaot/host/bridge-processing.cc @@ -1,18 +1,25 @@ -#include - #include #include #include using namespace xamarin::android; +const BridgeProcessingCallbacks BridgeProcessing::bridge_processing_callbacks { + .maybe_call_gc_user_peerable_add_managed_reference = &BridgeProcessing::maybe_call_gc_user_peerable_add_managed_reference, + .maybe_call_gc_user_peerable_clear_managed_references = &BridgeProcessing::maybe_call_gc_user_peerable_clear_managed_references, +}; + +BridgeProcessing::BridgeProcessing (MarkCrossReferencesArgs *args) noexcept + : BridgeProcessingShared (args, &bridge_processing_callbacks) +{} + void BridgeProcessing::naot_initialize_on_runtime_init (JNIEnv *env) noexcept { GCUserPeerable_class = env->FindClass ("net/dot/jni/GCUserPeerable"); if (GCUserPeerable_class == nullptr) [[unlikely]] { Helpers::abort_application ( LOG_DEFAULT, - "Failed to find net/dot/jni/GCUserPeerable class while initializing GC bridge processing."sv + "Failed to find net/dot/jni/GCUserPeerable class while initializing GC bridge processing." ); } @@ -21,21 +28,19 @@ void BridgeProcessing::naot_initialize_on_runtime_init (JNIEnv *env) noexcept GCUserPeerable_jiClearManagedReferences = env->GetMethodID (GCUserPeerable_class, "jiClearManagedReferences", "()V"); if (GCUserPeerable_jiAddManagedReference == nullptr || GCUserPeerable_jiClearManagedReferences == nullptr) [[unlikely]] { - constexpr auto ABSENT = "absent"sv; - constexpr auto PRESENT = "present"sv; - - Helpers::abort_application ( + constexpr char ABSENT[] = "absent"; + constexpr char PRESENT[] = "present"; + Helpers::abort_applicationf ( LOG_DEFAULT, - std::format ( - "Failed to find GCUserPeerable method(s): jiAddManagedReference ({}); jiClearManagedReferences ({})"sv, - GCUserPeerable_jiAddManagedReference == nullptr ? ABSENT : PRESENT, - GCUserPeerable_jiClearManagedReferences == nullptr ? ABSENT : PRESENT - ) + std::source_location::current (), + "Failed to find GCUserPeerable method(s): jiAddManagedReference (%s); jiClearManagedReferences (%s)", + GCUserPeerable_jiAddManagedReference == nullptr ? ABSENT : PRESENT, + GCUserPeerable_jiClearManagedReferences == nullptr ? ABSENT : PRESENT ); } } -auto BridgeProcessing::maybe_call_gc_user_peerable_add_managed_reference (JNIEnv *env, jobject from, jobject to) noexcept -> bool +bool BridgeProcessing::maybe_call_gc_user_peerable_add_managed_reference (JNIEnv *env, jobject from, jobject to) noexcept { if (!env->IsInstanceOf (from, GCUserPeerable_class)) { return false; @@ -45,7 +50,7 @@ auto BridgeProcessing::maybe_call_gc_user_peerable_add_managed_reference (JNIEnv return true; } -auto BridgeProcessing::maybe_call_gc_user_peerable_clear_managed_references (JNIEnv *env, jobject handle) noexcept -> bool +bool BridgeProcessing::maybe_call_gc_user_peerable_clear_managed_references (JNIEnv *env, jobject handle) noexcept { if (!env->IsInstanceOf (handle, GCUserPeerable_class)) { return false; diff --git a/src/native/nativeaot/host/cxx-shims.cc b/src/native/nativeaot/host/cxx-shims.cc new file mode 100644 index 00000000000..19e1e62ec49 --- /dev/null +++ b/src/native/nativeaot/host/cxx-shims.cc @@ -0,0 +1,65 @@ +#include +#include + +#include + +namespace std { + // NativeAOT is built without libc++ and with -fno-cxx-exceptions. Provide + // only the allocation/nothrow symbols needed by the runtime pack, and abort + // instead of throwing on allocation failure. + const nothrow_t nothrow {}; +} + +static void *allocate (size_t size) noexcept +{ + return malloc (size == 0 ? 1 : size); +} + +static void *allocate_or_abort (size_t size) noexcept +{ + void *ret = allocate (size); + if (ret == nullptr) { + abort (); + } + return ret; +} + +void *operator new (size_t size) +{ + return allocate_or_abort (size); +} + +void *operator new[] (size_t size) +{ + return allocate_or_abort (size); +} + +void *operator new (size_t size, std::nothrow_t const&) noexcept +{ + return allocate (size); +} + +void *operator new[] (size_t size, std::nothrow_t const&) noexcept +{ + return allocate (size); +} + +void operator delete (void *ptr) noexcept +{ + free (ptr); +} + +void operator delete[] (void *ptr) noexcept +{ + free (ptr); +} + +void operator delete (void *ptr, size_t) noexcept +{ + free (ptr); +} + +void operator delete[] (void *ptr, size_t) noexcept +{ + free (ptr); +} diff --git a/src/native/nativeaot/host/host.cc b/src/native/nativeaot/host/host.cc index b6d87483c78..7c823f13439 100644 --- a/src/native/nativeaot/host/host.cc +++ b/src/native/nativeaot/host/host.cc @@ -33,12 +33,15 @@ auto HostCommon::Java_JNI_OnLoad (JavaVM *vm, void *reserved) noexcept -> jint if (__jni_on_load_handler_count > 0) { for (uint32_t i = 0; i < __jni_on_load_handler_count; i++) { - log_debug ( - LOG_ASSEMBLY, - "Calling JNI on-load init func '{}' ({:p})", - optional_string (__jni_on_load_handler_names[i]), - reinterpret_cast(__jni_on_load_handlers[i]) - ); + if ((log_categories & LOG_ASSEMBLY) != 0) { + log_write_fmt ( + LOG_ASSEMBLY, + LogLevel::Debug, + "Calling JNI on-load init func '%s' (%p)", + optional_string (__jni_on_load_handler_names[i]), + reinterpret_cast(__jni_on_load_handlers[i]) + ); + } __jni_on_load_handlers[i] (vm, reserved); } } diff --git a/src/native/nativeaot/host/internal-pinvoke-stubs.cc b/src/native/nativeaot/host/internal-pinvoke-stubs.cc index 1c59786a9b1..b33316c1e4f 100644 --- a/src/native/nativeaot/host/internal-pinvoke-stubs.cc +++ b/src/native/nativeaot/host/internal-pinvoke-stubs.cc @@ -5,13 +5,12 @@ using namespace xamarin::android; namespace { [[gnu::noreturn]] - void pinvoke_unreachable (std::source_location sloc = std::source_location::current ()) + void pinvoke_unreachable () { Helpers::abort_application ( LOG_DEFAULT, - "The p/invoke is not implemented. This is a stub and should not be called."sv, - true, // log_location - sloc + "The p/invoke is not implemented. This is a stub and should not be called.", + false // log_location ); } } diff --git a/src/native/nativeaot/include/host/bridge-processing.hh b/src/native/nativeaot/include/host/bridge-processing.hh index 17f533aae0b..80aed8dad3a 100644 --- a/src/native/nativeaot/include/host/bridge-processing.hh +++ b/src/native/nativeaot/include/host/bridge-processing.hh @@ -7,17 +7,16 @@ class BridgeProcessing final : public BridgeProcessingShared { public: - explicit BridgeProcessing (MarkCrossReferencesArgs *args) noexcept - : BridgeProcessingShared (args) - {} + explicit BridgeProcessing (MarkCrossReferencesArgs *args) noexcept; static void naot_initialize_on_runtime_init (JNIEnv *env) noexcept; private: - auto maybe_call_gc_user_peerable_add_managed_reference (JNIEnv *env, jobject from, jobject to) noexcept -> bool override final; - auto maybe_call_gc_user_peerable_clear_managed_references (JNIEnv *env, jobject handle) noexcept -> bool override final; + static bool maybe_call_gc_user_peerable_add_managed_reference (JNIEnv *env, jobject from, jobject to) noexcept; + static bool maybe_call_gc_user_peerable_clear_managed_references (JNIEnv *env, jobject handle) noexcept; private: + static const BridgeProcessingCallbacks bridge_processing_callbacks; static inline jclass GCUserPeerable_class = nullptr; static inline jmethodID GCUserPeerable_jiAddManagedReference = nullptr; static inline jmethodID GCUserPeerable_jiClearManagedReferences = nullptr; diff --git a/src/native/nativeaot/include/host/host.hh b/src/native/nativeaot/include/host/host.hh new file mode 100644 index 00000000000..c582b598bd4 --- /dev/null +++ b/src/native/nativeaot/include/host/host.hh @@ -0,0 +1,3 @@ +#pragma once + +#include "host-nativeaot.hh"