Skip to content

Commit

Permalink
Support encoding TypedReferences in signatures. (#85360)
Browse files Browse the repository at this point in the history
* Add `SignatureTypeEncoder.TypedReference`.

* Stop failing when encoding a `PrimitiveTypeCode.TypedReference`.
Since we have a dedicated method for typed references, there is no reason to prohibit it.

* Update the documentation of `SignatureTypeEncoder`.

Co-authored-by: Buyaa Namnan <[email protected]>
  • Loading branch information
teo-tsirpanis and buyaa-n authored May 1, 2023
1 parent 05618c7 commit 7a87fc1
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3064,6 +3064,7 @@ public void Single() { }
public void String() { }
public System.Reflection.Metadata.Ecma335.SignatureTypeEncoder SZArray() { throw null; }
public void Type(System.Reflection.Metadata.EntityHandle type, bool isValueType) { }
public void TypedReference() { }
public void UInt16() { }
public void UInt32() { }
public void UInt64() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -885,10 +885,20 @@ public void Enum(string enumTypeName)
}
}

/// <summary>
/// Encodes a type in a signature.
/// </summary>
public readonly struct SignatureTypeEncoder
{
/// <summary>
/// The <see cref="BlobBuilder"/> where the signature is written to.
/// </summary>
public BlobBuilder Builder { get; }

/// <summary>
/// Creates a <see cref="SignatureTypeEncoder"/>.
/// </summary>
/// <param name="builder">The <see cref="BlobBuilder"/> where the signature will be written.</param>
public SignatureTypeEncoder(BlobBuilder builder)
{
Builder = builder;
Expand All @@ -904,27 +914,79 @@ private void ClassOrValue(bool isValueType)
Builder.WriteByte(isValueType ? (byte)SignatureTypeKind.ValueType : (byte)SignatureTypeKind.Class);
}

/// <summary>
/// Encodes <see cref="bool"/>.
/// </summary>
public void Boolean() => WriteTypeCode(SignatureTypeCode.Boolean);
/// <summary>
/// Encodes <see cref="char"/>.
/// </summary>
public void Char() => WriteTypeCode(SignatureTypeCode.Char);
/// <summary>
/// Encodes <see cref="sbyte"/>.
/// </summary>
public void SByte() => WriteTypeCode(SignatureTypeCode.SByte);
/// <summary>
/// Encodes <see cref="byte"/>.
/// </summary>
public void Byte() => WriteTypeCode(SignatureTypeCode.Byte);
/// <summary>
/// Encodes <see cref="short"/>.
/// </summary>
public void Int16() => WriteTypeCode(SignatureTypeCode.Int16);
/// <summary>
/// Encodes <see cref="ushort"/>.
/// </summary>
public void UInt16() => WriteTypeCode(SignatureTypeCode.UInt16);
/// <summary>
/// Encodes <see cref="int"/>.
/// </summary>
public void Int32() => WriteTypeCode(SignatureTypeCode.Int32);
/// <summary>
/// Encodes <see cref="uint"/>.
/// </summary>
public void UInt32() => WriteTypeCode(SignatureTypeCode.UInt32);
/// <summary>
/// Encodes <see cref="long"/>.
/// </summary>
public void Int64() => WriteTypeCode(SignatureTypeCode.Int64);
/// <summary>
/// Encodes <see cref="ulong"/>.
/// </summary>
public void UInt64() => WriteTypeCode(SignatureTypeCode.UInt64);
/// <summary>
/// Encodes <see cref="float"/>.
/// </summary>
public void Single() => WriteTypeCode(SignatureTypeCode.Single);
/// <summary>
/// Encodes <see cref="double"/>.
/// </summary>
public void Double() => WriteTypeCode(SignatureTypeCode.Double);
/// <summary>
/// Encodes <see cref="string"/>.
/// </summary>
public void String() => WriteTypeCode(SignatureTypeCode.String);
/// <summary>
/// Encodes <see cref="System.TypedReference"/>.
/// </summary>
public void TypedReference() => WriteTypeCode(SignatureTypeCode.TypedReference);
/// <summary>
/// Encodes <see cref="System.IntPtr"/>.
/// </summary>
public void IntPtr() => WriteTypeCode(SignatureTypeCode.IntPtr);
/// <summary>
/// Encodes <see cref="System.UIntPtr"/>.
/// </summary>
public void UIntPtr() => WriteTypeCode(SignatureTypeCode.UIntPtr);
/// <summary>
/// Encodes <see cref="object"/>.
/// </summary>
public void Object() => WriteTypeCode(SignatureTypeCode.Object);

/// <summary>
/// Writes primitive type code.
/// Encodes a primitive type.
/// </summary>
/// <param name="type">Any primitive type code except for <see cref="PrimitiveTypeCode.TypedReference"/> and <see cref="PrimitiveTypeCode.Void"/>.</param>
/// <param name="type">Any primitive type code except for <see cref="PrimitiveTypeCode.Void"/>.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not valid in this context.</exception>
public void PrimitiveType(PrimitiveTypeCode type)
{
Expand All @@ -942,14 +1004,14 @@ public void PrimitiveType(PrimitiveTypeCode type)
case PrimitiveTypeCode.UInt64:
case PrimitiveTypeCode.Single:
case PrimitiveTypeCode.Double:
case PrimitiveTypeCode.TypedReference:
case PrimitiveTypeCode.IntPtr:
case PrimitiveTypeCode.UIntPtr:
case PrimitiveTypeCode.String:
case PrimitiveTypeCode.Object:
Builder.WriteByte((byte)type);
return;

case PrimitiveTypeCode.TypedReference:
case PrimitiveTypeCode.Void:
default:
Throw.ArgumentOutOfRange(nameof(type));
Expand All @@ -958,7 +1020,7 @@ public void PrimitiveType(PrimitiveTypeCode type)
}

/// <summary>
/// Encodes an array type.
/// Starts encoding an array type.
/// Returns a pair of encoders that must be used in the order they appear in the parameter list.
/// </summary>
/// <param name="elementType">Use first, to encode the type of the element.</param>
Expand Down Expand Up @@ -1011,7 +1073,7 @@ public void Type(EntityHandle type, bool isValueType)
}

/// <summary>
/// Starts a function pointer signature.
/// Starts encoding a function pointer signature.
/// </summary>
/// <param name="convention">Calling convention.</param>
/// <param name="attributes">Function pointer attributes.</param>
Expand Down Expand Up @@ -1051,7 +1113,7 @@ public MethodSignatureEncoder FunctionPointer(
}

/// <summary>
/// Starts a generic instantiation signature.
/// Starts encoding a generic instantiation signature.
/// </summary>
/// <param name="genericType"><see cref="TypeDefinitionHandle"/> or <see cref="TypeReferenceHandle"/>.</param>
/// <param name="genericArgumentCount">Generic argument count.</param>
Expand Down Expand Up @@ -1109,7 +1171,7 @@ public void GenericTypeParameter(int parameterIndex)
}

/// <summary>
/// Starts pointer signature.
/// Starts encoding a pointer signature.
/// </summary>
public SignatureTypeEncoder Pointer()
{
Expand All @@ -1127,7 +1189,7 @@ public void VoidPointer()
}

/// <summary>
/// Starts SZ array (vector) signature.
/// Starts encoding an SZ array (vector) signature.
/// </summary>
public SignatureTypeEncoder SZArray()
{
Expand All @@ -1136,7 +1198,7 @@ public SignatureTypeEncoder SZArray()
}

/// <summary>
/// Starts a signature of a type with custom modifiers.
/// Starts encoding a signature of a type with custom modifiers.
/// </summary>
public CustomModifiersEncoder CustomModifiers()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,10 @@ public void SignatureTypeEncoder_Primitives()
AssertEx.Equal(new byte[] { 0x0E }, b.ToArray());
b.Clear();

e.TypedReference();
AssertEx.Equal(new byte[] { 0x16 }, b.ToArray());
b.Clear();

e.IntPtr();
AssertEx.Equal(new byte[] { 0x18 }, b.ToArray());
b.Clear();
Expand Down Expand Up @@ -1044,6 +1048,10 @@ public void SignatureTypeEncoder_PrimitiveType()
AssertEx.Equal(new byte[] { 0x0E }, b.ToArray());
b.Clear();

e.PrimitiveType(PrimitiveTypeCode.TypedReference);
AssertEx.Equal(new byte[] { 0x16 }, b.ToArray());
b.Clear();

e.PrimitiveType(PrimitiveTypeCode.IntPtr);
AssertEx.Equal(new byte[] { 0x18 }, b.ToArray());
b.Clear();
Expand All @@ -1057,7 +1065,6 @@ public void SignatureTypeEncoder_PrimitiveType()
b.Clear();

Assert.Throws<ArgumentOutOfRangeException>(() => e.PrimitiveType(PrimitiveTypeCode.Void));
Assert.Throws<ArgumentOutOfRangeException>(() => e.PrimitiveType(PrimitiveTypeCode.TypedReference));
Assert.Throws<ArgumentOutOfRangeException>(() => e.PrimitiveType((PrimitiveTypeCode)255));
}

Expand Down

0 comments on commit 7a87fc1

Please sign in to comment.