From 95de74b88cd66fe8200873ff3f1b1aa7ed33d283 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 5 Jan 2021 09:10:53 +0100 Subject: [PATCH] [typemap] Handle managed -> Java duplicate mapping correctly Fixes: https://github.com/xamarin/xamarin-android/issues/5409 Context: a017561b1e44c51a9af79fae0baaa50fe01c4123 Context: bb55bb064b967adf8ca975928736346694dceb02 This is another commit in the series of properly handling the N:1 type mapping from Java to Managed types. a017561b implemented most of the handling properly, bb55bb064 fixed it up for generic types but neither of the two commits accounted for the situation when a Managed type map is requested that points back to a duplicate Java type. In fact, such Managed types were removed from the typemap unless they were the type pointed to from the Java duplicate. This meant that, effectively, all the `*Invoker` classes were not part of the mapping, leading to this error for Debug builds: app_process32: ---- DEBUG ASSERTION FAILED ---- app_process32: ---- Assert Short Message ---- app_process32: ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof(Android.Views.LayoutInflaterInvoker)).JniTypeName="" != "android/view/LayoutInflater" app_process32: ---- Assert Long Message ---- app_process32: app_process32: at System.Diagnostics.DebugProvider.Fail(String message, String detailMessage) app_process32: at System.Diagnostics.Debug.Fail(String message, String detailMessage) app_process32: at System.Diagnostics.Debug.Assert(Boolean condition, String message, String detailMessage) app_process32: at System.Diagnostics.Debug.Assert(Boolean condition, String message) app_process32: at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType, Boolean checkManagedPeerType, Boolean isInterface) app_process32: at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType) app_process32: at Android.Runtime.XAPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType) app_process32: at Android.Views.LayoutInflaterInvoker..cctor() app_process32: at System.Reflection.RuntimeConstructorInfo.InternalInvoke(RuntimeConstruct : CLR: Managed code called FailFast, saying "ManagedPeerType <=> JniTypeName Mismatch! javaVM.GetJniTypeInfoForType(typeof(Android.Views.LayoutInflaterInvoker)).JniTypeName="" != "android/view/LayoutInflater" : at System.Diagnostics.DebugProvider.Fail(String message, String detailMessage) : at System.Diagnostics.Debug.Fail(String message, String detailMessage) : at System.Diagnostics.Debug.Assert(Boolean condition, String message, String detailMessage) : at System.Diagnostics.Debug.Assert(Boolean condition, String message) : at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType, Boolean checkManagedPeerType, Boolean isInterface) : at Java.Interop.JniPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType) : at Android.Runtime.XAPeerMembers..ctor(String jniPeerTypeName, Type managedPeerType) : at Android.Views.LayoutInflaterInvoker..cctor() This commit modifies the mapping code to make sure that all duplicate Java types point to the **first** Managed type but that all the Managed types point back to their original Java type. --- .../Utilities/TypeMapGenerator.cs | 13 +++++++++---- .../TypeMappingDebugNativeAssemblyGenerator.cs | 4 +++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs index 590b2018b71..7ab407f45ee 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs @@ -81,6 +81,7 @@ internal sealed class TypeMapDebugEntry public int ManagedIndex; public TypeDefinition TypeDefinition; public bool SkipInJavaToManaged; + public TypeMapDebugEntry DuplicateForJavaToManaged; } // Widths include the terminating nul character but not the padding! @@ -267,11 +268,13 @@ void SyncDebugDuplicates (Dictionary> javaDuplic continue; } + // Java duplicates must all point to the same managed type + // Managed types, however, must point back to the original Java type instead + // File/assembly generator use the `DuplicateForJavaToManaged` field to know to which managed type the + // duplicate Java type must be mapped. TypeMapDebugEntry template = duplicates [0]; for (int i = 1; i < duplicates.Count; i++) { - duplicates[i].TypeDefinition = template.TypeDefinition; - duplicates[i].ManagedName = template.ManagedName; - duplicates[i].SkipInJavaToManaged = template.SkipInJavaToManaged; + duplicates[i].DuplicateForJavaToManaged = template; } } } @@ -571,7 +574,9 @@ void OutputModule (BinaryWriter bw, ModuleDebugData moduleData) foreach (TypeMapDebugEntry entry in moduleData.JavaToManagedMap) { bw.Write (outputEncoding.GetBytes (entry.JavaName)); PadField (bw, entry.JavaName.Length, (int)moduleData.JavaNameWidth); - bw.Write (entry.SkipInJavaToManaged ? InvalidJavaToManagedMappingIndex : (uint)entry.ManagedIndex); + + TypeMapGenerator.TypeMapDebugEntry managedEntry = entry.DuplicateForJavaToManaged != null ? entry.DuplicateForJavaToManaged : entry; + bw.Write (managedEntry.SkipInJavaToManaged ? InvalidJavaToManagedMappingIndex : (uint)managedEntry.ManagedIndex); } foreach (TypeMapDebugEntry entry in moduleData.ManagedToJavaMap) { diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs index 3ae7ba809e4..678c012f180 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs @@ -70,7 +70,9 @@ protected override void WriteSymbols (StreamWriter output) if (haveJavaToManaged) { foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.JavaToManagedMap) { size += WritePointer (output, entry.JavaLabel); - size += WritePointer (output, entry.SkipInJavaToManaged ? null : entry.ManagedLabel); + + TypeMapGenerator.TypeMapDebugEntry managedEntry = entry.DuplicateForJavaToManaged != null ? entry.DuplicateForJavaToManaged : entry; + size += WritePointer (output, managedEntry.SkipInJavaToManaged ? null : managedEntry.ManagedLabel); } } WriteStructureSize (output, JavaToManagedSymbol, size, alwaysWriteSize: true);