diff --git a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs index 8907992aa53..aaa8823deed 100644 --- a/src/Mono.Android/Android.Runtime/AndroidRuntime.cs +++ b/src/Mono.Android/Android.Runtime/AndroidRuntime.cs @@ -243,7 +243,7 @@ public override void DeleteWeakGlobalReference (ref JniObjectReference value) } class AndroidTypeManager : JniRuntime.JniTypeManager { - struct MAMReplacementMethod + struct JniRemappingReplacementMethod { public string target_type; public string target_name; @@ -329,7 +329,7 @@ protected override IEnumerable GetSimpleReferences (Type type) protected override string? GetReplacementTypeCore (string jniSimpleReference) { - if (!JNIEnv.mamInUse) { + if (!JNIEnv.jniRemappingInUse) { return null; } @@ -346,7 +346,7 @@ protected override IEnumerable GetSimpleReferences (Type type) protected override JniRuntime.ReplacementMethodInfo? GetReplacementMethodInfoCore (string jniSourceType, string jniMethodName, string jniMethodSignature) { - if (!JNIEnv.mamInUse) { + if (!JNIEnv.jniRemappingInUse) { return null; } @@ -355,8 +355,8 @@ protected override IEnumerable GetSimpleReferences (Type type) return null; } - var method = new MAMReplacementMethod (); - method = Marshal.PtrToStructure(retInfo); + var method = new JniRemappingReplacementMethod (); + method = Marshal.PtrToStructure(retInfo); int? paramCount = null; if (method.is_static) { diff --git a/src/Mono.Android/Android.Runtime/JNIEnv.cs b/src/Mono.Android/Android.Runtime/JNIEnv.cs index 775a79d984d..36c2e476340 100644 --- a/src/Mono.Android/Android.Runtime/JNIEnv.cs +++ b/src/Mono.Android/Android.Runtime/JNIEnv.cs @@ -35,7 +35,7 @@ struct JnienvInitializeArgs { public int packageNamingPolicy; public byte ioExceptionType; public int jniAddNativeMethodRegistrationAttributePresent; - public bool mamInUse; + public bool jniRemappingInUse; } #pragma warning restore 0649 @@ -49,7 +49,7 @@ public static partial class JNIEnv { static int androidSdkVersion; static bool AllocObjectSupported; - internal static bool mamInUse; + internal static bool jniRemappingInUse; static IntPtr grefIGCUserPeer_class; @@ -157,7 +157,7 @@ internal static unsafe void Initialize (JnienvInitializeArgs* args) gref_gc_threshold = args->grefGcThreshold; - mamInUse = args->mamInUse; + jniRemappingInUse = args->jniRemappingInUse; java_vm = args->javaVm; version = args->version; diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMamNativeCode.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJniRemappingNativeCode.cs similarity index 74% rename from src/Xamarin.Android.Build.Tasks/Tasks/GenerateMamNativeCode.cs rename to src/Xamarin.Android.Build.Tasks/Tasks/GenerateJniRemappingNativeCode.cs index daa01fc72a1..2c22150f41e 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GenerateMamNativeCode.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GenerateJniRemappingNativeCode.cs @@ -9,22 +9,23 @@ namespace Xamarin.Android.Tasks { - public class GenerateMamNativeCode : AndroidTask + public class GenerateJniRemappingNativeCode : AndroidTask { - internal const string MamNativeCodeInfoKey = ".:!MamNativeCodeInfo!:."; - internal sealed class MamNativeCodeInfo + internal const string JniRemappingNativeCodeInfoKey = ".:!JniRemappingNativeCodeInfo!:."; + + internal sealed class JniRemappingNativeCodeInfo { public int ReplacementTypeCount { get; } public int ReplacementMethodIndexEntryCount { get; } - public MamNativeCodeInfo (int replacementTypeCount, int replacementMethodIndexEntryCount) + public JniRemappingNativeCodeInfo (int replacementTypeCount, int replacementMethodIndexEntryCount) { ReplacementTypeCount = replacementTypeCount; ReplacementMethodIndexEntryCount = replacementMethodIndexEntryCount; } } - public override string TaskPrefix => "GMAMNC"; + public override string TaskPrefix => "GJRNC"; public ITaskItem RemappingXmlFilePath { get; set; } @@ -53,13 +54,13 @@ public override bool RunTask () void GenerateEmpty () { - Generate (new MamRemappingAssemblyGenerator (), typeReplacementsCount: 0); + Generate (new JniRemappingAssemblyGenerator (), typeReplacementsCount: 0); } void Generate () { - var typeReplacements = new List (); - var methodReplacements = new List (); + var typeReplacements = new List (); + var methodReplacements = new List (); var readerSettings = new XmlReaderSettings { XmlResolver = null, @@ -73,32 +74,32 @@ void Generate () } } - Generate (new MamRemappingAssemblyGenerator (typeReplacements, methodReplacements), typeReplacements.Count); + Generate (new JniRemappingAssemblyGenerator (typeReplacements, methodReplacements), typeReplacements.Count); } - void Generate (MamRemappingAssemblyGenerator mamGenerator, int typeReplacementsCount) + void Generate (JniRemappingAssemblyGenerator jniRemappingGenerator, int typeReplacementsCount) { - mamGenerator.Init (); + jniRemappingGenerator.Init (); foreach (string abi in SupportedAbis) { - string baseAsmFilePath = Path.Combine (OutputDirectory, $"mam_remap.{abi.ToLowerInvariant ()}"); + string baseAsmFilePath = Path.Combine (OutputDirectory, $"jni_remap.{abi.ToLowerInvariant ()}"); string llFilePath = $"{baseAsmFilePath}.ll"; using (var sw = MemoryStreamPool.Shared.CreateStreamWriter ()) { - mamGenerator.Write (GeneratePackageManagerJava.GetAndroidTargetArchForAbi (abi), sw, llFilePath); + jniRemappingGenerator.Write (GeneratePackageManagerJava.GetAndroidTargetArchForAbi (abi), sw, llFilePath); sw.Flush (); Files.CopyIfStreamChanged (sw.BaseStream, llFilePath); } } BuildEngine4.RegisterTaskObjectAssemblyLocal ( - MamNativeCodeInfoKey, - new MamNativeCodeInfo (typeReplacementsCount, mamGenerator.ReplacementMethodIndexEntryCount), + JniRemappingNativeCodeInfoKey, + new JniRemappingNativeCodeInfo (typeReplacementsCount, jniRemappingGenerator.ReplacementMethodIndexEntryCount), RegisteredTaskObjectLifetime.Build ); } - void ReadXml (XmlReader reader, List typeReplacements, List methodReplacements) + void ReadXml (XmlReader reader, List typeReplacements, List methodReplacements) { bool haveAllAttributes; @@ -115,7 +116,7 @@ void ReadXml (XmlReader reader, List typeReplacements, List< continue; } - typeReplacements.Add (new MamTypeReplacement (from, to)); + typeReplacements.Add (new JniRemappingTypeReplacement (from, to)); } else if (String.Compare ("replace-method", reader.LocalName, StringComparison.Ordinal) == 0) { haveAllAttributes &= GetRequiredAttribute ("source-type", out string sourceType); haveAllAttributes &= GetRequiredAttribute ("source-method-name", out string sourceMethodName); @@ -134,7 +135,7 @@ void ReadXml (XmlReader reader, List typeReplacements, List< string sourceMethodSignature = reader.GetAttribute ("source-method-signature"); methodReplacements.Add ( - new MamMethodReplacement ( + new JniRemappingMethodReplacement ( sourceType, sourceMethodName, sourceMethodSignature, targetType, targetMethodName, isStatic ) diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index 8505edf6ba7..a5db7a9d3f1 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -403,7 +403,7 @@ void AddEnvironment () bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); var appConfState = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ApplicationConfigTaskState.RegisterTaskObjectKey, RegisteredTaskObjectLifetime.Build); - var mamNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (GenerateMamNativeCode.MamNativeCodeInfoKey, RegisteredTaskObjectLifetime.Build); + var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey, RegisteredTaskObjectLifetime.Build); var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { IsBundledApp = IsBundledApplication, UsesMonoAOT = usesMonoAOT, @@ -430,8 +430,8 @@ void AddEnvironment () AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, JNIEnvInitializeToken = jnienv_initialize_method_token, JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, - MAMReplacementTypeCount = mamNativeCodeInfo == null ? 0 : mamNativeCodeInfo.ReplacementTypeCount, - MAMReplacementMethodIndexEntryCount = mamNativeCodeInfo == null ? 0 : mamNativeCodeInfo.ReplacementMethodIndexEntryCount, + JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, + JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, }; appConfigAsmGen.Init (); diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs b/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs index 049f3928626..1998dc9db52 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/PrepareAbiItems.cs @@ -14,7 +14,7 @@ public class PrepareAbiItems : AndroidTask const string TypeMapBase = "typemaps"; const string EnvBase = "environment"; const string CompressedAssembliesBase = "compressed_assemblies"; - const string MamBase = "mam_remap"; + const string JniRemappingBase = "jni_remap"; public override string TaskPrefix => "PAI"; @@ -51,8 +51,8 @@ public override bool RunTask () baseName = EnvBase; } else if (String.Compare ("compressed", Mode, StringComparison.OrdinalIgnoreCase) == 0) { baseName = CompressedAssembliesBase; - } else if (String.Compare ("mamremap", Mode, StringComparison.OrdinalIgnoreCase) == 0) { - baseName = MamBase; + } else if (String.Compare ("jniremap", Mode, StringComparison.OrdinalIgnoreCase) == 0) { + baseName = JniRemappingBase; } else { Log.LogError ($"Unknown mode: {Mode}"); return false; diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs index 4fca5480f53..32a2a3637fa 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Utilities/EnvironmentHelper.cs @@ -60,8 +60,8 @@ public sealed class ApplicationConfig public uint android_runtime_jnienv_class_token; public uint jnienv_initialize_method_token; public uint jnienv_registerjninatives_method_token; - public uint mam_replacement_type_count; - public uint mam_replacement_method_index_entry_count; + public uint jni_remapping_replacement_type_count; + public uint jni_remapping_replacement_method_index_entry_count; public uint mono_components_mask; public string android_package_name = String.Empty; } @@ -310,14 +310,14 @@ static ApplicationConfig ReadApplicationConfig (EnvironmentFile envFile) ret.number_of_dso_cache_entries = ConvertFieldToUInt32 ("jnienv_registerjninatives_method_token", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 21: // mam_replacement_type_count: uint32_t / .word | .long + case 21: // jni_remapping_replacement_type_count: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); - ret.mam_replacement_type_count = ConvertFieldToUInt32 ("mam_replacement_type_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + ret.jni_remapping_replacement_type_count = ConvertFieldToUInt32 ("jni_remapping_replacement_type_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; - case 22: // mam_replacement_method_index_entry_count: uint32_t / .word | .long + case 22: // jni_remapping_replacement_method_index_entry_count: uint32_t / .word | .long Assert.IsTrue (expectedUInt32Types.Contains (field [0]), $"Unexpected uint32_t field type in '{envFile.Path}:{item.LineNumber}': {field [0]}"); - ret.mam_replacement_method_index_entry_count = ConvertFieldToUInt32 ("mam_replacement_method_index_entry_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); + ret.jni_remapping_replacement_method_index_entry_count = ConvertFieldToUInt32 ("jni_remapping_replacement_method_index_entry_count", envFile.Path, parser.SourceFilePath, item.LineNumber, field [1]); break; case 23: // mono_components_mask: uint32_t / .word | .long diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs index d0d2a4bca41..369bc794b50 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfig.cs @@ -45,8 +45,8 @@ sealed class ApplicationConfig public uint android_runtime_jnienv_class_token; public uint jnienv_initialize_method_token; public uint jnienv_registerjninatives_method_token; - public uint mam_replacement_type_count; - public uint mam_replacement_method_index_entry_count; + public uint jni_remapping_replacement_type_count; + public uint jni_remapping_replacement_method_index_entry_count; public uint mono_components_mask; public string android_package_name = String.Empty; } diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs index e90bf6c59c6..eba20e9a5f2 100644 --- a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGenerator.cs @@ -170,8 +170,8 @@ sealed class XamarinAndroidBundledAssembly public int AndroidRuntimeJNIEnvToken { get; set; } public int JNIEnvInitializeToken { get; set; } public int JNIEnvRegisterJniNativesToken { get; set; } - public int MAMReplacementTypeCount { get; set; } - public int MAMReplacementMethodIndexEntryCount { get; set; } + public int JniRemappingReplacementTypeCount { get; set; } + public int JniRemappingReplacementMethodIndexEntryCount { get; set; } public MonoComponent MonoComponents { get; set; } public PackageNamingPolicy PackageNamingPolicy { get; set; } public List NativeLibraries { get; set; } @@ -214,8 +214,8 @@ public override void Init () android_runtime_jnienv_class_token = (uint)AndroidRuntimeJNIEnvToken, jnienv_initialize_method_token = (uint)JNIEnvInitializeToken, jnienv_registerjninatives_method_token = (uint)JNIEnvRegisterJniNativesToken, - mam_replacement_type_count = (uint)MAMReplacementTypeCount, - mam_replacement_method_index_entry_count = (uint)MAMReplacementMethodIndexEntryCount, + jni_remapping_replacement_type_count = (uint)JniRemappingReplacementTypeCount, + jni_remapping_replacement_method_index_entry_count = (uint)JniRemappingReplacementMethodIndexEntryCount, mono_components_mask = (uint)MonoComponents, android_package_name = AndroidPackageName, }; diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/JniRemappingAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/JniRemappingAssemblyGenerator.cs new file mode 100644 index 00000000000..486fd2f4c7e --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/JniRemappingAssemblyGenerator.cs @@ -0,0 +1,365 @@ +using System; +using System.Collections.Generic; +using System.Text; + +using Xamarin.Android.Tasks.LLVMIR; + +namespace Xamarin.Android.Tasks +{ + sealed class JniRemappingTypeReplacement + { + public string From { get; } + public string To { get; } + + public JniRemappingTypeReplacement (string from, string to) + { + From = from; + To = to; + } + } + + sealed class JniRemappingMethodReplacement + { + public string SourceType { get; } + public string SourceMethod { get; } + public string SourceMethodSignature { get; } + + public string TargetType { get; } + public string TargetMethod { get; } + + public bool TargetIsStatic { get; } + + public JniRemappingMethodReplacement (string sourceType, string sourceMethod, string sourceMethodSignature, + string targetType, string targetMethod, bool targetIsStatic) + { + SourceType = sourceType; + SourceMethod = sourceMethod; + SourceMethodSignature = sourceMethodSignature; + + TargetType = targetType; + TargetMethod = targetMethod; + TargetIsStatic = targetIsStatic; + } + } + + class JniRemappingAssemblyGenerator : LlvmIrComposer + { + sealed class JniRemappingTypeReplacementEntryContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override string GetComment (object data, string fieldName) + { + var entry = EnsureType(data); + + if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { + return $"name: {entry.name.str}"; + } + + if (String.Compare ("replacement", fieldName, StringComparison.Ordinal) == 0) { + return $"replacement: {entry.replacement}"; + } + + return String.Empty; + } + } + + sealed class JniRemappingIndexTypeEntryContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override string GetComment (object data, string fieldName) + { + var entry = EnsureType (data); + + if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { + return $"name: {entry.name.str}"; + } + + return String.Empty; + } + + public override string GetPointedToSymbolName (object data, string fieldName) + { + var entry = EnsureType (data); + + if (String.Compare ("methods", fieldName, StringComparison.Ordinal) == 0) { + return entry.MethodsArraySymbolName; + } + + return base.GetPointedToSymbolName (data, fieldName); + } + + public override ulong GetBufferSize (object data, string fieldName) + { + var entry = EnsureType (data); + if (String.Compare ("methods", fieldName, StringComparison.Ordinal) == 0) { + return (ulong)entry.TypeMethods.Count; + } + + return 0; + } + } + + sealed class JniRemappingIndexMethodEntryContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override string GetComment (object data, string fieldName) + { + var entry = EnsureType (data); + + if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { + return $"name: {entry.name.str}"; + } + + if (String.Compare ("replacement", fieldName, StringComparison.Ordinal) == 0) { + return $"replacement: {entry.replacement.target_type}.{entry.replacement.target_name}"; + } + + if (String.Compare ("signature", fieldName, StringComparison.Ordinal) == 0) { + if (entry.signature.length == 0) { + return String.Empty; + } + + return $"signature: {entry.signature.str}"; + } + + return String.Empty; + } + } + + sealed class JniRemappingString + { + public uint length; + public string str; + }; + + sealed class JniRemappingReplacementMethod + { + public string target_type; + public string target_name; + public bool is_static; + }; + + [NativeAssemblerStructContextDataProvider (typeof(JniRemappingIndexMethodEntryContextDataProvider))] + sealed class JniRemappingIndexMethodEntry + { + [NativeAssembler (UsesDataProvider = true)] + public JniRemappingString name; + + [NativeAssembler (UsesDataProvider = true)] + public JniRemappingString signature; + + [NativeAssembler (UsesDataProvider = true)] + public JniRemappingReplacementMethod replacement; + }; + + [NativeAssemblerStructContextDataProvider (typeof(JniRemappingIndexTypeEntryContextDataProvider))] + sealed class JniRemappingIndexTypeEntry + { + [NativeAssembler (UsesDataProvider = true)] + public JniRemappingString name; + public uint method_count; + + [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToSymbol = "")] + public JniRemappingIndexMethodEntry methods; + + [NativeAssembler (Ignore = true)] + public string MethodsArraySymbolName; + + [NativeAssembler (Ignore = true)] + public List> TypeMethods; + }; + + [NativeAssemblerStructContextDataProvider (typeof(JniRemappingTypeReplacementEntryContextDataProvider))] + sealed class JniRemappingTypeReplacementEntry + { + [NativeAssembler (UsesDataProvider = true)] + public JniRemappingString name; + + [NativeAssembler (UsesDataProvider = true)] + public string replacement; + }; + + List typeReplacementsInput; + List methodReplacementsInput; + + StructureInfo jniRemappingStringStructureInfo; + StructureInfo jniRemappingReplacementMethodStructureInfo; + StructureInfo jniRemappingIndexMethodEntryStructureInfo; + StructureInfo jniRemappingIndexTypeEntryStructureInfo; + StructureInfo jniRemappingTypeReplacementEntryStructureInfo; + + List> typeReplacements; + List> methodIndexTypes; + + public int ReplacementMethodIndexEntryCount { get; private set; } = 0; + + public JniRemappingAssemblyGenerator () + {} + + public JniRemappingAssemblyGenerator (List typeReplacements, List methodReplacements) + { + this.typeReplacementsInput = typeReplacements ?? throw new ArgumentNullException (nameof (typeReplacements)); + this.methodReplacementsInput = methodReplacements ?? throw new ArgumentNullException (nameof (methodReplacements)); + } + + public override void Init () + { + if (typeReplacementsInput == null) { + return; + } + + typeReplacements = new List> (); + foreach (JniRemappingTypeReplacement mtr in typeReplacementsInput) { + var entry = new JniRemappingTypeReplacementEntry { + name = MakeJniRemappingString (mtr.From), + replacement = mtr.To, + }; + + typeReplacements.Add (new StructureInstance (entry)); + } + typeReplacements.Sort ((StructureInstance l, StructureInstance r) => l.Obj.name.str.CompareTo (r.Obj.name.str)); + + methodIndexTypes = new List> (); + var types = new Dictionary> (StringComparer.Ordinal); + + foreach (JniRemappingMethodReplacement mmr in methodReplacementsInput) { + if (!types.TryGetValue (mmr.SourceType, out StructureInstance typeEntry)) { + var entry = new JniRemappingIndexTypeEntry { + name = MakeJniRemappingString (mmr.SourceType), + MethodsArraySymbolName = MakeMethodsArrayName (mmr.SourceType), + TypeMethods = new List> (), + }; + + typeEntry = new StructureInstance (entry); + methodIndexTypes.Add (typeEntry); + types.Add (mmr.SourceType, typeEntry); + } + + var method = new JniRemappingIndexMethodEntry { + name = MakeJniRemappingString (mmr.SourceMethod), + signature = MakeJniRemappingString (mmr.SourceMethodSignature), + replacement = new JniRemappingReplacementMethod { + target_type = mmr.TargetType, + target_name = mmr.TargetMethod, + is_static = mmr.TargetIsStatic, + }, + }; + + typeEntry.Obj.TypeMethods.Add (new StructureInstance (method)); + } + + foreach (var kvp in types) { + kvp.Value.Obj.method_count = (uint)kvp.Value.Obj.TypeMethods.Count; + kvp.Value.Obj.TypeMethods.Sort ((StructureInstance l, StructureInstance r) => l.Obj.name.str.CompareTo (r.Obj.name.str)); + } + + methodIndexTypes.Sort ((StructureInstance l, StructureInstance r) => l.Obj.name.str.CompareTo (r.Obj.name.str)); + ReplacementMethodIndexEntryCount = methodIndexTypes.Count; + + string MakeMethodsArrayName (string typeName) + { + return $"mm_{typeName.Replace ('/', '_')}"; + } + + JniRemappingString MakeJniRemappingString (string str) + { + return new JniRemappingString { + length = GetLength (str), + str = str, + }; + } + } + + uint GetLength (string str) + { + if (String.IsNullOrEmpty (str)) { + return 0; + } + + return (uint)Encoding.UTF8.GetBytes (str).Length; + } + + protected override void MapStructures (LlvmIrGenerator generator) + { + jniRemappingStringStructureInfo = generator.MapStructure (); + jniRemappingReplacementMethodStructureInfo = generator.MapStructure (); + jniRemappingIndexMethodEntryStructureInfo = generator.MapStructure (); + jniRemappingIndexTypeEntryStructureInfo = generator.MapStructure (); + jniRemappingTypeReplacementEntryStructureInfo = generator.MapStructure (); + } + + void WriteNestedStructure (LlvmIrGenerator generator, LlvmIrGenerator.StructureBodyWriterOptions bodyWriterOptions, Type structureType, object fieldInstance) + { + if (fieldInstance == null) { + return; + } + + if (structureType == typeof (JniRemappingString)) { + generator.WriteNestedStructure (jniRemappingStringStructureInfo, new StructureInstance ((JniRemappingString)fieldInstance), bodyWriterOptions); + return; + } + + if (structureType == typeof (JniRemappingReplacementMethod)) { + generator.WriteNestedStructure (jniRemappingReplacementMethodStructureInfo, new StructureInstance ((JniRemappingReplacementMethod)fieldInstance), bodyWriterOptions); + return; + } + + if (structureType == typeof (JniRemappingIndexTypeEntry)) { + generator.WriteNestedStructure (jniRemappingIndexTypeEntryStructureInfo, new StructureInstance ((JniRemappingIndexTypeEntry)fieldInstance), bodyWriterOptions); + } + + if (structureType == typeof (JniRemappingIndexMethodEntry)) { + generator.WriteNestedStructure (jniRemappingIndexMethodEntryStructureInfo, new StructureInstance ((JniRemappingIndexMethodEntry)fieldInstance), bodyWriterOptions); + } + + throw new InvalidOperationException ($"Unsupported nested structure type {structureType}"); + } + + protected override void Write (LlvmIrGenerator generator) + { + generator.WriteEOL (); + generator.WriteEOL ("JNI remapping data"); + + if (typeReplacements == null) { + generator.WriteStructureArray ( + jniRemappingTypeReplacementEntryStructureInfo, + 0, + LlvmIrVariableOptions.GlobalConstant, + "jni_remapping_type_replacements" + ); + + generator.WriteStructureArray ( + jniRemappingIndexTypeEntryStructureInfo, + 0, + LlvmIrVariableOptions.GlobalConstant, + "jni_remapping_method_replacement_index" + ); + + return; + } + + generator.WriteStructureArray ( + jniRemappingTypeReplacementEntryStructureInfo, + typeReplacements, + LlvmIrVariableOptions.GlobalConstant, + "jni_remapping_type_replacements", + nestedStructureWriter: WriteNestedStructure + ); + + foreach (StructureInstance entry in methodIndexTypes) { + generator.WriteStructureArray ( + jniRemappingIndexMethodEntryStructureInfo, + entry.Obj.TypeMethods, + LlvmIrVariableOptions.LocalConstant, + entry.Obj.MethodsArraySymbolName, + nestedStructureWriter: WriteNestedStructure + ); + } + + generator.WriteStructureArray ( + jniRemappingIndexTypeEntryStructureInfo, + methodIndexTypes, + LlvmIrVariableOptions.GlobalConstant, + "jni_remapping_method_replacement_index", + nestedStructureWriter: WriteNestedStructure + ); + } + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/MamRemappingAssemblyGenerator.cs b/src/Xamarin.Android.Build.Tasks/Utilities/MamRemappingAssemblyGenerator.cs deleted file mode 100644 index 00a1746c2ad..00000000000 --- a/src/Xamarin.Android.Build.Tasks/Utilities/MamRemappingAssemblyGenerator.cs +++ /dev/null @@ -1,381 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -using Xamarin.Android.Tasks.LLVMIR; - -namespace Xamarin.Android.Tasks -{ - sealed class MamTypeReplacement - { - public string From { get; } - public string To { get; } - - public MamTypeReplacement (string from, string to) - { - From = from; - To = to; - } - } - - sealed class MamMethodReplacement - { - public string SourceType { get; } - public string SourceMethod { get; } - public string SourceMethodSignature { get; } - - public string TargetType { get; } - public string TargetMethod { get; } - - public bool TargetIsStatic { get; } - - public MamMethodReplacement (string sourceType, string sourceMethod, string sourceMethodSignature, - string targetType, string targetMethod, bool targetIsStatic) - { - SourceType = sourceType; - SourceMethod = sourceMethod; - SourceMethodSignature = sourceMethodSignature; - - TargetType = targetType; - TargetMethod = targetMethod; - TargetIsStatic = targetIsStatic; - } - } - - class MamRemappingAssemblyGenerator : LlvmIrComposer - { - sealed class MAMTypeReplacementEntryContextDataProvider : NativeAssemblerStructContextDataProvider - { - public override string GetComment (object data, string fieldName) - { - var entry = EnsureType(data); - - if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { - return $"name: {entry.name.str}"; - } - - if (String.Compare ("replacement", fieldName, StringComparison.Ordinal) == 0) { - return $"replacement: {entry.replacement}"; - } - - return String.Empty; - } - } - - sealed class MAMIndexTypeEntryContextDataProvider : NativeAssemblerStructContextDataProvider - { - public override string GetComment (object data, string fieldName) - { - var entry = EnsureType (data); - - if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { - return $"name: {entry.name.str}"; - } - - return String.Empty; - } - - public override string GetPointedToSymbolName (object data, string fieldName) - { - var entry = EnsureType (data); - - if (String.Compare ("methods", fieldName, StringComparison.Ordinal) == 0) { - return entry.MethodsArraySymbolName; - } - - return base.GetPointedToSymbolName (data, fieldName); - } - - public override ulong GetBufferSize (object data, string fieldName) - { - var entry = EnsureType (data); - if (String.Compare ("methods", fieldName, StringComparison.Ordinal) == 0) { - return (ulong)entry.TypeMethods.Count; - } - - return 0; - } - } - - sealed class MAMIndexMethodEntryContextDataProvider : NativeAssemblerStructContextDataProvider - { - public override string GetComment (object data, string fieldName) - { - var entry = EnsureType (data); - - if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { - return $"name: {entry.name.str}"; - } - - if (String.Compare ("replacement", fieldName, StringComparison.Ordinal) == 0) { - return $"replacement: {entry.replacement.target_type}.{entry.replacement.target_name}"; - } - - if (String.Compare ("signature", fieldName, StringComparison.Ordinal) == 0) { - if (entry.signature.length == 0) { - return String.Empty; - } - - return $"signature: {entry.signature.str}"; - } - - return String.Empty; - } - } - - sealed class MAMString - { - public uint length; - public string str; - }; - - sealed class MAMReplacementMethod - { - public string target_type; - public string target_name; - public bool is_static; - }; - - [NativeAssemblerStructContextDataProvider (typeof(MAMIndexMethodEntryContextDataProvider))] - sealed class MAMIndexMethodEntry - { - [NativeAssembler (UsesDataProvider = true)] - public MAMString name; - - [NativeAssembler (UsesDataProvider = true)] - public MAMString signature; - - [NativeAssembler (UsesDataProvider = true)] - public MAMReplacementMethod replacement; - - public uint signature_return_type_offset; - }; - - [NativeAssemblerStructContextDataProvider (typeof(MAMIndexTypeEntryContextDataProvider))] - sealed class MAMIndexTypeEntry - { - [NativeAssembler (UsesDataProvider = true)] - public MAMString name; - public uint method_count; - - [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToSymbol = "")] - public MAMIndexMethodEntry methods; - - [NativeAssembler (Ignore = true)] - public string MethodsArraySymbolName; - - [NativeAssembler (Ignore = true)] - public List> TypeMethods; - }; - - [NativeAssemblerStructContextDataProvider (typeof(MAMTypeReplacementEntryContextDataProvider))] - sealed class MAMTypeReplacementEntry - { - [NativeAssembler (UsesDataProvider = true)] - public MAMString name; - - [NativeAssembler (UsesDataProvider = true)] - public string replacement; - }; - - List typeReplacementsInput; - List methodReplacementsInput; - - StructureInfo mamStringStructureInfo; - StructureInfo mamReplacementMethodStructureInfo; - StructureInfo mamIndexMethodEntryStructureInfo; - StructureInfo mamIndexTypeEntryStructureInfo; - StructureInfo mamTypeReplacementEntryStructureInfo; - - List> typeReplacements; - List> methodIndexTypes; - - public int ReplacementMethodIndexEntryCount { get; private set; } = 0; - - public MamRemappingAssemblyGenerator () - {} - - public MamRemappingAssemblyGenerator (List typeReplacements, List methodReplacements) - { - this.typeReplacementsInput = typeReplacements ?? throw new ArgumentNullException (nameof (typeReplacements)); - this.methodReplacementsInput = methodReplacements ?? throw new ArgumentNullException (nameof (methodReplacements)); - } - - public override void Init () - { - if (typeReplacementsInput == null) { - return; - } - - typeReplacements = new List> (); - foreach (MamTypeReplacement mtr in typeReplacementsInput) { - var entry = new MAMTypeReplacementEntry { - name = MakeMamString (mtr.From), - replacement = mtr.To, - }; - - typeReplacements.Add (new StructureInstance (entry)); - } - typeReplacements.Sort ((StructureInstance l, StructureInstance r) => l.Obj.name.str.CompareTo (r.Obj.name.str)); - - methodIndexTypes = new List> (); - var types = new Dictionary> (StringComparer.Ordinal); - - foreach (MamMethodReplacement mmr in methodReplacementsInput) { - if (!types.TryGetValue (mmr.SourceType, out StructureInstance typeEntry)) { - var entry = new MAMIndexTypeEntry { - name = MakeMamString (mmr.SourceType), - MethodsArraySymbolName = MakeMethodsArrayName (mmr.SourceType), - TypeMethods = new List> (), - }; - - typeEntry = new StructureInstance (entry); - methodIndexTypes.Add (typeEntry); - types.Add (mmr.SourceType, typeEntry); - } - - var method = new MAMIndexMethodEntry { - name = MakeMamString (mmr.SourceMethod), - signature = MakeMamString (mmr.SourceMethodSignature), - replacement = new MAMReplacementMethod { - target_type = mmr.TargetType, - target_name = mmr.TargetMethod, - is_static = mmr.TargetIsStatic, - }, - }; - - if (method.signature.length > 0) { - int idx = method.signature.str.IndexOf (')'); - if (idx == method.signature.str.Length - 1) { - // There's no return type, we can optimize lookups in this case and tell the native that there's no reason to check for a match to - // signature without return type. - idx = 0; - } - - method.signature_return_type_offset = (uint)(idx >= 0 ? idx : 0); - } else { - method.signature_return_type_offset = 0; - } - - typeEntry.Obj.TypeMethods.Add (new StructureInstance (method)); - } - - foreach (var kvp in types) { - kvp.Value.Obj.method_count = (uint)kvp.Value.Obj.TypeMethods.Count; - kvp.Value.Obj.TypeMethods.Sort ((StructureInstance l, StructureInstance r) => l.Obj.name.str.CompareTo (r.Obj.name.str)); - } - - methodIndexTypes.Sort ((StructureInstance l, StructureInstance r) => l.Obj.name.str.CompareTo (r.Obj.name.str)); - ReplacementMethodIndexEntryCount = methodIndexTypes.Count; - - string MakeMethodsArrayName (string typeName) - { - return $"mm_{typeName.Replace ('/', '_')}"; - } - - MAMString MakeMamString (string str) - { - return new MAMString { - length = GetLength (str), - str = str, - }; - } - } - - uint GetLength (string str) - { - if (String.IsNullOrEmpty (str)) { - return 0; - } - - return (uint)Encoding.UTF8.GetBytes (str).Length; - } - - protected override void MapStructures (LlvmIrGenerator generator) - { - mamStringStructureInfo = generator.MapStructure (); - mamReplacementMethodStructureInfo = generator.MapStructure (); - mamIndexMethodEntryStructureInfo = generator.MapStructure (); - mamIndexTypeEntryStructureInfo = generator.MapStructure (); - mamTypeReplacementEntryStructureInfo = generator.MapStructure (); - } - - void WriteNestedStructure (LlvmIrGenerator generator, LlvmIrGenerator.StructureBodyWriterOptions bodyWriterOptions, Type structureType, object fieldInstance) - { - if (fieldInstance == null) { - // TODO: write zeroinitializer - return; - } - - if (structureType == typeof (MAMString)) { - generator.WriteNestedStructure (mamStringStructureInfo, new StructureInstance ((MAMString)fieldInstance), bodyWriterOptions); - return; - } - - if (structureType == typeof (MAMReplacementMethod)) { - generator.WriteNestedStructure (mamReplacementMethodStructureInfo, new StructureInstance ((MAMReplacementMethod)fieldInstance), bodyWriterOptions); - return; - } - - if (structureType == typeof (MAMIndexTypeEntry)) { - generator.WriteNestedStructure (mamIndexTypeEntryStructureInfo, new StructureInstance ((MAMIndexTypeEntry)fieldInstance), bodyWriterOptions); - } - - if (structureType == typeof (MAMIndexMethodEntry)) { - generator.WriteNestedStructure (mamIndexMethodEntryStructureInfo, new StructureInstance ((MAMIndexMethodEntry)fieldInstance), bodyWriterOptions); - } - - throw new InvalidOperationException ($"Unsupported nested structure type {structureType}"); - } - - protected override void Write (LlvmIrGenerator generator) - { - generator.WriteEOL (); - generator.WriteEOL ("MAM remapping data"); - - if (typeReplacements == null) { - generator.WriteStructureArray ( - mamTypeReplacementEntryStructureInfo, - 0, - LlvmIrVariableOptions.GlobalConstant, - "mam_type_replacements" - ); - - generator.WriteStructureArray ( - mamIndexTypeEntryStructureInfo, - 0, - LlvmIrVariableOptions.GlobalConstant, - "mam_method_replacement_index" - ); - - return; - } - - generator.WriteStructureArray ( - mamTypeReplacementEntryStructureInfo, - typeReplacements, - LlvmIrVariableOptions.GlobalConstant, - "mam_type_replacements", - nestedStructureWriter: WriteNestedStructure - ); - - foreach (StructureInstance entry in methodIndexTypes) { - generator.WriteStructureArray ( - mamIndexMethodEntryStructureInfo, - entry.Obj.TypeMethods, - LlvmIrVariableOptions.LocalConstant, - entry.Obj.MethodsArraySymbolName, - nestedStructureWriter: WriteNestedStructure - ); - } - - generator.WriteStructureArray ( - mamIndexTypeEntryStructureInfo, - methodIndexTypes, - LlvmIrVariableOptions.GlobalConstant, - "mam_method_replacement_index", - nestedStructureWriter: WriteNestedStructure - ); - } - } -} diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 5b45874bf44..16f9539e440 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -90,7 +90,7 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. - +