From 3471de7ffda7105f395a25a57094097a7cc0dc88 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Sat, 27 Jul 2024 13:24:31 -0700 Subject: [PATCH] Remove HelperMethodFrame from `GetMulticastInvoke` (#105584) * Remove HelperMethodFrame from GetMulticastInvoke Move MethodTable acquisition from unmanaged to managed. This allows for converting instance FCalls to static. --- .../src/System/Delegate.CoreCLR.cs | 29 +++++++++- src/coreclr/vm/comdelegate.cpp | 57 +++++++++++-------- src/coreclr/vm/comdelegate.h | 6 +- src/coreclr/vm/qcallentrypoints.cpp | 1 + 4 files changed, 64 insertions(+), 29 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs index 5e36f1e7e0b9c..ee48dc77e94fe 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs @@ -482,10 +482,35 @@ internal static unsafe bool InternalEqualTypes(object a, object b) private extern void DelegateConstruct(object target, IntPtr slot); [MethodImpl(MethodImplOptions.InternalCall)] - internal extern IntPtr GetMulticastInvoke(); + private static extern unsafe void* GetMulticastInvoke(MethodTable* pMT); + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Delegate_GetMulticastInvokeSlow")] + private static unsafe partial void* GetMulticastInvokeSlow(MethodTable* pMT); + + internal unsafe IntPtr GetMulticastInvoke() + { + MethodTable* pMT = RuntimeHelpers.GetMethodTable(this); + void* ptr = GetMulticastInvoke(pMT); + if (ptr == null) + { + ptr = GetMulticastInvokeSlow(pMT); + Debug.Assert(ptr != null); + Debug.Assert(ptr == GetMulticastInvoke(pMT)); + } + // No GC.KeepAlive() since the caller must keep instance alive to use returned pointer. + return (IntPtr)ptr; + } [MethodImpl(MethodImplOptions.InternalCall)] - internal extern IntPtr GetInvokeMethod(); + private static extern unsafe void* GetInvokeMethod(MethodTable* pMT); + + internal unsafe IntPtr GetInvokeMethod() + { + MethodTable* pMT = RuntimeHelpers.GetMethodTable(this); + void* ptr = GetInvokeMethod(pMT); + // No GC.KeepAlive() since the caller must keep instance alive to use returned pointer. + return (IntPtr)ptr; + } internal IRuntimeMethodInfo FindMethodHandle() { diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 86b5e68f06704..2cb10d29b1a28 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2120,36 +2120,43 @@ extern "C" BOOL QCALLTYPE Delegate_InternalEqualMethodHandles(QCall::ObjectHandl return fRet; } -FCIMPL1(MethodDesc*, COMDelegate::GetInvokeMethod, Object* refThisIn) +FCIMPL1(MethodDesc*, COMDelegate::GetInvokeMethod, MethodTable* pDelegateMT) { FCALL_CONTRACT; + _ASSERTE(pDelegateMT != NULL); - OBJECTREF refThis = ObjectToOBJECTREF(refThisIn); - MethodTable * pDelMT = refThis->GetMethodTable(); - - MethodDesc* pMD = ((DelegateEEClass*)(pDelMT->GetClass()))->GetInvokeMethod(); - _ASSERTE(pMD); + MethodDesc* pMD = ((DelegateEEClass*)(pDelegateMT->GetClass()))->GetInvokeMethod(); + _ASSERTE(pMD != NULL); return pMD; } FCIMPLEND -FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) +FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, MethodTable* pDelegateMT) { FCALL_CONTRACT; + _ASSERTE(pDelegateMT != NULL); + + DelegateEEClass* delegateEEClass = (DelegateEEClass*)pDelegateMT->GetClass(); + Stub *pStub = delegateEEClass->m_pMultiCastInvokeStub; + return (pStub != NULL) ? pStub->GetEntryPoint() : (PCODE)NULL; +} +FCIMPLEND + +extern "C" PCODE QCALLTYPE Delegate_GetMulticastInvokeSlow(MethodTable* pDelegateMT) +{ + QCALL_CONTRACT; + _ASSERTE(pDelegateMT != NULL); + + PCODE fptr = (PCODE)NULL; - OBJECTREF refThis = ObjectToOBJECTREF(refThisIn); - MethodTable *pDelegateMT = refThis->GetMethodTable(); + BEGIN_QCALL; - DelegateEEClass *delegateEEClass = ((DelegateEEClass*)(pDelegateMT->GetClass())); + DelegateEEClass *delegateEEClass = (DelegateEEClass*)pDelegateMT->GetClass(); Stub *pStub = delegateEEClass->m_pMultiCastInvokeStub; if (pStub == NULL) { MethodDesc* pMD = delegateEEClass->GetInvokeMethod(); - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - GCX_PREEMP(); - MetaSig sig(pMD); BOOL fReturnVal = !sig.IsReturnTypeVoid(); @@ -2162,7 +2169,7 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) DWORD dwLoopCounterNum = pCode->NewLocal(ELEMENT_TYPE_I4); DWORD dwReturnValNum = -1; - if(fReturnVal) + if (fReturnVal) dwReturnValNum = pCode->NewLocal(sig.GetRetTypeHandleNT()); ILCodeLabel *nextDelegate = pCode->NewCodeLabel(); @@ -2192,7 +2199,7 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitCALL(pCode->GetToken(pMD), sig.NumFixedArgs(), fReturnVal); // Save return value. - if(fReturnVal) + if (fReturnVal) pCode->EmitSTLOC(dwReturnValNum); // increment counter @@ -2203,7 +2210,7 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) //Label_checkCount pCode->EmitLabel(checkCount); - + #ifdef DEBUGGING_SUPPORTED ILCodeLabel *invokeTraceHelper = pCode->NewCodeLabel(); ILCodeLabel *debuggerCheckEnd = pCode->NewCodeLabel(); @@ -2228,7 +2235,7 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitBLT(nextDelegate); // load the return value. return value from the last delegate call is returned - if(fReturnVal) + if (fReturnVal) pCode->EmitLDLOC(dwReturnValNum); // return @@ -2247,8 +2254,7 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) PCCOR_SIGNATURE pSig; DWORD cbSig; - - pMD->GetSig(&pSig,&cbSig); + pMD->GetSig(&pSig, &cbSig); MethodDesc* pStubMD = ILStubCache::CreateAndLinkNewILStubMethodDesc(pMD->GetLoaderAllocator(), pMD->GetMethodTable(), @@ -2257,17 +2263,18 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pSig, cbSig, NULL, &sl); - pStub = Stub::NewStub(JitILStub(pStubMD)); InterlockedCompareExchangeT(&delegateEEClass->m_pMultiCastInvokeStub, pStub, NULL); - - HELPER_METHOD_FRAME_END(); + pStub = delegateEEClass->m_pMultiCastInvokeStub; } - return pStub->GetEntryPoint(); + fptr = pStub->GetEntryPoint(); + + END_QCALL; + + return fptr; } -FCIMPLEND PCODE COMDelegate::GetWrapperInvoke(MethodDesc* pMD) { diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index dd5948f02bb98..bb12973f505e2 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -45,8 +45,8 @@ class COMDelegate static FCDECL3(void, DelegateConstruct, Object* refThis, Object* target, PCODE method); // Get the invoke method for the delegate. Used to transition delegates to multicast delegates. - static FCDECL1(PCODE, GetMulticastInvoke, Object* refThis); - static FCDECL1(MethodDesc*, GetInvokeMethod, Object* refThis); + static FCDECL1(PCODE, GetMulticastInvoke, MethodTable* pDelegateMT); + static FCDECL1(MethodDesc*, GetInvokeMethod, MethodTable* pDelegateMT); static PCODE GetWrapperInvoke(MethodDesc* pMD); // determines where the delegate needs to be wrapped for non-security reason static BOOL NeedsWrapperDelegate(MethodDesc* pTargetMD); @@ -114,6 +114,8 @@ class COMDelegate BOOL fIsOpenDelegate); }; +extern "C" PCODE QCALLTYPE Delegate_GetMulticastInvokeSlow(MethodTable* pDelegateMT); + extern "C" PCODE QCALLTYPE Delegate_AdjustTarget(QCall::ObjectHandleOnStack target, PCODE method); extern "C" void QCALLTYPE Delegate_InitializeVirtualCallStub(QCall::ObjectHandleOnStack d, PCODE method); diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index cf72e66de6d99..11234b4ba2dce 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -89,6 +89,7 @@ static const Entry s_QCall[] = DllImportEntry(Delegate_BindToMethodName) DllImportEntry(Delegate_BindToMethodInfo) DllImportEntry(Delegate_InitializeVirtualCallStub) + DllImportEntry(Delegate_GetMulticastInvokeSlow) DllImportEntry(Delegate_AdjustTarget) DllImportEntry(Delegate_InternalAlloc) DllImportEntry(Delegate_InternalAllocLike)