Skip to content
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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)
{
Expand Down Expand Up @@ -144,17 +146,120 @@ internal static void WriteCompressedSignedInteger(BlobBuilder writer, int value)
}
}

/// <summary>
/// Writes a scalar (non-string) constant to a span.
/// </summary>
/// <param name="bytes">The span where the content will be encoded.</param>
/// <param name="value">The constant value.</param>
Comment thread
teo-tsirpanis marked this conversation as resolved.
/// <returns>The number of bytes that was written.</returns>
internal static int WriteScalarConstant(Span<byte> bytes, object? value)
Comment thread
jkotas marked this conversation as resolved.
{
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);
Comment thread
AaronRobinsonMSFT marked this conversation as resolved.
return sizeof(uint);
}
Comment thread
jkotas marked this conversation as resolved.

var type = value.GetType();
Comment thread
jkotas marked this conversation as resolved.
if (type.IsEnum)
{
type = Enum.GetUnderlyingType(type);
}

if (type == typeof(bool))
Comment thread
jkotas marked this conversation as resolved.
{
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);
Comment thread
jkotas marked this conversation as resolved.
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);
}
Expand Down Expand Up @@ -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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<byte> buffer = stackalloc byte[BlobWriterImpl.MaxScalarConstantSize];
int length = BlobWriterImpl.WriteScalarConstant(buffer, value);
return GetOrAddBlob(buffer.Slice(0, length));
}

/// <summary>
Expand Down
Loading