diff --git a/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs b/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs
index 431f089d0..7685cad7d 100644
--- a/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs
+++ b/ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs
@@ -350,36 +350,54 @@ namespace ICSharpCode.Decompiler.Metadata
public static IEnumerable<(Handle Handle, MethodSemanticsAttributes Semantics, MethodDefinitionHandle Method, EntityHandle Association)> GetMethodSemantics(this MetadataReader metadata)
{
- int offset = metadata.GetTableMetadataOffset(TableIndex.MethodSemantics);
- int rowSize = metadata.GetTableRowSize(TableIndex.MethodSemantics);
int rowCount = metadata.GetTableRowCount(TableIndex.MethodSemantics);
+ var reader = metadata.AsBlobReader();
+ reader.Offset = metadata.GetTableMetadataOffset(TableIndex.MethodSemantics);
- bool methodSmall = metadata.GetTableRowCount(TableIndex.MethodDef) <= ushort.MaxValue;
- bool assocSmall = metadata.GetTableRowCount(TableIndex.Property) <= ushort.MaxValue && metadata.GetTableRowCount(TableIndex.Event) <= ushort.MaxValue;
- int assocOffset = (methodSmall ? 2 : 4) + 2;
- for (int row = 0; row < rowCount; row++)
+ int methodSize = SimpleIndexSize(metadata, TableIndex.MethodDef);
+ // HasSemantics coded index: 1 tag bit over Event (tag 0) and Property (tag 1).
+ int assocSize = CodedIndexSize(metadata, 1, TableIndex.Event, TableIndex.Property);
+ for (int rid = 1; rid <= rowCount; rid++)
{
- yield return Read(row);
- }
-
- (Handle Handle, MethodSemanticsAttributes Semantics, MethodDefinitionHandle Method, EntityHandle Association) Read(int row)
- {
- var span = metadata.AsReadOnlySpan();
- var methodDefSpan = span.Slice(offset + rowSize * row + 2);
- int methodDef = methodSmall ? BinaryPrimitives.ReadUInt16LittleEndian(methodDefSpan) : (int)BinaryPrimitives.ReadUInt32LittleEndian(methodDefSpan);
- var assocSpan = span.Slice(assocOffset);
- int assocDef = assocSmall ? BinaryPrimitives.ReadUInt16LittleEndian(assocSpan) : (int)BinaryPrimitives.ReadUInt32LittleEndian(assocSpan);
+ var semantics = (MethodSemanticsAttributes)reader.ReadUInt16();
+ int methodRow = methodSize == 2 ? reader.ReadUInt16() : reader.ReadInt32();
+ int assocTag = assocSize == 2 ? reader.ReadUInt16() : reader.ReadInt32();
EntityHandle propOrEvent;
- if ((assocDef & 0x1) == 1)
+ if ((assocTag & 0x1) == 1)
{
- propOrEvent = MetadataTokens.PropertyDefinitionHandle(assocDef >> 1);
+ propOrEvent = MetadataTokens.PropertyDefinitionHandle(assocTag >> 1);
}
else
{
- propOrEvent = MetadataTokens.EventDefinitionHandle(assocDef >> 1);
+ propOrEvent = MetadataTokens.EventDefinitionHandle(assocTag >> 1);
}
- return (MetadataTokens.Handle(0x18000000 | (row + 1)), (MethodSemanticsAttributes)(BinaryPrimitives.ReadUInt16LittleEndian(span)), MetadataTokens.MethodDefinitionHandle(methodDef), propOrEvent);
+ yield return (MetadataTokens.Handle(((int)TableIndex.MethodSemantics << 24) | rid), semantics, MetadataTokens.MethodDefinitionHandle(methodRow), propOrEvent);
+ }
+ }
+
+ ///
+ /// Size in bytes of a column indexing directly
+ /// (ECMA-335 II.24.2.6: 2 bytes while the table has fewer than 2^16 rows).
+ ///
+ static int SimpleIndexSize(MetadataReader metadata, TableIndex table)
+ {
+ return metadata.GetTableRowCount(table) < (1 << 16) ? 2 : 4;
+ }
+
+ ///
+ /// Size in bytes of a coded-index column over with
+ /// tag bits (ECMA-335 II.24.2.6: 2 bytes while every
+ /// indexed table has fewer than 2^(16 - tagBits) rows).
+ ///
+ static int CodedIndexSize(MetadataReader metadata, int tagBits, params TableIndex[] tables)
+ {
+ int smallLimit = 1 << (16 - tagBits);
+ foreach (var table in tables)
+ {
+ if (metadata.GetTableRowCount(table) >= smallLimit)
+ return 4;
}
+ return 2;
}
public static IEnumerable GetFieldLayouts(this MetadataReader metadata)