From 5ec51980de746084ad6cb77c6fd2f6ce3abf747f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 16 Jun 2024 23:06:47 +0800 Subject: [PATCH 01/13] Enable FEATURE_MULTICASTSTUB_AS_IL on win-x86 --- src/coreclr/clr.featuredefines.props | 3 +-- src/coreclr/clrdefinitions.cmake | 9 +-------- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/coreclr/clr.featuredefines.props b/src/coreclr/clr.featuredefines.props index 82dded497b6f9..97053a57bb5ed 100644 --- a/src/coreclr/clr.featuredefines.props +++ b/src/coreclr/clr.featuredefines.props @@ -1,5 +1,6 @@ + true true true true @@ -10,12 +11,10 @@ true - true true - true true true true diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index e376c63f75847..3e15c386d19c3 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -67,14 +67,7 @@ if(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64) add_compile_definitions(OUT_OF_PROCESS_SETTHREADCONTEXT) endif(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64) -# Features - please keep them alphabetically sorted -if(CLR_CMAKE_TARGET_WIN32) - if(NOT CLR_CMAKE_TARGET_ARCH_I386) - add_definitions(-DFEATURE_MULTICASTSTUB_AS_IL) - endif() -else(CLR_CMAKE_TARGET_WIN32) - add_definitions(-DFEATURE_MULTICASTSTUB_AS_IL) -endif(CLR_CMAKE_TARGET_WIN32) +add_definitions(-DFEATURE_MULTICASTSTUB_AS_IL) if(NOT CLR_CMAKE_TARGET_ARCH_I386) add_definitions(-DFEATURE_PORTABLE_SHUFFLE_THUNKS) From a8225a4714a01666956580bcc51bb8b74583a68f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 16 Jun 2024 23:21:49 +0800 Subject: [PATCH 02/13] Unconditionally enable at use sites --- .../System.Private.CoreLib/src/System/StubHelpers.cs | 2 -- src/coreclr/debug/ee/controller.cpp | 7 ++----- src/coreclr/debug/ee/frameinfo.cpp | 2 -- src/coreclr/vm/corelib.h | 2 -- src/coreclr/vm/dllimport.h | 4 ---- src/coreclr/vm/ecalllist.h | 2 -- src/coreclr/vm/ilstubcache.cpp | 4 ---- src/coreclr/vm/method.hpp | 4 ---- src/coreclr/vm/stubhelpers.cpp | 2 -- src/coreclr/vm/stubhelpers.h | 2 -- src/coreclr/vm/stubmgr.cpp | 9 +-------- 11 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index cd96be0804900..4d04557565c3c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1616,10 +1616,8 @@ internal static unsafe void LayoutDestroyNativeInternal(object obj, byte* pNativ [MethodImpl(MethodImplOptions.InternalCall)] internal static extern IntPtr GetStubContext(); -#if FEATURE_MULTICASTSTUB_AS_IL [MethodImpl(MethodImplOptions.InternalCall)] internal static extern void MulticastDebuggerTraceHelper(object o, int count); -#endif [Intrinsic] [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/src/coreclr/debug/ee/controller.cpp b/src/coreclr/debug/ee/controller.cpp index 31feaf4a088f7..a285a98b183de 100644 --- a/src/coreclr/debug/ee/controller.cpp +++ b/src/coreclr/debug/ee/controller.cpp @@ -6259,7 +6259,6 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio _ASSERTE(IsCloserToLeaf(dbgLastFP, info->m_activeFrame.fp)); #endif -#ifdef FEATURE_MULTICASTSTUB_AS_IL if (info->m_activeFrame.md != nullptr && info->m_activeFrame.md->IsILStub() && info->m_activeFrame.md->AsDynamicMethodDesc()->IsMulticastStub()) { LOG((LF_CORDB, LL_INFO10000, @@ -6286,10 +6285,8 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio true)) break; } - else -#endif // FEATURE_MULTICASTSTUB_AS_IL - if (info->m_activeFrame.md != nullptr && info->m_activeFrame.md->IsILStub() && - info->m_activeFrame.md->AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubTailCallCallTarget) + else if (info->m_activeFrame.md != nullptr && info->m_activeFrame.md->IsILStub() && + info->m_activeFrame.md->AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubTailCallCallTarget) { // Normally the stack trace would not include IL stubs, but we // include this specific IL stub so that we can check if a call into diff --git a/src/coreclr/debug/ee/frameinfo.cpp b/src/coreclr/debug/ee/frameinfo.cpp index 371e65c54a95f..f45c59c378b47 100644 --- a/src/coreclr/debug/ee/frameinfo.cpp +++ b/src/coreclr/debug/ee/frameinfo.cpp @@ -1562,9 +1562,7 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) { _ASSERTE(md->IsDynamicMethod()); DynamicMethodDesc* dMD = md->AsDynamicMethodDesc(); -#ifdef FEATURE_MULTICASTSTUB_AS_IL use |= dMD->IsMulticastStub(); -#endif use |= dMD->GetILStubType() == DynamicMethodDesc::StubTailCallCallTarget; if (use) diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 2e1a7e970563f..0941e376d83e7 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -938,9 +938,7 @@ DEFINE_METHOD(STUBHELPERS, PROFILER_BEGIN_TRANSITION_CALLBACK, Profiler DEFINE_METHOD(STUBHELPERS, PROFILER_END_TRANSITION_CALLBACK, ProfilerEndTransitionCallback, SM_IntPtr_IntPtr_RetVoid) #endif -#ifdef FEATURE_MULTICASTSTUB_AS_IL DEFINE_METHOD(STUBHELPERS, MULTICAST_DEBUGGER_TRACE_HELPER, MulticastDebuggerTraceHelper, SM_Obj_Int_RetVoid) -#endif DEFINE_CLASS(CLEANUP_WORK_LIST_ELEMENT, StubHelpers, CleanupWorkListElement) diff --git a/src/coreclr/vm/dllimport.h b/src/coreclr/vm/dllimport.h index 891221cff6b84..f5e2c058fb1a1 100644 --- a/src/coreclr/vm/dllimport.h +++ b/src/coreclr/vm/dllimport.h @@ -194,9 +194,7 @@ enum ILStubTypes ILSTUB_ARRAYOP_GET = 0x80000001, ILSTUB_ARRAYOP_SET = 0x80000002, ILSTUB_ARRAYOP_ADDRESS = 0x80000003, -#ifdef FEATURE_MULTICASTSTUB_AS_IL ILSTUB_MULTICASTDELEGATE_INVOKE = 0x80000004, -#endif #ifdef FEATURE_INSTANTIATINGSTUB_AS_IL ILSTUB_UNBOXINGILSTUB = 0x80000005, ILSTUB_INSTANTIATINGSTUB = 0x80000006, @@ -231,9 +229,7 @@ inline bool SF_IsArrayOpStub (DWORD dwStubFlags) { LIMITED_METHOD_CONT (dwStubFlags == ILSTUB_ARRAYOP_SET) || (dwStubFlags == ILSTUB_ARRAYOP_ADDRESS)); } -#ifdef FEATURE_MULTICASTSTUB_AS_IL inline bool SF_IsMulticastDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_MULTICASTDELEGATE_INVOKE); } -#endif inline bool SF_IsWrapperDelegateStub (DWORD dwStubFlags) { LIMITED_METHOD_CONTRACT; return (dwStubFlags == ILSTUB_WRAPPERDELEGATE_INVOKE); } #ifdef FEATURE_INSTANTIATINGSTUB_AS_IL diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index d820c4d8e33b2..523261cfc0e9e 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -473,9 +473,7 @@ FCFuncStart(gStubHelperFuncs) FCFuncElement("ValidateByref", StubHelpers::ValidateByref) FCFuncElement("LogPinnedArgument", StubHelpers::LogPinnedArgument) FCFuncElement("GetStubContext", StubHelpers::GetStubContext) -#ifdef FEATURE_MULTICASTSTUB_AS_IL FCFuncElement("MulticastDebuggerTraceHelper", StubHelpers::MulticastDebuggerTraceHelper) -#endif //FEATURE_MULTICASTSTUB_AS_IL FCFuncElement("NextCallReturnAddress", StubHelpers::NextCallReturnAddress) FCFuncEnd() diff --git a/src/coreclr/vm/ilstubcache.cpp b/src/coreclr/vm/ilstubcache.cpp index 8d3c4fe20b27f..65afb93865dcd 100644 --- a/src/coreclr/vm/ilstubcache.cpp +++ b/src/coreclr/vm/ilstubcache.cpp @@ -147,9 +147,7 @@ namespace case DynamicMethodDesc::StubCOMToCLRInterop: return "IL_STUB_COMtoCLR"; case DynamicMethodDesc::StubStructMarshalInterop: return "IL_STUB_StructMarshal"; case DynamicMethodDesc::StubArrayOp: return "IL_STUB_Array"; -#ifdef FEATURE_MULTICASTSTUB_AS_IL case DynamicMethodDesc::StubMulticastDelegate: return "IL_STUB_MulticastDelegate_Invoke"; -#endif #ifdef FEATURE_INSTANTIATINGSTUB_AS_IL case DynamicMethodDesc::StubUnboxingIL: return "IL_STUB_UnboxingStub"; case DynamicMethodDesc::StubInstantiating: return "IL_STUB_InstantiatingStub"; @@ -239,13 +237,11 @@ MethodDesc* ILStubCache::CreateNewMethodDesc(LoaderHeap* pCreationHeap, MethodTa pMD->SetILStubType(DynamicMethodDesc::StubArrayOp); } else -#ifdef FEATURE_MULTICASTSTUB_AS_IL if (SF_IsMulticastDelegateStub(dwStubFlags)) { pMD->SetILStubType(DynamicMethodDesc::StubMulticastDelegate); } else -#endif if (SF_IsWrapperDelegateStub(dwStubFlags)) { pMD->SetILStubType(DynamicMethodDesc::StubWrapperDelegate); diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 288b5350dc1d4..7c229b146a538 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -2433,9 +2433,7 @@ class DynamicMethodDesc : public StoredSigMethodDesc StubCOMToCLRInterop, StubStructMarshalInterop, StubArrayOp, -#ifdef FEATURE_MULTICASTSTUB_AS_IL StubMulticastDelegate, -#endif StubWrapperDelegate, #ifdef FEATURE_INSTANTIATINGSTUB_AS_IL StubUnboxingIL, @@ -2587,14 +2585,12 @@ class DynamicMethodDesc : public StoredSigMethodDesc && GetILStubType() == StubCLRToNativeInterop; } -#ifdef FEATURE_MULTICASTSTUB_AS_IL bool IsMulticastStub() const { LIMITED_METHOD_DAC_CONTRACT; _ASSERTE(IsILStub()); return GetILStubType() == DynamicMethodDesc::StubMulticastDelegate; } -#endif bool IsWrapperDelegateStub() const { LIMITED_METHOD_DAC_CONTRACT; diff --git a/src/coreclr/vm/stubhelpers.cpp b/src/coreclr/vm/stubhelpers.cpp index 187c86f53a375..e533422417c16 100644 --- a/src/coreclr/vm/stubhelpers.cpp +++ b/src/coreclr/vm/stubhelpers.cpp @@ -808,14 +808,12 @@ FCIMPL1(DWORD, StubHelpers::CalcVaListSize, VARARGS *varargs) } FCIMPLEND -#ifdef FEATURE_MULTICASTSTUB_AS_IL FCIMPL2(void, StubHelpers::MulticastDebuggerTraceHelper, Object* element, INT32 count) { FCALL_CONTRACT; FCUnique(0xa5); } FCIMPLEND -#endif // FEATURE_MULTICASTSTUB_AS_IL FCIMPL0(void*, StubHelpers::NextCallReturnAddress) { diff --git a/src/coreclr/vm/stubhelpers.h b/src/coreclr/vm/stubhelpers.h index 16b3f9230fcd7..3a5c1f30e5781 100644 --- a/src/coreclr/vm/stubhelpers.h +++ b/src/coreclr/vm/stubhelpers.h @@ -75,9 +75,7 @@ class StubHelpers static FCDECL2(void, ProfilerEndTransitionCallback, MethodDesc* pRealMD, Thread* pThread); #endif -#ifdef FEATURE_MULTICASTSTUB_AS_IL static FCDECL2(void, MulticastDebuggerTraceHelper, Object*, INT32); -#endif static FCDECL0(void*, NextCallReturnAddress); }; diff --git a/src/coreclr/vm/stubmgr.cpp b/src/coreclr/vm/stubmgr.cpp index d1a7c11f7d649..c24e0c277fd91 100644 --- a/src/coreclr/vm/stubmgr.cpp +++ b/src/coreclr/vm/stubmgr.cpp @@ -1810,14 +1810,12 @@ BOOL ILStubManager::DoTraceStub(PCODE stubStartAddress, PCODE traceDestination = (PCODE)NULL; -#ifdef FEATURE_MULTICASTSTUB_AS_IL MethodDesc* pStubMD = ExecutionManager::GetCodeMethodDesc(stubStartAddress); if (pStubMD != NULL && pStubMD->AsDynamicMethodDesc()->IsMulticastStub()) { traceDestination = GetEEFuncEntryPoint(StubHelpers::MulticastDebuggerTraceHelper); } else -#endif // FEATURE_MULTICASTSTUB_AS_IL { // This call is going out to unmanaged code, either through pinvoke or COM interop. traceDestination = stubStartAddress; @@ -1872,13 +1870,11 @@ BOOL ILStubManager::TraceManager(Thread *thread, PCODE stubIP = GetIP(pContext); *pRetAddr = (BYTE *)StubManagerHelpers::GetReturnAddress(pContext); -#ifdef FEATURE_MULTICASTSTUB_AS_IL if (stubIP == GetEEFuncEntryPoint(StubHelpers::MulticastDebuggerTraceHelper)) { stubIP = (PCODE)*pRetAddr; *pRetAddr = (BYTE*)StubManagerHelpers::GetRetAddrFromMulticastILStubFrame(pContext); } -#endif DynamicMethodDesc *pStubMD = Entry2MethodDesc(stubIP, NULL)->AsDynamicMethodDesc(); TADDR arg = StubManagerHelpers::GetHiddenArg(pContext); @@ -1889,7 +1885,6 @@ BOOL ILStubManager::TraceManager(Thread *thread, // See code:ILStubCache.CreateNewMethodDesc for the code that sets flags on stub MDs PCODE target = (PCODE)NULL; -#ifdef FEATURE_MULTICASTSTUB_AS_IL if (pStubMD->IsMulticastStub()) { _ASSERTE(GetIP(pContext) == GetEEFuncEntryPoint(StubHelpers::MulticastDebuggerTraceHelper)); @@ -1913,9 +1908,7 @@ BOOL ILStubManager::TraceManager(Thread *thread, return StubLinkStubManager::TraceDelegateObject(pbDel, trace); } } - else -#endif // FEATURE_MULTICASTSTUB_AS_IL - if (pStubMD->IsReverseStub()) + else if (pStubMD->IsReverseStub()) { if (pStubMD->IsStatic()) { From 70c5e195e60d84341434232871091cf03882fa56 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 17 Jun 2024 00:18:56 +0800 Subject: [PATCH 03/13] Remove dead code --- src/coreclr/debug/ee/frameinfo.cpp | 22 -- src/coreclr/inc/vptr_list.h | 1 - src/coreclr/vm/appdomain.cpp | 12 -- src/coreclr/vm/comdelegate.cpp | 67 ------ src/coreclr/vm/comdelegate.h | 11 - src/coreclr/vm/frames.cpp | 68 ------ src/coreclr/vm/frames.h | 65 ------ src/coreclr/vm/i386/stublinkerx86.cpp | 287 -------------------------- src/coreclr/vm/i386/stublinkerx86.h | 11 - src/coreclr/vm/stublink.cpp | 231 --------------------- src/coreclr/vm/stublink.h | 66 ------ 11 files changed, 841 deletions(-) diff --git a/src/coreclr/debug/ee/frameinfo.cpp b/src/coreclr/debug/ee/frameinfo.cpp index f45c59c378b47..e69c50c4d0b8c 100644 --- a/src/coreclr/debug/ee/frameinfo.cpp +++ b/src/coreclr/debug/ee/frameinfo.cpp @@ -1757,28 +1757,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data) break; - // Put frames we want to ignore here: - case Frame::TYPE_MULTICAST: - LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_MULTICAST.\n")); - if (d->ShouldIgnoreNonmethodFrames()) - { - // Multicast frames exist only to gc protect the arguments - // between invocations of a delegate. They don't have code that - // we can (currently) show the user (we could change this with - // work, but why bother? It's an internal stub, and even if the - // user could see it, they can't modify it). - LOG((LF_CORDB, LL_INFO100000, "DWSP: Skipping frame 0x%x b/c it's " - "a multicast frame!\n", frame)); - use = false; - } - else - { - LOG((LF_CORDB, LL_INFO100000, "DWSP: NOT Skipping frame 0x%x even thought it's " - "a multicast frame!\n", frame)); - INTERNAL_FRAME_ACTION(d, use); - } - break; - default: _ASSERTE(!"Invalid frame type!"); break; diff --git a/src/coreclr/inc/vptr_list.h b/src/coreclr/inc/vptr_list.h index 8ad9ff44e8cf0..de8b5bfc9d190 100644 --- a/src/coreclr/inc/vptr_list.h +++ b/src/coreclr/inc/vptr_list.h @@ -68,7 +68,6 @@ VPTR_CLASS(HelperMethodFrame_PROTECTOBJ) VPTR_CLASS(HijackFrame) #endif VPTR_CLASS(InlinedCallFrame) -VPTR_CLASS(MulticastFrame) VPTR_CLASS(PInvokeCalliFrame) VPTR_CLASS(PrestubMethodFrame) VPTR_CLASS(ProtectByRefsFrame) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 80a8faace0d90..e36a2b57a0390 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1582,18 +1582,6 @@ StackWalkAction SystemDomain::CallersMethodCallbackWithStackMark(CrawlFrame* pCf if (SystemDomain::IsReflectionInvocationMethod(pFunc)) return SWA_CONTINUE; - if (frame && frame->GetFrameType() == Frame::TYPE_MULTICAST) - { - // This must be either a multicast delegate invocation. - - _ASSERTE(pFunc->GetMethodTable()->IsDelegate()); - - DELEGATEREF del = (DELEGATEREF)((MulticastFrame*)frame)->GetThis(); // This can throw. - - _ASSERTE(COMDelegate::IsTrueMulticastDelegate(del)); - return SWA_CONTINUE; - } - // Return the first non-reflection/remoting frame if no stack mark was // supplied. if (!pCaller->stackMark) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index fd399b9724c01..3940444e9be4c 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -728,9 +728,6 @@ VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArrayInit(TRUE, &lock); m_pShuffleThunkCache = new ShuffleThunkCache(SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap()); -#ifndef FEATURE_MULTICASTSTUB_AS_IL - m_pMulticastStubCache = new MulticastStubCache(); -#endif } #ifdef FEATURE_COMINTEROP @@ -2139,7 +2133,6 @@ FCIMPL1(MethodDesc*, COMDelegate::GetInvokeMethod, Object* refThisIn) } FCIMPLEND -#ifdef FEATURE_MULTICASTSTUB_AS_IL FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) { FCALL_CONTRACT; @@ -2260,66 +2253,6 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) } FCIMPLEND -#else // FEATURE_MULTICASTSTUB_AS_IL - -FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) -{ - FCALL_CONTRACT; - - OBJECTREF refThis = ObjectToOBJECTREF(refThisIn); - MethodTable *pDelegateMT = refThis->GetMethodTable(); - - 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); - - UINT_PTR hash = CPUSTUBLINKER::HashMulticastInvoke(&sig); - - pStub = m_pMulticastStubCache->GetStub(hash); - if (!pStub) - { - CPUSTUBLINKER sl; - - LOG((LF_CORDB,LL_INFO10000, "COMD::GIMS making a multicast delegate\n")); - - sl.EmitMulticastInvoke(hash); - - // The cache is process-wide, based on signature. It never unloads - Stub *pCandidate = sl.Link(SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap(), NEWSTUB_FL_MULTICAST); - - Stub *pWinner = m_pMulticastStubCache->AttemptToSetStub(hash,pCandidate); - ExecutableWriterHolder candidateWriterHolder(pCandidate, sizeof(Stub)); - candidateWriterHolder.GetRW()->DecRef(); - - if (!pWinner) - COMPlusThrowOM(); - - LOG((LF_CORDB,LL_INFO10000, "Putting a MC stub at 0x%p (code:0x%p)\n", - pWinner, (BYTE*)pWinner+sizeof(Stub))); - - pStub = pWinner; - } - - // we don't need to do an InterlockedCompareExchange here - the m_pMulticastStubCache->AttemptToSetStub - // will make sure all threads racing here will get the same stub, so they'll all store the same value - delegateEEClass->m_pMultiCastInvokeStub = pStub; - - HELPER_METHOD_FRAME_END(); - } - - return pStub->GetEntryPoint(); -} -FCIMPLEND -#endif // FEATURE_MULTICASTSTUB_AS_IL - PCODE COMDelegate::GetWrapperInvoke(MethodDesc* pMD) { CONTRACTL diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h index 344c62e97dbaa..dd5948f02bb98 100644 --- a/src/coreclr/vm/comdelegate.h +++ b/src/coreclr/vm/comdelegate.h @@ -17,10 +17,6 @@ class ShuffleThunkCache; #include "dllimportcallback.h" #include "stubcache.h" -#ifndef FEATURE_MULTICASTSTUB_AS_IL -typedef ArgBasedStubCache MulticastStubCache; -#endif - VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, struct ShuffleEntry * pShuffleEntryArray, size_t nEntries); enum class ShuffleComputationType @@ -34,15 +30,8 @@ BOOL GenerateShuffleArrayPortable(MethodDesc* pMethodSrc, MethodDesc *pMethodDst class COMDelegate { private: - // friend VOID CPUSTUBLINKER::EmitMulticastInvoke(...); // friend VOID CPUSTUBLINKER::EmitShuffleThunk(...); friend class CPUSTUBLINKER; - friend BOOL MulticastFrame::TraceFrame(Thread *thread, BOOL fromPatch, - TraceDestination *trace, REGDISPLAY *regs); - -#ifndef FEATURE_MULTICASTSTUB_AS_IL - static MulticastStubCache* m_pMulticastStubCache; -#endif static CrstStatic s_DelegateToFPtrHashCrst; // Lock for the following hash. static PtrHashMap* s_pDelegateToFPtrHash; // Hash table containing the Delegate->FPtr pairs diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index c530940fc6f7f..62a1a78c6c128 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -1911,74 +1911,6 @@ BOOL HelperMethodFrame::InsureInit(bool initialInit, } -#include "comdelegate.h" - -BOOL MulticastFrame::TraceFrame(Thread *thread, BOOL fromPatch, - TraceDestination *trace, REGDISPLAY *regs) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - _ASSERTE(!fromPatch); - -#ifdef DACCESS_COMPILE - return FALSE; - -#else // !DACCESS_COMPILE - LOG((LF_CORDB,LL_INFO10000, "MulticastFrame::TF FromPatch:0x%x, at 0x%x\n", fromPatch, GetControlPC(regs))); - - // At this point we have no way to recover the Stub object from the control pc. We can't use the MD stored - // in the MulticastFrame because it points to the dummy Invoke() method, not the method we want to call. - - BYTE *pbDel = NULL; - int delegateCount = 0; - -#if defined(TARGET_X86) - // At this point the counter hasn't been incremented yet. - delegateCount = *regs->GetEdiLocation() + 1; - pbDel = *(BYTE **)( (size_t)*regs->GetEsiLocation() + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset()); -#elif defined(TARGET_AMD64) - // At this point the counter hasn't been incremented yet. - delegateCount = (int)regs->pCurrentContext->Rdi + 1; - pbDel = *(BYTE **)( (size_t)(regs->pCurrentContext->Rsi) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset()); -#elif defined(TARGET_ARM) - // At this point the counter has not yet been incremented. Counter is in R7, frame pointer in R4. - delegateCount = regs->pCurrentContext->R7 + 1; - pbDel = *(BYTE **)( (size_t)(regs->pCurrentContext->R4) + GetOffsetOfTransitionBlock() + ArgIterator::GetThisOffset()); -#else - delegateCount = 0; - PORTABILITY_ASSERT("MulticastFrame::TraceFrame (frames.cpp)"); -#endif - - int totalDelegateCount = (int)*(size_t*)(pbDel + DelegateObject::GetOffsetOfInvocationCount()); - - _ASSERTE( COMDelegate::IsTrueMulticastDelegate( ObjectToOBJECTREF((Object*)pbDel) ) ); - - if (delegateCount == totalDelegateCount) - { - LOG((LF_CORDB, LL_INFO1000, "MF::TF: Executed all stubs, should return\n")); - // We've executed all the stubs, so we should return - return FALSE; - } - else - { - // We're going to execute stub delegateCount next, so go and grab it. - BYTE *pbDelInvocationList = *(BYTE **)(pbDel + DelegateObject::GetOffsetOfInvocationList()); - - pbDel = *(BYTE**)( ((ArrayBase *)pbDelInvocationList)->GetDataPtr() + - ((ArrayBase *)pbDelInvocationList)->GetComponentSize()*delegateCount); - - _ASSERTE(pbDel); - return StubLinkStubManager::TraceDelegateObject(pbDel, trace); - } -#endif // !DACCESS_COMPILE -} - #ifndef DACCESS_COMPILE VOID InlinedCallFrame::Init() diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index bf4097d6e1a6d..75f397e978ac6 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -199,7 +199,6 @@ FRAME_TYPE_NAME(HelperMethodFrame_2OBJ) FRAME_TYPE_NAME(HelperMethodFrame_3OBJ) FRAME_TYPE_NAME(HelperMethodFrame_PROTECTOBJ) FRAME_ABSTRACT_TYPE_NAME(FramedMethodFrame) -FRAME_TYPE_NAME(MulticastFrame) #ifdef FEATURE_COMINTEROP FRAME_ABSTRACT_TYPE_NAME(UnmanagedToManagedFrame) FRAME_TYPE_NAME(ComMethodFrame) @@ -551,7 +550,6 @@ class Frame : public FrameBase TYPE_SECURITY, TYPE_CALL, TYPE_FUNC_EVAL, - TYPE_MULTICAST, // HMFs and derived classes should use this so the profiling API knows it needs // to ensure HMF-specific lazy initialization gets done w/out re-entering to the host. @@ -1749,69 +1747,6 @@ class FramedMethodFrame : public TransitionFrame } }; -//------------------------------------------------------------------------ -// This represents a call Multicast.Invoke. It's only used to gc-protect -// the arguments during the iteration. -//------------------------------------------------------------------------ - -class MulticastFrame : public TransitionFrame -{ - VPTR_VTABLE_CLASS(MulticastFrame, TransitionFrame) - - PTR_MethodDesc m_pMD; - TransitionBlock m_TransitionBlock; - -public: - - virtual MethodDesc* GetFunction() - { - LIMITED_METHOD_CONTRACT; - return m_pMD; - } - - virtual TADDR GetTransitionBlock() - { - LIMITED_METHOD_DAC_CONTRACT; - return PTR_HOST_MEMBER_TADDR(MulticastFrame, this, - m_TransitionBlock); - } - - static int GetOffsetOfTransitionBlock() - { - LIMITED_METHOD_DAC_CONTRACT; - return offsetof(MulticastFrame, m_TransitionBlock); - } - - virtual void GcScanRoots(promote_func *fn, ScanContext* sc) - { - WRAPPER_NO_CONTRACT; - TransitionFrame::GcScanRoots(fn, sc); - PromoteCallerStack(fn, sc); - } - - int GetFrameType() - { - LIMITED_METHOD_DAC_CONTRACT; - return TYPE_MULTICAST; - } - - // For the debugger: - // Our base class, FramedMethodFrame, is a M2U transition; - // but Delegate.Invoke isn't. So override and fix it here. - // If we didn't do this, we'd see a Managed/Unmanaged transition in debugger's stack trace. - virtual ETransitionType GetTransitionType() - { - LIMITED_METHOD_DAC_CONTRACT; - return TT_NONE; - } - - virtual BOOL TraceFrame(Thread *thread, BOOL fromPatch, - TraceDestination *trace, REGDISPLAY *regs); - - // Keep as last entry in class - DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(MulticastFrame) -}; - #ifdef FEATURE_COMINTEROP diff --git a/src/coreclr/vm/i386/stublinkerx86.cpp b/src/coreclr/vm/i386/stublinkerx86.cpp index fd1346b8f339f..cfe9eec74af2e 100644 --- a/src/coreclr/vm/i386/stublinkerx86.cpp +++ b/src/coreclr/vm/i386/stublinkerx86.cpp @@ -2861,138 +2861,6 @@ void StubLinkerCPU::EmitSharedComMethodStubEpilog(TADDR pFrameVptr, #if !defined(FEATURE_STUBS_AS_IL) && defined(TARGET_X86) -/*============================================================================== - Pushes a TransitionFrame on the stack - If you make any changes to the prolog instruction sequence, be sure - to update UpdateRegdisplay, too!! This service should only be called from - within the runtime. It should not be called for any unmanaged -> managed calls in. - - At the end of the generated prolog stub code: - pFrame is in ESI/RSI. - the previous pFrame is in EDI/RDI - The current Thread* is in EBX/RBX. - For x86, ESP points to TransitionFrame - For amd64, ESP points to the space reserved for the outgoing argument registers -*/ - -VOID StubLinkerCPU::EmitMethodStubProlog(TADDR pFrameVptr, int transitionBlockOffset) -{ - STANDARD_VM_CONTRACT; - - // push ebp ;; save callee-saved register - // mov ebp,esp - // push ebx ;; save callee-saved register - // push esi ;; save callee-saved register - // push edi ;; save callee-saved register - X86EmitPushEBPframe(); - - X86EmitPushReg(kEBX); - X86EmitPushReg(kESI); - X86EmitPushReg(kEDI); - - // Push & initialize ArgumentRegisters - #define ARGUMENT_REGISTER(regname) X86EmitPushReg(k##regname); - ENUM_ARGUMENT_REGISTERS(); - #undef ARGUMENT_REGISTER - - // Push m_datum - X86EmitPushReg(kEAX); - - // push edx ;leave room for m_next (edx is an arbitrary choice) - X86EmitPushReg(kEDX); - - // push Frame vptr - X86EmitPushImmPtr((LPVOID) pFrameVptr); - - // mov esi,esp - X86EmitMovRegSP(kESI); - - X86EmitPushImmPtr((LPVOID)GetProcessGSCookie()); - - // ebx <-- GetThread() - X86EmitCurrentThreadFetch(kEBX, 0); - -#if _DEBUG - - // call ObjectRefFlush - X86EmitPushReg(kEBX); // arg on stack - - // Make the call - X86EmitCall(NewExternalCodeLabel((LPVOID) Thread::ObjectRefFlush), sizeof(void*)); - -#endif // _DEBUG - - // mov edi,[ebx + Thread.GetFrame()] ;; get previous frame - X86EmitIndexRegLoad(kEDI, kEBX, Thread::GetOffsetOfCurrentFrame()); - - // mov [esi + Frame.m_next], edi - X86EmitIndexRegStore(kESI, Frame::GetOffsetOfNextLink(), kEDI); - - // mov [ebx + Thread.GetFrame()], esi - X86EmitIndexRegStore(kEBX, Thread::GetOffsetOfCurrentFrame(), kESI); - -#if _DEBUG - - if (Frame::ShouldLogTransitions()) - { - // call LogTransition - X86EmitPushReg(kESI); // arg on stack - - X86EmitCall(NewExternalCodeLabel((LPVOID) Frame::LogTransition), sizeof(void*)); - } - -#endif // _DEBUG - - - // For x86, the patch label can be specified only after the GSCookie is pushed - // Otherwise the debugger will see a Frame without a valid GSCookie -} - -/*============================================================================== - EmitMethodStubEpilog generates the part of the stub that will pop off the - Frame - - restoreArgRegs - indicates whether the argument registers need to be - restored from m_argumentRegisters - - At this point of the stub: - pFrame is in ESI/RSI. - the previous pFrame is in EDI/RDI - The current Thread* is in EBX/RBX. - For x86, ESP points to the FramedMethodFrame::NegInfo -*/ - -VOID StubLinkerCPU::EmitMethodStubEpilog(WORD numArgBytes, int transitionBlockOffset) -{ - STANDARD_VM_CONTRACT; - - // mov [ebx + Thread.GetFrame()], edi ;; restore previous frame - X86EmitIndexRegStore(kEBX, Thread::GetOffsetOfCurrentFrame(), kEDI); - - // deallocate Frame - X86EmitAddEsp(sizeof(GSCookie) + transitionBlockOffset + TransitionBlock::GetOffsetOfCalleeSavedRegisters()); - - // pop edi ; restore callee-saved registers - // pop esi - // pop ebx - // pop ebp - X86EmitPopReg(kEDI); - X86EmitPopReg(kESI); - X86EmitPopReg(kEBX); - X86EmitPopReg(kEBP); - -#if defined(UNIX_X86_ABI) - // Caller deallocates argument space. (Bypasses ASSERT in - // X86EmitReturn.) - numArgBytes = 0; -#endif - - X86EmitReturn(numArgBytes); -} - - -// On entry, ESI should be pointing to the Frame - VOID StubLinkerCPU::EmitCheckGSCookie(X86Reg frameReg, int gsCookieOffset) { STANDARD_VM_CONTRACT; @@ -3718,41 +3586,6 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) #if !defined(FEATURE_STUBS_AS_IL) -#if defined(TARGET_X86) && !defined(FEATURE_MULTICASTSTUB_AS_IL) -//=========================================================================== -// Computes hash code for MulticastDelegate.Invoke() -UINT_PTR StubLinkerCPU::HashMulticastInvoke(MetaSig* pSig) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END; - - ArgIterator argit(pSig); - - UINT numStackBytes = argit.SizeOfArgStack(); - - if (numStackBytes > 0x7FFF) - COMPlusThrow(kNotSupportedException, W("NotSupported_TooManyArgs")); - - // check if the function is returning a float, in which case the stub has to take - // care of popping the floating point stack except for the last invocation - - _ASSERTE(!(numStackBytes & 3)); - - UINT hash = numStackBytes; - - if (CorTypeInfo::IsFloat(pSig->GetReturnType())) - { - hash |= 2; - } - - return hash; -} -#endif // defined(TARGET_X86) && !defined(FEATURE_MULTICASTSTUB_AS_IL) - #ifdef TARGET_X86 //=========================================================================== // Emits code for MulticastDelegate.Invoke() @@ -3790,126 +3623,6 @@ VOID StubLinkerCPU::EmitDelegateInvoke() } #endif // TARGET_X86 -#if defined(TARGET_X86) && !defined(FEATURE_MULTICASTSTUB_AS_IL) -VOID StubLinkerCPU::EmitMulticastInvoke(UINT_PTR hash) -{ - STANDARD_VM_CONTRACT; - - int thisRegOffset = MulticastFrame::GetOffsetOfTransitionBlock() + - TransitionBlock::GetOffsetOfArgumentRegisters() + offsetof(ArgumentRegisters, THIS_REG); - - // push the methoddesc on the stack - // mov eax, [ecx + offsetof(_methodAuxPtr)] - X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, THIS_kREG, DelegateObject::GetOffsetOfMethodPtrAux()); - - // Push a MulticastFrame on the stack. - EmitMethodStubProlog(MulticastFrame::GetMethodFrameVPtr(), MulticastFrame::GetOffsetOfTransitionBlock()); - - // Frame is ready to be inspected by debugger for patch location - EmitPatchLabel(); - - // TODO: on AMD64, pick different regs for locals so don't need the pushes - - // push edi ;; Save EDI (want to use it as loop index) - X86EmitPushReg(kEDI); - - // xor edi,edi ;; Loop counter: EDI=0,1,2... - X86EmitZeroOutReg(kEDI); - - CodeLabel *pLoopLabel = NewCodeLabel(); - CodeLabel *pEndLoopLabel = NewCodeLabel(); - - EmitLabel(pLoopLabel); - - // Entry: - // EDI == iteration counter - - // mov ecx, [esi + this] ;; get delegate - X86EmitIndexRegLoad(THIS_kREG, kESI, thisRegOffset); - - // cmp edi,[ecx]._invocationCount - X86EmitOp(0x3b, kEDI, THIS_kREG, DelegateObject::GetOffsetOfInvocationCount()); - - // je ENDLOOP - X86EmitCondJump(pEndLoopLabel, X86CondCode::kJZ); - - UINT16 numStackBytes = static_cast(hash & ~3); - - // ..repush & reenregister args.. - INT32 ofs = numStackBytes + MulticastFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgs(); - while (ofs != MulticastFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgs()) - { - ofs -= sizeof(void*); - X86EmitIndexPush(kESI, ofs); - } - - #define ARGUMENT_REGISTER(regname) if (k##regname != THIS_kREG) { X86EmitIndexRegLoad(k##regname, kESI, \ - offsetof(ArgumentRegisters, regname) + MulticastFrame::GetOffsetOfTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters()); } - - ENUM_ARGUMENT_REGISTERS_BACKWARD(); - - #undef ARGUMENT_REGISTER - - // mov SCRATCHREG, [ecx+Delegate._invocationList] ;;fetch invocation list - X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, THIS_kREG, DelegateObject::GetOffsetOfInvocationList()); - - // mov SCRATCHREG, [SCRATCHREG+m_Array+edi*4] ;; index into invocation list - X86EmitOp(0x8b, kEAX, SCRATCH_REGISTER_X86REG, PtrArray::GetDataOffset(), kEDI, sizeof(void*)); - - // mov THISREG, [SCRATCHREG+Delegate.object] ;;replace "this" pointer - X86EmitIndexRegLoad(THIS_kREG, SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfTarget()); - - // call [SCRATCHREG+Delegate.target] ;; call current subscriber - X86EmitOffsetModRM(0xff, (X86Reg)2, SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfMethodPtr()); - INDEBUG(Emit8(0x90)); // Emit a nop after the call in debug so that - // we know that this is a call that can directly call - // managed code - - // inc edi - Emit8(0x47); - - if (hash & 2) // CorTypeInfo::IsFloat(pSig->GetReturnType()) - { - // if the return value is a float/double check if we just did the last call - if not, - // emit the pop of the float stack - - // mov SCRATCHREG, [esi + this] ;; get delegate - X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, kESI, thisRegOffset); - - // cmp edi,[SCRATCHREG]._invocationCount - X86EmitOffsetModRM(0x3b, kEDI, SCRATCH_REGISTER_X86REG, DelegateObject::GetOffsetOfInvocationCount()); - - CodeLabel *pNoFloatStackPopLabel = NewCodeLabel(); - - // je NOFLOATSTACKPOP - X86EmitCondJump(pNoFloatStackPopLabel, X86CondCode::kJZ); - - // fstp 0 - Emit16(0xd8dd); - - // NoFloatStackPopLabel: - EmitLabel(pNoFloatStackPopLabel); - } - - // The debugger may need to stop here, so grab the offset of this code. - EmitPatchLabel(); - - // jmp LOOP - X86EmitNearJump(pLoopLabel); - - //ENDLOOP: - EmitLabel(pEndLoopLabel); - - // pop edi ;; Restore edi - X86EmitPopReg(kEDI); - - EmitCheckGSCookie(kESI, MulticastFrame::GetOffsetOfGSCookie()); - - // Epilog - EmitMethodStubEpilog(numStackBytes, MulticastFrame::GetOffsetOfTransitionBlock()); -} -#endif // defined(TARGET_X86) && !defined(FEATURE_MULTICASTSTUB_AS_IL) - #endif // !FEATURE_STUBS_AS_IL #if !defined(FEATURE_STUBS_AS_IL) diff --git a/src/coreclr/vm/i386/stublinkerx86.h b/src/coreclr/vm/i386/stublinkerx86.h index 5274455ab3661..031ca2f9b0aa3 100644 --- a/src/coreclr/vm/i386/stublinkerx86.h +++ b/src/coreclr/vm/i386/stublinkerx86.h @@ -333,9 +333,6 @@ class StubLinkerCPU : public StubLinker #endif // FEATURE_COMINTEROP && TARGET_X86 #ifndef FEATURE_STUBS_AS_IL - VOID EmitMethodStubProlog(TADDR pFrameVptr, int transitionBlockOffset); - VOID EmitMethodStubEpilog(WORD numArgBytes, int transitionBlockOffset); - VOID EmitCheckGSCookie(X86Reg frameReg, int gsCookieOffset); #endif // !FEATURE_STUBS_AS_IL @@ -378,9 +375,6 @@ class StubLinkerCPU : public StubLinker #endif // FEATURE_COMINTEROP && TARGET_X86 #ifndef FEATURE_STUBS_AS_IL - //=========================================================================== - // Computes hash code for MulticastDelegate.Invoke() - static UINT_PTR HashMulticastInvoke(MetaSig* pSig); #ifdef TARGET_X86 //=========================================================================== @@ -388,11 +382,6 @@ class StubLinkerCPU : public StubLinker VOID EmitDelegateInvoke(); #endif // TARGET_X86 -#if defined(TARGET_X86) && !defined(FEATURE_MULTICASTSTUB_AS_IL) - //=========================================================================== - // Emits code for MulticastDelegate.Invoke() - sig specific - VOID EmitMulticastInvoke(UINT_PTR hash); -#endif // defined(TARGET_X86) && !defined(FEATURE_MULTICASTSTUB_AS_IL) #endif // !FEATURE_STUBS_AS_IL //=========================================================================== diff --git a/src/coreclr/vm/stublink.cpp b/src/coreclr/vm/stublink.cpp index d7facfbb6b833..be99fec457770 100644 --- a/src/coreclr/vm/stublink.cpp +++ b/src/coreclr/vm/stublink.cpp @@ -2295,236 +2295,5 @@ void Stub::SetupStub(int numCodeBytes, DWORD flags #endif } -//------------------------------------------------------------------- -// Constructor -//------------------------------------------------------------------- -ArgBasedStubCache::ArgBasedStubCache(UINT fixedSlots) - : m_numFixedSlots(fixedSlots), - m_crst(CrstArgBasedStubCache) -{ - WRAPPER_NO_CONTRACT; - - m_aStub = new Stub * [m_numFixedSlots]; - _ASSERTE(m_aStub != NULL); - - for (uint32_t i = 0; i < m_numFixedSlots; i++) { - m_aStub[i] = NULL; - } - m_pSlotEntries = NULL; -} - - -//------------------------------------------------------------------- -// Destructor -//------------------------------------------------------------------- -ArgBasedStubCache::~ArgBasedStubCache() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - for (uint32_t i = 0; i < m_numFixedSlots; i++) { - Stub *pStub = m_aStub[i]; - if (pStub) { - pStub->DecRef(); - } - } - // a size of 0 is a signal to Nirvana to flush the entire cache - // not sure if this is needed, but should have no CLR perf impact since size is 0. - FlushInstructionCache(GetCurrentProcess(),0,0); - - SlotEntry **ppSlotEntry = &m_pSlotEntries; - SlotEntry *pCur; - while (NULL != (pCur = *ppSlotEntry)) { - Stub *pStub = pCur->m_pStub; - pStub->DecRef(); - *ppSlotEntry = pCur->m_pNext; - delete pCur; - } - delete [] m_aStub; -} - - - -//------------------------------------------------------------------- -// Queries/retrieves a previously cached stub. -// -// If there is no stub corresponding to the given index, -// this function returns NULL. -// -// Otherwise, this function returns the stub after -// incrementing its refcount. -//------------------------------------------------------------------- -Stub *ArgBasedStubCache::GetStub(UINT_PTR key) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - Stub *pStub; - - CrstHolder ch(&m_crst); - - if (key < m_numFixedSlots) { - pStub = m_aStub[key]; - } else { - pStub = NULL; - for (SlotEntry *pSlotEntry = m_pSlotEntries; - pSlotEntry != NULL; - pSlotEntry = pSlotEntry->m_pNext) { - - if (pSlotEntry->m_key == key) { - pStub = pSlotEntry->m_pStub; - break; - } - } - } - if (pStub) { - ExecutableWriterHolder stubWriterHolder(pStub, sizeof(Stub)); - stubWriterHolder.GetRW()->IncRef(); - } - return pStub; -} - - -//------------------------------------------------------------------- -// Tries to associate a stub with a given index. This association -// may fail because some other thread may have beaten you to it -// just before you make the call. -// -// If the association succeeds, "pStub" is installed, and it is -// returned back to the caller. The stub's refcount is incremented -// twice (one to reflect the cache's ownership, and one to reflect -// the caller's ownership.) -// -// If the association fails because another stub is already installed, -// then the incumbent stub is returned to the caller and its refcount -// is incremented once (to reflect the caller's ownership.) -// -// If the association fails due to lack of memory, NULL is returned -// and no one's refcount changes. -// -// This routine is intended to be called like this: -// -// Stub *pCandidate = MakeStub(); // after this, pCandidate's rc is 1 -// Stub *pWinner = cache->SetStub(idx, pCandidate); -// pCandidate->DecRef(); -// pCandidate = 0xcccccccc; // must not use pCandidate again. -// if (!pWinner) { -// OutOfMemoryError; -// } -// // If the association succeeded, pWinner's refcount is 2 and so -// // is pCandidate's (because it *is* pWinner);. -// // If the association failed, pWinner's refcount is still 2 -// // and pCandidate got destroyed by the last DecRef(). -// // Either way, pWinner is now the official index holder. It -// // has a refcount of 2 (one for the cache's ownership, and -// // one belonging to this code.) -//------------------------------------------------------------------- -Stub* ArgBasedStubCache::AttemptToSetStub(UINT_PTR key, Stub *pStub) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - CrstHolder ch(&m_crst); - - bool incRefForCache = false; - - if (key < m_numFixedSlots) { - if (m_aStub[key]) { - pStub = m_aStub[key]; - } else { - m_aStub[key] = pStub; - incRefForCache = true; - } - } else { - SlotEntry *pSlotEntry; - for (pSlotEntry = m_pSlotEntries; - pSlotEntry != NULL; - pSlotEntry = pSlotEntry->m_pNext) { - - if (pSlotEntry->m_key == key) { - pStub = pSlotEntry->m_pStub; - break; - } - } - if (!pSlotEntry) { - pSlotEntry = new SlotEntry; - pSlotEntry->m_pStub = pStub; - incRefForCache = true; - pSlotEntry->m_key = key; - pSlotEntry->m_pNext = m_pSlotEntries; - m_pSlotEntries = pSlotEntry; - } - } - if (pStub) { - ExecutableWriterHolder stubWriterHolder(pStub, sizeof(Stub)); - if (incRefForCache) - { - stubWriterHolder.GetRW()->IncRef(); // IncRef on cache's behalf - } - stubWriterHolder.GetRW()->IncRef(); // IncRef because we're returning it to caller - } - return pStub; -} - - - -#ifdef _DEBUG -// Diagnostic dump -VOID ArgBasedStubCache::Dump() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - printf("--------------------------------------------------------------\n"); - printf("ArgBasedStubCache dump (%u fixed entries):\n", m_numFixedSlots); - for (UINT32 i = 0; i < m_numFixedSlots; i++) { - - printf(" Fixed slot %u: ", (ULONG)i); - Stub *pStub = m_aStub[i]; - if (!pStub) { - printf("empty\n"); - } else { - printf("%zxh - refcount is %u\n", - (size_t)(pStub->GetEntryPoint()), - (ULONG)( *( ( ((ULONG*)(pStub->GetEntryPoint())) - 1)))); - } - } - - for (SlotEntry *pSlotEntry = m_pSlotEntries; - pSlotEntry != NULL; - pSlotEntry = pSlotEntry->m_pNext) { - - printf(" Dyna. slot %u: ", (ULONG)(pSlotEntry->m_key)); - Stub *pStub = pSlotEntry->m_pStub; - printf("%zxh - refcount is %u\n", - (size_t)(pStub->GetEntryPoint()), - (ULONG)( *( ( ((ULONG*)(pStub->GetEntryPoint())) - 1)))); - - } - - - printf("--------------------------------------------------------------\n"); -} -#endif - #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/stublink.h b/src/coreclr/vm/stublink.h index a665e2b566620..3d01f2b6561d6 100644 --- a/src/coreclr/vm/stublink.h +++ b/src/coreclr/vm/stublink.h @@ -1112,72 +1112,6 @@ class InstructionFormat - - -//------------------------------------------------------------------------- -// This stub cache associates stubs with an integer key. For some clients, -// this might represent the size of the argument stack in some cpu-specific -// units (for the x86, the size is expressed in DWORDS.) For other clients, -// this might take into account the style of stub (e.g. whether it returns -// an object reference or not). -//------------------------------------------------------------------------- -class ArgBasedStubCache -{ - public: - ArgBasedStubCache(UINT fixedSize = NUMFIXEDSLOTS); - ~ArgBasedStubCache(); - - //----------------------------------------------------------------- - // Retrieves the stub associated with the given key. - //----------------------------------------------------------------- - Stub *GetStub(UINT_PTR key); - - //----------------------------------------------------------------- - // Tries to associate the stub with the given key. - // It may fail because another thread might swoop in and - // do the association before you do. Thus, you must use the - // return value stub rather than the pStub. - //----------------------------------------------------------------- - Stub* AttemptToSetStub(UINT_PTR key, Stub *pStub); - - - // Suggestions for number of slots - enum { - #ifdef _DEBUG - NUMFIXEDSLOTS = 3, - #else - NUMFIXEDSLOTS = 16, - #endif - }; - -#ifdef _DEBUG - VOID Dump(); //Diagnostic dump -#endif - - private: - - // How many low-numbered keys have direct access? - UINT m_numFixedSlots; - - // For 'm_numFixedSlots' low-numbered keys, we store them in an array. - Stub **m_aStub; - - - struct SlotEntry - { - Stub *m_pStub; - UINT_PTR m_key; - SlotEntry *m_pNext; - }; - - // High-numbered keys are stored in a sparse linked list. - SlotEntry *m_pSlotEntries; - - - Crst m_crst; -}; - - #define CPUSTUBLINKER StubLinkerCPU class NDirectStubLinker; From c2bbd66efcd2b83e1f5dcc0a501f5479da22bce6 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 17 Jun 2024 00:19:40 +0800 Subject: [PATCH 04/13] Delete feature flag --- src/coreclr/clr.featuredefines.props | 2 -- src/coreclr/clrdefinitions.cmake | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/coreclr/clr.featuredefines.props b/src/coreclr/clr.featuredefines.props index 97053a57bb5ed..1f513b1354d7a 100644 --- a/src/coreclr/clr.featuredefines.props +++ b/src/coreclr/clr.featuredefines.props @@ -1,6 +1,5 @@ - true true true true @@ -29,7 +28,6 @@ - $(DefineConstants);FEATURE_MULTICASTSTUB_AS_IL $(DefineConstants);FEATURE_COMWRAPPERS $(DefineConstants);FEATURE_COMINTEROP $(DefineConstants);FEATURE_COMINTEROP_APARTMENT_SUPPORT diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake index 3e15c386d19c3..ec09ee61ae1f3 100644 --- a/src/coreclr/clrdefinitions.cmake +++ b/src/coreclr/clrdefinitions.cmake @@ -67,8 +67,6 @@ if(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64) add_compile_definitions(OUT_OF_PROCESS_SETTHREADCONTEXT) endif(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64) -add_definitions(-DFEATURE_MULTICASTSTUB_AS_IL) - if(NOT CLR_CMAKE_TARGET_ARCH_I386) add_definitions(-DFEATURE_PORTABLE_SHUFFLE_THUNKS) endif() From 49bd3b2000c7c754de04a7643f67e7ab9eccaf4c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 29 Jun 2024 17:17:32 +0800 Subject: [PATCH 05/13] Skip MulticastDebuggerTraceHelper when no debugger --- src/coreclr/vm/comdelegate.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 3940444e9be4c..eefd795599ccc 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2182,9 +2182,22 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitLabel(nextDelegate); #ifdef DEBUGGING_SUPPORTED + ILCodeLabel *debuggerCheck = pCode->NewCodeLabel(); + + // Call MulticastDebuggerTraceHelper only if any debugger is attatched + pCode->EmitLDC((DWORD_PTR)&g_CORDebuggerControlFlags); + pCode->EmitCONV_I(); + pCode->EmitLDIND_I4(); + + // (g_CORDebuggerControlFlags & DBCF_ATTACHED) != 0 + pCode->EmitLDC(DBCF_ATTACHED); + pCode->EmitAND(); + pCode->EmitBRFALSE(debuggerCheck); + pCode->EmitLoadThis(); pCode->EmitLDLOC(dwLoopCounterNum); pCode->EmitCALL(METHOD__STUBHELPERS__MULTICAST_DEBUGGER_TRACE_HELPER, 2, 0); + pCode->EmitLabel(debuggerCheck); #endif // DEBUGGING_SUPPORTED // compare LoopCounter with InvocationCount. If equal then branch to Label_endOfMethod From e6ca8d561ab16e46c6ff4f07dd933a48f11df710 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 29 Jun 2024 17:39:41 +0800 Subject: [PATCH 06/13] Reduce register pressure --- src/coreclr/vm/comdelegate.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index eefd795599ccc..f212dbf964cc3 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2159,7 +2159,11 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch); +#ifndef TARGET_X86 + // x86 has much less available registers comparing to other architectures. + // To reduce register pressure and stack spilling, avoid saving invocationCount in local variable. DWORD dwInvocationCountNum = pCode->NewLocal(ELEMENT_TYPE_I4); +#endif // TARGET_X86 DWORD dwLoopCounterNum = pCode->NewLocal(ELEMENT_TYPE_I4); DWORD dwReturnValNum = -1; @@ -2169,10 +2173,12 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) ILCodeLabel *nextDelegate = pCode->NewCodeLabel(); ILCodeLabel *endOfMethod = pCode->NewCodeLabel(); +#ifndef TARGET_X86 // Get count of delegates pCode->EmitLoadThis(); pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT))); pCode->EmitSTLOC(dwInvocationCountNum); +#endif // TARGET_X86 // initialize counter pCode->EmitLDC(0); @@ -2202,7 +2208,12 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) // compare LoopCounter with InvocationCount. If equal then branch to Label_endOfMethod pCode->EmitLDLOC(dwLoopCounterNum); +#ifdef TARGET_X86 + pCode->EmitLoadThis(); + pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT))); +#else pCode->EmitLDLOC(dwInvocationCountNum); +#endif pCode->EmitBEQ(endOfMethod); // Load next delegate from array using LoopCounter as index From c50c39cba590ec78a4b61378b588a34f1a909149 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 29 Jun 2024 17:41:02 +0800 Subject: [PATCH 07/13] Tune branch prediction --- src/coreclr/vm/comdelegate.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index f212dbf964cc3..fbb456949ea7d 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2188,7 +2188,8 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitLabel(nextDelegate); #ifdef DEBUGGING_SUPPORTED - ILCodeLabel *debuggerCheck = pCode->NewCodeLabel(); + ILCodeLabel *invokeTraceHelper = pCode->NewCodeLabel(); + ILCodeLabel *debuggerCheckEnd = pCode->NewCodeLabel(); // Call MulticastDebuggerTraceHelper only if any debugger is attatched pCode->EmitLDC((DWORD_PTR)&g_CORDebuggerControlFlags); @@ -2198,13 +2199,17 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) // (g_CORDebuggerControlFlags & DBCF_ATTACHED) != 0 pCode->EmitLDC(DBCF_ATTACHED); pCode->EmitAND(); - pCode->EmitBRFALSE(debuggerCheck); + pCode->EmitBRTRUE(invokeTraceHelper); + pCode->EmitBR(debuggerCheckEnd); // Tune branch prediction to prefer non-debugging path + + pCode->EmitLabel(invokeTraceHelper); pCode->EmitLoadThis(); pCode->EmitLDLOC(dwLoopCounterNum); pCode->EmitCALL(METHOD__STUBHELPERS__MULTICAST_DEBUGGER_TRACE_HELPER, 2, 0); - pCode->EmitLabel(debuggerCheck); -#endif // DEBUGGING_SUPPORTED + + pCode->EmitLabel(debuggerCheckEnd); +#endif // compare LoopCounter with InvocationCount. If equal then branch to Label_endOfMethod pCode->EmitLDLOC(dwLoopCounterNum); From 59641658242aecda208dcbb96ce3d1224519d4a8 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 29 Jun 2024 20:44:34 +0800 Subject: [PATCH 08/13] ifdef format --- src/coreclr/vm/comdelegate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index fbb456949ea7d..7f970beec621d 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2209,16 +2209,16 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitCALL(METHOD__STUBHELPERS__MULTICAST_DEBUGGER_TRACE_HELPER, 2, 0); pCode->EmitLabel(debuggerCheckEnd); -#endif +#endif // DEBUGGING_SUPPORTED // compare LoopCounter with InvocationCount. If equal then branch to Label_endOfMethod pCode->EmitLDLOC(dwLoopCounterNum); #ifdef TARGET_X86 pCode->EmitLoadThis(); pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT))); -#else +#else // TARGET_X86 pCode->EmitLDLOC(dwInvocationCountNum); -#endif +#endif // TARGET_X86 pCode->EmitBEQ(endOfMethod); // Load next delegate from array using LoopCounter as index From 03e88112eba09ec8bcb98aec8d10c106fedac9ef Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 30 Jun 2024 14:29:00 +0800 Subject: [PATCH 09/13] Typo --- src/coreclr/vm/comdelegate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 7f970beec621d..3c4f176c0cbeb 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2191,7 +2191,7 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) ILCodeLabel *invokeTraceHelper = pCode->NewCodeLabel(); ILCodeLabel *debuggerCheckEnd = pCode->NewCodeLabel(); - // Call MulticastDebuggerTraceHelper only if any debugger is attatched + // Call MulticastDebuggerTraceHelper only if any debugger is attached pCode->EmitLDC((DWORD_PTR)&g_CORDebuggerControlFlags); pCode->EmitCONV_I(); pCode->EmitLDIND_I4(); From 0744c51baee655e42df675e09b18583eb45dcf33 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 30 Jun 2024 14:47:12 +0800 Subject: [PATCH 10/13] Simplify register saving --- src/coreclr/vm/comdelegate.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 3c4f176c0cbeb..9a08f1da25325 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2159,11 +2159,6 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch); -#ifndef TARGET_X86 - // x86 has much less available registers comparing to other architectures. - // To reduce register pressure and stack spilling, avoid saving invocationCount in local variable. - DWORD dwInvocationCountNum = pCode->NewLocal(ELEMENT_TYPE_I4); -#endif // TARGET_X86 DWORD dwLoopCounterNum = pCode->NewLocal(ELEMENT_TYPE_I4); DWORD dwReturnValNum = -1; @@ -2173,13 +2168,6 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) ILCodeLabel *nextDelegate = pCode->NewCodeLabel(); ILCodeLabel *endOfMethod = pCode->NewCodeLabel(); -#ifndef TARGET_X86 - // Get count of delegates - pCode->EmitLoadThis(); - pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT))); - pCode->EmitSTLOC(dwInvocationCountNum); -#endif // TARGET_X86 - // initialize counter pCode->EmitLDC(0); pCode->EmitSTLOC(dwLoopCounterNum); @@ -2213,12 +2201,8 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) // compare LoopCounter with InvocationCount. If equal then branch to Label_endOfMethod pCode->EmitLDLOC(dwLoopCounterNum); -#ifdef TARGET_X86 pCode->EmitLoadThis(); pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT))); -#else // TARGET_X86 - pCode->EmitLDLOC(dwInvocationCountNum); -#endif // TARGET_X86 pCode->EmitBEQ(endOfMethod); // Load next delegate from array using LoopCounter as index From a5ec68ad50b0aef5a9dfba7de1dcebe099931f61 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 30 Jun 2024 15:15:48 +0800 Subject: [PATCH 11/13] Normalize loop --- src/coreclr/vm/comdelegate.cpp | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 9a08f1da25325..3c1a0a8c198f8 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2166,12 +2166,15 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) dwReturnValNum = pCode->NewLocal(sig.GetRetTypeHandleNT()); ILCodeLabel *nextDelegate = pCode->NewCodeLabel(); - ILCodeLabel *endOfMethod = pCode->NewCodeLabel(); + ILCodeLabel *checkCount = pCode->NewCodeLabel(); // initialize counter pCode->EmitLDC(0); pCode->EmitSTLOC(dwLoopCounterNum); + // Make the shape of the loop similar to what C# compiler emits + pCode->EmitBR(checkCount); + //Label_nextDelegate: pCode->EmitLabel(nextDelegate); @@ -2199,12 +2202,6 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitLabel(debuggerCheckEnd); #endif // DEBUGGING_SUPPORTED - // compare LoopCounter with InvocationCount. If equal then branch to Label_endOfMethod - pCode->EmitLDLOC(dwLoopCounterNum); - pCode->EmitLoadThis(); - pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT))); - pCode->EmitBEQ(endOfMethod); - // Load next delegate from array using LoopCounter as index pCode->EmitLoadThis(); pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_LIST))); @@ -2212,9 +2209,8 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitLDELEM_REF(); // Load the arguments - UINT paramCount = 0; - while(paramCount < sig.NumFixedArgs()) - pCode->EmitLDARG(paramCount++); + for (UINT paramCount = 0; paramCount < sig.NumFixedArgs(); paramCount++) + pCode->EmitLDARG(paramCount); // call the delegate pCode->EmitCALL(pCode->GetToken(pMD), sig.NumFixedArgs(), fReturnVal); @@ -2229,11 +2225,14 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitADD(); pCode->EmitSTLOC(dwLoopCounterNum); - // branch to next delegate - pCode->EmitBR(nextDelegate); + //Label_checkCount + pCode->EmitLabel(checkCount); - //Label_endOfMethod - pCode->EmitLabel(endOfMethod); + // compare LoopCounter with InvocationCount. If less then branch to nextDelegate + pCode->EmitLDLOC(dwLoopCounterNum); + pCode->EmitLoadThis(); + pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT))); + pCode->EmitBLT(nextDelegate); // load the return value. return value from the last delegate call is returned if(fReturnVal) From b492c11263c6fef1542572da0581ce87cce30e4d Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 30 Jun 2024 16:49:15 +0800 Subject: [PATCH 12/13] Hot-cold splitting --- src/coreclr/vm/comdelegate.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 3c1a0a8c198f8..131744c5a2d40 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2191,13 +2191,6 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) pCode->EmitLDC(DBCF_ATTACHED); pCode->EmitAND(); pCode->EmitBRTRUE(invokeTraceHelper); - pCode->EmitBR(debuggerCheckEnd); // Tune branch prediction to prefer non-debugging path - - pCode->EmitLabel(invokeTraceHelper); - - pCode->EmitLoadThis(); - pCode->EmitLDLOC(dwLoopCounterNum); - pCode->EmitCALL(METHOD__STUBHELPERS__MULTICAST_DEBUGGER_TRACE_HELPER, 2, 0); pCode->EmitLabel(debuggerCheckEnd); #endif // DEBUGGING_SUPPORTED @@ -2241,6 +2234,17 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) // return pCode->EmitRET(); +#ifdef DEBUGGING_SUPPORTED + // Emit debugging support at the end of the method for better perf + pCode->EmitLabel(invokeTraceHelper); + + pCode->EmitLoadThis(); + pCode->EmitLDLOC(dwLoopCounterNum); + pCode->EmitCALL(METHOD__STUBHELPERS__MULTICAST_DEBUGGER_TRACE_HELPER, 2, 0); + + pCode->EmitBR(debuggerCheckEnd); +#endif // DEBUGGING_SUPPORTED + PCCOR_SIGNATURE pSig; DWORD cbSig; From 4c83681e6f55614a5d30f676a82d565bb9951edb Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 30 Jun 2024 23:47:35 +0800 Subject: [PATCH 13/13] Fix trace helper --- src/coreclr/vm/comdelegate.cpp | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp index 131744c5a2d40..b9ff707e60947 100644 --- a/src/coreclr/vm/comdelegate.cpp +++ b/src/coreclr/vm/comdelegate.cpp @@ -2178,23 +2178,6 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) //Label_nextDelegate: pCode->EmitLabel(nextDelegate); -#ifdef DEBUGGING_SUPPORTED - ILCodeLabel *invokeTraceHelper = pCode->NewCodeLabel(); - ILCodeLabel *debuggerCheckEnd = pCode->NewCodeLabel(); - - // Call MulticastDebuggerTraceHelper only if any debugger is attached - pCode->EmitLDC((DWORD_PTR)&g_CORDebuggerControlFlags); - pCode->EmitCONV_I(); - pCode->EmitLDIND_I4(); - - // (g_CORDebuggerControlFlags & DBCF_ATTACHED) != 0 - pCode->EmitLDC(DBCF_ATTACHED); - pCode->EmitAND(); - pCode->EmitBRTRUE(invokeTraceHelper); - - pCode->EmitLabel(debuggerCheckEnd); -#endif // DEBUGGING_SUPPORTED - // Load next delegate from array using LoopCounter as index pCode->EmitLoadThis(); pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_LIST))); @@ -2220,6 +2203,23 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn) //Label_checkCount pCode->EmitLabel(checkCount); + +#ifdef DEBUGGING_SUPPORTED + ILCodeLabel *invokeTraceHelper = pCode->NewCodeLabel(); + ILCodeLabel *debuggerCheckEnd = pCode->NewCodeLabel(); + + // Call MulticastDebuggerTraceHelper only if any debugger is attached + pCode->EmitLDC((DWORD_PTR)&g_CORDebuggerControlFlags); + pCode->EmitCONV_I(); + pCode->EmitLDIND_I4(); + + // (g_CORDebuggerControlFlags & DBCF_ATTACHED) != 0 + pCode->EmitLDC(DBCF_ATTACHED); + pCode->EmitAND(); + pCode->EmitBRTRUE(invokeTraceHelper); + + pCode->EmitLabel(debuggerCheckEnd); +#endif // DEBUGGING_SUPPORTED // compare LoopCounter with InvocationCount. If less then branch to nextDelegate pCode->EmitLDLOC(dwLoopCounterNum);