From 43977bdca78053c5eef117822f8b590046fbe564 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 22 Apr 2025 18:53:26 +0200 Subject: [PATCH 01/20] Changes from https://github.com/dotnet/android/pull/10065 --- .../Utilities/TypeMapCecilAdapter.cs | 10 +++-- .../Utilities/TypeMapGenerator.cs | 2 +- ...eMappingDebugNativeAssemblyGeneratorCLR.cs | 43 +++++++------------ .../Xamarin.Android.Common.targets | 36 ++++++++++++++-- src/native/clr/host/typemap.cc | 28 ++++++++++++ 5 files changed, 83 insertions(+), 36 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs index fc6b4930af4..331adda506d 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs @@ -32,8 +32,10 @@ public static (TypeMapDebugDataSets dataSets, bool foundJniNativeRegistration) G var managedToJava = new List (); var foundJniNativeRegistration = false; - foreach (var td in types) { - foundJniNativeRegistration = JniAddNativeMethodRegistrationAttributeFound (foundJniNativeRegistration, td); + var javaDuplicates = new Dictionary> (StringComparer.Ordinal); + var uniqueAssemblies = needUniqueAssemblies ? new Dictionary (StringComparer.OrdinalIgnoreCase) : null; + foreach (TypeDefinition td in state.AllJavaTypes) { + UpdateApplicationConfig (state, td); TypeMapDebugEntry entry = GetDebugEntry (td, cache); HandleDebugDuplicates (javaDuplicates, entry, td, cache); @@ -60,11 +62,11 @@ public static (TypeMapDebugDataSets dataSets, bool foundJniNativeRegistration) G SyncDebugDuplicates (javaDuplicates); - return (new TypeMapDebugDataSets { + return new TypeMapDebugDataSets { JavaToManaged = javaToManaged, ManagedToJava = managedToJava, UniqueAssemblies = uniqueAssemblies != null ? new List (uniqueAssemblies.Values) : null - }, foundJniNativeRegistration); + }; } public static ReleaseGenerationState GetReleaseGenerationState (NativeCodeGenState state) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs index 56b33164d33..6cd0c3203b8 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs @@ -153,7 +153,7 @@ public void Generate (bool debugBuild, bool skipJniAddNativeMethodRegistrationAt void GenerateDebugNativeAssembly (string outputDirectory) { - TypeMapDebugDataSets dataSets = state.GetDebugNativeEntries (needUniqueAssemblies: runtime == AndroidRuntime.CoreCLR); + TypeMapDebugDataSets dataSets = TypeMapCecilAdapter.GetDebugNativeEntries (state, needUniqueAssemblies: runtime == AndroidRuntime.CoreCLR); var data = new ModuleDebugData { EntryCount = (uint)dataSets.JavaToManaged.Count, diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index 2257754a2d5..bc3592ec198 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -22,14 +22,15 @@ sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvid public override ulong GetBufferSize (object data, string fieldName) { var map_module = EnsureType (data); - return fieldName switch { - "java_to_managed" => map_module.entry_count, - "managed_to_java" => map_module.entry_count, - _ => 0 - }; + if (String.Compare ("java_to_managed", fieldName, StringComparison.Ordinal) == 0 || + String.Compare ("managed_to_java", fieldName, StringComparison.Ordinal) == 0) { + return map_module.entry_count; + } + + return 0; } - public override string? GetPointedToSymbolName (object data, string fieldName) + public override string GetPointedToSymbolName (object data, string fieldName) { var map_module = EnsureType (data); @@ -87,10 +88,10 @@ public override string GetComment (object data, string fieldName) sealed class TypeMapEntry { [NativeAssembler (UsesDataProvider = true)] - public string from = String.Empty; + public string from; [NativeAssembler (UsesDataProvider = true)] - public string? to; + public string to; }; // Order of fields and their type must correspond *exactly* to that in @@ -121,7 +122,7 @@ sealed class TypeMap sealed class TypeMapAssembly { [NativeAssembler (Ignore = true)] - public string Name = String.Empty; + public string Name; [NativeAssembler (Ignore = true)] public Guid MVID; @@ -135,13 +136,13 @@ sealed class TypeMapAssembly } readonly TypeMapGenerator.ModuleDebugData data; - StructureInfo? typeMapEntryStructureInfo; - StructureInfo? typeMapStructureInfo; - StructureInfo? typeMapAssemblyStructureInfo; + StructureInfo typeMapEntryStructureInfo; + StructureInfo typeMapStructureInfo; + StructureInfo typeMapAssemblyStructureInfo; List> javaToManagedMap; List> managedToJavaMap; List> uniqueAssemblies; - StructureInstance? type_map; + StructureInstance type_map; public TypeMappingDebugNativeAssemblyGeneratorCLR (TaskLoggingHelper log, TypeMapGenerator.ModuleDebugData data) : base (log) @@ -161,10 +162,6 @@ protected override void Construct (LlvmIrModule module) { module.DefaultStringGroup = "tmd"; - if (data.UniqueAssemblies == null) { - throw new InvalidOperationException ("Internal error: unique assemblies collection must be present"); - } - MapStructures (module); if (data.ManagedToJavaMap != null && data.ManagedToJavaMap.Count > 0) { @@ -206,17 +203,7 @@ protected override void Construct (LlvmIrModule module) assemblyNamesBlob.AddRange (nameBytes); assemblyNamesBlob.Add (0); } - uniqueAssemblies.Sort ((StructureInstance a, StructureInstance b) => { - if (a.Instance == null) { - return b.Instance == null ? 0 : -1; - } - - if (b.Instance == null) { - return 1; - } - - return a.Instance.mvid_hash.CompareTo (b.Instance.mvid_hash); - }); + uniqueAssemblies.Sort ((StructureInstance a, StructureInstance b) => a.Instance.mvid_hash.CompareTo (b.Instance.mvid_hash)); var map = new TypeMap { JavaToManagedCount = data.JavaToManagedMap == null ? 0 : data.JavaToManagedMap.Count, diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 6421833e60e..def9301bd9a 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1880,9 +1880,39 @@ because xbuild doesn't support framework reference assemblies. + ResolvedAssemblies="@(_ResolvedAssemblies)" + ResolvedUserAssemblies="@(_ResolvedUserAssemblies)" + SatelliteAssemblies="@(_AndroidResolvedSatellitePaths)" + IntermediateOutputDirectory="$(IntermediateOutputPath)" + NativeLibraries="@(AndroidNativeLibrary);@(EmbeddedNativeLibrary);@(FrameworkNativeLibrary)" + MonoComponents="@(_MonoComponent)" + MainAssembly="$(TargetPath)" + OutputDirectory="$(_AndroidIntermediateJavaSourceDirectory)mono" + EnvironmentOutputDirectory="$(IntermediateOutputPath)android" + TargetFrameworkVersion="$(TargetFrameworkVersion)" + Manifest="$(IntermediateOutputPath)android\AndroidManifest.xml" + Environments="@(_EnvironmentFiles)" + AndroidAotMode="$(AndroidAotMode)" + AndroidAotEnableLazyLoad="$(AndroidAotEnableLazyLoad)" + EnableLLVM="$(EnableLLVM)" + HttpClientHandlerType="$(AndroidHttpClientHandlerType)" + TlsProvider="$(AndroidTlsProvider)" + Debug="$(AndroidIncludeDebugSymbols)" + AndroidSequencePointsMode="$(_SequencePointsMode)" + EnableSGenConcurrent="$(AndroidEnableSGenConcurrent)" + SupportedAbis="@(_BuildTargetAbis)" + AndroidPackageName="$(_AndroidPackage)" + EnablePreloadAssembliesDefault="$(_AndroidEnablePreloadAssembliesDefault)" + PackageNamingPolicy="$(AndroidPackageNamingPolicy)" + BoundExceptionType="$(AndroidBoundExceptionType)" + RuntimeConfigBinFilePath="$(_BinaryRuntimeConfigPath)" + UseAssemblyStore="$(_AndroidUseAssemblyStore)" + EnableMarshalMethods="$(_AndroidUseMarshalMethods)" + EnableManagedMarshalMethodsLookup="$(_AndroidUseManagedMarshalMethodsLookup)" + CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" + TargetsCLR="$(_AndroidUseCLR)" + ProjectRuntimeConfigFilePath="$(ProjectRuntimeConfigFilePath)" + > bool +{ + log_debug (LOG_ASSEMBLY, "typemap_java_to_managed: looking up type '{}'", optional_string (java_type_name)); + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing.start_event (TimingEventKind::JavaToManaged); + } + + if (java_type_name == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "typemap: type name not specified in typemap_java_to_managed"); + return false; + } + + bool ret; +#if defined(RELEASE) + ret = typemap_java_to_managed_release (java_type_name, assembly_name, managed_type_token_id); +#else + ret = typemap_java_to_managed_debug (java_type_name, assembly_name, managed_type_token_id); +#endif + + if (FastTiming::enabled ()) [[unlikely]] { + internal_timing.end_event (); + } + + return ret; +} From 7367dc3cadaa08e204a2c67e09a8f8872d08cc2e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 24 Apr 2025 22:27:23 +0200 Subject: [PATCH 02/20] WIP --- .../Android.Runtime/AndroidRuntime.cs | 2 + src/Mono.Android/Java.Interop/TypeManager.cs | 3 + .../LlvmIrGenerator/LlvmIrGenerator.cs | 39 ++++++++++++ .../LlvmIrGenerator/LlvmIrStringBlob.cs | 63 +++++++++++++++++++ ...appingReleaseNativeAssemblyGeneratorCLR.cs | 6 ++ src/native/clr/host/host.cc | 6 ++ src/native/clr/host/internal-pinvokes.cc | 1 + 7 files changed, 120 insertions(+) create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs index 3f6d8f86cf2..ec0f0891c86 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs @@ -265,9 +265,11 @@ public AndroidTypeManager (bool jniAddNativeMethodRegistrationAttributePresent) protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) { + RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"#1 GetTypesForSimpleReference (\"{jniSimpleReference}\")"); foreach (var ti in base.GetTypesForSimpleReference (jniSimpleReference)) yield return ti; + RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"#2 GetTypesForSimpleReference (\"{jniSimpleReference}\")"); var t = Java.Interop.TypeManager.GetJavaToManagedType (jniSimpleReference); if (t != null) yield return t; diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index adc07f0edb1..e526c52bd39 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -131,6 +131,7 @@ static Type[] GetParameterTypes (string? signature) [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type.GetType() can never statically know the string value from parameter 'typename_ptr'.")] static void n_Activate (IntPtr jnienv, IntPtr jclass, IntPtr typename_ptr, IntPtr signature_ptr, IntPtr jobject, IntPtr parameters_ptr) { + RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"TypeManager.n_Activate"); if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return; @@ -253,6 +254,7 @@ static Type monovm_typemap_java_to_managed (string java_type_name) internal static Type? GetJavaToManagedType (string class_name) { + RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"TypeManager.GetJavaToManagedType (\"{class_name}\")"); Type? type = JNIEnvInit.RuntimeType switch { DotNetRuntimeType.MonoVM => monovm_typemap_java_to_managed (class_name), DotNetRuntimeType.CoreCLR => clr_typemap_java_to_managed (class_name), @@ -281,6 +283,7 @@ static Type monovm_typemap_java_to_managed (string java_type_name) [UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "TypeManager.CreateProxy() does not statically know the value of the 'type' local variable.")] internal static IJavaPeerable? CreateInstance (IntPtr handle, JniHandleOwnership transfer, Type? targetType) { + RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"TypeManager.CreateInstance ()"); Type? type = null; IntPtr class_ptr = JNIEnv.GetObjectClass (handle); string? class_name = GetClassName (class_ptr); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs index ccc4fb0b506..406c745d563 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs @@ -479,6 +479,11 @@ void WriteType (GeneratorWriteContext context, Type type, object? value, out Llv return; } + if (type == typeof(LlvmIrStringBlob)) { + WriteStringBlobType (context, (LlvmIrStringBlob?)value, out typeInfo); + return; + } + irType = GetIRType (context, type, out size, out isPointer); typeInfo = new LlvmTypeInfo ( isPointer: isPointer, @@ -490,6 +495,21 @@ void WriteType (GeneratorWriteContext context, Type type, object? value, out Llv context.Output.Write (irType); } + void WriteStringBlobType (GeneratorWriteContext context, LlvmIrStringBlob? blob, out LlvmTypeInfo typeInfo) + { + long size = blob?.Size ?? 0; + // Blobs are always arrays of bytes + context.Output.Write ($"[{size} x i8]"); + + typeInfo = new LlvmTypeInfo ( + isPointer: false, + isAggregate: true, + isStructure: false, + size: (ulong)size, + maxFieldAlignment: 1 + ); + } + void WriteArrayType (GeneratorWriteContext context, Type elementType, ulong elementCount, out LlvmTypeInfo typeInfo) { WriteArrayType (context, elementType, elementCount, variable: null, out typeInfo); @@ -769,6 +789,11 @@ public void WriteValue (GeneratorWriteContext context, Type type, object? value, return; } + if (type == typeof(LlvmIrStringBlob)) { + WriteStringBlobArray (context, (LlvmIrStringBlob)value); + return; + } + if (type.IsArray) { if (type == typeof(byte[])) { WriteInlineArray (context, (byte[])value, encodeAsASCII: true); @@ -786,6 +811,20 @@ public void WriteValue (GeneratorWriteContext context, Type type, object? value, throw new NotSupportedException ($"Internal error: value type '{type}' is unsupported"); } + void WriteStringBlobArray (GeneratorWriteContext context, LlvmIrStringBlob blob) + { + foreach (LlvmIrStringBlob.StringInfo si in blob.GetSegments ()) { + if (si.Offset > 0) { + context.Output.WriteLine (); + } + + WriteCommentLine (context, $" {si.Value}"); + // TODO: write bytes, 16 hex numbers per line + context.Output.WriteLine (", u0x00,"); // Terminating NUL is counted for each string, but not included in its bytes + } + throw new NotImplementedException (); + } + void WriteStructureValue (GeneratorWriteContext context, StructureInstance? instance) { if (instance == null || instance.IsZeroInitialized) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs new file mode 100644 index 00000000000..aa6a26eea1a --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; + +namespace Xamarin.Android.Tasks.LLVMIR; + +/// +/// This class is an optimization which allows us to store strings +/// as a single "blob" of data where each string follows another, all +/// of them separated with a NUL character. This allows us to use a single +/// pointer at run time instead of several (one per string). The result is +/// less relocations in the final .so, which is good for performance +/// +/// Each string is converted to UTF8 before storing as a byte array. To optimize +/// for size, duplicate strings are not stored, instead the earlier offset+length +/// are returned when calling the method. +/// +/// +class LlvmIrStringBlob +{ + // Length is one more than byte size, to account for the terminating nul + public record struct StringInfo (int Offset, int Length, byte[] Bytes, string Value); + + Dictionary cache = new (StringComparer.Ordinal); + List segments = new (); + long size = 0; + + public long Size => size; + + public (int offset, int length) Add (string s) + { + if (cache.TryGetValue (s, out StringInfo info)) { + return (info.Offset, info.Length); + } + + byte[] bytes = MonoAndroidHelper.Utf8StringToBytes (s); + int offset; + if (segments.Count > 0) { + StringInfo lastSegment = segments[segments.Count - 1]; + offset = lastSegment.Offset + lastSegment.Length; + } else { + offset = 0; + } + + info = new StringInfo ( + Offset: offset, + Length: bytes.Length + 1, // MUST include the terminating NUL ("virtual") + Bytes: bytes, + Value: s + ); + segments.Add (info); + cache.Add (s, info); + size += info.Length; + + return (info.Offset, info.Length); + } + + public IEnumerable GetSegments () + { + foreach (StringInfo si in segments) { + yield return si; + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs index a27b5fa5908..78366bd3596 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs @@ -219,6 +219,7 @@ sealed class ConstructionState public List> JavaMap; public List AllModulesData; public List AssemblyNames; + public LlvmIrStringBlob AssemblyNamesBlob; } readonly NativeTypeMappingData mappingData; @@ -299,6 +300,9 @@ protected override void Construct (LlvmIrModule module) module.AddGlobalVariable ("java_type_names", cs.JavaNames, LlvmIrVariableOptions.GlobalConstant, " Java type names"); module.AddGlobalVariable ("managed_type_names", cs.ManagedTypeNames, LlvmIrVariableOptions.GlobalConstant, " Managed type names"); module.AddGlobalVariable ("managed_assembly_names", cs.AssemblyNames, LlvmIrVariableOptions.GlobalConstant, " Managed assembly names"); + + // WIP + module.AddGlobalVariable ("managed_assembly_names_blob", cs.AssemblyNamesBlob, LlvmIrVariableOptions.GlobalConstant, " Managed assembly names"); } void SortEntriesAndUpdateJavaIndexes (LlvmIrVariable variable, LlvmIrModuleTarget target, object? callerState) @@ -427,6 +431,7 @@ void InitMapModules (ConstructionState cs) cs.MapModules = new List> (); cs.AssemblyNames = new List (); + cs.AssemblyNamesBlob = new (); foreach (TypeMapGenerator.ModuleReleaseData data in mappingData.Modules) { uint assemblyNameIndex = GetEntryIndex (data.AssemblyName, seenAssemblyNames, cs.AssemblyNames); string mapName = $"module{moduleCounter++}_managed_to_java"; @@ -438,6 +443,7 @@ void InitMapModules (ConstructionState cs) duplicateMapName = $"{mapName}_duplicates"; } + (int stringOffset, int stringLength) = cs.AssemblyNamesBlob.Add (data.AssemblyName); var map_module = new TypeMapModule { MVID = data.Mvid, MapSymbolName = mapName, diff --git a/src/native/clr/host/host.cc b/src/native/clr/host/host.cc index 5ca6b4f7877..8103c70030b 100644 --- a/src/native/clr/host/host.cc +++ b/src/native/clr/host/host.cc @@ -433,6 +433,12 @@ void Host::Java_mono_android_Runtime_register (JNIEnv *env, jstring managedType, int methods_len = env->GetStringLength (methods); const jchar *methods_ptr = env->GetStringChars (methods, nullptr); + 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: '{}'", managed_type_name.get ()); + env->ReleaseStringUTFChars (managedType, mt_ptr); + // TODO: must attach thread to the runtime here jnienv_register_jni_natives (managedType_ptr, managedType_len, nativeClass, methods_ptr, methods_len); diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 4d801afe032..a6b8c8f4880 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -33,6 +33,7 @@ const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mv bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept { + log_debug (LOG_ASSEMBLY, __PRETTY_FUNCTION__); return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); } From 2770605c4340c7f8b544900aa1a5c279f0ee78b3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 25 Apr 2025 12:20:51 +0200 Subject: [PATCH 03/20] Fix after rebase --- .../Xamarin.Android.Common.targets | 36 ++----------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index def9301bd9a..6421833e60e 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1880,39 +1880,9 @@ because xbuild doesn't support framework reference assemblies. + MainAssembly="$(TargetPath)" + OutputDirectory="$(_AndroidIntermediateJavaSourceDirectory)mono" + ResolvedUserAssemblies="@(_ResolvedUserAssemblies)"> Date: Fri, 25 Apr 2025 17:52:11 +0200 Subject: [PATCH 04/20] Use string blobs to decrease number of relocations --- .../LlvmIrGenerator/LlvmIrGenerator.cs | 61 +++++++++++++++++-- .../LlvmIrGenerator/LlvmIrStringBlob.cs | 6 +- ...eMappingDebugNativeAssemblyGeneratorCLR.cs | 14 ++--- ...appingReleaseNativeAssemblyGeneratorCLR.cs | 43 ++++++------- src/native/clr/host/typemap.cc | 27 ++++---- src/native/clr/include/xamarin-app.hh | 12 ++-- .../xamarin-app-stub/application_dso_stub.cc | 9 +-- 7 files changed, 117 insertions(+), 55 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs index 406c745d563..28f8a57809e 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrGenerator.cs @@ -374,6 +374,10 @@ bool IsValueAssignableFrom (Type valueType, LlvmIrVariable variable) ulong GetAggregateValueElementCount (GeneratorWriteContext context, Type type, object? value, LlvmIrGlobalVariable? globalVariable = null) { + if (type == typeof(LlvmIrStringBlob)) { + return 1; // String blobs are a collection of bytes + } + if (!type.IsArray ()) { throw new InvalidOperationException ($"Internal error: unknown type {type} when trying to determine aggregate type element count"); } @@ -813,16 +817,65 @@ public void WriteValue (GeneratorWriteContext context, Type type, object? value, void WriteStringBlobArray (GeneratorWriteContext context, LlvmIrStringBlob blob) { + const uint stride = 16; + Type elementType = typeof(byte); + + LlvmIrVariableNumberFormat oldNumberFormat = context.NumberFormat; + context.NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal; + WriteArrayValueStart (context); foreach (LlvmIrStringBlob.StringInfo si in blob.GetSegments ()) { if (si.Offset > 0) { + context.Output.Write (','); + context.Output.WriteLine (); context.Output.WriteLine (); } - WriteCommentLine (context, $" {si.Value}"); - // TODO: write bytes, 16 hex numbers per line - context.Output.WriteLine (", u0x00,"); // Terminating NUL is counted for each string, but not included in its bytes + context.Output.Write (context.CurrentIndent); + WriteCommentLine (context, $" '{si.Value}' @ {si.Offset}"); + WriteBytes (si.Bytes); + } + context.Output.WriteLine (); + WriteArrayValueEnd (context); + context.NumberFormat = oldNumberFormat; + + void WriteBytes (byte[] bytes) + { + ulong counter = 0; + bool first = true; + foreach (byte b in bytes) { + if (!first) { + WriteCommaWithStride (counter); + } else { + context.Output.Write (context.CurrentIndent); + first = false; + } + + counter++; + WriteByteTypeAndValue (b); + } + + WriteCommaWithStride (counter); + WriteByteTypeAndValue (0); // Terminating NUL is counted for each string, but not included in its bytes + } + + void WriteCommaWithStride (ulong counter) + { + context.Output.Write (','); + if (stride == 1 || counter % stride == 0) { + context.Output.WriteLine (); + context.Output.Write (context.CurrentIndent); + } else { + context.Output.Write (' '); + } + } + + void WriteByteTypeAndValue (byte v) + { + WriteType (context, elementType, v, out _); + + context.Output.Write (' '); + WriteValue (context, elementType, v); } - throw new NotImplementedException (); } void WriteStructureValue (GeneratorWriteContext context, StructureInstance? instance) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs index aa6a26eea1a..0f74ecc8d1c 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs @@ -36,20 +36,20 @@ public record struct StringInfo (int Offset, int Length, byte[] Bytes, string Va int offset; if (segments.Count > 0) { StringInfo lastSegment = segments[segments.Count - 1]; - offset = lastSegment.Offset + lastSegment.Length; + offset = lastSegment.Offset + lastSegment.Length + 1; // Include trailing NUL here } else { offset = 0; } info = new StringInfo ( Offset: offset, - Length: bytes.Length + 1, // MUST include the terminating NUL ("virtual") + Length: bytes.Length, Bytes: bytes, Value: s ); segments.Add (info); cache.Add (s, info); - size += info.Length; + size += info.Length + 1; // Account for the trailing NUL return (info.Offset, info.Length); } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index bc3592ec198..8f4242ba770 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -15,7 +15,7 @@ class TypeMappingDebugNativeAssemblyGeneratorCLR : LlvmIrComposer // These names MUST match src/native/clr/include/xamarin-app.hh const string TypeMapSymbol = "type_map"; const string UniqueAssembliesSymbol = "type_map_unique_assemblies"; - const string AssemblyNamesBlobSymbol = "type_map_assembly_names_blob"; + const string AssemblyNamesBlobSymbol = "type_map_assembly_names"; sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvider { @@ -188,20 +188,18 @@ protected override void Construct (LlvmIrModule module) // CoreCLR supports only 64-bit targets, so we can make things simpler by hashing the MVIDs here instead of // in a callback during code generation - var assemblyNamesBlob = new List (); + var assemblyNamesBlob = new LlvmIrStringBlob (); foreach (TypeMapGenerator.TypeMapDebugAssembly asm in data.UniqueAssemblies) { - byte[] nameBytes = MonoAndroidHelper.Utf8StringToBytes (asm.Name); + (int assemblyNameOffset, int assemblyNameLength) = assemblyNamesBlob.Add (asm.Name); var entry = new TypeMapAssembly { Name = asm.Name, MVID = asm.MVID, mvid_hash = MonoAndroidHelper.GetXxHash (asm.MVIDBytes, is64Bit: true), - name_length = (ulong)nameBytes.Length, // without the trailing NUL - name_offset = (ulong)assemblyNamesBlob.Count, + name_length = (ulong)assemblyNameLength, // without the trailing NUL + name_offset = (ulong)assemblyNameOffset, }; uniqueAssemblies.Add (new StructureInstance (typeMapAssemblyStructureInfo, entry)); - assemblyNamesBlob.AddRange (nameBytes); - assemblyNamesBlob.Add (0); } uniqueAssemblies.Sort ((StructureInstance a, StructureInstance b) => a.Instance.mvid_hash.CompareTo (b.Instance.mvid_hash)); @@ -211,7 +209,7 @@ protected override void Construct (LlvmIrModule module) entry_count = data.EntryCount, unique_assemblies_count = (ulong)data.UniqueAssemblies.Count, - assembly_names_blob_size = (ulong)assemblyNamesBlob.Count, + assembly_names_blob_size = (ulong)assemblyNamesBlob.Size, }; type_map = new StructureInstance (typeMapStructureInfo, map); module.AddGlobalVariable (TypeMapSymbol, type_map, LlvmIrVariableOptions.GlobalConstant); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs index 78366bd3596..03662f4d459 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingReleaseNativeAssemblyGeneratorCLR.cs @@ -145,6 +145,7 @@ sealed class TypeMapModule [NativeAssembler (UsesDataProvider = true)] public uint assembly_name_index; + public uint assembly_name_length; [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToSymbol = "")] public TypeMapModuleEntry map; @@ -174,12 +175,14 @@ sealed class TypeMapJava [NativeAssembler (UsesDataProvider = true)] public uint managed_type_name_index; + public uint managed_type_name_length; [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] public uint managed_type_token_id; [NativeAssembler (UsesDataProvider = true)] public uint java_name_index; + public uint java_name_length; } sealed class ModuleMapData @@ -214,12 +217,11 @@ sealed class ConstructionState { public List> MapModules; public Dictionary JavaTypesByName; - public List JavaNames; - public List ManagedTypeNames; public List> JavaMap; public List AllModulesData; - public List AssemblyNames; public LlvmIrStringBlob AssemblyNamesBlob; + public LlvmIrStringBlob JavaTypeNamesBlob; + public LlvmIrStringBlob ManagedTypeNamesBlob; } readonly NativeTypeMappingData mappingData; @@ -260,7 +262,6 @@ protected override void Construct (LlvmIrModule module) var cs = new ConstructionState (); cs.JavaTypesByName = new Dictionary (StringComparer.Ordinal); - cs.JavaNames = new List (); InitJavaMap (cs); InitMapModules (cs); HashJavaNames (cs); @@ -297,12 +298,10 @@ protected override void Construct (LlvmIrModule module) } module.AddGlobalVariable ("java_to_managed_map", cs.JavaMap, LlvmIrVariableOptions.GlobalConstant, " Java to managed map"); - module.AddGlobalVariable ("java_type_names", cs.JavaNames, LlvmIrVariableOptions.GlobalConstant, " Java type names"); - module.AddGlobalVariable ("managed_type_names", cs.ManagedTypeNames, LlvmIrVariableOptions.GlobalConstant, " Managed type names"); - module.AddGlobalVariable ("managed_assembly_names", cs.AssemblyNames, LlvmIrVariableOptions.GlobalConstant, " Managed assembly names"); - - // WIP - module.AddGlobalVariable ("managed_assembly_names_blob", cs.AssemblyNamesBlob, LlvmIrVariableOptions.GlobalConstant, " Managed assembly names"); + module.AddGlobalVariable ("java_type_names", cs.JavaTypeNamesBlob, LlvmIrVariableOptions.GlobalConstant, " Java type names"); + module.AddGlobalVariable ("java_type_names_size", (ulong)cs.JavaTypeNamesBlob.Size, LlvmIrVariableOptions.GlobalConstant, " Java type names blob size"); + module.AddGlobalVariable ("managed_type_names", cs.ManagedTypeNamesBlob, LlvmIrVariableOptions.GlobalConstant, " Managed type names"); + module.AddGlobalVariable ("managed_assembly_names", cs.AssemblyNamesBlob, LlvmIrVariableOptions.GlobalConstant, " Managed assembly names"); } void SortEntriesAndUpdateJavaIndexes (LlvmIrVariable variable, LlvmIrModuleTarget target, object? callerState) @@ -402,21 +401,24 @@ void InitJavaMap (ConstructionState cs) { var seenManagedTypeNames = new Dictionary (StringComparer.Ordinal); cs.JavaMap = new List> (); - cs.ManagedTypeNames = new List (); + cs.ManagedTypeNamesBlob = new (); + cs.JavaTypeNamesBlob = new (); TypeMapJava map_entry; foreach (TypeMapGenerator.TypeMapReleaseEntry entry in mappingData.JavaTypes) { string assemblyName = mappingData.Modules[entry.ModuleIndex].AssemblyName; - uint managedTypeNameIndex = GetEntryIndex (entry.ManagedTypeName, seenManagedTypeNames, cs.ManagedTypeNames); - cs.JavaNames.Add (entry.JavaName); + (int managedTypeNameIndex, int managedTypeNameLength) = cs.ManagedTypeNamesBlob.Add (entry.ManagedTypeName); + (int javaTypeNameIndex, int javaTypeNameLength) = cs.JavaTypeNamesBlob.Add (entry.JavaName); map_entry = new TypeMapJava { - ManagedTypeName = cs.ManagedTypeNames[(int)managedTypeNameIndex], + ManagedTypeName = entry.ManagedTypeName, module_index = (uint)entry.ModuleIndex, // UInt32.MaxValue, - managed_type_name_index = managedTypeNameIndex, + managed_type_name_index = (uint)managedTypeNameIndex, + managed_type_name_length = (uint)managedTypeNameLength, managed_type_token_id = entry.Token, - java_name_index = (uint)(cs.JavaNames.Count - 1), + java_name_index = (uint)javaTypeNameIndex, + java_name_length = (uint)javaTypeNameLength, JavaName = entry.JavaName, }; @@ -430,10 +432,8 @@ void InitMapModules (ConstructionState cs) var seenAssemblyNames = new Dictionary (StringComparer.OrdinalIgnoreCase); cs.MapModules = new List> (); - cs.AssemblyNames = new List (); cs.AssemblyNamesBlob = new (); foreach (TypeMapGenerator.ModuleReleaseData data in mappingData.Modules) { - uint assemblyNameIndex = GetEntryIndex (data.AssemblyName, seenAssemblyNames, cs.AssemblyNames); string mapName = $"module{moduleCounter++}_managed_to_java"; string duplicateMapName; @@ -443,18 +443,19 @@ void InitMapModules (ConstructionState cs) duplicateMapName = $"{mapName}_duplicates"; } - (int stringOffset, int stringLength) = cs.AssemblyNamesBlob.Add (data.AssemblyName); + (int assemblyNameIndex, int assemblyNameLength) = cs.AssemblyNamesBlob.Add (data.AssemblyName); var map_module = new TypeMapModule { MVID = data.Mvid, MapSymbolName = mapName, DuplicateMapSymbolName = duplicateMapName.Length == 0 ? null : duplicateMapName, Data = data, - AssemblyName = cs.AssemblyNames[(int)assemblyNameIndex], + AssemblyName = data.AssemblyName, module_uuid = data.MvidBytes, entry_count = (uint)data.Types.Length, duplicate_count = (uint)data.DuplicateTypes.Count, - assembly_name_index = assemblyNameIndex, + assembly_name_index = (uint)assemblyNameIndex, + assembly_name_length = (uint)assemblyNameLength, }; cs.MapModules.Add (new StructureInstance (typeMapModuleStructureInfo, map_module)); diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 783d1db1eef..51a1eceed79 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -115,8 +115,13 @@ auto TypeMapper::typemap_managed_to_java_debug (const char *typeName, const uint if (idx >= 0) [[likely]] { TypeMapAssembly const& assm = type_map_unique_assemblies[idx]; full_type_name.append (", "sv); - full_type_name.append (&type_map_assembly_names_blob[assm.name_offset], assm.name_length); - log_debug (LOG_ASSEMBLY, "Fixed-up type name: '{}'", full_type_name.get ()); + + if (assm.name_offset < type_map.assembly_names_blob_size) [[likely]] { + full_type_name.append (&type_map_assembly_names[assm.name_offset], assm.name_length); + log_debug (LOG_ASSEMBLY, "Fixed-up type name: '{}'", full_type_name.get ()); + } else { + log_warn (LOG_ASSEMBLY, "Invalid assembly name offset {}", assm.name_offset); + } } else { log_warn (LOG_ASSEMBLY, "Unable to look up assembly name for type '{}', trying without it.", typeName); } @@ -207,7 +212,7 @@ auto TypeMapper::typemap_managed_to_java_release (const char *typeName, const ui optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - optional_string (managed_assembly_names[match->assembly_name_index]) + std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length) ); return nullptr; } @@ -220,21 +225,21 @@ auto TypeMapper::typemap_managed_to_java_release (const char *typeName, const ui optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - optional_string (managed_assembly_names[match->assembly_name_index]), + std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), entry->java_map_index ); return nullptr; } TypeMapJava const& java_entry = java_to_managed_map[entry->java_map_index]; - if (java_entry.java_name_index >= java_type_count) [[unlikely]] { + 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 {})", optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - optional_string (managed_assembly_names[match->assembly_name_index]), + std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), entry->java_map_index, java_entry.java_name_index ); @@ -242,7 +247,7 @@ auto TypeMapper::typemap_managed_to_java_release (const char *typeName, const ui return nullptr; } - const char *ret = java_type_names[java_entry.java_name_index]; + 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); } @@ -253,7 +258,7 @@ auto TypeMapper::typemap_managed_to_java_release (const char *typeName, const ui optional_string (typeName), name_hash, MonoGuidString (mvid).c_str (), - optional_string (managed_assembly_names[match->assembly_name_index]), + std::string_view (&managed_assembly_names[match->assembly_name_index], match->assembly_name_length), ret ); @@ -358,16 +363,16 @@ auto TypeMapper::typemap_java_to_managed_release (const char *java_type_name, ch } TypeMapModule const &module = managed_to_java_map[java_entry->module_index]; - *assembly_name = managed_assembly_names[module.assembly_name_index]; + *assembly_name = &managed_assembly_names[module.assembly_name_index]; *managed_type_token_id = java_entry->managed_type_token_id; log_debug ( LOG_ASSEMBLY, "Java type '{}' corresponds to managed type '{}' (token 0x{:x} in assembly '{}')", optional_string (java_type_name), - optional_string (managed_type_names[java_entry->managed_type_name_index]), + std::string_view (&managed_type_names[java_entry->managed_type_name_index], java_entry->managed_type_name_length), *managed_type_token_id, - optional_string (*assembly_name) + std::string_view (&managed_assembly_names[module.assembly_name_index], module.assembly_name_length) ); return true; diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index b8717e5e7eb..e56d345a568 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -91,6 +91,7 @@ struct TypeMapModule uint32_t entry_count; uint32_t duplicate_count; uint32_t assembly_name_index; + uint32_t assembly_name_length; TypeMapModuleEntry const *map; TypeMapModuleEntry const *duplicate_map; }; @@ -99,8 +100,10 @@ struct TypeMapJava { uint32_t module_index; uint32_t managed_type_name_index; + uint32_t managed_type_name_length; uint32_t managed_type_token_id; uint32_t java_name_index; + uint32_t java_name_length; }; #endif @@ -321,13 +324,14 @@ extern "C" { #if defined (DEBUG) [[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs [[gnu::visibility("default")]] extern const TypeMapAssembly type_map_unique_assemblies[]; - [[gnu::visibility("default")]] extern const char type_map_assembly_names_blob[]; + [[gnu::visibility("default")]] extern const char type_map_assembly_names[]; #else [[gnu::visibility("default")]] extern const uint32_t managed_to_java_map_module_count; [[gnu::visibility("default")]] extern const uint32_t java_type_count; - [[gnu::visibility("default")]] extern const char* const java_type_names[]; - [[gnu::visibility("default")]] extern const char* const managed_type_names[]; - [[gnu::visibility("default")]] extern const char* const managed_assembly_names[]; + [[gnu::visibility("default")]] extern const char java_type_names[]; + [[gnu::visibility("default")]] extern const uint64_t java_type_names_size; + [[gnu::visibility("default")]] extern const char managed_type_names[]; + [[gnu::visibility("default")]] extern const char managed_assembly_names[]; [[gnu::visibility("default")]] extern TypeMapModule managed_to_java_map[]; [[gnu::visibility("default")]] extern const TypeMapJava java_to_managed_map[]; [[gnu::visibility("default")]] extern const xamarin::android::hash_t java_to_managed_hashes[]; diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 146414e0dc4..8d9ea293736 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -23,13 +23,14 @@ const TypeMap type_map = { }; const TypeMapAssembly type_map_unique_assemblies[] = {}; -const char type_map_assembly_names_blob[] = {}; +const char type_map_assembly_names[] = {}; #else const uint32_t managed_to_java_map_module_count = 0; const uint32_t java_type_count = 0; -const char* const java_type_names[] = {}; -const char* const managed_type_names[] = {}; -const char* const managed_assembly_names[] = {}; +const char java_type_names[] = {}; +const uint64_t java_type_names_size = 0; +const char managed_type_names[] = {}; +const char managed_assembly_names[] = {}; TypeMapModule managed_to_java_map[] = {}; const TypeMapJava java_to_managed_map[] = {}; const xamarin::android::hash_t java_to_managed_hashes[] = {}; From c422e106092d3ee25440637935d13b15a17201ae Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Fri, 25 Apr 2025 18:42:53 +0200 Subject: [PATCH 05/20] Optimize debug maps a bit --- ...eMappingDebugNativeAssemblyGeneratorCLR.cs | 77 +++++++++++++------ src/native/clr/host/typemap.cc | 28 ++++--- src/native/clr/include/host/typemap.hh | 2 +- src/native/clr/include/xamarin-app.hh | 11 ++- .../xamarin-app-stub/application_dso_stub.cc | 3 +- 5 files changed, 82 insertions(+), 39 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index 8f4242ba770..bfa42d40346 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -16,6 +16,8 @@ class TypeMappingDebugNativeAssemblyGeneratorCLR : LlvmIrComposer const string TypeMapSymbol = "type_map"; const string UniqueAssembliesSymbol = "type_map_unique_assemblies"; const string AssemblyNamesBlobSymbol = "type_map_assembly_names"; + const string ManagedTypeNamesBlobSymbol = "type_map_managed_type_names"; + const string JavaTypeNamesBlobSymbol = "type_map_java_type_names"; sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvider { @@ -53,11 +55,11 @@ public override string GetComment (object data, string fieldName) var entry = EnsureType (data); if (String.Compare ("from", fieldName, StringComparison.Ordinal) == 0) { - return $"from: {entry.from}"; + return $"from: {entry.From}"; } if (String.Compare ("to", fieldName, StringComparison.Ordinal) == 0) { - return $"to: {entry.to}"; + return $"to: {entry.To}"; } return String.Empty; @@ -87,11 +89,23 @@ public override string GetComment (object data, string fieldName) [NativeAssemblerStructContextDataProvider (typeof (TypeMapEntryContextDataProvider))] sealed class TypeMapEntry { + [NativeAssembler (Ignore = true)] + public string From; + + [NativeAssembler (Ignore = true)] + public string To; + [NativeAssembler (UsesDataProvider = true)] - public string from; + public uint from; + + [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public ulong from_hash; [NativeAssembler (UsesDataProvider = true)] - public string to; + public uint to; + + [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public ulong to_hash; }; // Order of fields and their type must correspond *exactly* to that in @@ -164,30 +178,45 @@ protected override void Construct (LlvmIrModule module) MapStructures (module); - if (data.ManagedToJavaMap != null && data.ManagedToJavaMap.Count > 0) { - foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.ManagedToJavaMap) { - var m2j = new TypeMapEntry { - from = entry.ManagedName, - to = entry.JavaName, - }; - managedToJavaMap.Add (new StructureInstance (typeMapEntryStructureInfo, m2j)); - } + var managedTypeNames = new LlvmIrStringBlob (); + var javaTypeNames = new LlvmIrStringBlob (); + + // CoreCLR supports only 64-bit targets, so we can make things simpler by hashing all the things here instead of + // in a callback during code generation + foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.ManagedToJavaMap) { + (int managedTypeNameOffset, int _) = managedTypeNames.Add (entry.ManagedName); + (int javaTypeNameOffset, int _) = javaTypeNames.Add (entry.JavaName); + var m2j = new TypeMapEntry { + From = entry.ManagedName, + To = entry.JavaName, + + from = (uint)managedTypeNameOffset, + from_hash = MonoAndroidHelper.GetXxHash (entry.ManagedName, is64Bit: true), + to = (uint)javaTypeNameOffset, + to_hash = MonoAndroidHelper.GetXxHash (entry.JavaName, is64Bit: true), + }; + managedToJavaMap.Add (new StructureInstance (typeMapEntryStructureInfo, m2j)); } + managedToJavaMap.Sort ((StructureInstance a, StructureInstance b) => a.Instance.from_hash.CompareTo (b.Instance.from_hash)); - if (data.JavaToManagedMap != null && data.JavaToManagedMap.Count > 0) { - foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.JavaToManagedMap) { - TypeMapGenerator.TypeMapDebugEntry managedEntry = entry.DuplicateForJavaToManaged != null ? entry.DuplicateForJavaToManaged : entry; + foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.JavaToManagedMap) { + TypeMapGenerator.TypeMapDebugEntry managedEntry = entry.DuplicateForJavaToManaged != null ? entry.DuplicateForJavaToManaged : entry; + (int managedTypeNameOffset, int _) = managedTypeNames.Add (entry.ManagedName); + (int javaTypeNameOffset, int _) = javaTypeNames.Add (entry.JavaName); - var j2m = new TypeMapEntry { - from = entry.JavaName, - to = managedEntry.SkipInJavaToManaged ? null : managedEntry.ManagedName, - }; - javaToManagedMap.Add (new StructureInstance (typeMapEntryStructureInfo, j2m)); - } + var j2m = new TypeMapEntry { + From = entry.JavaName, + To = managedEntry.SkipInJavaToManaged ? String.Empty : entry.ManagedName, + + from = (uint)javaTypeNameOffset, + from_hash = MonoAndroidHelper.GetXxHash (entry.JavaName, is64Bit: true), + to = managedEntry.SkipInJavaToManaged ? uint.MaxValue : (uint)managedTypeNameOffset, + to_hash = managedEntry.SkipInJavaToManaged ? 0 : MonoAndroidHelper.GetXxHash (entry.ManagedName, is64Bit: true), + }; + javaToManagedMap.Add (new StructureInstance (typeMapEntryStructureInfo, j2m)); } + javaToManagedMap.Sort ((StructureInstance a, StructureInstance b) => a.Instance.from_hash.CompareTo (b.Instance.from_hash)); - // CoreCLR supports only 64-bit targets, so we can make things simpler by hashing the MVIDs here instead of - // in a callback during code generation var assemblyNamesBlob = new LlvmIrStringBlob (); foreach (TypeMapGenerator.TypeMapDebugAssembly asm in data.UniqueAssemblies) { (int assemblyNameOffset, int assemblyNameLength) = assemblyNamesBlob.Add (asm.Name); @@ -224,6 +253,8 @@ protected override void Construct (LlvmIrModule module) module.AddGlobalVariable (UniqueAssembliesSymbol, uniqueAssemblies, LlvmIrVariableOptions.GlobalConstant); module.AddGlobalVariable (AssemblyNamesBlobSymbol, assemblyNamesBlob, LlvmIrVariableOptions.GlobalConstant); + module.AddGlobalVariable (ManagedTypeNamesBlobSymbol, managedTypeNames, LlvmIrVariableOptions.GlobalConstant); + module.AddGlobalVariable (JavaTypeNamesBlobSymbol, javaTypeNames, LlvmIrVariableOptions.GlobalConstant); } void MapStructures (LlvmIrModule module) diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 51a1eceed79..e69c3b3215c 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -65,36 +65,40 @@ namespace { #if defined(DEBUG) [[gnu::always_inline]] -auto TypeMapper::typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char* +auto TypeMapper::typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char* { log_debug (LOG_ASSEMBLY, "Looking up {} type '{}'", from_name, optional_string (typeName)); - auto equal = [](TypeMapEntry const& entry, const char *key) -> bool { - if (entry.from == nullptr) { + auto equal = [](TypeMapEntry const& entry, hash_t key) -> bool { + if (entry.from == std::numeric_limits::max ()) { return 1; } - return strcmp (entry.from, key) == 0; + return entry.from_hash == key; }; - auto less_than = [](TypeMapEntry const& entry, const char *key) -> bool { - if (entry.from == nullptr) { + auto less_than = [](TypeMapEntry const& entry, hash_t key) -> bool { + if (entry.from == std::numeric_limits::max ()) { return 1; } - return strcmp (entry.from, key) < 0; + return entry.from_hash < key; }; - ssize_t idx = Search::binary_search (typeName, map, type_map.entry_count); + hash_t type_name_hash = xxhash::hash (typeName, strlen (typeName)); + ssize_t idx = Search::binary_search (type_name_hash, map, type_map.entry_count); if (idx >= 0) [[likely]] { + TypeMapEntry const& entry = map[idx]; + const char *mapped_name = &name_map[entry.to]; + log_debug ( LOG_ASSEMBLY, "{} type '{}' maps to {} type '{}'", from_name, optional_string (typeName), to_name, - optional_string (type_map.managed_to_java[idx].to) + optional_string (mapped_name) ); - return type_map.managed_to_java[idx].to; + return mapped_name; } return nullptr; @@ -126,7 +130,7 @@ auto TypeMapper::typemap_managed_to_java_debug (const char *typeName, const uint log_warn (LOG_ASSEMBLY, "Unable to look up assembly name for type '{}', trying without it.", typeName); } - return typemap_type_to_type_debug (full_type_name.get (), type_map.managed_to_java, MANAGED, JAVA); + return typemap_type_to_type_debug (full_type_name.get (), type_map.managed_to_java, type_map_java_type_names, MANAGED, JAVA); } #endif // def DEBUG @@ -300,7 +304,7 @@ auto TypeMapper::typemap_java_to_managed_debug (const char *java_type_name, char // FIXME: this is currently VERY broken *assembly_name = nullptr; *managed_type_token_id = 0; - return typemap_type_to_type_debug (java_type_name, type_map.java_to_managed, JAVA, MANAGED); + return typemap_type_to_type_debug (java_type_name, type_map.java_to_managed, type_map_managed_type_names, JAVA, MANAGED); } #else // def DEBUG diff --git a/src/native/clr/include/host/typemap.hh b/src/native/clr/include/host/typemap.hh index fa15db569cf..f8a65424ee0 100644 --- a/src/native/clr/include/host/typemap.hh +++ b/src/native/clr/include/host/typemap.hh @@ -27,7 +27,7 @@ namespace xamarin::android { static auto find_java_to_managed_entry (hash_t name_hash) noexcept -> const TypeMapJava*; #else - static auto typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char*; + static auto typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char*; static auto typemap_managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char*; static auto typemap_java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool; #endif diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index e56d345a568..295ceae13ed 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -56,10 +56,15 @@ struct TypeMapIndexHeader uint32_t module_file_name_width; }; +// If any of the members is set to maximum uint32_t value it means the entry is ignored (treated +// as equivalent to `nullptr` if the member was a pointer). The reasoning is that no string could +// begin at this offset (well, an empty string could, but we don't have those here) struct TypeMapEntry { - const char *from; - const char *to; + const uint32_t from; + const xamarin::android::hash_t from_hash; + const uint32_t to; + const xamarin::android::hash_t to_hash; }; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -325,6 +330,8 @@ extern "C" { [[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs [[gnu::visibility("default")]] extern const TypeMapAssembly type_map_unique_assemblies[]; [[gnu::visibility("default")]] extern const char type_map_assembly_names[]; + [[gnu::visibility("default")]] extern const char type_map_managed_type_names[]; + [[gnu::visibility("default")]] extern const char type_map_java_type_names[]; #else [[gnu::visibility("default")]] extern const uint32_t managed_to_java_map_module_count; [[gnu::visibility("default")]] extern const uint32_t java_type_count; diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 8d9ea293736..3ea8bacf25c 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -10,7 +10,6 @@ const uint64_t format_tag = FORMAT_TAG; #if defined (DEBUG) static TypeMapEntry java_to_managed[] = {}; - static TypeMapEntry managed_to_java[] = {}; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs @@ -24,6 +23,8 @@ const TypeMap type_map = { const TypeMapAssembly type_map_unique_assemblies[] = {}; const char type_map_assembly_names[] = {}; +const char type_map_managed_type_names[] = {}; +const char type_map_java_type_names[] = {}; #else const uint32_t managed_to_java_map_module_count = 0; const uint32_t java_type_count = 0; From 2ba659cdb9cb76ebfd407b7d87b073c1bd7d744e Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 28 Apr 2025 14:25:24 +0200 Subject: [PATCH 06/20] Implement fallback matching when hash clashes are detected --- ...eMappingDebugNativeAssemblyGeneratorCLR.cs | 35 ++++-- src/native/clr/host/internal-pinvokes.cc | 4 +- src/native/clr/host/typemap.cc | 116 +++++++++++++----- src/native/clr/include/host/typemap.hh | 12 +- src/native/clr/include/xamarin-app.hh | 2 +- .../xamarin-app-stub/application_dso_stub.cc | 1 + .../common/include/runtime-base/search.hh | 30 ++++- 7 files changed, 147 insertions(+), 53 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index bfa42d40346..0d849221029 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -18,6 +18,7 @@ class TypeMappingDebugNativeAssemblyGeneratorCLR : LlvmIrComposer const string AssemblyNamesBlobSymbol = "type_map_assembly_names"; const string ManagedTypeNamesBlobSymbol = "type_map_managed_type_names"; const string JavaTypeNamesBlobSymbol = "type_map_java_type_names"; + const string TypeMapUsesHashesSymbol = "typemap_use_hashes"; sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvider { @@ -103,9 +104,6 @@ sealed class TypeMapEntry [NativeAssembler (UsesDataProvider = true)] public uint to; - - [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] - public ulong to_hash; }; // Order of fields and their type must correspond *exactly* to that in @@ -183,6 +181,13 @@ protected override void Construct (LlvmIrModule module) // CoreCLR supports only 64-bit targets, so we can make things simpler by hashing all the things here instead of // in a callback during code generation + + // Probability of xxHash clashes on managed type names is very low, it might be hard to find such type names that + // would create collision, so in order to be able to test the string-based managed-to-java typemaps, we check whether + // the `CI_TYPEMAP_DEBUG_USE_STRINGS` environment variable is present and not empty. If it's not in the environment + // or its value is an empty string, we default to using hashes for the managed-to-java type maps. + bool typemap_uses_hashes = String.IsNullOrEmpty (Environment.GetEnvironmentVariable ("CI_TYPEMAP_DEBUG_USE_STRINGS")); + var usedHashes = new Dictionary (); foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.ManagedToJavaMap) { (int managedTypeNameOffset, int _) = managedTypeNames.Add (entry.ManagedName); (int javaTypeNameOffset, int _) = javaTypeNames.Add (entry.JavaName); @@ -193,12 +198,27 @@ protected override void Construct (LlvmIrModule module) from = (uint)managedTypeNameOffset, from_hash = MonoAndroidHelper.GetXxHash (entry.ManagedName, is64Bit: true), to = (uint)javaTypeNameOffset, - to_hash = MonoAndroidHelper.GetXxHash (entry.JavaName, is64Bit: true), }; managedToJavaMap.Add (new StructureInstance (typeMapEntryStructureInfo, m2j)); + + if (usedHashes.ContainsKey (m2j.from_hash)) { + typemap_uses_hashes = false; + // It could be a warning, but it's not really actionable - users might not be able to rename the clashing types + Log.LogMessage ($"Detected xxHash conflict between managed type names '{entry.ManagedName}' and '{usedHashes[m2j.from_hash]}' when mapping to Java type '{entry.JavaName}'."); + } else { + usedHashes[m2j.from_hash] = entry.ManagedName; + } + } + // Input is sorted on name, we need to re-sort it on hashes, if used + if (typemap_uses_hashes) { + managedToJavaMap.Sort ((StructureInstance a, StructureInstance b) => a.Instance.from_hash.CompareTo (b.Instance.from_hash)); + } + + if (!typemap_uses_hashes) { + Log.LogMessage ("Managed-to-java typemaps will use string-based matching."); } - managedToJavaMap.Sort ((StructureInstance a, StructureInstance b) => a.Instance.from_hash.CompareTo (b.Instance.from_hash)); + // Java-to-managed maps don't use hashes since many mappings have multiple instances foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.JavaToManagedMap) { TypeMapGenerator.TypeMapDebugEntry managedEntry = entry.DuplicateForJavaToManaged != null ? entry.DuplicateForJavaToManaged : entry; (int managedTypeNameOffset, int _) = managedTypeNames.Add (entry.ManagedName); @@ -209,13 +229,11 @@ protected override void Construct (LlvmIrModule module) To = managedEntry.SkipInJavaToManaged ? String.Empty : entry.ManagedName, from = (uint)javaTypeNameOffset, - from_hash = MonoAndroidHelper.GetXxHash (entry.JavaName, is64Bit: true), + from_hash = 0, to = managedEntry.SkipInJavaToManaged ? uint.MaxValue : (uint)managedTypeNameOffset, - to_hash = managedEntry.SkipInJavaToManaged ? 0 : MonoAndroidHelper.GetXxHash (entry.ManagedName, is64Bit: true), }; javaToManagedMap.Add (new StructureInstance (typeMapEntryStructureInfo, j2m)); } - javaToManagedMap.Sort ((StructureInstance a, StructureInstance b) => a.Instance.from_hash.CompareTo (b.Instance.from_hash)); var assemblyNamesBlob = new LlvmIrStringBlob (); foreach (TypeMapGenerator.TypeMapDebugAssembly asm in data.UniqueAssemblies) { @@ -251,6 +269,7 @@ protected override void Construct (LlvmIrModule module) module.AddGlobalVariable (JavaToManagedSymbol, javaToManagedMap, LlvmIrVariableOptions.LocalConstant); } + module.AddGlobalVariable (TypeMapUsesHashesSymbol, typemap_uses_hashes, LlvmIrVariableOptions.GlobalConstant); module.AddGlobalVariable (UniqueAssembliesSymbol, uniqueAssemblies, LlvmIrVariableOptions.GlobalConstant); module.AddGlobalVariable (AssemblyNamesBlobSymbol, assemblyNamesBlob, LlvmIrVariableOptions.GlobalConstant); module.AddGlobalVariable (ManagedTypeNamesBlobSymbol, managedTypeNames, LlvmIrVariableOptions.GlobalConstant); diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index a6b8c8f4880..6f0a62b3002 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -28,13 +28,13 @@ void _monodroid_gref_log_delete (jobject handle, char type, const char *threadNa const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept { - return TypeMapper::typemap_managed_to_java (typeName, mvid); + return TypeMapper::managed_to_java (typeName, mvid); } bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept { log_debug (LOG_ASSEMBLY, __PRETTY_FUNCTION__); - return TypeMapper::typemap_java_to_managed (java_type_name, assembly_name, managed_type_token_id); + return TypeMapper::java_to_managed (java_type_name, assembly_name, managed_type_token_id); } void monodroid_log (LogLevel level, LogCategories category, const char *message) noexcept diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index e69c3b3215c..c144e80c19c 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -64,12 +64,43 @@ namespace { } #if defined(DEBUG) -[[gnu::always_inline]] -auto TypeMapper::typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char* +[[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); + + auto equal = [](TypeMapEntry const& entry, const char *key, const char (&name_map)[]) -> bool { + if (entry.from == std::numeric_limits::max ()) [[unlikely]] { + return 1; + } + + const char *type_name = &name_map[entry.from]; + return strcmp (type_name, key) == 0; + }; + + auto less_than = [](TypeMapEntry const& entry, const char *key, const char (&name_map)[]) -> bool { + if (entry.from == std::numeric_limits::max ()) [[unlikely]] { + return 1; + } + + const char *type_name = &name_map[entry.from]; + return strcmp (type_name, key) < 0; + }; + + return Search::binary_search (name_map, typeName, map, type_map.entry_count); +} + +[[gnu::always_inline, gnu::flatten]] +auto TypeMapper::find_index_by_hash (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> ssize_t { - log_debug (LOG_ASSEMBLY, "Looking up {} type '{}'", from_name, optional_string (typeName)); + if (!typemap_use_hashes) [[unlikely]] { + return find_index_by_name (typeName, map, name_map, from_name, to_name); + } + + log_debug (LOG_ASSEMBLY, "typemap: map {} -> {} uses hashes", from_name, to_name); + auto equal = [](TypeMapEntry const& entry, hash_t key) -> bool { - if (entry.from == std::numeric_limits::max ()) { + if (entry.from == std::numeric_limits::max ()) [[unlikely]] { return 1; } @@ -77,35 +108,40 @@ auto TypeMapper::typemap_type_to_type_debug (const char *typeName, const TypeMap }; auto less_than = [](TypeMapEntry const& entry, hash_t key) -> bool { - if (entry.from == std::numeric_limits::max ()) { + if (entry.from == std::numeric_limits::max ()) [[unlikely]] { return 1; } return entry.from_hash < key; }; - hash_t type_name_hash = xxhash::hash (typeName, strlen (typeName)); - ssize_t idx = Search::binary_search (type_name_hash, map, type_map.entry_count); - if (idx >= 0) [[likely]] { - TypeMapEntry const& entry = map[idx]; - const char *mapped_name = &name_map[entry.to]; + return Search::binary_search (type_name_hash, map, type_map.entry_count); +} - log_debug ( - LOG_ASSEMBLY, - "{} type '{}' maps to {} type '{}'", - from_name, - optional_string (typeName), - to_name, - optional_string (mapped_name) - ); - return mapped_name; +[[gnu::always_inline, gnu::flatten]] +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", from_name, typeName, to_name); + return nullptr; } - return nullptr; + TypeMapEntry const& entry = map[idx]; + const char *mapped_name = &name_map[entry.to]; + + log_debug ( + LOG_ASSEMBLY, + "typemap: {} type '{}' maps to {} type '{}'", + from_name, + optional_string (typeName), + to_name, + optional_string (mapped_name) + ); + return mapped_name; } -[[gnu::always_inline]] -auto TypeMapper::typemap_managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char* +[[gnu::always_inline, gnu::flatten]] +auto TypeMapper::managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char* { dynamic_local_path_string full_type_name; full_type_name.append (typeName); @@ -122,15 +158,20 @@ auto TypeMapper::typemap_managed_to_java_debug (const char *typeName, const uint if (assm.name_offset < type_map.assembly_names_blob_size) [[likely]] { full_type_name.append (&type_map_assembly_names[assm.name_offset], assm.name_length); - log_debug (LOG_ASSEMBLY, "Fixed-up type name: '{}'", full_type_name.get ()); + log_debug (LOG_ASSEMBLY, "typemap: fixed-up type name: '{}'", full_type_name.get ()); } else { - log_warn (LOG_ASSEMBLY, "Invalid assembly name offset {}", assm.name_offset); + log_warn (LOG_ASSEMBLY, "typemap: fnvalid assembly name offset {}", assm.name_offset); } } else { - log_warn (LOG_ASSEMBLY, "Unable to look up assembly name for type '{}', trying without it.", typeName); + log_warn (LOG_ASSEMBLY, "typemap: unable to look up assembly name for type '{}', trying without it.", typeName); } - return typemap_type_to_type_debug (full_type_name.get (), type_map.managed_to_java, type_map_java_type_names, MANAGED, JAVA); + // If hashes are used for matching, the type names array is not used. If, however, string-based matching is in + // effect, the managed type name is looked up and then... + idx = find_index_by_hash (full_type_name.get (), type_map.managed_to_java, type_map_managed_type_names, MANAGED, JAVA); + + // ...either method gives us index into the Java type names array + return index_to_name (idx, full_type_name.get (), type_map.managed_to_java, type_map_java_type_names, MANAGED, JAVA); } #endif // def DEBUG @@ -271,7 +312,7 @@ auto TypeMapper::typemap_managed_to_java_release (const char *typeName, const ui #endif // def RELEASE [[gnu::flatten]] -auto TypeMapper::typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char* +auto TypeMapper::managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char* { log_debug (LOG_ASSEMBLY, "typemap_managed_to_java: looking up type '{}'", optional_string (typeName)); if (FastTiming::enabled ()) [[unlikely]] { @@ -283,12 +324,14 @@ auto TypeMapper::typemap_managed_to_java (const char *typeName, const uint8_t *m return nullptr; } - const char *ret = nullptr; + auto do_map = [&typeName, &mvid]() -> const char* { #if defined(RELEASE) - ret = typemap_managed_to_java_release (typeName, mvid); + return typemap_managed_to_java_release (typeName, mvid); #else - ret = typemap_managed_to_java_debug (typeName, mvid); + return managed_to_java_debug (typeName, mvid); #endif + }; + const char *ret = do_map (); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.end_event (); @@ -299,12 +342,17 @@ auto TypeMapper::typemap_managed_to_java (const char *typeName, const uint8_t *m #if defined(DEBUG) [[gnu::flatten]] -auto TypeMapper::typemap_java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool +auto TypeMapper::java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { // FIXME: this is currently VERY broken *assembly_name = nullptr; *managed_type_token_id = 0; - return typemap_type_to_type_debug (java_type_name, type_map.java_to_managed, type_map_managed_type_names, JAVA, MANAGED); + + // We need to find entry matching the Java type name, which will then... + ssize_t idx = find_index_by_name (java_type_name, type_map.java_to_managed, type_map_java_type_names, JAVA, MANAGED); + + // ..provide us with the managed type name index + return index_to_name (idx, java_type_name, type_map.java_to_managed, type_map_managed_type_names, JAVA, MANAGED); } #else // def DEBUG @@ -384,7 +432,7 @@ auto TypeMapper::typemap_java_to_managed_release (const char *java_type_name, ch #endif // ndef DEBUG [[gnu::flatten]] -auto TypeMapper::typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool +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, "typemap_java_to_managed: looking up type '{}'", optional_string (java_type_name)); if (FastTiming::enabled ()) [[unlikely]] { @@ -400,7 +448,7 @@ auto TypeMapper::typemap_java_to_managed (const char *java_type_name, char const #if defined(RELEASE) ret = typemap_java_to_managed_release (java_type_name, assembly_name, managed_type_token_id); #else - ret = typemap_java_to_managed_debug (java_type_name, assembly_name, managed_type_token_id); + ret = java_to_managed_debug (java_type_name, assembly_name, managed_type_token_id); #endif if (FastTiming::enabled ()) [[unlikely]] { diff --git a/src/native/clr/include/host/typemap.hh b/src/native/clr/include/host/typemap.hh index f8a65424ee0..99f6bc4191a 100644 --- a/src/native/clr/include/host/typemap.hh +++ b/src/native/clr/include/host/typemap.hh @@ -14,8 +14,8 @@ namespace xamarin::android { static constexpr std::string_view JAVA { "Java" }; public: - static auto typemap_managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char*; - static auto typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool; + static auto managed_to_java (const char *typeName, const uint8_t *mvid) noexcept -> const char*; + static auto java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool; private: #if defined(RELEASE) @@ -27,9 +27,11 @@ namespace xamarin::android { static auto find_java_to_managed_entry (hash_t name_hash) noexcept -> const TypeMapJava*; #else - static auto typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char*; - static auto typemap_managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char*; - static auto typemap_java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool; + static auto index_to_name (ssize_t index, const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) -> const char*; + static auto find_index_by_hash (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> ssize_t; + static auto 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; + static auto managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char*; + static auto java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool; #endif }; } diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index 295ceae13ed..fa12aa5d67c 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -64,7 +64,6 @@ struct TypeMapEntry const uint32_t from; const xamarin::android::hash_t from_hash; const uint32_t to; - const xamarin::android::hash_t to_hash; }; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -327,6 +326,7 @@ extern "C" { [[gnu::visibility("default")]] extern const uint64_t format_tag; #if defined (DEBUG) + [[gnu::visibility("default")]] extern const bool typemap_use_hashes; [[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs [[gnu::visibility("default")]] extern const TypeMapAssembly type_map_unique_assemblies[]; [[gnu::visibility("default")]] extern const char type_map_assembly_names[]; diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 3ea8bacf25c..893fd46ef0a 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -21,6 +21,7 @@ const TypeMap type_map = { .managed_to_java = managed_to_java, }; +const bool typemap_use_hashes = true; const TypeMapAssembly type_map_unique_assemblies[] = {}; const char type_map_assembly_names[] = {}; const char type_map_managed_type_names[] = {}; diff --git a/src/native/common/include/runtime-base/search.hh b/src/native/common/include/runtime-base/search.hh index 4c789b1bffc..855bac976b0 100644 --- a/src/native/common/include/runtime-base/search.hh +++ b/src/native/common/include/runtime-base/search.hh @@ -9,8 +9,32 @@ namespace xamarin::android { class Search final { public: + // Code duplication in the two functions below is lamentable, but avoiding it would require + // making the code much uglier (and harder to read) with meta programming tricks, just not worth it. + template + [[gnu::always_inline, gnu::flatten]] + static ssize_t binary_search (const TState& state, TKey key, const T *arr, size_t n) noexcept + { + static_assert (equal != nullptr, "equal is a required template parameter"); + static_assert (less_than != nullptr, "less_than is a required template parameter"); + + ssize_t left = -1z; + ssize_t right = static_cast(n); + + while (right - left > 1) { + ssize_t middle = (left + right) >> 1u; + if (less_than (arr[middle], key, state)) { + left = middle; + } else { + right = middle; + } + } + + return equal (arr[right], key, state) ? right : -1z; + } + template - [[gnu::always_inline]] + [[gnu::always_inline, gnu::flatten]] static ssize_t binary_search (TKey key, const T *arr, size_t n) noexcept { static_assert (equal != nullptr, "equal is a required template parameter"); @@ -32,13 +56,13 @@ namespace xamarin::android { } template - [[gnu::always_inline]] + [[gnu::always_inline, gnu::flatten]] static ssize_t binary_search (hash_t key, const T *arr, size_t n) noexcept { return binary_search (key, arr, n); } - [[gnu::always_inline]] + [[gnu::always_inline, gnu::flatten]] static ssize_t binary_search (hash_t key, const hash_t *arr, size_t n) noexcept { auto equal = [](hash_t const& entry, hash_t key) -> bool { return entry == key; }; From a45e495b37eda59a1287e536165610151ebb9e6c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 28 Apr 2025 15:27:01 +0200 Subject: [PATCH 07/20] java-to-managed map should be fully functional now --- .../LlvmIrGenerator/LlvmIrStringBlob.cs | 13 +++ .../Utilities/TypeMapCecilAdapter.cs | 1 + .../Utilities/TypeMapGenerator.cs | 1 + ...eMappingDebugNativeAssemblyGeneratorCLR.cs | 83 ++++++++++++++----- src/native/clr/host/typemap.cc | 29 ++++++- src/native/clr/include/xamarin-app.hh | 11 +++ .../xamarin-app-stub/application_dso_stub.cc | 1 + 7 files changed, 114 insertions(+), 25 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs index 0f74ecc8d1c..410efcdcb4d 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/LlvmIrGenerator/LlvmIrStringBlob.cs @@ -54,6 +54,19 @@ public record struct StringInfo (int Offset, int Length, byte[] Bytes, string Va return (info.Offset, info.Length); } + public int GetIndexOf (string s) + { + if (String.IsNullOrEmpty (s)) { + return -1; + } + + if (!cache.TryGetValue (s, out StringInfo info)) { + return -1; + } + + return info.Offset; + } + public IEnumerable GetSegments () { foreach (StringInfo si in segments) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs index 331adda506d..b9d991d083b 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs @@ -149,6 +149,7 @@ static TypeMapDebugEntry GetDebugEntry (TypeDefinition td, TypeDefinitionCache c ManagedName = GetManagedTypeName (td), TypeDefinition = td, SkipInJavaToManaged = ShouldSkipInJavaToManaged (td), + AssemblyName = td.Module.Assembly.Name.Name, }; } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs index 6cd0c3203b8..f1a92d50112 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs @@ -64,6 +64,7 @@ internal sealed class TypeMapDebugEntry public string ManagedName; public bool SkipInJavaToManaged; public TypeMapDebugEntry DuplicateForJavaToManaged; + public string AssemblyName; // This field is only used by the Cecil adapter for temp storage while reading. // It is not used to create the typemap. diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index 0d849221029..f499f0afaef 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -19,6 +19,7 @@ class TypeMappingDebugNativeAssemblyGeneratorCLR : LlvmIrComposer const string ManagedTypeNamesBlobSymbol = "type_map_managed_type_names"; const string JavaTypeNamesBlobSymbol = "type_map_java_type_names"; const string TypeMapUsesHashesSymbol = "typemap_use_hashes"; + const string TypeMapManagedTypeInfoSymbol = "type_map_managed_type_info"; sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvider { @@ -85,6 +86,20 @@ public override string GetComment (object data, string fieldName) } } + sealed class TypeMapManagedTypeInfoContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override string GetComment (object data, string fieldName) + { + var entry = EnsureType (data); + + if (String.Compare ("assembly_name_index", fieldName, StringComparison.Ordinal) == 0) { + return $" '{entry.AssemblyName}'"; + } + + return String.Empty; + } + } + // Order of fields and their type must correspond *exactly* to that in // src/native/clr/include/xamarin-app.hh TypeMapEntry structure [NativeAssemblerStructContextDataProvider (typeof (TypeMapEntryContextDataProvider))] @@ -106,6 +121,21 @@ sealed class TypeMapEntry public uint to; }; + // Order of fields and their type must correspond *exactly* to that in + // src/native/clr/include/xamarin-app.hh TypeMapManagedTypeInfo structure + [NativeAssemblerStructContextDataProvider (typeof (TypeMapManagedTypeInfoContextDataProvider))] + sealed class TypeMapManagedTypeInfo + { + [NativeAssembler (Ignore = true)] + public string AssemblyName; + + [NativeAssembler (UsesDataProvider = true)] + public uint assembly_name_index; + + [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public uint managed_type_token_id; + }; + // Order of fields and their type must correspond *exactly* to that in // src/native/clr/include/xamarin-app.hh TypeMap structure [NativeAssemblerStructContextDataProvider (typeof (TypeMapContextDataProvider))] @@ -151,9 +181,11 @@ sealed class TypeMapAssembly StructureInfo typeMapEntryStructureInfo; StructureInfo typeMapStructureInfo; StructureInfo typeMapAssemblyStructureInfo; + StructureInfo typeMapManagedTypeInfoStructureInfo; List> javaToManagedMap; List> managedToJavaMap; List> uniqueAssemblies; + List> managedTypeInfos; StructureInstance type_map; public TypeMappingDebugNativeAssemblyGeneratorCLR (TaskLoggingHelper log, TypeMapGenerator.ModuleDebugData data) @@ -218,6 +250,22 @@ protected override void Construct (LlvmIrModule module) Log.LogMessage ("Managed-to-java typemaps will use string-based matching."); } + var assemblyNamesBlob = new LlvmIrStringBlob (); + foreach (TypeMapGenerator.TypeMapDebugAssembly asm in data.UniqueAssemblies) { + (int assemblyNameOffset, int assemblyNameLength) = assemblyNamesBlob.Add (asm.Name); + var entry = new TypeMapAssembly { + Name = asm.Name, + MVID = asm.MVID, + + mvid_hash = MonoAndroidHelper.GetXxHash (asm.MVIDBytes, is64Bit: true), + name_length = (ulong)assemblyNameLength, // without the trailing NUL + name_offset = (ulong)assemblyNameOffset, + }; + uniqueAssemblies.Add (new StructureInstance (typeMapAssemblyStructureInfo, entry)); + } + uniqueAssemblies.Sort ((StructureInstance a, StructureInstance b) => a.Instance.mvid_hash.CompareTo (b.Instance.mvid_hash)); + + var managedTypeInfos = new List> (); // Java-to-managed maps don't use hashes since many mappings have multiple instances foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.JavaToManagedMap) { TypeMapGenerator.TypeMapDebugEntry managedEntry = entry.DuplicateForJavaToManaged != null ? entry.DuplicateForJavaToManaged : entry; @@ -233,22 +281,20 @@ protected override void Construct (LlvmIrModule module) to = managedEntry.SkipInJavaToManaged ? uint.MaxValue : (uint)managedTypeNameOffset, }; javaToManagedMap.Add (new StructureInstance (typeMapEntryStructureInfo, j2m)); - } - var assemblyNamesBlob = new LlvmIrStringBlob (); - foreach (TypeMapGenerator.TypeMapDebugAssembly asm in data.UniqueAssemblies) { - (int assemblyNameOffset, int assemblyNameLength) = assemblyNamesBlob.Add (asm.Name); - var entry = new TypeMapAssembly { - Name = asm.Name, - MVID = asm.MVID, + int assemblyNameOffset = assemblyNamesBlob.GetIndexOf (entry.AssemblyName); + if (assemblyNameOffset < 0) { + throw new InvalidOperationException ($"Internal error: assembly name '{entry.AssemblyName}' not found in the assembly names blob."); + } - mvid_hash = MonoAndroidHelper.GetXxHash (asm.MVIDBytes, is64Bit: true), - name_length = (ulong)assemblyNameLength, // without the trailing NUL - name_offset = (ulong)assemblyNameOffset, + var typeInfo = new TypeMapManagedTypeInfo { + AssemblyName = entry.AssemblyName, + + assembly_name_index = (uint)assemblyNameOffset, + managed_type_token_id = entry.TypeDefinition.MetadataToken.ToUInt32 (), }; - uniqueAssemblies.Add (new StructureInstance (typeMapAssemblyStructureInfo, entry)); + managedTypeInfos.Add (new StructureInstance (typeMapManagedTypeInfoStructureInfo, typeInfo)); } - uniqueAssemblies.Sort ((StructureInstance a, StructureInstance b) => a.Instance.mvid_hash.CompareTo (b.Instance.mvid_hash)); var map = new TypeMap { JavaToManagedCount = data.JavaToManagedMap == null ? 0 : data.JavaToManagedMap.Count, @@ -260,15 +306,9 @@ protected override void Construct (LlvmIrModule module) }; type_map = new StructureInstance (typeMapStructureInfo, map); module.AddGlobalVariable (TypeMapSymbol, type_map, LlvmIrVariableOptions.GlobalConstant); - - if (managedToJavaMap.Count > 0) { - module.AddGlobalVariable (ManagedToJavaSymbol, managedToJavaMap, LlvmIrVariableOptions.LocalConstant); - } - - if (javaToManagedMap.Count > 0) { - module.AddGlobalVariable (JavaToManagedSymbol, javaToManagedMap, LlvmIrVariableOptions.LocalConstant); - } - + module.AddGlobalVariable (ManagedToJavaSymbol, managedToJavaMap, LlvmIrVariableOptions.LocalConstant); + module.AddGlobalVariable (JavaToManagedSymbol, javaToManagedMap, LlvmIrVariableOptions.LocalConstant); + module.AddGlobalVariable (TypeMapManagedTypeInfoSymbol, managedTypeInfos, LlvmIrVariableOptions.GlobalConstant); module.AddGlobalVariable (TypeMapUsesHashesSymbol, typemap_uses_hashes, LlvmIrVariableOptions.GlobalConstant); module.AddGlobalVariable (UniqueAssembliesSymbol, uniqueAssemblies, LlvmIrVariableOptions.GlobalConstant); module.AddGlobalVariable (AssemblyNamesBlobSymbol, assemblyNamesBlob, LlvmIrVariableOptions.GlobalConstant); @@ -281,5 +321,6 @@ void MapStructures (LlvmIrModule module) typeMapAssemblyStructureInfo = module.MapStructure (); typeMapEntryStructureInfo = module.MapStructure (); typeMapStructureInfo = module.MapStructure (); + typeMapManagedTypeInfoStructureInfo = module.MapStructure (); } } diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index c144e80c19c..da9ee192b4c 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -344,15 +344,36 @@ auto TypeMapper::managed_to_java (const char *typeName, const uint8_t *mvid) noe [[gnu::flatten]] auto TypeMapper::java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { - // FIXME: this is currently VERY broken - *assembly_name = nullptr; - *managed_type_token_id = 0; + if (assembly_name == nullptr || managed_type_token_id == nullptr) [[unlikely]] { + log_warn (LOG_ASSEMBLY, "Managed land called java-to-managed mapping function with invalid pointers"); + return false; + } // We need to find entry matching the Java type name, which will then... ssize_t idx = find_index_by_name (java_type_name, type_map.java_to_managed, type_map_java_type_names, JAVA, MANAGED); // ..provide us with the managed type name index - return index_to_name (idx, java_type_name, type_map.java_to_managed, type_map_managed_type_names, JAVA, MANAGED); + const char *name = index_to_name (idx, java_type_name, type_map.java_to_managed, type_map_managed_type_names, JAVA, MANAGED); + if (name == nullptr) { + *assembly_name = nullptr; + *managed_type_token_id = 0; + return false; + } + + TypeMapManagedTypeInfo const& type_info = type_map_managed_type_info[idx]; + *assembly_name = &type_map_assembly_names[type_info.assembly_name_index]; + *managed_type_token_id = type_info.managed_type_token_id; + + log_debug ( + LOG_ASSEMBLY, + "Mapped Java type '{}' to managed type '{}' in assembly '{}' and with token '{:x}'", + optional_string (java_type_name), + name, + *assembly_name, + *managed_type_token_id + ); + + return true; } #else // def DEBUG diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index fa12aa5d67c..ab97fe94e1b 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -56,6 +56,8 @@ struct TypeMapIndexHeader uint32_t module_file_name_width; }; +// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +// // If any of the members is set to maximum uint32_t value it means the entry is ignored (treated // as equivalent to `nullptr` if the member was a pointer). The reasoning is that no string could // begin at this offset (well, an empty string could, but we don't have those here) @@ -66,6 +68,13 @@ struct TypeMapEntry const uint32_t to; }; +// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +struct TypeMapManagedTypeInfo +{ + const uint32_t assembly_name_index; + const uint32_t managed_type_token_id; +}; + // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs struct TypeMap { @@ -76,6 +85,7 @@ struct TypeMap const TypeMapEntry *managed_to_java; }; +// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs struct TypeMapAssembly { xamarin::android::hash_t mvid_hash; @@ -328,6 +338,7 @@ extern "C" { #if defined (DEBUG) [[gnu::visibility("default")]] extern const bool typemap_use_hashes; [[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs + [[gnu::visibility("default")]] extern const TypeMapManagedTypeInfo type_map_managed_type_info[]; [[gnu::visibility("default")]] extern const TypeMapAssembly type_map_unique_assemblies[]; [[gnu::visibility("default")]] extern const char type_map_assembly_names[]; [[gnu::visibility("default")]] extern const char type_map_managed_type_names[]; diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 893fd46ef0a..61d2eb72131 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -22,6 +22,7 @@ const TypeMap type_map = { }; const bool typemap_use_hashes = true; +const TypeMapManagedTypeInfo type_map_managed_type_info[] = {}; const TypeMapAssembly type_map_unique_assemblies[] = {}; const char type_map_assembly_names[] = {}; const char type_map_managed_type_names[] = {}; From 31cc431a7a381218173a9d6656ad3f7265894e57 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 29 Apr 2025 10:57:56 +0200 Subject: [PATCH 08/20] A handful of tweaks for the Debug build --- .../Utilities/TypeMapCecilAdapter.cs | 1 + .../Utilities/TypeMapGenerator.cs | 1 + ...eMappingDebugNativeAssemblyGeneratorCLR.cs | 25 +++++++++++++------ src/native/clr/host/typemap.cc | 9 +++---- src/native/clr/include/xamarin-app.hh | 1 - .../xamarin-app-stub/application_dso_stub.cc | 1 - 6 files changed, 23 insertions(+), 15 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs index b9d991d083b..ab8288ff33c 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs @@ -147,6 +147,7 @@ static TypeMapDebugEntry GetDebugEntry (TypeDefinition td, TypeDefinitionCache c return new TypeMapDebugEntry { JavaName = Java.Interop.Tools.TypeNameMappings.JavaNativeTypeManager.ToJniName (td, cache), ManagedName = GetManagedTypeName (td), + ManagedTypeTokenId = td.MetadataToken.ToUInt32 (), TypeDefinition = td, SkipInJavaToManaged = ShouldSkipInJavaToManaged (td), AssemblyName = td.Module.Assembly.Name.Name, diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs index f1a92d50112..3183f49154b 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs @@ -62,6 +62,7 @@ internal sealed class TypeMapDebugEntry { public string JavaName; public string ManagedName; + public uint ManagedTypeTokenId; public bool SkipInJavaToManaged; public TypeMapDebugEntry DuplicateForJavaToManaged; public string AssemblyName; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index f499f0afaef..83e2fc064e7 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -57,11 +57,11 @@ public override string GetComment (object data, string fieldName) var entry = EnsureType (data); if (String.Compare ("from", fieldName, StringComparison.Ordinal) == 0) { - return $"from: {entry.From}"; + return $" from: '{entry.From}'"; } if (String.Compare ("to", fieldName, StringComparison.Ordinal) == 0) { - return $"to: {entry.To}"; + return $" to: '{entry.To}'"; } return String.Empty; @@ -96,6 +96,10 @@ public override string GetComment (object data, string fieldName) return $" '{entry.AssemblyName}'"; } + if (String.Compare ("managed_type_token_id", fieldName, StringComparison.Ordinal) == 0) { + return $" '{entry.ManagedTypeName}'"; + } + return String.Empty; } } @@ -129,10 +133,13 @@ sealed class TypeMapManagedTypeInfo [NativeAssembler (Ignore = true)] public string AssemblyName; + [NativeAssembler (Ignore = true)] + public string ManagedTypeName; + [NativeAssembler (UsesDataProvider = true)] public uint assembly_name_index; - [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + [NativeAssembler (UsesDataProvider = true, NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] public uint managed_type_token_id; }; @@ -149,7 +156,6 @@ sealed class TypeMap public uint entry_count; public ulong unique_assemblies_count; - public ulong assembly_names_blob_size; [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToSymbol = "")] public TypeMapEntry? java_to_managed = null; @@ -228,11 +234,15 @@ protected override void Construct (LlvmIrModule module) To = entry.JavaName, from = (uint)managedTypeNameOffset, - from_hash = MonoAndroidHelper.GetXxHash (entry.ManagedName, is64Bit: true), + from_hash = typemap_uses_hashes ? MonoAndroidHelper.GetXxHash (entry.ManagedName, is64Bit: true) : 0, to = (uint)javaTypeNameOffset, }; managedToJavaMap.Add (new StructureInstance (typeMapEntryStructureInfo, m2j)); + if (!typemap_uses_hashes) { + continue; + } + if (usedHashes.ContainsKey (m2j.from_hash)) { typemap_uses_hashes = false; // It could be a warning, but it's not really actionable - users might not be able to rename the clashing types @@ -289,9 +299,10 @@ protected override void Construct (LlvmIrModule module) var typeInfo = new TypeMapManagedTypeInfo { AssemblyName = entry.AssemblyName, + ManagedTypeName = entry.ManagedName, assembly_name_index = (uint)assemblyNameOffset, - managed_type_token_id = entry.TypeDefinition.MetadataToken.ToUInt32 (), + managed_type_token_id = entry.ManagedTypeTokenId, }; managedTypeInfos.Add (new StructureInstance (typeMapManagedTypeInfoStructureInfo, typeInfo)); } @@ -302,9 +313,9 @@ protected override void Construct (LlvmIrModule module) entry_count = data.EntryCount, unique_assemblies_count = (ulong)data.UniqueAssemblies.Count, - assembly_names_blob_size = (ulong)assemblyNamesBlob.Size, }; type_map = new StructureInstance (typeMapStructureInfo, map); + module.AddGlobalVariable (TypeMapSymbol, type_map, LlvmIrVariableOptions.GlobalConstant); module.AddGlobalVariable (ManagedToJavaSymbol, managedToJavaMap, LlvmIrVariableOptions.LocalConstant); module.AddGlobalVariable (JavaToManagedSymbol, javaToManagedMap, LlvmIrVariableOptions.LocalConstant); diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index da9ee192b4c..04ed84a27ff 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -156,12 +156,8 @@ auto TypeMapper::managed_to_java_debug (const char *typeName, const uint8_t *mvi TypeMapAssembly const& assm = type_map_unique_assemblies[idx]; full_type_name.append (", "sv); - if (assm.name_offset < type_map.assembly_names_blob_size) [[likely]] { - full_type_name.append (&type_map_assembly_names[assm.name_offset], assm.name_length); - log_debug (LOG_ASSEMBLY, "typemap: fixed-up type name: '{}'", full_type_name.get ()); - } else { - log_warn (LOG_ASSEMBLY, "typemap: fnvalid assembly name offset {}", assm.name_offset); - } + // 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.", typeName); } @@ -360,6 +356,7 @@ auto TypeMapper::java_to_managed_debug (const char *java_type_name, char const** return false; } + // We explicitly trust the build process here, with regards to the size of the arrays TypeMapManagedTypeInfo const& type_info = type_map_managed_type_info[idx]; *assembly_name = &type_map_assembly_names[type_info.assembly_name_index]; *managed_type_token_id = type_info.managed_type_token_id; diff --git a/src/native/clr/include/xamarin-app.hh b/src/native/clr/include/xamarin-app.hh index ab97fe94e1b..8caa09323d4 100644 --- a/src/native/clr/include/xamarin-app.hh +++ b/src/native/clr/include/xamarin-app.hh @@ -80,7 +80,6 @@ struct TypeMap { uint32_t entry_count; uint64_t unique_assemblies_count; - uint64_t assembly_names_blob_size; const TypeMapEntry *java_to_managed; const TypeMapEntry *managed_to_java; }; diff --git a/src/native/clr/xamarin-app-stub/application_dso_stub.cc b/src/native/clr/xamarin-app-stub/application_dso_stub.cc index 61d2eb72131..7919083ef1f 100644 --- a/src/native/clr/xamarin-app-stub/application_dso_stub.cc +++ b/src/native/clr/xamarin-app-stub/application_dso_stub.cc @@ -16,7 +16,6 @@ static TypeMapEntry managed_to_java[] = {}; const TypeMap type_map = { .entry_count = 0, .unique_assemblies_count = 0, - .assembly_names_blob_size = 0, .java_to_managed = java_to_managed, .managed_to_java = managed_to_java, }; From 130cbac020719acf3e2f1f9a012b6660d5995490 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 29 Apr 2025 11:07:53 +0200 Subject: [PATCH 09/20] Cleanup --- src/Mono.Android/Android.Runtime/AndroidRuntime.cs | 2 -- src/Mono.Android/Java.Interop/TypeManager.cs | 3 --- .../Utilities/TypeMappingDebugNativeAssemblyGenerator.cs | 4 ++-- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs index ec0f0891c86..3f6d8f86cf2 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs @@ -265,11 +265,9 @@ public AndroidTypeManager (bool jniAddNativeMethodRegistrationAttributePresent) protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) { - RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"#1 GetTypesForSimpleReference (\"{jniSimpleReference}\")"); foreach (var ti in base.GetTypesForSimpleReference (jniSimpleReference)) yield return ti; - RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"#2 GetTypesForSimpleReference (\"{jniSimpleReference}\")"); var t = Java.Interop.TypeManager.GetJavaToManagedType (jniSimpleReference); if (t != null) yield return t; diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index e526c52bd39..adc07f0edb1 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -131,7 +131,6 @@ static Type[] GetParameterTypes (string? signature) [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type.GetType() can never statically know the string value from parameter 'typename_ptr'.")] static void n_Activate (IntPtr jnienv, IntPtr jclass, IntPtr typename_ptr, IntPtr signature_ptr, IntPtr jobject, IntPtr parameters_ptr) { - RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"TypeManager.n_Activate"); if (!global::Java.Interop.JniEnvironment.BeginMarshalMethod (jnienv, out var __envp, out var __r)) return; @@ -254,7 +253,6 @@ static Type monovm_typemap_java_to_managed (string java_type_name) internal static Type? GetJavaToManagedType (string class_name) { - RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"TypeManager.GetJavaToManagedType (\"{class_name}\")"); Type? type = JNIEnvInit.RuntimeType switch { DotNetRuntimeType.MonoVM => monovm_typemap_java_to_managed (class_name), DotNetRuntimeType.CoreCLR => clr_typemap_java_to_managed (class_name), @@ -283,7 +281,6 @@ static Type monovm_typemap_java_to_managed (string java_type_name) [UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "TypeManager.CreateProxy() does not statically know the value of the 'type' local variable.")] internal static IJavaPeerable? CreateInstance (IntPtr handle, JniHandleOwnership transfer, Type? targetType) { - RuntimeNativeMethods.monodroid_log (LogLevel.Warn, LogCategories.Default, $"TypeManager.CreateInstance ()"); Type? type = null; IntPtr class_ptr = JNIEnv.GetObjectClass (handle); string? class_name = GetClassName (class_ptr); diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs index 60e52b0e06d..5613bb6263f 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs @@ -66,11 +66,11 @@ public override string GetComment (object data, string fieldName) var entry = EnsureType (data); if (String.Compare ("from", fieldName, StringComparison.Ordinal) == 0) { - return $"from: {entry.from}"; + return $" from: {entry.from}"; } if (String.Compare ("to", fieldName, StringComparison.Ordinal) == 0) { - return $"to: {entry.to}"; + return $" to: {entry.to}"; } return String.Empty; From 0471ffec4090baa2e59978417e56273d2d2df67c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 29 Apr 2025 11:40:26 +0200 Subject: [PATCH 10/20] Add on-device test for string-based typemaps --- .../Utilities/DeviceTest.cs | 5 +-- .../Tests/InstallAndRunTests.cs | 31 ++++++++++++++++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs index a6dec7fe137..d5744ce96d4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/DeviceTest.cs @@ -1,6 +1,7 @@ using NUnit.Framework; using NUnit.Framework.Interfaces; using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Diagnostics; @@ -207,10 +208,10 @@ protected static string AdbStartActivity (string activity) return RunAdbCommand ($"shell am start -S -n \"{activity}\""); } - protected static void RunProjectAndAssert (XamarinAndroidApplicationProject proj, ProjectBuilder builder, string logName = "run.log", bool doNotCleanupOnUpdate = false, string [] parameters = null) + protected static void RunProjectAndAssert (XamarinAndroidApplicationProject proj, ProjectBuilder builder, string logName = "run.log", Dictionary environmentVariables = null, bool doNotCleanupOnUpdate = false, string [] parameters = null) { builder.BuildLogFile = logName; - Assert.True (builder.RunTarget (proj, "Run", doNotCleanupOnUpdate: doNotCleanupOnUpdate, parameters: parameters), "Project should have run."); + Assert.True (builder.RunTarget (proj, "Run", doNotCleanupOnUpdate: doNotCleanupOnUpdate, parameters: parameters, environmentVariables: environmentVariables), "Project should have run."); } protected static void StartActivityAndAssert (XamarinAndroidApplicationProject proj) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 246287cae37..d179740e994 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -565,8 +565,18 @@ public void SingleProject_ApplicationId ([Values (false, true)] bool testOnly) } [Test] - public void AppWithStyleableUsageRuns ([Values (true, false)] bool isRelease, [Values (true, false)] bool linkResources) + public void AppWithStyleableUsageRuns ([Values (true, false)] bool useCLR, [Values (true, false)] bool isRelease, + [Values (true, false)] bool linkResources, [Values (true, false)] bool useStringTypeMaps) { + // Not all combinations are valid, ignore those that aren't + if (!useCLR && useStringTypeMaps) { + Assert.Ignore ("String-based typemaps mode is used only in CoreCLR apps"); + } + + if (useCLR && isRelease && useStringTypeMaps) { + Assert.Ignore ("String-based typemaps mode is available only in Debug CoreCLR builds"); + } + var rootPath = Path.Combine (Root, "temp", TestName); var lib = new XamarinAndroidLibraryProject () { ProjectName = "Styleable.Library" @@ -615,6 +625,7 @@ public MyLibraryLayout (Android.Content.Context context, Android.Util.IAttribute proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, }; + proj.SetProperty ("UseMonoRuntime", useCLR ? "false" : "true"); proj.AddReference (lib); proj.AndroidResources.Add (new AndroidItem.AndroidResource ("Resources\\values\\styleables.xml") { @@ -652,15 +663,27 @@ public MyLayout (Android.Content.Context context, Android.Util.IAttributeSet att } "); - var abis = new string [] { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }; + string[] abis = useCLR switch { + true => new string [] { "arm64-v8a", "x86_64" }, + false => new string [] { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }, + }; + proj.SetAndroidSupportedAbis (abis); var libBuilder = CreateDllBuilder (Path.Combine (rootPath, lib.ProjectName)); Assert.IsTrue (libBuilder.Build (lib), "Library should have built succeeded."); builder = CreateApkBuilder (Path.Combine (rootPath, proj.ProjectName)); - Assert.IsTrue (builder.Install (proj), "Install should have succeeded."); - RunProjectAndAssert (proj, builder); + + Dictionary? environmentVariables = null; + if (useCLR && !isRelease && useStringTypeMaps) { + // The variable must have content to enable string-based typemaps + environmentVariables = new (StringComparer.Ordinal) { + {"CI_TYPEMAP_DEBUG_USE_STRINGS", "yes"} + }; + } + + RunProjectAndAssert (proj, builder, environmentVariables: environmentVariables); var didStart = WaitForActivityToStart (proj.PackageName, "MainActivity", Path.Combine (Root, builder.ProjectDirectory, "startup-logcat.log")); From 15fe56637c290ec4e14f31785c04d3bae40ad9b3 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Wed, 30 Apr 2025 20:38:33 +0200 Subject: [PATCH 11/20] Fix after rebase --- .../Utilities/TypeMapCecilAdapter.cs | 10 ++++------ .../Utilities/TypeMapGenerator.cs | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs index ab8288ff33c..e48923c4771 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs @@ -32,10 +32,8 @@ public static (TypeMapDebugDataSets dataSets, bool foundJniNativeRegistration) G var managedToJava = new List (); var foundJniNativeRegistration = false; - var javaDuplicates = new Dictionary> (StringComparer.Ordinal); - var uniqueAssemblies = needUniqueAssemblies ? new Dictionary (StringComparer.OrdinalIgnoreCase) : null; - foreach (TypeDefinition td in state.AllJavaTypes) { - UpdateApplicationConfig (state, td); + foreach (var td in types) { + foundJniNativeRegistration = JniAddNativeMethodRegistrationAttributeFound (foundJniNativeRegistration, td); TypeMapDebugEntry entry = GetDebugEntry (td, cache); HandleDebugDuplicates (javaDuplicates, entry, td, cache); @@ -62,11 +60,11 @@ public static (TypeMapDebugDataSets dataSets, bool foundJniNativeRegistration) G SyncDebugDuplicates (javaDuplicates); - return new TypeMapDebugDataSets { + return (new TypeMapDebugDataSets { JavaToManaged = javaToManaged, ManagedToJava = managedToJava, UniqueAssemblies = uniqueAssemblies != null ? new List (uniqueAssemblies.Values) : null - }; + }, foundJniNativeRegistration); } public static ReleaseGenerationState GetReleaseGenerationState (NativeCodeGenState state) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs index 3183f49154b..7a22e76f2a0 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs @@ -155,7 +155,7 @@ public void Generate (bool debugBuild, bool skipJniAddNativeMethodRegistrationAt void GenerateDebugNativeAssembly (string outputDirectory) { - TypeMapDebugDataSets dataSets = TypeMapCecilAdapter.GetDebugNativeEntries (state, needUniqueAssemblies: runtime == AndroidRuntime.CoreCLR); + TypeMapDebugDataSets dataSets = state.GetDebugNativeEntries (needUniqueAssemblies: runtime == AndroidRuntime.CoreCLR); var data = new ModuleDebugData { EntryCount = (uint)dataSets.JavaToManaged.Count, From 4e992dd018c293a87554843623d88f8905a7a422 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 5 May 2025 14:24:47 +0200 Subject: [PATCH 12/20] Fix nullable issues after rebase on `main` --- ...eMappingDebugNativeAssemblyGeneratorCLR.cs | 52 ++++++++++++++----- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index 83e2fc064e7..a6b76fc23da 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -34,7 +34,7 @@ public override ulong GetBufferSize (object data, string fieldName) return 0; } - public override string GetPointedToSymbolName (object data, string fieldName) + public override string? GetPointedToSymbolName (object data, string fieldName) { var map_module = EnsureType (data); @@ -110,10 +110,10 @@ public override string GetComment (object data, string fieldName) sealed class TypeMapEntry { [NativeAssembler (Ignore = true)] - public string From; + public string From = String.Empty; [NativeAssembler (Ignore = true)] - public string To; + public string To = String.Empty; [NativeAssembler (UsesDataProvider = true)] public uint from; @@ -131,10 +131,10 @@ sealed class TypeMapEntry sealed class TypeMapManagedTypeInfo { [NativeAssembler (Ignore = true)] - public string AssemblyName; + public string AssemblyName = String.Empty; [NativeAssembler (Ignore = true)] - public string ManagedTypeName; + public string ManagedTypeName = String.Empty; [NativeAssembler (UsesDataProvider = true)] public uint assembly_name_index; @@ -170,7 +170,7 @@ sealed class TypeMap sealed class TypeMapAssembly { [NativeAssembler (Ignore = true)] - public string Name; + public string Name = String.Empty; [NativeAssembler (Ignore = true)] public Guid MVID; @@ -184,15 +184,15 @@ sealed class TypeMapAssembly } readonly TypeMapGenerator.ModuleDebugData data; - StructureInfo typeMapEntryStructureInfo; - StructureInfo typeMapStructureInfo; - StructureInfo typeMapAssemblyStructureInfo; - StructureInfo typeMapManagedTypeInfoStructureInfo; + StructureInfo? typeMapEntryStructureInfo; + StructureInfo? typeMapStructureInfo; + StructureInfo? typeMapAssemblyStructureInfo; + StructureInfo? typeMapManagedTypeInfoStructureInfo; List> javaToManagedMap; List> managedToJavaMap; List> uniqueAssemblies; List> managedTypeInfos; - StructureInstance type_map; + StructureInstance? type_map; public TypeMappingDebugNativeAssemblyGeneratorCLR (TaskLoggingHelper log, TypeMapGenerator.ModuleDebugData data) : base (log) @@ -206,12 +206,17 @@ public TypeMappingDebugNativeAssemblyGeneratorCLR (TaskLoggingHelper log, TypeMa javaToManagedMap = new (); managedToJavaMap = new (); uniqueAssemblies = new (); + managedTypeInfos = new (); } protected override void Construct (LlvmIrModule module) { module.DefaultStringGroup = "tmd"; + if (data.UniqueAssemblies == null) { + throw new InvalidOperationException ("Internal error: unique assemblies collection must be present"); + } + MapStructures (module); var managedTypeNames = new LlvmIrStringBlob (); @@ -253,7 +258,17 @@ protected override void Construct (LlvmIrModule module) } // Input is sorted on name, we need to re-sort it on hashes, if used if (typemap_uses_hashes) { - managedToJavaMap.Sort ((StructureInstance a, StructureInstance b) => a.Instance.from_hash.CompareTo (b.Instance.from_hash)); + managedToJavaMap.Sort ((StructureInstance a, StructureInstance b) => { + if (a.Instance == null) { + return b.Instance == null ? 0 : -1; + } + + if (b.Instance == null) { + return 1; + } + + return a.Instance.from_hash.CompareTo (b.Instance.from_hash); + }); } if (!typemap_uses_hashes) { @@ -273,7 +288,18 @@ protected override void Construct (LlvmIrModule module) }; uniqueAssemblies.Add (new StructureInstance (typeMapAssemblyStructureInfo, entry)); } - uniqueAssemblies.Sort ((StructureInstance a, StructureInstance b) => a.Instance.mvid_hash.CompareTo (b.Instance.mvid_hash)); + + uniqueAssemblies.Sort ((StructureInstance a, StructureInstance b) => { + if (a.Instance == null) { + return b.Instance == null ? 0 : -1; + } + + if (b.Instance == null) { + return 1; + } + + return a.Instance.mvid_hash.CompareTo (b.Instance.mvid_hash); + }); var managedTypeInfos = new List> (); // Java-to-managed maps don't use hashes since many mappings have multiple instances From bfdb0c34b285f8b584dca7bd3f0c40a80621a8a6 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 5 May 2025 14:40:03 +0200 Subject: [PATCH 13/20] Deserialize assembly name --- .../Utilities/TypeMapObjectsXmlFile.cs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapObjectsXmlFile.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapObjectsXmlFile.cs index 9eb190dabc0..a591c83d325 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapObjectsXmlFile.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapObjectsXmlFile.cs @@ -198,19 +198,20 @@ public static TypeMapObjectsXmlFile Import (string filename) static void ImportDebugData (XElement root, TypeMapObjectsXmlFile file) { - var isMonoAndroid = root.GetAttributeOrDefault ("assembly-name", string.Empty) == "Mono.Android"; + var assemblyName = root.GetAttributeOrDefault ("assembly-name", string.Empty); + var isMonoAndroid = assemblyName == "Mono.Android"; var javaToManaged = root.Element ("java-to-managed"); if (javaToManaged is not null) { foreach (var entry in javaToManaged.Elements ("entry")) - file.JavaToManagedDebugEntries.Add (FromDebugEntryXml (entry, isMonoAndroid)); + file.JavaToManagedDebugEntries.Add (FromDebugEntryXml (entry, assemblyName, isMonoAndroid)); } var managedToJava = root.Element ("managed-to-java"); if (managedToJava is not null) { foreach (var entry in managedToJava.Elements ("entry")) - file.ManagedToJavaDebugEntries.Add (FromDebugEntryXml (entry, isMonoAndroid)); + file.ManagedToJavaDebugEntries.Add (FromDebugEntryXml (entry, assemblyName, isMonoAndroid)); } } @@ -251,7 +252,7 @@ public static void WriteEmptyFile (string destination, TaskLoggingHelper log) File.Create (destination).Dispose (); } - static TypeMapDebugEntry FromDebugEntryXml (XElement entry, bool isMonoAndroid) + static TypeMapDebugEntry FromDebugEntryXml (XElement entry, string assemblyName, bool isMonoAndroid) { var javaName = entry.GetAttributeOrDefault ("java-name", string.Empty); var managedName = entry.GetAttributeOrDefault ("managed-name", string.Empty); @@ -264,6 +265,7 @@ static TypeMapDebugEntry FromDebugEntryXml (XElement entry, bool isMonoAndroid) SkipInJavaToManaged = skipInJavaToManaged, IsInvoker = isInvoker, IsMonoAndroid = isMonoAndroid, + AssemblyName = assemblyName, }; } From ed3b17c7593690f0415be554e1e3cc8bf6ff3720 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 5 May 2025 13:11:41 +0200 Subject: [PATCH 14/20] This test requires more changes in the runtime, will be enabled in another PR --- .../Tests/InstallAndRunTests.cs | 31 +++---------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index d179740e994..246287cae37 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -565,18 +565,8 @@ public void SingleProject_ApplicationId ([Values (false, true)] bool testOnly) } [Test] - public void AppWithStyleableUsageRuns ([Values (true, false)] bool useCLR, [Values (true, false)] bool isRelease, - [Values (true, false)] bool linkResources, [Values (true, false)] bool useStringTypeMaps) + public void AppWithStyleableUsageRuns ([Values (true, false)] bool isRelease, [Values (true, false)] bool linkResources) { - // Not all combinations are valid, ignore those that aren't - if (!useCLR && useStringTypeMaps) { - Assert.Ignore ("String-based typemaps mode is used only in CoreCLR apps"); - } - - if (useCLR && isRelease && useStringTypeMaps) { - Assert.Ignore ("String-based typemaps mode is available only in Debug CoreCLR builds"); - } - var rootPath = Path.Combine (Root, "temp", TestName); var lib = new XamarinAndroidLibraryProject () { ProjectName = "Styleable.Library" @@ -625,7 +615,6 @@ public MyLibraryLayout (Android.Content.Context context, Android.Util.IAttribute proj = new XamarinAndroidApplicationProject () { IsRelease = isRelease, }; - proj.SetProperty ("UseMonoRuntime", useCLR ? "false" : "true"); proj.AddReference (lib); proj.AndroidResources.Add (new AndroidItem.AndroidResource ("Resources\\values\\styleables.xml") { @@ -663,27 +652,15 @@ public MyLayout (Android.Content.Context context, Android.Util.IAttributeSet att } "); - string[] abis = useCLR switch { - true => new string [] { "arm64-v8a", "x86_64" }, - false => new string [] { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }, - }; - + var abis = new string [] { "armeabi-v7a", "arm64-v8a", "x86", "x86_64" }; proj.SetAndroidSupportedAbis (abis); var libBuilder = CreateDllBuilder (Path.Combine (rootPath, lib.ProjectName)); Assert.IsTrue (libBuilder.Build (lib), "Library should have built succeeded."); builder = CreateApkBuilder (Path.Combine (rootPath, proj.ProjectName)); - Assert.IsTrue (builder.Install (proj), "Install should have succeeded."); - - Dictionary? environmentVariables = null; - if (useCLR && !isRelease && useStringTypeMaps) { - // The variable must have content to enable string-based typemaps - environmentVariables = new (StringComparer.Ordinal) { - {"CI_TYPEMAP_DEBUG_USE_STRINGS", "yes"} - }; - } - RunProjectAndAssert (proj, builder, environmentVariables: environmentVariables); + Assert.IsTrue (builder.Install (proj), "Install should have succeeded."); + RunProjectAndAssert (proj, builder); var didStart = WaitForActivityToStart (proj.PackageName, "MainActivity", Path.Combine (Root, builder.ProjectDirectory, "startup-logcat.log")); From 1c6196ae98215fe58d2ac68c88579b8e372a653a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 6 May 2025 12:13:02 +0200 Subject: [PATCH 15/20] Store managed type token id in the XML typemap files --- .../Utilities/TypeMapObjectsXmlFile.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapObjectsXmlFile.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapObjectsXmlFile.cs index a591c83d325..5be21da534a 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapObjectsXmlFile.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapObjectsXmlFile.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Linq; using System.Xml; @@ -101,6 +102,7 @@ void WriteTypeMapDebugEntry (XmlWriter xml, TypeMapDebugEntry entry) xml.WriteAttributeStringIfNotDefault ("managed-name", entry.ManagedName); xml.WriteAttributeStringIfNotDefault ("skip-in-java-to-managed", entry.SkipInJavaToManaged); xml.WriteAttributeStringIfNotDefault ("is-invoker", entry.IsInvoker); + xml.WriteAttributeString ("managed-type-token-id", entry.ManagedTypeTokenId.ToString (CultureInfo.InvariantCulture)); xml.WriteEndElement (); } @@ -258,10 +260,12 @@ static TypeMapDebugEntry FromDebugEntryXml (XElement entry, string assemblyName, var managedName = entry.GetAttributeOrDefault ("managed-name", string.Empty); var skipInJavaToManaged = entry.GetAttributeOrDefault ("skip-in-java-to-managed", false); var isInvoker = entry.GetAttributeOrDefault ("is-invoker", false); + var managedTokenId = entry.GetAttributeOrDefault ("managed-type-token-id", (uint)0); return new TypeMapDebugEntry { JavaName = javaName, ManagedName = managedName, + ManagedTypeTokenId = managedTokenId, SkipInJavaToManaged = skipInJavaToManaged, IsInvoker = isInvoker, IsMonoAndroid = isMonoAndroid, From 1c469eb1ec92f7dbf047c150014bc6be97bd219a Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Thu, 8 May 2025 21:51:47 +0200 Subject: [PATCH 16/20] Use better looking code --- .../TypeMappingDebugNativeAssemblyGeneratorCLR.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index a6b76fc23da..6ea4ba8b455 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -26,12 +26,11 @@ sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvid public override ulong GetBufferSize (object data, string fieldName) { var map_module = EnsureType (data); - if (String.Compare ("java_to_managed", fieldName, StringComparison.Ordinal) == 0 || - String.Compare ("managed_to_java", fieldName, StringComparison.Ordinal) == 0) { - return map_module.entry_count; - } - - return 0; + return fieldName switch { + "java_to_managed" => map_module.entry_count, + "managed_to_java" => map_module.entry_count, + _ => 0 + }; } public override string? GetPointedToSymbolName (object data, string fieldName) From 3631ad6b3fa099a022c80f074e913171f2955d38 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Mon, 12 May 2025 22:18:39 +0200 Subject: [PATCH 17/20] Drop the `typemap_` prefix --- src/native/clr/host/typemap.cc | 8 ++++---- src/native/clr/include/host/typemap.hh | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 04ed84a27ff..189ef96ec7b 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -213,7 +213,7 @@ auto TypeMapper::find_managed_to_java_map_entry (hash_t name_hash, const TypeMap } [[gnu::always_inline]] -auto TypeMapper::typemap_managed_to_java_release (const char *typeName, const uint8_t *mvid) noexcept -> const char* +auto TypeMapper::managed_to_java_release (const char *typeName, const uint8_t *mvid) noexcept -> const char* { const TypeMapModule *match = find_module_entry (mvid, managed_to_java_map, managed_to_java_map_module_count); if (match == nullptr) { @@ -322,7 +322,7 @@ auto TypeMapper::managed_to_java (const char *typeName, const uint8_t *mvid) noe auto do_map = [&typeName, &mvid]() -> const char* { #if defined(RELEASE) - return typemap_managed_to_java_release (typeName, mvid); + return managed_to_java_release (typeName, mvid); #else return managed_to_java_debug (typeName, mvid); #endif @@ -386,7 +386,7 @@ auto TypeMapper::find_java_to_managed_entry (hash_t name_hash) noexcept -> const } [[gnu::flatten]] -auto TypeMapper::typemap_java_to_managed_release (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool +auto TypeMapper::java_to_managed_release (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool { if (java_type_name == nullptr || assembly_name == nullptr || managed_type_token_id == nullptr) [[unlikely]] { if (java_type_name == nullptr) { @@ -464,7 +464,7 @@ auto TypeMapper::java_to_managed (const char *java_type_name, char const** assem bool ret; #if defined(RELEASE) - ret = typemap_java_to_managed_release (java_type_name, assembly_name, managed_type_token_id); + ret = java_to_managed_release (java_type_name, assembly_name, managed_type_token_id); #else ret = java_to_managed_debug (java_type_name, assembly_name, managed_type_token_id); #endif diff --git a/src/native/clr/include/host/typemap.hh b/src/native/clr/include/host/typemap.hh index 99f6bc4191a..eea9564cc98 100644 --- a/src/native/clr/include/host/typemap.hh +++ b/src/native/clr/include/host/typemap.hh @@ -22,8 +22,8 @@ namespace xamarin::android { static auto compare_mvid (const uint8_t *mvid, TypeMapModule const& module) noexcept -> int; static auto find_module_entry (const uint8_t *mvid, const TypeMapModule *entries, size_t entry_count) noexcept -> const TypeMapModule*; static auto find_managed_to_java_map_entry (hash_t name_hash, const TypeMapModuleEntry *map, size_t entry_count) noexcept -> const TypeMapModuleEntry*; - static auto typemap_managed_to_java_release (const char *typeName, const uint8_t *mvid) noexcept -> const char*; - static auto typemap_java_to_managed_release (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool; + static auto managed_to_java_release (const char *typeName, const uint8_t *mvid) noexcept -> const char*; + static auto java_to_managed_release (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool; static auto find_java_to_managed_entry (hash_t name_hash) noexcept -> const TypeMapJava*; #else From 250a0618b5e40615f3fdec5c2a2baae6d3304b3c Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 13 May 2025 08:57:24 +0200 Subject: [PATCH 18/20] Fix after rebase --- ...eMappingDebugNativeAssemblyGeneratorCLR.cs | 1 + src/native/clr/host/typemap.cc | 28 ------------------- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs index 6ea4ba8b455..7990cd12e51 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs @@ -277,6 +277,7 @@ protected override void Construct (LlvmIrModule module) var assemblyNamesBlob = new LlvmIrStringBlob (); foreach (TypeMapGenerator.TypeMapDebugAssembly asm in data.UniqueAssemblies) { (int assemblyNameOffset, int assemblyNameLength) = assemblyNamesBlob.Add (asm.Name); + var entry = new TypeMapAssembly { Name = asm.Name, MVID = asm.MVID, diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 189ef96ec7b..16249372a85 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -475,31 +475,3 @@ auto TypeMapper::java_to_managed (const char *java_type_name, char const** assem return ret; } -#endif // ndef DEBUG - -[[gnu::flatten]] -auto TypeMapper::typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool -{ - log_debug (LOG_ASSEMBLY, "typemap_java_to_managed: looking up type '{}'", optional_string (java_type_name)); - if (FastTiming::enabled ()) [[unlikely]] { - internal_timing.start_event (TimingEventKind::JavaToManaged); - } - - if (java_type_name == nullptr) [[unlikely]] { - log_warn (LOG_ASSEMBLY, "typemap: type name not specified in typemap_java_to_managed"); - return false; - } - - bool ret; -#if defined(RELEASE) - ret = typemap_java_to_managed_release (java_type_name, assembly_name, managed_type_token_id); -#else - ret = typemap_java_to_managed_debug (java_type_name, assembly_name, managed_type_token_id); -#endif - - if (FastTiming::enabled ()) [[unlikely]] { - internal_timing.end_event (); - } - - return ret; -} From 0b2b4588f0381bccfb9925c3c2928cd3bcac4fe7 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 13 May 2025 09:18:14 +0200 Subject: [PATCH 19/20] Cleanup --- src/native/clr/host/internal-pinvokes.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/native/clr/host/internal-pinvokes.cc b/src/native/clr/host/internal-pinvokes.cc index 6f0a62b3002..2bcca553fd6 100644 --- a/src/native/clr/host/internal-pinvokes.cc +++ b/src/native/clr/host/internal-pinvokes.cc @@ -33,7 +33,6 @@ const char* clr_typemap_managed_to_java (const char *typeName, const uint8_t *mv bool clr_typemap_java_to_managed (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept { - log_debug (LOG_ASSEMBLY, __PRETTY_FUNCTION__); return TypeMapper::java_to_managed (java_type_name, assembly_name, managed_type_token_id); } From 5032a34eb1d082ab4655c89aa4650d46e37e37f6 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 13 May 2025 09:19:44 +0200 Subject: [PATCH 20/20] More cleanup --- src/native/clr/host/typemap.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/native/clr/host/typemap.cc b/src/native/clr/host/typemap.cc index 16249372a85..012feaa59b2 100644 --- a/src/native/clr/host/typemap.cc +++ b/src/native/clr/host/typemap.cc @@ -310,7 +310,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, "typemap_managed_to_java: looking up type '{}'", optional_string (typeName)); + log_debug (LOG_ASSEMBLY, "managed_to_java: looking up type '{}'", optional_string (typeName)); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::ManagedToJava); } @@ -452,7 +452,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, "typemap_java_to_managed: looking up type '{}'", optional_string (java_type_name)); + log_debug (LOG_ASSEMBLY, "java_to_managed: looking up type '{}'", optional_string (java_type_name)); if (FastTiming::enabled ()) [[unlikely]] { internal_timing.start_event (TimingEventKind::JavaToManaged); }