diff --git a/src/libraries/Common/src/Polyfills/StreamSpanPolyfills.cs b/src/libraries/Common/src/Polyfills/StreamSpanPolyfills.cs new file mode 100644 index 00000000000000..b8a61e311c2222 --- /dev/null +++ b/src/libraries/Common/src/Polyfills/StreamSpanPolyfills.cs @@ -0,0 +1,38 @@ +// 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; + +namespace System.IO; + +/// Provides downlevel polyfills for Span-based instance methods on . +internal static class StreamSpanPolyfills +{ + extension(Stream stream) + { + public int ReadAtLeast(Span destination, int minimumBytes, bool throwOnEndOfStream = true) + { + byte[] buffer = ArrayPool.Shared.Rent(Math.Min(destination.Length, 81920)); + int totalWritten = 0; + while (totalWritten < minimumBytes && !destination.IsEmpty) + { + int written = stream.Read(buffer, 0, Math.Min(buffer.Length, destination.Length)); + if (written == 0) + { + if (throwOnEndOfStream) + { + ThrowEndOfStreamException(); + } + break; + } + buffer.AsSpan(0, written).CopyTo(destination); + totalWritten += written; + destination = destination.Slice(written); + } + ArrayPool.Shared.Return(buffer); + return totalWritten; + + static void ThrowEndOfStreamException() => throw new EndOfStreamException(); + } + } +} diff --git a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj index 02c844b70e43e9..c7b84cfc9ee3e3 100644 --- a/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj +++ b/src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetCoreAppPrevious);$(NetCoreAppMinimum);netstandard2.0;$(NetFrameworkMinimum) @@ -27,6 +27,9 @@ The System.Reflection.Metadata library is built-in as part of the shared framewo + @@ -111,8 +114,7 @@ The System.Reflection.Metadata library is built-in as part of the shared framewo - - + 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 f705ac97d924b9..be4c38b380e5b0 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 @@ -99,10 +99,10 @@ public static unsafe void WriteUTF8(this byte[] buffer, int start, char* charPtr continue; } - if (IsSurrogateChar(c)) + if (char.IsSurrogate(c)) { // surrogate pair - if (IsHighSurrogateChar(c) && charPtr < strEnd && IsLowSurrogateChar(*charPtr)) + if (char.IsHighSurrogate(c) && charPtr < strEnd && char.IsLowSurrogate(*charPtr)) { int highSurrogate = c; int lowSurrogate = *charPtr++; @@ -134,14 +134,6 @@ public static unsafe void WriteUTF8(this byte[] buffer, int start, char* charPtr } } - internal static unsafe int GetUTF8ByteCount(string str) - { - fixed (char* ptr = str) - { - return GetUTF8ByteCount(ptr, str.Length); - } - } - internal static unsafe int GetUTF8ByteCount(char* str, int charCount) { return GetUTF8ByteCount(str, charCount, int.MaxValue, out _); @@ -165,7 +157,7 @@ internal static unsafe int GetUTF8ByteCount(char* str, int charCount, int byteLi { characterSize = 2; } - else if (IsHighSurrogateChar(c) && ptr < end && IsLowSurrogateChar(*ptr)) + else if (char.IsHighSurrogate(c) && ptr < end && char.IsLowSurrogate(*ptr)) { // surrogate pair: characterSize = 4; @@ -189,21 +181,6 @@ internal static unsafe int GetUTF8ByteCount(char* str, int charCount, int byteLi return byteCount; } - internal static bool IsSurrogateChar(int c) - { - return unchecked((uint)(c - 0xD800)) <= 0xDFFF - 0xD800; - } - - internal static bool IsHighSurrogateChar(int c) - { - return unchecked((uint)(c - 0xD800)) <= 0xDBFF - 0xD800; - } - - internal static bool IsLowSurrogateChar(int c) - { - return unchecked((uint)(c - 0xDC00)) <= 0xDFFF - 0xDC00; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ValidateRange(int bufferLength, int start, int byteCount, string byteCountParameterName) { diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/EncodingHelper.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/EncodingHelper.cs index 5c74d8573696f0..94dbbd5bd9ae09 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/EncodingHelper.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/EncodingHelper.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; using System.Diagnostics; using System.Reflection.Metadata; using System.Runtime.InteropServices; @@ -13,15 +14,7 @@ namespace System.Reflection.Internal /// internal static unsafe class EncodingHelper { - // Size of pooled buffers. The vast majority of metadata strings - // are quite small so we don't need to waste memory with large buffers. - public const int PooledBufferSize = 200; - - // Use AcquireBuffer(int) and ReleaseBuffer(byte[]) - // instead of the pool directly to implement the size check. - private static readonly ObjectPool s_pool = new ObjectPool(() => new byte[PooledBufferSize]); - - public static string DecodeUtf8(byte* bytes, int byteCount, byte[] prefix, MetadataStringDecoder utf8Decoder) + public static string DecodeUtf8(byte* bytes, int byteCount, byte[]? prefix, MetadataStringDecoder utf8Decoder) { Debug.Assert(utf8Decoder != null); @@ -49,7 +42,7 @@ private static string DecodeUtf8Prefixed(byte* bytes, int byteCount, byte[] pref return string.Empty; } - byte[] buffer = AcquireBuffer(prefixedByteCount); + byte[] buffer = ArrayPool.Shared.Rent(prefixedByteCount); prefix.CopyTo(buffer, 0); Marshal.Copy((IntPtr)bytes, buffer, prefix.Length, byteCount); @@ -60,26 +53,8 @@ private static string DecodeUtf8Prefixed(byte* bytes, int byteCount, byte[] pref result = utf8Decoder.GetString(prefixedBytes, prefixedByteCount); } - ReleaseBuffer(buffer); + ArrayPool.Shared.Return(buffer); return result; } - - private static byte[] AcquireBuffer(int byteCount) - { - if (byteCount > PooledBufferSize) - { - return new byte[byteCount]; - } - - return s_pool.Allocate(); - } - - private static void ReleaseBuffer(byte[] buffer) - { - if (buffer.Length == PooledBufferSize) - { - s_pool.Free(buffer); - } - } } } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/EncodingHelper.netcoreapp.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/EncodingHelper.netcoreapp.cs deleted file mode 100644 index 94dbbd5bd9ae09..00000000000000 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/EncodingHelper.netcoreapp.cs +++ /dev/null @@ -1,60 +0,0 @@ -// 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; -using System.Diagnostics; -using System.Reflection.Metadata; -using System.Runtime.InteropServices; - -namespace System.Reflection.Internal -{ - /// - /// Provides helpers to decode strings from unmanaged memory to System.String while avoiding - /// intermediate allocation. - /// - internal static unsafe class EncodingHelper - { - public static string DecodeUtf8(byte* bytes, int byteCount, byte[]? prefix, MetadataStringDecoder utf8Decoder) - { - Debug.Assert(utf8Decoder != null); - - if (prefix != null) - { - return DecodeUtf8Prefixed(bytes, byteCount, prefix, utf8Decoder); - } - - if (byteCount == 0) - { - return string.Empty; - } - - return utf8Decoder.GetString(bytes, byteCount); - } - - private static string DecodeUtf8Prefixed(byte* bytes, int byteCount, byte[] prefix, MetadataStringDecoder utf8Decoder) - { - Debug.Assert(utf8Decoder != null); - - int prefixedByteCount = byteCount + prefix.Length; - - if (prefixedByteCount == 0) - { - return string.Empty; - } - - byte[] buffer = ArrayPool.Shared.Rent(prefixedByteCount); - - prefix.CopyTo(buffer, 0); - Marshal.Copy((IntPtr)bytes, buffer, prefix.Length, byteCount); - - string result; - fixed (byte* prefixedBytes = &buffer[0]) - { - result = utf8Decoder.GetString(prefixedBytes, prefixedByteCount); - } - - ArrayPool.Shared.Return(buffer); - return result; - } - } -} diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/Hash.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/Hash.cs index d083ff1307c3c3..26f51152cb28fc 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/Hash.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/Hash.cs @@ -17,11 +17,6 @@ internal static int Combine(uint newKey, int currentKey) return unchecked((currentKey * (int)0xA5555529) + (int)newKey); } - internal static int Combine(bool newKeyPart, int currentKey) - { - return Combine(currentKey, newKeyPart ? 1 : 0); - } - /// /// The offset bias value used in the FNV-1a algorithm /// See http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/StreamExtensions.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/StreamExtensions.cs index b8495aa9fcc079..336278d0700189 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/StreamExtensions.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Internal/Utilities/StreamExtensions.cs @@ -46,29 +46,6 @@ internal static int TryReadAll(this Stream stream, byte[] buffer, int offset, in return totalBytesRead; } -#if NET - internal static int TryReadAll(this Stream stream, Span buffer) -#if NET - => stream.ReadAtLeast(buffer, buffer.Length, throwOnEndOfStream: false); -#else - { - int totalBytesRead = 0; - while (totalBytesRead < buffer.Length) - { - int bytesRead = stream.Read(buffer.Slice(totalBytesRead)); - if (bytesRead == 0) - { - break; - } - - totalBytesRead += bytesRead; - } - - return totalBytesRead; - } -#endif -#endif - /// /// Resolve image size as either the given user-specified size or distance from current position to end-of-stream. /// Also performs the relevant argument validation and publicly visible caller has same argument names. 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 4be040305ad989..b143adf20a9604 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 @@ -6,6 +6,7 @@ using System.IO; using System.Reflection.Internal; using System.Runtime.InteropServices; +using System.Text; namespace System.Reflection.Metadata { @@ -469,7 +470,7 @@ private unsafe void WriteUTF8(string str, int start, int length, bool allowUnpai fixed (char* strPtr = str) { char* charPtr = strPtr + start; - int byteCount = BlobUtilities.GetUTF8ByteCount(charPtr, length); + int byteCount = Encoding.UTF8.GetByteCount(charPtr, length); if (prependSize) { diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs index ec99c415fe8d3c..5bded8d832a13b 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Heaps.cs @@ -5,6 +5,7 @@ using System.Collections.Immutable; using System.Reflection.Internal; using System.Runtime.InteropServices; +using System.Text; namespace System.Reflection.Metadata.Ecma335 { @@ -553,10 +554,10 @@ private static ImmutableArray SerializeStringHeap( int position = stringHeapStartOffset + heapBuilder.Count; // It is important to use ordinal comparison otherwise we'll use the current culture! - if (prev.EndsWith(entry.Key, StringComparison.Ordinal) && !BlobUtilities.IsLowSurrogateChar(entry.Key[0])) + if (prev.EndsWith(entry.Key, StringComparison.Ordinal) && !char.IsLowSurrogate(entry.Key[0])) { // Map over the tail of prev string. Watch for null-terminator of prev string. - stringVirtualIndexToHeapOffsetMap[entry.Value.GetWriterVirtualIndex()] = position - (BlobUtilities.GetUTF8ByteCount(entry.Key) + 1); + stringVirtualIndexToHeapOffsetMap[entry.Value.GetWriterVirtualIndex()] = position - (Encoding.UTF8.GetByteCount(entry.Key) + 1); } else { diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.cs index c0c576cf806021..c7bfdd82c5638c 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.cs @@ -57,10 +57,7 @@ internal static void SerializeMetadataHeader(BlobBuilder builder, string metadat builder.WriteByte(0); int metadataVersionEnd = builder.Count; - for (int i = 0; i < sizes.MetadataVersionPaddedLength - (metadataVersionEnd - metadataVersionStart); i++) - { - builder.WriteByte(0); - } + builder.WriteBytes(0, sizes.MetadataVersionPaddedLength - (metadataVersionEnd - metadataVersionStart)); // reserved builder.WriteUInt16(0); @@ -74,45 +71,39 @@ internal static void SerializeMetadataHeader(BlobBuilder builder, string metadat // emit the #Pdb stream first so that only a single page has to be read in order to find out PDB ID if (sizes.IsStandaloneDebugMetadata) { - SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.StandalonePdbStreamSize, "#Pdb", builder); + SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.StandalonePdbStreamSize, "#Pdb"u8, builder); } // Spec: Some compilers store metadata in a #- stream, which holds an uncompressed, or non-optimized, representation of metadata tables; // this includes extra metadata -Ptr tables. Such PE files do not form part of ECMA-335 standard. // // Note: EnC delta is stored as uncompressed metadata stream. - SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.MetadataTableStreamSize, (sizes.IsCompressed ? "#~" : "#-"), builder); + SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.MetadataTableStreamSize, (sizes.IsCompressed ? "#~"u8 : "#-"u8), builder); - SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings", builder); - SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US", builder); - SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID", builder); - SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob", builder); + SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.String), "#Strings"u8, builder); + SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.UserString), "#US"u8, builder); + SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Guid), "#GUID"u8, builder); + SerializeStreamHeader(ref offsetFromStartOfMetadata, sizes.GetAlignedHeapSize(HeapIndex.Blob), "#Blob"u8, builder); if (sizes.IsEncDelta) { - SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD", builder); + SerializeStreamHeader(ref offsetFromStartOfMetadata, 0, "#JTD"u8, builder); } int endOffset = builder.Count; Debug.Assert(endOffset - startOffset == sizes.MetadataHeaderSize); } - private static void SerializeStreamHeader(ref int offsetFromStartOfMetadata, int alignedStreamSize, string streamName, BlobBuilder builder) + private static void SerializeStreamHeader(ref int offsetFromStartOfMetadata, int alignedStreamSize, ReadOnlySpan streamName, BlobBuilder builder) { // 4 for the first uint (offset), 4 for the second uint (padded size), length of stream name + 1 for null terminator (then padded) int sizeOfStreamHeader = MetadataSizes.GetMetadataStreamHeaderSize(streamName); builder.WriteInt32(offsetFromStartOfMetadata); builder.WriteInt32(alignedStreamSize); - foreach (char ch in streamName) - { - builder.WriteByte((byte)ch); - } + builder.WriteBytes(streamName); // After offset, size, and stream name, write 0-bytes until we reach our padded size. - for (uint i = 8 + (uint)streamName.Length; i < sizeOfStreamHeader; i++) - { - builder.WriteByte(0); - } + builder.WriteBytes(0, sizeOfStreamHeader - (8 + streamName.Length)); offsetFromStartOfMetadata += alignedStreamSize; } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataRootBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataRootBuilder.cs index 2945d14acbfb52..241d4132c69269 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataRootBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataRootBuilder.cs @@ -3,6 +3,7 @@ using System.Collections.Immutable; using System.Diagnostics; +using System.Text; namespace System.Reflection.Metadata.Ecma335 { @@ -58,8 +59,8 @@ public MetadataRootBuilder(MetadataBuilder tablesAndHeaps, string? metadataVersi Throw.ArgumentNull(nameof(tablesAndHeaps)); } - Debug.Assert(BlobUtilities.GetUTF8ByteCount(DefaultMetadataVersionString) == DefaultMetadataVersionString.Length); - int metadataVersionByteCount = metadataVersion != null ? BlobUtilities.GetUTF8ByteCount(metadataVersion) : DefaultMetadataVersionString.Length; + Debug.Assert(Encoding.UTF8.GetByteCount(DefaultMetadataVersionString) == DefaultMetadataVersionString.Length); + int metadataVersionByteCount = metadataVersion != null ? Encoding.UTF8.GetByteCount(metadataVersion) : DefaultMetadataVersionString.Length; if (metadataVersionByteCount > MetadataSizes.MaxMetadataVersionByteCount) { diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataSizes.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataSizes.cs index 7e8ffaafe47143..5a7d6ce08f3aa6 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataSizes.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataSizes.cs @@ -361,14 +361,14 @@ internal int MetadataHeaderSize const int StandalonePdbStreamHeaderSize = 16; Debug.Assert(RegularStreamHeaderSizes == - GetMetadataStreamHeaderSize("#~") + - GetMetadataStreamHeaderSize("#Strings") + - GetMetadataStreamHeaderSize("#US") + - GetMetadataStreamHeaderSize("#GUID") + - GetMetadataStreamHeaderSize("#Blob")); + GetMetadataStreamHeaderSize("#~"u8) + + GetMetadataStreamHeaderSize("#Strings"u8) + + GetMetadataStreamHeaderSize("#US"u8) + + GetMetadataStreamHeaderSize("#GUID"u8) + + GetMetadataStreamHeaderSize("#Blob"u8)); - Debug.Assert(EncDeltaMarkerStreamHeaderSize == GetMetadataStreamHeaderSize("#JTD")); - Debug.Assert(StandalonePdbStreamHeaderSize == GetMetadataStreamHeaderSize("#Pdb")); + Debug.Assert(EncDeltaMarkerStreamHeaderSize == GetMetadataStreamHeaderSize("#JTD"u8)); + Debug.Assert(StandalonePdbStreamHeaderSize == GetMetadataStreamHeaderSize("#Pdb"u8)); return sizeof(uint) + // signature @@ -385,7 +385,7 @@ internal int MetadataHeaderSize } } - internal static int GetMetadataStreamHeaderSize(string streamName) + internal static int GetMetadataStreamHeaderSize(ReadOnlySpan streamName) { return sizeof(int) + // offset diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/PortablePdbBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/PortablePdbBuilder.cs index dfd862daee2340..28a138c247b286 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/PortablePdbBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/PortablePdbBuilder.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; +using System.Text; namespace System.Reflection.Metadata.Ecma335 { @@ -60,7 +61,7 @@ public PortablePdbBuilder( _builder = tablesAndHeaps; _entryPoint = entryPoint; - Debug.Assert(BlobUtilities.GetUTF8ByteCount(MetadataVersion) == MetadataVersion.Length); + Debug.Assert(Encoding.UTF8.GetByteCount(MetadataVersion) == MetadataVersion.Length); _serializedMetadata = tablesAndHeaps.GetSerializedMetadata(typeSystemRowCounts, MetadataVersion.Length, isStandaloneDebugMetadata: true); IdProvider = idProvider ?? BlobContentId.GetTimeBasedProvider(); diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs index 6085b95d0f4b90..0d9c72f377cc92 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/IL/MethodBodyBlock.cs @@ -191,8 +191,8 @@ public static MethodBodyBlock Create(BlobReader reader) private static ImmutableArray ReadSmallExceptionHandlers(ref BlobReader memReader, int count) { - var result = new ExceptionRegion[count]; - for (int i = 0; i < result.Length; i++) + var result = ImmutableArray.CreateBuilder(count); + for (int i = 0; i < count; i++) { var kind = (ExceptionRegionKind)memReader.ReadUInt16(); var tryOffset = memReader.ReadUInt16(); @@ -200,27 +200,27 @@ private static ImmutableArray ReadSmallExceptionHandlers(ref Bl var handlerOffset = memReader.ReadUInt16(); var handlerLength = memReader.ReadByte(); var classTokenOrFilterOffset = memReader.ReadInt32(); - result[i] = new ExceptionRegion(kind, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset); + result.Add(new ExceptionRegion(kind, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset)); } - return ImmutableArray.Create(result); + return result.MoveToImmutable(); } private static ImmutableArray ReadFatExceptionHandlers(ref BlobReader memReader, int count) { - var result = new ExceptionRegion[count]; - for (int i = 0; i < result.Length; i++) + var result = ImmutableArray.CreateBuilder(count); + for (int i = 0; i < count; i++) { - var sehFlags = (ExceptionRegionKind)memReader.ReadUInt32(); + var kind = (ExceptionRegionKind)memReader.ReadUInt32(); int tryOffset = memReader.ReadInt32(); int tryLength = memReader.ReadInt32(); int handlerOffset = memReader.ReadInt32(); int handlerLength = memReader.ReadInt32(); int classTokenOrFilterOffset = memReader.ReadInt32(); - result[i] = new ExceptionRegion(sehFlags, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset); + result.Add(new ExceptionRegion(kind, tryOffset, tryLength, handlerOffset, handlerLength, classTokenOrFilterOffset)); } - return ImmutableArray.Create(result); + return result.MoveToImmutable(); } } } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs index 00bac867344a61..19c342445a03c0 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Internal/BlobHeap.cs @@ -85,12 +85,11 @@ internal BlobHeap(MemoryBlock block, MetadataKind metadataKind) } } - internal byte[] GetBytes(BlobHandle handle) + internal byte[] GetBytes(BlobHandle handle, bool unique = true) { if (handle.IsVirtual) { - // consider: if we returned an ImmutableArray we wouldn't need to copy - return GetVirtualBlobBytes(handle, unique: true); + return GetVirtualBlobBytes(handle, unique); } int offset = handle.GetHeapOffset(); diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs index fc0bfd054042e8..f170f67573d5cb 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/MetadataReader.cs @@ -1080,8 +1080,7 @@ public byte[] GetBlobBytes(BlobHandle handle) public ImmutableArray GetBlobContent(BlobHandle handle) { - // TODO: We can skip a copy for virtual blobs. - byte[]? bytes = GetBlobBytes(handle); + byte[]? bytes = BlobHeap.GetBytes(handle, unique: false); return ImmutableCollectionsMarshal.AsImmutableArray(bytes); } diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs index 7ed8d1381c2737..c7201870d4741d 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/ManagedTextSection.cs @@ -275,11 +275,9 @@ public void Serialize( } // strong name signature: - strongNameSignature = builder.ReserveBytes(StrongNameSignatureSize); - // The bytes are required to be 0 for the purpose of calculating hash of the PE content - // when strong name signing. - new BlobWriter(strongNameSignature).WriteBytes(0, StrongNameSignatureSize); + // when strong name signing. This is already handled by ReserveBytes. + strongNameSignature = builder.ReserveBytes(StrongNameSignatureSize); // debug directory and data: if (debugDataBuilderOpt != null) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEBuilder.cs index 22fec2c1d4d12f..8389ff7359c1b0 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEBuilder.cs @@ -150,23 +150,16 @@ private ImmutableArray SerializeSections() return result.MoveToImmutable(); } - private static unsafe void WritePESignature(BlobBuilder builder) + private static void WritePESignature(BlobBuilder builder) { // MS-DOS stub (128 bytes) - ReadOnlySpan header = DosHeader; - Debug.Assert(DosHeader.Length == DosHeaderSize); - fixed (byte* ptr = header) - { - builder.WriteBytes(ptr, header.Length); - } + builder.WriteBytes(DosHeader); // PE Signature "PE\0\0" builder.WriteUInt32(PEHeaders.PESignature); } - internal const int DosHeaderSize = 0x80; - - private static ReadOnlySpan DosHeader => // DosHeaderSize + internal static ReadOnlySpan DosHeader => [ 0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEHeaderBuilder.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEHeaderBuilder.cs index adf2334da9c5bc..9b6764fcb6d007 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEHeaderBuilder.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEHeaderBuilder.cs @@ -108,7 +108,7 @@ public static PEHeaderBuilder CreateLibraryHeader() internal bool Is32Bit => Machine != Machine.Amd64 && Machine != Machine.IA64 && Machine != Machine.Arm64 && Machine != Machine.LoongArch64 && Machine != Machine.RiscV64; internal int ComputeSizeOfPEHeaders(int sectionCount) => - PEBuilder.DosHeaderSize + + PEBuilder.DosHeader.Length + PEHeaders.PESignatureSize + CoffHeader.Size + PEHeader.Size(Is32Bit) + 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 cf8aeb00bcc0da..5fc2814f1c199a 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 @@ -99,13 +99,7 @@ internal static unsafe NativeHeapMemoryBlock DecodeEmbeddedPortablePdbDebugDirec try { -#if NET - actualLength = deflate.TryReadAll(new Span(decompressed.Pointer, decompressed.Size)); -#else - using var decompressedStream = new UnmanagedMemoryStream(decompressed.Pointer, decompressed.Size, decompressed.Size, FileAccess.Write); - deflate.CopyTo(decompressedStream); - actualLength = (int)decompressedStream.Position; -#endif + actualLength = deflate.ReadAtLeast(new Span(decompressed.Pointer, decompressed.Size), decompressed.Size, throwOnEndOfStream: false); } catch (Exception e) { diff --git a/src/libraries/System.Reflection.Metadata/tests/Utilities/HashTests.cs b/src/libraries/System.Reflection.Metadata/tests/Utilities/HashTests.cs index b1cc1c0108f29a..08ad13dc15e770 100644 --- a/src/libraries/System.Reflection.Metadata/tests/Utilities/HashTests.cs +++ b/src/libraries/System.Reflection.Metadata/tests/Utilities/HashTests.cs @@ -32,11 +32,5 @@ public void CombineUIntInt() { Assert.Equal(536869063, Hash.Combine((uint)13, 42)); } - - [Fact] - public void CombineBoolInt() - { - Assert.Equal(-1521134253, Hash.Combine(true, 42)); - } } }