Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement more APIs in new TypeBuilder, fix bugs found during testing #95753

Merged
merged 16 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,9 @@ internal static bool IsTypeEqual(Type? t1, Type? t2)
Type? runtimeType2;

// set up the runtimeType and TypeBuilder type corresponding to t1 and t2
if (t1 is RuntimeTypeBuilder)
if (t1 is RuntimeTypeBuilder rtb1)
{
tb1 = (RuntimeTypeBuilder)t1;
tb1 = rtb1;
// This will be null if it is not baked.
runtimeType1 = tb1.m_bakedRuntimeType;
}
Expand All @@ -156,9 +156,9 @@ internal static bool IsTypeEqual(Type? t1, Type? t2)
runtimeType1 = t1;
}

if (t2 is RuntimeTypeBuilder)
if (t2 is RuntimeTypeBuilder rtb2)
{
tb2 = (RuntimeTypeBuilder)t2;
tb2 = rtb2;
// This will be null if it is not baked.
runtimeType2 = tb2.m_bakedRuntimeType;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Microsoft Visual Studio Solution File, Format Version 12.00
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "..\..\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj", "{772C93D4-FC45-46AA-B09F-26F01B672EDC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{E5543842-139D-43BD-B604-E65EBB91649E}"
Expand Down Expand Up @@ -727,4 +727,4 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {739AA767-154B-4C69-8C9B-C3D332833D92}
EndGlobalSection
EndGlobal
EndGlobal
35 changes: 34 additions & 1 deletion src/libraries/System.Reflection.Emit/src/Resources/Strings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@
<value>The invoked member is not supported in a dynamic module.</value>
</data>
<data name="Argument_InvalidTypeCodeForTypeArgument" xml:space="preserve">
<value>The type code may not be used as a type argument of a custom attribute .</value>
<value>The type code may not be used as a type argument of a custom attribute.</value>
</data>
<data name="NotSupported_UnmanagedTypeOnlyForFields" xml:space="preserve">
<value> 'UnmanagedType.{0}' named parameter is only valid for fields.</value>
Expand Down Expand Up @@ -228,4 +228,37 @@
<data name="Arg_NotGenericMethodDefinition" xml:space="preserve">
<value>{0} is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.</value>
</data>
<data name="ArgumentException_BadMethodImplBody" xml:space="preserve">
<value>MethodOverride's body must be from this type.</value>
</data>
<data name="Argument_GenericParameter" xml:space="preserve">
<value>Method must be called on a Type for which Type.IsGenericParameter is false.</value>
</data>
<data name="Argument_InvalidMethodOverride" xml:space="preserve">
<value>Type '{0}' tried to override method '{1}' but does not implement or inherit that method.</value>
</data>
<data name="Argument_InterfaceNotFound" xml:space="preserve">
<value>Interface not found.</value>
</data>
<data name="Argument_MethodOverriden" xml:space="preserve">
<value>Method '{0}' on type '{1}' is overriding a method that has been overridden.</value>
</data>
<data name="Argument_MustBeInterface" xml:space="preserve">
<value>Type passed must be an interface.</value>
</data>
<data name="TypeLoad_MissingMethod" xml:space="preserve">
<value>Abstract method '{0}' in type '{1}' does not have an implementation.</value>
</data>
<data name="InvalidOperation_BadMethodBody" xml:space="preserve">
<value>Method '{0}' cannot have a method body</value>
</data>
<data name="InvalidOperation_BadTypeAttributesNotAbstract" xml:space="preserve">
<value>Type must be declared abstract if any of its methods are abstract.</value>
</data>
<data name="AmbiguousMatch_MemberInfo" xml:space="preserve">
<value>Ambiguous match found for '{0} {1}'</value>
</data>
<data name="InvalidOperation_BadEmptyMethodBody" xml:space="preserve">
<value>Method '{0}' does not have a method body.</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -133,5 +133,7 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan
_customAttributes ??= new List<CustomAttributeWrapper>();
_customAttributes.Add(new CustomAttributeWrapper(con, binaryAttribute));
}

public override string? FullName => _assemblyName.FullName;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@
// 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;
using System.Runtime.InteropServices;

namespace System.Reflection.Emit
{
Expand Down Expand Up @@ -83,7 +80,7 @@ internal static CustomAttributeInfo DecodeCustomAttribute(ConstructorInfo ctor,
if (namedType == Field)
{
// For known pseudo custom attributes underlying Enum type is int
Type fieldType = dataType == EnumType ? typeof(int) : ElementTypeToType((PrimitiveSerializationTypeCode)dataType);
Type fieldType = dataType == EnumType ? typeof(int) : ElementTypeToType((SerializationTypeCode)dataType);
info._namedParamValues[i] = DecodeCustomAttributeValue(fieldType, binaryAttribute, pos, out pos); ;
}
else
Expand Down Expand Up @@ -149,30 +146,31 @@ private static int DecodeLen(ReadOnlySpan<byte> data, int pos, out int rpos)

if (subtype >= 0x02 && subtype <= 0x0e)
{
return DecodeCustomAttributeValue(ElementTypeToType((PrimitiveSerializationTypeCode)subtype), data, pos, out rpos);
return DecodeCustomAttributeValue(ElementTypeToType((SerializationTypeCode)subtype), data, pos, out rpos);
}
break;
}

throw new NotImplementedException(SR.Format(SR.NotImplemented_TypeForValue, t));
}

private static Type ElementTypeToType(PrimitiveSerializationTypeCode elementType) =>
private static Type ElementTypeToType(SerializationTypeCode elementType) =>
elementType switch
{
PrimitiveSerializationTypeCode.Boolean => typeof(bool),
PrimitiveSerializationTypeCode.Char => typeof(char),
PrimitiveSerializationTypeCode.SByte => typeof(sbyte),
PrimitiveSerializationTypeCode.Byte => typeof(byte),
PrimitiveSerializationTypeCode.Int16 => typeof(short),
PrimitiveSerializationTypeCode.UInt16 => typeof(ushort),
PrimitiveSerializationTypeCode.Int32 => typeof(int),
PrimitiveSerializationTypeCode.UInt32 => typeof(uint),
PrimitiveSerializationTypeCode.Int64 => typeof(long),
PrimitiveSerializationTypeCode.UInt64 => typeof(ulong),
PrimitiveSerializationTypeCode.Single => typeof(float),
PrimitiveSerializationTypeCode.Double => typeof(double),
PrimitiveSerializationTypeCode.String => typeof(string),
SerializationTypeCode.Boolean => typeof(bool),
SerializationTypeCode.Char => typeof(char),
SerializationTypeCode.SByte => typeof(sbyte),
SerializationTypeCode.Byte => typeof(byte),
SerializationTypeCode.Int16 => typeof(short),
SerializationTypeCode.UInt16 => typeof(ushort),
SerializationTypeCode.Int32 => typeof(int),
SerializationTypeCode.UInt32 => typeof(uint),
SerializationTypeCode.Int64 => typeof(long),
SerializationTypeCode.UInt64 => typeof(ulong),
SerializationTypeCode.Single => typeof(float),
SerializationTypeCode.Double => typeof(double),
SerializationTypeCode.String => typeof(string),
SerializationTypeCode.Type => typeof(string), // the type name written in string format
_ => throw new ArgumentException(SR.Argument_InvalidTypeCodeForTypeArgument, "binaryAttribute"),
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ internal sealed class MethodBuilderImpl : MethodBuilder
private ILGeneratorImpl? _ilGenerator;
private bool _initLocals;

internal bool _canBeRuntimeImpl;
internal DllImportData? _dllImportData;
internal List<CustomAttributeWrapper>? _customAttributes;
internal ParameterBuilderImpl[]? _parameterBuilders;
Expand Down Expand Up @@ -70,36 +71,47 @@ internal MethodBuilderImpl(string name, MethodAttributes attributes, CallingConv

internal ILGeneratorImpl? ILGeneratorImpl => _ilGenerator;

public new bool IsConstructor
{
get
{
if ((_attributes & (MethodAttributes.RTSpecialName | MethodAttributes.SpecialName)) != (MethodAttributes.RTSpecialName | MethodAttributes.SpecialName))
{
return false;
}

return _name.Equals(ConstructorInfo.ConstructorName) || _name.Equals(ConstructorInfo.TypeConstructorName);
}
}

internal BlobBuilder GetMethodSignatureBlob() => MetadataSignatureHelper.MethodSignatureEncoder(_module,
_parameterTypes, ReturnType, GetSignatureConvention(_callingConventions), GetGenericArguments().Length, !IsStatic);
_parameterTypes, ReturnType, GetSignatureConvention(_callingConventions, _dllImportData), GetGenericArguments().Length, !IsStatic);

internal static SignatureCallingConvention GetSignatureConvention(CallingConventions callingConventions)
internal static SignatureCallingConvention GetSignatureConvention(CallingConventions callingConvention, DllImportData? dllImportData = null)
{
// TODO: find out and handle other SignatureCallingConvention scenarios
SignatureCallingConvention convention = SignatureCallingConvention.Default;
if ((callingConventions & CallingConventions.HasThis) != 0 ||
(callingConventions & CallingConventions.ExplicitThis) != 0)

if ((callingConvention & CallingConventions.VarArgs) != 0)
{
convention |= SignatureCallingConvention.ThisCall;
convention = SignatureCallingConvention.VarArgs;
}

if ((callingConventions & CallingConventions.VarArgs) != 0)
if (dllImportData != null)
{
convention |= SignatureCallingConvention.VarArgs;
// Set native call signature
convention = dllImportData.Flags switch
{
MethodImportAttributes.CallingConventionCDecl => SignatureCallingConvention.CDecl,
MethodImportAttributes.CallingConventionStdCall => SignatureCallingConvention.StdCall,
MethodImportAttributes.CallingConventionThisCall => SignatureCallingConvention.ThisCall,
MethodImportAttributes.CallingConventionFastCall => SignatureCallingConvention.FastCall,
_ => SignatureCallingConvention.Unmanaged,
};
}

return convention;
}

internal BindingFlags GetBindingFlags()
{
BindingFlags bindingFlags = (_attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public ?
BindingFlags.Public : BindingFlags.NonPublic;
bindingFlags |= (_attributes & MethodAttributes.Static) != 0 ? BindingFlags.Static : BindingFlags.Instance;

return bindingFlags;
}

protected override bool InitLocalsCore
{
get { ThrowIfGeneric(); return _initLocals; }
Expand Down Expand Up @@ -174,11 +186,13 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan
case "System.Runtime.CompilerServices.MethodImplAttribute":
int implValue = BinaryPrimitives.ReadUInt16LittleEndian(binaryAttribute.Slice(2));
_methodImplFlags |= (MethodImplAttributes)implValue;
_canBeRuntimeImpl = true;
return;
case "System.Runtime.InteropServices.DllImportAttribute":
{
_dllImportData = DllImportData.CreateDllImportData(CustomAttributeInfo.DecodeCustomAttribute(con, binaryAttribute), out var preserveSig);
_attributes |= MethodAttributes.PinvokeImpl;
_canBeRuntimeImpl = true;
if (preserveSig)
{
_methodImplFlags |= MethodImplAttributes.PreserveSig;
Expand All @@ -203,6 +217,8 @@ protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan
protected override void SetImplementationFlagsCore(MethodImplAttributes attributes)
{
_declaringType.ThrowIfCreated();

_canBeRuntimeImpl = true;
_methodImplFlags = attributes;
}

Expand Down
Loading
Loading