|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Loader;
using System.Runtime.Serialization;
using System.Runtime.Versioning;
using System.Threading;
namespace System
{
[NonVersionable]
public unsafe partial struct RuntimeTypeHandle : IEquatable<RuntimeTypeHandle>, ISerializable
{
// Returns handle for interop with EE. The handle is guaranteed to be non-null.
internal RuntimeTypeHandle GetNativeHandle() =>
new RuntimeTypeHandle(GetRuntimeTypeChecked());
// Returns type for interop with EE. The type is guaranteed to be non-null.
internal RuntimeType GetRuntimeTypeChecked() =>
m_type ?? throw new ArgumentNullException(null, SR.Arg_InvalidHandle);
/// <summary>
/// Returns a new <see cref="RuntimeTypeHandle"/> object created from a handle to a RuntimeType.
/// </summary>
/// <param name="value">An IntPtr handle to a RuntimeType to create a <see cref="RuntimeTypeHandle"/> object from.</param>
/// <returns>A new <see cref="RuntimeTypeHandle"/> object that corresponds to the value parameter.</returns>
public static RuntimeTypeHandle FromIntPtr(IntPtr value) =>
new RuntimeTypeHandle(value == IntPtr.Zero ? null : GetRuntimeTypeFromHandle(value));
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow")]
private static partial void GetRuntimeTypeFromHandleSlow(
IntPtr handle,
ObjectHandleOnStack typeObject);
[MethodImpl(MethodImplOptions.NoInlining)]
private static RuntimeType GetRuntimeTypeFromHandleSlow(IntPtr handle)
{
RuntimeType? typeObject = null;
GetRuntimeTypeFromHandleSlow(handle, ObjectHandleOnStack.Create(ref typeObject));
return typeObject!;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern RuntimeType? GetRuntimeTypeFromHandleIfExists(IntPtr handle);
private static RuntimeType GetRuntimeTypeFromHandle(IntPtr handle)
{
return GetRuntimeTypeFromHandleIfExists(handle) ?? GetRuntimeTypeFromHandleSlow(handle);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe RuntimeType GetRuntimeType(MethodTable* pMT)
{
return pMT->AuxiliaryData->ExposedClassObject ?? GetRuntimeTypeFromHandleSlow((IntPtr)pMT);
}
/// <summary>
/// Returns the internal pointer representation of a <see cref="RuntimeTypeHandle"/> object.
/// </summary>
/// <param name="value">A <see cref="RuntimeTypeHandle"/> object to retrieve an internal pointer representation from.</param>
/// <returns>An <see cref="IntPtr"/> object that represents a <see cref="RuntimeTypeHandle"/> object.</returns>
[Intrinsic]
public static IntPtr ToIntPtr(RuntimeTypeHandle value) => value.Value;
public static bool operator ==(RuntimeTypeHandle left, object? right) => left.Equals(right);
public static bool operator ==(object? left, RuntimeTypeHandle right) => right.Equals(left);
public static bool operator !=(RuntimeTypeHandle left, object? right) => !left.Equals(right);
public static bool operator !=(object? left, RuntimeTypeHandle right) => !right.Equals(left);
// This is the RuntimeType for the type
internal RuntimeType? m_type;
public override int GetHashCode()
=> m_type?.GetHashCode() ?? 0;
public override bool Equals(object? obj)
=> (obj is RuntimeTypeHandle handle) && ReferenceEquals(handle.m_type, m_type);
public bool Equals(RuntimeTypeHandle handle)
=> ReferenceEquals(handle.m_type, m_type);
public IntPtr Value => m_type?.m_handle ?? 0;
internal RuntimeTypeHandle(RuntimeType? type)
{
m_type = type;
}
internal bool IsNullHandle()
{
return m_type == null;
}
internal static bool IsTypeDefinition(RuntimeType type)
{
CorElementType corElemType = type.GetCorElementType();
if (!((corElemType >= CorElementType.ELEMENT_TYPE_VOID && corElemType < CorElementType.ELEMENT_TYPE_PTR) ||
corElemType == CorElementType.ELEMENT_TYPE_VALUETYPE ||
corElemType == CorElementType.ELEMENT_TYPE_CLASS ||
corElemType == CorElementType.ELEMENT_TYPE_TYPEDBYREF ||
corElemType == CorElementType.ELEMENT_TYPE_I ||
corElemType == CorElementType.ELEMENT_TYPE_U ||
corElemType == CorElementType.ELEMENT_TYPE_OBJECT))
return false;
if (type.IsConstructedGenericType)
return false;
return true;
}
internal static bool IsPrimitive(RuntimeType type)
{
return RuntimeHelpers.IsPrimitiveType(type.GetCorElementType());
}
internal static bool IsByRef(RuntimeType type)
{
CorElementType corElemType = type.GetCorElementType();
return corElemType == CorElementType.ELEMENT_TYPE_BYREF;
}
internal static bool IsPointer(RuntimeType type)
{
CorElementType corElemType = type.GetCorElementType();
return corElemType == CorElementType.ELEMENT_TYPE_PTR;
}
internal static bool IsArray(RuntimeType type)
{
CorElementType corElemType = type.GetCorElementType();
return corElemType == CorElementType.ELEMENT_TYPE_ARRAY || corElemType == CorElementType.ELEMENT_TYPE_SZARRAY;
}
internal static bool IsSZArray(RuntimeType type)
{
CorElementType corElemType = type.GetCorElementType();
return corElemType == CorElementType.ELEMENT_TYPE_SZARRAY;
}
internal static bool IsFunctionPointer(RuntimeType type)
{
CorElementType corElemType = type.GetCorElementType();
return corElemType == CorElementType.ELEMENT_TYPE_FNPTR;
}
internal static bool HasElementType(RuntimeType type)
{
CorElementType corElemType = type.GetCorElementType();
return corElemType == CorElementType.ELEMENT_TYPE_ARRAY || corElemType == CorElementType.ELEMENT_TYPE_SZARRAY // IsArray
|| (corElemType == CorElementType.ELEMENT_TYPE_PTR) // IsPointer
|| (corElemType == CorElementType.ELEMENT_TYPE_BYREF); // IsByRef
}
// ** WARNING **
// Caller bears responsibility for ensuring that the provided Types remain
// GC-reachable while the unmanaged handles are being manipulated. The caller
// may need to make a defensive copy of the input array to ensure it's not
// mutated by another thread, and this defensive copy should be passed to
// a KeepAlive routine.
internal static ReadOnlySpan<IntPtr> CopyRuntimeTypeHandles(RuntimeTypeHandle[]? inHandles, Span<IntPtr> stackScratch)
{
if (inHandles == null || inHandles.Length == 0)
{
return default;
}
Span<IntPtr> outHandles = inHandles.Length <= stackScratch.Length ?
stackScratch.Slice(0, inHandles.Length) :
new IntPtr[inHandles.Length];
for (int i = 0; i < inHandles.Length; i++)
{
outHandles[i] = inHandles[i].Value;
}
return outHandles;
}
// ** WARNING **
// Caller bears responsibility for ensuring that the provided Types remain
// GC-reachable while the unmanaged handles are being manipulated. The caller
// may need to make a defensive copy of the input array to ensure it's not
// mutated by another thread, and this defensive copy should be passed to
// a KeepAlive routine.
internal static IntPtr[]? CopyRuntimeTypeHandles(Type[]? inHandles, out int length)
{
if (inHandles == null || inHandles.Length == 0)
{
length = 0;
return null;
}
IntPtr[] outHandles = new IntPtr[inHandles.Length];
for (int i = 0; i < inHandles.Length; i++)
{
outHandles[i] = inHandles[i].TypeHandle.Value;
}
length = outHandles.Length;
return outHandles;
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:ParameterDoesntMeetParameterRequirements",
Justification = "The parameter 'type' is passed by ref to QCallTypeHandle which only instantiates" +
"the type using the public parameterless constructor and doesn't modify it")]
internal static object CreateInstanceForAnotherGenericParameter(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type,
RuntimeType genericParameter)
{
Debug.Assert(type.GetConstructor(Type.EmptyTypes) is ConstructorInfo c && c.IsPublic,
$"CreateInstanceForAnotherGenericParameter requires {nameof(type)} to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors.");
object? instantiatedObject = null;
IntPtr typeHandle = genericParameter.TypeHandle.Value;
CreateInstanceForAnotherGenericParameter(
new QCallTypeHandle(ref type),
&typeHandle,
1,
ObjectHandleOnStack.Create(ref instantiatedObject));
GC.KeepAlive(genericParameter);
return instantiatedObject!;
}
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2067:ParameterDoesntMeetParameterRequirements",
Justification = "The parameter 'type' is passed by ref to QCallTypeHandle which only instantiates" +
"the type using the public parameterless constructor and doesn't modify it")]
internal static object CreateInstanceForAnotherGenericParameter(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] RuntimeType type,
RuntimeType genericParameter1,
RuntimeType genericParameter2)
{
Debug.Assert(type.GetConstructor(Type.EmptyTypes) is ConstructorInfo c && c.IsPublic,
$"CreateInstanceForAnotherGenericParameter requires {nameof(type)} to have a public parameterless constructor so it can be annotated for trimming without preserving private constructors.");
object? instantiatedObject = null;
IntPtr* pTypeHandles = stackalloc IntPtr[]
{
genericParameter1.TypeHandle.Value,
genericParameter2.TypeHandle.Value
};
CreateInstanceForAnotherGenericParameter(
new QCallTypeHandle(ref type),
pTypeHandles,
2,
ObjectHandleOnStack.Create(ref instantiatedObject));
GC.KeepAlive(genericParameter1);
GC.KeepAlive(genericParameter2);
return instantiatedObject!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_CreateInstanceForAnotherGenericParameter")]
private static partial void CreateInstanceForAnotherGenericParameter(
QCallTypeHandle baseType,
IntPtr* pTypeHandles,
int cTypeHandles,
ObjectHandleOnStack instantiatedObject);
internal static unsafe object InternalAlloc(MethodTable* pMT)
{
object? result = null;
InternalAlloc(pMT, ObjectHandleOnStack.Create(ref result));
return result!;
}
internal static object InternalAlloc(RuntimeType type)
{
Debug.Assert(!type.GetNativeTypeHandle().IsTypeDesc);
object result = InternalAlloc(type.GetNativeTypeHandle().AsMethodTable());
GC.KeepAlive(type);
return result;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAlloc")]
private static unsafe partial void InternalAlloc(MethodTable* pMT, ObjectHandleOnStack result);
internal static object InternalAllocNoChecks(RuntimeType type)
{
Debug.Assert(!type.GetNativeTypeHandle().IsTypeDesc);
object? result = null;
InternalAllocNoChecks(type.GetNativeTypeHandle().AsMethodTable(), ObjectHandleOnStack.Create(ref result));
GC.KeepAlive(type);
return result!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_InternalAllocNoChecks")]
private static unsafe partial void InternalAllocNoChecks(MethodTable* pMT, ObjectHandleOnStack result);
/// <summary>
/// Given a RuntimeType, returns information about how to activate it via calli
/// semantics. This method will ensure the type object is fully initialized within
/// the VM, but it will not call any static ctors on the type.
/// </summary>
internal static void GetActivationInfo(
RuntimeType rt,
out delegate*<void*, object> pfnAllocator,
out void* vAllocatorFirstArg,
out delegate*<object, void> pfnRefCtor,
out delegate*<ref byte, void> pfnValueCtor,
out bool ctorIsPublic)
{
Debug.Assert(rt != null);
delegate*<void*, object> pfnAllocatorTemp = default;
void* vAllocatorFirstArgTemp = default;
delegate*<object, void> pfnRefCtorTemp = default;
delegate*<ref byte, void> pfnValueCtorTemp = default;
Interop.BOOL fCtorIsPublicTemp = default;
GetActivationInfo(
ObjectHandleOnStack.Create(ref rt),
&pfnAllocatorTemp, &vAllocatorFirstArgTemp,
&pfnRefCtorTemp, &pfnValueCtorTemp, &fCtorIsPublicTemp);
pfnAllocator = pfnAllocatorTemp;
vAllocatorFirstArg = vAllocatorFirstArgTemp;
pfnRefCtor = pfnRefCtorTemp;
pfnValueCtor = pfnValueCtorTemp;
ctorIsPublic = fCtorIsPublicTemp != Interop.BOOL.FALSE;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetActivationInfo")]
private static partial void GetActivationInfo(
ObjectHandleOnStack pRuntimeType,
delegate*<void*, object>* ppfnAllocator,
void** pvAllocatorFirstArg,
delegate*<object, void>* ppfnRefCtor,
delegate*<ref byte, void>* ppfnValueCtor,
Interop.BOOL* pfCtorIsPublic);
#if FEATURE_COMINTEROP
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_AllocateComObject")]
private static partial void AllocateComObject(void* pClassFactory, ObjectHandleOnStack result);
// Referenced by unmanaged layer (see GetActivationInfo).
// First parameter is ComClassFactory*.
private static object AllocateComObject(void* pClassFactory)
{
object? result = null;
AllocateComObject(pClassFactory, ObjectHandleOnStack.Create(ref result));
return result!;
}
#endif // FEATURE_COMINTEROP
internal RuntimeType GetRuntimeType()
{
return m_type!;
}
internal static RuntimeAssembly GetAssembly(RuntimeType type)
{
return GetAssemblyIfExists(type) ?? GetAssemblyWorker(type);
[MethodImpl(MethodImplOptions.NoInlining)]
static RuntimeAssembly GetAssemblyWorker(RuntimeType type)
{
RuntimeAssembly? assembly = null;
GetAssemblySlow(ObjectHandleOnStack.Create(ref type), ObjectHandleOnStack.Create(ref assembly));
return assembly!;
}
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern RuntimeAssembly? GetAssemblyIfExists(RuntimeType type);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetAssemblySlow")]
private static partial void GetAssemblySlow(ObjectHandleOnStack type, ObjectHandleOnStack assembly);
internal static RuntimeModule GetModule(RuntimeType type)
{
return GetModuleIfExists(type) ?? GetModuleWorker(type);
[MethodImpl(MethodImplOptions.NoInlining)]
static RuntimeModule GetModuleWorker(RuntimeType type)
{
RuntimeModule? module = null;
GetModuleSlow(ObjectHandleOnStack.Create(ref type), ObjectHandleOnStack.Create(ref module));
return module!;
}
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern RuntimeModule? GetModuleIfExists(RuntimeType type);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetModuleSlow")]
private static partial void GetModuleSlow(ObjectHandleOnStack type, ObjectHandleOnStack module);
public ModuleHandle GetModuleHandle()
{
if (m_type is null)
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
return new ModuleHandle(GetModule(m_type));
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern TypeAttributes GetAttributes(RuntimeType type);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern IntPtr GetElementTypeHandle(IntPtr handle);
internal static RuntimeType? GetElementType(RuntimeType type)
{
IntPtr handle = GetElementTypeHandle(type.GetUnderlyingNativeHandle());
if (handle == IntPtr.Zero)
{
return null;
}
RuntimeType result = GetRuntimeTypeFromHandle(handle);
GC.KeepAlive(type);
return result;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool CompareCanonicalHandles(RuntimeType left, RuntimeType right);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetArrayRank(RuntimeType type);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetToken(RuntimeType type);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetMethodAt")]
private static unsafe partial IntPtr GetMethodAt(MethodTable* pMT, int slot);
internal static RuntimeMethodHandleInternal GetMethodAt(RuntimeType type, int slot)
{
TypeHandle typeHandle = type.GetNativeTypeHandle();
if (typeHandle.IsTypeDesc)
{
throw new ArgumentException(SR.Arg_InvalidHandle);
}
if (slot < 0)
{
throw new ArgumentException(SR.Arg_ArgumentOutOfRangeException);
}
return new RuntimeMethodHandleInternal(GetMethodAt(typeHandle.AsMethodTable(), slot));
}
internal static Type[] GetArgumentTypesFromFunctionPointer(RuntimeType type)
{
Debug.Assert(type.IsFunctionPointer);
Type[]? argTypes = null;
GetArgumentTypesFromFunctionPointer(new QCallTypeHandle(ref type), ObjectHandleOnStack.Create(ref argTypes));
return argTypes!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetArgumentTypesFromFunctionPointer")]
private static partial void GetArgumentTypesFromFunctionPointer(QCallTypeHandle type, ObjectHandleOnStack argTypes);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool IsUnmanagedFunctionPointer(RuntimeType type);
// This is managed wrapper for MethodTable::IntroducedMethodIterator
internal struct IntroducedMethodEnumerator
{
private bool _firstCall;
private RuntimeMethodHandleInternal _handle;
internal IntroducedMethodEnumerator(RuntimeType type)
{
_handle = GetFirstIntroducedMethod(type);
_firstCall = true;
}
public bool MoveNext()
{
if (_firstCall)
{
_firstCall = false;
}
else if (_handle.Value != IntPtr.Zero)
{
GetNextIntroducedMethod(ref _handle);
}
return !(_handle.Value == IntPtr.Zero);
}
public RuntimeMethodHandleInternal Current => _handle;
// Glue to make this work nicely with C# foreach statement
public IntroducedMethodEnumerator GetEnumerator()
{
return this;
}
}
internal static IntroducedMethodEnumerator GetIntroducedMethods(RuntimeType type)
{
return new IntroducedMethodEnumerator(type);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern RuntimeMethodHandleInternal GetFirstIntroducedMethod(RuntimeType type);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void GetNextIntroducedMethod(ref RuntimeMethodHandleInternal method);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetFields")]
private static partial Interop.BOOL GetFields(MethodTable* pMT, Span<IntPtr> data, ref int usedCount);
internal static bool GetFields(RuntimeType type, Span<IntPtr> buffer, out int count)
{
Debug.Assert(!IsGenericVariable(type));
TypeHandle typeHandle = type.GetNativeTypeHandle();
if (typeHandle.IsTypeDesc)
{
count = 0;
return true;
}
int countLocal = buffer.Length;
bool success = GetFields(typeHandle.AsMethodTable(), buffer, ref countLocal) != Interop.BOOL.FALSE;
GC.KeepAlive(type);
count = countLocal;
return success;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetInterfaces")]
private static unsafe partial void GetInterfaces(MethodTable* pMT, ObjectHandleOnStack result);
internal static Type[] GetInterfaces(RuntimeType type)
{
Debug.Assert(!IsGenericVariable(type));
TypeHandle typeHandle = type.GetNativeTypeHandle();
if (typeHandle.IsTypeDesc)
{
return [];
}
Type[] result = [];
GetInterfaces(typeHandle.AsMethodTable(), ObjectHandleOnStack.Create(ref result));
GC.KeepAlive(type);
return result;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetConstraints")]
private static partial void GetConstraints(QCallTypeHandle handle, ObjectHandleOnStack types);
internal Type[] GetConstraints()
{
Type[]? types = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
GetConstraints(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref types));
return types!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "QCall_GetGCHandleForTypeHandle")]
private static partial IntPtr GetGCHandle(QCallTypeHandle handle, GCHandleType type);
internal IntPtr GetGCHandle(GCHandleType type)
{
RuntimeTypeHandle nativeHandle = GetNativeHandle();
return GetGCHandle(new QCallTypeHandle(ref nativeHandle), type);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "QCall_FreeGCHandleForTypeHandle")]
private static partial IntPtr FreeGCHandle(QCallTypeHandle typeHandle, IntPtr objHandle);
internal IntPtr FreeGCHandle(IntPtr objHandle)
{
RuntimeTypeHandle nativeHandle = GetNativeHandle();
return FreeGCHandle(new QCallTypeHandle(ref nativeHandle), objHandle);
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetNumVirtuals(RuntimeType type);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetNumVirtualsAndStaticVirtuals")]
private static partial int GetNumVirtualsAndStaticVirtuals(QCallTypeHandle type);
internal static int GetNumVirtualsAndStaticVirtuals(RuntimeType type)
{
Debug.Assert(type != null);
return GetNumVirtualsAndStaticVirtuals(new QCallTypeHandle(ref type));
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_VerifyInterfaceIsImplemented")]
private static partial void VerifyInterfaceIsImplemented(QCallTypeHandle handle, QCallTypeHandle interfaceHandle);
internal void VerifyInterfaceIsImplemented(RuntimeTypeHandle interfaceHandle)
{
RuntimeTypeHandle nativeHandle = GetNativeHandle();
RuntimeTypeHandle nativeInterfaceHandle = interfaceHandle.GetNativeHandle();
VerifyInterfaceIsImplemented(new QCallTypeHandle(ref nativeHandle), new QCallTypeHandle(ref nativeInterfaceHandle));
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetInterfaceMethodImplementation")]
private static partial RuntimeMethodHandleInternal GetInterfaceMethodImplementation(QCallTypeHandle handle, QCallTypeHandle interfaceHandle, RuntimeMethodHandleInternal interfaceMethodHandle);
internal RuntimeMethodHandleInternal GetInterfaceMethodImplementation(RuntimeTypeHandle interfaceHandle, RuntimeMethodHandleInternal interfaceMethodHandle)
{
RuntimeTypeHandle nativeHandle = GetNativeHandle();
RuntimeTypeHandle nativeInterfaceHandle = interfaceHandle.GetNativeHandle();
return GetInterfaceMethodImplementation(new QCallTypeHandle(ref nativeHandle), new QCallTypeHandle(ref nativeInterfaceHandle), interfaceMethodHandle);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_IsVisible")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool _IsVisible(QCallTypeHandle typeHandle);
internal static bool IsVisible(RuntimeType type)
{
return _IsVisible(new QCallTypeHandle(ref type));
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_ConstructName")]
private static partial void ConstructName(QCallTypeHandle handle, TypeNameFormatFlags formatFlags, StringHandleOnStack retString);
internal string ConstructName(TypeNameFormatFlags formatFlags)
{
string? name = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
ConstructName(new QCallTypeHandle(ref nativeHandle), formatFlags, new StringHandleOnStack(ref name));
return name!;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe void* GetUtf8NameInternal(MethodTable* pMT);
// Since the returned string is a pointer into metadata, the caller should
// ensure the passed in type is alive for at least as long as returned result is
// needed.
internal static unsafe MdUtf8String GetUtf8Name(RuntimeType type)
{
TypeHandle th = type.GetNativeTypeHandle();
if (th.IsTypeDesc || th.AsMethodTable()->IsArray)
{
throw new ArgumentException(SR.Arg_InvalidHandle);
}
void* name = GetUtf8NameInternal(th.AsMethodTable());
if (name is null)
{
throw new BadImageFormatException();
}
return new MdUtf8String(name);
}
internal static bool CanCastTo(RuntimeType type, RuntimeType target)
{
bool ret = TypeHandle.CanCastToForReflection(type.GetNativeTypeHandle(), target.GetNativeTypeHandle());
GC.KeepAlive(type);
GC.KeepAlive(target);
return ret;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetDeclaringTypeHandleForGenericVariable")]
private static partial IntPtr GetDeclaringTypeHandleForGenericVariable(IntPtr typeHandle);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetDeclaringTypeHandle")]
private static partial IntPtr GetDeclaringTypeHandle(IntPtr typeHandle);
internal static unsafe RuntimeType? GetDeclaringType(RuntimeType type)
{
IntPtr retTypeHandle = IntPtr.Zero;
TypeHandle typeHandle = type.GetNativeTypeHandle();
if (typeHandle.IsTypeDesc)
{
CorElementType elementType = (CorElementType)typeHandle.GetCorElementType();
if (elementType is CorElementType.ELEMENT_TYPE_VAR or CorElementType.ELEMENT_TYPE_MVAR)
{
retTypeHandle = GetDeclaringTypeHandleForGenericVariable(type.GetUnderlyingNativeHandle());
}
}
else
{
retTypeHandle = GetDeclaringTypeHandle(type.GetUnderlyingNativeHandle());
}
if (retTypeHandle == IntPtr.Zero)
{
return null;
}
RuntimeType result = GetRuntimeTypeFromHandle(retTypeHandle);
GC.KeepAlive(type);
return result;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetDeclaringMethodForGenericParameter")]
private static partial void GetDeclaringMethodForGenericParameter(QCallTypeHandle typeHandle, ObjectHandleOnStack result);
internal static IRuntimeMethodInfo? GetDeclaringMethodForGenericParameter(RuntimeType type)
{
Debug.Assert(IsGenericVariable(type));
IRuntimeMethodInfo? method = null;
GetDeclaringMethodForGenericParameter(new QCallTypeHandle(ref type), ObjectHandleOnStack.Create(ref method));
return method;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetInstantiation")]
internal static partial void GetInstantiation(QCallTypeHandle type, ObjectHandleOnStack types, Interop.BOOL fAsRuntimeTypeArray);
internal RuntimeType[] GetInstantiationInternal()
{
RuntimeType[]? types = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
GetInstantiation(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref types), Interop.BOOL.TRUE);
return types!;
}
internal Type[] GetInstantiationPublic()
{
Type[]? types = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
GetInstantiation(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref types), Interop.BOOL.FALSE);
return types!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_Instantiate")]
private static partial void Instantiate(QCallTypeHandle handle, IntPtr* pInst, int numGenericArgs, ObjectHandleOnStack type);
internal RuntimeType Instantiate(RuntimeType inst)
{
IntPtr ptr = inst.TypeHandle.Value;
RuntimeType? type = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
Instantiate(new QCallTypeHandle(ref nativeHandle), &ptr, 1, ObjectHandleOnStack.Create(ref type));
GC.KeepAlive(inst);
return type!;
}
internal RuntimeType Instantiate(Type[]? inst)
{
IntPtr[]? instHandles = CopyRuntimeTypeHandles(inst, out int instCount);
fixed (IntPtr* pInst = instHandles)
{
RuntimeType? type = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
Instantiate(new QCallTypeHandle(ref nativeHandle), pInst, instCount, ObjectHandleOnStack.Create(ref type));
GC.KeepAlive(inst);
return type!;
}
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_MakeArray")]
private static partial void MakeArray(QCallTypeHandle handle, int rank, ObjectHandleOnStack type);
internal RuntimeType MakeArray(int rank)
{
RuntimeType? type = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
MakeArray(new QCallTypeHandle(ref nativeHandle), rank, ObjectHandleOnStack.Create(ref type));
return type!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_MakeSZArray")]
private static partial void MakeSZArray(QCallTypeHandle handle, ObjectHandleOnStack type);
internal RuntimeType MakeSZArray()
{
RuntimeType? type = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
MakeSZArray(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref type));
return type!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_MakeByRef")]
private static partial void MakeByRef(QCallTypeHandle handle, ObjectHandleOnStack type);
internal RuntimeType MakeByRef()
{
RuntimeType? type = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
MakeByRef(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref type));
return type!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_MakePointer")]
private static partial void MakePointer(QCallTypeHandle handle, ObjectHandleOnStack type);
internal RuntimeType MakePointer()
{
RuntimeType? type = null;
RuntimeTypeHandle nativeHandle = GetNativeHandle();
MakePointer(new QCallTypeHandle(ref nativeHandle), ObjectHandleOnStack.Create(ref type));
return type!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_IsCollectible")]
internal static partial Interop.BOOL IsCollectible(QCallTypeHandle handle);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetGenericTypeDefinition")]
internal static partial void GetGenericTypeDefinition(QCallTypeHandle type, ObjectHandleOnStack retType);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool IsGenericVariable(RuntimeType type);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int GetGenericVariableIndex(RuntimeType type);
internal int GetGenericVariableIndex()
{
RuntimeType type = GetRuntimeTypeChecked();
if (!IsGenericVariable(type))
throw new InvalidOperationException(SR.Arg_NotGenericParameter);
return GetGenericVariableIndex(type);
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool ContainsGenericVariables(RuntimeType handle);
internal bool ContainsGenericVariables()
{
return ContainsGenericVariables(GetRuntimeTypeChecked());
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_SatisfiesConstraints")]
private static partial Interop.BOOL SatisfiesConstraints(QCallTypeHandle paramType, QCallTypeHandle pTypeContext, RuntimeMethodHandleInternal pMethodContext, QCallTypeHandle toType);
internal static bool SatisfiesConstraints(RuntimeType paramType, RuntimeType? typeContext, RuntimeMethodInfo? methodContext, RuntimeType toType)
{
RuntimeMethodHandleInternal methodContextRaw = ((IRuntimeMethodInfo?)methodContext)?.Value ?? RuntimeMethodHandleInternal.EmptyHandle;
bool result = SatisfiesConstraints(new QCallTypeHandle(ref paramType), new QCallTypeHandle(ref typeContext!), methodContextRaw, new QCallTypeHandle(ref toType)) != Interop.BOOL.FALSE;
GC.KeepAlive(methodContext);
return result;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_RegisterCollectibleTypeDependency")]
private static partial void RegisterCollectibleTypeDependency(QCallTypeHandle type, QCallAssembly assembly);
internal static void RegisterCollectibleTypeDependency(RuntimeType type, RuntimeAssembly? assembly)
{
RegisterCollectibleTypeDependency(new QCallTypeHandle(ref type), new QCallAssembly(ref assembly!));
}
[Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new PlatformNotSupportedException();
}
#if FEATURE_TYPEEQUIVALENCE
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_IsEquivalentTo")]
private static partial Interop.BOOL IsEquivalentTo(QCallTypeHandle rtType1, QCallTypeHandle rtType2);
internal static bool IsEquivalentTo(RuntimeType rtType1, RuntimeType rtType2)
=> IsEquivalentTo(new QCallTypeHandle(ref rtType1), new QCallTypeHandle(ref rtType2)) == Interop.BOOL.TRUE;
#endif // FEATURE_TYPEEQUIVALENCE
}
// This type is used to remove the expense of having a managed reference object that is dynamically
// created when we can prove that we don't need that object. Use of this type requires code to ensure
// that the underlying native resource is not freed.
// Cases in which this may be used:
// 1. When native code calls managed code passing one of these as a parameter
// 2. When managed code acquires one of these from an IRuntimeMethodInfo, and ensure that the IRuntimeMethodInfo is preserved
// across the lifetime of the RuntimeMethodHandleInternal instance
// 3. When another object is used to keep the RuntimeMethodHandleInternal alive. See delegates, CreateInstance cache, Signature structure
// When in doubt, do not use.
internal struct RuntimeMethodHandleInternal
{
internal static RuntimeMethodHandleInternal EmptyHandle => default;
internal bool IsNullHandle()
{
return m_handle == IntPtr.Zero;
}
internal IntPtr Value => m_handle;
internal RuntimeMethodHandleInternal(IntPtr value)
{
m_handle = value;
}
private IntPtr m_handle;
}
internal sealed class RuntimeMethodInfoStub : IRuntimeMethodInfo
{
public RuntimeMethodInfoStub(RuntimeMethodHandleInternal methodHandleValue, object keepalive)
{
m_keepalive = keepalive;
m_value = methodHandleValue;
}
public RuntimeMethodInfoStub(IntPtr methodHandleValue, object keepalive)
{
m_keepalive = keepalive;
m_value = new RuntimeMethodHandleInternal(methodHandleValue);
}
private readonly object m_keepalive;
// These unused variables are used to ensure that this class has the same layout as RuntimeMethodInfo
#pragma warning disable CA1823, 414, 169, IDE0044
private object? m_a;
private object? m_b;
private object? m_c;
private object? m_d;
private object? m_e;
private object? m_f;
private object? m_g;
private object? m_h;
#pragma warning restore CA1823, 414, 169, IDE0044
public RuntimeMethodHandleInternal m_value;
RuntimeMethodHandleInternal IRuntimeMethodInfo.Value => m_value;
}
internal interface IRuntimeMethodInfo
{
RuntimeMethodHandleInternal Value
{
get;
}
}
[NonVersionable]
public unsafe partial struct RuntimeMethodHandle : IEquatable<RuntimeMethodHandle>, ISerializable
{
// Returns handle for interop with EE. The handle is guaranteed to be non-null.
internal static IRuntimeMethodInfo EnsureNonNullMethodInfo(IRuntimeMethodInfo method)
{
if (method == null)
throw new ArgumentNullException(null, SR.Arg_InvalidHandle);
return method;
}
private readonly IRuntimeMethodInfo m_value;
internal RuntimeMethodHandle(IRuntimeMethodInfo method)
{
m_value = method;
}
internal IRuntimeMethodInfo GetMethodInfo()
{
return m_value;
}
// ISerializable interface
[Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new PlatformNotSupportedException();
}
public IntPtr Value => m_value != null ? m_value.Value.Value : IntPtr.Zero;
public override int GetHashCode()
{
return HashCode.Combine(Value);
}
public override bool Equals(object? obj)
{
if (obj is not RuntimeMethodHandle)
return false;
RuntimeMethodHandle handle = (RuntimeMethodHandle)obj;
return handle.Value == Value;
}
/// <summary>
/// Returns a new <see cref="RuntimeMethodHandle"/> object created from a handle to a RuntimeMethodInfo.
/// </summary>
/// <param name="value">An IntPtr handle to a RuntimeMethodInfo to create a <see cref="RuntimeMethodHandle"/> object from.</param>
/// <returns>A new <see cref="RuntimeMethodHandle"/> object that corresponds to the value parameter.</returns>
public static RuntimeMethodHandle FromIntPtr(IntPtr value)
{
var handle = new RuntimeMethodHandleInternal(value);
var methodInfo = new RuntimeMethodInfoStub(handle, GetLoaderAllocator(handle));
return new RuntimeMethodHandle(methodInfo);
}
/// <summary>
/// Returns the internal pointer representation of a <see cref="RuntimeMethodHandle"/> object.
/// </summary>
/// <param name="value">A <see cref="RuntimeMethodHandle"/> object to retrieve an internal pointer representation from.</param>
/// <returns>An <see cref="IntPtr"/> object that represents a <see cref="RuntimeMethodHandle"/> object.</returns>
public static IntPtr ToIntPtr(RuntimeMethodHandle value) => value.Value;
public static bool operator ==(RuntimeMethodHandle left, RuntimeMethodHandle right) => left.Equals(right);
public static bool operator !=(RuntimeMethodHandle left, RuntimeMethodHandle right) => !left.Equals(right);
public bool Equals(RuntimeMethodHandle handle)
{
return handle.Value == Value;
}
internal bool IsNullHandle()
{
return m_value == null;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_GetFunctionPointer")]
internal static partial IntPtr GetFunctionPointer(RuntimeMethodHandleInternal handle);
public IntPtr GetFunctionPointer()
{
IntPtr ptr = GetFunctionPointer(EnsureNonNullMethodInfo(m_value!).Value);
GC.KeepAlive(m_value);
return ptr;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_GetIsCollectible")]
internal static partial Interop.BOOL GetIsCollectible(RuntimeMethodHandleInternal handle);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_IsCAVisibleFromDecoratedType")]
internal static partial Interop.BOOL IsCAVisibleFromDecoratedType(
QCallTypeHandle attrTypeHandle,
RuntimeMethodHandleInternal attrCtor,
QCallTypeHandle sourceTypeHandle,
QCallModule sourceModule);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern MethodAttributes GetAttributes(RuntimeMethodHandleInternal method);
internal static MethodAttributes GetAttributes(IRuntimeMethodInfo method)
{
MethodAttributes retVal = GetAttributes(method.Value);
GC.KeepAlive(method);
return retVal;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern MethodImplAttributes GetImplAttributes(IRuntimeMethodInfo method);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_ConstructInstantiation")]
private static partial void ConstructInstantiation(RuntimeMethodHandleInternal method, TypeNameFormatFlags format, StringHandleOnStack retString);
internal static string ConstructInstantiation(IRuntimeMethodInfo method, TypeNameFormatFlags format)
{
string? name = null;
IRuntimeMethodInfo methodInfo = EnsureNonNullMethodInfo(method);
ConstructInstantiation(methodInfo.Value, format, new StringHandleOnStack(ref name));
GC.KeepAlive(methodInfo);
return name!;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe MethodTable* GetMethodTable(RuntimeMethodHandleInternal method);
internal static unsafe RuntimeType GetDeclaringType(RuntimeMethodHandleInternal method)
{
Debug.Assert(!method.IsNullHandle());
MethodTable* pMT = GetMethodTable(method);
return RuntimeTypeHandle.GetRuntimeType(pMT);
}
internal static RuntimeType GetDeclaringType(IRuntimeMethodInfo method)
{
RuntimeType type = GetDeclaringType(method.Value);
GC.KeepAlive(method);
return type;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetSlot(RuntimeMethodHandleInternal method);
internal static int GetSlot(IRuntimeMethodInfo method)
{
Debug.Assert(method != null);
int slot = GetSlot(method.Value);
GC.KeepAlive(method);
return slot;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int GetMethodDef(RuntimeMethodHandleInternal method);
internal static int GetMethodDef(IRuntimeMethodInfo method)
{
Debug.Assert(method != null);
int token = GetMethodDef(method.Value);
GC.KeepAlive(method);
return token;
}
internal static string GetName(RuntimeMethodHandleInternal method)
=> GetUtf8Name(method).ToString();
internal static string GetName(IRuntimeMethodInfo method)
{
string name = GetName(method.Value);
GC.KeepAlive(method);
return name;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void* GetUtf8NameInternal(RuntimeMethodHandleInternal method);
// Since the returned string is a pointer into metadata, the caller should
// ensure the passed in type is alive for at least as long as returned result is
// needed.
internal static MdUtf8String GetUtf8Name(RuntimeMethodHandleInternal method)
{
void* name = GetUtf8NameInternal(method);
if (name is null)
{
throw new BadImageFormatException();
}
return new MdUtf8String(name);
}
[DebuggerStepThrough]
[DebuggerHidden]
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_InvokeMethod")]
private static partial void InvokeMethod(ObjectHandleOnStack target, void** arguments, ObjectHandleOnStack sig, Interop.BOOL isConstructor, ObjectHandleOnStack result);
[DebuggerStepThrough]
[DebuggerHidden]
internal static object? InvokeMethod(object? target, void** arguments, Signature sig, bool isConstructor)
{
object? result = null;
InvokeMethod(
ObjectHandleOnStack.Create(ref target),
arguments,
ObjectHandleOnStack.Create(ref sig),
isConstructor ? Interop.BOOL.TRUE : Interop.BOOL.FALSE,
ObjectHandleOnStack.Create(ref result));
return result;
}
/// <summary>
/// For a true boxed Nullable{T}, re-box to a boxed {T} or null, otherwise just return the input.
/// </summary>
internal static object? ReboxFromNullable(object? src)
{
// If src is null or not NullableOfT, just return that state.
if (src is null)
{
return null;
}
MethodTable* pMT = RuntimeHelpers.GetMethodTable(src);
if (!pMT->IsNullable)
{
return src;
}
return CastHelpers.ReboxFromNullable(pMT, src);
}
/// <summary>
/// Convert a boxed value of {T} (which is either {T} or null) to a true boxed Nullable{T}.
/// </summary>
internal static object ReboxToNullable(object? src, RuntimeType destNullableType)
{
Debug.Assert(destNullableType.IsNullableOfT);
MethodTable* pMT = destNullableType.GetNativeTypeHandle().AsMethodTable();
object obj = RuntimeTypeHandle.InternalAlloc(pMT);
GC.KeepAlive(destNullableType); // The obj instance will keep the type alive.
CastHelpers.Unbox_Nullable(
ref obj.GetRawData(),
pMT,
src);
return obj;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_GetMethodInstantiation")]
private static partial void GetMethodInstantiation(RuntimeMethodHandleInternal method, ObjectHandleOnStack types, Interop.BOOL fAsRuntimeTypeArray);
internal static RuntimeType[] GetMethodInstantiationInternal(IRuntimeMethodInfo method)
{
RuntimeType[]? types = null;
GetMethodInstantiation(EnsureNonNullMethodInfo(method).Value, ObjectHandleOnStack.Create(ref types), Interop.BOOL.TRUE);
GC.KeepAlive(method);
return types!;
}
internal static RuntimeType[] GetMethodInstantiationInternal(RuntimeMethodHandleInternal method)
{
RuntimeType[]? types = null;
GetMethodInstantiation(method, ObjectHandleOnStack.Create(ref types), Interop.BOOL.TRUE);
return types!;
}
internal static Type[] GetMethodInstantiationPublic(IRuntimeMethodInfo method)
{
RuntimeType[]? types = null;
GetMethodInstantiation(EnsureNonNullMethodInfo(method).Value, ObjectHandleOnStack.Create(ref types), Interop.BOOL.FALSE);
GC.KeepAlive(method);
return types!;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool HasMethodInstantiation(RuntimeMethodHandleInternal method);
internal static bool HasMethodInstantiation(IRuntimeMethodInfo method)
{
bool fRet = HasMethodInstantiation(method.Value);
GC.KeepAlive(method);
return fRet;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern RuntimeMethodHandleInternal GetStubIfNeededInternal(RuntimeMethodHandleInternal method, RuntimeType declaringType);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_GetStubIfNeededSlow")]
private static partial RuntimeMethodHandleInternal GetStubIfNeededSlow(RuntimeMethodHandleInternal method, QCallTypeHandle declaringTypeHandle, ObjectHandleOnStack methodInstantiation);
internal static RuntimeMethodHandleInternal GetStubIfNeeded(RuntimeMethodHandleInternal method, RuntimeType declaringType, RuntimeType[]? methodInstantiation)
{
if (methodInstantiation is null)
{
RuntimeMethodHandleInternal handle = GetStubIfNeededInternal(method, declaringType);
if (!handle.IsNullHandle())
return handle;
}
return GetStubIfNeededWorker(method, declaringType, methodInstantiation);
[MethodImpl(MethodImplOptions.NoInlining)]
static RuntimeMethodHandleInternal GetStubIfNeededWorker(RuntimeMethodHandleInternal method, RuntimeType declaringType, RuntimeType[]? methodInstantiation)
=> GetStubIfNeededSlow(method, new QCallTypeHandle(ref declaringType), ObjectHandleOnStack.Create(ref methodInstantiation));
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern RuntimeMethodHandleInternal GetMethodFromCanonical(RuntimeMethodHandleInternal method, RuntimeType declaringType);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool IsGenericMethodDefinition(RuntimeMethodHandleInternal method);
internal static bool IsGenericMethodDefinition(IRuntimeMethodInfo method)
{
bool fRet = IsGenericMethodDefinition(method.Value);
GC.KeepAlive(method);
return fRet;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern bool IsTypicalMethodDefinition(IRuntimeMethodInfo method);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_GetTypicalMethodDefinition")]
private static partial void GetTypicalMethodDefinition(RuntimeMethodHandleInternal method, ObjectHandleOnStack outMethod);
internal static IRuntimeMethodInfo GetTypicalMethodDefinition(IRuntimeMethodInfo method)
{
if (!IsTypicalMethodDefinition(method))
{
GetTypicalMethodDefinition(method.Value, ObjectHandleOnStack.Create(ref method));
GC.KeepAlive(method);
}
return method;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int GetGenericParameterCount(RuntimeMethodHandleInternal method);
internal static int GetGenericParameterCount(IRuntimeMethodInfo method) => GetGenericParameterCount(method.Value);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_StripMethodInstantiation")]
private static partial void StripMethodInstantiation(RuntimeMethodHandleInternal method, ObjectHandleOnStack outMethod);
internal static IRuntimeMethodInfo StripMethodInstantiation(IRuntimeMethodInfo method)
{
IRuntimeMethodInfo strippedMethod = method;
StripMethodInstantiation(method.Value, ObjectHandleOnStack.Create(ref strippedMethod));
GC.KeepAlive(method);
return strippedMethod;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool IsDynamicMethod(RuntimeMethodHandleInternal method);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_Destroy")]
internal static partial void Destroy(RuntimeMethodHandleInternal method);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern Resolver GetResolver(RuntimeMethodHandleInternal method);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeMethodHandle_GetMethodBody")]
private static partial void GetMethodBody(RuntimeMethodHandleInternal method, QCallTypeHandle declaringType, ObjectHandleOnStack result);
internal static RuntimeMethodBody? GetMethodBody(IRuntimeMethodInfo method, RuntimeType declaringType)
{
RuntimeMethodBody? result = null;
GetMethodBody(method.Value, new QCallTypeHandle(ref declaringType), ObjectHandleOnStack.Create(ref result));
GC.KeepAlive(method);
return result;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool IsConstructor(RuntimeMethodHandleInternal method);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern LoaderAllocator GetLoaderAllocatorInternal(RuntimeMethodHandleInternal method);
internal static LoaderAllocator GetLoaderAllocator(RuntimeMethodHandleInternal method)
{
if (method.IsNullHandle())
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
return GetLoaderAllocatorInternal(method);
}
}
// This type is used to remove the expense of having a managed reference object that is dynamically
// created when we can prove that we don't need that object. Use of this type requires code to ensure
// that the underlying native resource is not freed.
// Cases in which this may be used:
// 1. When native code calls managed code passing one of these as a parameter
// 2. When managed code acquires one of these from an RtFieldInfo, and ensure that the RtFieldInfo is preserved
// across the lifetime of the RuntimeFieldHandleInternal instance
// 3. When another object is used to keep the RuntimeFieldHandleInternal alive.
// When in doubt, do not use.
internal struct RuntimeFieldHandleInternal
{
internal bool IsNullHandle()
{
return m_handle == IntPtr.Zero;
}
internal IntPtr Value => m_handle;
internal RuntimeFieldHandleInternal(IntPtr value)
{
m_handle = value;
}
internal IntPtr m_handle;
}
internal interface IRuntimeFieldInfo
{
RuntimeFieldHandleInternal Value
{
get;
}
}
[StructLayout(LayoutKind.Sequential)]
internal sealed class RuntimeFieldInfoStub : IRuntimeFieldInfo
{
public RuntimeFieldInfoStub(RuntimeFieldHandleInternal fieldHandle, object keepalive)
{
m_keepalive = keepalive;
m_fieldHandle = fieldHandle;
}
private readonly object m_keepalive;
// These unused variables are used to ensure that this class has the same layout as RuntimeFieldInfo
#pragma warning disable 414, 169, IDE0044
private object? m_c;
private object? m_d;
private int m_b;
private object? m_e;
private object? m_f;
private RuntimeFieldHandleInternal m_fieldHandle;
#pragma warning restore 414, 169, IDE0044
RuntimeFieldHandleInternal IRuntimeFieldInfo.Value => m_fieldHandle;
}
[NonVersionable]
public unsafe partial struct RuntimeFieldHandle : IEquatable<RuntimeFieldHandle>, ISerializable
{
// Returns handle for interop with EE. The handle is guaranteed to be non-null.
internal RuntimeFieldHandle GetNativeHandle() =>
new RuntimeFieldHandle(m_ptr ?? throw new ArgumentNullException(null, SR.Arg_InvalidHandle));
private readonly IRuntimeFieldInfo m_ptr;
internal RuntimeFieldHandle(IRuntimeFieldInfo fieldInfo)
{
m_ptr = fieldInfo;
}
internal IRuntimeFieldInfo GetRuntimeFieldInfo()
{
return m_ptr;
}
public IntPtr Value => m_ptr != null ? m_ptr.Value.Value : IntPtr.Zero;
internal bool IsNullHandle()
{
return m_ptr == null;
}
public override int GetHashCode()
{
return HashCode.Combine(Value);
}
public override bool Equals(object? obj)
{
if (obj is not RuntimeFieldHandle)
return false;
RuntimeFieldHandle handle = (RuntimeFieldHandle)obj;
return handle.Value == Value;
}
public bool Equals(RuntimeFieldHandle handle)
{
return handle.Value == Value;
}
/// <summary>
/// Returns a new <see cref="RuntimeFieldHandle"/> object created from a handle to a RuntimeFieldInfo.
/// </summary>
/// <param name="value">An IntPtr handle to a RuntimeFieldInfo to create a <see cref="RuntimeFieldHandle"/> object from.</param>
/// <returns>A new <see cref="RuntimeFieldHandle"/> object that corresponds to the value parameter.</returns>
public static RuntimeFieldHandle FromIntPtr(IntPtr value)
{
var handle = new RuntimeFieldHandleInternal(value);
var fieldInfo = new RuntimeFieldInfoStub(handle, GetLoaderAllocator(handle));
return new RuntimeFieldHandle(fieldInfo);
}
/// <summary>
/// Returns the internal pointer representation of a <see cref="RuntimeFieldHandle"/> object.
/// </summary>
/// <param name="value">A <see cref="RuntimeFieldHandle"/> object to retrieve an internal pointer representation from.</param>
/// <returns>An <see cref="IntPtr"/> object that represents a <see cref="RuntimeFieldHandle"/> object.</returns>
public static IntPtr ToIntPtr(RuntimeFieldHandle value) => value.Value;
public static bool operator ==(RuntimeFieldHandle left, RuntimeFieldHandle right) => left.Equals(right);
public static bool operator !=(RuntimeFieldHandle left, RuntimeFieldHandle right) => !left.Equals(right);
internal static string GetName(IRuntimeFieldInfo field)
{
string name = GetUtf8Name(field.Value).ToString();
GC.KeepAlive(field);
return name;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern void* GetUtf8NameInternal(RuntimeFieldHandleInternal field);
// Since the returned string is a pointer into metadata, the caller should
// ensure the passed in type is alive for at least as long as returned result is
// needed.
internal static MdUtf8String GetUtf8Name(RuntimeFieldHandleInternal field)
{
void* name = GetUtf8NameInternal(field);
if (name is null)
{
throw new BadImageFormatException();
}
return new MdUtf8String(name);
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern FieldAttributes GetAttributes(RuntimeFieldHandleInternal field);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern MethodTable* GetApproxDeclaringMethodTable(RuntimeFieldHandleInternal field);
internal static RuntimeType GetApproxDeclaringType(RuntimeFieldHandleInternal field)
{
Debug.Assert(!field.IsNullHandle());
MethodTable* pMT = GetApproxDeclaringMethodTable(field);
Debug.Assert(pMT != null);
return RuntimeTypeHandle.GetRuntimeType(pMT);
}
internal static RuntimeType GetApproxDeclaringType(IRuntimeFieldInfo field)
{
RuntimeType type = GetApproxDeclaringType(field.Value);
GC.KeepAlive(field);
return type;
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool IsFastPathSupported(RtFieldInfo field);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern int GetInstanceFieldOffset(RtFieldInfo field);
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IntPtr GetStaticFieldAddress(RtFieldInfo field);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeFieldHandle_GetRVAFieldInfo")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool GetRVAFieldInfo(RuntimeFieldHandleInternal field, out void* address, out uint size);
internal static ref byte GetFieldDataReference(object target, RuntimeFieldInfo field)
{
ByteRef fieldDataRef = default;
GetFieldDataReference(((RtFieldInfo)field).GetFieldDesc(), ObjectHandleOnStack.Create(ref target), ByteRefOnStack.Create(ref fieldDataRef));
Debug.Assert(!Unsafe.IsNullRef(ref fieldDataRef.Get()));
GC.KeepAlive(field);
return ref fieldDataRef.Get();
}
internal static ref byte GetFieldDataReference(ref byte target, RuntimeFieldInfo field)
{
Debug.Assert(!Unsafe.IsNullRef(ref target));
int offset = GetInstanceFieldOffset((RtFieldInfo)field);
return ref Unsafe.AddByteOffset(ref target, offset);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeFieldHandle_GetFieldDataReference")]
private static unsafe partial void GetFieldDataReference(IntPtr fieldDesc, ObjectHandleOnStack target, ByteRefOnStack fieldDataRef);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern int GetToken(IntPtr fieldDesc);
internal static int GetToken(RtFieldInfo field)
{
int tk = GetToken(field.GetFieldDesc());
GC.KeepAlive(field);
return tk;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeFieldHandle_GetValue")]
private static partial void GetValue(
IntPtr fieldDesc,
ObjectHandleOnStack instance,
QCallTypeHandle fieldType,
QCallTypeHandle declaringType,
[MarshalAs(UnmanagedType.Bool)] ref bool isClassInitialized,
ObjectHandleOnStack result);
internal static object? GetValue(RtFieldInfo field, object? instance, RuntimeType fieldType, RuntimeType? declaringType, ref bool isClassInitialized)
{
if (field is null || fieldType is null)
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
object? result = null;
GetValue(field.GetFieldDesc(), ObjectHandleOnStack.Create(ref instance), new QCallTypeHandle(ref fieldType), new QCallTypeHandle(ref declaringType!), ref isClassInitialized, ObjectHandleOnStack.Create(ref result));
GC.KeepAlive(field);
return result;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeFieldHandle_GetValueDirect")]
private static partial void GetValueDirect(
IntPtr fieldDesc,
void* pTypedRef,
QCallTypeHandle fieldType,
QCallTypeHandle declaringType,
ObjectHandleOnStack result);
internal static object? GetValueDirect(RtFieldInfo field, RuntimeType fieldType, TypedReference typedRef, RuntimeType? contextType)
{
if (field is null || fieldType is null)
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
object? result = null;
GetValueDirect(field.GetFieldDesc(), &typedRef, new QCallTypeHandle(ref fieldType), new QCallTypeHandle(ref contextType!), ObjectHandleOnStack.Create(ref result));
GC.KeepAlive(field);
return result;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeFieldHandle_SetValue")]
private static partial void SetValue(
IntPtr fieldDesc,
ObjectHandleOnStack instance,
ObjectHandleOnStack value,
QCallTypeHandle fieldType,
QCallTypeHandle declaringType,
[MarshalAs(UnmanagedType.Bool)] ref bool isClassInitialized);
internal static void SetValue(RtFieldInfo field, object? obj, object? value, RuntimeType fieldType, RuntimeType? declaringType, ref bool isClassInitialized)
{
if (field is null || fieldType is null)
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
SetValue(field.GetFieldDesc(), ObjectHandleOnStack.Create(ref obj), ObjectHandleOnStack.Create(ref value), new QCallTypeHandle(ref fieldType), new QCallTypeHandle(ref declaringType!), ref isClassInitialized);
GC.KeepAlive(field);
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeFieldHandle_SetValueDirect")]
private static partial void SetValueDirect(
IntPtr fieldDesc,
void* pTypedRef,
ObjectHandleOnStack value,
QCallTypeHandle fieldType,
QCallTypeHandle declaringType);
internal static void SetValueDirect(RtFieldInfo field, RuntimeType fieldType, TypedReference typedRef, object? value, RuntimeType? contextType)
{
if (field is null || fieldType is null)
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
SetValueDirect(field.GetFieldDesc(), &typedRef, ObjectHandleOnStack.Create(ref value), new QCallTypeHandle(ref fieldType), new QCallTypeHandle(ref contextType!));
GC.KeepAlive(field);
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe RuntimeFieldHandleInternal GetStaticFieldForGenericType(RuntimeFieldHandleInternal field, MethodTable* pMT);
internal static RuntimeFieldHandleInternal GetStaticFieldForGenericType(RuntimeFieldHandleInternal field, RuntimeType declaringType)
{
TypeHandle th = declaringType.GetNativeTypeHandle();
Debug.Assert(!th.IsTypeDesc);
return GetStaticFieldForGenericType(field, th.AsMethodTable());
}
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool AcquiresContextFromThis(RuntimeFieldHandleInternal field);
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern LoaderAllocator GetLoaderAllocatorInternal(RuntimeFieldHandleInternal field);
internal static LoaderAllocator GetLoaderAllocator(RuntimeFieldHandleInternal field)
{
if (field.IsNullHandle())
{
throw new ArgumentNullException(SR.Arg_InvalidHandle);
}
return GetLoaderAllocatorInternal(field);
}
// ISerializable interface
[Obsolete(Obsoletions.LegacyFormatterImplMessage, DiagnosticId = Obsoletions.LegacyFormatterImplDiagId, UrlFormat = Obsoletions.SharedUrlFormat)]
[EditorBrowsable(EditorBrowsableState.Never)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new PlatformNotSupportedException();
}
}
public unsafe partial struct ModuleHandle : IEquatable<ModuleHandle>
{
#region Public Static Members
public static readonly ModuleHandle EmptyHandle;
#endregion
#region Private Data Members
private readonly RuntimeModule m_ptr;
#endregion
#region Constructor
internal ModuleHandle(RuntimeModule module)
{
m_ptr = module;
}
#endregion
internal RuntimeModule GetRuntimeModule()
{
return m_ptr;
}
public override int GetHashCode()
{
return m_ptr != null ? m_ptr.GetHashCode() : 0;
}
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj is not ModuleHandle)
return false;
ModuleHandle handle = (ModuleHandle)obj;
return handle.m_ptr == m_ptr;
}
public bool Equals(ModuleHandle handle)
{
return handle.m_ptr == m_ptr;
}
public static bool operator ==(ModuleHandle left, ModuleHandle right) => left.Equals(right);
public static bool operator !=(ModuleHandle left, ModuleHandle right) => !left.Equals(right);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleHandle_GetDynamicMethod", StringMarshalling = StringMarshalling.Utf8)]
private static partial void GetDynamicMethod(
QCallModule module,
string name,
byte[] sig,
int sigLen,
ObjectHandleOnStack resolver,
ObjectHandleOnStack result);
internal static IRuntimeMethodInfo GetDynamicMethod(RuntimeModule module, string name, byte[] sig, Resolver resolver)
{
IRuntimeMethodInfo? methodInfo = null;
GetDynamicMethod(
new QCallModule(ref module),
name,
sig,
sig.Length,
ObjectHandleOnStack.Create(ref resolver),
ObjectHandleOnStack.Create(ref methodInfo));
return methodInfo!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleHandle_GetToken")]
[SuppressGCTransition]
private static partial int GetToken(QCallModule module);
internal static int GetToken(RuntimeModule module)
=> GetToken(new QCallModule(ref module));
private static void ValidateModulePointer(RuntimeModule module)
{
// Make sure we have a valid Module to resolve against.
if (module is null)
{
// Local function to allow inlining of simple null check.
ThrowInvalidOperationException();
}
[StackTraceHidden]
[DoesNotReturn]
static void ThrowInvalidOperationException() => throw new InvalidOperationException(SR.InvalidOperation_NullModuleHandle);
}
// SQL-CLR LKG9 Compiler dependency
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeTypeHandle GetRuntimeTypeHandleFromMetadataToken(int typeToken) { return ResolveTypeHandle(typeToken); }
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeTypeHandle ResolveTypeHandle(int typeToken) => ResolveTypeHandle(typeToken, null, null);
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeTypeHandle ResolveTypeHandle(int typeToken, RuntimeTypeHandle[]? typeInstantiationContext, RuntimeTypeHandle[]? methodInstantiationContext)
{
RuntimeModule module = GetRuntimeModule();
ValidateModulePointer(module);
scoped ReadOnlySpan<IntPtr> typeInstantiationContextHandles = default;
scoped ReadOnlySpan<IntPtr> methodInstantiationContextHandles = default;
// defensive copy of user-provided array, per CopyRuntimeTypeHandles contract
if (typeInstantiationContext?.Length > 0)
{
typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext.Clone();
typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, stackScratch: stackalloc IntPtr[8]);
}
if (methodInstantiationContext?.Length > 0)
{
methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext.Clone();
methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, stackScratch: stackalloc IntPtr[8]);
}
fixed (IntPtr* typeInstArgs = typeInstantiationContextHandles, methodInstArgs = methodInstantiationContextHandles)
{
try
{
RuntimeType? type = null;
ResolveType(new QCallModule(ref module), typeToken, typeInstArgs, typeInstantiationContextHandles.Length, methodInstArgs, methodInstantiationContextHandles.Length, ObjectHandleOnStack.Create(ref type));
GC.KeepAlive(typeInstantiationContext);
GC.KeepAlive(methodInstantiationContext);
return new RuntimeTypeHandle(type!);
}
catch (Exception)
{
if (!module.MetadataImport.IsValidToken(typeToken))
throw new ArgumentOutOfRangeException(nameof(typeToken),
SR.Format(SR.Argument_InvalidToken, typeToken, new ModuleHandle(module)));
throw;
}
}
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleHandle_ResolveType")]
private static partial void ResolveType(QCallModule module,
int typeToken,
IntPtr* typeInstArgs,
int typeInstCount,
IntPtr* methodInstArgs,
int methodInstCount,
ObjectHandleOnStack type);
// SQL-CLR LKG9 Compiler dependency
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeMethodHandle GetRuntimeMethodHandleFromMetadataToken(int methodToken) { return ResolveMethodHandle(methodToken); }
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeMethodHandle ResolveMethodHandle(int methodToken) => ResolveMethodHandle(methodToken, null, null);
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeMethodHandle ResolveMethodHandle(int methodToken, RuntimeTypeHandle[]? typeInstantiationContext, RuntimeTypeHandle[]? methodInstantiationContext)
{
RuntimeModule module = GetRuntimeModule();
// defensive copy of user-provided array, per CopyRuntimeTypeHandles contract
typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext?.Clone();
methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext?.Clone();
ReadOnlySpan<IntPtr> typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, stackScratch: stackalloc IntPtr[8]);
ReadOnlySpan<IntPtr> methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, stackScratch: stackalloc IntPtr[8]);
RuntimeMethodHandleInternal handle = ResolveMethodHandleInternal(module, methodToken, typeInstantiationContextHandles, methodInstantiationContextHandles);
IRuntimeMethodInfo retVal = new RuntimeMethodInfoStub(handle, RuntimeMethodHandle.GetLoaderAllocator(handle));
GC.KeepAlive(typeInstantiationContext);
GC.KeepAlive(methodInstantiationContext);
return new RuntimeMethodHandle(retVal);
}
internal static RuntimeMethodHandleInternal ResolveMethodHandleInternal(RuntimeModule module, int methodToken, ReadOnlySpan<IntPtr> typeInstantiationContext, ReadOnlySpan<IntPtr> methodInstantiationContext)
{
ValidateModulePointer(module);
try
{
fixed (IntPtr* typeInstArgs = typeInstantiationContext, methodInstArgs = methodInstantiationContext)
{
return ResolveMethod(new QCallModule(ref module), methodToken, typeInstArgs, typeInstantiationContext.Length, methodInstArgs, methodInstantiationContext.Length);
}
}
catch (Exception)
{
if (!module.MetadataImport.IsValidToken(methodToken))
throw new ArgumentOutOfRangeException(nameof(methodToken),
SR.Format(SR.Argument_InvalidToken, methodToken, new ModuleHandle(module)));
throw;
}
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleHandle_ResolveMethod")]
private static partial RuntimeMethodHandleInternal ResolveMethod(QCallModule module,
int methodToken,
IntPtr* typeInstArgs,
int typeInstCount,
IntPtr* methodInstArgs,
int methodInstCount);
// SQL-CLR LKG9 Compiler dependency
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeFieldHandle GetRuntimeFieldHandleFromMetadataToken(int fieldToken) { return ResolveFieldHandle(fieldToken); }
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeFieldHandle ResolveFieldHandle(int fieldToken) => ResolveFieldHandle(fieldToken, null, null);
[RequiresUnreferencedCode("Trimming changes metadata tokens")]
public RuntimeFieldHandle ResolveFieldHandle(int fieldToken, RuntimeTypeHandle[]? typeInstantiationContext, RuntimeTypeHandle[]? methodInstantiationContext)
{
RuntimeModule module = GetRuntimeModule();
ValidateModulePointer(module);
scoped ReadOnlySpan<IntPtr> typeInstantiationContextHandles = default;
scoped ReadOnlySpan<IntPtr> methodInstantiationContextHandles = default;
// defensive copy of user-provided array, per CopyRuntimeTypeHandles contract
if (typeInstantiationContext?.Length > 0)
{
typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext.Clone();
typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, stackScratch: stackalloc IntPtr[8]);
}
if (methodInstantiationContext?.Length > 0)
{
methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext.Clone();
methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, stackScratch: stackalloc IntPtr[8]);
}
fixed (IntPtr* typeInstArgs = typeInstantiationContextHandles, methodInstArgs = methodInstantiationContextHandles)
{
try
{
IRuntimeFieldInfo? field = null;
ResolveField(new QCallModule(ref module), fieldToken, typeInstArgs, typeInstantiationContextHandles.Length, methodInstArgs, methodInstantiationContextHandles.Length, ObjectHandleOnStack.Create(ref field));
GC.KeepAlive(typeInstantiationContext);
GC.KeepAlive(methodInstantiationContext);
return new RuntimeFieldHandle(field!);
}
catch (Exception)
{
if (!module.MetadataImport.IsValidToken(fieldToken))
throw new ArgumentOutOfRangeException(nameof(fieldToken),
SR.Format(SR.Argument_InvalidToken, fieldToken, new ModuleHandle(module)));
throw;
}
}
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleHandle_ResolveField")]
private static partial void ResolveField(QCallModule module,
int fieldToken,
IntPtr* typeInstArgs,
int typeInstCount,
IntPtr* methodInstArgs,
int methodInstCount,
ObjectHandleOnStack retField);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleHandle_GetModuleType")]
internal static partial void GetModuleType(QCallModule handle, ObjectHandleOnStack type);
internal static RuntimeType GetModuleType(RuntimeModule module)
{
RuntimeType? type = null;
GetModuleType(new QCallModule(ref module), ObjectHandleOnStack.Create(ref type));
return type!;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleHandle_GetPEKind")]
private static partial void GetPEKind(QCallModule handle, int* peKind, int* machine);
// making this internal, used by Module.GetPEKind
internal static void GetPEKind(RuntimeModule module, out PortableExecutableKinds peKind, out ImageFileMachine machine)
{
int lKind, lMachine;
GetPEKind(new QCallModule(ref module), &lKind, &lMachine);
peKind = (PortableExecutableKinds)lKind;
machine = (ImageFileMachine)lMachine;
}
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ModuleHandle_GetMDStreamVersion")]
[SuppressGCTransition]
private static partial int GetMDStreamVersion(QCallModule module);
internal static int GetMDStreamVersion(RuntimeModule module)
=> GetMDStreamVersion(new QCallModule(ref module));
public int MDStreamVersion => GetMDStreamVersion(GetRuntimeModule());
}
internal sealed unsafe partial class Signature
{
#region Private Data Members
//
// Keep the layout in sync with SignatureNative in the VM
//
private RuntimeType[]? _arguments;
private RuntimeType _declaringType;
private RuntimeType _returnTypeORfieldType;
#pragma warning disable CA1823, 169
private object? _keepAlive;
#pragma warning restore CA1823, 169
private void* _sig;
private int _csig;
private int _managedCallingConventionAndArgIteratorFlags; // lowest byte is CallingConvention, upper 3 bytes are ArgIterator flags
#pragma warning disable CA1823, 169
private int _nSizeOfArgStack;
#pragma warning restore CA1823, 169
private RuntimeMethodHandleInternal _pMethod;
#endregion
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Signature_Init")]
private static partial void Init(
ObjectHandleOnStack _this,
void* pCorSig, int cCorSig,
RuntimeFieldHandleInternal fieldHandle,
RuntimeMethodHandleInternal methodHandle);
[MemberNotNull(nameof(_returnTypeORfieldType))]
private void Init(
void* pCorSig, int cCorSig,
RuntimeFieldHandleInternal fieldHandle,
RuntimeMethodHandleInternal methodHandle)
{
Signature _this = this;
Init(ObjectHandleOnStack.Create(ref _this),
pCorSig, cCorSig,
fieldHandle,
methodHandle);
Debug.Assert(_returnTypeORfieldType != null);
}
#region Constructors
public Signature(
IRuntimeMethodInfo methodHandle,
RuntimeType[] arguments,
RuntimeType returnType,
CallingConventions callingConvention)
{
_arguments = arguments;
_returnTypeORfieldType = returnType;
_managedCallingConventionAndArgIteratorFlags = (int)callingConvention;
Debug.Assert((_managedCallingConventionAndArgIteratorFlags & 0xffffff00) == 0);
_pMethod = methodHandle.Value;
_declaringType = RuntimeMethodHandle.GetDeclaringType(_pMethod);
Init(null, 0, default, _pMethod);
GC.KeepAlive(methodHandle);
}
public Signature(IRuntimeMethodInfo methodHandle, RuntimeType declaringType)
{
_declaringType = declaringType;
Init(null, 0, default, methodHandle.Value);
GC.KeepAlive(methodHandle);
}
public Signature(IRuntimeFieldInfo fieldHandle, RuntimeType declaringType)
{
_declaringType = declaringType;
Init(null, 0, fieldHandle.Value, default);
GC.KeepAlive(fieldHandle);
}
public Signature(void* pCorSig, int cCorSig, RuntimeType declaringType)
{
_declaringType = declaringType;
Init(pCorSig, cCorSig, default, default);
}
#endregion
#region Internal Members
internal CallingConventions CallingConvention => (CallingConventions)(_managedCallingConventionAndArgIteratorFlags & 0xff);
internal RuntimeType[] Arguments
{
get
{
Debug.Assert(_arguments != null);
return _arguments;
}
}
internal RuntimeType ReturnType => _returnTypeORfieldType;
internal RuntimeType FieldType => _returnTypeORfieldType;
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Signature_AreEqual")]
private static partial Interop.BOOL AreEqual(
void* sig1, int csig1, QCallTypeHandle type1,
void* sig2, int csig2, QCallTypeHandle type2);
internal static bool AreEqual(Signature sig1, Signature sig2)
{
return AreEqual(
sig1._sig, sig1._csig, new QCallTypeHandle(ref sig1._declaringType),
sig2._sig, sig2._csig, new QCallTypeHandle(ref sig2._declaringType)) != Interop.BOOL.FALSE;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe int GetParameterOffsetInternal(void* sig, int csig, int parameterIndex);
internal int GetParameterOffset(int parameterIndex)
{
int offsetMaybe = GetParameterOffsetInternal(_sig, _csig, parameterIndex);
// If the result is negative, it is an error code.
if (offsetMaybe < 0)
Marshal.ThrowExceptionForHR(offsetMaybe, new IntPtr(-1));
return offsetMaybe;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe int GetTypeParameterOffsetInternal(void* sig, int csig, int offset, int index);
internal int GetTypeParameterOffset(int offset, int index)
{
if (offset < 0)
{
Debug.Assert(offset == -1);
return offset;
}
int offsetMaybe = GetTypeParameterOffsetInternal(_sig, _csig, offset, index);
// If the result is negative and not -1, it is an error code.
if (offsetMaybe < 0 && offsetMaybe != -1)
Marshal.ThrowExceptionForHR(offsetMaybe, new IntPtr(-1));
return offsetMaybe;
}
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe int GetCallingConventionFromFunctionPointerAtOffsetInternal(void* sig, int csig, int offset);
internal SignatureCallingConvention GetCallingConventionFromFunctionPointerAtOffset(int offset)
{
if (offset < 0)
{
Debug.Assert(offset == -1);
return SignatureCallingConvention.Default;
}
int callConvMaybe = GetCallingConventionFromFunctionPointerAtOffsetInternal(_sig, _csig, offset);
// If the result is negative, it is an error code.
if (callConvMaybe < 0)
Marshal.ThrowExceptionForHR(callConvMaybe, new IntPtr(-1));
return (SignatureCallingConvention)callConvMaybe;
}
internal Type[] GetCustomModifiers(int parameterIndex, bool required) =>
GetCustomModifiersAtOffset(GetParameterOffset(parameterIndex), required);
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Signature_GetCustomModifiersAtOffset")]
private static partial void GetCustomModifiersAtOffset(
ObjectHandleOnStack sigObj,
int offset,
Interop.BOOL required,
ObjectHandleOnStack result);
internal Type[] GetCustomModifiersAtOffset(int offset, bool required)
{
Signature _this = this;
Type[]? result = null;
GetCustomModifiersAtOffset(
ObjectHandleOnStack.Create(ref _this),
offset,
required ? Interop.BOOL.TRUE : Interop.BOOL.FALSE,
ObjectHandleOnStack.Create(ref result));
return result!;
}
#endregion
}
internal abstract class Resolver
{
internal struct CORINFO_EH_CLAUSE
{
internal int Flags;
internal int TryOffset;
internal int TryLength;
internal int HandlerOffset;
internal int HandlerLength;
internal int ClassTokenOrFilterOffset;
}
// ILHeader info
internal abstract RuntimeType? GetJitContext(out int securityControlFlags);
internal abstract byte[] GetCodeInfo(out int stackSize, out int initLocals, out int EHCount);
internal abstract byte[] GetLocalsSignature();
internal abstract unsafe void GetEHInfo(int EHNumber, void* exception);
internal abstract byte[]? GetRawEHInfo();
// token resolution
internal abstract string? GetStringLiteral(int token);
internal abstract void ResolveToken(int token, out IntPtr typeHandle, out IntPtr methodHandle, out IntPtr fieldHandle);
internal abstract byte[]? ResolveSignature(int token, int fromMethod);
//
internal abstract MethodInfo GetDynamicMethod();
}
}
|