|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using CultureInfo = System.Globalization.CultureInfo;
namespace System.Reflection.Emit
{
internal sealed partial class RuntimeTypeBuilder : TypeBuilder
{
public override bool IsAssignableFrom([NotNullWhen(true)] TypeInfo? typeInfo)
{
if (typeInfo == null) return false;
return IsAssignableFrom(typeInfo.AsType());
}
#region Declarations
private sealed class CustAttr
{
private readonly ConstructorInfo? m_con;
private readonly byte[]? m_binaryAttribute;
private readonly CustomAttributeBuilder? m_customBuilder;
public CustAttr(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
ArgumentNullException.ThrowIfNull(con);
m_con = con;
m_binaryAttribute = binaryAttribute.ToArray();
}
public CustAttr(CustomAttributeBuilder customBuilder)
{
ArgumentNullException.ThrowIfNull(customBuilder);
m_customBuilder = customBuilder;
}
public void Bake(RuntimeModuleBuilder module, int token)
{
if (m_customBuilder == null)
{
Debug.Assert(m_con != null);
DefineCustomAttribute(module, token, module.GetMethodMetadataToken(m_con),
m_binaryAttribute);
}
else
{
m_customBuilder.CreateCustomAttribute(module, token);
}
}
}
#endregion
#region Private Static FCalls
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_SetParentType")]
private static partial void SetParentType(QCallModule module, int tdTypeDef, int tkParent);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_AddInterfaceImpl")]
private static partial void AddInterfaceImpl(QCallModule module, int tdTypeDef, int tkInterface);
#endregion
#region Internal Static FCalls
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineMethod", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int DefineMethod(QCallModule module, int tkParent, string name, byte[] signature, int sigLength,
MethodAttributes attributes);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineMethodSpec")]
internal static partial int DefineMethodSpec(QCallModule module, int tkParent, byte[] signature, int sigLength);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineField", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int DefineField(QCallModule module, int tkParent, string name, byte[] signature, int sigLength,
FieldAttributes attributes);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_SetMethodIL")]
private static partial void SetMethodIL(QCallModule module, int tk, [MarshalAs(UnmanagedType.Bool)] bool isInitLocals,
byte[]? body, int bodyLength,
byte[] LocalSig, int sigLength,
int maxStackSize,
ExceptionHandler[]? exceptions, int numExceptions,
int[]? tokenFixups, int numTokenFixups);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineCustomAttribute")]
private static partial void DefineCustomAttribute(QCallModule module, int tkAssociate, int tkConstructor,
ReadOnlySpan<byte> attr, int attrLength);
internal static void DefineCustomAttribute(RuntimeModuleBuilder module, int tkAssociate, int tkConstructor,
ReadOnlySpan<byte> attr)
{
DefineCustomAttribute(new QCallModule(ref module), tkAssociate, tkConstructor,
attr, attr.Length);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineProperty", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int DefineProperty(QCallModule module, int tkParent, string name, PropertyAttributes attributes,
byte[] signature, int sigLength);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineEvent", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int DefineEvent(QCallModule module, int tkParent, string name, EventAttributes attributes, int tkEventType);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineMethodSemantics")]
internal static partial void DefineMethodSemantics(QCallModule module, int tkAssociation,
MethodSemanticsAttributes semantics, int tkMethod);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineMethodImpl")]
internal static partial void DefineMethodImpl(QCallModule module, int tkType, int tkBody, int tkDecl);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_SetMethodImpl")]
internal static partial void SetMethodImpl(QCallModule module, int tkMethod, MethodImplAttributes MethodImplAttributes);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_SetParamInfo", StringMarshalling = StringMarshalling.Utf16)]
internal static partial int SetParamInfo(QCallModule module, int tkMethod, int iSequence,
ParameterAttributes iParamAttributes, string? strParamName);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_GetTokenFromSig")]
internal static partial int GetTokenFromSig(QCallModule module, byte[] signature, int sigLength);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_SetFieldLayoutOffset")]
internal static partial void SetFieldLayoutOffset(QCallModule module, int fdToken, int iOffset);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_SetClassLayout")]
internal static partial void SetClassLayout(QCallModule module, int tk, PackingSize iPackingSize, int iTypeSize);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_SetConstantValue")]
private static unsafe partial void SetConstantValue(QCallModule module, int tk, int corType, void* pValue);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_SetPInvokeData", StringMarshalling = StringMarshalling.Utf16)]
private static partial void SetPInvokeData(QCallModule module, string DllName, string name, int token, int linkFlags);
#endregion
#region Internal\Private Static Members
internal static bool IsTypeEqual(Type? t1, Type? t2)
{
// Maybe we are lucky that they are equal in the first place
if (t1 == t2)
return true;
RuntimeTypeBuilder? tb1 = null;
RuntimeTypeBuilder? tb2 = null;
Type? runtimeType1;
Type? runtimeType2;
// set up the runtimeType and TypeBuilder type corresponding to t1 and t2
if (t1 is RuntimeTypeBuilder rtb1)
{
tb1 = rtb1;
// This will be null if it is not baked.
runtimeType1 = tb1.m_bakedRuntimeType;
}
else
{
runtimeType1 = t1;
}
if (t2 is RuntimeTypeBuilder rtb2)
{
tb2 = rtb2;
// This will be null if it is not baked.
runtimeType2 = tb2.m_bakedRuntimeType;
}
else
{
runtimeType2 = t2;
}
// If the type builder view is equal then it is equal
if (tb1 != null && tb2 != null && ReferenceEquals(tb1, tb2))
return true;
// if the runtimetype view is eqaul than it is equal
if (runtimeType1 != null && runtimeType2 != null && runtimeType1 == runtimeType2)
return true;
return false;
}
internal static unsafe void SetConstantValue(RuntimeModuleBuilder module, int tk, Type destType, object? value)
{
// This is a helper function that is used by ParameterBuilder, PropertyBuilder,
// and FieldBuilder to validate a default value and save it in the meta-data.
if (value != null)
{
Type type = value.GetType();
// We should allow setting a constant value on a ByRef parameter
if (destType.IsByRef)
destType = destType.GetElementType()!;
// Convert nullable types to their underlying type.
// This is necessary for nullable enum types to pass the IsEnum check that's coming next.
destType = Nullable.GetUnderlyingType(destType) ?? destType;
if (destType.IsEnum)
{
// | | UnderlyingSystemType | Enum.GetUnderlyingType() | IsEnum
// |-----------------------------------|---------------------------|---------------------------|---------
// | runtime Enum Type | self | underlying type of enum | TRUE
// | EnumBuilder | underlying type of enum | underlying type of enum* | TRUE
// | TypeBuilder of enum types** | underlying type of enum | Exception | TRUE
// | TypeBuilder of enum types (baked) | runtime enum type | Exception | TRUE
// *: the behavior of Enum.GetUnderlyingType(EnumBuilder) might change in the future
// so let's not depend on it.
// **: created with System.Enum as the parent type.
// The above behaviors might not be the most consistent but we have to live with them.
Type? underlyingType;
if (destType is RuntimeEnumBuilder enumBldr)
{
underlyingType = enumBldr.GetEnumUnderlyingType();
// The constant value supplied should match either the baked enum type or its underlying type
// we don't need to compare it with the EnumBuilder itself because you can never have an object of that type
if (type != enumBldr.m_typeBuilder.m_bakedRuntimeType && type != underlyingType)
throw new ArgumentException(SR.Argument_ConstantDoesntMatch);
}
else if (destType is RuntimeTypeBuilder typeBldr)
{
underlyingType = typeBldr.m_enumUnderlyingType;
// The constant value supplied should match either the baked enum type or its underlying type
// typeBldr.m_enumUnderlyingType is null if the user hasn't created a "value__" field on the enum
if (underlyingType == null || (type != typeBldr.UnderlyingSystemType && type != underlyingType))
throw new ArgumentException(SR.Argument_ConstantDoesntMatch);
}
else // must be a runtime Enum Type
{
Debug.Assert(destType is RuntimeType, "destType is not a runtime type, an EnumBuilder, or a TypeBuilder.");
underlyingType = Enum.GetUnderlyingType(destType);
// The constant value supplied should match either the enum itself or its underlying type
if (type != destType && type != underlyingType)
throw new ArgumentException(SR.Argument_ConstantDoesntMatch);
}
type = underlyingType;
}
else
{
// Note that it is non CLS compliant if destType != type. But RefEmit never guarantees CLS-Compliance.
if (!destType.IsAssignableFrom(type))
throw new ArgumentException(SR.Argument_ConstantDoesntMatch);
}
CorElementType corType = RuntimeTypeHandle.GetCorElementType((RuntimeType)type);
switch (corType)
{
case CorElementType.ELEMENT_TYPE_I1:
case CorElementType.ELEMENT_TYPE_U1:
case CorElementType.ELEMENT_TYPE_BOOLEAN:
case CorElementType.ELEMENT_TYPE_I2:
case CorElementType.ELEMENT_TYPE_U2:
case CorElementType.ELEMENT_TYPE_CHAR:
case CorElementType.ELEMENT_TYPE_I4:
case CorElementType.ELEMENT_TYPE_U4:
case CorElementType.ELEMENT_TYPE_R4:
case CorElementType.ELEMENT_TYPE_I8:
case CorElementType.ELEMENT_TYPE_U8:
case CorElementType.ELEMENT_TYPE_R8:
fixed (byte* pData = &value.GetRawData())
SetConstantValue(new QCallModule(ref module), tk, (int)corType, pData);
break;
default:
if (type == typeof(string))
{
fixed (char* pString = (string)value)
SetConstantValue(new QCallModule(ref module), tk, (int)CorElementType.ELEMENT_TYPE_STRING, pString);
}
else if (type == typeof(DateTime))
{
// date is a I8 representation
long ticks = ((DateTime)value).Ticks;
SetConstantValue(new QCallModule(ref module), tk, (int)CorElementType.ELEMENT_TYPE_I8, &ticks);
}
else
{
throw new ArgumentException(SR.Format(SR.Argument_ConstantNotSupported, type));
}
break;
}
}
else
{
// A null default value in metadata is permissible even for non-nullable value types.
// (See ECMA-335 II.15.4.1.4 "The .param directive" and II.22.9 "Constant" for details.)
// This is how the Roslyn compilers generally encode `default(TValueType)` default values.
SetConstantValue(new QCallModule(ref module), tk, (int)CorElementType.ELEMENT_TYPE_CLASS, null);
}
}
#endregion
#region Private Data Members
private List<CustAttr>? m_ca;
private int m_tdType;
private readonly RuntimeModuleBuilder m_module;
private readonly string? m_strName;
private readonly string? m_strNameSpace;
private string? m_strFullQualName;
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
private Type? m_typeParent;
private List<Type>? m_typeInterfaces;
private readonly TypeAttributes m_iAttr;
private GenericParameterAttributes m_genParamAttributes;
internal List<RuntimeMethodBuilder>? m_listMethods;
internal int m_lastTokenizedMethod;
private int m_constructorCount;
private readonly int m_iTypeSize;
private readonly PackingSize m_iPackingSize;
private readonly RuntimeTypeBuilder? m_DeclaringType;
// We cannot store this on EnumBuilder because users can define enum types manually using TypeBuilder.
private Type? m_enumUnderlyingType;
internal bool m_isHiddenGlobalType;
private bool m_hasBeenCreated;
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
private RuntimeType m_bakedRuntimeType = null!;
private readonly int m_genParamPos;
private RuntimeGenericTypeParameterBuilder[]? m_inst;
private readonly bool m_bIsGenParam;
private readonly RuntimeMethodBuilder? m_declMeth;
private readonly RuntimeTypeBuilder? m_genTypeDef;
#endregion
#region Constructor
// ctor for the global (module) type
internal RuntimeTypeBuilder(RuntimeModuleBuilder module)
{
m_tdType = ((int)MetadataTokenType.TypeDef);
m_isHiddenGlobalType = true;
m_module = module;
m_listMethods = new List<RuntimeMethodBuilder>();
// No token has been created so let's initialize it to -1
// The first time we call MethodBuilder.GetToken this will incremented.
m_lastTokenizedMethod = -1;
}
// ctor for generic method parameter
internal RuntimeTypeBuilder(string szName, int genParamPos, RuntimeMethodBuilder declMeth)
{
m_strName = szName;
m_genParamPos = genParamPos;
m_bIsGenParam = true;
m_typeInterfaces = new List<Type>();
Debug.Assert(declMeth != null);
m_declMeth = declMeth;
m_DeclaringType = m_declMeth.GetTypeBuilder();
m_module = declMeth.GetModuleBuilder();
}
// ctor for generic type parameter
private RuntimeTypeBuilder(string szName, int genParamPos, RuntimeTypeBuilder declType)
{
m_strName = szName;
m_genParamPos = genParamPos;
m_bIsGenParam = true;
m_typeInterfaces = new List<Type>();
Debug.Assert(declType != null);
m_DeclaringType = declType;
m_module = declType.GetModuleBuilder();
}
internal RuntimeTypeBuilder(
string name, TypeAttributes attr, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent, Type[]? interfaces, RuntimeModuleBuilder module,
PackingSize iPackingSize, int iTypeSize, RuntimeTypeBuilder? enclosingType)
{
if (name[0] == '\0')
throw new ArgumentException(SR.Argument_IllegalName, nameof(name));
if (name.Length > 1023)
throw new ArgumentException(SR.Argument_TypeNameTooLong, nameof(name));
int i;
m_module = module;
m_DeclaringType = enclosingType;
RuntimeAssemblyBuilder containingAssem = m_module.ContainingAssemblyBuilder;
// cannot have two types within the same assembly of the same name
containingAssem.CheckTypeNameConflict(name, enclosingType);
if (enclosingType != null)
{
// Nested Type should have nested attribute set.
// If we are renumbering TypeAttributes' bit, we need to change the logic here.
if (((attr & TypeAttributes.VisibilityMask) == TypeAttributes.Public) || ((attr & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic))
throw new ArgumentException(SR.Argument_BadNestedTypeFlags, nameof(attr));
}
int[]? interfaceTokens = null;
if (interfaces != null)
{
interfaceTokens = new int[interfaces.Length + 1];
for (i = 0; i < interfaces.Length; i++)
{
// cannot contain null in the interface list
ArgumentNullException.ThrowIfNull(interfaces[i], nameof(interfaces));
interfaceTokens[i] = m_module.GetTypeTokenInternal(interfaces[i]);
}
}
int iLast = name.LastIndexOf('.');
if (iLast <= 0)
{
// no name space
m_strNameSpace = string.Empty;
m_strName = name;
}
else
{
// split the name space
m_strNameSpace = name.Substring(0, iLast);
m_strName = name.Substring(iLast + 1);
}
VerifyTypeAttributes(attr);
m_iAttr = attr;
SetParent(parent);
m_listMethods = new List<RuntimeMethodBuilder>();
m_lastTokenizedMethod = -1;
SetInterfaces(interfaces);
int tkParent = 0;
if (m_typeParent != null)
tkParent = m_module.GetTypeTokenInternal(m_typeParent);
int tkEnclosingType = 0;
if (enclosingType != null)
{
tkEnclosingType = enclosingType.m_tdType;
}
m_tdType = DefineType(new QCallModule(ref module),
name, tkParent, m_iAttr, tkEnclosingType, interfaceTokens!);
m_iPackingSize = iPackingSize;
m_iTypeSize = iTypeSize;
if ((m_iPackingSize != 0) || (m_iTypeSize != 0))
SetClassLayout(new QCallModule(ref module), m_tdType, m_iPackingSize, m_iTypeSize);
m_module.AddType(FullName!, this);
}
#endregion
#region Private Members
private FieldBuilder DefineDataHelper(string name, byte[]? data, int size, FieldAttributes attributes)
{
string strValueClassName;
TypeBuilder? valueClassType;
FieldBuilder fdBuilder;
TypeAttributes typeAttributes;
ArgumentException.ThrowIfNullOrEmpty(name);
if (size <= 0 || size >= 0x003f0000)
throw new ArgumentException(SR.Argument_BadSizeForData);
ThrowIfCreated();
// form the value class name
strValueClassName = $"$ArrayType${size}";
// Is this already defined in this module?
Type? temp = m_module.FindTypeBuilderWithName(strValueClassName, false);
valueClassType = temp as TypeBuilder;
if (valueClassType == null)
{
typeAttributes = TypeAttributes.Public | TypeAttributes.ExplicitLayout | TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.AnsiClass;
// Define the backing value class
valueClassType = m_module.DefineType(strValueClassName, typeAttributes, typeof(ValueType), PackingSize.Size1, size);
valueClassType.CreateType();
}
fdBuilder = DefineField(name, valueClassType, attributes | FieldAttributes.Static);
// now we need to set the RVA
((RuntimeFieldBuilder)fdBuilder).SetData(data, size);
return fdBuilder;
}
private void VerifyTypeAttributes(TypeAttributes attr)
{
// Verify attr consistency for Nesting or otherwise.
if (DeclaringType == null)
{
// Not a nested class.
if (((attr & TypeAttributes.VisibilityMask) != TypeAttributes.NotPublic) && ((attr & TypeAttributes.VisibilityMask) != TypeAttributes.Public))
{
throw new ArgumentException(SR.Argument_BadTypeAttrNestedVisibilityOnNonNestedType);
}
}
else
{
// Nested class.
if (((attr & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic) || ((attr & TypeAttributes.VisibilityMask) == TypeAttributes.Public))
{
throw new ArgumentException(SR.Argument_BadTypeAttrNonNestedVisibilityNestedType);
}
}
// Verify that the layout mask is valid.
if (((attr & TypeAttributes.LayoutMask) != TypeAttributes.AutoLayout) && ((attr & TypeAttributes.LayoutMask) != TypeAttributes.SequentialLayout) && ((attr & TypeAttributes.LayoutMask) != TypeAttributes.ExplicitLayout))
{
throw new ArgumentException(SR.Argument_BadTypeAttrInvalidLayout);
}
// Check if the user attempted to set any reserved bits.
if ((attr & TypeAttributes.ReservedMask) != 0)
{
throw new ArgumentException(SR.Argument_BadTypeAttrReservedBitsSet);
}
}
protected override bool IsCreatedCore()
{
return m_hasBeenCreated;
}
#endregion
#region FCalls
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineType", StringMarshalling = StringMarshalling.Utf16)]
private static partial int DefineType(QCallModule module,
string fullname, int tkParent, TypeAttributes attributes, int tkEnclosingType, int[] interfaceTokens);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_DefineGenericParam", StringMarshalling = StringMarshalling.Utf16)]
private static partial int DefineGenericParam(QCallModule module,
string name, int tkParent, GenericParameterAttributes attributes, int position, int[] constraints);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "TypeBuilder_TermCreateClass")]
private static partial void TermCreateClass(QCallModule module, int tk, ObjectHandleOnStack type);
#endregion
#region Internal Methods
internal void ThrowIfCreated()
{
if (IsCreated())
throw new InvalidOperationException(SR.InvalidOperation_TypeHasBeenCreated);
}
internal object SyncRoot => m_module.SyncRoot;
internal RuntimeModuleBuilder GetModuleBuilder()
{
return m_module;
}
internal RuntimeType BakedRuntimeType => m_bakedRuntimeType;
internal void SetGenParamAttributes(GenericParameterAttributes genericParameterAttributes)
{
m_genParamAttributes = genericParameterAttributes;
}
internal void SetGenParamCustomAttribute(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
CustAttr ca = new CustAttr(con, binaryAttribute);
lock (SyncRoot)
{
SetGenParamCustomAttributeNoLock(ca);
}
}
internal void SetGenParamCustomAttribute(CustomAttributeBuilder customBuilder)
{
CustAttr ca = new CustAttr(customBuilder);
lock (SyncRoot)
{
SetGenParamCustomAttributeNoLock(ca);
}
}
private void SetGenParamCustomAttributeNoLock(CustAttr ca)
{
m_ca ??= new List<CustAttr>();
m_ca.Add(ca);
}
#endregion
#region Object Overrides
public override string ToString()
{
return TypeNameBuilder.ToString(this, TypeNameBuilder.Format.ToString)!;
}
#endregion
#region MemberInfo Overrides
public override Type? DeclaringType => m_DeclaringType;
public override Type? ReflectedType => m_DeclaringType;
public override string Name =>
// one of the constructors allows this to be null but it is only used internally without accessing Name
m_strName!;
public override Module Module => GetModuleBuilder();
public override bool IsByRefLike => false;
public override int MetadataToken => m_tdType;
#endregion
#region Type Overrides
public override Guid GUID
{
get
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GUID;
}
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public override object? InvokeMember(string name, BindingFlags invokeAttr, Binder? binder, object? target,
object?[]? args, ParameterModifier[]? modifiers, CultureInfo? culture, string[]? namedParameters)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
}
public override Assembly Assembly => m_module.Assembly;
public override RuntimeTypeHandle TypeHandle => throw new NotSupportedException(SR.NotSupported_DynamicModule);
public override string? FullName => m_strFullQualName ??= TypeNameBuilder.ToString(this, TypeNameBuilder.Format.FullName);
public override string? Namespace => m_strNameSpace;
public override string? AssemblyQualifiedName => TypeNameBuilder.ToString(this, TypeNameBuilder.Format.AssemblyQualifiedName);
public override Type? BaseType => m_typeParent;
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
protected override ConstructorInfo? GetConstructorImpl(BindingFlags bindingAttr, Binder? binder,
CallingConventions callConvention, Type[] types, ParameterModifier[]? modifiers)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetConstructor(bindingAttr, binder, callConvention, types, modifiers);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors | DynamicallyAccessedMemberTypes.NonPublicConstructors)]
public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetConstructors(bindingAttr);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
protected override MethodInfo? GetMethodImpl(string name, BindingFlags bindingAttr, Binder? binder,
CallingConventions callConvention, Type[]? types, ParameterModifier[]? modifiers)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
if (types == null)
{
return m_bakedRuntimeType.GetMethod(name, bindingAttr);
}
else
{
return m_bakedRuntimeType.GetMethod(name, bindingAttr, binder, callConvention, types, modifiers);
}
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)]
public override MethodInfo[] GetMethods(BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetMethods(bindingAttr);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
public override FieldInfo? GetField(string name, BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetField(name, bindingAttr);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicFields | DynamicallyAccessedMemberTypes.NonPublicFields)]
public override FieldInfo[] GetFields(BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetFields(bindingAttr);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
public override Type? GetInterface(string name, bool ignoreCase)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetInterface(name, ignoreCase);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)]
public override Type[] GetInterfaces()
{
if (m_bakedRuntimeType != null)
{
return m_bakedRuntimeType.GetInterfaces();
}
if (m_typeInterfaces == null)
{
return EmptyTypes;
}
return m_typeInterfaces.ToArray();
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
public override EventInfo? GetEvent(string name, BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetEvent(name, bindingAttr);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents)]
public override EventInfo[] GetEvents()
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetEvents();
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder? binder,
Type? returnType, Type[]? types, ParameterModifier[]? modifiers)
{
throw new NotSupportedException(SR.NotSupported_DynamicModule);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.NonPublicProperties)]
public override PropertyInfo[] GetProperties(BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetProperties(bindingAttr);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
public override Type[] GetNestedTypes(BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetNestedTypes(bindingAttr);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicNestedTypes | DynamicallyAccessedMemberTypes.NonPublicNestedTypes)]
public override Type? GetNestedType(string name, BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetNestedType(name, bindingAttr);
}
[DynamicallyAccessedMembers(GetAllMembers)]
public override MemberInfo[] GetMember(string name, MemberTypes type, BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetMember(name, type, bindingAttr);
}
public override InterfaceMapping GetInterfaceMap([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods | DynamicallyAccessedMemberTypes.NonPublicMethods)] Type interfaceType)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetInterfaceMap(interfaceType);
}
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicEvents | DynamicallyAccessedMemberTypes.NonPublicEvents)]
public override EventInfo[] GetEvents(BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetEvents(bindingAttr);
}
[DynamicallyAccessedMembers(GetAllMembers)]
public override MemberInfo[] GetMembers(BindingFlags bindingAttr)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return m_bakedRuntimeType.GetMembers(bindingAttr);
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",
Justification = "The GetInterfaces technically requires all interfaces to be preserved" +
"But in this case it acts only on TypeBuilder which is never trimmed (as it's runtime created).")]
public override bool IsAssignableFrom([NotNullWhen(true)] Type? c)
{
if (IsTypeEqual(c, this))
return true;
Type? fromRuntimeType;
RuntimeTypeBuilder? fromTypeBuilder = c as RuntimeTypeBuilder;
if (fromTypeBuilder != null)
fromRuntimeType = fromTypeBuilder.m_bakedRuntimeType;
else
fromRuntimeType = c;
if (fromRuntimeType != null && fromRuntimeType is RuntimeType)
{
// fromType is baked. So if this type is not baked, it cannot be assignable to!
if (m_bakedRuntimeType == null)
return false;
// since toType is also baked, delegate to the base
return m_bakedRuntimeType.IsAssignableFrom(fromRuntimeType);
}
// So if c is not a runtimeType nor TypeBuilder. We don't know how to deal with it.
// return false then.
if (fromTypeBuilder == null)
return false;
// If fromTypeBuilder is a subclass of this class, then c can be cast to this type.
if (fromTypeBuilder.IsSubclassOf(this))
return true;
if (!IsInterface)
return false;
// now is This type a base type on one of the interface impl?
Type[] interfaces = fromTypeBuilder.GetInterfaces();
for (int i = 0; i < interfaces.Length; i++)
{
// unfortunately, IsSubclassOf does not cover the case when they are the same type.
if (IsTypeEqual(interfaces[i], this))
return true;
if (interfaces[i].IsSubclassOf(this))
return true;
}
return false;
}
protected override TypeAttributes GetAttributeFlagsImpl()
{
return m_iAttr;
}
public override bool IsTypeDefinition => true;
public override bool IsSZArray => false;
protected override bool IsArrayImpl()
{
return false;
}
protected override bool IsByRefImpl()
{
return false;
}
protected override bool IsPointerImpl()
{
return false;
}
protected override bool IsPrimitiveImpl()
{
return false;
}
protected override bool IsCOMObjectImpl()
{
return ((GetAttributeFlagsImpl() & TypeAttributes.Import) != 0) ? true : false;
}
public override Type GetElementType()
{
// You will never have to deal with a TypeBuilder if you are just referring to arrays.
throw new NotSupportedException(SR.NotSupported_DynamicModule);
}
protected override bool HasElementTypeImpl()
{
return false;
}
public override bool IsSecurityCritical => true;
public override bool IsSecuritySafeCritical => false;
public override bool IsSecurityTransparent => false;
public override bool IsSubclassOf(Type c)
{
Type? p = this;
if (IsTypeEqual(p, c))
return false;
p = p.BaseType;
while (p != null)
{
if (IsTypeEqual(p, c))
return true;
p = p.BaseType;
}
return false;
}
public override Type UnderlyingSystemType
{
get
{
if (m_bakedRuntimeType != null)
return m_bakedRuntimeType;
if (IsEnum)
{
if (m_enumUnderlyingType == null)
throw new InvalidOperationException(SR.InvalidOperation_NoUnderlyingTypeOnEnum);
return m_enumUnderlyingType;
}
else
{
return this;
}
}
}
#endregion
#region ICustomAttributeProvider Implementation
public override object[] GetCustomAttributes(bool inherit)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
return CustomAttribute.GetCustomAttributes(m_bakedRuntimeType, (typeof(object) as RuntimeType)!, inherit);
}
public override object[] GetCustomAttributes(Type attributeType, bool inherit)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
ArgumentNullException.ThrowIfNull(attributeType);
if (attributeType.UnderlyingSystemType is not RuntimeType attributeRuntimeType)
throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
return CustomAttribute.GetCustomAttributes(m_bakedRuntimeType, attributeRuntimeType, inherit);
}
public override bool IsDefined(Type attributeType, bool inherit)
{
if (!IsCreated())
throw new NotSupportedException(SR.NotSupported_TypeNotYetCreated);
ArgumentNullException.ThrowIfNull(attributeType);
if (attributeType.UnderlyingSystemType is not RuntimeType attributeRuntimeType)
throw new ArgumentException(SR.Arg_MustBeType, nameof(attributeType));
return CustomAttribute.IsDefined(m_bakedRuntimeType, attributeRuntimeType, inherit);
}
#endregion
#region Public Member
#region DefineType
public override GenericParameterAttributes GenericParameterAttributes => m_genParamAttributes;
internal void SetInterfaces(params Type[]? interfaces)
{
ThrowIfCreated();
m_typeInterfaces = new List<Type>();
if (interfaces != null)
{
m_typeInterfaces.AddRange(interfaces);
}
}
protected override GenericTypeParameterBuilder[] DefineGenericParametersCore(params string[] names)
{
if (m_inst != null)
{
throw new InvalidOperationException();
}
m_inst = new RuntimeGenericTypeParameterBuilder[names.Length];
for (int i = 0; i < names.Length; i++)
{
string name = names[i];
ArgumentNullException.ThrowIfNull(name, nameof(names));
m_inst[i] = new RuntimeGenericTypeParameterBuilder(new RuntimeTypeBuilder(name, i, this));
}
return m_inst;
}
public override Type[] GetGenericArguments() => m_inst ?? EmptyTypes;
// If a TypeBuilder is generic, it must be a generic type definition
// All instantiated generic types are TypeBuilderInstantiation.
public override bool IsGenericTypeDefinition => IsGenericType;
public override bool IsGenericType => m_inst != null;
public override bool IsGenericParameter => m_bIsGenParam;
public override bool IsConstructedGenericType => false;
public override int GenericParameterPosition => m_genParamPos;
public override MethodBase? DeclaringMethod => m_declMeth;
public override Type GetGenericTypeDefinition() { if (IsGenericTypeDefinition) return this; if (m_genTypeDef == null) throw new InvalidOperationException(); return m_genTypeDef; }
#endregion
#region Define Method
protected override void DefineMethodOverrideCore(MethodInfo methodInfoBody, MethodInfo methodInfoDeclaration)
{
lock (SyncRoot)
{
ThrowIfCreated();
if (!ReferenceEquals(methodInfoBody.DeclaringType, this))
// Loader restriction: body method has to be from this class
throw new ArgumentException(SR.ArgumentException_BadMethodImplBody);
int tkBody = m_module.GetMethodMetadataToken(methodInfoBody);
int tkDecl = m_module.GetMethodMetadataToken(methodInfoDeclaration);
RuntimeModuleBuilder module = m_module;
DefineMethodImpl(new QCallModule(ref module), m_tdType, tkBody, tkDecl);
}
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2082:UnrecognizedReflectionPattern",
Justification = "Reflection.Emit is not subject to trimming")]
protected override MethodBuilder DefineMethodCore(string name, MethodAttributes attributes, CallingConventions callingConvention,
Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers,
Type[]? parameterTypes, Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers)
{
lock (SyncRoot)
{
ThrowIfCreated();
// pass in Method attributes
RuntimeMethodBuilder method = new RuntimeMethodBuilder(
name, attributes, callingConvention,
returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers,
parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers,
m_module, this);
if (!m_isHiddenGlobalType)
{
// If this method is declared to be a constructor, increment our constructor count.
if ((method.Attributes & MethodAttributes.SpecialName) != 0 && method.Name.Equals(ConstructorInfo.ConstructorName))
{
m_constructorCount++;
}
}
m_listMethods!.Add(method);
return method;
}
}
[RequiresUnreferencedCode("P/Invoke marshalling may dynamically access members that could be trimmed.")]
protected override MethodBuilder DefinePInvokeMethodCore(string name, string dllName, string entryName, MethodAttributes attributes,
CallingConventions callingConvention,
Type? returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers,
Type[]? parameterTypes, Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers,
CallingConvention nativeCallConv, CharSet nativeCharSet)
{
lock (SyncRoot)
{
if ((attributes & MethodAttributes.Abstract) != 0)
throw new ArgumentException(SR.Argument_BadPInvokeMethod);
if ((m_iAttr & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface)
throw new ArgumentException(SR.Argument_BadPInvokeOnInterface);
ThrowIfCreated();
attributes |= MethodAttributes.PinvokeImpl;
RuntimeMethodBuilder method = new RuntimeMethodBuilder(name, attributes, callingConvention,
returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers,
parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers,
m_module, this);
// The signature grabbing code has to be up here or the signature won't be finished
// and our equals check won't work.
_ = method.GetMethodSignature().InternalGetSignature(out _);
if (m_listMethods!.Contains(method))
{
throw new ArgumentException(SR.Argument_MethodRedefined);
}
m_listMethods.Add(method);
int token = method.MetadataToken;
int linkFlags = 0;
switch (nativeCallConv)
{
case CallingConvention.Winapi:
linkFlags = (int)PInvokeAttributes.CallConvWinapi;
break;
case CallingConvention.Cdecl:
linkFlags = (int)PInvokeAttributes.CallConvCdecl;
break;
case CallingConvention.StdCall:
linkFlags = (int)PInvokeAttributes.CallConvStdcall;
break;
case CallingConvention.ThisCall:
linkFlags = (int)PInvokeAttributes.CallConvThiscall;
break;
case CallingConvention.FastCall:
linkFlags = (int)PInvokeAttributes.CallConvFastcall;
break;
}
switch (nativeCharSet)
{
case CharSet.None:
linkFlags |= (int)PInvokeAttributes.CharSetNotSpec;
break;
case CharSet.Ansi:
linkFlags |= (int)PInvokeAttributes.CharSetAnsi;
break;
case CharSet.Unicode:
linkFlags |= (int)PInvokeAttributes.CharSetUnicode;
break;
case CharSet.Auto:
linkFlags |= (int)PInvokeAttributes.CharSetAuto;
break;
}
RuntimeModuleBuilder module = m_module;
SetPInvokeData(new QCallModule(ref module),
dllName,
entryName,
token,
linkFlags);
method.SetToken(token);
return method;
}
}
#endregion
#region Define Constructor
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2082:UnrecognizedReflectionPattern",
Justification = "Reflection.Emit is not subject to trimming")]
protected override ConstructorBuilder DefineTypeInitializerCore()
{
lock (SyncRoot)
{
ThrowIfCreated();
// change the attributes and the class constructor's name
const MethodAttributes attr = MethodAttributes.Private | MethodAttributes.Static | MethodAttributes.SpecialName;
ConstructorBuilder constBuilder = new RuntimeConstructorBuilder(
ConstructorInfo.TypeConstructorName, attr, CallingConventions.Standard, null, m_module, this);
return constBuilder;
}
}
protected override ConstructorBuilder DefineDefaultConstructorCore(MethodAttributes attributes)
{
if ((m_iAttr & TypeAttributes.Interface) == TypeAttributes.Interface)
{
throw new InvalidOperationException(SR.InvalidOperation_ConstructorNotAllowedOnInterface);
}
lock (SyncRoot)
{
return DefineDefaultConstructorNoLock(attributes);
}
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2055:UnrecognizedReflectionPattern",
Justification = "MakeGenericType is only called on a TypeBuilderInstantiation which is not subject to trimming")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:UnrecognizedReflectionPattern",
Justification = "GetConstructor is only called on a TypeBuilderInstantiation which is not subject to trimming")]
private RuntimeConstructorBuilder DefineDefaultConstructorNoLock(MethodAttributes attributes)
{
RuntimeConstructorBuilder constBuilder;
// get the parent class's default constructor
// We really don't want(BindingFlags.Instance|BindingFlags.Public|BindingFlags.NonPublic) here. We really want
// constructors visible from the subclass, but that is not currently
// available in BindingFlags. This more open binding is open to
// runtime binding failures(like if we resolve to a private
// constructor).
ConstructorInfo? con = null;
if (m_typeParent is TypeBuilderInstantiation)
{
Type? genericTypeDefinition = m_typeParent.GetGenericTypeDefinition();
if (genericTypeDefinition is RuntimeTypeBuilder rtBuilder)
genericTypeDefinition = rtBuilder.m_bakedRuntimeType;
if (genericTypeDefinition == null)
throw new NotSupportedException(SR.NotSupported_DynamicModule);
Type inst = genericTypeDefinition.MakeGenericType(m_typeParent.GetGenericArguments());
if (inst is TypeBuilderInstantiation)
con = GetConstructor(inst, genericTypeDefinition.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, EmptyTypes, null)!);
else
con = inst.GetConstructor(
BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, EmptyTypes, null);
}
con ??= m_typeParent!.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, EmptyTypes, null);
if (con == null)
throw new NotSupportedException(SR.NotSupported_NoParentDefaultConstructor);
// Define the constructor Builder
constBuilder = (RuntimeConstructorBuilder)DefineConstructor(attributes, CallingConventions.Standard, null);
// generate the code to call the parent's default constructor
ILGenerator il = constBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, con);
il.Emit(OpCodes.Ret);
constBuilder.m_isDefaultConstructor = true;
return constBuilder;
}
protected override ConstructorBuilder DefineConstructorCore(MethodAttributes attributes, CallingConventions callingConvention,
Type[]? parameterTypes, Type[][]? requiredCustomModifiers, Type[][]? optionalCustomModifiers)
{
if ((m_iAttr & TypeAttributes.Interface) == TypeAttributes.Interface && (attributes & MethodAttributes.Static) != MethodAttributes.Static)
{
throw new InvalidOperationException(SR.InvalidOperation_ConstructorNotAllowedOnInterface);
}
lock (SyncRoot)
{
return DefineConstructorNoLock(attributes, callingConvention, parameterTypes, requiredCustomModifiers, optionalCustomModifiers);
}
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2082:UnrecognizedReflectionPattern",
Justification = "Reflection.Emit is not subject to trimming")]
private ConstructorBuilder DefineConstructorNoLock(MethodAttributes attributes, CallingConventions callingConvention,
Type[]? parameterTypes, Type[][]? requiredCustomModifiers, Type[][]? optionalCustomModifiers)
{
ThrowIfCreated();
string name;
if ((attributes & MethodAttributes.Static) == 0)
{
name = ConstructorInfo.ConstructorName;
}
else
{
name = ConstructorInfo.TypeConstructorName;
}
attributes |= MethodAttributes.SpecialName;
ConstructorBuilder constBuilder =
new RuntimeConstructorBuilder(name, attributes, callingConvention,
parameterTypes, requiredCustomModifiers, optionalCustomModifiers, m_module, this);
m_constructorCount++;
return constBuilder;
}
#endregion
#region Define Nested Type
protected override TypeBuilder DefineNestedTypeCore(string name, TypeAttributes attr, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent, Type[]? interfaces, PackingSize packSize, int typeSize)
{
lock (SyncRoot)
{
return new RuntimeTypeBuilder(name, attr, parent, interfaces, m_module, packSize, typeSize, this);
}
}
#endregion
#region Define Field
protected override FieldBuilder DefineFieldCore(string fieldName, Type type, Type[]? requiredCustomModifiers,
Type[]? optionalCustomModifiers, FieldAttributes attributes)
{
lock (SyncRoot)
{
ThrowIfCreated();
if (m_enumUnderlyingType == null && IsEnum)
{
if ((attributes & FieldAttributes.Static) == 0)
{
// remember the underlying type for enum type
m_enumUnderlyingType = type;
}
}
return new RuntimeFieldBuilder(this, fieldName, type, requiredCustomModifiers, optionalCustomModifiers, attributes);
}
}
protected override FieldBuilder DefineInitializedDataCore(string name, byte[] data, FieldAttributes attributes)
{
lock (SyncRoot)
{
// This method will define an initialized Data in .sdata.
// We will create a fake TypeDef to represent the data with size. This TypeDef
// will be the signature for the Field.
return DefineDataHelper(name, data, data.Length, attributes);
}
}
protected override FieldBuilder DefineUninitializedDataCore(string name, int size, FieldAttributes attributes)
{
lock (SyncRoot)
{
// This method will define an uninitialized Data in .sdata.
// We will create a fake TypeDef to represent the data with size. This TypeDef
// will be the signature for the Field.
return DefineDataHelper(name, null, size, attributes);
}
}
#endregion
#region Define Properties and Events
protected override PropertyBuilder DefinePropertyCore(string name, PropertyAttributes attributes, CallingConventions callingConvention,
Type returnType, Type[]? returnTypeRequiredCustomModifiers, Type[]? returnTypeOptionalCustomModifiers,
Type[]? parameterTypes, Type[][]? parameterTypeRequiredCustomModifiers, Type[][]? parameterTypeOptionalCustomModifiers)
{
lock (SyncRoot)
{
SignatureHelper sigHelper;
byte[] sigBytes;
ThrowIfCreated();
// get the signature in SignatureHelper form
sigHelper = SignatureHelper.GetPropertySigHelper(
m_module, callingConvention,
returnType, returnTypeRequiredCustomModifiers, returnTypeOptionalCustomModifiers,
parameterTypes, parameterTypeRequiredCustomModifiers, parameterTypeOptionalCustomModifiers);
// get the signature in byte form
sigBytes = sigHelper.InternalGetSignature(out int sigLength);
RuntimeModuleBuilder module = m_module;
int prToken = DefineProperty(
new QCallModule(ref module),
m_tdType,
name,
attributes,
sigBytes,
sigLength);
// create the property builder now.
return new RuntimePropertyBuilder(
m_module,
name,
attributes,
returnType,
prToken,
this);
}
}
protected override EventBuilder DefineEventCore(string name, EventAttributes attributes, Type eventtype)
{
if (name[0] == '\0')
{
throw new ArgumentException(SR.Argument_IllegalName, nameof(name));
}
lock (SyncRoot)
{
int tkType;
int evToken;
ThrowIfCreated();
tkType = m_module.GetTypeTokenInternal(eventtype);
// Internal helpers to define property records
RuntimeModuleBuilder module = m_module;
evToken = DefineEvent(
new QCallModule(ref module),
m_tdType,
name,
attributes,
tkType);
// create the property builder now.
return new RuntimeEventBuilder(
m_module,
name,
attributes,
this,
evToken);
}
}
#endregion
#region Create Type
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
protected override TypeInfo CreateTypeInfoCore()
{
TypeInfo? typeInfo = CreateTypeInfoImpl();
Debug.Assert(m_isHiddenGlobalType || typeInfo != null);
return typeInfo!;
}
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
internal TypeInfo? CreateTypeInfoImpl()
{
lock (SyncRoot)
{
return CreateTypeNoLock();
}
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2083:UnrecognizedReflectionPattern",
Justification = "Reflection.Emit is not subject to trimming")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2068:UnrecognizedReflectionPattern",
Justification = "Reflection.Emit is not subject to trimming")]
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2069:UnrecognizedReflectionPattern",
Justification = "Reflection.Emit is not subject to trimming")]
[return: DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
private TypeInfo? CreateTypeNoLock()
{
if (IsCreated())
return m_bakedRuntimeType;
m_typeInterfaces ??= new List<Type>();
int[] interfaceTokens = new int[m_typeInterfaces.Count];
for (int i = 0; i < m_typeInterfaces.Count; i++)
{
interfaceTokens[i] = m_module.GetTypeTokenInternal(m_typeInterfaces[i]);
}
int tkParent = 0;
if (m_typeParent != null)
{
tkParent = m_module.GetTypeTokenInternal(m_typeParent);
}
RuntimeModuleBuilder module = m_module;
if (IsGenericParameter)
{
int[] constraints; // Array of token constrains terminated by null token
if (m_typeParent != null)
{
constraints = new int[m_typeInterfaces.Count + 2];
constraints[^2] = tkParent;
}
else
{
constraints = new int[m_typeInterfaces.Count + 1];
}
for (int i = 0; i < m_typeInterfaces.Count; i++)
{
constraints[i] = m_module.GetTypeTokenInternal(m_typeInterfaces[i]);
}
int declMember = m_declMeth == null ? m_DeclaringType!.m_tdType : m_declMeth.MetadataToken;
m_tdType = DefineGenericParam(new QCallModule(ref module),
m_strName!, declMember, m_genParamAttributes, m_genParamPos, constraints);
if (m_ca != null)
{
foreach (CustAttr ca in m_ca)
ca.Bake(m_module, MetadataToken);
}
m_hasBeenCreated = true;
// Baking a generic parameter does not put sufficient information into the metadata to actually be able to load it as a type,
// the associated generic type/method needs to be baked first. So we return this rather than the baked type.
return this;
}
else
{
// Check for global typebuilder
if (((m_tdType & 0x00FFFFFF) != 0) && ((tkParent & 0x00FFFFFF) != 0))
{
SetParentType(new QCallModule(ref module), m_tdType, tkParent);
}
if (m_inst != null)
{
foreach (RuntimeGenericTypeParameterBuilder tb in m_inst)
{
tb.m_type.CreateType();
}
}
}
if (!m_isHiddenGlobalType)
{
// create a public default constructor if this class has no constructor.
// except if the type is Interface, ValueType, Enum, or a static class.
if (m_constructorCount == 0 && ((m_iAttr & TypeAttributes.Interface) == 0) && !IsValueType && ((m_iAttr & (TypeAttributes.Abstract | TypeAttributes.Sealed)) != (TypeAttributes.Abstract | TypeAttributes.Sealed)))
{
DefineDefaultConstructor(MethodAttributes.Public);
}
}
int size = m_listMethods!.Count;
for (int i = 0; i < size; i++)
{
RuntimeMethodBuilder meth = m_listMethods[i];
if (meth.IsGenericMethodDefinition)
{
_ = meth.MetadataToken; // Doubles as "CreateMethod" for MethodBuilder -- analogous to CreateType()
}
MethodAttributes methodAttrs = meth.Attributes;
// Any of these flags in the implementation flags is set, we will not attach the IL method body
if (((meth.GetMethodImplementationFlags() & (MethodImplAttributes.CodeTypeMask | MethodImplAttributes.PreserveSig | MethodImplAttributes.Unmanaged)) != MethodImplAttributes.IL) ||
((methodAttrs & MethodAttributes.PinvokeImpl) != (MethodAttributes)0))
{
continue;
}
byte[] localSig = meth.GetLocalSignature(out int sigLength);
// Check that they haven't declared an abstract method on a non-abstract class
if (((methodAttrs & MethodAttributes.Abstract) != 0) && ((m_iAttr & TypeAttributes.Abstract) == 0))
{
throw new InvalidOperationException(SR.InvalidOperation_BadTypeAttributesNotAbstract);
}
byte[]? body = meth.GetBody();
// If this is an abstract method or an interface, we don't need to set the IL.
if ((methodAttrs & MethodAttributes.Abstract) != 0)
{
// We won't check on Interface because we can have class static initializer on interface.
// We will just let EE or validator to catch the problem.
// ((m_iAttr & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface))
if (body != null)
throw new InvalidOperationException(SR.Format(SR.InvalidOperation_BadMethodBody, meth.Name));
}
else if (body == null || body.Length == 0)
{
// If it's not an abstract or an interface, set the IL.
if (meth.m_ilGenerator != null)
{
// we need to bake the method here.
meth.CreateMethodBodyHelper(((RuntimeILGenerator)meth.GetILGenerator()));
}
body = meth.GetBody();
if ((body == null || body.Length == 0) && !meth.m_canBeRuntimeImpl)
throw new InvalidOperationException(
SR.Format(SR.InvalidOperation_BadEmptyMethodBody, meth.Name));
}
int maxStack = meth.GetMaxStack();
ExceptionHandler[]? exceptions = meth.GetExceptionHandlers();
int[]? tokenFixups = meth.GetTokenFixups();
SetMethodIL(new QCallModule(ref module), meth.MetadataToken, meth.InitLocals,
body, (body != null) ? body.Length : 0,
localSig, sigLength, maxStack,
exceptions, (exceptions != null) ? exceptions.Length : 0,
tokenFixups, (tokenFixups != null) ? tokenFixups.Length : 0);
if (m_module.ContainingAssemblyBuilder._access == AssemblyBuilderAccess.Run)
{
// if we don't need the data structures to build the method any more
// throw them away.
meth.ReleaseBakedStructures();
}
}
m_hasBeenCreated = true;
// Terminate the process.
RuntimeType? cls = null;
TermCreateClass(new QCallModule(ref module), m_tdType, ObjectHandleOnStack.Create(ref cls));
if (!m_isHiddenGlobalType)
{
m_bakedRuntimeType = cls!;
// if this type is a nested type, we need to invalidate the cached nested runtime type on the nesting type
if (m_DeclaringType != null && m_DeclaringType.m_bakedRuntimeType != null)
{
m_DeclaringType.m_bakedRuntimeType.InvalidateCachedNestedType();
}
return cls;
}
else
{
return null;
}
}
#endregion
#region Misc
protected override int SizeCore => m_iTypeSize;
protected override PackingSize PackingSizeCore => m_iPackingSize;
protected override void SetParentCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type? parent)
{
ThrowIfCreated();
if (parent != null)
{
if (parent.IsInterface)
throw new ArgumentException(SR.Argument_CannotSetParentToInterface);
m_typeParent = parent;
}
else
{
if ((m_iAttr & TypeAttributes.Interface) != TypeAttributes.Interface)
{
m_typeParent = typeof(object);
}
else
{
if ((m_iAttr & TypeAttributes.Abstract) == 0)
throw new InvalidOperationException(SR.InvalidOperation_BadInterfaceNotAbstract);
// there is no extends for interface class
m_typeParent = null;
}
}
}
protected override void AddInterfaceImplementationCore([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type interfaceType)
{
ThrowIfCreated();
int tkInterface = m_module.GetTypeTokenInternal(interfaceType);
RuntimeModuleBuilder module = m_module;
AddInterfaceImpl(new QCallModule(ref module), m_tdType, tkInterface);
m_typeInterfaces!.Add(interfaceType);
}
internal int TypeToken
{
get
{
if (IsGenericParameter)
ThrowIfCreated();
return m_tdType;
}
}
internal void SetCustomAttribute(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
SetCustomAttributeCore(con, binaryAttribute);
}
protected override void SetCustomAttributeCore(ConstructorInfo con, ReadOnlySpan<byte> binaryAttribute)
{
DefineCustomAttribute(m_module, m_tdType, m_module.GetMethodMetadataToken(con), binaryAttribute);
}
#endregion
#endregion
}
}
|