diff --git a/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs index 5891149578f..ff7ec8395f3 100644 --- a/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs +++ b/src/Microsoft.Android.Runtime.NativeAOT/Java.Interop/JreRuntime.cs @@ -56,6 +56,9 @@ static NativeAotRuntimeOptions CreateJreVM (NativeAotRuntimeOptions builder) builder.EnvironmentPointer == IntPtr.Zero && string.IsNullOrEmpty (builder.JvmLibraryPath)) throw new InvalidOperationException ($"Member `{nameof (NativeAotRuntimeOptions)}.{nameof (NativeAotRuntimeOptions.JvmLibraryPath)}` must be set."); + if (!RuntimeFeature.TrimmableTypeMap) { + throw new NotSupportedException ("NativeAOT requires the trimmable typemap."); + } #if NET builder.TypeManager ??= CreateDefaultTypeManager (); @@ -77,11 +80,11 @@ internal protected JreRuntime (NativeAotRuntimeOptions builder) static JniRuntime.JniTypeManager CreateDefaultTypeManager () { - if (RuntimeFeature.TrimmableTypeMap) { - return new TrimmableTypeMapTypeManager (); + if (!RuntimeFeature.TrimmableTypeMap) { + throw new NotSupportedException ("NativeAOT requires the trimmable typemap."); } - return new ManagedTypeManager (); + return new TrimmableTypeMapTypeManager (); } public override string? GetCurrentManagedThreadName () diff --git a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj index 6d3aa528fa1..d1ec626bab5 100644 --- a/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj +++ b/src/Microsoft.Android.Sdk.ILLink/Microsoft.Android.Sdk.ILLink.csproj @@ -22,13 +22,8 @@ - - - - - diff --git a/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs b/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs deleted file mode 100644 index 0f775f4d87c..00000000000 --- a/src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs +++ /dev/null @@ -1,422 +0,0 @@ -using System; -using System.Buffers.Binary; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.InteropServices; -using Java.Interop.Tools.Cecil; -using Java.Interop.Tools.TypeNameMappings; -using Mono.Cecil; -using Mono.Cecil.Cil; -using Mono.Linker; -using Mono.Linker.Steps; - -namespace Microsoft.Android.Sdk.ILLink; - -/// -/// MVP "typemap" implementation for NativeAOT -/// -public class TypeMappingStep : BaseStep -{ - const string AssemblyName = "Mono.Android"; - const string TypeName = "Microsoft.Android.Runtime.ManagedTypeMapping"; - const string SystemIOHashingAssemblyPathCustomData = "SystemIOHashingAssemblyPath"; - readonly IDictionary> TypeMappings = new Dictionary> (StringComparer.Ordinal); - AssemblyDefinition? MonoAndroidAssembly; - - delegate ulong HashMethod (ReadOnlySpan data, long seed = 0); - HashMethod? _hashMethod; - - protected override void Process () - { - _hashMethod = LoadHashMethod (); - } - - protected override void ProcessAssembly (AssemblyDefinition assembly) - { - if (assembly.Name.Name == AssemblyName) { - MonoAndroidAssembly = assembly; - } - if (Annotations?.GetAction (assembly) == AssemblyAction.Delete) - return; - - foreach (var type in assembly.MainModule.Types) { - ProcessType (assembly, type); - } - } - - protected override void EndProcess () - { - Context.LogMessage ($"Writing {TypeMappings.Count} typemap entries"); - - if (MonoAndroidAssembly is null) { - throw new InvalidOperationException ($"Unable to find {AssemblyName} assembly"); - } - - var module = MonoAndroidAssembly.MainModule; - var type = module.GetType (TypeName); - if (type is null) { - throw new InvalidOperationException ($"Unable to find {TypeName} type"); - } - - var typeMappingRecords = TypeMappings - .Select (kvp => - new TypeMapRecord { - JniName = kvp.Key, - Types = kvp.Value.ToArray (), - Context = Context, - }) - .ToArray (); - - // Java -> .NET mapping - { - var orderedJavaToDotnetMapping = typeMappingRecords.OrderBy (record => Hash (record.JniName)) - .ToArray (); - var jniNames = orderedJavaToDotnetMapping.Select (record => record.JniName) - .ToArray (); - var jniNameHashes = jniNames.Select (Hash) - .ToArray (); - var types = orderedJavaToDotnetMapping.Select (record => record.SelectTypeDefinition ()) - .ToArray (); - - Context.LogMessage ("JNI -> .NET mappings"); - Context.LogMessage ($"Generated field {type.FullName}.s_get_JniNameHashes_data contains {jniNameHashes.Length} hashes:"); - for (int i = 0; i < jniNameHashes.Length; ++i ) { - var java = jniNames [i]; - var hash = jniNameHashes [i]; - Context.LogMessage ($"\t0x{hash.ToString ("x", System.Globalization.CultureInfo.InvariantCulture), -16} // {i,4}: {java}"); - } - Context.LogMessage ($"Generated method {type.FullName}.GetTypeByJniNameHashIndex contains {types.Length} mappings:"); - var maxAqtnLength = types.Max (t => TypeDefinitionRocks.GetAssemblyQualifiedName (t, Context).Length)+2; - for (int i = 0; i < types.Length; ++i ) { - var aqtn = TypeDefinitionRocks.GetAssemblyQualifiedName (types [i], Context); - var java = jniNames [i]; - var hash = jniNameHashes [i]; - Context.LogMessage ( - string.Format (System.Globalization.CultureInfo.InvariantCulture, - "\tindex {0,4} => Type.GetType({1,-" + maxAqtnLength + "}), // `{2}` hash=0x{3:x16}", i, $"\"{aqtn}\"", java, hash)); - } - Context.LogMessage ($"Generated method {type.FullName}.GetJniNameByJniNameHashIndex contains {jniNames.Length} mappings:"); - var maxJavaLength = jniNames.Max (s => s.Length)+2; - for (int i = 0; i < jniNames.Length; ++i ) { - var java = jniNames [i]; - var aqtn = TypeDefinitionRocks.GetAssemblyQualifiedName (types [i], Context); - var hash = jniNameHashes [i]; - Context.LogMessage ( - string.Format (System.Globalization.CultureInfo.InvariantCulture, - "\tindex {0,4} => {1,-" + maxJavaLength + "}, // `{2}` hash=0x{3:x16}", i, $"\"{java}\"", aqtn, hash)); - } - - GenerateHashes (jniNameHashes, methodName: "get_JniNameHashes"); - GenerateGetTypeByJniNameHashIndex (types); - GenerateStringSwitchMethod (type, "GetJniNameByJniNameHashIndex", jniNames); - } - - // .NET -> Java mapping - { - var orderedManagedToJavaMapping = typeMappingRecords - .SelectMany (record => record.Flatten ()) - .OrderBy (record => Hash (record.TypeName)) - .ToArray (); - - var typeNames = orderedManagedToJavaMapping - .Select (record => record.TypeName) - .ToArray (); - var typeNameHashes = typeNames.Select (Hash) - .ToArray (); - var jniNames = orderedManagedToJavaMapping.Select (record => record.JniName) - .ToArray (); - - Context.LogMessage (".NET -> JNI mappings"); - Context.LogMessage ($"Generated field {type.FullName}.s_get_TypeNameHashes_data contains {typeNameHashes.Length} hashes:"); - for (int i = 0; i < typeNameHashes.Length; ++i ) { - var aqtn = typeNames [i]; - var hash = typeNameHashes [i]; - Context.LogMessage ($"\t0x{hash.ToString ("x", System.Globalization.CultureInfo.InvariantCulture), -16} // {i,4}: {aqtn}"); - } - var maxJavaLength = jniNames.Max (s => s.Length) + 2; - Context.LogMessage ($"Generated method {type.FullName}.GetJniNameByTypeNameHashIndex contains {jniNames.Length} mappings:"); - for (int i = 0; i < jniNames.Length; ++i ) { - var java = jniNames [i]; - var aqtn = typeNames [i]; - var hash = typeNameHashes [i]; - Context.LogMessage ( - string.Format (System.Globalization.CultureInfo.InvariantCulture, - "\tindex {0,4} => {1,-" + maxJavaLength + "}, // `{2}` hash=0x{3:x16}", i, $"\"{java}\"", aqtn, hash)); - } - Context.LogMessage ($"Generated method {type.FullName}.GetTypeNameByTypeNameHashIndex contains {typeNames.Length} mappings:"); - var maxAqtnLength = typeNames.Max (s => s.Length) + 2; - for (int i = 0; i < typeNames.Length; ++i ) { - var java = jniNames [i]; - var aqtn = typeNames [i]; - var hash = typeNameHashes [i]; - Context.LogMessage ( - string.Format (System.Globalization.CultureInfo.InvariantCulture, - "\tindex {0,4} => {1,-" + maxAqtnLength + "}, // `{2}` hash=0x{3:x16}", i, $"\"{aqtn}\"", java, hash)); - } - - GenerateHashes (typeNameHashes, methodName: "get_TypeNameHashes"); - GenerateStringSwitchMethod (type, "GetJniNameByTypeNameHashIndex", jniNames); - GenerateStringSwitchMethod (type, "GetTypeNameByTypeNameHashIndex", typeNames); - } - - void GenerateGetTypeByJniNameHashIndex (IEnumerable types) - { - var method = type.Methods.FirstOrDefault (m => m.Name == "GetTypeByJniNameHashIndex"); - if (method is null) { - throw new InvalidOperationException ($"Unable to find {TypeName}.GetTypeByJniNameHashIndex() method"); - } - - var getTypeFromHandle = module.ImportReference (typeof (Type).GetMethod ("GetTypeFromHandle")); - if (getTypeFromHandle is null) { - throw new InvalidOperationException ($"Unable to find Type.GetTypeFromHandle() method"); - } - - // Clear IL in method body - method.Body.Instructions.Clear (); - - var il = method.Body.GetILProcessor (); - - var targets = new List (); - foreach (var target in types) { - targets.Add (il.Create (OpCodes.Ldtoken, module.ImportReference (target))); - } - - il.Emit (OpCodes.Ldarg_0); - il.Emit (OpCodes.Switch, targets.ToArray ()); - - var defaultTarget = il.Create (OpCodes.Ldnull); - il.Emit (OpCodes.Br, defaultTarget); - - foreach (var target in targets) { - il.Append (target); - il.Emit (OpCodes.Call, getTypeFromHandle); - il.Emit (OpCodes.Ret); - } - - il.Append (defaultTarget); - il.Emit (OpCodes.Ret); - } - - void GenerateStringSwitchMethod (TypeDefinition type, string methodName, string[] values) - { - var method = type.Methods.FirstOrDefault (m => m.Name == methodName); - if (method is null) { - throw new InvalidOperationException ($"Unable to find {type.FullName}.{methodName} method"); - } - - // Clear IL in method body - method.Body.Instructions.Clear (); - - var il = method.Body.GetILProcessor (); - - var targets = new List (); - foreach (var value in values) { - targets.Add (il.Create (OpCodes.Ldstr, value)); - } - - il.Emit (OpCodes.Ldarg_0); - il.Emit (OpCodes.Switch, targets.ToArray ()); - - var defaultTarget = il.Create (OpCodes.Ldnull); - il.Emit (OpCodes.Br, defaultTarget); - - foreach (var target in targets) { - il.Append (target); - il.Emit (OpCodes.Ret); - } - - il.Append (defaultTarget); - il.Emit (OpCodes.Ret); - } - - void GenerateHashes (ulong[] hashes, string methodName) - { - // Sanity check: hashes must be unique and sorted - if (hashes.Length > 0) { - ulong previous = hashes[0]; - for (int i = 1; i < hashes.Length; ++i) { - if (hashes[i] == previous) { - throw new InvalidOperationException ($"Duplicate hashes"); - } else if (hashes[i] < previous) { - throw new InvalidOperationException ($"Hashes are not in ascending order"); - } - - previous = hashes[i]; - } - } - - GenerateReadOnlySpanGetter (type, methodName, hashes, sizeof (ulong), BitConverter.GetBytes); - } - - void GenerateReadOnlySpanGetter (TypeDefinition type, string name, T[] data, int sizeOfT, Func getBytes) - where T : struct - { - // Create static array struct for `byte[#data * sizeof(T)]` - var arrayType = GetArrayType (type, data.Length * sizeOfT); - - // Create static field to store the raw bytes - var bytesField = new FieldDefinition ($"s_{name}_data", FieldAttributes.Private | FieldAttributes.Static | FieldAttributes.InitOnly, arrayType); - bytesField.InitialValue = data.SelectMany (getBytes).ToArray (); - if (!bytesField.Attributes.HasFlag (FieldAttributes.HasFieldRVA)) { - throw new InvalidOperationException ($"Field {bytesField.Name} does not have RVA"); - } - - type.Fields.Add (bytesField); - - // Generate the Hashes getter - var getHashes = type.Methods.FirstOrDefault (f => f.Name == name) ?? throw new InvalidOperationException ($"Unable to find {TypeName}.{name} field"); - - getHashes.Body.Instructions.Clear (); - var il = getHashes.Body.GetILProcessor (); - - il.Emit (OpCodes.Ldsflda, bytesField); - il.Emit (OpCodes.Ldc_I4, data.Length); - il.Emit (OpCodes.Newobj, module.ImportReference (typeof (ReadOnlySpan).GetConstructor (new[] { typeof(void*), typeof(int) }))); - - il.Emit (OpCodes.Ret); - } - - TypeDefinition GetArrayType (TypeDefinition type, int size) - { - var hashesArrayName = $"HashesArray_{size}"; - var arrayType = type.NestedTypes.FirstOrDefault (td => td.Name == hashesArrayName); - if (arrayType is null) { - arrayType = new TypeDefinition ( - "", - hashesArrayName, - TypeAttributes.NestedPrivate | TypeAttributes.ExplicitLayout, - module.ImportReference (typeof (ValueType))) - { - PackingSize = 1, - ClassSize = size, - }; - - type.NestedTypes.Add (arrayType); - } - - return arrayType; - } - } - - class TypeMapRecord - { - public required string JniName { get; init; } - public required TypeDefinition[] Types { get; init; } - public required LinkContext Context { get; init; } - - public string TypeName - { - get - { - // We need to drop the version, culture, and public key information from the AQN. - var type = SelectTypeDefinition (); - var assemblyQualifiedName = TypeDefinitionRocks.GetAssemblyQualifiedName (type, Context); - var commaIndex = assemblyQualifiedName.IndexOf(','); - var secondCommaIndex = assemblyQualifiedName.IndexOf(',', startIndex: commaIndex + 1); - return secondCommaIndex < 0 - ? assemblyQualifiedName - : assemblyQualifiedName.Substring (0, secondCommaIndex); - } - } - - public TypeDefinition SelectTypeDefinition () - { - if (Types.Length == 1) - return Types[0]; - - var best = Types[0]; - foreach (var type in Types) { - if (type == best) - continue; - // Types in Mono.Android assembly should be first in the list - if (best.Module.Assembly.Name.Name != "Mono.Android" && - type.Module.Assembly.Name.Name == "Mono.Android") { - best = type; - continue; - } - // We found the `Invoker` type *before* the declared type - // Fix things up so the abstract type is first, and the `Invoker` is considered a duplicate. - if ((type.IsAbstract || type.IsInterface) && - !best.IsAbstract && - !best.IsInterface && - type.IsAssignableFrom (best, Context)) { - best = type; - continue; - } - - // we found a generic subclass of a non-generic type - if (type.IsGenericInstance && - !best.IsGenericInstance && - type.IsAssignableFrom (best, Context)) { - best = type; - continue; - } - } - foreach (var type in Types) { - if (type == best) - continue; - Context.LogMessage ($"Duplicate typemap entry for {JniName} => {type.FullName}"); - } - return best; - } - - public IEnumerable Flatten () => - Types.Select (type => - new TypeMapRecord { - JniName = JniName, - Types = new[] { type }, - Context = Context, - }); - } - - void ProcessType (AssemblyDefinition assembly, TypeDefinition type) - { - if (type.HasJavaPeer (Context)) { - var javaName = JavaNativeTypeManager.ToJniName (type, Context); - if (!TypeMappings.TryGetValue (javaName, out var list)) { - TypeMappings.Add (javaName, list = new List ()); - } - list.Add (type); - } - - if (!type.HasNestedTypes) - return; - - foreach (TypeDefinition nested in type.NestedTypes) - ProcessType (assembly, nested); - } - - ulong Hash (string value) - { - ReadOnlySpan bytes = MemoryMarshal.AsBytes(value.AsSpan ()); - ulong hash = _hashMethod!(bytes); - - if (!BitConverter.IsLittleEndian) { - hash = BinaryPrimitives.ReverseEndianness (hash); - } - - return hash; - } - - HashMethod LoadHashMethod () - { - if (!Context.TryGetCustomData (SystemIOHashingAssemblyPathCustomData, out var assemblyPath)) { - throw new InvalidOperationException ($"The {nameof (TypeMappingStep)} step requires setting the '{SystemIOHashingAssemblyPathCustomData}' custom data"); - } else if (!System.IO.File.Exists (assemblyPath)) { - throw new InvalidOperationException ($"The '{SystemIOHashingAssemblyPathCustomData}' custom data must point to a valid assembly path ('{assemblyPath}' does not exist)"); - } - - System.Reflection.MethodInfo? hashToUInt64MethodInfo; - try { - hashToUInt64MethodInfo = System.Reflection.Assembly.LoadFile (assemblyPath).GetType ("System.IO.Hashing.XxHash3")?.GetMethod ("HashToUInt64"); - } catch (Exception ex) { - throw new InvalidOperationException ($"The '{SystemIOHashingAssemblyPathCustomData}' custom data must point to a valid assembly path ('{assemblyPath}' could not be loaded)", ex); - } - - if (hashToUInt64MethodInfo is null) { - throw new InvalidOperationException ($"Unable to find System.IO.Hashing.XxHash3.HashToUInt64 method, {nameof(TypeMappingStep)} cannot proceed"); - } - - return (HashMethod)Delegate.CreateDelegate (typeof (HashMethod), hashToUInt64MethodInfo, throwOnBindFailure: true); - } -} diff --git a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs index c2e7ea913ca..9c116bebb7d 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnvInit.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnvInit.cs @@ -174,8 +174,8 @@ internal static JniRuntime.JniTypeManager CreateTypeManager (JnienvInitializeArg return new TrimmableTypeMapTypeManager (); } - if (RuntimeFeature.IsNativeAotRuntime || RuntimeFeature.ManagedTypeMap) { - return new ManagedTypeManager (); + if (RuntimeFeature.IsNativeAotRuntime) { + return new TrimmableTypeMapTypeManager (); } return new AndroidTypeManager (args.jniAddNativeMethodRegistrationAttributePresent != 0); @@ -225,7 +225,7 @@ static void InitializeTrimmableTypeMapDataIfNeeded () static void RegisterTrimmableTypeMapNativeMethodsIfNeeded () { if (RuntimeFeature.TrimmableTypeMap) { - // TypeMapLoader.Initialize() only loads managed typemap data. Registering + // TypeMapLoader.Initialize() only loads typemap data. Registering // mono.android.Runtime natives requires JniRuntime.Current and its ClassLoader. TrimmableTypeMap.RegisterNativeMethods (); } diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeManager.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeManager.cs deleted file mode 100644 index 454bab0e1bb..00000000000 --- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeManager.cs +++ /dev/null @@ -1,194 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Reflection; -using Java.Interop; -using Java.Interop.Tools.TypeNameMappings; - -namespace Microsoft.Android.Runtime; - -class ManagedTypeManager : JniRuntime.JniTypeManager { - - const DynamicallyAccessedMemberTypes Constructors = DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors; - internal const DynamicallyAccessedMemberTypes Methods = DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods; - internal const DynamicallyAccessedMemberTypes MethodsAndPrivateNested = Methods | DynamicallyAccessedMemberTypes.NonPublicNestedTypes; - - public ManagedTypeManager () - { - } - - [return: DynamicallyAccessedMembers (Constructors)] - protected override Type? GetInvokerTypeCore ( - [DynamicallyAccessedMembers (Constructors)] - Type type) - { - const string suffix = "Invoker"; - - // https://github.com/xamarin/xamarin-android/blob/5472eec991cc075e4b0c09cd98a2331fb93aa0f3/src/Microsoft.Android.Sdk.ILLink/MarkJavaObjects.cs#L176-L186 - const string assemblyGetTypeMessage = "'Invoker' types are preserved by the MarkJavaObjects trimmer step."; - const string makeGenericTypeMessage = "Generic 'Invoker' types are preserved by the MarkJavaObjects trimmer step."; - - [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = assemblyGetTypeMessage)] - [UnconditionalSuppressMessage ("Trimming", "IL2073", Justification = assemblyGetTypeMessage)] - [return: DynamicallyAccessedMembers (Constructors)] - static Type? AssemblyGetType (Assembly assembly, string typeName) => - assembly.GetType (typeName); - - [UnconditionalSuppressMessage ("Trimming", "IL2055", Justification = makeGenericTypeMessage)] - [return: DynamicallyAccessedMembers (Constructors)] - static Type MakeGenericType ( - [DynamicallyAccessedMembers (Constructors)] - Type type, - Type [] arguments) => - // FIXME: https://github.com/dotnet/java-interop/issues/1192 - #pragma warning disable IL3050 - type.MakeGenericType (arguments); - #pragma warning restore IL3050 - - Type[] arguments = type.GetGenericArguments (); - if (arguments.Length == 0) - return AssemblyGetType (type.Assembly, type + suffix) ?? base.GetInvokerTypeCore (type); - Type definition = type.GetGenericTypeDefinition (); - int bt = definition.FullName!.IndexOf ("`", StringComparison.Ordinal); - if (bt == -1) - throw new NotSupportedException ("Generic type doesn't follow generic type naming convention! " + type.FullName); - Type? suffixDefinition = AssemblyGetType (definition.Assembly, - definition.FullName.Substring (0, bt) + suffix + definition.FullName.Substring (bt)); - if (suffixDefinition == null) - return base.GetInvokerTypeCore (type); - return MakeGenericType (suffixDefinition, arguments); - } - - // NOTE: suppressions below also in `src/Mono.Android/Android.Runtime/AndroidRuntime.cs` - [UnconditionalSuppressMessage ("Trimming", "IL2057", Justification = "Type.GetType() can never statically know the string value parsed from parameter 'methods'.")] - [UnconditionalSuppressMessage ("Trimming", "IL2067", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")] - [UnconditionalSuppressMessage ("Trimming", "IL2072", Justification = "Delegate.CreateDelegate() can never statically know the string value parsed from parameter 'methods'.")] - public override void RegisterNativeMembers ( - JniType nativeClass, - [DynamicallyAccessedMembers (MethodsAndPrivateNested)] - Type type, - ReadOnlySpan methods) - { - if (methods.IsEmpty) { - base.RegisterNativeMembers (nativeClass, type, methods); - return; - } - - int methodCount = CountMethods (methods); - if (methodCount < 1) { - base.RegisterNativeMembers (nativeClass, type, methods); - return; - } - - JniNativeMethodRegistration [] natives = new JniNativeMethodRegistration [methodCount]; - int nativesIndex = 0; - - ReadOnlySpan methodsSpan = methods; - bool needToRegisterNatives = false; - - while (!methodsSpan.IsEmpty) { - int newLineIndex = methodsSpan.IndexOf ('\n'); - - ReadOnlySpan methodLine = methodsSpan.Slice (0, newLineIndex != -1 ? newLineIndex : methodsSpan.Length); - if (!methodLine.IsEmpty) { - SplitMethodLine (methodLine, - out ReadOnlySpan name, - out ReadOnlySpan signature, - out ReadOnlySpan callbackString, - out ReadOnlySpan callbackDeclaringTypeString); - - Delegate? callback = null; - if (callbackString.SequenceEqual ("__export__")) { - throw new InvalidOperationException (FormattableString.Invariant ($"Methods such as {callbackString.ToString ()} are not implemented!")); - } else { - Type callbackDeclaringType = type; - if (!callbackDeclaringTypeString.IsEmpty) { - callbackDeclaringType = Type.GetType (callbackDeclaringTypeString.ToString (), throwOnError: true)!; - } - while (callbackDeclaringType.ContainsGenericParameters) { - callbackDeclaringType = callbackDeclaringType.BaseType!; - } - - GetCallbackHandler connector = (GetCallbackHandler) Delegate.CreateDelegate (typeof (GetCallbackHandler), - callbackDeclaringType, callbackString.ToString ()); - callback = connector (); - } - - if (callback != null) { - needToRegisterNatives = true; - natives [nativesIndex++] = new JniNativeMethodRegistration (name.ToString (), signature.ToString (), callback); - } - } - - methodsSpan = newLineIndex != -1 ? methodsSpan.Slice (newLineIndex + 1) : default; - } - - if (needToRegisterNatives) { - JniEnvironment.Types.RegisterNatives (nativeClass.PeerReference, natives, nativesIndex); - } - } - - - protected override IEnumerable GetTypesForSimpleReference (string jniSimpleReference) - { - // Base class contains built-in mappings (e.g. java/lang/String → System.String) - // which must take priority over ManagedTypeMapping (which would return Java.Lang.String). - foreach (var t in base.GetTypesForSimpleReference (jniSimpleReference)) { - yield return t; - } - if (ManagedTypeMapping.TryGetType (jniSimpleReference, out var target)) { - yield return target; - } - } - - protected override IEnumerable GetSimpleReferences (Type type) - { - foreach (var r in base.GetSimpleReferences (type)) { - yield return r; - } - - if (ManagedTypeMapping.TryGetJniName (type, out var jniName)) { - yield return jniName; - } - } - - protected override IReadOnlyList? GetStaticMethodFallbackTypesCore (string jniSimpleReference) - { - return JniRemappingLookup.GetStaticMethodFallbackTypes (jniSimpleReference, useReplacementTypes: false); - } - - static int CountMethods (ReadOnlySpan methodsSpan) - { - int count = 0; - while (!methodsSpan.IsEmpty) { - count++; - - int newLineIndex = methodsSpan.IndexOf ('\n'); - methodsSpan = newLineIndex != -1 ? methodsSpan.Slice (newLineIndex + 1) : default; - } - return count; - } - - static void SplitMethodLine ( - ReadOnlySpan methodLine, - out ReadOnlySpan name, - out ReadOnlySpan signature, - out ReadOnlySpan callback, - out ReadOnlySpan callbackDeclaringType) - { - int colonIndex = methodLine.IndexOf (':'); - name = methodLine.Slice (0, colonIndex); - methodLine = methodLine.Slice (colonIndex + 1); - - colonIndex = methodLine.IndexOf (':'); - signature = methodLine.Slice (0, colonIndex); - methodLine = methodLine.Slice (colonIndex + 1); - - colonIndex = methodLine.IndexOf (':'); - callback = methodLine.Slice (0, colonIndex != -1 ? colonIndex : methodLine.Length); - - callbackDeclaringType = colonIndex != -1 ? methodLine.Slice (colonIndex + 1) : default; - } - - delegate Delegate GetCallbackHandler (); -} diff --git a/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeMapping.cs b/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeMapping.cs deleted file mode 100644 index 3cc7d790342..00000000000 --- a/src/Mono.Android/Microsoft.Android.Runtime/ManagedTypeMapping.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Buffers.Binary; -using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; -using System.IO.Hashing; -using System.Runtime.InteropServices; -using System.Text; -using Android.Runtime; - -namespace Microsoft.Android.Runtime; - -internal static class ManagedTypeMapping -{ - internal static bool TryGetType (string jniName, [NotNullWhen (true)] out Type? type) - { - type = null; - - // the hashes array is sorted and all the hashes are unique - ulong jniNameHash = Hash (jniName); - int jniNameHashIndex = MemoryExtensions.BinarySearch (JniNameHashes, jniNameHash); - if (jniNameHashIndex < 0) { - return false; - } - - // we need to make sure if this is the right match or if it is a hash collision - if (jniName != GetJniNameByJniNameHashIndex (jniNameHashIndex)) { - return false; - } - - type = GetTypeByJniNameHashIndex (jniNameHashIndex); - if (type is null) { - throw new InvalidOperationException ($"Type for {jniName} (hash: {jniNameHash}, index: {jniNameHashIndex}) not found."); - } - - return true; - } - - internal static bool TryGetJniName (Type type, [NotNullWhen (true)] out string? jniName) - { - jniName = null; - - string? assemblyQualifiedName = type.AssemblyQualifiedName; - if (assemblyQualifiedName is null) { - jniName = null; - return false; - } - - ReadOnlySpan typeName = GetSimplifiedAssemblyQualifiedTypeName (assemblyQualifiedName); - - // the hashes array is sorted and all the hashes are unique - ulong typeNameHash = Hash (typeName); - int typeNameHashIndex = MemoryExtensions.BinarySearch (TypeNameHashes, typeNameHash); - if (typeNameHashIndex < 0) { - return false; - } - - // we need to make sure if this is the match or if it is a hash collision - if (!typeName.SequenceEqual (GetTypeNameByTypeNameHashIndex (typeNameHashIndex))) { - return false; - } - - jniName = GetJniNameByTypeNameHashIndex (typeNameHashIndex); - if (jniName is null) { - throw new InvalidOperationException ($"JNI name for {typeName} (hash: {typeNameHash}, index: {typeNameHashIndex}) not found."); - } - - return true; - } - - private static ulong Hash (ReadOnlySpan value) - { - ReadOnlySpan bytes = MemoryMarshal.AsBytes (value); - ulong hash = XxHash3.HashToUInt64 (bytes); - - // The bytes in the hashes array are stored as little endian. If the target platform is big endian, - // we need to reverse the endianness of the hash. - if (!BitConverter.IsLittleEndian) { - hash = BinaryPrimitives.ReverseEndianness (hash); - } - - return hash; - } - - // This method keeps only the full type name and the simple assembly name. - // It drops the version, culture, and public key information. - // - // For example: "System.Int32, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e" - // becomes: "System.Int32, System.Private.CoreLib" - private static ReadOnlySpan GetSimplifiedAssemblyQualifiedTypeName(string assemblyQualifiedName) - { - var commaIndex = assemblyQualifiedName.IndexOf(','); - var secondCommaIndex = assemblyQualifiedName.IndexOf(',', startIndex: commaIndex + 1); - return secondCommaIndex < 0 - ? assemblyQualifiedName - : assemblyQualifiedName.AsSpan(0, secondCommaIndex); - } - - // Replaced by src/Microsoft.Android.Sdk.ILLink/TypeMappingStep.cs - private static ReadOnlySpan TypeNameHashes => throw new NotImplementedException (); - private static Type? GetTypeByJniNameHashIndex (int jniNameHashIndex) => throw new NotImplementedException (); - private static string? GetJniNameByJniNameHashIndex (int jniNameHashIndex) => throw new NotImplementedException (); - - private static ReadOnlySpan JniNameHashes => throw new NotImplementedException (); - private static string? GetJniNameByTypeNameHashIndex (int typeNameHashIndex) => throw new NotImplementedException (); - private static string? GetTypeNameByTypeNameHashIndex (int typeNameHashIndex) => throw new NotImplementedException (); -} diff --git a/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs b/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs index 5d20f9e5ac4..f15a79ff6f4 100644 --- a/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs +++ b/src/Mono.Android/Microsoft.Android.Runtime/RuntimeFeature.cs @@ -5,7 +5,6 @@ namespace Microsoft.Android.Runtime; static class RuntimeFeature { - const bool ManagedTypeMapEnabledByDefault = false; const bool IsMonoRuntimeEnabledByDefault = true; const bool IsCoreClrRuntimeEnabledByDefault = false; const bool IsNativeAotRuntimeEnabledByDefault = false; @@ -17,10 +16,6 @@ static class RuntimeFeature const string FeatureSwitchPrefix = "Microsoft.Android.Runtime.RuntimeFeature."; const string StartupHookProviderSwitch = "System.StartupHookProvider.IsSupported"; - [FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}")] - internal static bool ManagedTypeMap { get; } = - AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (ManagedTypeMap)}", out bool isEnabled) ? isEnabled : ManagedTypeMapEnabledByDefault; - [FeatureSwitchDefinition ($"{FeatureSwitchPrefix}{nameof (IsMonoRuntime)}")] internal static bool IsMonoRuntime { get; } = AppContext.TryGetSwitch ($"{FeatureSwitchPrefix}{nameof (IsMonoRuntime)}", out bool isEnabled) ? isEnabled : IsMonoRuntimeEnabledByDefault; diff --git a/src/Mono.Android/Mono.Android.csproj b/src/Mono.Android/Mono.Android.csproj index 611ef7edf07..0b21238d63d 100644 --- a/src/Mono.Android/Mono.Android.csproj +++ b/src/Mono.Android/Mono.Android.csproj @@ -363,8 +363,6 @@ - - diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets index e145c311485..53f153a8720 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.NativeAOT.targets @@ -17,7 +17,7 @@ This file contains the NativeAOT-specific MSBuild logic for .NET for Android. <_AndroidRuntimePackRuntime>NativeAOT <_AndroidUseWorkloadNativeLinker Condition=" '$(_AndroidUseWorkloadNativeLinker)' == '' ">true <_AndroidJcwCodegenTarget Condition=" '$(_AndroidJcwCodegenTarget)' == '' ">JavaInterop1 - <_AndroidTypeMapImplementation Condition=" '$(_AndroidTypeMapImplementation)' == '' ">managed + <_AndroidTypeMapImplementation Condition=" '$(_AndroidTypeMapImplementation)' == '' ">trimmable true diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets index 276cc236459..fe4db586982 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.RuntimeConfig.targets @@ -12,7 +12,6 @@ See: https://github.com/dotnet/runtime/blob/b13715b6984889a709ba29ea8a1961db469f <_BinaryRuntimeConfigPath>$(IntermediateOutputPath)$(ProjectRuntimeConfigFileName).bin - <_AndroidUseManagedTypeMap Condition=" '$(_AndroidTypeMapImplementation)' == 'managed' ">true <_AndroidEnableObjectReferenceLogging Condition=" '$(_AndroidEnableObjectReferenceLogging)' == '' And '$(PublishTrimmed)' == 'true' ">false @@ -54,10 +53,6 @@ See: https://github.com/dotnet/runtime/blob/b13715b6984889a709ba29ea8a1961db469f Value="$(AndroidAvoidEmitForPerformance)" Trim="true" /> - @@ -165,7 +164,6 @@ --> <_TrimmerDumpDependencies Condition=" '$(LinkerDumpDependencies)' == 'true' ">true <_AndroidLinkerCustomStepAssembly>$(MSBuildThisFileDirectory)..\tools\Microsoft.Android.Sdk.ILLink.dll - <_SystemIOHashingAssemblyPath>$(MSBuildThisFileDirectory)..\tools\System.IO.Hashing.dll <_ProguardProjectConfiguration Condition=" '$(AndroidLinkTool)' != '' ">$(IntermediateOutputPath)proguard\proguard_project_references.cfg @@ -174,7 +172,6 @@ https://github.com/dotnet/sdk/blob/a5393731b5b7b225692fff121f747fbbc9e8b140/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.ILLink.targets#L147 --> <_TrimmerCustomData Include="AndroidCustomViewMapFile" Value="$(_OuterCustomViewMapFile)" /> - <_TrimmerCustomData Include="SystemIOHashingAssemblyPath" Value="$(_SystemIOHashingAssemblyPath)" /> - <_TrimmerCustomSteps - Condition=" '$(_AndroidTypeMapImplementation)' == 'managed' " - Include="$(_AndroidLinkerCustomStepAssembly)" - AfterStep="CleanStep" - Type="Microsoft.Android.Sdk.ILLink.TypeMappingStep" - /> + diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs index 1d6dfb5a434..b703e39d30d 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateTypeMappings.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using Java.Interop.Tools.Cecil; using Microsoft.Android.Build.Tasks; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; @@ -39,8 +38,6 @@ public class GenerateTypeMappings : AndroidTask [Required] public string [] SupportedAbis { get; set; } = []; - public string TypemapImplementation { get; set; } = "llvm-ir"; - [Required] public string TypemapOutputDirectory { get; set; } = ""; @@ -53,7 +50,7 @@ public override bool RunTask () androidRuntime = MonoAndroidHelper.ParseAndroidRuntime (AndroidRuntime); if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) { - // NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep` + // NativeAOT uses the trimmable typemap. Log.LogDebugMessage ("Skipping type maps for NativeAOT."); return !Log.HasLoggedErrors; } @@ -89,11 +86,6 @@ void GenerateTypeMap (AndroidTargetArch arch, List assemblies) if (state is null) return; - if (TypemapImplementation != "llvm-ir") { - Log.LogDebugMessage ($"TypemapImplementation='{TypemapImplementation}' will write an empty native typemap."); - state.XmlFiles.Clear (); - } - var tmg = new TypeMapGenerator (Log, state, androidRuntime); tmg.Generate (Debug, SkipJniAddNativeMethodRegistrationAttributeScan, TypemapOutputDirectory); @@ -119,7 +111,7 @@ void GenerateAllTypeMappingsFromNativeState (bool useMarshalMethods) foreach (var kvp in nativeCodeGenStates) { NativeCodeGenState state = kvp.Value; templateCodeGenState = state; - GenerateTypeMapFromNativeState (state, useMarshalMethods); + GenerateTypeMapFromNativeState (state); } if (templateCodeGenState is null) @@ -130,20 +122,15 @@ void GenerateAllTypeMappingsFromNativeState (bool useMarshalMethods) NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent = templateCodeGenState.JniAddNativeMethodRegistrationAttributePresent; } - void GenerateTypeMapFromNativeState (NativeCodeGenState state, bool useMarshalMethods) + void GenerateTypeMapFromNativeState (NativeCodeGenState state) { if (androidRuntime == Xamarin.Android.Tasks.AndroidRuntime.NativeAOT) { - // NativeAOT typemaps are generated in `Microsoft.Android.Sdk.ILLink.TypeMappingStep` + // NativeAOT uses the trimmable typemap. Log.LogDebugMessage ("Skipping type maps for NativeAOT."); return; } Log.LogDebugMessage ($"Generating type maps from native state for architecture '{state.TargetArch}'"); - if (TypemapImplementation != "llvm-ir") { - Log.LogDebugMessage ($"TypemapImplementation='{TypemapImplementation}' will write an empty native typemap."); - state = new NativeCodeGenState (state.TargetArch, new TypeDefinitionCache (), state.Resolver, [], [], state.Classifier); - } - var tmg = new TypeMapGenerator (Log, new NativeCodeGenStateAdapter (state), androidRuntime); tmg.Generate (Debug, SkipJniAddNativeMethodRegistrationAttributeScan, TypemapOutputDirectory); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs index 05a317d6669..76f3c3110e4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest2.cs @@ -166,15 +166,13 @@ public void NativeAOT () ProjectName = "Hello", }; proj.SetRuntime (AndroidRuntime.NativeAOT); - proj.SetProperty ("_ExtraTrimmerArgs", "--verbose"); - // Required for java/util/ArrayList assertion below + // Exercise typemap generation for framework generic mappings. proj.MainActivity = proj.DefaultMainActivity .Replace ("//${AFTER_ONCREATE}", "new Android.Runtime.JavaList (); new Android.Runtime.JavaList ();"); using var b = CreateApkBuilder (); Assert.IsTrue (b.Build (proj), "Build should have succeeded."); - b.Output.AssertTargetIsNotSkipped ("_PrepareLinking"); string [] mono_classes = [ "Lmono/MonoRuntimeProvider;", @@ -191,66 +189,9 @@ public void NativeAOT () var intermediate = Path.Combine (Root, b.ProjectDirectory, proj.IntermediateOutputPath); var output = Path.Combine (Root, b.ProjectDirectory, proj.OutputPath); - var linkedMonoAndroidAssembly = Path.Combine (intermediate, "android-arm64", "linked", "Mono.Android.dll"); - FileAssert.Exists (linkedMonoAndroidAssembly); - var javaClassNames = new List (); - var types = new List (); - - using (var assembly = AssemblyDefinition.ReadAssembly (linkedMonoAndroidAssembly)) { - var typeName = "Android.App.Activity"; - var methodName = "GetOnCreate_Landroid_os_Bundle_Handler"; - var type = assembly.MainModule.GetType (typeName); - Assert.IsNotNull (type, $"{linkedMonoAndroidAssembly} should contain {typeName}"); - var method = type.Methods.FirstOrDefault (m => m.Name == methodName); - Assert.IsNotNull (method, $"{linkedMonoAndroidAssembly} should contain {typeName}.{methodName}"); - - type = assembly.MainModule.Types.FirstOrDefault (t => t.Name == "ManagedTypeMapping"); - Assert.IsNotNull (type, $"{linkedMonoAndroidAssembly} should contain ManagedTypeMapping"); - method = type.Methods.FirstOrDefault (m => m.Name == "GetJniNameByTypeNameHashIndex"); - Assert.IsNotNull (method, $"{type.Name} should contain GetJniNameByTypeNameHashIndex"); - - foreach (var i in method.Body.Instructions) { - if (i.OpCode != Mono.Cecil.Cil.OpCodes.Ldstr) - continue; - if (i.Operand is not string javaName) - continue; - if (i.Next.OpCode != Mono.Cecil.Cil.OpCodes.Ret) - continue; - javaClassNames.Add (javaName); - } - - method = type.Methods.FirstOrDefault (m => m.Name == "GetTypeByJniNameHashIndex"); - Assert.IsNotNull (method, $"{type.Name} should contain GetTypeByJniNameHashIndex"); - - foreach (var i in method.Body.Instructions) { - if (i.OpCode != Mono.Cecil.Cil.OpCodes.Ldtoken) - continue; - if (i.Operand is not TypeReference typeReference) - continue; - if (i.Next?.OpCode != Mono.Cecil.Cil.OpCodes.Call) - continue; - if (i.Next.Next?.OpCode != Mono.Cecil.Cil.OpCodes.Ret) - continue; - types.Add (typeReference); - } - - // Basic types - AssertTypeMap ("java/lang/Object", "Java.Lang.Object"); - AssertTypeMap ("java/lang/String", "Java.Lang.String"); - AssertTypeMap ("[Ljava/lang/Object;", "Java.Interop.JavaArray`1"); - AssertTypeMap ("java/util/ArrayList", "Android.Runtime.JavaList"); - AssertTypeMap ("android/app/Activity", "Android.App.Activity"); - AssertTypeMap ("android/widget/Button", "Android.Widget.Button"); - Assert.IsFalse (StringAssertEx.ContainsText (b.LastBuildOutput, - "Duplicate typemap entry for java/util/ArrayList => Android.Runtime.JavaList`1"), - "Should get log message about duplicate Android.Runtime.JavaList`1!"); - - // Special *Invoker case - AssertTypeMap ("android/view/View$OnClickListener", "Android.Views.View/IOnClickListener"); - Assert.IsFalse (StringAssertEx.ContainsText (b.LastBuildOutput, - "Duplicate typemap entry for android/view/View$OnClickListener => Android.Views.View/IOnClickListenerInvoker"), - "Should get log message about duplicate IOnClickListenerInvoker!"); - } + var typemapDir = Path.Combine (intermediate, "typemap"); + FileAssert.Exists (Path.Combine (typemapDir, "_Microsoft.Android.TypeMaps.dll")); + FileAssert.Exists (Path.Combine (typemapDir, "_Mono.Android.TypeMap.dll")); // Verify that Java stubs for Mono.Android.dll were generated, instead of using mono.android.jar/dex var onLayoutChangeListenerImplementor = Path.Combine (intermediate, "android", "src", "mono", "android", "view", "View_OnClickListenerImplementor.java"); @@ -271,18 +212,6 @@ public void NativeAOT () foreach (var nativeaot_file in nativeaot_files) { Assert.IsTrue (zip.ContainsEntry (nativeaot_file, caseSensitive: true), $"APK must contain `{nativeaot_file}`."); } - - void AssertTypeMap(string javaName, string managedName) - { - var javaNameIndex = javaClassNames.FindIndex (name => name == javaName); - var typeIndex = types.FindIndex (td => td.ToString() == managedName); - - if (javaNameIndex < 0) { - Assert.Fail ($"TypeMapping should contain \"{javaName}\"!"); - } else if (typeIndex < 0) { - Assert.Fail ($"TypeMapping should contain \"{managedName}\"!"); - } - } } [Test] diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index ea3cf49c141..41d5bacc865 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -2930,8 +2930,10 @@ because xbuild doesn't support framework reference assemblies. Condition=" '$(DesignTimeBuild)' != 'true' "/> - + + + Condition=" '$(_AndroidTypeMapImplementation)' == 'llvm-ir' " /> diff --git a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs index 5eae82b12ce..103f0856749 100644 --- a/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs +++ b/tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs @@ -51,9 +51,6 @@ static IEnumerable Get_DotNetRun_Data () foreach (AndroidRuntime runtime in Enum.GetValues (typeof (AndroidRuntime))) { AddTestData (true, "llvm-ir", runtime); AddTestData (false, "llvm-ir", runtime); - AddTestData (true, "managed", runtime); - // NOTE: TypeMappingStep is not yet setup for Debug mode - //AddTestData (false, "managed", runtime); } return ret; @@ -82,7 +79,7 @@ public void DotNetRun (bool isRelease, string typemapImplementation, AndroidRunt // Input file "obj/Release/build.props" is newer than output file "obj/Release/stamp/_GeneratePackageManagerJava.stamp". // if (runtime == AndroidRuntime.MonoVM && isRelease) { - Assert.Ignore ("dotnet run --no-build breaks marshal methods (both managed and llvm-ir) on MonoVM"); + Assert.Ignore ("dotnet run --no-build breaks marshal methods on MonoVM"); } if (runtime == AndroidRuntime.NativeAOT && typemapImplementation == "llvm-ir") { diff --git a/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.NET.csproj b/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.NET.csproj index 14d29d76d54..577d32dd347 100644 --- a/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.NET.csproj +++ b/tests/Mono.Android-Tests/Java.Interop-Tests/Java.Interop-Tests.NET.csproj @@ -42,9 +42,9 @@ - - + + diff --git a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs index 764fc416379..b1e2e2fabe3 100644 --- a/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs +++ b/tests/Mono.Android-Tests/Mono.Android-Tests/Java.Lang/ObjectTest.cs @@ -86,7 +86,7 @@ public void NestedDisposeInvocations () value.Dispose (); } - // TODO: fix on CoreCLR once new managed type maps are implemented. Currently fails with + // TODO: fix on CoreCLR once the typemap behavior is fixed. Currently fails with // java/lang/Object is typemap'd to Java.InteropTests.JavaLangRemappingTestObject, not Java.Lang.Object, Mono.Android! [Test] public void java_lang_Object_Is_Java_Lang_Object ()