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/clr.featuredefines.props b/src/coreclr/clr.featuredefines.props
index 82dded497b6f9..1f513b1354d7a 100644
--- a/src/coreclr/clr.featuredefines.props
+++ b/src/coreclr/clr.featuredefines.props
@@ -10,12 +10,10 @@
true
- true
true
- true
true
true
true
@@ -30,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 e376c63f75847..ec09ee61ae1f3 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -67,15 +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)
-# 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)
-
if(NOT CLR_CMAKE_TARGET_ARCH_I386)
add_definitions(-DFEATURE_PORTABLE_SHUFFLE_THUNKS)
endif()
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..e69c50c4d0b8c 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)
@@ -1759,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..b9ff707e60947 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;
@@ -2166,7 +2159,6 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch);
- DWORD dwInvocationCountNum = pCode->NewLocal(ELEMENT_TYPE_I4);
DWORD dwLoopCounterNum = pCode->NewLocal(ELEMENT_TYPE_I4);
DWORD dwReturnValNum = -1;
@@ -2174,31 +2166,18 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
dwReturnValNum = pCode->NewLocal(sig.GetRetTypeHandleNT());
ILCodeLabel *nextDelegate = pCode->NewCodeLabel();
- ILCodeLabel *endOfMethod = pCode->NewCodeLabel();
-
- // Get count of delegates
- pCode->EmitLoadThis();
- pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT)));
- pCode->EmitSTLOC(dwInvocationCountNum);
+ 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);
-#ifdef DEBUGGING_SUPPORTED
- pCode->EmitLoadThis();
- pCode->EmitLDLOC(dwLoopCounterNum);
- pCode->EmitCALL(METHOD__STUBHELPERS__MULTICAST_DEBUGGER_TRACE_HELPER, 2, 0);
-#endif // DEBUGGING_SUPPORTED
-
- // compare LoopCounter with InvocationCount. If equal then branch to Label_endOfMethod
- pCode->EmitLDLOC(dwLoopCounterNum);
- pCode->EmitLDLOC(dwInvocationCountNum);
- 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)));
@@ -2206,9 +2185,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);
@@ -2223,11 +2201,31 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
pCode->EmitADD();
pCode->EmitSTLOC(dwLoopCounterNum);
- // branch to next delegate
- pCode->EmitBR(nextDelegate);
+ //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();
- //Label_endOfMethod
- pCode->EmitLabel(endOfMethod);
+ // (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);
+ 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)
@@ -2236,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;
@@ -2260,66 +2269,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/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/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/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/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;
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())
{