From 51e9275027a1a9ab5e7589d3feb4a2e31f73eaab Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 5 Dec 2024 16:45:49 -0800 Subject: [PATCH 1/8] Convert RuntimeTypeHandle.GetFields() to QCall. --- .../src/System/RuntimeHandles.cs | 26 ++++++++++- .../src/System/RuntimeType.CoreCLR.cs | 23 +++++----- src/coreclr/vm/ecalllist.h | 1 - src/coreclr/vm/qcallentrypoints.cpp | 1 + src/coreclr/vm/runtimehandles.cpp | 46 ++++++------------- src/coreclr/vm/runtimehandles.h | 2 +- 6 files changed, 52 insertions(+), 47 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 236078b88c5679..9d70d7361596f3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -514,8 +514,30 @@ internal static IntroducedMethodEnumerator GetIntroducedMethods(RuntimeType type [MethodImpl(MethodImplOptions.InternalCall)] private static extern void GetNextIntroducedMethod(ref RuntimeMethodHandleInternal method); - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool GetFields(RuntimeType type, IntPtr* result, int* count); + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetFields")] + private static partial Interop.BOOL GetFields(MethodTable* pMT, Span data, ref int usedCount); + + internal static bool GetFields(RuntimeType type, ref Span buffer, ref int count) + { + TypeHandle typeHandle = type.GetNativeTypeHandle(); + + CorElementType elementType = (CorElementType)typeHandle.GetCorElementType(); + if (elementType is CorElementType.ELEMENT_TYPE_VAR or CorElementType.ELEMENT_TYPE_MVAR) + { + throw new ArgumentException(SR.Arg_InvalidHandle); + } + + if (typeHandle.IsTypeDesc) + { + count = 0; + return true; + } + + count = buffer.Length; + bool success = GetFields(typeHandle.AsMethodTable(), buffer, ref count) != Interop.BOOL.FALSE; + GC.KeepAlive(type); + return success; + } [MethodImpl(MethodImplOptions.InternalCall)] internal static extern Type[]? GetInterfaces(RuntimeType type); diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index b73f8263782e90..77dcf4ca7c580a 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -858,25 +858,24 @@ private RuntimeFieldInfo[] PopulateFields(Filter filter) private unsafe void PopulateRtFields(Filter filter, RuntimeType declaringType, ref ListBuilder list) { - IntPtr* pResult = stackalloc IntPtr[64]; - int count = 64; + Span result = stackalloc IntPtr[64]; + int count = 0; - if (!RuntimeTypeHandle.GetFields(declaringType, pResult, &count)) + if (!RuntimeTypeHandle.GetFields(declaringType, ref result, ref count)) { - fixed (IntPtr* pBigResult = new IntPtr[count]) - { - RuntimeTypeHandle.GetFields(declaringType, pBigResult, &count); - PopulateRtFields(filter, pBigResult, count, declaringType, ref list); - } + result = new IntPtr[count]; + bool success = RuntimeTypeHandle.GetFields(declaringType, ref result, ref count); + Debug.Assert(success && result.Length == count); + PopulateRtFields(filter, result, declaringType, ref list); } else if (count > 0) { - PopulateRtFields(filter, pResult, count, declaringType, ref list); + PopulateRtFields(filter, result.Slice(0, count), declaringType, ref list); } } private unsafe void PopulateRtFields(Filter filter, - IntPtr* ppFieldHandles, int count, RuntimeType declaringType, ref ListBuilder list) + Span ppFieldHandles, RuntimeType declaringType, ref ListBuilder list) { Debug.Assert(declaringType != null); Debug.Assert(ReflectedType != null); @@ -884,9 +883,9 @@ private unsafe void PopulateRtFields(Filter filter, bool needsStaticFieldForGeneric = declaringType.IsGenericType && !RuntimeTypeHandle.ContainsGenericVariables(declaringType); bool isInherited = declaringType != ReflectedType; - for (int i = 0; i < count; i++) + foreach (IntPtr handle in ppFieldHandles) { - RuntimeFieldHandleInternal runtimeFieldHandle = new RuntimeFieldHandleInternal(ppFieldHandles[i]); + RuntimeFieldHandleInternal runtimeFieldHandle = new RuntimeFieldHandleInternal(handle); if (filter.RequiresStringComparison()) { diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 5aff25d5caa72c..dfafd7631bcaaa 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -91,7 +91,6 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("GetArrayRank", RuntimeTypeHandle::GetArrayRank) FCFuncElement("GetToken", RuntimeTypeHandle::GetToken) FCFuncElement("GetUtf8NameInternal", RuntimeTypeHandle::GetUtf8Name) - FCFuncElement("GetFields", RuntimeTypeHandle::GetFields) FCFuncElement("GetInterfaces", RuntimeTypeHandle::GetInterfaces) FCFuncElement("GetAttributes", RuntimeTypeHandle::GetAttributes) FCFuncElement("GetNumVirtuals", RuntimeTypeHandle::GetNumVirtuals) diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index a60d16dfb22218..7c330dd013dcef 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -125,6 +125,7 @@ static const Entry s_QCall[] = DllImportEntry(RuntimeTypeHandle_GetModuleSlow) DllImportEntry(RuntimeTypeHandle_GetNumVirtualsAndStaticVirtuals) DllImportEntry(RuntimeTypeHandle_GetMethodAt) + DllImportEntry(RuntimeTypeHandle_GetFields) DllImportEntry(RuntimeTypeHandle_VerifyInterfaceIsImplemented) DllImportEntry(RuntimeTypeHandle_GetInterfaceMethodImplementation) DllImportEntry(RuntimeTypeHandle_GetDeclaringTypeHandleForGenericVariable) diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 932c69fa34eb5a..4e2f60d998b6bd 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -455,55 +455,39 @@ extern "C" MethodDesc* QCALLTYPE RuntimeTypeHandle_GetMethodAt(MethodTable* pMT, return pRetMethod; } -FCIMPL3(FC_BOOL_RET, RuntimeTypeHandle::GetFields, ReflectClassBaseObject *pTypeUNSAFE, INT32 **result, INT32 *pCount) { - CONTRACTL { - FCALL_CHECK; - } - CONTRACTL_END; - - REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - if (refType == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - TypeHandle typeHandle = refType->GetType(); - - if (!pCount || !result) - FCThrow(kArgumentNullException); +extern "C" BOOL QCALLTYPE RuntimeTypeHandle_GetFields(MethodTable* pMT, intptr_t* result, INT32* pCount) +{ + QCALL_CONTRACT; - if (typeHandle.IsGenericVariable()) - FCThrowRes(kArgumentException, W("Arg_InvalidHandle")); + _ASSERTE(pMT != NULL); + _ASSERTE(result != NULL); + _ASSERTE(pCount != NULL); - if (typeHandle.IsTypeDesc() || typeHandle.IsArray()) { - *pCount = 0; - FC_RETURN_BOOL(TRUE); - } + BOOL retVal = FALSE; - MethodTable *pMT= typeHandle.GetMethodTable(); - if (!pMT) - FCThrowRes(kArgumentException, W("Arg_InvalidHandle")); + BEGIN_QCALL; - BOOL retVal = FALSE; - HELPER_METHOD_FRAME_BEGIN_RET_1(refType); - // Check this approximation - we may be losing exact type information EncApproxFieldDescIterator fdIterator(pMT, ApproxFieldDescIterator::ALL_FIELDS, TRUE); INT32 count = (INT32)fdIterator.Count(); if (count > *pCount) { *pCount = count; + retVal = FALSE; } else { - for(INT32 i = 0; i < count; i ++) - result[i] = (INT32*)fdIterator.Next(); + for(INT32 i = 0; i < count; ++i) + result[i] = (intptr_t)fdIterator.Next(); *pCount = count; retVal = TRUE; } - HELPER_METHOD_FRAME_END(); - FC_RETURN_BOOL(retVal); + + END_QCALL; + + return retVal; } -FCIMPLEND extern "C" void QCALLTYPE RuntimeMethodHandle_ConstructInstantiation(MethodDesc * pMethod, DWORD format, QCall::StringHandleOnStack retString) { diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index 30683f5c2a8e70..c756a3c8c7c7b8 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -141,7 +141,6 @@ class RuntimeTypeHandle static FCDECL1(EnregisteredTypeHandle, GetElementTypeHandle, EnregisteredTypeHandle th); static FCDECL1(INT32, GetNumVirtuals, ReflectClassBaseObject *pType); - static FCDECL3(FC_BOOL_RET, GetFields, ReflectClassBaseObject *pType, INT32 **result, INT32 *pCount); static FCDECL1(MethodDesc *, GetFirstIntroducedMethod, ReflectClassBaseObject* pType); static FCDECL1(void, GetNextIntroducedMethod, MethodDesc **ppMethod); @@ -190,6 +189,7 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_GetAssemblySlow(QCall::ObjectHandleO extern "C" void QCALLTYPE RuntimeTypeHandle_GetModuleSlow(QCall::ObjectHandleOnStack type, QCall::ObjectHandleOnStack module); extern "C" INT32 QCALLTYPE RuntimeTypeHandle_GetNumVirtualsAndStaticVirtuals(QCall::TypeHandle pTypeHandle); extern "C" MethodDesc* QCALLTYPE RuntimeTypeHandle_GetMethodAt(MethodTable* pMT, INT32 slot); +extern "C" BOOL QCALLTYPE RuntimeTypeHandle_GetFields(MethodTable* pMT, intptr_t* result, INT32* pCount); extern "C" void QCALLTYPE RuntimeTypeHandle_VerifyInterfaceIsImplemented(QCall::TypeHandle pTypeHandle, QCall::TypeHandle pIFaceHandle); extern "C" MethodDesc* QCALLTYPE RuntimeTypeHandle_GetInterfaceMethodImplementation(QCall::TypeHandle pTypeHandle, QCall::TypeHandle pOwner, MethodDesc * pMD); extern "C" EnregisteredTypeHandle QCALLTYPE RuntimeTypeHandle_GetDeclaringTypeHandleForGenericVariable(EnregisteredTypeHandle pTypeHandle); From 5d1f4e55b51120a783801ed98ea0f92c657880bc Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 5 Dec 2024 20:02:14 -0800 Subject: [PATCH 2/8] Convert RuntimeTypeHandle.GetInterfaces() to QCall. --- .../src/System/RuntimeHandles.cs | 20 +++- .../src/System/RuntimeType.CoreCLR.cs | 51 ++++----- src/coreclr/vm/ecalllist.h | 1 - src/coreclr/vm/qcallentrypoints.cpp | 1 + src/coreclr/vm/runtimehandles.cpp | 100 ++++++++---------- src/coreclr/vm/runtimehandles.h | 3 +- 6 files changed, 83 insertions(+), 93 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 9d70d7361596f3..3d132e75bbc70f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -539,8 +539,24 @@ internal static bool GetFields(RuntimeType type, ref Span buffer, ref in return success; } - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern Type[]? GetInterfaces(RuntimeType type); + [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)); + + Type[] result = Array.Empty(); + TypeHandle typeHandle = type.GetNativeTypeHandle(); + if (typeHandle.IsTypeDesc) + { + return 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); diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 77dcf4ca7c580a..9ca9e8f4d7b0f4 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -826,30 +826,21 @@ private RuntimeFieldInfo[] PopulateFields(Filter filter) #endregion #region Populate Literal Fields on Interfaces + Type[] interfaces; if (ReflectedType.IsGenericParameter) { - Type[] interfaces = ReflectedType.BaseType!.GetInterfaces(); - - for (int i = 0; i < interfaces.Length; i++) - { - // Populate literal fields defined on any of the interfaces implemented by the declaring type - PopulateLiteralFields(filter, (RuntimeType)interfaces[i], ref list); - PopulateRtFields(filter, (RuntimeType)interfaces[i], ref list); - } + interfaces = ReflectedType.BaseType!.GetInterfaces(); } else { - Type[]? interfaces = RuntimeTypeHandle.GetInterfaces(ReflectedType); + interfaces = RuntimeTypeHandle.GetInterfaces(ReflectedType); + } - if (interfaces != null) - { - for (int i = 0; i < interfaces.Length; i++) - { - // Populate literal fields defined on any of the interfaces implemented by the declaring type - PopulateLiteralFields(filter, (RuntimeType)interfaces[i], ref list); - PopulateRtFields(filter, (RuntimeType)interfaces[i], ref list); - } - } + foreach (Type iface in interfaces) + { + // Populate literal fields defined on any of the interfaces implemented by the declaring type + PopulateLiteralFields(filter, (RuntimeType)iface, ref list); + PopulateRtFields(filter, (RuntimeType)iface, ref list); } #endregion @@ -1016,23 +1007,19 @@ private RuntimeType[] PopulateInterfaces(Filter filter) if (!RuntimeTypeHandle.IsGenericVariable(declaringType)) { - Type[]? ifaces = RuntimeTypeHandle.GetInterfaces(declaringType); - - if (ifaces != null) + Type[] ifaces = RuntimeTypeHandle.GetInterfaces(declaringType); + foreach (Type iface in ifaces) { - for (int i = 0; i < ifaces.Length; i++) - { - RuntimeType interfaceType = (RuntimeType)ifaces[i]; - - if (filter.RequiresStringComparison()) - { - if (!filter.Match(RuntimeTypeHandle.GetUtf8Name(interfaceType))) - continue; - } + RuntimeType interfaceType = (RuntimeType)iface; - Debug.Assert(interfaceType.IsInterface); - list.Add(interfaceType); + if (filter.RequiresStringComparison()) + { + if (!filter.Match(RuntimeTypeHandle.GetUtf8Name(interfaceType))) + continue; } + + Debug.Assert(interfaceType.IsInterface); + list.Add(interfaceType); } if (ReflectedType.IsSZArray) diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index dfafd7631bcaaa..643c24f1b8440f 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -91,7 +91,6 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("GetArrayRank", RuntimeTypeHandle::GetArrayRank) FCFuncElement("GetToken", RuntimeTypeHandle::GetToken) FCFuncElement("GetUtf8NameInternal", RuntimeTypeHandle::GetUtf8Name) - FCFuncElement("GetInterfaces", RuntimeTypeHandle::GetInterfaces) FCFuncElement("GetAttributes", RuntimeTypeHandle::GetAttributes) FCFuncElement("GetNumVirtuals", RuntimeTypeHandle::GetNumVirtuals) FCFuncElement("CanCastTo", RuntimeTypeHandle::CanCastTo) diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 7c330dd013dcef..a45eda8c4bb9fd 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -132,6 +132,7 @@ static const Entry s_QCall[] = DllImportEntry(RuntimeTypeHandle_GetDeclaringTypeHandle) DllImportEntry(RuntimeTypeHandle_IsVisible) DllImportEntry(RuntimeTypeHandle_ConstructName) + DllImportEntry(RuntimeTypeHandle_GetInterfaces) DllImportEntry(RuntimeTypeHandle_GetInstantiation) DllImportEntry(RuntimeTypeHandle_Instantiate) DllImportEntry(RuntimeTypeHandle_GetGenericTypeDefinition) diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 4e2f60d998b6bd..190a33a1126632 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -515,7 +515,50 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_ConstructName(QCall::TypeHandle pTyp END_QCALL; } -PTRARRAYREF CopyRuntimeTypeHandles(TypeHandle * prgTH, INT32 numTypeHandles, BinderClassID arrayElemType) +extern "C" void QCALLTYPE RuntimeTypeHandle_GetInterfaces(MethodTable* pMT, QCall::ObjectHandleOnStack result) +{ + QCALL_CONTRACT; + + _ASSERTE(pMT != NULL); + + BEGIN_QCALL; + + INT32 ifaceCount = pMT->GetNumInterfaces(); + // Allocate the array + if (ifaceCount > 0) + { + GCX_COOP(); + + struct + { + PTRARRAYREF Types; + } gc; + gc.Types = NULL; + GCPROTECT_BEGIN(gc); + TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pRuntimeTypeClass), ELEMENT_TYPE_SZARRAY); + gc.Types = (PTRARRAYREF)AllocateSzArray(arrayHandle, ifaceCount); + + UINT i = 0; + + // Populate type array + MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap(); + while (it.Next()) + { + _ASSERTE(i < ifaceCount); + OBJECTREF refInterface = it.GetInterface(pMT)->GetManagedClassObject(); + gc.Types->SetAt(i, refInterface); + _ASSERTE(gc.Types->GetAt(i) != NULL); + i++; + } + + result.Set(gc.Types); + GCPROTECT_END(); + } + + END_QCALL; +} + +static PTRARRAYREF CopyRuntimeTypeHandles(TypeHandle * prgTH, INT32 numTypeHandles, BinderClassID arrayElemType) { CONTRACTL { THROWS; @@ -579,61 +622,6 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_GetConstraints(QCall::TypeHandle pTy return; } -FCIMPL1(PtrArray*, RuntimeTypeHandle::GetInterfaces, ReflectClassBaseObject *pTypeUNSAFE) { - CONTRACTL { - FCALL_CHECK; - } - CONTRACTL_END; - - REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - - if (refType == NULL) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - TypeHandle typeHandle = refType->GetType(); - - if (typeHandle.IsGenericVariable()) - FCThrowRes(kArgumentNullException, W("Arg_InvalidHandle")); - - INT32 ifaceCount = 0; - - PTRARRAYREF refRetVal = NULL; - HELPER_METHOD_FRAME_BEGIN_RET_2(refRetVal, refType); - { - if (typeHandle.IsTypeDesc()) - { - ifaceCount = 0; - } - else - { - ifaceCount = typeHandle.GetMethodTable()->GetNumInterfaces(); - } - - // Allocate the array - if (ifaceCount > 0) - { - TypeHandle arrayHandle = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pRuntimeTypeClass), ELEMENT_TYPE_SZARRAY); - refRetVal = (PTRARRAYREF)AllocateSzArray(arrayHandle, ifaceCount); - - // populate type array - UINT i = 0; - - MethodTable::InterfaceMapIterator it = typeHandle.GetMethodTable()->IterateInterfaceMap(); - while (it.Next()) - { - OBJECTREF refInterface = it.GetInterface(typeHandle.GetMethodTable())->GetManagedClassObject(); - refRetVal->SetAt(i, refInterface); - _ASSERTE(refRetVal->GetAt(i) != NULL); - i++; - } - } - } - HELPER_METHOD_FRAME_END(); - - return (PtrArray*)OBJECTREFToObject(refRetVal); -} -FCIMPLEND - FCIMPL1(INT32, RuntimeTypeHandle::GetAttributes, ReflectClassBaseObject *pTypeUNSAFE) { CONTRACTL { FCALL_CHECK; diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index c756a3c8c7c7b8..7ae67d880954f2 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -137,8 +137,6 @@ class RuntimeTypeHandle static FCDECL2(FC_BOOL_RET, CompareCanonicalHandles, PTR_ReflectClassBaseObject pLeft, PTR_ReflectClassBaseObject pRight); - static FCDECL1(PtrArray*, GetInterfaces, ReflectClassBaseObject *pType); - static FCDECL1(EnregisteredTypeHandle, GetElementTypeHandle, EnregisteredTypeHandle th); static FCDECL1(INT32, GetNumVirtuals, ReflectClassBaseObject *pType); @@ -179,6 +177,7 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_MakeArray(QCall::TypeHandle pTypeHan extern "C" BOOL QCALLTYPE RuntimeTypeHandle_IsCollectible(QCall::TypeHandle pTypeHandle); extern "C" void QCALLTYPE RuntimeTypeHandle_PrepareMemberInfoCache(QCall::TypeHandle pMemberInfoCache); extern "C" void QCALLTYPE RuntimeTypeHandle_ConstructName(QCall::TypeHandle pTypeHandle, DWORD format, QCall::StringHandleOnStack retString); +extern "C" void QCALLTYPE RuntimeTypeHandle_GetInterfaces(MethodTable* pMT, QCall::ObjectHandleOnStack result); extern "C" BOOL QCALLTYPE RuntimeTypeHandle_IsVisible(QCall::TypeHandle pTypeHandle); extern "C" void QCALLTYPE RuntimeTypeHandle_GetInstantiation(QCall::TypeHandle pTypeHandle, QCall::ObjectHandleOnStack retType, BOOL fAsRuntimeTypeArray); extern "C" void QCALLTYPE RuntimeTypeHandle_Instantiate(QCall::TypeHandle pTypeHandle, TypeHandle * pInstArray, INT32 cInstArray, QCall::ObjectHandleOnStack retType); From 3e8c428f7b3c206fc3ded7608948218af46a7711 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Thu, 5 Dec 2024 20:37:10 -0800 Subject: [PATCH 3/8] Convert Signature.CompareSig() to QCall. Rename to Signature.AreEqual(). --- .../System/Reflection/RuntimePropertyInfo.cs | 2 +- .../src/System/RuntimeHandles.cs | 15 +++++++-- src/coreclr/vm/callhelpers.cpp | 4 --- src/coreclr/vm/ecalllist.h | 1 - src/coreclr/vm/qcallentrypoints.cpp | 1 + src/coreclr/vm/runtimehandles.cpp | 33 ++++++++----------- src/coreclr/vm/runtimehandles.h | 6 ++-- src/coreclr/vm/siginfo.cpp | 1 - 8 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs index 2d542fb78ee101..51b1f84864b1a9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/RuntimePropertyInfo.cs @@ -107,7 +107,7 @@ internal bool EqualsSig(RuntimePropertyInfo target) Debug.Assert(this != target); Debug.Assert(this.ReflectedType == target.ReflectedType); - return Signature.CompareSig(this.Signature, target.Signature); + return Signature.AreEqual(this.Signature, target.Signature); } internal BindingFlags BindingFlags => m_bindingFlags; #endregion diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 3d132e75bbc70f..126584d7798de9 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -1897,7 +1897,7 @@ internal static int GetMDStreamVersion(RuntimeModule module) public int MDStreamVersion => GetMDStreamVersion(GetRuntimeModule()); } - internal sealed unsafe class Signature + internal sealed unsafe partial class Signature { #region FCalls [MemberNotNull(nameof(m_arguments))] @@ -1961,8 +1961,17 @@ public Signature(void* pCorSig, int cCorSig, RuntimeType declaringType) internal RuntimeType ReturnType => m_returnTypeORfieldType; internal RuntimeType FieldType => m_returnTypeORfieldType; - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern bool CompareSig(Signature sig1, Signature sig2); + [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.m_sig, sig1.m_csig, new QCallTypeHandle(ref sig1.m_declaringType!), + sig2.m_sig, sig2.m_csig, new QCallTypeHandle(ref sig2.m_declaringType!)) != Interop.BOOL.FALSE; + } internal Type[] GetCustomModifiers(int parameterIndex, bool required) => GetCustomModifiersAtOffset(GetParameterOffset(parameterIndex), required); diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp index 3906d396c87f54..d926ff9d8d62c7 100644 --- a/src/coreclr/vm/callhelpers.cpp +++ b/src/coreclr/vm/callhelpers.cpp @@ -11,10 +11,6 @@ // To include declaration of "AppDomainTransitionExceptionFilter" #include "excep.h" - -// To include declaration of "SignatureNative" -#include "runtimehandles.h" - #include "invokeutil.h" #include "argdestination.h" diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 643c24f1b8440f..87e1178e0e97e9 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -133,7 +133,6 @@ FCFuncEnd() FCFuncStart(gSignatureNative) FCFuncElement("GetSignature", SignatureNative::GetSignature) - FCFuncElement("CompareSig", SignatureNative::CompareSig) FCFuncElement("GetParameterOffsetInternal", SignatureNative::GetParameterOffsetInternal) FCFuncElement("GetTypeParameterOffset", SignatureNative::GetTypeParameterOffset) FCFuncElement("GetCustomModifiersAtOffset", SignatureNative::GetCustomModifiersAtOffset) diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index a45eda8c4bb9fd..f4f733d855c2c2 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -188,6 +188,7 @@ static const Entry s_QCall[] = DllImportEntry(ModuleHandle_GetPEKind) DllImportEntry(ModuleHandle_GetDynamicMethod) DllImportEntry(AssemblyHandle_GetManifestModuleSlow) + DllImportEntry(Signature_AreEqual) DllImportEntry(TypeBuilder_DefineGenericParam) DllImportEntry(TypeBuilder_DefineType) DllImportEntry(TypeBuilder_SetParentType) diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 190a33a1126632..39db2d580ca7ec 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1828,32 +1828,25 @@ FCIMPL6(void, SignatureNative::GetSignature, } FCIMPLEND -FCIMPL2(FC_BOOL_RET, SignatureNative::CompareSig, SignatureNative* pLhsUNSAFE, SignatureNative* pRhsUNSAFE) +extern "C" BOOL QCALLTYPE Signature_AreEqual( + PCCOR_SIGNATURE sig1, INT32 cSig1, QCall::TypeHandle handle1, + PCCOR_SIGNATURE sig2, INT32 cSig2, QCall::TypeHandle handle2) { - FCALL_CONTRACT; + QCALL_CONTRACT; - INT32 ret = 0; + BOOL ret = FALSE; - struct - { - SIGNATURENATIVEREF pLhs; - SIGNATURENATIVEREF pRhs; - } gc; + BEGIN_QCALL; - gc.pLhs = (SIGNATURENATIVEREF)pLhsUNSAFE; - gc.pRhs = (SIGNATURENATIVEREF)pRhsUNSAFE; + ret = MetaSig::CompareMethodSigs( + sig1, cSig1, handle1.AsTypeHandle().GetModule(), NULL, + sig2, cSig2, handle2.AsTypeHandle().GetModule(), NULL, + FALSE); - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - { - ret = MetaSig::CompareMethodSigs( - gc.pLhs->GetCorSig(), gc.pLhs->GetCorSigSize(), gc.pLhs->GetModule(), NULL, - gc.pRhs->GetCorSig(), gc.pRhs->GetCorSigSize(), gc.pRhs->GetModule(), NULL, - FALSE); - } - HELPER_METHOD_FRAME_END(); - FC_RETURN_BOOL(ret); + END_QCALL; + + return ret; } -FCIMPLEND extern "C" void QCALLTYPE RuntimeMethodHandle_GetMethodInstantiation(MethodDesc * pMethod, QCall::ObjectHandleOnStack retTypes, BOOL fAsRuntimeTypeArray) { diff --git a/src/coreclr/vm/runtimehandles.h b/src/coreclr/vm/runtimehandles.h index 7ae67d880954f2..5dd2f5ff5676e9 100644 --- a/src/coreclr/vm/runtimehandles.h +++ b/src/coreclr/vm/runtimehandles.h @@ -327,8 +327,6 @@ class SignatureNative : public Object FieldDesc *pFieldDesc, ReflectMethodObject *pMethodUNSAFE, ReflectClassBaseObject *pDeclaringType); - static FCDECL2(FC_BOOL_RET, CompareSig, SignatureNative* pLhs, SignatureNative* pRhs); - static FCDECL3(INT32, GetParameterOffsetInternal, PCCOR_SIGNATURE sig, DWORD csig, INT32 parameterIndex); static FCDECL3(INT32, GetTypeParameterOffset, SignatureNative* pSig, INT32 offset, INT32 index); @@ -508,6 +506,10 @@ class SignatureNative : public Object MethodDesc* m_pMethod; }; +extern "C" BOOL QCALLTYPE Signature_AreEqual( + PCCOR_SIGNATURE sig1, INT32 cSig1, QCall::TypeHandle handle1, + PCCOR_SIGNATURE sig2, INT32 cSig2, QCall::TypeHandle handle2); + class ReflectionPointer : public Object { public: diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index d1154722b340c5..e7717aba1ce75a 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -16,7 +16,6 @@ #include "gcheaputilities.h" #include "field.h" #include "eeconfig.h" -#include "runtimehandles.h" // for SignatureNative #include "winwrap.h" #include #include "sigbuilder.h" From 1a413f83ecf15503f1a1bcb75ee22dc3c91f8690 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 6 Dec 2024 08:01:03 -0800 Subject: [PATCH 4/8] Fix nullable result for FCall --- .../System.Private.CoreLib/src/System/RuntimeHandles.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 126584d7798de9..e0d8228781c2df 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -1901,6 +1901,7 @@ internal sealed unsafe partial class Signature { #region FCalls [MemberNotNull(nameof(m_arguments))] + [MemberNotNull(nameof(m_declaringType))] [MemberNotNull(nameof(m_returnTypeORfieldType))] [MethodImpl(MethodImplOptions.InternalCall)] private extern void GetSignature( @@ -1913,7 +1914,7 @@ private extern void GetSignature( // Keep the layout in sync with SignatureNative in the VM // internal RuntimeType[] m_arguments; - internal RuntimeType? m_declaringType; + internal RuntimeType m_declaringType; internal RuntimeType m_returnTypeORfieldType; internal object? m_keepalive; internal void* m_sig; @@ -1969,8 +1970,8 @@ private static partial Interop.BOOL AreEqual( internal static bool AreEqual(Signature sig1, Signature sig2) { return AreEqual( - sig1.m_sig, sig1.m_csig, new QCallTypeHandle(ref sig1.m_declaringType!), - sig2.m_sig, sig2.m_csig, new QCallTypeHandle(ref sig2.m_declaringType!)) != Interop.BOOL.FALSE; + sig1.m_sig, sig1.m_csig, new QCallTypeHandle(ref sig1.m_declaringType), + sig2.m_sig, sig2.m_csig, new QCallTypeHandle(ref sig2.m_declaringType)) != Interop.BOOL.FALSE; } internal Type[] GetCustomModifiers(int parameterIndex, bool required) => From 04b3b36fa97f5ffe055ed7d1a4bf54304376e535 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Fri, 6 Dec 2024 08:26:07 -0800 Subject: [PATCH 5/8] Fix type --- src/coreclr/vm/runtimehandles.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 39db2d580ca7ec..42f1772e37d8c7 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -544,7 +544,7 @@ extern "C" void QCALLTYPE RuntimeTypeHandle_GetInterfaces(MethodTable* pMT, QCal MethodTable::InterfaceMapIterator it = pMT->IterateInterfaceMap(); while (it.Next()) { - _ASSERTE(i < ifaceCount); + _ASSERTE(i < (UINT)ifaceCount); OBJECTREF refInterface = it.GetInterface(pMT)->GetManagedClassObject(); gc.Types->SetAt(i, refInterface); _ASSERTE(gc.Types->GetAt(i) != NULL); From 7a98fd0b833a7905e90800b8f4c9fafd2921c139 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 6 Dec 2024 17:43:34 -0800 Subject: [PATCH 6/8] Update src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs Co-authored-by: Adeel Mujahid <3840695+am11@users.noreply.github.com> --- .../System.Private.CoreLib/src/System/RuntimeHandles.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index e0d8228781c2df..70a2e80e9a809b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -546,13 +546,13 @@ internal static Type[] GetInterfaces(RuntimeType type) { Debug.Assert(!IsGenericVariable(type)); - Type[] result = Array.Empty(); TypeHandle typeHandle = type.GetNativeTypeHandle(); if (typeHandle.IsTypeDesc) { - return result; + return []; } + Type[] result = []; GetInterfaces(typeHandle.AsMethodTable(), ObjectHandleOnStack.Create(ref result)); GC.KeepAlive(type); return result; From 31687fde3a1dfddfadbfccd1c452eb6064e55f06 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Sun, 8 Dec 2024 18:54:48 -0800 Subject: [PATCH 7/8] Feedback --- .../src/System/RuntimeHandles.cs | 16 ++++++---------- .../src/System/RuntimeType.CoreCLR.cs | 18 ++++++------------ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 70a2e80e9a809b..a1907fd90df765 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -517,25 +517,21 @@ internal static IntroducedMethodEnumerator GetIntroducedMethods(RuntimeType type [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "RuntimeTypeHandle_GetFields")] private static partial Interop.BOOL GetFields(MethodTable* pMT, Span data, ref int usedCount); - internal static bool GetFields(RuntimeType type, ref Span buffer, ref int count) + internal static bool GetFields(RuntimeType type, Span buffer, out int count) { - TypeHandle typeHandle = type.GetNativeTypeHandle(); - - CorElementType elementType = (CorElementType)typeHandle.GetCorElementType(); - if (elementType is CorElementType.ELEMENT_TYPE_VAR or CorElementType.ELEMENT_TYPE_MVAR) - { - throw new ArgumentException(SR.Arg_InvalidHandle); - } + Debug.Assert(!IsGenericVariable(type)); + TypeHandle typeHandle = type.GetNativeTypeHandle(); if (typeHandle.IsTypeDesc) { count = 0; return true; } - count = buffer.Length; - bool success = GetFields(typeHandle.AsMethodTable(), buffer, ref count) != Interop.BOOL.FALSE; + int countLocal = buffer.Length; + bool success = GetFields(typeHandle.AsMethodTable(), buffer, ref countLocal) != Interop.BOOL.FALSE; GC.KeepAlive(type); + count = countLocal; return success; } diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 9ca9e8f4d7b0f4..93aba95fae2649 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -850,23 +850,17 @@ private RuntimeFieldInfo[] PopulateFields(Filter filter) private unsafe void PopulateRtFields(Filter filter, RuntimeType declaringType, ref ListBuilder list) { Span result = stackalloc IntPtr[64]; - int count = 0; - - if (!RuntimeTypeHandle.GetFields(declaringType, ref result, ref count)) + int count; + while (!RuntimeTypeHandle.GetFields(declaringType, result, out count)) { + Debug.Assert(count > result.Length); result = new IntPtr[count]; - bool success = RuntimeTypeHandle.GetFields(declaringType, ref result, ref count); - Debug.Assert(success && result.Length == count); - PopulateRtFields(filter, result, declaringType, ref list); - } - else if (count > 0) - { - PopulateRtFields(filter, result.Slice(0, count), declaringType, ref list); } + PopulateRtFields(filter, result.Slice(0, count), declaringType, ref list); } private unsafe void PopulateRtFields(Filter filter, - Span ppFieldHandles, RuntimeType declaringType, ref ListBuilder list) + ReadOnlySpan fieldHandles, RuntimeType declaringType, ref ListBuilder list) { Debug.Assert(declaringType != null); Debug.Assert(ReflectedType != null); @@ -874,7 +868,7 @@ private unsafe void PopulateRtFields(Filter filter, bool needsStaticFieldForGeneric = declaringType.IsGenericType && !RuntimeTypeHandle.ContainsGenericVariables(declaringType); bool isInherited = declaringType != ReflectedType; - foreach (IntPtr handle in ppFieldHandles) + foreach (IntPtr handle in fieldHandles) { RuntimeFieldHandleInternal runtimeFieldHandle = new RuntimeFieldHandleInternal(handle); From d550647acde05eb99ece0c48627b137190640630 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Mon, 9 Dec 2024 08:54:41 -0800 Subject: [PATCH 8/8] Feedback --- .../src/System/RuntimeType.CoreCLR.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index 93aba95fae2649..d1591d88036b28 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -856,7 +856,11 @@ private unsafe void PopulateRtFields(Filter filter, RuntimeType declaringType, r Debug.Assert(count > result.Length); result = new IntPtr[count]; } - PopulateRtFields(filter, result.Slice(0, count), declaringType, ref list); + + if (count > 0) + { + PopulateRtFields(filter, result.Slice(0, count), declaringType, ref list); + } } private unsafe void PopulateRtFields(Filter filter,