Skip to content

Commit 03a87c4

Browse files
committed
Optimize debug maps a bit
1 parent b25368f commit 03a87c4

5 files changed

Lines changed: 82 additions & 39 deletions

File tree

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

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class TypeMappingDebugNativeAssemblyGeneratorCLR : LlvmIrComposer
1616
const string TypeMapSymbol = "type_map";
1717
const string UniqueAssembliesSymbol = "type_map_unique_assemblies";
1818
const string AssemblyNamesBlobSymbol = "type_map_assembly_names";
19+
const string ManagedTypeNamesBlobSymbol = "type_map_managed_type_names";
20+
const string JavaTypeNamesBlobSymbol = "type_map_java_type_names";
1921

2022
sealed class TypeMapContextDataProvider : NativeAssemblerStructContextDataProvider
2123
{
@@ -53,11 +55,11 @@ public override string GetComment (object data, string fieldName)
5355
var entry = EnsureType<TypeMapEntry> (data);
5456

5557
if (String.Compare ("from", fieldName, StringComparison.Ordinal) == 0) {
56-
return $"from: {entry.from}";
58+
return $"from: {entry.From}";
5759
}
5860

5961
if (String.Compare ("to", fieldName, StringComparison.Ordinal) == 0) {
60-
return $"to: {entry.to}";
62+
return $"to: {entry.To}";
6163
}
6264

6365
return String.Empty;
@@ -87,11 +89,23 @@ public override string GetComment (object data, string fieldName)
8789
[NativeAssemblerStructContextDataProvider (typeof (TypeMapEntryContextDataProvider))]
8890
sealed class TypeMapEntry
8991
{
92+
[NativeAssembler (Ignore = true)]
93+
public string From;
94+
95+
[NativeAssembler (Ignore = true)]
96+
public string To;
97+
9098
[NativeAssembler (UsesDataProvider = true)]
91-
public string from;
99+
public uint from;
100+
101+
[NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)]
102+
public ulong from_hash;
92103

93104
[NativeAssembler (UsesDataProvider = true)]
94-
public string to;
105+
public uint to;
106+
107+
[NativeAssembler (NumberFormat = LlvmIrVariableNumberFormat.Hexadecimal)]
108+
public ulong to_hash;
95109
};
96110

97111
// Order of fields and their type must correspond *exactly* to that in
@@ -164,30 +178,45 @@ protected override void Construct (LlvmIrModule module)
164178

165179
MapStructures (module);
166180

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-
}
181+
var managedTypeNames = new LlvmIrStringBlob ();
182+
var javaTypeNames = new LlvmIrStringBlob ();
183+
184+
// CoreCLR supports only 64-bit targets, so we can make things simpler by hashing all the things here instead of
185+
// in a callback during code generation
186+
foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.ManagedToJavaMap) {
187+
(int managedTypeNameOffset, int _) = managedTypeNames.Add (entry.ManagedName);
188+
(int javaTypeNameOffset, int _) = javaTypeNames.Add (entry.JavaName);
189+
var m2j = new TypeMapEntry {
190+
From = entry.ManagedName,
191+
To = entry.JavaName,
192+
193+
from = (uint)managedTypeNameOffset,
194+
from_hash = MonoAndroidHelper.GetXxHash (entry.ManagedName, is64Bit: true),
195+
to = (uint)javaTypeNameOffset,
196+
to_hash = MonoAndroidHelper.GetXxHash (entry.JavaName, is64Bit: true),
197+
};
198+
managedToJavaMap.Add (new StructureInstance<TypeMapEntry> (typeMapEntryStructureInfo, m2j));
175199
}
200+
managedToJavaMap.Sort ((StructureInstance<TypeMapEntry> a, StructureInstance<TypeMapEntry> b) => a.Instance.from_hash.CompareTo (b.Instance.from_hash));
176201

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;
202+
foreach (TypeMapGenerator.TypeMapDebugEntry entry in data.JavaToManagedMap) {
203+
TypeMapGenerator.TypeMapDebugEntry managedEntry = entry.DuplicateForJavaToManaged != null ? entry.DuplicateForJavaToManaged : entry;
204+
(int managedTypeNameOffset, int _) = managedTypeNames.Add (entry.ManagedName);
205+
(int javaTypeNameOffset, int _) = javaTypeNames.Add (entry.JavaName);
180206

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-
}
207+
var j2m = new TypeMapEntry {
208+
From = entry.JavaName,
209+
To = managedEntry.SkipInJavaToManaged ? String.Empty : entry.ManagedName,
210+
211+
from = (uint)javaTypeNameOffset,
212+
from_hash = MonoAndroidHelper.GetXxHash (entry.JavaName, is64Bit: true),
213+
to = managedEntry.SkipInJavaToManaged ? uint.MaxValue : (uint)managedTypeNameOffset,
214+
to_hash = managedEntry.SkipInJavaToManaged ? 0 : MonoAndroidHelper.GetXxHash (entry.ManagedName, is64Bit: true),
215+
};
216+
javaToManagedMap.Add (new StructureInstance<TypeMapEntry> (typeMapEntryStructureInfo, j2m));
187217
}
218+
javaToManagedMap.Sort ((StructureInstance<TypeMapEntry> a, StructureInstance<TypeMapEntry> b) => a.Instance.from_hash.CompareTo (b.Instance.from_hash));
188219

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
191220
var assemblyNamesBlob = new LlvmIrStringBlob ();
192221
foreach (TypeMapGenerator.TypeMapDebugAssembly asm in data.UniqueAssemblies) {
193222
(int assemblyNameOffset, int assemblyNameLength) = assemblyNamesBlob.Add (asm.Name);
@@ -224,6 +253,8 @@ protected override void Construct (LlvmIrModule module)
224253

225254
module.AddGlobalVariable (UniqueAssembliesSymbol, uniqueAssemblies, LlvmIrVariableOptions.GlobalConstant);
226255
module.AddGlobalVariable (AssemblyNamesBlobSymbol, assemblyNamesBlob, LlvmIrVariableOptions.GlobalConstant);
256+
module.AddGlobalVariable (ManagedTypeNamesBlobSymbol, managedTypeNames, LlvmIrVariableOptions.GlobalConstant);
257+
module.AddGlobalVariable (JavaTypeNamesBlobSymbol, javaTypeNames, LlvmIrVariableOptions.GlobalConstant);
227258
}
228259

229260
void MapStructures (LlvmIrModule module)

src/native/clr/host/typemap.cc

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,36 +65,40 @@ namespace {
6565

6666
#if defined(DEBUG)
6767
[[gnu::always_inline]]
68-
auto TypeMapper::typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char*
68+
auto TypeMapper::typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char*
6969
{
7070
log_debug (LOG_ASSEMBLY, "Looking up {} type '{}'", from_name, optional_string (typeName));
71-
auto equal = [](TypeMapEntry const& entry, const char *key) -> bool {
72-
if (entry.from == nullptr) {
71+
auto equal = [](TypeMapEntry const& entry, hash_t key) -> bool {
72+
if (entry.from == std::numeric_limits<uint32_t>::max ()) {
7373
return 1;
7474
}
7575

76-
return strcmp (entry.from, key) == 0;
76+
return entry.from_hash == key;
7777
};
7878

79-
auto less_than = [](TypeMapEntry const& entry, const char *key) -> bool {
80-
if (entry.from == nullptr) {
79+
auto less_than = [](TypeMapEntry const& entry, hash_t key) -> bool {
80+
if (entry.from == std::numeric_limits<uint32_t>::max ()) {
8181
return 1;
8282
}
8383

84-
return strcmp (entry.from, key) < 0;
84+
return entry.from_hash < key;
8585
};
8686

87-
ssize_t idx = Search::binary_search<TypeMapEntry, const char*, equal, less_than> (typeName, map, type_map.entry_count);
87+
hash_t type_name_hash = xxhash::hash (typeName, strlen (typeName));
88+
ssize_t idx = Search::binary_search<TypeMapEntry, hash_t, equal, less_than> (type_name_hash, map, type_map.entry_count);
8889
if (idx >= 0) [[likely]] {
90+
TypeMapEntry const& entry = map[idx];
91+
const char *mapped_name = &name_map[entry.to];
92+
8993
log_debug (
9094
LOG_ASSEMBLY,
9195
"{} type '{}' maps to {} type '{}'",
9296
from_name,
9397
optional_string (typeName),
9498
to_name,
95-
optional_string (type_map.managed_to_java[idx].to)
99+
optional_string (mapped_name)
96100
);
97-
return type_map.managed_to_java[idx].to;
101+
return mapped_name;
98102
}
99103

100104
return nullptr;
@@ -126,7 +130,7 @@ auto TypeMapper::typemap_managed_to_java_debug (const char *typeName, const uint
126130
log_warn (LOG_ASSEMBLY, "Unable to look up assembly name for type '{}', trying without it.", typeName);
127131
}
128132

129-
return typemap_type_to_type_debug (full_type_name.get (), type_map.managed_to_java, MANAGED, JAVA);
133+
return typemap_type_to_type_debug (full_type_name.get (), type_map.managed_to_java, type_map_java_type_names, MANAGED, JAVA);
130134
}
131135
#endif // def DEBUG
132136

@@ -300,7 +304,7 @@ auto TypeMapper::typemap_java_to_managed_debug (const char *java_type_name, char
300304
// FIXME: this is currently VERY broken
301305
*assembly_name = nullptr;
302306
*managed_type_token_id = 0;
303-
return typemap_type_to_type_debug (java_type_name, type_map.java_to_managed, JAVA, MANAGED);
307+
return typemap_type_to_type_debug (java_type_name, type_map.java_to_managed, type_map_managed_type_names, JAVA, MANAGED);
304308
}
305309
#else // def DEBUG
306310

src/native/clr/include/host/typemap.hh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ namespace xamarin::android {
2727

2828
static auto find_java_to_managed_entry (hash_t name_hash) noexcept -> const TypeMapJava*;
2929
#else
30-
static auto typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char*;
30+
static auto typemap_type_to_type_debug (const char *typeName, const TypeMapEntry *map, const char (&name_map)[], std::string_view const& from_name, std::string_view const& to_name) noexcept -> const char*;
3131
static auto typemap_managed_to_java_debug (const char *typeName, const uint8_t *mvid) noexcept -> const char*;
3232
static auto typemap_java_to_managed_debug (const char *java_type_name, char const** assembly_name, uint32_t *managed_type_token_id) noexcept -> bool;
3333
#endif

src/native/clr/include/xamarin-app.hh

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,15 @@ struct TypeMapIndexHeader
5656
uint32_t module_file_name_width;
5757
};
5858

59+
// If any of the members is set to maximum uint32_t value it means the entry is ignored (treated
60+
// as equivalent to `nullptr` if the member was a pointer). The reasoning is that no string could
61+
// begin at this offset (well, an empty string could, but we don't have those here)
5962
struct TypeMapEntry
6063
{
61-
const char *from;
62-
const char *to;
64+
const uint32_t from;
65+
const xamarin::android::hash_t from_hash;
66+
const uint32_t to;
67+
const xamarin::android::hash_t to_hash;
6368
};
6469

6570
// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs
@@ -325,6 +330,8 @@ extern "C" {
325330
[[gnu::visibility("default")]] extern const TypeMap type_map; // MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGeneratorCLR.cs
326331
[[gnu::visibility("default")]] extern const TypeMapAssembly type_map_unique_assemblies[];
327332
[[gnu::visibility("default")]] extern const char type_map_assembly_names[];
333+
[[gnu::visibility("default")]] extern const char type_map_managed_type_names[];
334+
[[gnu::visibility("default")]] extern const char type_map_java_type_names[];
328335
#else
329336
[[gnu::visibility("default")]] extern const uint32_t managed_to_java_map_module_count;
330337
[[gnu::visibility("default")]] extern const uint32_t java_type_count;

src/native/clr/xamarin-app-stub/application_dso_stub.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ const uint64_t format_tag = FORMAT_TAG;
1010

1111
#if defined (DEBUG)
1212
static TypeMapEntry java_to_managed[] = {};
13-
1413
static TypeMapEntry managed_to_java[] = {};
1514

1615
// MUST match src/Xamarin.Android.Build.Tasks/Utilities/TypeMappingDebugNativeAssemblyGenerator.cs
@@ -24,6 +23,8 @@ const TypeMap type_map = {
2423

2524
const TypeMapAssembly type_map_unique_assemblies[] = {};
2625
const char type_map_assembly_names[] = {};
26+
const char type_map_managed_type_names[] = {};
27+
const char type_map_java_type_names[] = {};
2728
#else
2829
const uint32_t managed_to_java_map_module_count = 0;
2930
const uint32_t java_type_count = 0;

0 commit comments

Comments
 (0)