Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
a18807f
LLVM IR code generator refactoring and updates
grendello Jun 21, 2023
dc53ba7
Merge branch 'main' into llvm-generator-update
grendello Jun 22, 2023
12e36e7
Fix native assembly reader
grendello Jun 22, 2023
5939b44
A handful of updates
grendello Jun 22, 2023
042858d
A handful of updates
grendello Jun 23, 2023
2caf192
Merge branch 'main' into llvm-generator-update
grendello Jun 26, 2023
3ed01e9
Add some more tracing capabilities
grendello Jun 26, 2023
53ceea8
Merge branch 'main' into llvm-generator-update
grendello Jun 27, 2023
c573767
Another fixlet
grendello Jun 27, 2023
1d43520
A handful of additions and changes
grendello Jun 28, 2023
66f9566
Beginning to fix typemaps for per-abi assemblies
grendello Jun 30, 2023
e393968
Typemaps generated properly, testing and marshal methods tomorrow
grendello Jul 3, 2023
a37cd9a
Something isn't right...
grendello Jul 4, 2023
a18c352
New typemap scanner, disable marshal methods by default
grendello Jul 5, 2023
4c94cc6
Merge branch 'main' into typemap-per-rid-support
grendello Jul 6, 2023
1528dd9
Fix test failures
grendello Jul 6, 2023
e4108d4
More test fixes
grendello Jul 6, 2023
80c4fb4
Merge branch 'main' into llvm-generator-update
grendello Jul 6, 2023
1c417d6
Merge branch 'typemap-per-rid-support' into llvm-generator-update
grendello Jul 6, 2023
3b733f0
Merge branch 'main' into typemap-per-rid-support
grendello Jul 6, 2023
55b1325
Updates + fixes + per-rid typemaps
grendello Jul 6, 2023
f30e88e
Hopefully fix Windows tests
grendello Jul 7, 2023
40a5d47
Add some timing debug prints
grendello Jul 7, 2023
915670d
Merge branch 'main' into typemap-per-rid-support
grendello Jul 7, 2023
6810bc8
More printfs
grendello Jul 7, 2023
0230052
Let's see if using the resolver directly helps
grendello Jul 7, 2023
0427147
Remove debug stuff
grendello Jul 7, 2023
6796153
Merge branch 'typemap-per-rid-support' into llvm-generator-update
grendello Jul 7, 2023
0b63e28
Use a custom assembly resolver
grendello Jul 10, 2023
2a781e2
Merge branch 'typemap-per-rid-support' into llvm-generator-update
grendello Jul 10, 2023
4aff8b7
Merge branch 'main' into llvm-generator-update
grendello Jul 14, 2023
6fa66c7
Updates from main
grendello Jul 14, 2023
4f946ab
Merge branch 'main' into llvm-generator-update
grendello Jul 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
LLVM IR code generator refactoring and updates
  * Migrate to opaque pointers (LLVM 15+) which will be the only ones
    supported from LLVM 16 onwards
  * Change code generation model.  Now the "client" classes don't need
    to concern themselves with **how** the LLVM IR code looks and how
    it is formatted.  Instead, they build a model of the code they want
    to output and let the generator do the rest.
  * Handle many more tasks automatically:
    * LLVM IR string management and registration
    * Buffer management for structures which have pointers to buffers
    * References to local variables and strings
    * Local temporary counting (unnamed labels and function parameters)
  • Loading branch information
grendello committed Jun 21, 2023
commit a18807f89a873a5b1802ec90aa93092a3b94b3fd
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,22 @@ void GenerateCompressedAssemblySources ()

void Generate (IDictionary<string, CompressedAssemblyInfo> dict)
{
var llvmAsmgen = new CompressedAssembliesNativeAssemblyGenerator (dict);
llvmAsmgen.Init ();
var composer = new CompressedAssembliesNativeAssemblyGenerator (dict);
LLVMIR.LlvmIrModule compressedAssemblies = composer.Construct ();

foreach (string abi in SupportedAbis) {
string baseAsmFilePath = Path.Combine (EnvironmentOutputDirectory, $"compressed_assemblies.{abi.ToLowerInvariant ()}");
string llvmIrFilePath = $"{baseAsmFilePath}.ll";

using (var sw = MemoryStreamPool.Shared.CreateStreamWriter ()) {
llvmAsmgen.Write (GeneratePackageManagerJava.GetAndroidTargetArchForAbi (abi), sw, llvmIrFilePath);
sw.Flush ();
try {
composer.Generate (compressedAssemblies, GeneratePackageManagerJava.GetAndroidTargetArchForAbi (abi), sw, llvmIrFilePath);
} catch {
throw;
} finally {
sw.Flush ();
}

if (Files.CopyIfStreamChanged (sw.BaseStream, llvmIrFilePath)) {
Log.LogDebugMessage ($"File {llvmIrFilePath} was regenerated");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,24 +77,24 @@ void Generate ()
Generate (new JniRemappingAssemblyGenerator (typeReplacements, methodReplacements), typeReplacements.Count);
}

void Generate (JniRemappingAssemblyGenerator jniRemappingGenerator, int typeReplacementsCount)
void Generate (JniRemappingAssemblyGenerator jniRemappingComposer, int typeReplacementsCount)
{
jniRemappingGenerator.Init ();
LLVMIR.LlvmIrModule module = jniRemappingComposer.Construct ();

foreach (string abi in SupportedAbis) {
string baseAsmFilePath = Path.Combine (OutputDirectory, $"jni_remap.{abi.ToLowerInvariant ()}");
string llFilePath = $"{baseAsmFilePath}.ll";

using (var sw = MemoryStreamPool.Shared.CreateStreamWriter ()) {
jniRemappingGenerator.Write (GeneratePackageManagerJava.GetAndroidTargetArchForAbi (abi), sw, llFilePath);
jniRemappingComposer.Generate (module, GeneratePackageManagerJava.GetAndroidTargetArchForAbi (abi), sw, llFilePath);
sw.Flush ();
Files.CopyIfStreamChanged (sw.BaseStream, llFilePath);
}
}

BuildEngine4.RegisterTaskObjectAssemblyLocal (
ProjectSpecificTaskObjectKey (JniRemappingNativeCodeInfoKey),
new JniRemappingNativeCodeInfo (typeReplacementsCount, jniRemappingGenerator.ReplacementMethodIndexEntryCount),
new JniRemappingNativeCodeInfo (typeReplacementsCount, jniRemappingComposer.ReplacementMethodIndexEntryCount),
RegisteredTaskObjectLifetime.Build
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ void AddEnvironment ()
// and up to 4 other for arch-specific assemblies. Only **one** arch-specific store is ever loaded on the app
// runtime, thus the number 2 here. All architecture specific stores contain assemblies with the same names
// and in the same order.
MonoComponents = monoComponents,
MonoComponents = (MonoComponent)monoComponents,
NativeLibraries = uniqueNativeLibraries,
HaveAssemblyStore = UseAssemblyStore,
AndroidRuntimeJNIEnvToken = android_runtime_jnienv_class_token,
Expand All @@ -400,7 +400,7 @@ void AddEnvironment ()
JniRemappingReplacementMethodIndexEntryCount = jniRemappingNativeCodeInfo == null ? 0 : jniRemappingNativeCodeInfo.ReplacementMethodIndexEntryCount,
MarshalMethodsEnabled = EnableMarshalMethods,
};
appConfigAsmGen.Init ();
LLVMIR.LlvmIrModule appConfigModule = appConfigAsmGen.Construct ();

var marshalMethodsState = BuildEngine4.GetRegisteredTaskObjectAssemblyLocal<MarshalMethodsState> (ProjectSpecificTaskObjectKey (GenerateJavaStubs.MarshalMethodsRegisterTaskKey), RegisteredTaskObjectLifetime.Build);
MarshalMethodsNativeAssemblyGenerator marshalMethodsAsmGen;
Expand All @@ -415,26 +415,36 @@ void AddEnvironment ()
} else {
marshalMethodsAsmGen = new MarshalMethodsNativeAssemblyGenerator (assemblyCount, uniqueAssemblyNames);
}
marshalMethodsAsmGen.Init ();
LLVMIR.LlvmIrModule marshalMethodsModule = marshalMethodsAsmGen.Construct ();

foreach (string abi in SupportedAbis) {
string targetAbi = abi.ToLowerInvariant ();
string environmentBaseAsmFilePath = Path.Combine (EnvironmentOutputDirectory, $"environment.{targetAbi}");
string marshalMethodsBaseAsmFilePath = Path.Combine (EnvironmentOutputDirectory, $"marshal_methods.{targetAbi}");
string environmentLlFilePath = $"{environmentBaseAsmFilePath}.ll";
string marshalMethodsLlFilePath = $"{marshalMethodsBaseAsmFilePath}.ll";

AndroidTargetArch targetArch = GetAndroidTargetArchForAbi (abi);

using (var sw = MemoryStreamPool.Shared.CreateStreamWriter ()) {
appConfigAsmGen.Write (targetArch, sw, environmentLlFilePath);
sw.Flush ();
Files.CopyIfStreamChanged (sw.BaseStream, environmentLlFilePath);
try {
appConfigAsmGen.Generate (appConfigModule, targetArch, sw, environmentLlFilePath);
} catch {
throw;
} finally {
sw.Flush ();
Files.CopyIfStreamChanged (sw.BaseStream, environmentLlFilePath);
}
}

using (var sw = MemoryStreamPool.Shared.CreateStreamWriter ()) {
marshalMethodsAsmGen.Write (targetArch, sw, marshalMethodsLlFilePath);
sw.Flush ();
Files.CopyIfStreamChanged (sw.BaseStream, marshalMethodsLlFilePath);
try {
marshalMethodsAsmGen.Generate (marshalMethodsModule, targetArch, sw, marshalMethodsLlFilePath);
} catch {
throw;
} finally {
sw.Flush ();
Files.CopyIfStreamChanged (sw.BaseStream, marshalMethodsLlFilePath);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using Java.Interop.Tools.TypeNameMappings;
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;

using Xamarin.Android.Tasks.LLVMIR;

namespace Xamarin.Android.Tasks
Expand All @@ -27,17 +26,13 @@ sealed class DSOCacheEntryContextDataProvider : NativeAssemblerStructContextData
{
public override string GetComment (object data, string fieldName)
{
var dso_entry = data as DSOCacheEntry;
if (dso_entry == null) {
throw new InvalidOperationException ("Invalid data type, expected an instance of DSOCacheEntry");
}

var dso_entry = EnsureType<DSOCacheEntry> (data);
if (String.Compare ("hash", fieldName, StringComparison.Ordinal) == 0) {
return $"hash 0x{dso_entry.hash:x}, from name: {dso_entry.HashedName}";
return $" hash 0x{dso_entry.hash:x}, from name: {dso_entry.HashedName}";
}

if (String.Compare ("name", fieldName, StringComparison.Ordinal) == 0) {
return $"name: {dso_entry.name}";
return $" name: {dso_entry.name}";
}

return String.Empty;
Expand All @@ -57,6 +52,7 @@ sealed class DSOCacheEntry
public ulong hash;
public bool ignore;

[NativeAssembler (UsesDataProvider = true)]
public string name;
public IntPtr handle = IntPtr.Zero;
}
Expand Down Expand Up @@ -131,24 +127,24 @@ sealed class XamarinAndroidBundledAssembly
public uint name_length;

[NativeAssembler (UsesDataProvider = true), NativePointer (PointsToPreAllocatedBuffer = true)]
public char name;
public string name;
}

// Keep in sync with FORMAT_TAG in src/monodroid/jni/xamarin-app.hh
const ulong FORMAT_TAG = 0x015E6972616D58;

SortedDictionary <string, string> environmentVariables;
SortedDictionary <string, string> systemProperties;
SortedDictionary <string, string>? environmentVariables;
SortedDictionary <string, string>? systemProperties;
TaskLoggingHelper log;
StructureInstance<ApplicationConfig>? application_config;
StructureInstance? application_config;
List<StructureInstance<DSOCacheEntry>>? dsoCache;
List<StructureInstance<XamarinAndroidBundledAssembly>>? xamarinAndroidBundledAssemblies;

StructureInfo<ApplicationConfig>? applicationConfigStructureInfo;
StructureInfo<DSOCacheEntry>? dsoCacheEntryStructureInfo;
StructureInfo<XamarinAndroidBundledAssembly>? xamarinAndroidBundledAssemblyStructureInfo;
StructureInfo<AssemblyStoreSingleAssemblyRuntimeData> assemblyStoreSingleAssemblyRuntimeDataStructureinfo;
StructureInfo<AssemblyStoreRuntimeData> assemblyStoreRuntimeDataStructureInfo;
StructureInfo? applicationConfigStructureInfo;
StructureInfo? dsoCacheEntryStructureInfo;
StructureInfo? xamarinAndroidBundledAssemblyStructureInfo;
StructureInfo? assemblyStoreSingleAssemblyRuntimeDataStructureinfo;
StructureInfo? assemblyStoreRuntimeDataStructureInfo;

public bool UsesMonoAOT { get; set; }
public bool UsesMonoLLVM { get; set; }
Expand Down Expand Up @@ -188,8 +184,23 @@ public ApplicationConfigNativeAssemblyGenerator (IDictionary<string, string> env
this.log = log;
}

public override void Init ()
protected override void Construct (LlvmIrModule module)
{
MapStructures (module);

module.AddGlobalVariable ("format_tag", FORMAT_TAG, comment: $" 0x{FORMAT_TAG:x}");
module.AddGlobalVariable ("mono_aot_mode_name", MonoAOTMode);

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 = InitDSOCache ();
var app_cfg = new ApplicationConfig {
uses_mono_llvm = UsesMonoLLVM,
Expand Down Expand Up @@ -218,7 +229,14 @@ public override void Init ()
mono_components_mask = (uint)MonoComponents,
android_package_name = AndroidPackageName,
};
application_config = new StructureInstance<ApplicationConfig> (app_cfg);
application_config = new StructureInstance<ApplicationConfig> (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);

if (!HaveAssemblyStore) {
xamarinAndroidBundledAssemblies = new List<StructureInstance<XamarinAndroidBundledAssembly>> (NumberOfAssembliesInApk);
Expand All @@ -229,13 +247,63 @@ public override void Init ()
data_size = 0,
data = 0,
name_length = (uint)BundledAssemblyNameWidth,
name = '\0',
name = null,
};

for (int i = 0; i < NumberOfAssembliesInApk; i++) {
xamarinAndroidBundledAssemblies.Add (new StructureInstance<XamarinAndroidBundledAssembly> (emptyBundledAssemblyData));
xamarinAndroidBundledAssemblies.Add (new StructureInstance<XamarinAndroidBundledAssembly> (xamarinAndroidBundledAssemblyStructureInfo, emptyBundledAssemblyData));
}
}

string bundledBuffersSize = xamarinAndroidBundledAssemblies == null ? "empty (unused when assembly stores are enabled)" : $"{BundledAssemblyNameWidth} bytes long";
var bundled_assemblies = new LlvmIrGlobalVariable (typeof(List<StructureInstance<XamarinAndroidBundledAssembly>>), "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)(HaveAssemblyStore ? NumberOfAssembliesInApk : 0);
var assembly_store_bundled_assemblies = new LlvmIrGlobalVariable (typeof(List<StructureInstance<AssemblyStoreSingleAssemblyRuntimeData>>), "assembly_store_bundled_assemblies", LlvmIrVariableOptions.GlobalWritable) {
ZeroInitializeArray = true,
ArrayItemCount = itemCount,
};
module.Add (assembly_store_bundled_assemblies);

itemCount = (ulong)(HaveAssemblyStore ? NumberOfAssemblyStoresInApks : 0);
var assembly_stores = new LlvmIrGlobalVariable (typeof(List<StructureInstance<AssemblyStoreRuntimeData>>), "assembly_stores", LlvmIrVariableOptions.GlobalWritable) {
ZeroInitializeArray = true,
ArrayItemCount = itemCount,
};
module.Add (assembly_stores);
}

void HashAndSortDSOCache (LlvmIrVariable variable, LlvmIrModuleTarget target, object? state)
{
var cache = variable.Value as List<StructureInstance<DSOCacheEntry>>;
if (cache == null) {
throw new InvalidOperationException ($"Internal error: DSO cache must no 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 = GetXxHash (entry.HashedName, is64Bit);
}

cache.Sort ((StructureInstance<DSOCacheEntry> a, StructureInstance<DSOCacheEntry> b) => a.Instance.hash.CompareTo (b.Instance.hash));
}

List<StructureInstance<DSOCacheEntry>> InitDSOCache ()
Expand Down Expand Up @@ -273,7 +341,7 @@ List<StructureInstance<DSOCacheEntry>> InitDSOCache ()
name = name,
};

dsoCache.Add (new StructureInstance<DSOCacheEntry> (entry));
dsoCache.Add (new StructureInstance<DSOCacheEntry> (dsoCacheEntryStructureInfo, entry));
}
}

Expand All @@ -300,56 +368,14 @@ void AddNameMutations (string name)
}
}

protected override void MapStructures (LlvmIrGenerator generator)
{
applicationConfigStructureInfo = generator.MapStructure<ApplicationConfig> ();
generator.MapStructure<AssemblyStoreAssemblyDescriptor> ();
assemblyStoreSingleAssemblyRuntimeDataStructureinfo = generator.MapStructure<AssemblyStoreSingleAssemblyRuntimeData> ();
assemblyStoreRuntimeDataStructureInfo = generator.MapStructure<AssemblyStoreRuntimeData> ();
xamarinAndroidBundledAssemblyStructureInfo = generator.MapStructure<XamarinAndroidBundledAssembly> ();
dsoCacheEntryStructureInfo = generator.MapStructure<DSOCacheEntry> ();
}

protected override void Write (LlvmIrGenerator generator)
{
generator.WriteVariable ("format_tag", FORMAT_TAG);
generator.WriteString ("mono_aot_mode_name", MonoAOTMode);

generator.WriteNameValueArray ("app_environment_variables", environmentVariables);
generator.WriteNameValueArray ("app_system_properties", systemProperties);

generator.WriteStructure (applicationConfigStructureInfo, application_config, LlvmIrVariableOptions.GlobalConstant, "application_config");

WriteDSOCache (generator);
WriteBundledAssemblies (generator);
WriteAssemblyStoreAssemblies (generator);
}

void WriteAssemblyStoreAssemblies (LlvmIrGenerator generator)
{
ulong count = (ulong)(HaveAssemblyStore ? NumberOfAssembliesInApk : 0);
generator.WriteStructureArray<AssemblyStoreSingleAssemblyRuntimeData> (assemblyStoreSingleAssemblyRuntimeDataStructureinfo, count, "assembly_store_bundled_assemblies", initialComment: "Assembly store individual assembly data");

count = (ulong)(HaveAssemblyStore ? NumberOfAssemblyStoresInApks : 0);
generator.WriteStructureArray<AssemblyStoreRuntimeData> (assemblyStoreRuntimeDataStructureInfo, count, "assembly_stores", initialComment: "Assembly store data");
}

void WriteBundledAssemblies (LlvmIrGenerator generator)
void MapStructures (LlvmIrModule module)
{
generator.WriteStructureArray (xamarinAndroidBundledAssemblyStructureInfo, xamarinAndroidBundledAssemblies, "bundled_assemblies", initialComment: $"Bundled assembly name buffers, all {BundledAssemblyNameWidth} bytes long");
}

void WriteDSOCache (LlvmIrGenerator generator)
{
bool is64Bit = generator.Is64Bit;

// We need to hash here, because the hash is architecture-specific
foreach (StructureInstance<DSOCacheEntry> entry in dsoCache) {
entry.Obj.hash = HashName (entry.Obj.HashedName, is64Bit);
}
dsoCache.Sort ((StructureInstance<DSOCacheEntry> a, StructureInstance<DSOCacheEntry> b) => a.Obj.hash.CompareTo (b.Obj.hash));

generator.WriteStructureArray (dsoCacheEntryStructureInfo, dsoCache, "dso_cache");
applicationConfigStructureInfo = module.MapStructure<ApplicationConfig> ();
module.MapStructure<AssemblyStoreAssemblyDescriptor> ();
assemblyStoreSingleAssemblyRuntimeDataStructureinfo = module.MapStructure<AssemblyStoreSingleAssemblyRuntimeData> ();
assemblyStoreRuntimeDataStructureInfo = module.MapStructure<AssemblyStoreRuntimeData> ();
xamarinAndroidBundledAssemblyStructureInfo = module.MapStructure<XamarinAndroidBundledAssembly> ();
dsoCacheEntryStructureInfo = module.MapStructure<DSOCacheEntry> ();
}
}
}
Loading