Skip to content

Commit

Permalink
Reduce "unsafe" by replacing byte* pointer usage with ReadOnlySpan<by…
Browse files Browse the repository at this point in the history
…te> (#3106)
  • Loading branch information
fowl2 authored Nov 1, 2023
1 parent eae54dd commit 0bab8a0
Show file tree
Hide file tree
Showing 12 changed files with 133 additions and 89 deletions.
40 changes: 30 additions & 10 deletions ICSharpCode.Decompiler/Metadata/MetadataExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
Expand Down Expand Up @@ -384,11 +385,13 @@ public static IEnumerable<MethodSpecificationHandle> GetMethodSpecifications(thi
yield return Read(row);
}

unsafe (Handle Handle, MethodSemanticsAttributes Semantics, MethodDefinitionHandle Method, EntityHandle Association) Read(int row)
(Handle Handle, MethodSemanticsAttributes Semantics, MethodDefinitionHandle Method, EntityHandle Association) Read(int row)
{
byte* ptr = metadata.MetadataPointer + offset + rowSize * row;
int methodDef = methodSmall ? *(ushort*)(ptr + 2) : (int)*(uint*)(ptr + 2);
int assocDef = assocSmall ? *(ushort*)(ptr + assocOffset) : (int)*(uint*)(ptr + assocOffset);
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);
EntityHandle propOrEvent;
if ((assocDef & 0x1) == 1)
{
Expand All @@ -398,7 +401,7 @@ public static IEnumerable<MethodSpecificationHandle> GetMethodSpecifications(thi
{
propOrEvent = MetadataTokens.EventDefinitionHandle(assocDef >> 1);
}
return (MetadataTokens.Handle(0x18000000 | (row + 1)), (MethodSemanticsAttributes)(*(ushort*)ptr), MetadataTokens.MethodDefinitionHandle(methodDef), propOrEvent);
return (MetadataTokens.Handle(0x18000000 | (row + 1)), (MethodSemanticsAttributes)(BinaryPrimitives.ReadUInt16LittleEndian(span)), MetadataTokens.MethodDefinitionHandle(methodDef), propOrEvent);
}
}

Expand All @@ -411,9 +414,9 @@ public static IEnumerable<EntityHandle> GetFieldLayouts(this MetadataReader meta
}
}

public unsafe static (int Offset, FieldDefinitionHandle FieldDef) GetFieldLayout(this MetadataReader metadata, EntityHandle fieldLayoutHandle)
public static (int Offset, FieldDefinitionHandle FieldDef) GetFieldLayout(this MetadataReader metadata, EntityHandle fieldLayoutHandle)
{
byte* startPointer = metadata.MetadataPointer;
var startPointer = metadata.AsReadOnlySpan();
int offset = metadata.GetTableMetadataOffset(TableIndex.FieldLayout);
int rowSize = metadata.GetTableRowSize(TableIndex.FieldLayout);
int rowCount = metadata.GetTableRowCount(TableIndex.FieldLayout);
Expand All @@ -422,14 +425,31 @@ public unsafe static (int Offset, FieldDefinitionHandle FieldDef) GetFieldLayout
bool small = metadata.GetTableRowCount(TableIndex.Field) <= ushort.MaxValue;
for (int row = rowCount - 1; row >= 0; row--)
{
byte* ptr = startPointer + offset + rowSize * row;
uint rowNo = small ? *(ushort*)(ptr + 4) : *(uint*)(ptr + 4);
ReadOnlySpan<byte> ptr = startPointer.Slice(offset + rowSize * row);
var rowNoSpan = ptr.Slice(4);
uint rowNo = small ? BinaryPrimitives.ReadUInt16LittleEndian(rowNoSpan) : BinaryPrimitives.ReadUInt32LittleEndian(rowNoSpan);
if (fieldRowNo == rowNo)
{
return (*(int*)ptr, MetadataTokens.FieldDefinitionHandle(fieldRowNo));
return (BinaryPrimitives.ReadInt32LittleEndian(ptr), MetadataTokens.FieldDefinitionHandle(fieldRowNo));
}
}
return (0, default);
}

public static ReadOnlySpan<byte> AsReadOnlySpan(this MetadataReader metadataReader)
{
unsafe
{
return new(metadataReader.MetadataPointer, metadataReader.MetadataLength);
}
}

public static BlobReader AsBlobReader(this MetadataReader metadataReader)
{
unsafe
{
return new(metadataReader.MetadataPointer, metadataReader.MetadataLength);
}
}
}
}
20 changes: 11 additions & 9 deletions ILSpy/Metadata/CorTables/ClassLayoutTableTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
Expand All @@ -38,7 +40,7 @@ public ClassLayoutTableTreeNode(PEFile module)

public override object Icon => Images.Literal;

public unsafe override bool View(ViewModels.TabPageModel tabPage)
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
tabPage.SupportsLanguageSwitching = false;
Expand All @@ -49,7 +51,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
var list = new List<ClassLayoutEntry>();

var length = metadata.GetTableRowCount(TableIndex.ClassLayout);
byte* ptr = metadata.MetadataPointer;
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
ClassLayoutEntry scrollTargetEntry = default;

Expand Down Expand Up @@ -80,15 +82,15 @@ readonly struct ClassLayout
public readonly EntityHandle Parent;
public readonly uint ClassSize;

public unsafe ClassLayout(byte* ptr, int typeDefSize)
public ClassLayout(ReadOnlySpan<byte> ptr, int typeDefSize)
{
PackingSize = (ushort)Helpers.GetValue(ptr, 2);
ClassSize = (uint)Helpers.GetValue(ptr + 2, 4);
Parent = MetadataTokens.TypeDefinitionHandle(Helpers.GetValue(ptr + 6, typeDefSize));
PackingSize = BinaryPrimitives.ReadUInt16LittleEndian(ptr);
ClassSize = BinaryPrimitives.ReadUInt32LittleEndian(ptr.Slice(2, 4));
Parent = MetadataTokens.TypeDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(6, typeDefSize)));
}
}

unsafe struct ClassLayoutEntry
struct ClassLayoutEntry
{
readonly PEFile module;
readonly MetadataReader metadata;
Expand Down Expand Up @@ -117,15 +119,15 @@ public void OnParentClick()
[ColumnInfo("X8", Kind = ColumnKind.Other)]
public uint ClassSize => classLayout.ClassSize;

public ClassLayoutEntry(PEFile module, byte* ptr, int metadataOffset, int row)
public ClassLayoutEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
{
this.module = module;
this.metadata = module.Metadata;
this.RID = row;
var rowOffset = metadata.GetTableMetadataOffset(TableIndex.ClassLayout)
+ metadata.GetTableRowSize(TableIndex.ClassLayout) * (row - 1);
this.Offset = metadataOffset + rowOffset;
this.classLayout = new ClassLayout(ptr + rowOffset, metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4);
this.classLayout = new ClassLayout(ptr.Slice(rowOffset), metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4);
this.parentTooltip = null;
}
}
Expand Down
17 changes: 9 additions & 8 deletions ILSpy/Metadata/CorTables/EventMapTableTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
Expand All @@ -38,7 +39,7 @@ public EventMapTableTreeNode(PEFile module)

public override object Icon => Images.Literal;

public unsafe override bool View(ViewModels.TabPageModel tabPage)
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
tabPage.SupportsLanguageSwitching = false;
Expand All @@ -50,7 +51,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
EventMapEntry scrollTargetEntry = default;

var length = metadata.GetTableRowCount(TableIndex.EventMap);
byte* ptr = metadata.MetadataPointer;
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
for (int rid = 1; rid <= length; rid++)
{
Expand Down Expand Up @@ -79,14 +80,14 @@ readonly struct EventMap
public readonly TypeDefinitionHandle Parent;
public readonly EventDefinitionHandle EventList;

public unsafe EventMap(byte* ptr, int typeDefSize, int eventDefSize)
public EventMap(ReadOnlySpan<byte> ptr, int typeDefSize, int eventDefSize)
{
Parent = MetadataTokens.TypeDefinitionHandle(Helpers.GetValue(ptr, typeDefSize));
EventList = MetadataTokens.EventDefinitionHandle(Helpers.GetValue(ptr + typeDefSize, eventDefSize));
Parent = MetadataTokens.TypeDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(0, typeDefSize)));
EventList = MetadataTokens.EventDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(typeDefSize, eventDefSize)));
}
}

unsafe struct EventMapEntry
struct EventMapEntry
{
readonly PEFile module;
readonly MetadataReader metadata;
Expand Down Expand Up @@ -120,7 +121,7 @@ public void OnEventListClick()
string eventListTooltip;
public string EventListTooltip => GenerateTooltip(ref eventListTooltip, module, eventMap.EventList);

public EventMapEntry(PEFile module, byte* ptr, int metadataOffset, int row)
public EventMapEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
{
this.module = module;
this.metadata = module.Metadata;
Expand All @@ -130,7 +131,7 @@ public EventMapEntry(PEFile module, byte* ptr, int metadataOffset, int row)
this.Offset = metadataOffset + rowOffset;
int typeDefSize = metadata.GetTableRowCount(TableIndex.TypeDef) < ushort.MaxValue ? 2 : 4;
int eventDefSize = metadata.GetTableRowCount(TableIndex.Event) < ushort.MaxValue ? 2 : 4;
this.eventMap = new EventMap(ptr + rowOffset, typeDefSize, eventDefSize);
this.eventMap = new EventMap(ptr.Slice(rowOffset), typeDefSize, eventDefSize);
this.parentTooltip = null;
this.eventListTooltip = null;
}
Expand Down
18 changes: 10 additions & 8 deletions ILSpy/Metadata/CorTables/FieldLayoutTableTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
Expand All @@ -38,7 +40,7 @@ public FieldLayoutTableTreeNode(PEFile module)

public override object Icon => Images.Literal;

public unsafe override bool View(ViewModels.TabPageModel tabPage)
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
tabPage.SupportsLanguageSwitching = false;
Expand All @@ -50,7 +52,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
FieldLayoutEntry scrollTargetEntry = default;

var length = metadata.GetTableRowCount(TableIndex.FieldLayout);
byte* ptr = metadata.MetadataPointer;
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
for (int rid = 1; rid <= length; rid++)
{
Expand Down Expand Up @@ -79,14 +81,14 @@ readonly struct FieldLayout
public readonly int Offset;
public readonly FieldDefinitionHandle Field;

public unsafe FieldLayout(byte* ptr, int fieldDefSize)
public FieldLayout(ReadOnlySpan<byte> ptr, int fieldDefSize)
{
Offset = Helpers.GetValue(ptr, 4);
Field = MetadataTokens.FieldDefinitionHandle(Helpers.GetValue(ptr + 4, fieldDefSize));
Offset = BinaryPrimitives.ReadInt32LittleEndian(ptr);
Field = MetadataTokens.FieldDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(4, fieldDefSize)));
}
}

unsafe struct FieldLayoutEntry
struct FieldLayoutEntry
{
readonly PEFile module;
readonly MetadataReader metadata;
Expand All @@ -112,7 +114,7 @@ public void OnFieldClick()
[ColumnInfo("X8", Kind = ColumnKind.Other)]
public int FieldOffset => fieldLayout.Offset;

public FieldLayoutEntry(PEFile module, byte* ptr, int metadataOffset, int row)
public FieldLayoutEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
{
this.module = module;
this.metadata = module.Metadata;
Expand All @@ -121,7 +123,7 @@ public FieldLayoutEntry(PEFile module, byte* ptr, int metadataOffset, int row)
+ metadata.GetTableRowSize(TableIndex.FieldLayout) * (row - 1);
this.Offset = metadataOffset + rowOffset;
int fieldDefSize = metadata.GetTableRowCount(TableIndex.Field) < ushort.MaxValue ? 2 : 4;
this.fieldLayout = new FieldLayout(ptr + rowOffset, fieldDefSize);
this.fieldLayout = new FieldLayout(ptr.Slice(rowOffset), fieldDefSize);
this.fieldTooltip = null;
}
}
Expand Down
17 changes: 9 additions & 8 deletions ILSpy/Metadata/CorTables/FieldMarshalTableTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
Expand All @@ -38,7 +39,7 @@ public FieldMarshalTableTreeNode(PEFile module)

public override object Icon => Images.Literal;

public unsafe override bool View(ViewModels.TabPageModel tabPage)
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
tabPage.SupportsLanguageSwitching = false;
Expand All @@ -50,7 +51,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
FieldMarshalEntry scrollTargetEntry = default;

var length = metadata.GetTableRowCount(TableIndex.FieldMarshal);
byte* ptr = metadata.MetadataPointer;
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
for (int rid = 1; rid <= length; rid++)
{
Expand Down Expand Up @@ -79,14 +80,14 @@ readonly struct FieldMarshal
public readonly BlobHandle NativeType;
public readonly EntityHandle Parent;

public unsafe FieldMarshal(byte* ptr, int blobHeapSize, int hasFieldMarshalRefSize)
public FieldMarshal(ReadOnlySpan<byte> ptr, int blobHeapSize, int hasFieldMarshalRefSize)
{
Parent = Helpers.FromHasFieldMarshalTag((uint)Helpers.GetValue(ptr, hasFieldMarshalRefSize));
NativeType = MetadataTokens.BlobHandle(Helpers.GetValue(ptr + hasFieldMarshalRefSize, blobHeapSize));
Parent = Helpers.FromHasFieldMarshalTag((uint)Helpers.GetValueLittleEndian(ptr, hasFieldMarshalRefSize));
NativeType = MetadataTokens.BlobHandle(Helpers.GetValueLittleEndian(ptr.Slice(hasFieldMarshalRefSize, blobHeapSize)));
}
}

unsafe struct FieldMarshalEntry
struct FieldMarshalEntry
{
readonly PEFile module;
readonly MetadataReader metadata;
Expand All @@ -112,7 +113,7 @@ public void OnParentClick()
[ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
public int NativeType => MetadataTokens.GetHeapOffset(fieldMarshal.NativeType);

public FieldMarshalEntry(PEFile module, byte* ptr, int metadataOffset, int row)
public FieldMarshalEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
{
this.module = module;
this.metadata = module.Metadata;
Expand All @@ -122,7 +123,7 @@ public FieldMarshalEntry(PEFile module, byte* ptr, int metadataOffset, int row)
this.Offset = metadataOffset + rowOffset;
int hasFieldMarshalRefSize = metadata.ComputeCodedTokenSize(32768, TableMask.Field | TableMask.Param);
int blobHeapSize = metadata.GetHeapSize(HeapIndex.Blob) < ushort.MaxValue ? 2 : 4;
this.fieldMarshal = new FieldMarshal(ptr + rowOffset, blobHeapSize, hasFieldMarshalRefSize);
this.fieldMarshal = new FieldMarshal(ptr.Slice(rowOffset), blobHeapSize, hasFieldMarshalRefSize);
this.parentTooltip = null;
}
}
Expand Down
18 changes: 10 additions & 8 deletions ILSpy/Metadata/CorTables/FieldRVATableTreeNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
Expand All @@ -38,7 +40,7 @@ public FieldRVATableTreeNode(PEFile module)

public override object Icon => Images.Literal;

public unsafe override bool View(ViewModels.TabPageModel tabPage)
public override bool View(ViewModels.TabPageModel tabPage)
{
tabPage.Title = Text.ToString();
tabPage.SupportsLanguageSwitching = false;
Expand All @@ -50,7 +52,7 @@ public unsafe override bool View(ViewModels.TabPageModel tabPage)
FieldRVAEntry scrollTargetEntry = default;

var length = metadata.GetTableRowCount(TableIndex.FieldRva);
byte* ptr = metadata.MetadataPointer;
ReadOnlySpan<byte> ptr = metadata.AsReadOnlySpan();
int metadataOffset = module.Reader.PEHeaders.MetadataStartOffset;
for (int rid = 1; rid <= length; rid++)
{
Expand Down Expand Up @@ -79,14 +81,14 @@ readonly struct FieldRVA
public readonly int Offset;
public readonly FieldDefinitionHandle Field;

public unsafe FieldRVA(byte* ptr, int fieldDefSize)
public FieldRVA(ReadOnlySpan<byte> ptr, int fieldDefSize)
{
Offset = Helpers.GetValue(ptr, 4);
Field = MetadataTokens.FieldDefinitionHandle(Helpers.GetValue(ptr + 4, fieldDefSize));
Offset = BinaryPrimitives.ReadInt32LittleEndian(ptr);
Field = MetadataTokens.FieldDefinitionHandle(Helpers.GetValueLittleEndian(ptr.Slice(4, fieldDefSize)));
}
}

unsafe struct FieldRVAEntry
struct FieldRVAEntry
{
readonly PEFile module;
readonly MetadataReader metadata;
Expand All @@ -112,7 +114,7 @@ public void OnFieldClick()
[ColumnInfo("X8", Kind = ColumnKind.Other)]
public int FieldOffset => fieldRVA.Offset;

public FieldRVAEntry(PEFile module, byte* ptr, int metadataOffset, int row)
public FieldRVAEntry(PEFile module, ReadOnlySpan<byte> ptr, int metadataOffset, int row)
{
this.module = module;
this.metadata = module.Metadata;
Expand All @@ -121,7 +123,7 @@ public FieldRVAEntry(PEFile module, byte* ptr, int metadataOffset, int row)
+ metadata.GetTableRowSize(TableIndex.FieldRva) * (row - 1);
this.Offset = metadataOffset + rowOffset;
int fieldDefSize = metadata.GetTableRowCount(TableIndex.Field) < ushort.MaxValue ? 2 : 4;
this.fieldRVA = new FieldRVA(ptr + rowOffset, fieldDefSize);
this.fieldRVA = new FieldRVA(ptr.Slice(rowOffset), fieldDefSize);
this.fieldTooltip = null;
}
}
Expand Down
Loading

0 comments on commit 0bab8a0

Please sign in to comment.