Skip to content

Commit 690efa6

Browse files
committed
[WIP] Generate duplicate maps
1 parent e73a971 commit 690efa6

File tree

6 files changed

+132
-85
lines changed

6 files changed

+132
-85
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ public NativeTypeMappingData (IDictionary<byte[], TypeMapGenerator.ModuleData> m
3333
AssemblyNames.Add (data.AssemblyNameLabel, data.AssemblyName);
3434

3535
int moduleIndex = moduleList.IndexOf (data);
36-
foreach (TypeMapGenerator.TypeMapEntry entry in data.Types) {
36+
foreach (var kvp2 in data.Types) {
37+
TypeMapGenerator.TypeMapEntry entry = kvp2.Value;
3738
entry.ModuleIndex = moduleIndex;
38-
JavaTypes[entry.JavaName] = entry;
39+
JavaTypes.Add (entry.JavaName, entry);
3940
}
4041
}
4142
}

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

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ internal sealed class ModuleData
4848
{
4949
public Guid Mvid;
5050
public AssemblyDefinition Assembly;
51-
public List<TypeMapEntry> Types;
51+
public SortedDictionary<string, TypeMapEntry> Types;
52+
public Dictionary<uint, TypeMapEntry> DuplicateTypes;
5253
public string AssemblyName;
5354
public string AssemblyNameLabel;
5455
public string OutputFilePath;
@@ -124,7 +125,8 @@ public bool Generate (DirectoryAssemblyResolver resolver, IEnumerable<string> as
124125
Mvid = td.Module.Mvid,
125126
Assembly = td.Module.Assembly,
126127
AssemblyName = td.Module.Assembly.Name.Name,
127-
Types = new List<TypeMapEntry> (),
128+
Types = new SortedDictionary<string, TypeMapEntry> (StringComparer.Ordinal),
129+
DuplicateTypes = new Dictionary<uint, TypeMapEntry> (),
128130
};
129131
modules.Add (moduleUUID, moduleData);
130132

@@ -151,14 +153,18 @@ public bool Generate (DirectoryAssemblyResolver resolver, IEnumerable<string> as
151153
maxJavaNameLength = javaName.Length;
152154
}
153155

154-
moduleData.Types.Add (
155-
new TypeMapEntry {
156-
JavaName = javaName,
157-
ManagedTypeName = td.FullName,
158-
Token = td.MetadataToken.ToUInt32 (),
159-
AssemblyNameIndex = knownAssemblies [assemblyName]
160-
}
161-
);
156+
var entry = new TypeMapEntry {
157+
JavaName = javaName,
158+
ManagedTypeName = td.FullName,
159+
Token = td.MetadataToken.ToUInt32 (),
160+
AssemblyNameIndex = knownAssemblies [assemblyName]
161+
};
162+
163+
if (moduleData.Types.ContainsKey (entry.JavaName)) {
164+
logger ($"Warning: duplicate Java type name '{entry.JavaName}' (new token: {entry.Token}).");
165+
moduleData.DuplicateTypes.Add (entry.Token, entry);
166+
} else
167+
moduleData.Types.Add (entry.JavaName, entry);
162168
}
163169

164170
NativeTypeMappingData data;
@@ -269,15 +275,17 @@ void OutputModule (string outputDirectory, byte[] moduleUUID, ModuleData moduleD
269275

270276
// Binary file format, all data is little-endian:
271277
//
272-
// [Magic string] # XATM
273-
// [Format version] # 32-bit integer, 4 bytes
274-
// [Module UUID] # 16 bytes
275-
// [Entry count] # 32-bit integer, 4 bytes
276-
// [Java type name width] # 32-bit integer, 4 bytes
277-
// [Assembly name size] # 32-bit integer, 4 bytes
278-
// [Assembly name] # Non-null terminated assembly name
279-
// [Java-to-managed map] # Format described below, [Entry count] entries
280-
// [Managed-to-java map] # Format described below, [Entry count] entries
278+
// [Magic string] # XATM
279+
// [Format version] # 32-bit integer, 4 bytes
280+
// [Module UUID] # 16 bytes
281+
// [Entry count] # 32-bit integer, 4 bytes
282+
// [Duplicate count] # 32-bit integer, 4 bytes (might be 0)
283+
// [Java type name width] # 32-bit integer, 4 bytes
284+
// [Assembly name size] # 32-bit integer, 4 bytes
285+
// [Assembly name] # Non-null terminated assembly name
286+
// [Java-to-managed map] # Format described below, [Entry count] entries
287+
// [Managed-to-java map] # Format described below, [Entry count] entries
288+
// [Managed-to-java duplicates map] # Map of unique managed IDs which point to the same Java type name (might be empty)
281289
//
282290
// Java-to-managed map format:
283291
//
@@ -297,27 +305,22 @@ void OutputModule (string outputDirectory, byte[] moduleUUID, ModuleData moduleD
297305
// Both fields are 32-bit integers, to a total of 8 bytes per entry. Index points into the
298306
// [Java-to-managed map] table above.
299307
//
308+
// Managed-to-java duplicates map format:
309+
//
310+
// Format is identical to [Managed-to-java] above.
311+
//
300312
void OutputModule (BinaryWriter bw, byte[] moduleUUID, ModuleData moduleData)
301313
{
302314
bw.Write (moduleMagicString);
303315
bw.Write (TypeMapFormatVersion);
304316
bw.Write (moduleUUID);
305317

306318
var javaNames = new SortedDictionary<string, uint> (StringComparer.Ordinal);
307-
var duplicateJavaNames = new Dictionary<string, bool> (StringComparer.Ordinal);
308319
var managedTypes = new SortedDictionary<uint, uint> ();
309-
310-
// TODO: put duplicate types in a separate list (typeid:index) at the end of the typemap file/assembly code
311-
// and mark such entries somehow in the typeid->java table (e.g. set the high bit of the index, it's unlikely
312-
// we'd have 4 billion entries)
313320
int maxJavaNameLength = 0;
314-
foreach (TypeMapEntry entry in moduleData.Types) {
315-
if (javaNames.ContainsKey (entry.JavaName)) {
316-
logger ($"Warning: duplicate Java type name '{entry.JavaName}' (old token: {javaNames [entry.JavaName]}; new token: {entry.Token}). Ignoring the new type.");
317-
if (!duplicateJavaNames.ContainsKey (entry.JavaName))
318-
duplicateJavaNames.Add (entry.JavaName, false);
319-
continue;
320-
}
321+
322+
foreach (var kvp in moduleData.Types) {
323+
TypeMapEntry entry = kvp.Value;
321324

322325
javaNames.Add (entry.JavaName, entry.Token);
323326
if (entry.JavaName.Length > maxJavaNameLength)
@@ -327,17 +330,14 @@ void OutputModule (BinaryWriter bw, byte[] moduleUUID, ModuleData moduleData)
327330
}
328331

329332
var javaNameList = javaNames.Keys.ToList ();
330-
foreach (TypeMapEntry entry in moduleData.Types) {
331-
if (duplicateJavaNames.TryGetValue (entry.JavaName, out bool skip)) {
332-
if (skip)
333-
continue;
334-
duplicateJavaNames [entry.JavaName] = true;
335-
}
336-
337-
managedTypes [entry.Token] = (uint)javaNameList.IndexOf (entry.JavaName);
333+
foreach (var kvp in moduleData.Types) {
334+
TypeMapEntry entry = kvp.Value;
335+
var javaIndex = (uint)javaNameList.IndexOf (entry.JavaName);
336+
managedTypes.Add (entry.Token, javaIndex);
338337
}
339338

340339
bw.Write (javaNames.Count);
340+
bw.Write (moduleData.DuplicateTypes.Count);
341341
bw.Write (maxJavaNameLength + 1);
342342

343343
string assemblyName = moduleData.Assembly.Name.Name;
@@ -353,12 +353,29 @@ void OutputModule (BinaryWriter bw, byte[] moduleUUID, ModuleData moduleData)
353353
bw.Write (token);
354354
}
355355

356-
foreach (var kvp in managedTypes) {
357-
uint token = kvp.Key;
358-
uint javaIndex = kvp.Value;
356+
WriteManagedTypes (managedTypes);
357+
if (moduleData.DuplicateTypes.Count == 0)
358+
return;
359359

360-
bw.Write (token);
361-
bw.Write (javaIndex);
360+
var managedDuplicates = new SortedDictionary<uint, uint> ();
361+
foreach (var kvp in moduleData.DuplicateTypes) {
362+
uint javaIndex = kvp.Key;
363+
uint typeId = kvp.Value.Token;
364+
365+
managedDuplicates.Add (javaIndex, typeId);
366+
}
367+
368+
WriteManagedTypes (managedDuplicates);
369+
370+
void WriteManagedTypes (IDictionary<uint, uint> types)
371+
{
372+
foreach (var kvp in types) {
373+
uint token = kvp.Key;
374+
uint javaIndex = kvp.Value;
375+
376+
bw.Write (token);
377+
bw.Write (javaIndex);
378+
}
362379
}
363380
}
364381

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

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,15 @@ void WriteAssemblyNames (StreamWriter output)
9999
}
100100
}
101101

102-
void WriteManagedMaps (StreamWriter output, string moduleSymbolName, TypeMapGenerator.ModuleData data)
102+
void WriteManagedMaps<TKey> (StreamWriter output, string moduleSymbolName, IDictionary<TKey, TypeMapGenerator.TypeMapEntry> entries)
103103
{
104+
if (entries == null || entries.Count == 0)
105+
return;
106+
104107
var javaTypes = mappingData.JavaTypes.Keys.ToList ();
105108
var tokens = new SortedDictionary<uint, uint> ();
106-
foreach (TypeMapGenerator.TypeMapEntry entry in data.Types) {
109+
foreach (var kvp in entries) {
110+
TypeMapGenerator.TypeMapEntry entry = kvp.Value;
107111
tokens[entry.Token] = (uint)javaTypes.IndexOf (entry.JavaName);
108112
}
109113

@@ -143,17 +147,26 @@ void WriteMapModules (StreamWriter output, StreamWriter mapOutput, string symbol
143147
TypeMapGenerator.ModuleData data = kvp.Value;
144148

145149
string mapName = $"module{moduleCounter++}_managed_to_java";
146-
size += WriteStructure (output, fieldAlignBytes, () => WriteMapModule (output, mapName, mvid, data));
147-
if (mapOutput != null)
148-
WriteManagedMaps (mapOutput, mapName, data);
150+
string duplicateMapName;
151+
152+
if (data.DuplicateTypes.Count == 0)
153+
duplicateMapName = null;
154+
else
155+
duplicateMapName = $"{mapName}_duplicates";
156+
157+
size += WriteStructure (output, fieldAlignBytes, () => WriteMapModule (output, mapName, duplicateMapName, mvid, data));
158+
if (mapOutput != null) {
159+
WriteManagedMaps (mapOutput, mapName, data.Types);
160+
WriteManagedMaps (mapOutput, duplicateMapName, data.DuplicateTypes);
161+
}
149162
}
150163

151164
WriteStructureSize (output, symbolName, size);
152165
WriteCommentLine (output, "Managed to Java map: END", indent: false);
153166
output.WriteLine ();
154167
}
155168

156-
uint WriteMapModule (StreamWriter output, string mapName, byte[] mvid, TypeMapGenerator.ModuleData data)
169+
uint WriteMapModule (StreamWriter output, string mapName, string duplicateMapName, byte[] mvid, TypeMapGenerator.ModuleData data)
157170
{
158171
uint size = 0;
159172
WriteCommentLine (output, $"module_uuid: {data.Mvid}");
@@ -162,9 +175,15 @@ uint WriteMapModule (StreamWriter output, string mapName, byte[] mvid, TypeMapGe
162175
WriteCommentLine (output, "entry_count");
163176
size += WriteData (output, data.Types.Count);
164177

178+
WriteCommentLine (output, "duplicate_count");
179+
size += WriteData (output, data.DuplicateTypes.Count);
180+
165181
WriteCommentLine (output, "map");
166182
size += WritePointer (output, mapName);
167183

184+
WriteCommentLine (output, "duplicate_map");
185+
size += WritePointer (output, duplicateMapName);
186+
168187
WriteCommentLine (output, $"assembly_name: {data.AssemblyName}");
169188
size += WritePointer (output, MakeLocalLabel (data.AssemblyNameLabel));
170189

src/monodroid/jni/embedded-assemblies.cc

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -602,27 +602,12 @@ EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const
602602
}
603603

604604
bool
605-
EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMapModule &module)
605+
EmbeddedAssemblies::typemap_load_file (BinaryTypeMapHeader &header, const char *dir_path, const char *file_path, int file_fd, TypeMapModule &module)
606606
{
607-
log_debug (LOG_ASSEMBLY, "Loading TypeMap file '%s/%s'", dir_path, file_path);
608-
609-
bool ret = true;
610-
BinaryTypeMapHeader header;
611-
size_t file_size;
612-
int fd = -1;
613-
size_t alloc_size;
614-
ssize_t nread;;
615-
char *chars;
616-
uint8_t *p;
617-
618-
if (!typemap_read_header (dir_fd, "TypeMap", dir_path, file_path, MODULE_MAGIC, header, file_size, fd)) {
619-
ret = false;
620-
goto cleanup;
621-
}
622-
623-
alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, header.assembly_name_length, 1);
607+
size_t alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, header.assembly_name_length, 1);
624608
module.assembly_name = new char[alloc_size];
625-
nread = read (fd, module.assembly_name, header.assembly_name_length);
609+
610+
ssize_t nread = read (file_fd, module.assembly_name, header.assembly_name_length);
626611
module.assembly_name [header.assembly_name_length] = 0;
627612
module.entry_count = header.entry_count;
628613

@@ -632,31 +617,23 @@ EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const c
632617
alloc_size = MULTIPLY_WITH_OVERFLOW_CHECK (size_t, header.java_name_width + 4, header.entry_count);
633618
module.java_name_width = header.java_name_width;
634619
module.java_map = new uint8_t[alloc_size];
635-
nread = read (fd, module.java_map, alloc_size);
620+
nread = read (file_fd, module.java_map, alloc_size);
636621
if (nread != static_cast<ssize_t>(alloc_size)) {
637622
log_error (LOG_ASSEMBLY, "Failed to read %u bytes (java-to-managed) from module file %s/%s. %s", alloc_size, dir_path, file_path, strerror (errno));
638-
ret = false;
639-
delete[] module.java_map;
640-
module.java_map = nullptr;
641-
goto cleanup;
623+
return false;
642624
}
643625

644626
module.map = new TypeMapModuleEntry[header.entry_count];
645627
alloc_size = MULTIPLY_WITH_OVERFLOW_CHECK (size_t, sizeof(TypeMapModuleEntry), header.entry_count);
646-
nread = read (fd, module.map, alloc_size);
628+
nread = read (file_fd, module.map, alloc_size);
647629
if (nread != static_cast<ssize_t>(alloc_size)) {
648630
log_error (LOG_ASSEMBLY, "Failed to read %u bytes (managed-to-java) from module file %s/%s. %s", alloc_size, dir_path, file_path, strerror (errno));
649-
ret = false;
650-
delete[] module.java_map;
651-
module.java_map = nullptr;
652-
delete[] module.map;
653-
module.map = nullptr;
654-
goto cleanup;
631+
return false;
655632
}
656633

657634
alloc_size = module.java_name_width + 1;
658-
chars = new char[alloc_size]();
659-
p = module.java_map;
635+
auto chars = new char[alloc_size]();
636+
uint8_t *p = module.java_map;
660637
log_debug (LOG_ASSEMBLY, "Java entries in %s/%s", dir_path, file_path);
661638
for (size_t i = 0; i < module.entry_count; i++) {
662639
memcpy (chars, p, module.java_name_width);
@@ -671,10 +648,40 @@ EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const c
671648
log_debug (LOG_ASSEMBLY, " %04u: token %u (0x%x); index %u", i, module.map[i].type_token_id, module.map[i].type_token_id, module.map[i].java_map_index);
672649
}
673650

651+
return true;
652+
}
653+
654+
bool
655+
EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMapModule &module)
656+
{
657+
log_debug (LOG_ASSEMBLY, "Loading TypeMap file '%s/%s'", dir_path, file_path);
658+
659+
bool ret = true;
660+
BinaryTypeMapHeader header;
661+
size_t file_size;
662+
int fd = -1;
663+
664+
module.java_map = nullptr;
665+
module.map = nullptr;
666+
667+
if (!typemap_read_header (dir_fd, "TypeMap", dir_path, file_path, MODULE_MAGIC, header, file_size, fd)) {
668+
ret = false;
669+
goto cleanup;
670+
}
671+
672+
ret = typemap_load_file (header, dir_path, file_path, fd, module);
673+
674674
cleanup:
675675
if (fd >= 0)
676676
close (fd);
677677

678+
if (!ret) {
679+
delete[] module.java_map;
680+
module.java_map = nullptr;
681+
delete[] module.map;
682+
module.map = nullptr;
683+
}
684+
678685
return ret;
679686
}
680687

src/monodroid/jni/embedded-assemblies.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ namespace xamarin::android::internal {
7878
uint8_t* typemap_load_index (int dir_fd, const char *dir_path, const char *index_path);
7979
uint8_t* typemap_load_index (TypeMapIndexHeader &header, size_t file_size, int index_fd);
8080
bool typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMapModule &module);
81+
bool typemap_load_file (BinaryTypeMapHeader &header, const char *dir_path, const char *file_path, int file_fd, TypeMapModule &module);
8182
#endif // DEBUG || !ANDROID
8283
bool register_debug_symbols_for_assembly (const char *entry_name, MonoBundledAssembly *assembly, const mono_byte *debug_contents, int debug_size);
8384

src/monodroid/jni/xamarin-app.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ struct BinaryTypeMapHeader
1818
uint32_t version;
1919
uint8_t module_uuid[16];
2020
uint32_t entry_count;
21+
uint32_t duplicate_count;
2122
uint32_t java_name_width;
2223
uint32_t assembly_name_length;
2324
};
@@ -41,6 +42,7 @@ struct TypeMapModule
4142
uint8_t module_uuid[16];
4243
uint32_t entry_count;
4344
TypeMapModuleEntry *map;
45+
TypeMapModuleEntry *duplicate_map;
4446
char *assembly_name;
4547
MonoImage *image;
4648
#ifdef DEBUG

0 commit comments

Comments
 (0)