Skip to content

Commit 2fc556e

Browse files
committed
Changes from #10065
1 parent d3d3584 commit 2fc556e

File tree

13 files changed

+482
-43
lines changed

13 files changed

+482
-43
lines changed

src/Xamarin.Android.Build.Tasks/Utilities/TypeMapCecilAdapter.cs

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
using ReleaseGenerationState = Xamarin.Android.Tasks.TypeMapGenerator.ReleaseGenerationState;
99
using TypeMapDebugEntry = Xamarin.Android.Tasks.TypeMapGenerator.TypeMapDebugEntry;
1010
using TypeMapReleaseEntry = Xamarin.Android.Tasks.TypeMapGenerator.TypeMapReleaseEntry;
11+
using TypeMapDebugDataSets = Xamarin.Android.Tasks.TypeMapGenerator.TypeMapDebugDataSets;
12+
using TypeMapDebugAssembly = Xamarin.Android.Tasks.TypeMapGenerator.TypeMapDebugAssembly;
1113

1214
namespace Xamarin.Android.Tasks;
1315

1416
// Converts types from Mono.Cecil to the format used by the typemap generator.
1517
class TypeMapCecilAdapter
1618
{
17-
public static (List<TypeMapDebugEntry> javaToManaged, List<TypeMapDebugEntry> managedToJava) GetDebugNativeEntries (NativeCodeGenState state)
19+
public static TypeMapDebugDataSets GetDebugNativeEntries (NativeCodeGenState state, bool needUniqueAssemblies)
1820
{
1921
var (javaToManaged, managedToJava, foundJniNativeRegistration) = GetDebugNativeEntries (state.AllJavaTypes, state.TypeCache);
2022

@@ -30,19 +32,41 @@ public static (List<TypeMapDebugEntry> javaToManaged, List<TypeMapDebugEntry> ma
3032
var managedToJava = new List<TypeMapDebugEntry> ();
3133
var foundJniNativeRegistration = false;
3234

33-
foreach (var td in types) {
34-
foundJniNativeRegistration = JniAddNativeMethodRegistrationAttributeFound (foundJniNativeRegistration, td);
35+
var javaDuplicates = new Dictionary<string, List<TypeMapDebugEntry>> (StringComparer.Ordinal);
36+
var uniqueAssemblies = needUniqueAssemblies ? new Dictionary<string, TypeMapDebugAssembly> (StringComparer.OrdinalIgnoreCase) : null;
37+
foreach (TypeDefinition td in state.AllJavaTypes) {
38+
UpdateApplicationConfig (state, td);
3539

3640
TypeMapDebugEntry entry = GetDebugEntry (td, cache);
3741
HandleDebugDuplicates (javaDuplicates, entry, td, cache);
3842

3943
javaToManaged.Add (entry);
4044
managedToJava.Add (entry);
45+
46+
if (uniqueAssemblies == null) {
47+
continue;
48+
}
49+
50+
string? asmName = td.Module.Assembly.Name.Name;
51+
if (String.IsNullOrEmpty (asmName) || uniqueAssemblies.ContainsKey (asmName)) {
52+
continue;
53+
}
54+
55+
var asmInfo = new TypeMapDebugAssembly {
56+
MVID = td.Module.Mvid,
57+
Name = asmName,
58+
};
59+
asmInfo.MVIDBytes = asmInfo.MVID.ToByteArray ();
60+
uniqueAssemblies.Add (asmName, asmInfo);
4161
}
4262

4363
SyncDebugDuplicates (javaDuplicates);
4464

45-
return (javaToManaged, managedToJava, foundJniNativeRegistration);
65+
return new TypeMapDebugDataSets {
66+
JavaToManaged = javaToManaged,
67+
ManagedToJava = managedToJava,
68+
UniqueAssemblies = uniqueAssemblies != null ? new List<TypeMapDebugAssembly> (uniqueAssemblies.Values) : null
69+
};
4670
}
4771

4872
public static ReleaseGenerationState GetReleaseGenerationState (NativeCodeGenState state)

src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,27 @@ public override string ToString ()
8181
}
8282
}
8383

84+
internal sealed class TypeMapDebugAssembly
85+
{
86+
public Guid MVID;
87+
public byte[] MVIDBytes;
88+
public string Name;
89+
}
90+
91+
internal sealed class TypeMapDebugDataSets
92+
{
93+
public List<TypeMapDebugEntry> JavaToManaged ;
94+
public List<TypeMapDebugEntry> ManagedToJava;
95+
public List<TypeMapDebugAssembly>? UniqueAssemblies;
96+
}
97+
8498
// Widths include the terminating nul character but not the padding!
8599
internal sealed class ModuleDebugData
86100
{
87101
public uint EntryCount;
88102
public List<TypeMapDebugEntry> JavaToManagedMap;
89103
public List<TypeMapDebugEntry> ManagedToJavaMap;
104+
public List<TypeMapDebugAssembly>? UniqueAssemblies;
90105
}
91106

92107
internal sealed class ReleaseGenerationState
@@ -136,18 +151,23 @@ public void Generate (bool debugBuild, bool skipJniAddNativeMethodRegistrationAt
136151

137152
void GenerateDebugNativeAssembly (string outputDirectory)
138153
{
139-
(var javaToManaged, var managedToJava) = state.GetDebugNativeEntries ();
154+
TypeMapDebugDataSets dataSets = TypeMapCecilAdapter.GetDebugNativeEntries (state, needUniqueAssemblies: runtime == AndroidRuntime.CoreCLR);
140155

141156
var data = new ModuleDebugData {
142-
EntryCount = (uint)javaToManaged.Count,
143-
JavaToManagedMap = javaToManaged,
144-
ManagedToJavaMap = managedToJava,
157+
EntryCount = (uint)dataSets.JavaToManaged.Count,
158+
JavaToManagedMap = dataSets.JavaToManaged,
159+
ManagedToJavaMap = dataSets.ManagedToJava,
160+
UniqueAssemblies = dataSets.UniqueAssemblies,
145161
};
146162

147163
data.JavaToManagedMap.Sort ((TypeMapDebugEntry a, TypeMapDebugEntry b) => String.Compare (a.JavaName, b.JavaName, StringComparison.Ordinal));
148164
data.ManagedToJavaMap.Sort ((TypeMapDebugEntry a, TypeMapDebugEntry b) => String.Compare (a.ManagedName, b.ManagedName, StringComparison.Ordinal));
149165

150-
var composer = new TypeMappingDebugNativeAssemblyGenerator (log, data);
166+
LLVMIR.LlvmIrComposer composer = runtime switch {
167+
AndroidRuntime.MonoVM => new TypeMappingDebugNativeAssemblyGenerator (log, data),
168+
AndroidRuntime.CoreCLR => new TypeMappingDebugNativeAssemblyGeneratorCLR (log, data),
169+
_ => throw new NotSupportedException ($"Internal error: unsupported runtime {runtime}")
170+
};
151171
GenerateNativeAssembly (composer, composer.Construct (), outputDirectory);
152172
}
153173

src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class TypeMappingDebugNativeAssemblyGenerator : LlvmIrComposer
1111
{
1212
const string JavaToManagedSymbol = "map_java_to_managed";
1313
const string ManagedToJavaSymbol = "map_managed_to_java";
14-
const string TypeMapSymbol = "type_map"; // MUST match src/monodroid/xamarin-app.hh
14+
const string TypeMapSymbol = "type_map"; // MUST match src/native/mono/xamarin-app-stub/xamarin-app.hh
1515

1616
sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvider
1717
{
@@ -64,19 +64,19 @@ public override string GetComment (object data, string fieldName)
6464
var entry = EnsureType<TypeMapEntry> (data);
6565

6666
if (String.Compare ("from", fieldName, StringComparison.Ordinal) == 0) {
67-
return $"from: entry.from";
67+
return $"from: {entry.from}";
6868
}
6969

7070
if (String.Compare ("to", fieldName, StringComparison.Ordinal) == 0) {
71-
return $"to: entry.to";
71+
return $"to: {entry.to}";
7272
}
7373

7474
return String.Empty;
7575
}
7676
}
7777

7878
// Order of fields and their type must correspond *exactly* to that in
79-
// src/monodroid/jni/xamarin-app.hh TypeMapEntry structure
79+
// src/native/mono/xamarin-app-stub/xamarin-app.hh TypeMapEntry structure
8080
[NativeAssemblerStructContextDataProvider (typeof (TypeMapEntryContextDataProvider))]
8181
sealed class TypeMapEntry
8282
{
@@ -85,7 +85,7 @@ sealed class TypeMapEntry
8585
};
8686

8787
// Order of fields and their type must correspond *exactly* to that in
88-
// src/monodroid/jni/xamarin-app.hh TypeMap structure
88+
// src/native/mono/xamarin-app-stub/xamarin-app.hh TypeMap structure
8989
[NativeAssemblerStructContextDataProvider (typeof (TypeMapContextDataProvider))]
9090
sealed class TypeMap
9191
{
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
using Microsoft.Build.Utilities;
5+
6+
using Xamarin.Android.Tasks.LLVMIR;
7+
8+
namespace Xamarin.Android.Tasks;
9+
10+
class TypeMappingDebugNativeAssemblyGeneratorCLR : LlvmIrComposer
11+
{
12+
const string JavaToManagedSymbol = "map_java_to_managed";
13+
const string ManagedToJavaSymbol = "map_managed_to_java";
14+
15+
// These names MUST match src/native/clr/include/xamarin-app.hh
16+
const string TypeMapSymbol = "type_map";
17+
const string UniqueAssembliesSymbol = "type_map_unique_assemblies";
18+
const string AssemblyNamesBlobSymbol = "type_map_assembly_names_blob";
19+
20+
sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvider
21+
{
22+
public override ulong GetBufferSize (object data, string fieldName)
23+
{
24+
var map_module = EnsureType<TypeMap> (data);
25+
if (String.Compare ("java_to_managed", fieldName, StringComparison.Ordinal) == 0 ||
26+
String.Compare ("managed_to_java", fieldName, StringComparison.Ordinal) == 0) {
27+
return map_module.entry_count;
28+
}
29+
30+
return 0;
31+
}
32+
33+
public override string GetPointedToSymbolName (object data, string fieldName)
34+
{
35+
var map_module = EnsureType<TypeMap> (data);
36+
37+
if (String.Compare ("java_to_managed", fieldName, StringComparison.Ordinal) == 0) {
38+
return map_module.JavaToManagedCount == 0 ? null : JavaToManagedSymbol;
39+
}
40+
41+
if (String.Compare ("managed_to_java", fieldName, StringComparison.Ordinal) == 0) {
42+
return map_module.ManagedToJavaCount == 0 ? null : ManagedToJavaSymbol;
43+
}
44+
45+
return base.GetPointedToSymbolName (data, fieldName);
46+
}
47+
}
48+
49+
sealed class TypeMapEntryContextDataProvider : NativeAssemblerStructContextDataProvider
50+
{
51+
public override string GetComment (object data, string fieldName)
52+
{
53+
var entry = EnsureType<TypeMapEntry> (data);
54+
55+
if (String.Compare ("from", fieldName, StringComparison.Ordinal) == 0) {
56+
return $"from: {entry.from}";
57+
}
58+
59+
if (String.Compare ("to", fieldName, StringComparison.Ordinal) == 0) {
60+
return $"to: {entry.to}";
61+
}
62+
63+
return String.Empty;
64+
}
65+
}
66+
67+
sealed class TypeMapAssemblyContextDataProvider : NativeAssemblerStructContextDataProvider
68+
{
69+
public override string GetComment (object data, string fieldName)
70+
{
71+
var entry = EnsureType<TypeMapAssembly> (data);
72+
73+
if (String.Compare ("mvid_hash", fieldName, StringComparison.Ordinal) == 0) {
74+
return $" MVID: {entry.MVID}";
75+
}
76+
77+
if (String.Compare ("name_offset", fieldName, StringComparison.Ordinal) == 0) {
78+
return $" {entry.Name}";
79+
}
80+
81+
return String.Empty;
82+
}
83+
}
84+
85+
// Order of fields and their type must correspond *exactly* to that in
86+
// src/native/clr/include/xamarin-app.hh TypeMapEntry structure
87+
[NativeAssemblerStructContextDataProvider (typeof (TypeMapEntryContextDataProvider))]
88+
sealed class TypeMapEntry
89+
{
90+
[NativeAssembler (UsesDataProvider = true)]
91+
public string from;
92+
93+
[NativeAssembler (UsesDataProvider = true)]
94+
public string to;
95+
};
96+
97+
// Order of fields and their type must correspond *exactly* to that in
98+
// src/native/clr/include/xamarin-app.hh TypeMap structure
99+
[NativeAssemblerStructContextDataProvider (typeof (TypeMapContextDataProvider))]
100+
sealed class TypeMap
101+
{
102+
[NativeAssembler (Ignore = true)]
103+
public int JavaToManagedCount;
104+
105+
[NativeAssembler (Ignore = true)]
106+
public int ManagedToJavaCount;
107+
108+
public uint entry_count;
109+
public ulong unique_assemblies_count;
110+
public ulong assembly_names_blob_size;
111+
112+
[NativeAssembler (UsesDataProvider = true), NativePointer (PointsToSymbol = "")]
113+
public TypeMapEntry? java_to_managed = null;
114+
115+
[NativeAssembler (UsesDataProvider = true), NativePointer (PointsToSymbol = "")]
116+
public TypeMapEntry? managed_to_java = null;
117+
};
118+
119+
// Order of fields and their type must correspond *exactly* to that in
120+
// src/native/clr/include/xamarin-app.hh TypeMapAssembly structure
121+
[NativeAssemblerStructContextDataProvider (typeof (TypeMapAssemblyContextDataProvider))]
122+
sealed class TypeMapAssembly
123+
{
124+
[NativeAssembler (Ignore = true)]
125+
public string Name;
126+
127+
[NativeAssembler (Ignore = true)]
128+
public Guid MVID;
129+
130+
[NativeAssembler (UsesDataProvider = true, NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)]
131+
public ulong mvid_hash;
132+
public ulong name_length;
133+
134+
[NativeAssembler (UsesDataProvider = true)]
135+
public ulong name_offset;
136+
}
137+
138+
readonly TypeMapGenerator.ModuleDebugData data;
139+
StructureInfo typeMapEntryStructureInfo;
140+
StructureInfo typeMapStructureInfo;
141+
StructureInfo typeMapAssemblyStructureInfo;
142+
List<StructureInstance<TypeMapEntry>> javaToManagedMap;
143+
List<StructureInstance<TypeMapEntry>> managedToJavaMap;
144+
List<StructureInstance<TypeMapAssembly>> uniqueAssemblies;
145+
StructureInstance<TypeMap> type_map;
146+
147+
public TypeMappingDebugNativeAssemblyGeneratorCLR (TaskLoggingHelper log, TypeMapGenerator.ModuleDebugData data)
148+
: base (log)
149+
{
150+
if (data.UniqueAssemblies == null || data.UniqueAssemblies.Count == 0) {
151+
throw new InvalidOperationException ("Internal error: set of unique assemblies must be provided.");
152+
}
153+
154+
this.data = data;
155+
156+
javaToManagedMap = new ();
157+
managedToJavaMap = new ();
158+
uniqueAssemblies = new ();
159+
}
160+
161+
protected override void Construct (LlvmIrModule module)
162+
{
163+
module.DefaultStringGroup = "tmd";
164+
165+
MapStructures (module);
166+
167+
if (data.ManagedToJavaMap != null && data.ManagedToJavaMap.Count > 0) {
168+
foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.ManagedToJavaMap) {
169+
var m2j = new TypeMapEntry {
170+
from = entry.ManagedName,
171+
to = entry.JavaName,
172+
};
173+
managedToJavaMap.Add (new StructureInstance<TypeMapEntry> (typeMapEntryStructureInfo, m2j));
174+
}
175+
}
176+
177+
if (data.JavaToManagedMap != null && data.JavaToManagedMap.Count > 0) {
178+
foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.JavaToManagedMap) {
179+
TypeMapGenerator.TypeMapDebugEntry managedEntry = entry.DuplicateForJavaToManaged != null ? entry.DuplicateForJavaToManaged : entry;
180+
181+
var j2m = new TypeMapEntry {
182+
from = entry.JavaName,
183+
to = managedEntry.SkipInJavaToManaged ? null : managedEntry.ManagedName,
184+
};
185+
javaToManagedMap.Add (new StructureInstance<TypeMapEntry> (typeMapEntryStructureInfo, j2m));
186+
}
187+
}
188+
189+
// CoreCLR supports only 64-bit targets, so we can make things simpler by hashing the MVIDs here instead of
190+
// in a callback during code generation
191+
var assemblyNamesBlob = new List<byte> ();
192+
foreach (TypeMapGenerator.TypeMapDebugAssembly asm in data.UniqueAssemblies) {
193+
byte[] nameBytes = MonoAndroidHelper.Utf8StringToBytes (asm.Name);
194+
var entry = new TypeMapAssembly {
195+
Name = asm.Name,
196+
MVID = asm.MVID,
197+
198+
mvid_hash = MonoAndroidHelper.GetXxHash (asm.MVIDBytes, is64Bit: true),
199+
name_length = (ulong)nameBytes.Length, // without the trailing NUL
200+
name_offset = (ulong)assemblyNamesBlob.Count,
201+
};
202+
uniqueAssemblies.Add (new StructureInstance<TypeMapAssembly> (typeMapAssemblyStructureInfo, entry));
203+
assemblyNamesBlob.AddRange (nameBytes);
204+
assemblyNamesBlob.Add (0);
205+
}
206+
uniqueAssemblies.Sort ((StructureInstance<TypeMapAssembly> a, StructureInstance<TypeMapAssembly> b) => a.Instance.mvid_hash.CompareTo (b.Instance.mvid_hash));
207+
208+
var map = new TypeMap {
209+
JavaToManagedCount = data.JavaToManagedMap == null ? 0 : data.JavaToManagedMap.Count,
210+
ManagedToJavaCount = data.ManagedToJavaMap == null ? 0 : data.ManagedToJavaMap.Count,
211+
212+
entry_count = data.EntryCount,
213+
unique_assemblies_count = (ulong)data.UniqueAssemblies.Count,
214+
assembly_names_blob_size = (ulong)assemblyNamesBlob.Count,
215+
};
216+
type_map = new StructureInstance<TypeMap> (typeMapStructureInfo, map);
217+
module.AddGlobalVariable (TypeMapSymbol, type_map, LlvmIrVariableOptions.GlobalConstant);
218+
219+
if (managedToJavaMap.Count > 0) {
220+
module.AddGlobalVariable (ManagedToJavaSymbol, managedToJavaMap, LlvmIrVariableOptions.LocalConstant);
221+
}
222+
223+
if (javaToManagedMap.Count > 0) {
224+
module.AddGlobalVariable (JavaToManagedSymbol, javaToManagedMap, LlvmIrVariableOptions.LocalConstant);
225+
}
226+
227+
module.AddGlobalVariable (UniqueAssembliesSymbol, uniqueAssemblies, LlvmIrVariableOptions.GlobalConstant);
228+
module.AddGlobalVariable (AssemblyNamesBlobSymbol, assemblyNamesBlob, LlvmIrVariableOptions.GlobalConstant);
229+
}
230+
231+
void MapStructures (LlvmIrModule module)
232+
{
233+
typeMapAssemblyStructureInfo = module.MapStructure<TypeMapAssembly> ();
234+
typeMapEntryStructureInfo = module.MapStructure<TypeMapEntry> ();
235+
typeMapStructureInfo = module.MapStructure<TypeMap> ();
236+
}
237+
}

0 commit comments

Comments
 (0)