Skip to content

Commit

Permalink
Update for changes introduced in 130905e
Browse files Browse the repository at this point in the history
  • Loading branch information
grendello committed Jan 10, 2020
1 parent b1680e4 commit 6f93cf4
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 41 deletions.
2 changes: 1 addition & 1 deletion src/Mono.Android/Android.Runtime/AndroidRuntime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ protected override IEnumerable<string> GetSimpleReferences (Type type)
foreach (var simpleRef in base.GetSimpleReferences (type)) {
yield return simpleRef;
}
var j = JNIEnv.monodroid_typemap_managed_to_java (type.FullName + ", " + type.Assembly.GetName ().Name);
var j = JNIEnv.monodroid_typemap_managed_to_java (type.Module.ModuleVersionId.ToByteArray (), type.MetadataToken);
if (j != IntPtr.Zero) {
yield return Marshal.PtrToStringAnsi (j);
}
Expand Down
16 changes: 13 additions & 3 deletions src/Xamarin.Android.Build.Tasks/Utilities/TypeMapGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -304,13 +304,18 @@ void OutputModule (BinaryWriter bw, byte[] moduleUUID, ModuleData moduleData)
bw.Write (moduleUUID);

var javaNames = new SortedDictionary<string, uint> (StringComparer.Ordinal);
var duplicateJavaNames = new Dictionary<string, bool> (StringComparer.Ordinal);
var managedTypes = new SortedDictionary<uint, uint> ();
var managedTypeNames = new Dictionary<uint, string> ();

// TODO: put duplicate types in a separate list (typeid:index) at the end of the typemap file/assembly code
// and mark such entries somehow in the typeid->java table (e.g. set the high bit of the index, it's unlikely
// we'd have 4 billion entries)
int maxJavaNameLength = 0;
foreach (TypeMapEntry entry in moduleData.Types) {
if (javaNames.ContainsKey (entry.JavaName)) {
logger ($"Warning: duplicate Java type name '{entry.JavaName}' (old token: {javaNames [entry.JavaName]}; new token: {entry.Token}). Ignoring the new type.");
if (!duplicateJavaNames.ContainsKey (entry.JavaName))
duplicateJavaNames.Add (entry.JavaName, false);
continue;
}

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

managedTypes.Add (entry.Token, 0);
managedTypeNames.Add (entry.Token, entry.ManagedTypeName);
}

var javaNameList = javaNames.Keys.ToList ();
foreach (TypeMapEntry entry in moduleData.Types) {
if (duplicateJavaNames.TryGetValue (entry.JavaName, out bool skip)) {
if (skip)
continue;
duplicateJavaNames [entry.JavaName] = true;
}

managedTypes [entry.Token] = (uint)javaNameList.IndexOf (entry.JavaName);
}

bw.Write (javaNames.Count);
bw.Write (maxJavaNameLength);
bw.Write (maxJavaNameLength + 1);

string assemblyName = moduleData.Assembly.Name.Name;
bw.Write (assemblyName.Length);
Expand Down
186 changes: 153 additions & 33 deletions src/monodroid/jni/embedded-assemblies.cc
Original file line number Diff line number Diff line change
Expand Up @@ -162,26 +162,35 @@ EmbeddedAssemblies::binary_search (const Key *key, const Entry *base, size_t nme
MonoReflectionType*
EmbeddedAssemblies::typemap_java_to_managed (MonoString *java_type)
{
// #if defined (DEBUG) || !defined (ANDROID)
// for (TypeMappingInfo *info = java_to_managed_maps; info != nullptr; info = info->next) {
// /* log_warn (LOG_DEFAULT, "# jonp: checking file: %s!%s for type '%s'", info->source_apk, info->source_entry, java); */
// 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));
// if (e == nullptr)
// continue;
// return e + info->value_offset;
// }
// #endif
timing_period total_time;
if (XA_UNLIKELY (utils.should_log (LOG_TIMING))) {
timing = new Timing ();
total_time.mark_start ();
}

simple_pointer_guard<char[], false> java_type_name (mono_string_to_utf8 (java_type));
if (!java_type_name || *java_type_name == '\0') {
if (XA_UNLIKELY (!java_type_name || *java_type_name == '\0')) {
return nullptr;
}

int32_t type_token_id = -1;
#if defined (DEBUG) || !defined (ANDROID)
size_t idx = 0;
for (; idx < module_count; idx++) {
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);
if (java_entry == nullptr)
continue;
type_token_id = *reinterpret_cast<const int32_t*>(java_entry + modules[idx].java_name_width);
break;
}

if (idx >= module_count) {
log_error (LOG_ASSEMBLY, "Unable to find module with Java type '%s' mapping", java_type_name.get ());
return nullptr;
}

TypeMapModule &module = modules[idx];
#else
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);
if (java_entry == nullptr) {
log_warn (LOG_ASSEMBLY, "Unable to find mapping to a managed type from Java type '%s'", java_type_name.get ());
Expand All @@ -199,6 +208,8 @@ EmbeddedAssemblies::typemap_java_to_managed (MonoString *java_type)
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));
return nullptr;
}
type_token_id = java_entry->type_token_id;
#endif

if (module.image == nullptr) {
module.image = mono_image_loaded (module.assembly_name);
Expand All @@ -213,10 +224,10 @@ EmbeddedAssemblies::typemap_java_to_managed (MonoString *java_type)
}
}

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);
MonoClass *klass = mono_class_get (module.image, static_cast<uint32_t>(java_entry->type_token_id));
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);
MonoClass *klass = mono_class_get (module.image, static_cast<uint32_t>(type_token_id));
if (klass == nullptr) {
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 ());
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 ());
return nullptr;
}

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

#if defined (DEBUG) || !defined (ANDROID)
int
EmbeddedAssemblies::compare_java_name (const char *java_name, const uint8_t *entry)
{
return strcmp (java_name, reinterpret_cast<const char*>(entry));
}
#endif // DEBUG || !ANDROID

const char*
EmbeddedAssemblies::typemap_managed_to_java (const uint8_t *mvid, const int32_t token)
{
Expand All @@ -258,7 +277,16 @@ EmbeddedAssemblies::typemap_managed_to_java (const uint8_t *mvid, const int32_t
return nullptr;
}

const TypeMapModule *match = binary_search<uint8_t, TypeMapModule, compare_mvid> (mvid, map_modules, map_module_count);
TypeMapModule *map;
uint32_t map_entry_count;
#if defined (DEBUG) || !defined (ANDROID)
map = modules;
map_entry_count = module_count;
#else
map = map_modules;
map_entry_count = map_module_count;
#endif
const TypeMapModule *match = binary_search<uint8_t, TypeMapModule, compare_mvid> (mvid, map, map_entry_count);
if (match == nullptr) {
log_warn (LOG_ASSEMBLY, "Module matching MVID [%s] not found.", mono_guid_to_string (mvid));
return nullptr;
Expand All @@ -272,17 +300,28 @@ EmbeddedAssemblies::typemap_managed_to_java (const uint8_t *mvid, const int32_t
// Each map entry is a pair of 32-bit integers: [TypeTokenID][JavaMapArrayIndex]
const TypeMapModuleEntry *entry = binary_search <int32_t, TypeMapModuleEntry, compare_type_token> (&token, match->map, match->entry_count);
if (entry == nullptr) {
log_warn (LOG_ASSEMBLY, "Type with token %d in module [%s] not found.", token, mono_guid_to_string (mvid));
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);
return nullptr;
}

if (entry->java_map_index >= java_type_count) {
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);
uint32_t java_entry_count;
#if defined (DEBUG) || !defined (ANDROID)
java_entry_count = match->entry_count;
#else
java_entry_count = java_type_count;
#endif
if (entry->java_map_index >= java_entry_count) {
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);
return nullptr;
}

char *ret;
#if defined (DEBUG) || !defined (ANDROID)
ret = reinterpret_cast<char*>(match->java_map + ((match->java_name_width + 4) * entry->java_map_index));
#else
const TypeMapJava *java_entry = reinterpret_cast<const TypeMapJava*> (reinterpret_cast<const uint8_t*>(map_java) + ((sizeof(TypeMapJava) + java_name_width) * entry->java_map_index));
const char *ret = reinterpret_cast<const char*>(java_entry->java_name);
ret = reinterpret_cast<char*>(java_entry->java_name);
#endif

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

log_debug (
LOG_ASSEMBLY,
"Type with token %d in module [%s] corresponds to Java type '%s'",
"Type with token %d (0x%x) in module {%s} (%s) corresponds to Java type '%s'",
token,
token,
mono_guid_to_string (mvid),
match->assembly_name,
ret
);

Expand Down Expand Up @@ -482,11 +523,10 @@ EmbeddedAssemblies::typemap_read_header ([[maybe_unused]] int dir_fd, const char
return false;
}

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

bool
uint8_t*
EmbeddedAssemblies::typemap_load_index (TypeMapIndexHeader &header, size_t file_size, int index_fd)
{
constexpr size_t UUID_SIZE = 16;

size_t entry_size = header.module_file_name_width + UUID_SIZE;
size_t data_size = entry_size * module_count;
if (sizeof(header) + data_size > file_size) {
log_error (LOG_ASSEMBLY, "Index file is too small, expected %u, found %u bytes", data_size + sizeof(header), file_size);
return nullptr;
}

auto data = new uint8_t [data_size];
ssize_t nread = read (index_fd, data, data_size);
if (nread != static_cast<ssize_t>(data_size)) {
log_error (LOG_ASSEMBLY, "Failed to read %u bytes from index file. %s", data_size, strerror (errno));
return nullptr;
}

uint8_t *p = data;
for (size_t i = 0; i < module_count; i++) {
memcpy (modules[i].module_uuid, p, UUID_SIZE);
modules[i].assembly_name = reinterpret_cast<char*>(p + UUID_SIZE);
p += entry_size;
}

return data;
}

uint8_t*
EmbeddedAssemblies::typemap_load_index (int dir_fd, const char *dir_path, const char *index_path)
{
log_debug (LOG_ASSEMBLY, "Loading TypeMap index file '%s/%s'", dir_path, index_path);

bool ret = true;
TypeMapIndexHeader header;
size_t file_size;
int fd = -1;
uint8_t *data = nullptr;

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

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

cleanup:
if (fd >= 0)
close (fd);

return ret;
return data;
}

bool
Expand All @@ -543,17 +610,66 @@ EmbeddedAssemblies::typemap_load_file (int dir_fd, const char *dir_path, const c
BinaryTypeMapHeader header;
size_t file_size;
int fd = -1;
size_t alloc_size;
ssize_t nread;;
char *chars;
uint8_t *p;

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

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));

alloc_size = ADD_WITH_OVERFLOW_CHECK (size_t, header.assembly_name_length, 1);
module.assembly_name = new char[alloc_size];
nread = read (fd, module.assembly_name, header.assembly_name_length);
module.assembly_name [header.assembly_name_length] = 0;
module.entry_count = header.entry_count;
// TODO: set module.assembly_name
// TODO: allocate memory for module.map and read data into it

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",
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);

alloc_size = MULTIPLY_WITH_OVERFLOW_CHECK (size_t, header.java_name_width + 4, header.entry_count);
module.java_name_width = header.java_name_width;
module.java_map = new uint8_t[alloc_size];
nread = read (fd, module.java_map, alloc_size);
if (nread != static_cast<ssize_t>(alloc_size)) {
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));
ret = false;
delete[] module.java_map;
module.java_map = nullptr;
goto cleanup;
}

module.map = new TypeMapModuleEntry[header.entry_count];
alloc_size = MULTIPLY_WITH_OVERFLOW_CHECK (size_t, sizeof(TypeMapModuleEntry), header.entry_count);
nread = read (fd, module.map, alloc_size);
if (nread != static_cast<ssize_t>(alloc_size)) {
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));
ret = false;
delete[] module.java_map;
module.java_map = nullptr;
delete[] module.map;
module.map = nullptr;
goto cleanup;
}

alloc_size = module.java_name_width + 1;
chars = new char[alloc_size]();
p = module.java_map;
log_debug (LOG_ASSEMBLY, "Java entries in %s/%s", dir_path, file_path);
for (size_t i = 0; i < module.entry_count; i++) {
memcpy (chars, p, module.java_name_width);
uint32_t token = *reinterpret_cast<const uint32_t*>(p + module.java_name_width);
log_debug (LOG_ASSEMBLY, " %04u: %s; %u (0x%x)", i, chars, token, token);
p += module.java_name_width + 4;
}
delete[] chars;

log_debug (LOG_ASSEMBLY, "Managed entries in %s/%s", dir_path, file_path);
for (size_t i = 0; i < module.entry_count; i++) {
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);
}

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

constexpr char index_name[] = "typemap.index";
if (!typemap_load_index (dir_fd, dir_path, index_name)) {

// The pointer must be stored here because, after index is loaded, module.assembly_name points into the index data
// and must be valid until after the actual module file is loaded.
simple_pointer_guard<uint8_t[], true> index_data = typemap_load_index (dir_fd, dir_path, index_name);
if (!index_data) {
log_fatal (LOG_ASSEMBLY, "Unable to load TypeMap data index from '%s/%s'", dir_path.get (), index_name);
exit (FATAL_EXIT_NO_ASSEMBLIES); // TODO: use a new error code here
}
Expand Down
6 changes: 5 additions & 1 deletion src/monodroid/jni/embedded-assemblies.hh
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,8 @@ namespace xamarin::android::internal {

template<typename H>
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);
bool typemap_load_index (int dir_fd, const char *dir_path, const char *index_path);
uint8_t* typemap_load_index (int dir_fd, const char *dir_path, const char *index_path);
uint8_t* typemap_load_index (TypeMapIndexHeader &header, size_t file_size, int index_fd);
bool typemap_load_file (int dir_fd, const char *dir_path, const char *file_path, TypeMapModule &module);
#endif // DEBUG || !ANDROID
bool register_debug_symbols_for_assembly (const char *entry_name, MonoBundledAssembly *assembly, const mono_byte *debug_contents, int debug_size);
Expand Down Expand Up @@ -108,6 +109,9 @@ namespace xamarin::android::internal {
static int compare_mvid (const uint8_t *mvid, const TypeMapModule *module);
static int compare_type_token (const int32_t *token, const TypeMapModuleEntry *entry);
static int compare_java_name (const char *java_name, const TypeMapJava *entry);
#if defined (DEBUG) || !defined (ANDROID)
static int compare_java_name (const char *java_name, const uint8_t *java_map);
#endif

private:
bool register_debug_symbols;
Expand Down
Loading

0 comments on commit 6f93cf4

Please sign in to comment.