Skip to content

Commit b3a091d

Browse files
committed
Changes from #10065
1 parent a7d3f99 commit b3a091d

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
@@ -7,13 +7,15 @@
77
using ReleaseGenerationState = Xamarin.Android.Tasks.TypeMapGenerator.ReleaseGenerationState;
88
using TypeMapDebugEntry = Xamarin.Android.Tasks.TypeMapGenerator.TypeMapDebugEntry;
99
using TypeMapReleaseEntry = Xamarin.Android.Tasks.TypeMapGenerator.TypeMapReleaseEntry;
10+
using TypeMapDebugDataSets = Xamarin.Android.Tasks.TypeMapGenerator.TypeMapDebugDataSets;
11+
using TypeMapDebugAssembly = Xamarin.Android.Tasks.TypeMapGenerator.TypeMapDebugAssembly;
1012

1113
namespace Xamarin.Android.Tasks;
1214

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

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

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

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

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

4262
SyncDebugDuplicates (javaDuplicates);
4363

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

4771
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
@@ -83,12 +83,27 @@ public override string ToString ()
8383
}
8484
}
8585

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

94109
internal sealed class ReleaseGenerationState
@@ -138,18 +153,23 @@ public void Generate (bool debugBuild, bool skipJniAddNativeMethodRegistrationAt
138153

139154
void GenerateDebugNativeAssembly (string outputDirectory)
140155
{
141-
(var javaToManaged, var managedToJava) = state.GetDebugNativeEntries ();
156+
TypeMapDebugDataSets dataSets = TypeMapCecilAdapter.GetDebugNativeEntries (state, needUniqueAssemblies: runtime == AndroidRuntime.CoreCLR);
142157

143158
var data = new ModuleDebugData {
144-
EntryCount = (uint)javaToManaged.Count,
145-
JavaToManagedMap = javaToManaged,
146-
ManagedToJavaMap = managedToJava,
159+
EntryCount = (uint)dataSets.JavaToManaged.Count,
160+
JavaToManagedMap = dataSets.JavaToManaged,
161+
ManagedToJavaMap = dataSets.ManagedToJava,
162+
UniqueAssemblies = dataSets.UniqueAssemblies,
147163
};
148164

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

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

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

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

1818
sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvider
1919
{
@@ -66,19 +66,19 @@ public override string GetComment (object data, string fieldName)
6666
var entry = EnsureType<TypeMapEntry> (data);
6767

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

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

7676
return String.Empty;
7777
}
7878
}
7979

8080
// Order of fields and their type must correspond *exactly* to that in
81-
// src/monodroid/jni/xamarin-app.hh TypeMapEntry structure
81+
// src/native/mono/xamarin-app-stub/xamarin-app.hh TypeMapEntry structure
8282
[NativeAssemblerStructContextDataProvider (typeof (TypeMapEntryContextDataProvider))]
8383
sealed class TypeMapEntry
8484
{
@@ -87,7 +87,7 @@ sealed class TypeMapEntry
8787
};
8888

8989
// Order of fields and their type must correspond *exactly* to that in
90-
// src/monodroid/jni/xamarin-app.hh TypeMap structure
90+
// src/native/mono/xamarin-app-stub/xamarin-app.hh TypeMap structure
9191
[NativeAssemblerStructContextDataProvider (typeof (TypeMapContextDataProvider))]
9292
sealed class TypeMap
9393
{
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)