Skip to content

Commit

Permalink
Remove HelperMethodFrame from GetMulticastInvoke (#105584)
Browse files Browse the repository at this point in the history
* Remove HelperMethodFrame from GetMulticastInvoke

Move MethodTable acquisition from unmanaged to managed.
This allows for converting instance FCalls to static.
  • Loading branch information
AaronRobinsonMSFT authored Jul 27, 2024
1 parent cb65d11 commit 3471de7
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 29 deletions.
29 changes: 27 additions & 2 deletions src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
57 changes: 32 additions & 25 deletions src/coreclr/vm/comdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand All @@ -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
Expand All @@ -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(),
Expand All @@ -2257,17 +2263,18 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
pSig, cbSig,
NULL,
&sl);

pStub = Stub::NewStub(JitILStub(pStubMD));

InterlockedCompareExchangeT<PTR_Stub>(&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)
{
Expand Down
6 changes: 4 additions & 2 deletions src/coreclr/vm/comdelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/qcallentrypoints.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit 3471de7

Please sign in to comment.