-
Notifications
You must be signed in to change notification settings - Fork 529
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[build] Optimize managed <-> java type lookups (#3992)
Typemap data is used to correlate JNI type names to .NET Assembly- Qualified Type Names, and vice versa: java/lang/Object <=> Java.Lang.Object, Mono.Android Typemap data is used from `JNIEnv.GetJniName()` for managed-to-JNI lookups, and from `TypeManager.GetJavaToManagedType()` for JNI-to-managed lookups. When [typemap files were first introduced][0], they relied on: 1. A string-oriented mapping from Java type names to .NET Assembly Qualified names and vice versa; and 2. A binary search via **bsearch**(3) over this table to find the associated type, using the source type as the "key". (The introduction of `libxamarin-app.so` (decfbcc) merely moved the (formerly separate) typemap data into `libxamarin-app.so` for Release config builds -- Debug builds continued using separate typemap files -- but didn't otherwise change how these mappings work.) This approach works very well at the expense of data size -- shorter strings are 0-padded to a common width -- and slightly degraded performance because of the requirement to perform string comparisons. Furthermore, the managed-to-JNI lookup required that Reflection is used to obtain the Assembly Qualified type name (`Type.AssemblyQualifiedName`), while the JNI-to-managed lookup likewise requires some Reflection to obtain `Type` instances (via `Type.GetType()`). Rework the typemap data in an effort to reduce Reflection use: For the managed-to-JNI mapping, use the combination of `type.Module.ModuleVersionId` and `Type.MetadataToken` -- a GUID and an int -- instead of using `Type.AssemblyQualifiedName`. This allows us to perform the binary search over a set of 20 bytes (16 bytes for the UUID and 4 bytes for the token ID). JNI-to-managed lookups still need to rely on a binary search across strings, but instead of mapping the JNI name to an Assembly-Qualified Type Name and using `Type.GetType()`, we instead map the JNI name to the same GUID+token pair via a new internal call which uses `mono_class_get()` & `mono_type_get_object()` to return the `Type`. As a result of this fundamental change, `libxamarin-app.so` decreases in size, and app startup time is reduced. For a Release configuration build of `tests/Xamarin.Forms-Performance-Integration`, `libs/arm64-v8a/libxamarin-app.so` shrinks from 377KB to 104KB (!), and on a Pixel 3 XL app the `ActivityTaskManager: Displayed` time was reduced from 805ms to 789ms (`$(AndroidEnablePreloadAssemblies)`=True), a nearly 10% improvement. Build time is also minimally impacted; `<GenerateJavaStubs/>` task time is reduced from 389ms to 247ms for the Xamarin.Forms build. ~~ Fast Deployment ~~ When Xamarin.Android Fast Deployment is *not* used for Debug builds (which is the case for OSS builds of xamarin-android), the typemap generation and deployment is identical for both Release and Debug builds: `libxamarin-app.so` contains the new typemap information. In commercial Xamarin.Android builds which use Fast Deployment, the typemap data is instead stored in two sets of files: * `typemap.index`: stores the mapping from module GUIDs to assembly filenames. * `*.typemap`: One file per .NET *module*, contain both the JNI-to- managed and managed-to-JNI maps, the latter using indexes into the Java to managed maps. All of these files are loaded during Debug app startup and used to construct a dataset which is then searched during all the lookups. ~~ File Formats ~~ All data in all file formats is little-endian. The `typemap.index` file stores the mapping from GUIDs to module filenames such as `Mono.Android.dll`. The file format in pseudo-C++: struct TypemapIndexHeader { byte magic [4]; // "XATI" uint32_t format_version; uint32_t entry_count; uint32_t module_filename_width; TypemapIndexEntry entries [entry_count]; }; struct TypemapIndexEntry { UUID module_uuid; // 16 bytes byte file_name [TypemapIndexHeader::module_filename_width]; }; `TypemapIndexHeader::module_filename_width` is the maximum filename length of any entry within `TypemapIndexEntry::file_name` + 1 for a terminating `NUL`. There is no order required within `TypemapIndexHeader::entries`. `TypemapIndexEntry::file_name` is `NUL` padded, filling the entire array until the next `TypemapIndexEntry` entry. The `*.typemap` file stores the mappings from JNI type names to module GUID and type token pairs. The file format in pseudo-C++: struct TypemapFileHeader { byte magic [4]; // "XATM" uint32_t format_version; GUID module_uuid; uint32_t entry_count; uint32_t duplicate_count; uint32_t jni_name_width; uint32_t assembly_name_size; byte assembly_name [assembly_name_size]; TypemapFileJavaToManagedEntry java_to_managed [entry_count]; TypemapFileManagedToJavaEntry managed_to_java [entry_count]; TypemapFileManagedToJavaEntry duplicates [duplicate_count]; }; struct TypemapFileJavaToManagedEntry { byte jni_name [TypemapFileHeader::jni_name_width]; uint32_t managed_type_token; }; struct TypemapFileManagedToJavaEntry { uint32_t managed_type_token; uint32_t java_to_managed_index; }; `TypemapFileHeader::duplicate_count` may be 0. `TypemapFileJavaToManagedEntry::jni_name` is `NUL` padded. `TypemapFileJavaToManagedEntry::managed_type_token` is the value of `Type.MetadataToken`. `TypemapFileManagedToJavaEntry::java_to_managed_index` is the index within `TypemapFileHeader::java_to_managed` that contains the JNI name. [0]: xamarin/monodroid@e69b76e [1]: https://github.com/xamarin/java.interop/blob/3226a4b57ad84574a69a151a310b077cfe69ee19/src/Java.Interop.Tools.JavaCallableWrappers/Java.Interop.Tools.JavaCallableWrappers/TypeNameMapGenerator.cs#L16-L56
- Loading branch information
Showing
63 changed files
with
1,939 additions
and
860 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
--- | ||
title: Xamarin.Android error XA4308 | ||
description: XA4308 error code | ||
ms.date: 02/07/2020 | ||
--- | ||
# Xamarin.Android error XA4308 | ||
|
||
## Issue | ||
|
||
The `GenerateJavaStubs` task was unable to generate type maps. Detailed diagnostic will be found before this | ||
error in the build log. | ||
|
||
## Solution | ||
|
||
Consider submitting a [bug][bug] if you are getting this warning under | ||
normal circumstances. | ||
|
||
[bug]: https://github.com/xamarin/xamarin-android/wiki/Submitting-Bugs,-Feature-Requests,-and-Pull-Requests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 0 additions & 30 deletions
30
src/Mono.Android/Test/Java.Interop-Tests/Properties/AssemblyInfo.cs
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.