diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/AbstractMemoryBlock.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/AbstractMemoryBlock.cs index c53809dec36cab..cee648185fbfdc 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/AbstractMemoryBlock.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/AbstractMemoryBlock.cs @@ -34,7 +34,7 @@ internal abstract class AbstractMemoryBlock : IDisposable /// public virtual unsafe ImmutableArray GetContentUnchecked(int start, int length) { - var result = BlobUtilities.ReadImmutableBytes(Pointer + start, length); + var result = new ReadOnlySpan(Pointer + start, length).ToImmutableArray(); GC.KeepAlive(this); return result; } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs index 0d91893ac236cb..735ae1b182deeb 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/MemoryBlocks/StreamMemoryBlockProvider.cs @@ -122,7 +122,7 @@ public override Stream GetStream(out StreamConstraints constraints) } /// IO error while mapping memory or not enough memory to create the mapping. - private unsafe bool TryCreateMemoryMappedFileBlock(long start, int size, [NotNullWhen(true)]out MemoryMappedFileBlock? block) + private unsafe bool TryCreateMemoryMappedFileBlock(long start, int size, [NotNullWhen(true)] out MemoryMappedFileBlock? block) { if (_lazyMemoryMap == null) { @@ -142,7 +142,8 @@ private unsafe bool TryCreateMemoryMappedFileBlock(long start, int size, [NotNul access: MemoryMappedFileAccess.Read, inheritability: HandleInheritability.None, leaveOpen: true); - } catch (UnauthorizedAccessException e) + } + catch (UnauthorizedAccessException e) { throw new IOException(e.Message, e); } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/BlobUtilities.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/BlobUtilities.cs index ed3e2b07625b2a..8f3a1321c284c6 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/BlobUtilities.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/BlobUtilities.cs @@ -1,8 +1,7 @@ // 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.Collections.Immutable; +using System.Buffers.Binary; using System.Diagnostics; using System.Reflection.Internal; using System.Runtime.CompilerServices; @@ -12,36 +11,11 @@ namespace System.Reflection { internal static unsafe class BlobUtilities { - public static byte[] ReadBytes(byte* buffer, int byteCount) - { - if (byteCount == 0) - { - return Array.Empty(); - } - - byte[] result = new byte[byteCount]; - Marshal.Copy((IntPtr)buffer, result, 0, byteCount); - return result; - } - - public static ImmutableArray ReadImmutableBytes(byte* buffer, int byteCount) - { - byte[]? bytes = ReadBytes(buffer, byteCount); - return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref bytes); - } - public static void WriteBytes(this byte[] buffer, int start, byte value, int byteCount) { Debug.Assert(buffer.Length > 0); - fixed (byte* bufferPtr = &buffer[0]) - { - byte* startPtr = bufferPtr + start; - for (int i = 0; i < byteCount; i++) - { - startPtr[i] = value; - } - } + new Span(buffer, start, byteCount).Fill(value); } public static void WriteDouble(this byte[] buffer, int start, double value) @@ -60,63 +34,20 @@ public static void WriteByte(this byte[] buffer, int start, byte value) buffer[start] = value; } - public static void WriteUInt16(this byte[] buffer, int start, ushort value) - { - fixed (byte* ptr = &buffer[start]) - { - unchecked - { - ptr[0] = (byte)value; - ptr[1] = (byte)(value >> 8); - } - } - } + public static void WriteUInt16(this byte[] buffer, int start, ushort value) => + Unsafe.WriteUnaligned(ref buffer[start], !BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(value) : value); - public static void WriteUInt16BE(this byte[] buffer, int start, ushort value) - { - fixed (byte* ptr = &buffer[start]) - { - unchecked - { - ptr[0] = (byte)(value >> 8); - ptr[1] = (byte)value; - } - } - } + public static void WriteUInt16BE(this byte[] buffer, int start, ushort value) => + Unsafe.WriteUnaligned(ref buffer[start], BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(value) : value); - public static void WriteUInt32BE(this byte[] buffer, int start, uint value) - { - fixed (byte* ptr = &buffer[start]) - { - unchecked - { - ptr[0] = (byte)(value >> 24); - ptr[1] = (byte)(value >> 16); - ptr[2] = (byte)(value >> 8); - ptr[3] = (byte)value; - } - } - } + public static void WriteUInt32BE(this byte[] buffer, int start, uint value) => + Unsafe.WriteUnaligned(ref buffer[start], BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(value) : value); - public static void WriteUInt32(this byte[] buffer, int start, uint value) - { - fixed (byte* ptr = &buffer[start]) - { - unchecked - { - ptr[0] = (byte)value; - ptr[1] = (byte)(value >> 8); - ptr[2] = (byte)(value >> 16); - ptr[3] = (byte)(value >> 24); - } - } - } + public static void WriteUInt32(this byte[] buffer, int start, uint value) => + Unsafe.WriteUnaligned(ref buffer[start], !BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(value) : value); - public static void WriteUInt64(this byte[] buffer, int start, ulong value) - { - WriteUInt32(buffer, start, unchecked((uint)value)); - WriteUInt32(buffer, start + 4, unchecked((uint)(value >> 32))); - } + public static void WriteUInt64(this byte[] buffer, int start, ulong value) => + Unsafe.WriteUnaligned(ref buffer[start], !BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(value) : value); public const int SizeOfSerializedDecimal = sizeof(byte) + 3 * sizeof(uint); @@ -137,6 +68,11 @@ public static void WriteDecimal(this byte[] buffer, int start, decimal value) public static void WriteGuid(this byte[] buffer, int start, Guid value) { +#if NETCOREAPP + bool written = value.TryWriteBytes(buffer.AsSpan(start)); + // This function is not public, callers have to ensure that enough space is available. + Debug.Assert(written); +#else fixed (byte* dst = &buffer[start]) { byte* src = (byte*)&value; @@ -167,6 +103,7 @@ public static void WriteGuid(this byte[] buffer, int start, Guid value) dst[14] = src[14]; dst[15] = src[15]; } +#endif } public static void WriteUTF8(this byte[] buffer, int start, char* charPtr, int charCount, int byteCount, bool allowUnpairedSurrogates) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ImmutableByteArrayInterop.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ImmutableByteArrayInterop.cs index 7b213d337c2cec..062133428d15d7 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ImmutableByteArrayInterop.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/ImmutableByteArrayInterop.cs @@ -2,7 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Immutable; -using System.Runtime.InteropServices; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace System.Reflection.Internal { @@ -22,16 +23,10 @@ namespace System.Reflection.Internal /// /// This implementation is scoped to byte arrays as that is all that the metadata reader needs. /// - /// Also, since we don't have access to immutable collection internals, we use a trick involving - /// overlapping a with an array reference. While - /// unverifiable, it is valid. See ECMA-335, section II.10.7 Controlling instance layout: + /// Also, since we don't have access to immutable collection internals, we use + /// . /// - /// "It is possible to overlap fields in this way, though offsets occupied by an object reference - /// shall not overlap with offsets occupied by a built-in value type or a part of - /// another object reference. While one object reference can completely overlap another, this is - /// unverifiable." - /// - /// Furthermore, the fact that backed by a single byte array + /// The fact that is backed by a single byte array /// field is something inherent to the design of ImmutableArray in order to get its performance /// characteristics and therefore something we (Microsoft) are comfortable defining as a contract that /// can be depended upon as below. @@ -59,9 +54,7 @@ internal static ImmutableArray DangerousCreateFromUnderlyingArray(ref byte byte[] givenArray = array!; array = null; - ByteArrayUnion union = default; - union.UnderlyingArray = givenArray; - return union.ImmutableArray; + return Unsafe.As>(ref givenArray); } /// @@ -81,19 +74,7 @@ internal static ImmutableArray DangerousCreateFromUnderlyingArray(ref byte /// The underlying array, or null if is true. internal static byte[]? DangerousGetUnderlyingArray(ImmutableArray array) { - ByteArrayUnion union = default; - union.ImmutableArray = array; - return union.UnderlyingArray; - } - - [StructLayout(LayoutKind.Explicit)] - private struct ByteArrayUnion - { - [FieldOffset(0)] - internal byte[]? UnderlyingArray; - - [FieldOffset(0)] - internal ImmutableArray ImmutableArray; + return Unsafe.As, byte[]>(ref array); } } } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/MemoryBlock.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/MemoryBlock.cs index 5931cb2043ab9e..64326d2bce4fa3 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/MemoryBlock.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/MemoryBlock.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; using System.Diagnostics; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; @@ -126,11 +127,8 @@ internal uint PeekUInt32(int offset) { CheckBounds(offset, sizeof(uint)); - unchecked - { - byte* ptr = Pointer + offset; - return (uint)(ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24)); - } + uint result = Unsafe.ReadUnaligned(Pointer + offset); + return BitConverter.IsLittleEndian ? result : BinaryPrimitives.ReverseEndianness(result); } /// @@ -187,11 +185,8 @@ internal ushort PeekUInt16(int offset) { CheckBounds(offset, sizeof(ushort)); - unchecked - { - byte* ptr = Pointer + offset; - return (ushort)(ptr[0] | (ptr[1] << 8)); - } + ushort result = Unsafe.ReadUnaligned(Pointer + offset); + return BitConverter.IsLittleEndian ? result : BinaryPrimitives.ReverseEndianness(result); } // When reference has tag bits. @@ -250,7 +245,7 @@ internal Guid PeekGuid(int offset) byte* ptr = Pointer + offset; if (BitConverter.IsLittleEndian) { - return *(Guid*)ptr; + return Unsafe.ReadUnaligned(ptr); } else { @@ -512,7 +507,7 @@ internal int CompareUtf8NullTerminatedStringWithAsciiString(int offset, string a internal byte[] PeekBytes(int offset, int byteCount) { CheckBounds(offset, byteCount); - return BlobUtilities.ReadBytes(Pointer + offset, byteCount); + return new ReadOnlySpan(Pointer + offset, byteCount).ToArray(); } internal int IndexOf(byte b, int start) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs index 6cde1154c5703c..8debffc0e94761 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobBuilder.cs @@ -7,7 +7,6 @@ using System.Reflection.Internal; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; namespace System.Reflection.Metadata { @@ -345,7 +344,7 @@ public void WriteContentTo(ref BlobWriter destination) foreach (var chunk in GetChunks()) { - destination.WriteBytes(chunk._buffer, 0, chunk.Length); + destination.WriteBytes(chunk._buffer.AsSpan(0, chunk.Length)); } } @@ -360,7 +359,7 @@ public void WriteContentTo(BlobBuilder destination) foreach (var chunk in GetChunks()) { - destination.WriteBytes(chunk._buffer, 0, chunk.Length); + destination.WriteBytes(chunk._buffer.AsSpan(0, chunk.Length)); } } @@ -652,24 +651,24 @@ public unsafe void WriteBytes(byte* buffer, int byteCount) Throw.InvalidOperationBuilderAlreadyLinked(); } - WriteBytesUnchecked(buffer, byteCount); + WriteBytesUnchecked(new ReadOnlySpan(buffer, byteCount)); } - private unsafe void WriteBytesUnchecked(byte* buffer, int byteCount) + private void WriteBytesUnchecked(ReadOnlySpan buffer) { - int bytesToCurrent = Math.Min(FreeBytes, byteCount); + int bytesToCurrent = Math.Min(FreeBytes, buffer.Length); - Marshal.Copy((IntPtr)buffer, _buffer, Length, bytesToCurrent); + buffer.Slice(0, bytesToCurrent).CopyTo(_buffer.AsSpan(Length)); AddLength(bytesToCurrent); - int remaining = byteCount - bytesToCurrent; - if (remaining > 0) + ReadOnlySpan remaining = buffer.Slice(bytesToCurrent); + if (!remaining.IsEmpty) { - Expand(remaining); + Expand(remaining.Length); - Marshal.Copy((IntPtr)(buffer + bytesToCurrent), _buffer, 0, remaining); - AddLength(remaining); + remaining.CopyTo(_buffer); + AddLength(remaining.Length); } } @@ -725,7 +724,12 @@ public int TryWriteBytes(Stream source, int byteCount) /// Builder is not writable, it has been linked with another one. public void WriteBytes(ImmutableArray buffer) { - WriteBytes(buffer, 0, buffer.IsDefault ? 0 : buffer.Length); + if (buffer.IsDefault) + { + Throw.ArgumentNull(nameof(buffer)); + } + + WriteBytes(buffer.AsSpan()); } /// is null. @@ -733,20 +737,32 @@ public void WriteBytes(ImmutableArray buffer) /// Builder is not writable, it has been linked with another one. public void WriteBytes(ImmutableArray buffer, int start, int byteCount) { - WriteBytes(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(buffer)!, start, byteCount); + if (buffer.IsDefault) + { + Throw.ArgumentNull(nameof(buffer)); + } + + BlobUtilities.ValidateRange(buffer.Length, start, byteCount, nameof(byteCount)); + + WriteBytes(buffer.AsSpan(start, byteCount)); } /// is null. /// Builder is not writable, it has been linked with another one. public void WriteBytes(byte[] buffer) { - WriteBytes(buffer, 0, buffer?.Length ?? 0); + if (buffer is null) + { + Throw.ArgumentNull(nameof(buffer)); + } + + WriteBytes(buffer.AsSpan()); } /// is null. /// Range specified by and falls outside of the bounds of the . /// Builder is not writable, it has been linked with another one. - public unsafe void WriteBytes(byte[] buffer, int start, int byteCount) + public void WriteBytes(byte[] buffer, int start, int byteCount) { if (buffer is null) { @@ -755,21 +771,17 @@ public unsafe void WriteBytes(byte[] buffer, int start, int byteCount) BlobUtilities.ValidateRange(buffer.Length, start, byteCount, nameof(byteCount)); + WriteBytes(buffer.AsSpan(start, byteCount)); + } + + private void WriteBytes(ReadOnlySpan buffer) + { if (!IsHead) { Throw.InvalidOperationBuilderAlreadyLinked(); } - // an empty array has no element pointer: - if (buffer.Length == 0) - { - return; - } - - fixed (byte* ptr = &buffer[0]) - { - WriteBytesUnchecked(ptr + start, byteCount); - } + WriteBytesUnchecked(buffer); } /// Builder is not writable, it has been linked with another one. @@ -929,7 +941,7 @@ public void WriteReference(int reference, bool isSmall) /// /// is null. /// Builder is not writable, it has been linked with another one. - public unsafe void WriteUTF16(char[] value) + public void WriteUTF16(char[] value) { if (value is null) { @@ -941,25 +953,7 @@ public unsafe void WriteUTF16(char[] value) Throw.InvalidOperationBuilderAlreadyLinked(); } - if (value.Length == 0) - { - return; - } - - if (BitConverter.IsLittleEndian) - { - fixed (char* ptr = &value[0]) - { - WriteBytesUnchecked((byte*)ptr, value.Length * sizeof(char)); - } - } - else - { - for (int i = 0; i < value.Length; i++) - { - WriteUInt16((ushort)value[i]); - } - } + WriteUTF16(value.AsSpan()); } /// @@ -967,7 +961,7 @@ public unsafe void WriteUTF16(char[] value) /// /// is null. /// Builder is not writable, it has been linked with another one. - public unsafe void WriteUTF16(string value) + public void WriteUTF16(string value) { if (value is null) { @@ -979,18 +973,25 @@ public unsafe void WriteUTF16(string value) Throw.InvalidOperationBuilderAlreadyLinked(); } + WriteUTF16(value.AsSpan()); + } + + private void WriteUTF16(ReadOnlySpan value) + { + if (!IsHead) + { + Throw.InvalidOperationBuilderAlreadyLinked(); + } + if (BitConverter.IsLittleEndian) { - fixed (char* ptr = value) - { - WriteBytesUnchecked((byte*)ptr, value.Length * sizeof(char)); - } + WriteBytesUnchecked(MemoryMarshal.AsBytes(value)); } else { - for (int i = 0; i < value.Length; i++) + foreach (char c in value) { - WriteUInt16((ushort)value[i]); + WriteUInt16(c); } } } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobContentId.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobContentId.cs index 653d9e69e61eca..db433de1e75940 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobContentId.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobContentId.cs @@ -12,27 +12,40 @@ namespace System.Reflection.Metadata { private const int Size = BlobUtilities.SizeOfGuid + sizeof(uint); - public Guid Guid { get; } - public uint Stamp { get; } + private readonly Guid _guid; + private readonly uint _stamp; + + public Guid Guid => _guid; + public uint Stamp => _stamp; public BlobContentId(Guid guid, uint stamp) { - Guid = guid; - Stamp = stamp; + _guid = guid; + _stamp = stamp; } public BlobContentId(ImmutableArray id) - : this(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(id)!) { + if (id.IsDefault) + { + Throw.ArgumentNull(nameof(id)); + } + + Initialize(id.AsSpan(), out _guid, out _stamp); } - public unsafe BlobContentId(byte[] id) + public BlobContentId(byte[] id) { if (id is null) { Throw.ArgumentNull(nameof(id)); } + Initialize(id, out _guid, out _stamp); + } + + private static unsafe void Initialize(ReadOnlySpan id, out Guid guid, out uint stamp) + { if (id.Length != Size) { throw new ArgumentException(SR.Format(SR.UnexpectedArrayLength, Size), nameof(id)); @@ -41,8 +54,8 @@ public unsafe BlobContentId(byte[] id) fixed (byte* ptr = &id[0]) { var reader = new BlobReader(ptr, id.Length); - Guid = reader.ReadGuid(); - Stamp = reader.ReadUInt32(); + guid = reader.ReadGuid(); + stamp = reader.ReadUInt32(); } } @@ -50,7 +63,12 @@ public unsafe BlobContentId(byte[] id) public static BlobContentId FromHash(ImmutableArray hashCode) { - return FromHash(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(hashCode)!); + if (hashCode.IsDefault) + { + Throw.ArgumentNull(nameof(hashCode)); + } + + return FromHash(hashCode.AsSpan()); } public static BlobContentId FromHash(byte[] hashCode) @@ -60,6 +78,11 @@ public static BlobContentId FromHash(byte[] hashCode) Throw.ArgumentNull(nameof(hashCode)); } + return FromHash(hashCode.AsSpan()); + } + + private static BlobContentId FromHash(ReadOnlySpan hashCode) + { const int minHashSize = 20; if (hashCode.Length < minHashSize) @@ -69,8 +92,8 @@ public static BlobContentId FromHash(byte[] hashCode) // extract guid components from input data uint a = ((uint)hashCode[3] << 24 | (uint)hashCode[2] << 16 | (uint)hashCode[1] << 8 | hashCode[0]); - ushort b = (ushort)((ushort)hashCode[5] << 8 | (ushort)hashCode[4]); - ushort c = (ushort)((ushort)hashCode[7] << 8 | (ushort)hashCode[6]); + ushort b = (ushort)(hashCode[5] << 8 | hashCode[4]); + ushort c = (ushort)(hashCode[7] << 8 | hashCode[6]); byte d = hashCode[8]; byte e = hashCode[9]; byte f = hashCode[10]; diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriter.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriter.cs index dc63a0de0a557f..fdd73e33ba289a 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriter.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriter.cs @@ -10,7 +10,7 @@ namespace System.Reflection.Metadata { // TODO: argument checking - public unsafe struct BlobWriter + public struct BlobWriter { // writable slice: private readonly byte[] _buffer; @@ -88,9 +88,7 @@ public byte[] ToArray(int start, int byteCount) { BlobUtilities.ValidateRange(Length, start, byteCount, nameof(byteCount)); - var result = new byte[byteCount]; - Array.Copy(_buffer, _start + start, result, 0, byteCount); - return result; + return _buffer.AsSpan(_start + start, byteCount).ToArray(); } public ImmutableArray ToImmutableArray() @@ -101,8 +99,9 @@ public ImmutableArray ToImmutableArray() /// Range specified by and falls outside of the bounds of the buffer content. public ImmutableArray ToImmutableArray(int start, int byteCount) { - byte[]? array = ToArray(start, byteCount); - return ImmutableByteArrayInterop.DangerousCreateFromUnderlyingArray(ref array); + BlobUtilities.ValidateRange(Length, start, byteCount, nameof(byteCount)); + + return ImmutableArray.Create(_buffer.AsSpan(_start + start, byteCount)); } private int Advance(int value) @@ -128,14 +127,7 @@ public void WriteBytes(byte value, int byteCount) } int start = Advance(byteCount); - fixed (byte* buffer = _buffer) - { - byte* ptr = buffer + start; - for (int i = 0; i < byteCount; i++) - { - ptr[i] = value; - } - } + _buffer.AsSpan(start, byteCount).Fill(value); } /// is null. @@ -152,13 +144,13 @@ public unsafe void WriteBytes(byte* buffer, int byteCount) Throw.ArgumentOutOfRange(nameof(byteCount)); } - WriteBytesUnchecked(buffer, byteCount); + WriteBytes(new ReadOnlySpan(buffer, byteCount)); } - private unsafe void WriteBytesUnchecked(byte* buffer, int byteCount) + internal void WriteBytes(ReadOnlySpan buffer) { - int start = Advance(byteCount); - Marshal.Copy((IntPtr)buffer, _buffer, start, byteCount); + int start = Advance(buffer.Length); + buffer.CopyTo(_buffer.AsSpan(start)); } /// is null. @@ -195,25 +187,42 @@ public int WriteBytes(Stream source, int byteCount) /// is null. public void WriteBytes(ImmutableArray buffer) { - WriteBytes(buffer, 0, buffer.IsDefault ? 0 : buffer.Length); + if (buffer.IsDefault) + { + Throw.ArgumentNull(nameof(buffer)); + } + + WriteBytes(buffer.AsSpan()); } /// is null. /// Range specified by and falls outside of the bounds of the . public void WriteBytes(ImmutableArray buffer, int start, int byteCount) { - WriteBytes(ImmutableByteArrayInterop.DangerousGetUnderlyingArray(buffer)!, start, byteCount); + if (buffer.IsDefault) + { + Throw.ArgumentNull(nameof(buffer)); + } + + BlobUtilities.ValidateRange(buffer.Length, start, byteCount, nameof(byteCount)); + + WriteBytes(buffer.AsSpan(start, byteCount)); } /// is null. - public unsafe void WriteBytes(byte[] buffer) + public void WriteBytes(byte[] buffer) { - WriteBytes(buffer, 0, buffer?.Length ?? 0); + if (buffer is null) + { + Throw.ArgumentNull(nameof(buffer)); + } + + WriteBytes(buffer.AsSpan()); } /// is null. /// Range specified by and falls outside of the bounds of the . - public unsafe void WriteBytes(byte[] buffer, int start, int byteCount) + public void WriteBytes(byte[] buffer, int start, int byteCount) { if (buffer is null) { @@ -222,16 +231,7 @@ public unsafe void WriteBytes(byte[] buffer, int start, int byteCount) BlobUtilities.ValidateRange(buffer.Length, start, byteCount, nameof(byteCount)); - // an empty array has no element pointer: - if (buffer.Length == 0) - { - return; - } - - fixed (byte* ptr = &buffer[0]) - { - WriteBytes(ptr + start, byteCount); - } + WriteBytes(buffer.AsSpan(start, byteCount)); } public void PadTo(int offset) @@ -376,25 +376,7 @@ public void WriteUTF16(char[] value) Throw.ArgumentNull(nameof(value)); } - if (value.Length == 0) - { - return; - } - - if (BitConverter.IsLittleEndian) - { - fixed (char* ptr = &value[0]) - { - WriteBytesUnchecked((byte*)ptr, value.Length * sizeof(char)); - } - } - else - { - for (int i = 0; i < value.Length; i++) - { - WriteUInt16((ushort)value[i]); - } - } + WriteUTF16(value.AsSpan()); } /// @@ -408,18 +390,20 @@ public void WriteUTF16(string value) Throw.ArgumentNull(nameof(value)); } + WriteUTF16(value.AsSpan()); + } + + private void WriteUTF16(ReadOnlySpan value) + { if (BitConverter.IsLittleEndian) { - fixed (char* ptr = value) - { - WriteBytesUnchecked((byte*)ptr, value.Length * sizeof(char)); - } + WriteBytes(MemoryMarshal.AsBytes(value)); } else { - for (int i = 0; i < value.Length; i++) + foreach (char c in value) { - WriteUInt16((ushort)value[i]); + WriteUInt16(c); } } } @@ -480,7 +464,7 @@ public void WriteUTF8(string value, bool allowUnpairedSurrogates) WriteUTF8(value, 0, value.Length, allowUnpairedSurrogates, prependSize: false); } - private void WriteUTF8(string str, int start, int length, bool allowUnpairedSurrogates, bool prependSize) + private unsafe void WriteUTF8(string str, int start, int length, bool allowUnpairedSurrogates, bool prependSize) { fixed (char* strPtr = str) { diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs index 49406b39dec156..a11a8fcacda4e5 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.netstandard.cs @@ -97,7 +97,7 @@ public static unsafe AssemblyName GetAssemblyName(string assemblyFile) } catch (InvalidOperationException ex) { - throw new BadImageFormatException(ex.Message); + throw new BadImageFormatException(ex.Message, assemblyFile, ex); } } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.EmbeddedPortablePdb.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.EmbeddedPortablePdb.cs index 0c9d4450e2c52e..763f2b72a5dcb4 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.EmbeddedPortablePdb.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.EmbeddedPortablePdb.cs @@ -83,9 +83,9 @@ internal static unsafe NativeHeapMemoryBlock DecodeEmbeddedPortablePdbDebugDirec { decompressed = new NativeHeapMemoryBlock(decompressedSize); } - catch + catch (Exception e) { - throw new BadImageFormatException(SR.DataTooBig); + throw new BadImageFormatException(SR.DataTooBig, e); } bool success = false; @@ -110,7 +110,7 @@ internal static unsafe NativeHeapMemoryBlock DecodeEmbeddedPortablePdbDebugDirec } catch (Exception e) { - throw new BadImageFormatException(e.Message, e.InnerException); + throw new BadImageFormatException(e.Message, e); } if (actualLength != decompressed.Size) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs index eda470b5bd7137..43be6cc595f771 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEReader.cs @@ -718,7 +718,7 @@ public bool TryOpenAssociatedPortablePdb(string peImagePath, Func(buffer, (int)(p + 1 - buffer)).ToArray(); } [Fact]