diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs index 972def9f6955cb..fc27827c788b6b 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/BlobWriterImpl.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; namespace System.Reflection.Metadata @@ -12,6 +13,7 @@ internal static class BlobWriterImpl internal const int MaxCompressedIntegerValue = 0x1fffffff; internal const int MinSignedCompressedIntegerValue = unchecked((int)0xF0000000); internal const int MaxSignedCompressedIntegerValue = 0x0FFFFFFF; + internal const int MaxScalarConstantSize = sizeof(ulong); internal static int GetCompressedIntegerSize(int value) { @@ -144,17 +146,120 @@ internal static void WriteCompressedSignedInteger(BlobBuilder writer, int value) } } + /// + /// Writes a scalar (non-string) constant to a span. + /// + /// The span where the content will be encoded. + /// The constant value. + /// The number of bytes that was written. + internal static int WriteScalarConstant(Span bytes, object? value) + { + if (value == null) + { + // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 4-byte zero. + BinaryPrimitives.WriteUInt32LittleEndian(bytes, 0); + return sizeof(uint); + } + + var type = value.GetType(); + if (type.IsEnum) + { + type = Enum.GetUnderlyingType(type); + } + + if (type == typeof(bool)) + { + bytes[0] = (byte)((bool)value ? 1 : 0); + return sizeof(bool); + } + else if (type == typeof(int)) + { + BinaryPrimitives.WriteInt32LittleEndian(bytes, (int)value); + return sizeof(int); + } + else if (type == typeof(byte)) + { + bytes[0] = (byte)value; + return sizeof(byte); + } + else if (type == typeof(char)) + { + BinaryPrimitives.WriteUInt16LittleEndian(bytes, (char)value); + return sizeof(char); + } + else if (type == typeof(double)) + { +#if NET + BinaryPrimitives.WriteDoubleLittleEndian(bytes, (double)value); +#else + double v = (double)value; + unsafe + { + BinaryPrimitives.WriteUInt64LittleEndian(bytes, *(ulong*)(&v)); + } +#endif + return sizeof(double); + } + else if (type == typeof(short)) + { + BinaryPrimitives.WriteInt16LittleEndian(bytes, (short)value); + return sizeof(short); + } + else if (type == typeof(long)) + { + BinaryPrimitives.WriteInt64LittleEndian(bytes, (long)value); + return sizeof(long); + } + else if (type == typeof(sbyte)) + { + bytes[0] = (byte)(sbyte)value; + return sizeof(sbyte); + } + else if (type == typeof(float)) + { +#if NET + BinaryPrimitives.WriteSingleLittleEndian(bytes, (float)value); +#else + float v = (float)value; + unsafe + { + BinaryPrimitives.WriteUInt32LittleEndian(bytes, *(uint*)(&v)); + } +#endif + return sizeof(float); + } + else if (type == typeof(ushort)) + { + BinaryPrimitives.WriteUInt16LittleEndian(bytes, (ushort)value); + return sizeof(ushort); + } + else if (type == typeof(uint)) + { + BinaryPrimitives.WriteUInt32LittleEndian(bytes, (uint)value); + return sizeof(uint); + } + else if (type == typeof(ulong)) + { + BinaryPrimitives.WriteUInt64LittleEndian(bytes, (ulong)value); + return sizeof(ulong); + } + else + { + throw new ArgumentException(SR.Format(SR.InvalidConstantValueOfType, type)); + } + } + internal static void WriteConstant(ref BlobWriter writer, object? value) { if (value == null) { - // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 32-bit. + // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 4-byte zero. writer.WriteUInt32(0); return; } var type = value.GetType(); - if (type.GetTypeInfo().IsEnum) + if (type.IsEnum) { type = Enum.GetUnderlyingType(type); } @@ -221,13 +326,13 @@ internal static void WriteConstant(BlobBuilder writer, object? value) { if (value == null) { - // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 32-bit. + // The encoding of Type for the nullref value for FieldInit is ELEMENT_TYPE_CLASS with a Value of a 4-byte zero. writer.WriteUInt32(0); return; } var type = value.GetType(); - if (type.GetTypeInfo().IsEnum) + if (type.IsEnum) { type = Enum.GetUnderlyingType(type); } 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 16a2007781507e..ec99c415fe8d3c 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 @@ -256,11 +256,9 @@ public BlobHandle GetOrAddConstantBlob(object? value) return GetOrAddBlobUTF16(str); } - var builder = PooledBlobBuilder.GetInstance(); - builder.WriteConstant(value); - var result = GetOrAddBlob(builder); - builder.Free(); - return result; + Span buffer = stackalloc byte[BlobWriterImpl.MaxScalarConstantSize]; + int length = BlobWriterImpl.WriteScalarConstant(buffer, value); + return GetOrAddBlob(buffer.Slice(0, length)); } ///