From 39dfcb67245f78d73fd977bf76df45d694151b05 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Fri, 12 Feb 2021 10:09:15 +0100 Subject: [PATCH 1/3] [illink] Type registrations fallback switch Context: https://github.com/xamarin/xamarin-android/issues/5515 Add new feature switch `XATypeRegistrationFallback` for type registrations fallback. The switch default value is `false` for linked net6 apps. We can remove the fallback by the linker, because all the java to managed type names lookup is now handled by typemap, so we should not need this fallback anymore - at least not on device. On desktop we still need it for Designer, which uses unlinked assemblies and thus the fallback still works. Also add lazy initialization of `packageLookup` field. That allows linker to link the field away. That also improves startup performance, as we don't create the dictionary in the static constructor. apk size savings, BuildReleaseArm64False/net6 test: Size difference in bytes ([*1] apk1 only, [*2] apk2 only): - 221 assemblies/System.Private.CoreLib.dll Type System.String - 13 Method public string ToUpperInvariant () - 20 Method public int LastIndexOf (char) Type System.Char - 8 Method public static char ToUpperInvariant (char) Type System.Globalization.TextInfo - 214 Method static string ToUpperAsciiInvariant (string) - 36 Method static char ToUpperInvariant (char) - 37 Method public string ToUpper (string) - 22 Method static char ToUpperAsciiInvariant (char) - 21,506 assemblies/Mono.Android.dll - Type Java.Interop.__TypeRegistrations Type Java.Interop.TypeManager - Field static System.Collections.Generic.Dictionary`2>> packageLookup + Field static readonly bool k__BackingField + Property bool TypeRegistrationFallbackIsEnabled { get; } - 184 Method static System.Type GetJavaToManagedType (string) - 110 Method public static void RegisterPackage (string, System.Converter`2) - 218 Method public static void RegisterPackages (string[], System.Converter`2[]) + 3 Method static bool get_TypeRegistrationFallbackIsEnabled () + 31 Method static bool InitializeTypeRegistrationFallbackIsEnabled () Type Java.Interop.Tools.TypeNameMappings.JavaNativeTypeManager - 86 Method public static string ToCliType (string) - 98 Method static string ToCliTypePart (string) - 67 Method static string ToPascalCase (string, int) Summary: - 21,727 Assemblies -3.05% (of 712,159) - 122,880 Uncompressed assemblies -8.30% (of 1,480,704) --- .../ILLink/ILLink.Substitutions.xml | 10 +++++++ src/Mono.Android/Java.Interop/TypeManager.cs | 28 +++++++++++++++++-- src/Mono.Android/Mono.Android.csproj | 3 ++ .../Microsoft.Android.Sdk.ILLink.targets | 5 ++++ .../Tasks/LinkerTests.cs | 23 +++++++++++++++ 5 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 src/Mono.Android/ILLink/ILLink.Substitutions.xml diff --git a/src/Mono.Android/ILLink/ILLink.Substitutions.xml b/src/Mono.Android/ILLink/ILLink.Substitutions.xml new file mode 100644 index 00000000000..8259197e735 --- /dev/null +++ b/src/Mono.Android/ILLink/ILLink.Substitutions.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index 2a8be4c2f81..6b438ee8aed 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -212,6 +212,10 @@ static Exception CreateJavaLocationException () [MethodImplAttribute(MethodImplOptions.InternalCall)] static extern Type monodroid_typemap_java_to_managed (string java_type_name); + private static bool TypeRegistrationFallbackIsEnabled { get; } = InitializeTypeRegistrationFallbackIsEnabled (); + private static bool InitializeTypeRegistrationFallbackIsEnabled () => + AppContext.TryGetSwitch ("Java.Interop.TypeManager.TypeRegistrationFallbackIsEnabled", out bool isEnabled) ? isEnabled : true; + internal static Type? GetJavaToManagedType (string class_name) { Type? type = monodroid_typemap_java_to_managed (class_name); @@ -225,10 +229,18 @@ static Exception CreateJavaLocationException () return null; } + if (TypeRegistrationFallbackIsEnabled) + return TypeRegistrationFallback (class_name); + + return null; + } + + internal static Type? TypeRegistrationFallback (string class_name) + { __TypeRegistrations.RegisterPackages (); - type = null; - int ls = class_name.LastIndexOf ('/'); + Type? type = null; + int ls = class_name.LastIndexOf ('/'); var package = ls >= 0 ? class_name.Substring (0, ls) : ""; if (packageLookup.TryGetValue (package, out var mappers)) { foreach (Converter c in mappers) { @@ -353,10 +365,18 @@ public static void RegisterType (string java_class, Type t) } } - static Dictionary>> packageLookup = new Dictionary>> (); + static Dictionary>>? packageLookup; + + static void LazyInitPackageLookup () + { + if (packageLookup == null) + packageLookup = new Dictionary>> (); + } public static void RegisterPackage (string package, Converter lookup) { + LazyInitPackageLookup (); + lock (packageLookup) { if (!packageLookup.TryGetValue (package, out var lookups)) packageLookup.Add (package, lookups = new List> ()); @@ -366,6 +386,8 @@ public static void RegisterPackage (string package, Converter look public static void RegisterPackages (string[] packages, Converter[] lookups) { + LazyInitPackageLookup (); + if (packages == null) throw new ArgumentNullException ("packages"); if (lookups == null) diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj index b9d9a31829d..de41c74ec0c 100644 --- a/src/Mono.Android/Mono.Android.csproj +++ b/src/Mono.Android/Mono.Android.csproj @@ -97,6 +97,9 @@ ILLink.LinkAttributes.xml + + ILLink.Substitutions.xml + diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets index 1eff7609be6..902ab5222ce 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.ILLink.targets @@ -22,6 +22,7 @@ This file contains the .NET 5-specific targets to customize ILLink true false false + false + Date: Tue, 16 Feb 2021 09:52:08 +0100 Subject: [PATCH 2/3] Requested changes --- src/Mono.Android/Java.Interop/TypeManager.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Mono.Android/Java.Interop/TypeManager.cs b/src/Mono.Android/Java.Interop/TypeManager.cs index 6b438ee8aed..83efa9f6ee5 100644 --- a/src/Mono.Android/Java.Interop/TypeManager.cs +++ b/src/Mono.Android/Java.Interop/TypeManager.cs @@ -212,9 +212,9 @@ static Exception CreateJavaLocationException () [MethodImplAttribute(MethodImplOptions.InternalCall)] static extern Type monodroid_typemap_java_to_managed (string java_type_name); - private static bool TypeRegistrationFallbackIsEnabled { get; } = InitializeTypeRegistrationFallbackIsEnabled (); - private static bool InitializeTypeRegistrationFallbackIsEnabled () => - AppContext.TryGetSwitch ("Java.Interop.TypeManager.TypeRegistrationFallbackIsEnabled", out bool isEnabled) ? isEnabled : true; + static bool TypeRegistrationFallbackIsEnabled { get; } = InitializeTypeRegistrationFallbackIsEnabled (); + static bool InitializeTypeRegistrationFallbackIsEnabled () => + !AppContext.TryGetSwitch ("Java.Interop.TypeManager.TypeRegistrationFallbackIsEnabled", out bool isEnabled) || isEnabled; internal static Type? GetJavaToManagedType (string class_name) { @@ -370,7 +370,7 @@ public static void RegisterType (string java_class, Type t) static void LazyInitPackageLookup () { if (packageLookup == null) - packageLookup = new Dictionary>> (); + packageLookup = new Dictionary>> (StringComparer.Ordinal); } public static void RegisterPackage (string package, Converter lookup) From e39fe7f6cb0d7fb1616f66f63ef2b6bb1a457119 Mon Sep 17 00:00:00 2001 From: Radek Doulik Date: Tue, 16 Feb 2021 23:31:53 +0100 Subject: [PATCH 3/3] Add Assert.Ignore call --- .../Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs index 6c33597184d..028f81e339b 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs @@ -399,7 +399,7 @@ public unsafe bool MyMethod (Android.OS.IBinder windowToken, [global::Android.Ru public void TypeRegistrationsFallback ([Values (true, false)] bool enabled) { if (!Builder.UseDotNet) - return; + Assert.Ignore ("Test only valid on .NET 6"); var proj = new XamarinAndroidApplicationProject () { IsRelease = true }; if (enabled)