Skip to content

Commit ee0afbd

Browse files
committed
A slightly different approach
1 parent 3787cd1 commit ee0afbd

File tree

9 files changed

+94
-78
lines changed

9 files changed

+94
-78
lines changed

src/Xamarin.Android.Build.Tasks/Utilities/AssemblyStoreGenerator.Classes.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,21 @@ public AssemblyStoreHeader (uint magic, uint version, uint entry_count, uint ind
3232

3333
sealed class AssemblyStoreIndexEntry
3434
{
35-
public const uint NativeSize32 = 2 * sizeof (uint);
36-
public const uint NativeSize64 = sizeof (ulong) + sizeof (uint);
35+
// We treat `bool` as `byte` here, since that's what gets written to the binary
36+
public const uint NativeSize32 = 2 * sizeof (uint) + sizeof (byte);
37+
public const uint NativeSize64 = sizeof (ulong) + sizeof (uint) + sizeof (byte);
3738

3839
public readonly string name;
3940
public readonly ulong name_hash;
4041
public readonly uint descriptor_index;
42+
public readonly bool ignore;
4143

42-
public AssemblyStoreIndexEntry (string name, ulong name_hash, uint descriptor_index)
44+
public AssemblyStoreIndexEntry (string name, ulong name_hash, uint descriptor_index, bool ignore)
4345
{
4446
this.name = name;
4547
this.name_hash = name_hash;
4648
this.descriptor_index = descriptor_index;
49+
this.ignore = ignore;
4750
}
4851
}
4952

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

Lines changed: 44 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ namespace Xamarin.Android.Tasks;
1616
// [HEADER]
1717
// [INDEX]
1818
// [ASSEMBLY_DESCRIPTORS]
19+
// [ASSEMBLY_NAMES]
1920
// [ASSEMBLY DATA]
2021
//
2122
// Formats of the sections above are as follows:
@@ -30,6 +31,7 @@ namespace Xamarin.Android.Tasks;
3031
// INDEX (variable size, HEADER.ENTRY_COUNT*2 entries, for assembly names with and without the extension)
3132
// [NAME_HASH] uint on 32-bit platforms, ulong on 64-bit platforms; xxhash of the assembly name
3233
// [DESCRIPTOR_INDEX] uint; index into in-store assembly descriptor array
34+
// [IGNORE] byte; if set to anything other than 0, the assembly is to be ignored when loading
3335
//
3436
// ASSEMBLY_DESCRIPTORS (variable size, HEADER.ENTRY_COUNT entries), each entry formatted as follows:
3537
// [MAPPING_INDEX] uint; index into a runtime array where assembly data pointers are stored
@@ -50,19 +52,14 @@ partial class AssemblyStoreGenerator
5052
const uint ASSEMBLY_STORE_MAGIC = 0x41424158; // 'XABA', little-endian, must match the BUNDLED_ASSEMBLIES_BLOB_MAGIC native constant
5153

5254
// Bit 31 is set for 64-bit platforms, cleared for the 32-bit ones
53-
const uint ASSEMBLY_STORE_FORMAT_VERSION_64BIT = 0x80000002; // Must match the ASSEMBLY_STORE_FORMAT_VERSION native constant
54-
const uint ASSEMBLY_STORE_FORMAT_VERSION_32BIT = 0x00000002;
55+
const uint ASSEMBLY_STORE_FORMAT_VERSION_64BIT = 0x80000003; // Must match the ASSEMBLY_STORE_FORMAT_VERSION native constant
56+
const uint ASSEMBLY_STORE_FORMAT_VERSION_32BIT = 0x00000003;
5557

5658
const uint ASSEMBLY_STORE_ABI_AARCH64 = 0x00010000;
5759
const uint ASSEMBLY_STORE_ABI_ARM = 0x00020000;
5860
const uint ASSEMBLY_STORE_ABI_X64 = 0x00030000;
5961
const uint ASSEMBLY_STORE_ABI_X86 = 0x00040000;
6062

61-
// This must be the same value as the native AssemblyStore::ASSEMBLY_STORE_IGNORED_INDEX_ENTRY constant,
62-
// found in src/native/clr/include/host/assembly-store.hh
63-
//
64-
const uint ASSEMBLY_STORE_IGNORED_INDEX_ENTRY = UInt32.MaxValue;
65-
6663
readonly TaskLoggingHelper log;
6764
readonly Dictionary<AndroidTargetArch, List<AssemblyStoreAssemblyInfo>> assemblies;
6865

@@ -127,22 +124,29 @@ string Generate (string baseOutputDirectory, AndroidTargetArch arch, List<Assemb
127124
using var fs = File.Open (storePath, FileMode.Create, FileAccess.Write, FileShare.Read);
128125
fs.Seek ((long)curPos, SeekOrigin.Begin);
129126

127+
uint mappingIndex = 0;
130128
foreach (AssemblyStoreAssemblyInfo info in infos) {
129+
(AssemblyStoreEntryDescriptor desc, curPos) = MakeDescriptor (info, curPos);
131130
if (info.Ignored) {
132-
AddToIndex (info, ASSEMBLY_STORE_IGNORED_INDEX_ENTRY);
133-
descriptors.Add (new AssemblyStoreEntryDescriptor ());
134-
continue;
131+
desc.mapping_index = 0;
132+
} else {
133+
desc.mapping_index = mappingIndex++;
135134
}
136-
137-
(AssemblyStoreEntryDescriptor desc, curPos) = MakeDescriptor (info, curPos);
138-
desc.mapping_index = (uint)descriptors.Count;
135+
uint entryIndex = (uint)descriptors.Count;
139136
descriptors.Add (desc);
140137

141-
if ((uint)fs.Position != desc.data_offset) {
138+
if (!info.Ignored && (uint)fs.Position != desc.data_offset) {
142139
throw new InvalidOperationException ($"Internal error: corrupted store '{storePath}' stream");
143140
}
144141

145-
AddToIndex (info, desc.mapping_index);
142+
ulong name_with_ext_hash = MonoAndroidHelper.GetXxHash (info.AssemblyNameBytes, is64Bit);
143+
ulong name_no_ext_hash = MonoAndroidHelper.GetXxHash (info.AssemblyNameNoExtBytes, is64Bit);
144+
index.Add (new AssemblyStoreIndexEntry (info.AssemblyName, name_with_ext_hash, entryIndex, info.Ignored));
145+
index.Add (new AssemblyStoreIndexEntry (info.AssemblyNameNoExt, name_no_ext_hash, entryIndex, info.Ignored));
146+
147+
if (info.Ignored) {
148+
continue;
149+
}
146150

147151
CopyData (info.SourceFile, fs, storePath);
148152
CopyData (info.SymbolsFile, fs, storePath);
@@ -175,14 +179,6 @@ string Generate (string baseOutputDirectory, AndroidTargetArch arch, List<Assemb
175179

176180
return storePath;
177181

178-
void AddToIndex (AssemblyStoreAssemblyInfo info, uint offset)
179-
{
180-
ulong name_with_ext_hash = MonoAndroidHelper.GetXxHash (info.AssemblyNameBytes, is64Bit);
181-
ulong name_no_ext_hash = MonoAndroidHelper.GetXxHash (info.AssemblyNameNoExtBytes, is64Bit);
182-
index.Add (new AssemblyStoreIndexEntry (info.AssemblyName, name_with_ext_hash, offset));
183-
index.Add (new AssemblyStoreIndexEntry (info.AssemblyNameNoExt, name_no_ext_hash, offset));
184-
}
185-
186182
uint IndexEntrySize () => is64Bit ? AssemblyStoreIndexEntry.NativeSize64 : AssemblyStoreIndexEntry.NativeSize32;
187183
}
188184

@@ -200,8 +196,8 @@ void CopyData (FileInfo? src, Stream dest, string storePath)
200196
static (AssemblyStoreEntryDescriptor desc, ulong newPos) MakeDescriptor (AssemblyStoreAssemblyInfo info, ulong curPos)
201197
{
202198
var ret = new AssemblyStoreEntryDescriptor {
203-
data_offset = (uint)curPos,
204-
data_size = GetDataLength (info.SourceFile),
199+
data_offset = info.Ignored ? 0 : (uint)curPos,
200+
data_size = info.Ignored ? 0 : GetDataLength (info.SourceFile),
205201
};
206202
if (info.SymbolsFile != null) {
207203
ret.debug_data_offset = ret.data_offset + ret.data_size;
@@ -213,9 +209,11 @@ void CopyData (FileInfo? src, Stream dest, string storePath)
213209
ret.config_data_size = GetDataLength (info.ConfigFile);
214210
}
215211

216-
curPos += ret.data_size + ret.debug_data_size + ret.config_data_size;
217-
if (curPos > UInt32.MaxValue) {
218-
throw new NotSupportedException ("Assembly store size exceeds the maximum supported value");
212+
if (!info.Ignored) {
213+
curPos += ret.data_size + ret.debug_data_size + ret.config_data_size;
214+
if (curPos > UInt32.MaxValue) {
215+
throw new NotSupportedException ("Assembly store size exceeds the maximum supported value");
216+
}
219217
}
220218

221219
return (ret, curPos);
@@ -268,21 +266,22 @@ void WriteIndex (BinaryWriter writer, StreamWriter manifestWriter, List<Assembly
268266
manifestWriter.Write ($"0x{(uint)entry.name_hash:x}");
269267
}
270268
writer.Write (entry.descriptor_index);
271-
272-
if (entry.descriptor_index == ASSEMBLY_STORE_IGNORED_INDEX_ENTRY) {
273-
manifestWriter.Write (" <IGNORED>");
274-
} else {
275-
manifestWriter.Write ($" di:{entry.descriptor_index}");
276-
AssemblyStoreEntryDescriptor desc = descriptors[(int)entry.descriptor_index];
277-
manifestWriter.Write ($" mi:{desc.mapping_index}");
278-
manifestWriter.Write ($" do:{desc.data_offset}");
279-
manifestWriter.Write ($" ds:{desc.data_size}");
280-
manifestWriter.Write ($" ddo:{desc.debug_data_offset}");
281-
manifestWriter.Write ($" dds:{desc.debug_data_size}");
282-
manifestWriter.Write ($" cdo:{desc.config_data_offset}");
283-
manifestWriter.Write ($" cds:{desc.config_data_size}");
269+
writer.Write ((byte)(entry.ignore ? 1 : 0));
270+
271+
manifestWriter.Write ($" di:{entry.descriptor_index}");
272+
AssemblyStoreEntryDescriptor desc = descriptors[(int)entry.descriptor_index];
273+
manifestWriter.Write ($" mi:{desc.mapping_index}");
274+
manifestWriter.Write ($" do:{desc.data_offset}");
275+
manifestWriter.Write ($" ds:{desc.data_size}");
276+
manifestWriter.Write ($" ddo:{desc.debug_data_offset}");
277+
manifestWriter.Write ($" dds:{desc.debug_data_size}");
278+
manifestWriter.Write ($" cdo:{desc.config_data_offset}");
279+
manifestWriter.Write ($" cds:{desc.config_data_size}");
280+
manifestWriter.Write ($" {entry.name}");
281+
if (entry.ignore) {
282+
manifestWriter.Write (" (ignored)");
284283
}
285-
manifestWriter.WriteLine ($" {entry.name}");
284+
manifestWriter.WriteLine ();
286285
}
287286
}
288287

@@ -305,7 +304,9 @@ List<AssemblyStoreIndexEntry> ReadIndex (BinaryReader reader, AssemblyStoreHeade
305304
}
306305

307306
uint descriptor_index = reader.ReadUInt32 ();
308-
index.Add (new AssemblyStoreIndexEntry (String.Empty, name_hash, descriptor_index));
307+
bool ignored = reader.ReadByte () != 0;
308+
309+
index.Add (new AssemblyStoreIndexEntry (String.Empty, name_hash, descriptor_index, ignored));
309310
}
310311

311312
return index;

src/native/clr/host/assembly-store.cc

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ auto AssemblyStore::find_assembly_store_entry (hash_t hash, const AssemblyStoreI
195195
auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size) noexcept -> void*
196196
{
197197
hash_t name_hash = xxhash::hash (name.data (), name.length ());
198-
log_debug (LOG_ASSEMBLY, "AssemblyStore::open_assembly: looking for bundled name: '{}' (hash {:x})"sv, optional_string (name.data ()), name_hash);
199198

200199
if constexpr (Constants::is_debug_build) {
201200
// In fastdev mode we might not have any assembly store.
@@ -206,17 +205,19 @@ auto AssemblyStore::open_assembly (std::string_view const& name, int64_t &size)
206205
}
207206

208207
const AssemblyStoreIndexEntry *hash_entry = find_assembly_store_entry (name_hash, assembly_store_hashes, assembly_store.index_entry_count);
209-
if (hash_entry == nullptr) {
208+
if (hash_entry == nullptr) [[unlikely]] {
209+
size = 0;
210210
log_warn (LOG_ASSEMBLY, "Assembly '{}' (hash 0x{:x}) not found"sv, name, name_hash);
211211
return nullptr;
212212
}
213213

214-
if (hash_entry->descriptor_index >= assembly_store.assembly_count) {
215-
if (hash_entry->descriptor_index == ASSEMBLY_STORE_IGNORED_INDEX_ENTRY) {
216-
log_debug (LOG_ASSEMBLY, "Assembly '{}' ignored"sv, name);
217-
return nullptr;
218-
}
214+
if (hash_entry->ignore != 0) {
215+
size = 0;
216+
log_debug (LOG_ASSEMBLY, "Assembly '{}' ignored"sv, name);
217+
return nullptr;
218+
}
219219

220+
if (hash_entry->descriptor_index >= assembly_store.assembly_count) {
220221
Helpers::abort_application (
221222
LOG_ASSEMBLY,
222223
std::format (

src/native/clr/include/host/assembly-store.hh

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,6 @@
1212
namespace xamarin::android {
1313
class AssemblyStore
1414
{
15-
using assembly_index_t = decltype(AssemblyStoreIndexEntry::descriptor_index);
16-
17-
static constexpr assembly_index_t ASSEMBLY_STORE_IGNORED_INDEX_ENTRY = std::numeric_limits<assembly_index_t>::max ();
18-
1915
public:
2016
static auto open_assembly (std::string_view const& name, int64_t &size) noexcept -> void*;
2117

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static constexpr uint32_t ASSEMBLY_STORE_ABI = 0x00040000;
3131
#endif
3232

3333
// Increase whenever an incompatible change is made to the assembly store format
34-
static constexpr uint32_t ASSEMBLY_STORE_FORMAT_VERSION = 2 | ASSEMBLY_STORE_64BIT_FLAG | ASSEMBLY_STORE_ABI;
34+
static constexpr uint32_t ASSEMBLY_STORE_FORMAT_VERSION = 3 | ASSEMBLY_STORE_64BIT_FLAG | ASSEMBLY_STORE_ABI;
3535

3636
static constexpr uint32_t MODULE_MAGIC_NAMES = 0x53544158; // 'XATS', little-endian
3737
static constexpr uint32_t MODULE_INDEX_MAGIC = 0x49544158; // 'XATI', little-endian
@@ -153,6 +153,7 @@ struct XamarinAndroidBundledAssembly
153153
// [HEADER]
154154
// [INDEX]
155155
// [ASSEMBLY_DESCRIPTORS]
156+
// [ASSEMBLY_NAMES]
156157
// [ASSEMBLY DATA]
157158
//
158159
// Formats of the sections above are as follows:
@@ -167,6 +168,7 @@ struct XamarinAndroidBundledAssembly
167168
// INDEX (variable size, HEADER.ENTRY_COUNT*2 entries, for assembly names with and without the extension)
168169
// [NAME_HASH] uint on 32-bit platforms, ulong on 64-bit platforms; xxhash of the assembly name
169170
// [DESCRIPTOR_INDEX] uint; index into in-store assembly descriptor array
171+
// [IGNORE] byte; if set to anything other than 0, the assembly is to be ignored when loading
170172
//
171173
// ASSEMBLY_DESCRIPTORS (variable size, HEADER.ENTRY_COUNT entries), each entry formatted as follows:
172174
// [MAPPING_INDEX] uint; index into a runtime array where assembly data pointers are stored
@@ -199,6 +201,7 @@ struct [[gnu::packed]] AssemblyStoreIndexEntry final
199201
{
200202
xamarin::android::hash_t name_hash;
201203
uint32_t descriptor_index;
204+
uint8_t ignore; // Assembly should be ignored when loading, its data isn't actually there
202205
};
203206

204207
struct [[gnu::packed]] AssemblyStoreEntryDescriptor final

tools/assembly-store-reader-mk2/AssemblyStore/AssemblyStoreItem.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@ abstract class AssemblyStoreItem
1616
public uint ConfigOffset { get; protected set; }
1717
public uint ConfigSize { get; protected set; }
1818
public AndroidTargetArch TargetArch { get; protected set; }
19+
public bool Ignore { get; }
1920

20-
protected AssemblyStoreItem (string name, bool is64Bit, List<ulong> hashes)
21+
protected AssemblyStoreItem (string name, bool is64Bit, List<ulong> hashes, bool ignore)
2122
{
2223
Name = name;
2324
Hashes = hashes.AsReadOnly ();
2425
Is64Bit = is64Bit;
26+
Ignore = ignore;
2527
}
2628
}

tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.Classes.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ sealed class IndexEntry
3232
{
3333
public readonly ulong name_hash;
3434
public readonly uint descriptor_index;
35+
public readonly bool ignore;
3536

36-
public IndexEntry (ulong name_hash, uint descriptor_index)
37+
public IndexEntry (ulong name_hash, uint descriptor_index, bool ignore)
3738
{
3839
this.name_hash = name_hash;
3940
this.descriptor_index = descriptor_index;
41+
this.ignore = ignore;
4042
}
4143
}
4244

@@ -56,8 +58,8 @@ sealed class EntryDescriptor
5658

5759
sealed class StoreItem_V2 : AssemblyStoreItem
5860
{
59-
public StoreItem_V2 (AndroidTargetArch targetArch, string name, bool is64Bit, List<IndexEntry> indexEntries, EntryDescriptor descriptor)
60-
: base (name, is64Bit, IndexToHashes (indexEntries))
61+
public StoreItem_V2 (AndroidTargetArch targetArch, string name, bool is64Bit, List<IndexEntry> indexEntries, EntryDescriptor descriptor, bool ignore)
62+
: base (name, is64Bit, IndexToHashes (indexEntries), ignore)
6163
{
6264
DataOffset = descriptor.data_offset;
6365
DataSize = descriptor.data_size;
@@ -84,11 +86,13 @@ sealed class TemporaryItem
8486
public readonly string Name;
8587
public readonly List<IndexEntry> IndexEntries = new List<IndexEntry> ();
8688
public readonly EntryDescriptor Descriptor;
89+
public readonly bool Ignored;
8790

88-
public TemporaryItem (string name, EntryDescriptor descriptor)
91+
public TemporaryItem (string name, EntryDescriptor descriptor, bool ignored)
8992
{
9093
Name = name;
9194
Descriptor = descriptor;
95+
Ignored = ignored;
9296
}
9397
}
9498
}

tools/assembly-store-reader-mk2/AssemblyStore/StoreReader_V2.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ namespace Xamarin.Android.AssemblyStore;
1111
partial class StoreReader_V2 : AssemblyStoreReader
1212
{
1313
// Bit 31 is set for 64-bit platforms, cleared for the 32-bit ones
14-
const uint ASSEMBLY_STORE_FORMAT_VERSION_64BIT = 0x80000002; // Must match the ASSEMBLY_STORE_FORMAT_VERSION native constant
15-
const uint ASSEMBLY_STORE_FORMAT_VERSION_32BIT = 0x00000002;
14+
const uint ASSEMBLY_STORE_FORMAT_VERSION_64BIT = 0x80000003; // Must match the ASSEMBLY_STORE_FORMAT_VERSION native constant
15+
const uint ASSEMBLY_STORE_FORMAT_VERSION_32BIT = 0x00000003;
1616
const uint ASSEMBLY_STORE_FORMAT_VERSION_MASK = 0xF0000000;
1717

1818
const uint ASSEMBLY_STORE_ABI_AARCH64 = 0x00010000;
@@ -162,7 +162,8 @@ protected override void Prepare ()
162162
}
163163

164164
uint descriptor_index = reader.ReadUInt32 ();
165-
index.Add (new IndexEntry (name_hash, descriptor_index));
165+
bool ignore = reader.ReadByte () != 0;
166+
index.Add (new IndexEntry (name_hash, descriptor_index, ignore));
166167
}
167168

168169
var descriptors = new List<EntryDescriptor> ();
@@ -197,7 +198,7 @@ protected override void Prepare ()
197198
var tempItems = new Dictionary<uint, TemporaryItem> ();
198199
foreach (IndexEntry ie in index) {
199200
if (!tempItems.TryGetValue (ie.descriptor_index, out TemporaryItem? item)) {
200-
item = new TemporaryItem (names[(int)ie.descriptor_index], descriptors[(int)ie.descriptor_index]);
201+
item = new TemporaryItem (names[(int)ie.descriptor_index], descriptors[(int)ie.descriptor_index], ie.ignore);
201202
tempItems.Add (ie.descriptor_index, item);
202203
}
203204
item.IndexEntries.Add (ie);
@@ -210,7 +211,7 @@ protected override void Prepare ()
210211
var storeItems = new List<AssemblyStoreItem> ();
211212
foreach (var kvp in tempItems) {
212213
TemporaryItem ti = kvp.Value;
213-
var item = new StoreItem_V2 (TargetArch, ti.Name, Is64Bit, ti.IndexEntries, ti.Descriptor);
214+
var item = new StoreItem_V2 (TargetArch, ti.Name, Is64Bit, ti.IndexEntries, ti.Descriptor, ti.Ignored);
214215
storeItems.Add (item);
215216
}
216217
Assemblies = storeItems.AsReadOnly ();

tools/assembly-store-reader-mk2/StorePrettyPrinter.cs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,21 @@ public void Show ()
3636
foreach (AssemblyStoreItem assembly in assemblies) {
3737
line.Clear ();
3838
line.Append (" ");
39-
line.AppendLine (assembly.Name);
40-
line.Append (" PE image data: ");
41-
FormatOffsetAndSize (line, assembly.DataOffset, assembly.DataSize);
42-
line.AppendLine ();
43-
line.Append (" Debug data: ");
44-
FormatOffsetAndSize (line, assembly.DebugOffset, assembly.DebugSize);
45-
line.AppendLine ();
46-
line.Append (" Config data: ");
47-
FormatOffsetAndSize (line, assembly.ConfigOffset, assembly.ConfigSize);
48-
line.AppendLine ();
39+
line.Append (assembly.Name);
40+
if (assembly.Ignore) {
41+
line.AppendLine (" <IGNORED>");
42+
} else {
43+
line.AppendLine ();
44+
line.Append (" PE image data: ");
45+
FormatOffsetAndSize (line, assembly.DataOffset, assembly.DataSize);
46+
line.AppendLine ();
47+
line.Append (" Debug data: ");
48+
FormatOffsetAndSize (line, assembly.DebugOffset, assembly.DebugSize);
49+
line.AppendLine ();
50+
line.Append (" Config data: ");
51+
FormatOffsetAndSize (line, assembly.ConfigOffset, assembly.ConfigSize);
52+
line.AppendLine ();
53+
}
4954
line.Append (" Name hashes: ");
5055
FormatHashes (line, assembly.Hashes);
5156
line.AppendLine ();

0 commit comments

Comments
 (0)