Skip to content

Commit e73a971

Browse files
committed
Update for changes introduced in 130905e
1 parent 6544965 commit e73a971

File tree

5 files changed

+178
-41
lines changed

5 files changed

+178
-41
lines changed

src/Mono.Android/Android.Runtime/AndroidRuntime.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
234234
foreach (var simpleRef in base.GetSimpleReferences (type)) {
235235
yield return simpleRef;
236236
}
237-
var j = JNIEnv.monodroid_typemap_managed_to_java (type.FullName + ", " + type.Assembly.GetName ().Name);
237+
var j = JNIEnv.monodroid_typemap_managed_to_java (type.Module.ModuleVersionId.ToByteArray (), type.MetadataToken);
238238
if (j != IntPtr.Zero) {
239239
yield return Marshal.PtrToStringAnsi (j);
240240
}

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,13 +304,18 @@ void OutputModule (BinaryWriter bw, byte[] moduleUUID, ModuleData moduleData)
304304
bw.Write (moduleUUID);
305305

306306
var javaNames = new SortedDictionary<string, uint> (StringComparer.Ordinal);
307+
var duplicateJavaNames = new Dictionary<string, bool> (StringComparer.Ordinal);
307308
var managedTypes = new SortedDictionary<uint, uint> ();
308-
var managedTypeNames = new Dictionary<uint, string> ();
309309

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)
310313
int maxJavaNameLength = 0;
311314
foreach (TypeMapEntry entry in moduleData.Types) {
312315
if (javaNames.ContainsKey (entry.JavaName)) {
313316
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);
314319
continue;
315320
}
316321

@@ -319,16 +324,21 @@ void OutputModule (BinaryWriter bw, byte[] moduleUUID, ModuleData moduleData)
319324
maxJavaNameLength = entry.JavaName.Length;
320325

321326
managedTypes.Add (entry.Token, 0);
322-
managedTypeNames.Add (entry.Token, entry.ManagedTypeName);
323327
}
324328

325329
var javaNameList = javaNames.Keys.ToList ();
326330
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+
327337
managedTypes [entry.Token] = (uint)javaNameList.IndexOf (entry.JavaName);
328338
}
329339

330340
bw.Write (javaNames.Count);
331-
bw.Write (maxJavaNameLength);
341+
bw.Write (maxJavaNameLength + 1);
332342

333343
string assemblyName = moduleData.Assembly.Name.Name;
334344
bw.Write (assemblyName.Length);

src/monodroid/jni/embedded-assemblies.cc

Lines changed: 153 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -162,26 +162,35 @@ EmbeddedAssemblies::binary_search (const Key *key, const Entry *base, size_t nme
162162
MonoReflectionType*
163163
EmbeddedAssemblies::typemap_java_to_managed (MonoString *java_type)
164164
{
165-
// #if defined (DEBUG) || !defined (ANDROID)
166-
// for (TypeMappingInfo *info = java_to_managed_maps; info != nullptr; info = info->next) {
167-
// /* log_warn (LOG_DEFAULT, "# jonp: checking file: %s!%s for type '%s'", info->source_apk, info->source_entry, java); */
168-
// const char *e = reinterpret_cast<const char*> (bsearch (java, info->mapping, static_cast<size_t>(info->num_entries), static_cast<size_t>(info->entry_length), TypeMappingInfo_compare_key));
169-
// if (e == nullptr)
170-
// continue;
171-
// return e + info->value_offset;
172-
// }
173-
// #endif
174165
timing_period total_time;
175166
if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) {
176167
timing = new Timing ();
177168
total_time.mark_start ();
178169
}
179170

180171
simple_pointer_guard<char[], false> java_type_name (mono_string_to_utf8 (java_type));
181-
if (!java_type_name || *java_type_name == '\0') {
172+
if (XA_UNLIKELY (!java_type_name || *java_type_name == '\0')) {
173+
return nullptr;
174+
}
175+
176+
int32_t type_token_id = -1;
177+
#if defined (DEBUG) || !defined (ANDROID)
178+
size_t idx = 0;
179+
for (; idx < module_count; idx++) {
180+
const uint8_t *java_entry = binary_search<const char, uint8_t, compare_java_name, true> (java_type_name.get (), modules[idx].java_map, modules[idx].entry_count, modules[idx].java_name_width + 3);
181+
if (java_entry == nullptr)
182+
continue;
183+
type_token_id = *reinterpret_cast<const int32_t*>(java_entry + modules[idx].java_name_width);
184+
break;
185+
}
186+
187+
if (idx >= module_count) {
188+
log_error (LOG_ASSEMBLY, "Unable to find module with Java type '%s' mapping", java_type_name.get ());
182189
return nullptr;
183190
}
184191

192+
TypeMapModule &module = modules[idx];
193+
#else
185194
const TypeMapJava *java_entry = binary_search<const char, TypeMapJava, compare_java_name, true> (java_type_name.get (), map_java, java_type_count, java_name_width);
186195
if (java_entry == nullptr) {
187196
log_warn (LOG_ASSEMBLY, "Unable to find mapping to a managed type from Java type '%s'", java_type_name.get ());
@@ -199,6 +208,8 @@ EmbeddedAssemblies::typemap_java_to_managed (MonoString *java_type)
199208
log_warn (LOG_ASSEMBLY, "Unable to find mapping from Java type '%s' to managed type with token ID %u in module [%s]", java_type_name.get (), java_entry->type_token_id, mono_guid_to_string (module.module_uuid));
200209
return nullptr;
201210
}
211+
type_token_id = java_entry->type_token_id;
212+
#endif
202213

203214
if (module.image == nullptr) {
204215
module.image = mono_image_loaded (module.assembly_name);
@@ -213,10 +224,10 @@ EmbeddedAssemblies::typemap_java_to_managed (MonoString *java_type)
213224
}
214225
}
215226

216-
log_warn (LOG_ASSEMBLY, "Java type '%s' corresponds to managed token id %u (0x%x)", java_type_name.get (), java_entry->type_token_id, java_entry->type_token_id);
217-
MonoClass *klass = mono_class_get (module.image, static_cast<uint32_t>(java_entry->type_token_id));
227+
log_warn (LOG_ASSEMBLY, "Java type '%s' corresponds to managed token id %u (0x%x)", java_type_name.get (), type_token_id, type_token_id);
228+
MonoClass *klass = mono_class_get (module.image, static_cast<uint32_t>(type_token_id));
218229
if (klass == nullptr) {
219-
log_error (LOG_ASSEMBLY, "Unable to find managed type with token ID %u in assembly '%s', corresponding to Java type '%s'", java_entry->type_token_id, module.assembly_name, java_type_name.get ());
230+
log_error (LOG_ASSEMBLY, "Unable to find managed type with token ID %u in assembly '%s', corresponding to Java type '%s'", type_token_id, module.assembly_name, java_type_name.get ());
220231
return nullptr;
221232
}
222233

@@ -236,6 +247,14 @@ EmbeddedAssemblies::compare_java_name (const char *java_name, const TypeMapJava
236247
return strcmp (java_name, reinterpret_cast<const char*>(entry->java_name));
237248
}
238249

250+
#if defined (DEBUG) || !defined (ANDROID)
251+
int
252+
EmbeddedAssemblies::compare_java_name (const char *java_name, const uint8_t *entry)
253+
{
254+
return strcmp (java_name, reinterpret_cast<const char*>(entry));
255+
}
256+
#endif // DEBUG || !ANDROID
257+
239258
const char*
240259
EmbeddedAssemblies::typemap_managed_to_java (const uint8_t *mvid, const int32_t token)
241260
{
@@ -258,7 +277,16 @@ EmbeddedAssemblies::typemap_managed_to_java (const uint8_t *mvid, const int32_t
258277
return nullptr;
259278
}
260279

261-
const TypeMapModule *match = binary_search<uint8_t, TypeMapModule, compare_mvid> (mvid, map_modules, map_module_count);
280+
TypeMapModule *map;
281+
uint32_t map_entry_count;
282+
#if defined (DEBUG) || !defined (ANDROID)
283+
map = modules;
284+
map_entry_count = module_count;
285+
#else
286+
map = map_modules;
287+
map_entry_count = map_module_count;
288+
#endif
289+
const TypeMapModule *match = binary_search<uint8_t, TypeMapModule, compare_mvid> (mvid, map, map_entry_count);
262290
if (match == nullptr) {
263291
log_warn (LOG_ASSEMBLY, "Module matching MVID [%s] not found.", mono_guid_to_string (mvid));
264292
return nullptr;
@@ -272,17 +300,28 @@ EmbeddedAssemblies::typemap_managed_to_java (const uint8_t *mvid, const int32_t
272300
// Each map entry is a pair of 32-bit integers: [TypeTokenID][JavaMapArrayIndex]
273301
const TypeMapModuleEntry *entry = binary_search <int32_t, TypeMapModuleEntry, compare_type_token> (&token, match->map, match->entry_count);
274302
if (entry == nullptr) {
275-
log_warn (LOG_ASSEMBLY, "Type with token %d in module [%s] not found.", token, mono_guid_to_string (mvid));
303+
log_warn (LOG_ASSEMBLY, "Type with token %d (0x%x) in module {%s} (%s) not found.", token, token, mono_guid_to_string (mvid), match->assembly_name);
276304
return nullptr;
277305
}
278306

279-
if (entry->java_map_index >= java_type_count) {
280-
log_warn (LOG_ASSEMBLY, "Type with token %d in module [%s] has invalid Java type index %u", token, mono_guid_to_string (mvid), entry->java_map_index);
307+
uint32_t java_entry_count;
308+
#if defined (DEBUG) || !defined (ANDROID)
309+
java_entry_count = match->entry_count;
310+
#else
311+
java_entry_count = java_type_count;
312+
#endif
313+
if (entry->java_map_index >= java_entry_count) {
314+
log_warn (LOG_ASSEMBLY, "Type with token %d (0x%x) in module {%s} (%s) has invalid Java type index %u", token, token, mono_guid_to_string (mvid), match->assembly_name, entry->java_map_index);
281315
return nullptr;
282316
}
283317

318+
char *ret;
319+
#if defined (DEBUG) || !defined (ANDROID)
320+
ret = reinterpret_cast<char*>(match->java_map + ((match->java_name_width + 4) * entry->java_map_index));
321+
#else
284322
const TypeMapJava *java_entry = reinterpret_cast<const TypeMapJava*> (reinterpret_cast<const uint8_t*>(map_java) + ((sizeof(TypeMapJava) + java_name_width) * entry->java_map_index));
285-
const char *ret = reinterpret_cast<const char*>(java_entry->java_name);
323+
ret = reinterpret_cast<char*>(java_entry->java_name);
324+
#endif
286325

287326
if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) {
288327
total_time.mark_end ();
@@ -292,9 +331,11 @@ EmbeddedAssemblies::typemap_managed_to_java (const uint8_t *mvid, const int32_t
292331

293332
log_debug (
294333
LOG_ASSEMBLY,
295-
"Type with token %d in module [%s] corresponds to Java type '%s'",
334+
"Type with token %d (0x%x) in module {%s} (%s) corresponds to Java type '%s'",
335+
token,
296336
token,
297337
mono_guid_to_string (mvid),
338+
match->assembly_name,
298339
ret
299340
);
300341

@@ -482,11 +523,10 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char
482523
return false;
483524
}
484525

485-
size_t data_size = 0;
486526
ssize_t nread = read (fd, &header, sizeof (header));
487527
if (nread <= 0) {
488528
if (nread < 0) {
489-
log_error (LOG_ASSEMBLY, "Failed to read %s file header from '%s/%s': %s", file_type, dir_path, file_path, strerror(errno));
529+
log_error (LOG_ASSEMBLY, "Failed to read %s file header from '%s/%s': %s", file_type, dir_path, file_path, strerror (errno));
490530
} else {
491531
log_error (LOG_ASSEMBLY, "End of file while reading %s file header from '%s/%s'", file_type, dir_path, file_path);
492532
}
@@ -507,31 +547,58 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char
507547
return true;
508548
}
509549

510-
bool
550+
uint8_t*
551+
EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_size, int index_fd)
552+
{
553+
constexpr size_t UUID_SIZE = 16;
554+
555+
size_t entry_size = header.module_file_name_width + UUID_SIZE;
556+
size_t data_size = entry_size * module_count;
557+
if (sizeof(header) + data_size > file_size) {
558+
log_error (LOG_ASSEMBLY, "Index file is too small, expected %u, found %u bytes", data_size + sizeof(header), file_size);
559+
return nullptr;
560+
}
561+
562+
auto data = new uint8_t [data_size];
563+
ssize_t nread = read (index_fd, data, data_size);
564+
if (nread != static_cast<ssize_t>(data_size)) {
565+
log_error (LOG_ASSEMBLY, "Failed to read %u bytes from index file. %s", data_size, strerror (errno));
566+
return nullptr;
567+
}
568+
569+
uint8_t *p = data;
570+
for (size_t i = 0; i < module_count; i++) {
571+
memcpy (modules[i].module_uuid, p, UUID_SIZE);
572+
modules[i].assembly_name = reinterpret_cast<char*>(p + UUID_SIZE);
573+
p += entry_size;
574+
}
575+
576+
return data;
577+
}
578+
579+
uint8_t*
511580
EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path)
512581
{
513582
log_debug (LOG_ASSEMBLY, "Loading TypeMap index file '%s/%s'", dir_path, index_path);
514583

515-
bool ret = true;
516584
TypeMapIndexHeader header;
517585
size_t file_size;
518586
int fd = -1;
587+
uint8_t *data = nullptr;
519588

520589
if (!typemap_read_header (dir_fd, "TypeMap index", dir_path, index_path, MODULE_INDEX_MAGIC, header, file_size, fd)) {
521-
ret = false;
522590
goto cleanup;
523591
}
524592

525593
module_count = header.entry_count;
526-
modules = new TypeMapModule[module_count];
527-
// TODO: read actual data
528-
// TODO: pre-fill UUID + file name (store in `assembly_name`) from the previous step
594+
modules = new TypeMapModule[module_count]();
595+
data = typemap_load_index (header, file_size, fd);
529596

530597
cleanup:
531598
if (fd >= 0)
532599
close (fd);
533600

534-
return ret;
601+
return data;
535602
}
536603

537604
bool
@@ -543,17 +610,66 @@ EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const c
543610
BinaryTypeMapHeader header;
544611
size_t file_size;
545612
int fd = -1;
613+
size_t alloc_size;
614+
ssize_t nread;;
615+
char *chars;
616+
uint8_t *p;
546617

547618
if (!typemap_read_header (dir_fd, "TypeMap", dir_path, file_path, MODULE_MAGIC, header, file_size, fd)) {
548619
ret = false;
549620
goto cleanup;
550621
}
551622

552-
log_debug (LOG_ASSEMBLY, "TypeMap '%s/%s': entry count == %u; Java type name field width == %u; MVID == %s", dir_path, file_path, header.entry_count, header.java_name_width, mono_guid_to_string (header.module_uuid));
553-
623+
alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, header.assembly_name_length, 1);
624+
module.assembly_name = new char[alloc_size];
625+
nread = read (fd, module.assembly_name, header.assembly_name_length);
626+
module.assembly_name [header.assembly_name_length] = 0;
554627
module.entry_count = header.entry_count;
555-
// TODO: set module.assembly_name
556-
// TODO: allocate memory for module.map and read data into it
628+
629+
log_debug (LOG_ASSEMBLY, "TypeMap '%s/%s': entry count == %u; Java type name field width == %u; MVID == %s; assembly name length == %u; assembly name == %s",
630+
dir_path, file_path, header.entry_count, header.java_name_width, mono_guid_to_string (header.module_uuid), header.assembly_name_length, module.assembly_name);
631+
632+
alloc_size = MULTIPLY_WITH_OVERFLOW_CHECK (size_t, header.java_name_width + 4, header.entry_count);
633+
module.java_name_width = header.java_name_width;
634+
module.java_map = new uint8_t[alloc_size];
635+
nread = read (fd, module.java_map, alloc_size);
636+
if (nread != static_cast<ssize_t>(alloc_size)) {
637+
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;
642+
}
643+
644+
module.map = new TypeMapModuleEntry[header.entry_count];
645+
alloc_size = MULTIPLY_WITH_OVERFLOW_CHECK (size_t, sizeof(TypeMapModuleEntry), header.entry_count);
646+
nread = read (fd, module.map, alloc_size);
647+
if (nread != static_cast<ssize_t>(alloc_size)) {
648+
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;
655+
}
656+
657+
alloc_size = module.java_name_width + 1;
658+
chars = new char[alloc_size]();
659+
p = module.java_map;
660+
log_debug (LOG_ASSEMBLY, "Java entries in %s/%s", dir_path, file_path);
661+
for (size_t i = 0; i < module.entry_count; i++) {
662+
memcpy (chars, p, module.java_name_width);
663+
uint32_t token = *reinterpret_cast<const uint32_t*>(p + module.java_name_width);
664+
log_debug (LOG_ASSEMBLY, " %04u: %s; %u (0x%x)", i, chars, token, token);
665+
p += module.java_name_width + 4;
666+
}
667+
delete[] chars;
668+
669+
log_debug (LOG_ASSEMBLY, "Managed entries in %s/%s", dir_path, file_path);
670+
for (size_t i = 0; i < module.entry_count; i++) {
671+
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);
672+
}
557673

558674
cleanup:
559675
if (fd >= 0)
@@ -580,7 +696,11 @@ EmbeddedAssemblies::try_load_typemaps_from_directory (const char *path)
580696
#endif
581697

582698
constexpr char index_name[] = "typemap.index";
583-
if (!typemap_load_index (dir_fd, dir_path, index_name)) {
699+
700+
// The pointer must be stored here because, after index is loaded, module.assembly_name points into the index data
701+
// and must be valid until after the actual module file is loaded.
702+
simple_pointer_guard<uint8_t[], true> index_data = typemap_load_index (dir_fd, dir_path, index_name);
703+
if (!index_data) {
584704
log_fatal (LOG_ASSEMBLY, "Unable to load TypeMap data index from '%s/%s'", dir_path.get (), index_name);
585705
exit (FATAL_EXIT_NO_ASSEMBLIES); // TODO: use a new error code here
586706
}

src/monodroid/jni/embedded-assemblies.hh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ namespace xamarin::android::internal {
7575

7676
template<typename H>
7777
bool typemap_read_header (int dir_fd, const char *file_type, const char *dir_path, const char *file_path, uint32_t expected_magic, H &header, size_t &file_size, int &fd);
78-
bool typemap_load_index (int dir_fd, const char *dir_path, const char *index_path);
78+
uint8_t* typemap_load_index (int dir_fd, const char *dir_path, const char *index_path);
79+
uint8_t* typemap_load_index (TypeMapIndexHeader &header, size_t file_size, int index_fd);
7980
bool typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMapModule &module);
8081
#endif // DEBUG || !ANDROID
8182
bool register_debug_symbols_for_assembly (const char *entry_name, MonoBundledAssembly *assembly, const mono_byte *debug_contents, int debug_size);
@@ -108,6 +109,9 @@ namespace xamarin::android::internal {
108109
static int compare_mvid (const uint8_t *mvid, const TypeMapModule *module);
109110
static int compare_type_token (const int32_t *token, const TypeMapModuleEntry *entry);
110111
static int compare_java_name (const char *java_name, const TypeMapJava *entry);
112+
#if defined (DEBUG) || !defined (ANDROID)
113+
static int compare_java_name (const char *java_name, const uint8_t *java_map);
114+
#endif
111115

112116
private:
113117
bool register_debug_symbols;

0 commit comments

Comments
 (0)