From caeb467770ec2af5700b53f4a6fd34ddf5eebebc Mon Sep 17 00:00:00 2001 From: PaulusParssinen Date: Wed, 24 Jul 2024 16:40:50 +0300 Subject: [PATCH 1/7] Use BinaryPrimitives in ILImporter --- .../tools/Common/TypeSystem/IL/ILImporter.cs | 42 +++++++++++-------- .../tools/Common/TypeSystem/IL/ILReader.cs | 2 +- .../IL/ILImporter.Scanner.cs | 7 ++-- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs index afc10fce167bae..7c73fcc22ea409 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,21 +53,29 @@ 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; } - private unsafe float ReadILFloat() + private float ReadILFloat() { - uint value = ReadILUInt32(); - return *(float*)(&value); + if (!BinaryPrimitives.TryReadSingleLittleEndian(_ilBytes.AsSpan(_currentOffset), out float value)) + ReportMethodEndInsideInstruction(); + + _currentOffset += sizeof(float); + return value; } - private unsafe double ReadILDouble() + private double ReadILDouble() { - ulong value = ReadILUInt64(); - return *(double*)(&value); + if (!BinaryPrimitives.TryReadDoubleLittleEndian(_ilBytes.AsSpan(_currentOffset), out double value)) + ReportMethodEndInsideInstruction(); + + _currentOffset += sizeof(double); + return value; } private void SkipIL(int bytes) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILReader.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILReader.cs index 8c462a8ac2281b..5015b91146fea9 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/ILReader.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/ILReader.cs @@ -80,7 +80,7 @@ public float ReadILFloat() return value; } - public unsafe double ReadILDouble() + public double ReadILDouble() { if (!BinaryPrimitives.TryReadDoubleLittleEndian(_ilBytes.Slice(_currentOffset), out double value)) ThrowHelper.ThrowInvalidProgramException(); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 81c35b2f72cbf8..538b80f3d9634f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.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; using Internal.ReadyToRunConstants; @@ -1380,10 +1382,7 @@ private void ImportFallthrough(BasicBlock next, object condition = null) private int ReadILTokenAt(int ilOffset) { - return (int)(_ilBytes[ilOffset] - + (_ilBytes[ilOffset + 1] << 8) - + (_ilBytes[ilOffset + 2] << 16) - + (_ilBytes[ilOffset + 3] << 24)); + return BinaryPrimitives.ReadInt32LittleEndian(_ilBytes.AsSpan(ilOffset, sizeof(int))); } private static void ReportInvalidBranchTarget(int targetOffset) From 7e069362a38ccc933a55d116a839ccfbe2fe36d4 Mon Sep 17 00:00:00 2001 From: PaulusParssinen Date: Wed, 24 Jul 2024 17:04:14 +0300 Subject: [PATCH 2/7] Use BinaryPrimitives in PgoFormat --- src/coreclr/tools/Common/Pgo/PgoFormat.cs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/coreclr/tools/Common/Pgo/PgoFormat.cs b/src/coreclr/tools/Common/Pgo/PgoFormat.cs index b0222f8a0c8f9a..feb91572b0ae13 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; } From 69251fabd8ccaf608bc8953d615ec3abed6b4f72 Mon Sep 17 00:00:00 2001 From: PaulusParssinen Date: Wed, 24 Jul 2024 17:14:17 +0300 Subject: [PATCH 3/7] Use BinaryPrimitives in ILDisassembler --- .../Common/TypeSystem/IL/ILDisassembler.cs | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs index 1dfe404b63f265..511393c080a470 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,21 +212,23 @@ 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; } - private unsafe float ReadILFloat() + private float ReadILFloat() { - uint value = ReadILUInt32(); - return *(float*)(&value); + float value = BinaryPrimitives.ReadSingleLittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(float))); + _currentOffset += sizeof(float); + return value; } - private unsafe double ReadILDouble() + private double ReadILDouble() { - ulong value = ReadILUInt64(); - return *(double*)(&value); + double value = BinaryPrimitives.ReadDoubleLittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(double))); + _currentOffset += sizeof(double); + return value; } public static void AppendOffset(StringBuilder sb, int offset) From a3b5da2835080e4503badb301441e139025d690f Mon Sep 17 00:00:00 2001 From: PaulusParssinen Date: Wed, 24 Jul 2024 17:37:55 +0300 Subject: [PATCH 4/7] Use BinaryPrimitives in ILEmitter --- .../Common/TypeSystem/IL/Stubs/ILEmitter.cs | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ILEmitter.cs index 4a4723d2b7afd4..20ae6f6e28a4e1 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); } } From 56ffaaf26ff986e9361d33f0b248f87b69edf885 Mon Sep 17 00:00:00 2001 From: PaulusParssinen Date: Wed, 24 Jul 2024 18:35:39 +0300 Subject: [PATCH 5/7] Revert "Use BinaryPrimitives in ILDisassembler" * One day ILVerify drops NS2.0, hopefully. This reverts commit 69251fabd8ccaf608bc8953d615ec3abed6b4f72. --- .../Common/TypeSystem/IL/ILDisassembler.cs | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs index 511393c080a470..1dfe404b63f265 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs @@ -2,7 +2,6 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Buffers.Binary; using System.Text; using Internal.TypeSystem; @@ -192,15 +191,15 @@ private byte ReadILByte() private ushort ReadILUInt16() { - ushort val = BinaryPrimitives.ReadUInt16LittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(ushort))); - _currentOffset += sizeof(ushort); + ushort val = (ushort)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8)); + _currentOffset += 2; return val; } private uint ReadILUInt32() { - uint val = BinaryPrimitives.ReadUInt32LittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(uint))); - _currentOffset += sizeof(uint); + uint val = (uint)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8) + (_ilBytes[_currentOffset + 2] << 16) + (_ilBytes[_currentOffset + 3] << 24)); + _currentOffset += 4; return val; } @@ -212,23 +211,21 @@ private int ReadILToken() private ulong ReadILUInt64() { - ulong value = BinaryPrimitives.ReadUInt64LittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(ulong))); - _currentOffset += sizeof(ulong); + ulong value = ReadILUInt32(); + value |= (((ulong)ReadILUInt32()) << 32); return value; } - private float ReadILFloat() + private unsafe float ReadILFloat() { - float value = BinaryPrimitives.ReadSingleLittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(float))); - _currentOffset += sizeof(float); - return value; + uint value = ReadILUInt32(); + return *(float*)(&value); } - private double ReadILDouble() + private unsafe double ReadILDouble() { - double value = BinaryPrimitives.ReadDoubleLittleEndian(_ilBytes.AsSpan(_currentOffset, sizeof(double))); - _currentOffset += sizeof(double); - return value; + ulong value = ReadILUInt64(); + return *(double*)(&value); } public static void AppendOffset(StringBuilder sb, int offset) From ca90179babc4c35106dac8122b9ff86e6a8e89a8 Mon Sep 17 00:00:00 2001 From: PaulusParssinen Date: Wed, 24 Jul 2024 18:35:54 +0300 Subject: [PATCH 6/7] Revert "Use BinaryPrimitives in ILImporter" * One day ILVerify drops NS2.0, hopefully. This reverts commit caeb467770ec2af5700b53f4a6fd34ddf5eebebc. --- .../tools/Common/TypeSystem/IL/ILImporter.cs | 42 ++++++++----------- .../tools/Common/TypeSystem/IL/ILReader.cs | 2 +- .../IL/ILImporter.Scanner.cs | 7 ++-- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs index 7c73fcc22ea409..afc10fce167bae 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/ILImporter.cs @@ -1,8 +1,6 @@ // 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 @@ -22,7 +20,7 @@ internal sealed partial class ILImporter private byte ReadILByte() { - if (_currentOffset + 1 > _ilBytes.Length) + if (_currentOffset >= _ilBytes.Length) ReportMethodEndInsideInstruction(); return _ilBytes[_currentOffset++]; @@ -30,20 +28,22 @@ private byte ReadILByte() private ushort ReadILUInt16() { - if (!BinaryPrimitives.TryReadUInt16LittleEndian(_ilBytes.AsSpan(_currentOffset), out ushort value)) + if (_currentOffset + 1 >= _ilBytes.Length) ReportMethodEndInsideInstruction(); - _currentOffset += sizeof(ushort); - return value; + ushort val = (ushort)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8)); + _currentOffset += 2; + return val; } private uint ReadILUInt32() { - if (!BinaryPrimitives.TryReadUInt32LittleEndian(_ilBytes.AsSpan(_currentOffset), out uint value)) + if (_currentOffset + 3 >= _ilBytes.Length) ReportMethodEndInsideInstruction(); - _currentOffset += sizeof(uint); - return value; + uint val = (uint)(_ilBytes[_currentOffset] + (_ilBytes[_currentOffset + 1] << 8) + (_ilBytes[_currentOffset + 2] << 16) + (_ilBytes[_currentOffset + 3] << 24)); + _currentOffset += 4; + return val; } private int ReadILToken() @@ -53,29 +53,21 @@ private int ReadILToken() private ulong ReadILUInt64() { - if (!BinaryPrimitives.TryReadUInt64LittleEndian(_ilBytes.AsSpan(_currentOffset), out ulong value)) - ReportMethodEndInsideInstruction(); - - _currentOffset += sizeof(ulong); + ulong value = ReadILUInt32(); + value |= (((ulong)ReadILUInt32()) << 32); return value; } - private float ReadILFloat() + private unsafe float ReadILFloat() { - if (!BinaryPrimitives.TryReadSingleLittleEndian(_ilBytes.AsSpan(_currentOffset), out float value)) - ReportMethodEndInsideInstruction(); - - _currentOffset += sizeof(float); - return value; + uint value = ReadILUInt32(); + return *(float*)(&value); } - private double ReadILDouble() + private unsafe double ReadILDouble() { - if (!BinaryPrimitives.TryReadDoubleLittleEndian(_ilBytes.AsSpan(_currentOffset), out double value)) - ReportMethodEndInsideInstruction(); - - _currentOffset += sizeof(double); - return value; + ulong value = ReadILUInt64(); + return *(double*)(&value); } private void SkipIL(int bytes) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILReader.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILReader.cs index 5015b91146fea9..8c462a8ac2281b 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/ILReader.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/ILReader.cs @@ -80,7 +80,7 @@ public float ReadILFloat() return value; } - public double ReadILDouble() + public unsafe double ReadILDouble() { if (!BinaryPrimitives.TryReadDoubleLittleEndian(_ilBytes.Slice(_currentOffset), out double value)) ThrowHelper.ThrowInvalidProgramException(); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index 538b80f3d9634f..81c35b2f72cbf8 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -1,8 +1,6 @@ // 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; using Internal.ReadyToRunConstants; @@ -1382,7 +1380,10 @@ private void ImportFallthrough(BasicBlock next, object condition = null) private int ReadILTokenAt(int ilOffset) { - return BinaryPrimitives.ReadInt32LittleEndian(_ilBytes.AsSpan(ilOffset, sizeof(int))); + return (int)(_ilBytes[ilOffset] + + (_ilBytes[ilOffset + 1] << 8) + + (_ilBytes[ilOffset + 2] << 16) + + (_ilBytes[ilOffset + 3] << 24)); } private static void ReportInvalidBranchTarget(int targetOffset) From 8ce25bc1d8dc2e913ed64eaa270cb37fcbb54995 Mon Sep 17 00:00:00 2001 From: PaulusParssinen Date: Wed, 24 Jul 2024 18:53:49 +0300 Subject: [PATCH 7/7] Use BinaryPrimitives in ILDisassembler & ILImporter part 2 --- .../Common/TypeSystem/IL/ILDisassembler.cs | 13 +++++----- .../tools/Common/TypeSystem/IL/ILImporter.cs | 24 ++++++++++--------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs b/src/coreclr/tools/Common/TypeSystem/IL/ILDisassembler.cs index 1dfe404b63f265..cb71913d0232c3 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 afc10fce167bae..74da13d94a398e 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; }