From 99d5cbc7c1bf6bac0e9c1b841c14c8b44ff7ba35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paulus=20P=C3=A4rssinen?= Date: Thu, 25 Jul 2024 11:57:17 +0000 Subject: [PATCH] Use `BinaryPrimitives` more in the ILCompiler (#105404) --- src/coreclr/tools/Common/Pgo/PgoFormat.cs | 15 ++----- .../Common/TypeSystem/IL/ILDisassembler.cs | 13 +++--- .../tools/Common/TypeSystem/IL/ILImporter.cs | 24 ++++++----- .../Common/TypeSystem/IL/Stubs/ILEmitter.cs | 41 +++++++++++-------- 4 files changed, 46 insertions(+), 47 deletions(-) diff --git a/src/coreclr/tools/Common/Pgo/PgoFormat.cs b/src/coreclr/tools/Common/Pgo/PgoFormat.cs index b0222f8a0c8f9..feb91572b0ae1 100644 --- a/src/coreclr/tools/Common/Pgo/PgoFormat.cs +++ b/src/coreclr/tools/Common/Pgo/PgoFormat.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Buffers.Binary; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -163,22 +164,12 @@ public bool MoveNext() } else if ((bytes[offset]) == 0xC1) // 8 byte specifier { - signedInt = (((long)bytes[offset + 1]) << 56) | - (((long)bytes[offset + 2]) << 48) | - (((long)bytes[offset + 3]) << 40) | - (((long)bytes[offset + 4]) << 32) | - (((long)bytes[offset + 5]) << 24) | - (((long)bytes[offset + 6]) << 16) | - (((long)bytes[offset + 7]) << 8) | - ((long)bytes[offset + 8]); + signedInt = BinaryPrimitives.ReadInt64BigEndian(bytes.AsSpan(offset + 1, sizeof(long))); offset += 9; } else { - signedInt = (((int)bytes[offset + 1]) << 24) | - (((int)bytes[offset + 2]) << 16) | - (((int)bytes[offset + 3]) << 8) | - ((int)bytes[offset + 4]); + signedInt = BinaryPrimitives.ReadInt32BigEndian(bytes.AsSpan(offset + 1, sizeof(int))); offset += 5; } diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs index 1dfe404b63f26..cb71913d0232c 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Buffers.Binary; using System.Text; using Internal.TypeSystem; @@ -191,15 +192,15 @@ private byte ReadILByte() private ushort ReadILUInt16() { - ushort val = (ushort)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8)); - _currentOffset += 2; + ushort val = BinaryPrimitives.ReadUInt16LittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(ushort))); + _currentOffset += sizeof(ushort); return val; } private uint ReadILUInt32() { - uint val = (uint)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8) + (_ilBytes[_currentOffset + 2] << 16) + (_ilBytes[_currentOffset + 3] << 24)); - _currentOffset += 4; + uint val = BinaryPrimitives.ReadUInt32LittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(uint))); + _currentOffset += sizeof(uint); return val; } @@ -211,8 +212,8 @@ private int ReadILToken() private ulong ReadILUInt64() { - ulong value = ReadILUInt32(); - value |= (((ulong)ReadILUInt32()) << 32); + ulong value = BinaryPrimitives.ReadUInt64LittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(ulong))); + _currentOffset += sizeof(ulong); return value; } diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs index afc10fce167ba..74da13d94a398 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System; +using System.Buffers.Binary; using Internal.TypeSystem; namespace Internal.IL @@ -20,7 +22,7 @@ internal sealed partial class ILImporter private byte ReadILByte() { - if (_currentOffset >= _ilBytes.Length) + if (_currentOffset + 1 > _ilBytes.Length) ReportMethodEndInsideInstruction(); return _ilBytes[_currentOffset++]; @@ -28,22 +30,20 @@ private byte ReadILByte() private ushort ReadILUInt16() { - if (_currentOffset + 1 >= _ilBytes.Length) + if (!BinaryPrimitives.TryReadUInt16LittleEndian(_ilBytes.AsSpan(_currentOffset), out ushort value)) ReportMethodEndInsideInstruction(); - ushort val = (ushort)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8)); - _currentOffset += 2; - return val; + _currentOffset += sizeof(ushort); + return value; } private uint ReadILUInt32() { - if (_currentOffset + 3 >= _ilBytes.Length) + if (!BinaryPrimitives.TryReadUInt32LittleEndian(_ilBytes.AsSpan(_currentOffset), out uint value)) ReportMethodEndInsideInstruction(); - uint val = (uint)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8) + (_ilBytes[_currentOffset + 2] << 16) + (_ilBytes[_currentOffset + 3] << 24)); - _currentOffset += 4; - return val; + _currentOffset += sizeof(uint); + return value; } private int ReadILToken() @@ -53,8 +53,10 @@ private int ReadILToken() private ulong ReadILUInt64() { - ulong value = ReadILUInt32(); - value |= (((ulong)ReadILUInt32()) << 32); + if (!BinaryPrimitives.TryReadUInt64LittleEndian(_ilBytes.AsSpan(_currentOffset), out ulong value)) + ReportMethodEndInsideInstruction(); + + _currentOffset += sizeof(ulong); return value; } diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs index 4a4723d2b7afd..20ae6f6e28a4e 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs @@ -2,8 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Buffers.Binary; using System.Collections.Generic; - +using System.Runtime.CompilerServices; using Internal.TypeSystem; using Debug = System.Diagnostics.Debug; @@ -49,23 +50,33 @@ internal int RelativeToAbsoluteOffset(int relativeOffset) private void EmitByte(byte b) { - if (_instructions.Length == _length) - Array.Resize(ref _instructions, 2 * _instructions.Length + 10); + if (_length == _instructions.Length) + Grow(); _instructions[_length++] = b; } private void EmitUInt16(ushort value) { - EmitByte((byte)value); - EmitByte((byte)(value >> 8)); + if (_length + sizeof(ushort) > _instructions.Length) + Grow(); + + BinaryPrimitives.WriteUInt16LittleEndian(_instructions.AsSpan(_length, sizeof(ushort)), value); + _length += sizeof(ushort); } private void EmitUInt32(int value) { - EmitByte((byte)value); - EmitByte((byte)(value >> 8)); - EmitByte((byte)(value >> 16)); - EmitByte((byte)(value >> 24)); + if (_length + sizeof(int) > _instructions.Length) + Grow(); + + BinaryPrimitives.WriteInt32LittleEndian(_instructions.AsSpan(_length, sizeof(int)), value); + _length += sizeof(int); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void Grow() + { + Array.Resize(ref _instructions, 2 * _instructions.Length + 10); } public void Emit(ILOpcode opcode) @@ -468,19 +479,13 @@ internal void PatchLabels() Debug.Assert(patch.Label.IsPlaced); Debug.Assert(_startOffsetForLinking != StartOffsetNotSet); - int offset = patch.Offset; + Span offsetSpan = _instructions.AsSpan(patch.Offset, sizeof(int)); - int delta = _instructions[offset + 3] << 24 | - _instructions[offset + 2] << 16 | - _instructions[offset + 1] << 8 | - _instructions[offset]; + int delta = BinaryPrimitives.ReadInt32LittleEndian(offsetSpan); int value = patch.Label.AbsoluteOffset - _startOffsetForLinking - patch.Offset - delta; - _instructions[offset] = (byte)value; - _instructions[offset + 1] = (byte)(value >> 8); - _instructions[offset + 2] = (byte)(value >> 16); - _instructions[offset + 3] = (byte)(value >> 24); + BinaryPrimitives.WriteInt32LittleEndian(offsetSpan, value); } }