From 13bbd932cdc472b201b3aca781abc60b87f55528 Mon Sep 17 00:00:00 2001 From: Marek Habersack Date: Tue, 3 Dec 2024 22:14:38 +0100 Subject: [PATCH] Build deps + application config for CLR --- .../Tasks/GeneratePackageManagerJava.cs | 75 ++-- .../Tasks/LinkApplicationSharedLibraries.cs | 8 +- .../Utilities/ApplicationConfigCLR.cs | 52 +++ ...icationConfigNativeAssemblyGeneratorCLR.cs | 388 ++++++++++++++++++ .../Xamarin.Android.Common.targets | 10 +- src/native-clr/host/host-jni.cc | 3 + src/native-clr/host/host.cc | 3 + src/native-clr/include/shared/log_types.hh | 6 + src/native-clr/java-interop/CMakeLists.txt | 8 - src/native-clr/lz4/CMakeLists.txt | 4 +- src/native-clr/native-clr.targets | 11 + src/native-clr/runtime-base/android-system.cc | 5 +- 12 files changed, 534 insertions(+), 39 deletions(-) create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs create mode 100644 src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs index c0f7f0432ce..1b5eced8bb5 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/GeneratePackageManagerJava.cs @@ -61,6 +61,9 @@ public class GeneratePackageManagerJava : AndroidTask [Required] public bool EnablePreloadAssembliesDefault { get; set; } + [Required] + public bool TargetsCLR { get; set; } + public bool EnableMarshalMethods { get; set; } public string RuntimeConfigBinFilePath { get; set; } public string BoundExceptionType { get; set; } @@ -321,31 +324,53 @@ void AddEnvironment () bool haveRuntimeConfigBlob = !String.IsNullOrEmpty (RuntimeConfigBinFilePath) && File.Exists (RuntimeConfigBinFilePath); var jniRemappingNativeCodeInfo = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal (ProjectSpecificTaskObjectKey (GenerateJniRemappingNativeCode.JniRemappingNativeCodeInfoKey), RegisteredTaskObjectLifetime.Build); - var appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { - UsesMonoAOT = usesMonoAOT, - UsesMonoLLVM = EnableLLVM, - UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, - MonoAOTMode = aotMode.ToString ().ToLowerInvariant (), - AotEnableLazyLoad = AndroidAotEnableLazyLoad, - AndroidPackageName = AndroidPackageName, - BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions, - PackageNamingPolicy = pnp, - BoundExceptionType = boundExceptionType, - JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, - HaveRuntimeConfigBlob = haveRuntimeConfigBlob, - NumberOfAssembliesInApk = assemblyCount, - BundledAssemblyNameWidth = assemblyNameWidth, - MonoComponents = (MonoComponent)monoComponents, - NativeLibraries = uniqueNativeLibraries, - HaveAssemblyStore = UseAssemblyStore, - AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, - JNIEnvInitializeToken = jnienv_initialize_method_token, - JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, - JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, - JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, - MarshalMethodsEnabled = EnableMarshalMethods, - IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), - }; + LLVMIR.LlvmIrComposer appConfigAsmGen; + + if (TargetsCLR) { + appConfigAsmGen = new ApplicationConfigNativeAssemblyGeneratorCLR (environmentVariables, systemProperties, Log) { + UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, + AndroidPackageName = AndroidPackageName, + PackageNamingPolicy = pnp, + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, + HaveRuntimeConfigBlob = haveRuntimeConfigBlob, + NumberOfAssembliesInApk = assemblyCount, + BundledAssemblyNameWidth = assemblyNameWidth, + NativeLibraries = uniqueNativeLibraries, + AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, + JNIEnvInitializeToken = jnienv_initialize_method_token, + JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, + JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, + JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, + MarshalMethodsEnabled = EnableMarshalMethods, + IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), + }; + } else { + appConfigAsmGen = new ApplicationConfigNativeAssemblyGenerator (environmentVariables, systemProperties, Log) { + UsesMonoAOT = usesMonoAOT, + UsesMonoLLVM = EnableLLVM, + UsesAssemblyPreload = environmentParser.UsesAssemblyPreload, + MonoAOTMode = aotMode.ToString ().ToLowerInvariant (), + AotEnableLazyLoad = AndroidAotEnableLazyLoad, + AndroidPackageName = AndroidPackageName, + BrokenExceptionTransitions = environmentParser.BrokenExceptionTransitions, + PackageNamingPolicy = pnp, + BoundExceptionType = boundExceptionType, + JniAddNativeMethodRegistrationAttributePresent = NativeCodeGenState.TemplateJniAddNativeMethodRegistrationAttributePresent, + HaveRuntimeConfigBlob = haveRuntimeConfigBlob, + NumberOfAssembliesInApk = assemblyCount, + BundledAssemblyNameWidth = assemblyNameWidth, + MonoComponents = (MonoComponent)monoComponents, + NativeLibraries = uniqueNativeLibraries, + HaveAssemblyStore = UseAssemblyStore, + AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token, + JNIEnvInitializeToken = jnienv_initialize_method_token, + JNIEnvRegisterJniNativesToken = jnienv_registerjninatives_method_token, + JniRemappingReplacementTypeCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementTypeCount, + JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount, + MarshalMethodsEnabled = EnableMarshalMethods, + IgnoreSplitConfigs = ShouldIgnoreSplitConfigs (), + }; + } LLVMIR.LlvmIrModule appConfigModule = appConfigAsmGen.Construct (); foreach (string abi in SupportedAbis) { diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs index 6fb2dac8967..4d9aef3bcd4 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/LinkApplicationSharedLibraries.cs @@ -43,6 +43,9 @@ sealed class InputFiles [Required] public string AndroidBinUtilsDirectory { get; set; } + [Required] + public bool TargetsCLR { get; set; } + public int ZipAlignmentPages { get; set; } = AndroidZipAlign.DefaultZipAlignment64Bit; public override System.Threading.Tasks.Task RunTaskAsync () @@ -123,11 +126,12 @@ IEnumerable GetLinkerConfigs () abis [abi] = GatherFilesForABI (item.ItemSpec, abi, ObjectFiles, runtimeNativeLibsDir, runtimeNativeLibStubsDir); } - const string commonLinkerArgs = + string soname = TargetsCLR ? "libxamarin-app-clr.so" : "libxamarin-app.so"; + string commonLinkerArgs = "--shared " + "--allow-shlib-undefined " + "--export-dynamic " + - "-soname libxamarin-app.so " + + $"-soname {soname} " + "-z relro " + "-z noexecstack " + "--enable-new-dtags " + diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs new file mode 100644 index 00000000000..0e5593bb363 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigCLR.cs @@ -0,0 +1,52 @@ +using System; + +namespace Xamarin.Android.Tasks; + +// Declaration order of fields and their types must correspond *exactly* to that in +// src/native-clr/xamarin-app-stub/xamarin-app.hh ApplicationConfig structure +// +// Type mappings: +// +// C++ C# +// -----------|---------- +// bool | bool +// uint8_t | byte +// int8_t | sbyte +// uint16_t | ushort +// int16_t | short +// uint32_t | uint +// int32_t | int +// uint64_t | ulong +// int64_t | long +// char* | string +// +// Names should be the same as in the above struct, but it's not a requirement +// (they will be used only to generate comments in the native code) +sealed class ApplicationConfigCLR +{ + public bool uses_assembly_preload; + public bool jni_add_native_method_registration_attribute_present; + public bool have_runtime_config_blob; + public bool marshal_methods_enabled; + public bool ignore_split_configs; + public uint package_naming_policy; + public uint environment_variable_count; + public uint system_property_count; + public uint number_of_assemblies_in_apk; + public uint bundled_assembly_name_width; + public uint number_of_dso_cache_entries; + public uint number_of_aot_cache_entries; + public uint number_of_shared_libraries; + + [NativeAssembler (NumberFormat = LLVMIR.LlvmIrVariableNumberFormat.Hexadecimal)] + public uint android_runtime_jnienv_class_token; + + [NativeAssembler (NumberFormat = LLVMIR.LlvmIrVariableNumberFormat.Hexadecimal)] + public uint jnienv_initialize_method_token; + + [NativeAssembler (NumberFormat = LLVMIR.LlvmIrVariableNumberFormat.Hexadecimal)] + public uint jnienv_registerjninatives_method_token; + public uint jni_remapping_replacement_type_count; + public uint jni_remapping_replacement_method_index_entry_count; + public string android_package_name = String.Empty; +} diff --git a/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs new file mode 100644 index 00000000000..24ec67e9e73 --- /dev/null +++ b/src/Xamarin.Android.Build.Tasks/Utilities/ApplicationConfigNativeAssemblyGeneratorCLR.cs @@ -0,0 +1,388 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; + +using Java.Interop.Tools.TypeNameMappings; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Xamarin.Android.Tasks.LLVMIR; + +namespace Xamarin.Android.Tasks; + +class ApplicationConfigNativeAssemblyGeneratorCLR : LlvmIrComposer +{ + sealed class DSOCacheEntryContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override string GetComment (object data, string fieldName) + { + var dso_entry = EnsureType (data); + if (String.Compare ("hash", fieldName, StringComparison.Ordinal) == 0) { + return $" from name: {dso_entry.HashedName}"; + } + + if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { + return $" name: {dso_entry.name}"; + } + + return String.Empty; + } + } + + // Order of fields and their type must correspond *exactly* (with exception of the + // ignored managed members) to that in + // src/monodroid/jni/xamarin-app.hh DSOCacheEntry structure + [NativeAssemblerStructContextDataProvider (typeof (DSOCacheEntryContextDataProvider))] + sealed class DSOCacheEntry + { + [NativeAssembler (Ignore = true)] + public string HashedName; + + [NativeAssembler (UsesDataProvider = true, NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public ulong hash; + + [NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)] + public ulong real_name_hash; + public bool ignore; + + [NativeAssembler (UsesDataProvider = true)] + public string name; + public IntPtr handle = IntPtr.Zero; + } + + sealed class DSOApkEntry + { + public ulong name_hash; + public uint offset; // offset into the APK + public int fd; // apk file descriptor + }; + + // Order of fields and their type must correspond *exactly* to that in + // src/monodroid/jni/xamarin-app.hh AssemblyStoreAssemblyDescriptor structure + sealed class AssemblyStoreAssemblyDescriptor + { + public uint data_offset; + public uint data_size; + + public uint debug_data_offset; + public uint debug_data_size; + + public uint config_data_offset; + public uint config_data_size; + } + + // Order of fields and their type must correspond *exactly* to that in + // src/monodroid/jni/xamarin-app.hh AssemblyStoreSingleAssemblyRuntimeData structure + sealed class AssemblyStoreSingleAssemblyRuntimeData + { + [NativePointer] + public byte image_data; + + [NativePointer] + public byte debug_info_data; + + [NativePointer] + public byte config_data; + + [NativePointer] + public AssemblyStoreAssemblyDescriptor descriptor; + } + + // Order of fields and their type must correspond *exactly* to that in + // src/monodroid/jni/xamarin-app.hh AssemblyStoreRuntimeData structure + sealed class AssemblyStoreRuntimeData + { + [NativePointer (IsNull = true)] + public byte data_start; + public uint assembly_count; + public uint index_entry_count; + + [NativePointer (IsNull = true)] + public AssemblyStoreAssemblyDescriptor assemblies; + } + + sealed class XamarinAndroidBundledAssemblyContextDataProvider : NativeAssemblerStructContextDataProvider + { + public override ulong GetBufferSize (object data, string fieldName) + { + var xaba = EnsureType (data); + if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) { + return xaba.name_length; + } + + if (String.Compare ("file_name", fieldName, StringComparison.Ordinal) == 0) { + return xaba.name_length + MonoAndroidHelper.GetMangledAssemblyNameSizeOverhead (); + } + + return 0; + } + } + + // Order of fields and their type must correspond *exactly* to that in + // src/monodroid/jni/xamarin-app.hh XamarinAndroidBundledAssembly structure + [NativeAssemblerStructContextDataProvider (typeof (XamarinAndroidBundledAssemblyContextDataProvider))] + sealed class XamarinAndroidBundledAssembly + { + public int file_fd; + + [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToPreAllocatedBuffer = true)] + public string file_name; + public uint data_offset; + public uint data_size; + + [NativePointer] + public byte data; + public uint name_length; + + [NativeAssembler (UsesDataProvider = true), NativePointer (PointsToPreAllocatedBuffer = true)] + public string name; + } + + // Keep in sync with FORMAT_TAG in src/monodroid/jni/xamarin-app.hh + const ulong FORMAT_TAG = 0x00025E6972616D58; // 'Xmari^XY' where XY is the format version + + SortedDictionary ? environmentVariables; + SortedDictionary ? systemProperties; + StructureInstance? application_config; + List>? dsoCache; + List>? aotDsoCache; + List>? xamarinAndroidBundledAssemblies; + + StructureInfo? applicationConfigStructureInfo; + StructureInfo? dsoCacheEntryStructureInfo; + StructureInfo? dsoApkEntryStructureInfo; + StructureInfo? xamarinAndroidBundledAssemblyStructureInfo; + StructureInfo? assemblyStoreSingleAssemblyRuntimeDataStructureinfo; + StructureInfo? assemblyStoreRuntimeDataStructureInfo; + + public bool UsesAssemblyPreload { get; set; } + public string AndroidPackageName { get; set; } + public bool JniAddNativeMethodRegistrationAttributePresent { get; set; } + public bool HaveRuntimeConfigBlob { get; set; } + public int NumberOfAssembliesInApk { get; set; } + public int BundledAssemblyNameWidth { get; set; } // including the trailing NUL + public int AndroidRuntimeJNIEnvToken { get; set; } + public int JNIEnvInitializeToken { get; set; } + public int JNIEnvRegisterJniNativesToken { get; set; } + public int JniRemappingReplacementTypeCount { get; set; } + public int JniRemappingReplacementMethodIndexEntryCount { get; set; } + public PackageNamingPolicy PackageNamingPolicy { get; set; } + public List NativeLibraries { get; set; } + public bool MarshalMethodsEnabled { get; set; } + public bool IgnoreSplitConfigs { get; set; } + + public ApplicationConfigNativeAssemblyGeneratorCLR (IDictionary environmentVariables, IDictionary systemProperties, TaskLoggingHelper log) + : base (log) + { + if (environmentVariables != null) { + this.environmentVariables = new SortedDictionary (environmentVariables, StringComparer.Ordinal); + } + + if (systemProperties != null) { + this.systemProperties = new SortedDictionary (systemProperties, StringComparer.Ordinal); + } + } + + protected override void Construct (LlvmIrModule module) + { + MapStructures (module); + + module.AddGlobalVariable ("format_tag", FORMAT_TAG, comment: $" 0x{FORMAT_TAG:x}"); + + var envVars = new LlvmIrGlobalVariable (environmentVariables, "app_environment_variables") { + Comment = " Application environment variables array, name:value", + }; + module.Add (envVars, stringGroupName: "env", stringGroupComment: " Application environment variables name:value pairs"); + + var sysProps = new LlvmIrGlobalVariable (systemProperties, "app_system_properties") { + Comment = " System properties defined by the application", + }; + module.Add (sysProps, stringGroupName: "sysprop", stringGroupComment: " System properties name:value pairs"); + + (dsoCache, aotDsoCache) = InitDSOCache (); + var app_cfg = new ApplicationConfigCLR { + uses_assembly_preload = UsesAssemblyPreload, + jni_add_native_method_registration_attribute_present = JniAddNativeMethodRegistrationAttributePresent, + have_runtime_config_blob = HaveRuntimeConfigBlob, + marshal_methods_enabled = MarshalMethodsEnabled, + ignore_split_configs = IgnoreSplitConfigs, + package_naming_policy = (uint)PackageNamingPolicy, + environment_variable_count = (uint)(environmentVariables == null ? 0 : environmentVariables.Count * 2), + system_property_count = (uint)(systemProperties == null ? 0 : systemProperties.Count * 2), + number_of_assemblies_in_apk = (uint)NumberOfAssembliesInApk, + number_of_shared_libraries = (uint)NativeLibraries.Count, + bundled_assembly_name_width = (uint)BundledAssemblyNameWidth, + number_of_dso_cache_entries = (uint)dsoCache.Count, + number_of_aot_cache_entries = (uint)aotDsoCache.Count, + android_runtime_jnienv_class_token = (uint)AndroidRuntimeJNIEnvToken, + jnienv_initialize_method_token = (uint)JNIEnvInitializeToken, + jnienv_registerjninatives_method_token = (uint)JNIEnvRegisterJniNativesToken, + jni_remapping_replacement_type_count = (uint)JniRemappingReplacementTypeCount, + jni_remapping_replacement_method_index_entry_count = (uint)JniRemappingReplacementMethodIndexEntryCount, + android_package_name = AndroidPackageName, + }; + application_config = new StructureInstance (applicationConfigStructureInfo, app_cfg); + module.AddGlobalVariable ("application_config", application_config); + + var dso_cache = new LlvmIrGlobalVariable (dsoCache, "dso_cache", LlvmIrVariableOptions.GlobalWritable) { + Comment = " DSO cache entries", + BeforeWriteCallback = HashAndSortDSOCache, + }; + module.Add (dso_cache); + + var aot_dso_cache = new LlvmIrGlobalVariable (aotDsoCache, "aot_dso_cache", LlvmIrVariableOptions.GlobalWritable) { + Comment = " AOT DSO cache entries", + BeforeWriteCallback = HashAndSortDSOCache, + }; + module.Add (aot_dso_cache); + + var dso_apk_entries = new LlvmIrGlobalVariable (typeof(List>), "dso_apk_entries") { + ArrayItemCount = (ulong)NativeLibraries.Count, + Options = LlvmIrVariableOptions.GlobalWritable, + ZeroInitializeArray = true, + }; + module.Add (dso_apk_entries); + + string bundledBuffersSize = xamarinAndroidBundledAssemblies == null ? "empty (unused when assembly stores are enabled)" : $"{BundledAssemblyNameWidth} bytes long"; + var bundled_assemblies = new LlvmIrGlobalVariable (typeof(List>), "bundled_assemblies", LlvmIrVariableOptions.GlobalWritable) { + Value = xamarinAndroidBundledAssemblies, + Comment = $" Bundled assembly name buffers, all {bundledBuffersSize}", + }; + module.Add (bundled_assemblies); + + AddAssemblyStores (module); + } + + void AddAssemblyStores (LlvmIrModule module) + { + ulong itemCount = (ulong)(NumberOfAssembliesInApk); + var assembly_store_bundled_assemblies = new LlvmIrGlobalVariable (typeof(List>), "assembly_store_bundled_assemblies", LlvmIrVariableOptions.GlobalWritable) { + ZeroInitializeArray = true, + ArrayItemCount = itemCount, + }; + module.Add (assembly_store_bundled_assemblies); + + var storeRuntimeData = new AssemblyStoreRuntimeData { + data_start = 0, + assembly_count = 0, + }; + + var assembly_store = new LlvmIrGlobalVariable ( + new StructureInstance(assemblyStoreRuntimeDataStructureInfo, storeRuntimeData), + "assembly_store", + LlvmIrVariableOptions.GlobalWritable + ); + module.Add (assembly_store); + } + + void HashAndSortDSOCache (LlvmIrVariable variable, LlvmIrModuleTarget target, object? state) + { + var cache = variable.Value as List>; + if (cache == null) { + throw new InvalidOperationException ($"Internal error: DSO cache must not be empty"); + } + + bool is64Bit = target.Is64Bit; + foreach (StructureInstance instance in cache) { + if (instance.Obj == null) { + throw new InvalidOperationException ("Internal error: DSO cache must not contain null entries"); + } + + var entry = instance.Obj as DSOCacheEntry; + if (entry == null) { + throw new InvalidOperationException ($"Internal error: DSO cache entry has unexpected type {instance.Obj.GetType ()}"); + } + + entry.hash = MonoAndroidHelper.GetXxHash (entry.HashedName, is64Bit); + entry.real_name_hash = MonoAndroidHelper.GetXxHash (entry.name, is64Bit); + } + + cache.Sort ((StructureInstance a, StructureInstance b) => a.Instance.hash.CompareTo (b.Instance.hash)); + } + + (List> dsoCache, List> aotDsoCache) InitDSOCache () + { + var dsos = new List<(string name, string nameLabel, bool ignore)> (); + var nameCache = new HashSet (StringComparer.OrdinalIgnoreCase); + + foreach (ITaskItem item in NativeLibraries) { + string? name = item.GetMetadata ("ArchiveFileName"); + if (String.IsNullOrEmpty (name)) { + name = item.ItemSpec; + } + name = Path.GetFileName (name); + + if (nameCache.Contains (name)) { + continue; + } + + dsos.Add ((name, $"dsoName{dsos.Count.ToString (CultureInfo.InvariantCulture)}", ELFHelper.IsEmptyAOTLibrary (Log, item.ItemSpec))); + } + + var dsoCache = new List> (); + var aotDsoCache = new List> (); + var nameMutations = new List (); + + for (int i = 0; i < dsos.Count; i++) { + string name = dsos[i].name; + nameMutations.Clear(); + AddNameMutations (name); + // All mutations point to the actual library name, but have hash of the mutated one + foreach (string entryName in nameMutations) { + var entry = new DSOCacheEntry { + HashedName = entryName, + hash = 0, // Hash is arch-specific, we compute it before writing + ignore = dsos[i].ignore, + name = name, + }; + + var item = new StructureInstance (dsoCacheEntryStructureInfo, entry); + if (name.StartsWith ("libaot-", StringComparison.OrdinalIgnoreCase)) { + aotDsoCache.Add (item); + } else { + dsoCache.Add (item); + } + } + } + + return (dsoCache, aotDsoCache); + + void AddNameMutations (string name) + { + nameMutations.Add (name); + if (name.EndsWith (".dll.so", StringComparison.OrdinalIgnoreCase)) { + string nameNoExt = Path.GetFileNameWithoutExtension (Path.GetFileNameWithoutExtension (name))!; + nameMutations.Add (nameNoExt); + + // This helps us at runtime, because sometimes MonoVM will ask for "AssemblyName" and sometimes for "AssemblyName.dll". + // In the former case, the runtime would ask for the "libaot-AssemblyName.so" image, which doesn't exist - we have + // "libaot-AssemblyName.dll.so" instead and, thus, we are forced to check for and append the missing ".dll" extension when + // loading the assembly, unnecessarily wasting time. + nameMutations.Add ($"{nameNoExt}.so"); + } else { + nameMutations.Add (Path.GetFileNameWithoutExtension (name)!); + } + + const string aotPrefix = "libaot-"; + if (name.StartsWith (aotPrefix, StringComparison.OrdinalIgnoreCase)) { + AddNameMutations (name.Substring (aotPrefix.Length)); + } + + const string libPrefix = "lib"; + if (name.StartsWith (libPrefix, StringComparison.OrdinalIgnoreCase)) { + AddNameMutations (name.Substring (libPrefix.Length)); + } + } + } + + void MapStructures (LlvmIrModule module) + { + applicationConfigStructureInfo = module.MapStructure (); + module.MapStructure (); + assemblyStoreSingleAssemblyRuntimeDataStructureinfo = module.MapStructure (); + assemblyStoreRuntimeDataStructureInfo = module.MapStructure (); + xamarinAndroidBundledAssemblyStructureInfo = module.MapStructure (); + dsoCacheEntryStructureInfo = module.MapStructure (); + dsoApkEntryStructureInfo = module.MapStructure (); + } +} diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index 5f02df064b9..4e33b2af86a 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -1745,6 +1745,7 @@ because xbuild doesn't support framework reference assemblies. UseAssemblyStore="$(AndroidUseAssemblyStore)" EnableMarshalMethods="$(_AndroidUseMarshalMethods)" CustomBundleConfigFile="$(AndroidBundleConfigurationFile)" + TargetsCLR="$(_AndroidUseCLR)" > @@ -2007,11 +2008,17 @@ because xbuild doesn't support framework reference assemblies. - + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app.so"> %(_BuildTargetAbis.Identity) + + + <_ApplicationSharedLibrary Include="$(_AndroidApplicationSharedLibraryPath)%(_BuildTargetAbis.Identity)\libxamarin-app-clr.so"> + %(_BuildTargetAbis.Identity) + + diff --git a/src/native-clr/host/host-jni.cc b/src/native-clr/host/host-jni.cc index 33b9180eff3..43775ad0918 100644 --- a/src/native-clr/host/host-jni.cc +++ b/src/native-clr/host/host-jni.cc @@ -1,11 +1,14 @@ #include #include +#include using namespace xamarin::android; JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM *vm, void *reserved) { + log_write (LOG_DEFAULT, LogLevel::Info, "JNI_OnLoad"); + return Host::Java_JNI_OnLoad (vm, reserved); } diff --git a/src/native-clr/host/host.cc b/src/native-clr/host/host.cc index 735ae4dfa60..8ca3f58580c 100644 --- a/src/native-clr/host/host.cc +++ b/src/native-clr/host/host.cc @@ -1,11 +1,14 @@ #include #include #include +#include using namespace xamarin::android; auto Host::Java_JNI_OnLoad (JavaVM *vm, [[maybe_unused]] void *reserved) noexcept -> jint { + log_write (LOG_DEFAULT, LogLevel::Info, "Host init"); + AndroidSystem::init_max_gref_count (); return JNI_VERSION_1_6; } diff --git a/src/native-clr/include/shared/log_types.hh b/src/native-clr/include/shared/log_types.hh index 66b1cae5097..656146ec203 100644 --- a/src/native-clr/include/shared/log_types.hh +++ b/src/native-clr/include/shared/log_types.hh @@ -47,6 +47,12 @@ namespace xamarin::android { // A slightly faster alternative to other log functions as it doesn't parse the message // for format placeholders nor it uses variable arguments void log_write (LogCategories category, LogLevel level, const char *message) noexcept; + + [[gnu::always_inline]] + static inline void log_write (LogCategories category, LogLevel level, std::string_view const& message) noexcept + { + log_write (category, level, message.data ()); + } } template [[gnu::always_inline]] diff --git a/src/native-clr/java-interop/CMakeLists.txt b/src/native-clr/java-interop/CMakeLists.txt index a731f0110e0..24a233e2b80 100644 --- a/src/native-clr/java-interop/CMakeLists.txt +++ b/src/native-clr/java-interop/CMakeLists.txt @@ -39,12 +39,4 @@ target_compile_options( ${XA_COMMON_CXX_ARGS} ) -if(DEBUG_BUILD) - set_target_properties( - ${LIB_NAME} - PROPERTIES - ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" - ) -endif() - xa_add_compile_definitions(${LIB_NAME}) diff --git a/src/native-clr/lz4/CMakeLists.txt b/src/native-clr/lz4/CMakeLists.txt index 16a35099fd5..140034771f1 100644 --- a/src/native-clr/lz4/CMakeLists.txt +++ b/src/native-clr/lz4/CMakeLists.txt @@ -1,4 +1,4 @@ -set(LIB_NAME xa-lz4-clr) +set(LIB_NAME xa-lz4) set(LIB_ALIAS xa::lz4-clr) set(LZ4_SRC_DIR "${EXTERNAL_DIR}/lz4/lib") @@ -16,6 +16,8 @@ add_library( add_library(${LIB_ALIAS} ALIAS ${LIB_NAME}) +set_static_library_suffix(${LIB_NAME}) + target_compile_definitions( ${LIB_NAME} PRIVATE diff --git a/src/native-clr/native-clr.targets b/src/native-clr/native-clr.targets index dba9f075f5b..6b5e9260382 100644 --- a/src/native-clr/native-clr.targets +++ b/src/native-clr/native-clr.targets @@ -15,6 +15,11 @@ <_ConfigureRuntimesInputs Include="CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="host\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="runtime-base\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="shared\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="startup\CMakeLists.txt" /> + <_ConfigureRuntimesInputs Include="xamarin-app-stub\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="java-interop\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="lz4\CMakeLists.txt" /> <_ConfigureRuntimesInputs Include="..\..\build-tools\scripts\Ndk.targets" /> @@ -58,6 +63,12 @@ + <_MonoDroidSources Include="include/**/*.hh" /> + <_MonoDroidSources Include="host/*.cc" /> + <_MonoDroidSources Include="runtime-base/*.cc" /> + <_MonoDroidSources Include="shared/*.cc" /> + <_MonoDroidSources Include="startup/*.cc" /> + <_MonoDroidSources Include="xamarin-app-stub/*.cc" /> <_MonoDroidSources Include="$(JavaInteropFullPath)\src\java-interop\*.cc;$(JavaInteropFullPath)\src\java-interop\*.h" /> <_MonoDroidSources Include="$(LZ4SourceFullPath)\lib\lz4.c;$(LZ4SourceFullPath)\lib\lz4.h" /> diff --git a/src/native-clr/runtime-base/android-system.cc b/src/native-clr/runtime-base/android-system.cc index 75dc394cdbd..dd381f994a8 100644 --- a/src/native-clr/runtime-base/android-system.cc +++ b/src/native-clr/runtime-base/android-system.cc @@ -86,8 +86,9 @@ auto AndroidSystem::monodroid_get_system_property (std::string_view const& name, size_t plen; const char *v = lookup_system_property (name, plen); - if (v == nullptr) + if (v == nullptr) { return len; + } value.assign (v, plen); return Helpers::add_with_overflow_check (plen, 0); @@ -107,7 +108,7 @@ AndroidSystem::get_max_gref_count_from_system () noexcept -> long dynamic_local_string override; if (monodroid_get_system_property (Constants::DEBUG_MONO_MAX_GREFC, override) > 0) { char *e; - max = strtol (override.get (), &e, 10); + max = strtol (override.get (), &e, 10); switch (*e) { case 'k': e++;