Skip to content

Commit

Permalink
Remove Helper Method Frames (HMF) from Reflection (dotnet#109996)
Browse files Browse the repository at this point in the history
Convert RuntimeMethodHandle.GetDeclaringType() to managed and QCall.
Convert RuntimeTypeHandle.GetElementType() to managed.
Correct nullability in signature and usage.
Convert RuntimeTypeHandle.GetDeclaringType() to managed and QCalls.
Remove GetRuntimeTypeHelper().
Root RuntimeAssembly and RuntimeType constructors.
  • Loading branch information
AaronRobinsonMSFT authored and mikelle-rogers committed Dec 4, 2024
1 parent 085106f commit 2cf75bf
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 191 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1085,7 +1085,7 @@ public CustomAttributeType(RuntimeType parameterType)

if (encodedType == CustomAttributeEncoding.Array)
{
parameterType = (RuntimeType)parameterType.GetElementType();
parameterType = (RuntimeType)parameterType.GetElementType()!;
encodedArrayType = RuntimeCustomAttributeData.TypeToCustomAttributeEncoding(parameterType);
}

Expand Down
92 changes: 69 additions & 23 deletions src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,49 +19,45 @@ public unsafe partial struct RuntimeTypeHandle : IEquatable<RuntimeTypeHandle>,
{
// Returns handle for interop with EE. The handle is guaranteed to be non-null.
internal RuntimeTypeHandle GetNativeHandle() =>
new RuntimeTypeHandle(m_type ?? throw new ArgumentNullException(null, SR.Arg_InvalidHandle));
new RuntimeTypeHandle(GetRuntimeTypeChecked());

// Returns type for interop with EE. The type is guaranteed to be non-null.
internal RuntimeType GetTypeChecked() =>
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(GetTypeFromHandle(value));
public static RuntimeTypeHandle FromIntPtr(IntPtr value) =>
new RuntimeTypeHandle(value == IntPtr.Zero ? null : GetRuntimeTypeFromHandle(value));

[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetTypeFromHandleSlow")]
private static partial void GetTypeFromHandleSlow(
[LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow")]
private static partial void GetRuntimeTypeFromHandleSlow(
IntPtr handle,
ObjectHandleOnStack typeObject);

[MethodImpl(MethodImplOptions.NoInlining)]
private static RuntimeType GetTypeFromHandleSlow(IntPtr handle)
private static RuntimeType GetRuntimeTypeFromHandleSlow(IntPtr handle)
{
RuntimeType? typeObject = null;
GetTypeFromHandleSlow(handle, ObjectHandleOnStack.Create(ref typeObject));
GetRuntimeTypeFromHandleSlow(handle, ObjectHandleOnStack.Create(ref typeObject));
return typeObject!;
}

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern RuntimeType? GetTypeFromHandleIfExists(IntPtr handle);
private static extern RuntimeType? GetRuntimeTypeFromHandleIfExists(IntPtr handle);

private static RuntimeType? GetTypeFromHandle(IntPtr handle)
private static RuntimeType GetRuntimeTypeFromHandle(IntPtr handle)
{
if (handle == IntPtr.Zero)
{
return null;
}

return GetTypeFromHandleIfExists(handle) ?? GetTypeFromHandleSlow(handle);
return GetRuntimeTypeFromHandleIfExists(handle) ?? GetRuntimeTypeFromHandleSlow(handle);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe RuntimeType GetRuntimeType(MethodTable* pMT)
{
return pMT->AuxiliaryData->ExposedClassObject ?? GetTypeFromHandleSlow((IntPtr)pMT);
return pMT->AuxiliaryData->ExposedClassObject ?? GetRuntimeTypeFromHandleSlow((IntPtr)pMT);
}

/// <summary>
Expand Down Expand Up @@ -386,7 +382,20 @@ public ModuleHandle GetModuleHandle()
internal static extern TypeAttributes GetAttributes(RuntimeType type);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern RuntimeType GetElementType(RuntimeType type);
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);
Expand Down Expand Up @@ -565,8 +574,38 @@ internal static unsafe MdUtf8String GetUtf8Name(RuntimeType type)
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern bool CanCastTo(RuntimeType type, RuntimeType target);

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern RuntimeType GetDeclaringType(RuntimeType type);
[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;
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern IRuntimeMethodInfo GetDeclaringMethod(RuntimeType type);
Expand Down Expand Up @@ -676,7 +715,7 @@ internal RuntimeType MakePointer()

internal int GetGenericVariableIndex()
{
RuntimeType type = GetTypeChecked();
RuntimeType type = GetRuntimeTypeChecked();

if (!IsGenericVariable(type))
throw new InvalidOperationException(SR.Arg_NotGenericParameter);
Expand All @@ -689,7 +728,7 @@ internal int GetGenericVariableIndex()

internal bool ContainsGenericVariables()
{
return ContainsGenericVariables(GetTypeChecked());
return ContainsGenericVariables(GetRuntimeTypeChecked());
}

[MethodImpl(MethodImplOptions.InternalCall)]
Expand Down Expand Up @@ -757,7 +796,7 @@ internal RuntimeMethodHandleInternal(IntPtr value)
m_handle = value;
}

internal IntPtr m_handle;
private IntPtr m_handle;
}

internal sealed class RuntimeMethodInfoStub : IRuntimeMethodInfo
Expand Down Expand Up @@ -928,7 +967,14 @@ internal static string ConstructInstantiation(IRuntimeMethodInfo method, TypeNam
}

[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern RuntimeType GetDeclaringType(RuntimeMethodHandleInternal method);
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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,7 @@ private RuntimeType[] PopulateInterfaces(Filter filter)

if (ReflectedType.IsSZArray)
{
RuntimeType arrayType = (RuntimeType)ReflectedType.GetElementType();
RuntimeType arrayType = (RuntimeType)ReflectedType.GetElementType()!;

if (!arrayType.IsPointer)
{
Expand Down Expand Up @@ -1597,7 +1597,7 @@ internal TypeCode TypeCode
if (m_enclosingType == null)
{
// Use void as a marker of null enclosing type
RuntimeType enclosingType = RuntimeTypeHandle.GetDeclaringType(GetRuntimeType());
RuntimeType? enclosingType = RuntimeTypeHandle.GetDeclaringType(GetRuntimeType());
Debug.Assert(enclosingType != typeof(void));
m_enclosingType = enclosingType ?? (RuntimeType)typeof(void);
}
Expand Down Expand Up @@ -2055,8 +2055,8 @@ internal static void ValidateGenericArguments(MemberInfo definition, RuntimeType
Type genericArgument = genericArguments[i];
Type genericParameter = genericParameters[i];

if (!RuntimeTypeHandle.SatisfiesConstraints(genericParameter.TypeHandle.GetTypeChecked(),
typeContext, methodContext, genericArgument.TypeHandle.GetTypeChecked()))
if (!RuntimeTypeHandle.SatisfiesConstraints(genericParameter.TypeHandle.GetRuntimeTypeChecked(),
typeContext, methodContext, genericArgument.TypeHandle.GetRuntimeTypeChecked()))
{
throw new ArgumentException(
SR.Format(SR.Argument_GenConstraintViolation, i.ToString(), genericArgument, definition, genericParameter), e);
Expand Down
7 changes: 6 additions & 1 deletion src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,9 @@ DEFINE_FIELD_U(m_fullname, AssemblyBaseObject, m_fullname)
DEFINE_FIELD_U(m_syncRoot, AssemblyBaseObject, m_pSyncRoot)
DEFINE_FIELD_U(m_assembly, AssemblyBaseObject, m_pAssembly)
DEFINE_CLASS(ASSEMBLY, Reflection, RuntimeAssembly)

#ifdef FOR_ILLINK
DEFINE_METHOD(ASSEMBLY, CTOR, .ctor, IM_RetVoid)
#endif // FOR_ILLINK

DEFINE_CLASS(ASYNCCALLBACK, System, AsyncCallback)
DEFINE_CLASS(ATTRIBUTE, System, Attribute)
Expand All @@ -152,6 +154,9 @@ DEFINE_METHOD(CLASS, GET_METHODS, GetMethods,
DEFINE_METHOD(CLASS, INVOKE_MEMBER, InvokeMember, IM_Str_BindingFlags_Binder_Obj_ArrObj_ArrParameterModifier_CultureInfo_ArrStr_RetObj)
DEFINE_METHOD(CLASS, GET_METHOD_BASE, GetMethodBase, SM_RuntimeType_RuntimeMethodHandleInternal_RetMethodBase)
DEFINE_METHOD(CLASS, GET_FIELD_INFO, GetFieldInfo, SM_RuntimeType_IRuntimeFieldInfo_RetFieldInfo)
#ifdef FOR_ILLINK
DEFINE_METHOD(CLASS, CTOR, .ctor, IM_RetVoid)
#endif // FOR_ILLINK

#ifdef FEATURE_COMINTEROP
DEFINE_METHOD(CLASS, FORWARD_CALL_TO_INVOKE, ForwardCallToInvokeMember, IM_Str_BindingFlags_Obj_ArrObj_ArrBool_ArrInt_ArrType_Type_RetObj)
Expand Down
7 changes: 3 additions & 4 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,11 @@ FCFuncEnd()

FCFuncStart(gCOMTypeHandleFuncs)
FCFuncElement("GetDeclaringMethod", RuntimeTypeHandle::GetDeclaringMethod)
FCFuncElement("GetDeclaringType", RuntimeTypeHandle::GetDeclaringType)
FCFuncElement("GetFirstIntroducedMethod", RuntimeTypeHandle::GetFirstIntroducedMethod)
FCFuncElement("GetNextIntroducedMethod", RuntimeTypeHandle::GetNextIntroducedMethod)
FCFuncElement("GetAssemblyIfExists", RuntimeTypeHandle::GetAssemblyIfExists)
FCFuncElement("GetModuleIfExists", RuntimeTypeHandle::GetModuleIfExists)
FCFuncElement("GetElementType", RuntimeTypeHandle::GetElementType)
FCFuncElement("GetElementTypeHandle", RuntimeTypeHandle::GetElementTypeHandle)
FCFuncElement("GetArrayRank", RuntimeTypeHandle::GetArrayRank)
FCFuncElement("GetToken", RuntimeTypeHandle::GetToken)
FCFuncElement("GetUtf8NameInternal", RuntimeTypeHandle::GetUtf8Name)
Expand All @@ -106,7 +105,7 @@ FCFuncStart(gCOMTypeHandleFuncs)
FCFuncElement("IsUnmanagedFunctionPointer", RuntimeTypeHandle::IsUnmanagedFunctionPointer)
FCFuncElement("CompareCanonicalHandles", RuntimeTypeHandle::CompareCanonicalHandles)
FCFuncElement("IsEquivalentTo", RuntimeTypeHandle::IsEquivalentTo)
FCFuncElement("GetTypeFromHandleIfExists", RuntimeTypeHandle::GetTypeFromHandleIfExists)
FCFuncElement("GetRuntimeTypeFromHandleIfExists", RuntimeTypeHandle::GetRuntimeTypeFromHandleIfExists)
FCFuncEnd()

FCFuncStart(gMetaDataImport)
Expand Down Expand Up @@ -152,7 +151,7 @@ FCFuncStart(gRuntimeMethodHandle)
FCFuncElement("ReboxToNullable", RuntimeMethodHandle::ReboxToNullable)
FCFuncElement("GetImplAttributes", RuntimeMethodHandle::GetImplAttributes)
FCFuncElement("GetAttributes", RuntimeMethodHandle::GetAttributes)
FCFuncElement("GetDeclaringType", RuntimeMethodHandle::GetDeclaringType)
FCFuncElement("GetMethodTable", RuntimeMethodHandle::GetMethodTable)
FCFuncElement("GetSlot", RuntimeMethodHandle::GetSlot)
FCFuncElement("GetMethodDef", RuntimeMethodHandle::GetMethodDef)
FCFuncElement("GetUtf8NameInternal", RuntimeMethodHandle::GetUtf8Name)
Expand Down
4 changes: 3 additions & 1 deletion src/coreclr/vm/qcallentrypoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ static const Entry s_QCall[] =
DllImportEntry(RuntimeTypeHandle_GetNumVirtualsAndStaticVirtuals)
DllImportEntry(RuntimeTypeHandle_VerifyInterfaceIsImplemented)
DllImportEntry(RuntimeTypeHandle_GetInterfaceMethodImplementation)
DllImportEntry(RuntimeTypeHandle_GetDeclaringTypeHandleForGenericVariable)
DllImportEntry(RuntimeTypeHandle_GetDeclaringTypeHandle)
DllImportEntry(RuntimeTypeHandle_IsVisible)
DllImportEntry(RuntimeTypeHandle_ConstructName)
DllImportEntry(RuntimeTypeHandle_GetInstantiation)
Expand All @@ -136,7 +138,7 @@ static const Entry s_QCall[] =
#ifdef FEATURE_COMINTEROP
DllImportEntry(RuntimeTypeHandle_AllocateComObject)
#endif // FEATURE_COMINTEROP
DllImportEntry(RuntimeTypeHandle_GetTypeFromHandleSlow)
DllImportEntry(RuntimeTypeHandle_GetRuntimeTypeFromHandleSlow)
DllImportEntry(RuntimeTypeHandle_CreateInstanceForAnotherGenericParameter)
DllImportEntry(RuntimeTypeHandle_AllocateTypeAssociatedMemory)
DllImportEntry(RuntimeTypeHandle_RegisterCollectibleTypeDependency)
Expand Down
Loading

0 comments on commit 2cf75bf

Please sign in to comment.