Skip to content

Commit 3dd3488

Browse files
authored
Enable FEATURE_MULTICASTSTUB_AS_IL for Windows x86 (#104192)
* Enable FEATURE_MULTICASTSTUB_AS_IL on win-x86 * Unconditionally enable at use sites * Remove dead code * Delete feature flag * Skip MulticastDebuggerTraceHelper when no debugger * Reduce register pressure * Tune branch prediction * Simplify register saving * Normalize loop * Hot-cold splitting
1 parent fcdb6db commit 3dd3488

23 files changed

+44
-915
lines changed

src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,10 +1616,8 @@ internal static unsafe void LayoutDestroyNativeInternal(object obj, byte* pNativ
16161616
[MethodImpl(MethodImplOptions.InternalCall)]
16171617
internal static extern IntPtr GetStubContext();
16181618

1619-
#if FEATURE_MULTICASTSTUB_AS_IL
16201619
[MethodImpl(MethodImplOptions.InternalCall)]
16211620
internal static extern void MulticastDebuggerTraceHelper(object o, int count);
1622-
#endif
16231621

16241622
[Intrinsic]
16251623
[MethodImpl(MethodImplOptions.InternalCall)]

src/coreclr/clr.featuredefines.props

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@
1010

1111
<PropertyGroup Condition="'$(TargetsUnix)' == 'true'">
1212
<FeatureXplatEventSource Condition="'$(TargetOS)' == 'linux'">true</FeatureXplatEventSource>
13-
<FeatureMulticastStubAsIL>true</FeatureMulticastStubAsIL>
1413
<FeatureComWrappers>true</FeatureComWrappers>
1514
</PropertyGroup>
1615

1716
<PropertyGroup Condition="'$(TargetsWindows)' == 'true'">
18-
<FeatureMulticastStubAsIL Condition="'$(Platform)' != 'x86'">true</FeatureMulticastStubAsIL>
1917
<FeatureComWrappers>true</FeatureComWrappers>
2018
<FeatureCominterop>true</FeatureCominterop>
2119
<FeatureCominteropApartmentSupport>true</FeatureCominteropApartmentSupport>
@@ -30,7 +28,6 @@
3028
</PropertyGroup>
3129

3230
<PropertyGroup>
33-
<DefineConstants Condition="'$(FeatureMulticastStubAsIL)' == 'true'">$(DefineConstants);FEATURE_MULTICASTSTUB_AS_IL</DefineConstants>
3431
<DefineConstants Condition="'$(FeatureComWrappers)' == 'true'">$(DefineConstants);FEATURE_COMWRAPPERS</DefineConstants>
3532
<DefineConstants Condition="'$(FeatureCominterop)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP</DefineConstants>
3633
<DefineConstants Condition="'$(FeatureCominteropApartmentSupport)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP_APARTMENT_SUPPORT</DefineConstants>

src/coreclr/clrdefinitions.cmake

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,6 @@ if(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64)
6767
add_compile_definitions(OUT_OF_PROCESS_SETTHREADCONTEXT)
6868
endif(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_TARGET_ARCH_AMD64)
6969

70-
# Features - please keep them alphabetically sorted
71-
if(CLR_CMAKE_TARGET_WIN32)
72-
if(NOT CLR_CMAKE_TARGET_ARCH_I386)
73-
add_definitions(-DFEATURE_MULTICASTSTUB_AS_IL)
74-
endif()
75-
else(CLR_CMAKE_TARGET_WIN32)
76-
add_definitions(-DFEATURE_MULTICASTSTUB_AS_IL)
77-
endif(CLR_CMAKE_TARGET_WIN32)
78-
7970
if(NOT CLR_CMAKE_TARGET_ARCH_I386)
8071
add_definitions(-DFEATURE_PORTABLE_SHUFFLE_THUNKS)
8172
endif()

src/coreclr/debug/ee/controller.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6259,7 +6259,6 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio
62596259
_ASSERTE(IsCloserToLeaf(dbgLastFP, info->m_activeFrame.fp));
62606260
#endif
62616261

6262-
#ifdef FEATURE_MULTICASTSTUB_AS_IL
62636262
if (info->m_activeFrame.md != nullptr && info->m_activeFrame.md->IsILStub() && info->m_activeFrame.md->AsDynamicMethodDesc()->IsMulticastStub())
62646263
{
62656264
LOG((LF_CORDB, LL_INFO10000,
@@ -6286,10 +6285,8 @@ void DebuggerStepper::TrapStepOut(ControllerStackInfo *info, bool fForceTraditio
62866285
true))
62876286
break;
62886287
}
6289-
else
6290-
#endif // FEATURE_MULTICASTSTUB_AS_IL
6291-
if (info->m_activeFrame.md != nullptr && info->m_activeFrame.md->IsILStub() &&
6292-
info->m_activeFrame.md->AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubTailCallCallTarget)
6288+
else if (info->m_activeFrame.md != nullptr && info->m_activeFrame.md->IsILStub() &&
6289+
info->m_activeFrame.md->AsDynamicMethodDesc()->GetILStubType() == DynamicMethodDesc::StubTailCallCallTarget)
62936290
{
62946291
// Normally the stack trace would not include IL stubs, but we
62956292
// include this specific IL stub so that we can check if a call into

src/coreclr/debug/ee/frameinfo.cpp

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,9 +1562,7 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data)
15621562
{
15631563
_ASSERTE(md->IsDynamicMethod());
15641564
DynamicMethodDesc* dMD = md->AsDynamicMethodDesc();
1565-
#ifdef FEATURE_MULTICASTSTUB_AS_IL
15661565
use |= dMD->IsMulticastStub();
1567-
#endif
15681566
use |= dMD->GetILStubType() == DynamicMethodDesc::StubTailCallCallTarget;
15691567

15701568
if (use)
@@ -1759,28 +1757,6 @@ StackWalkAction DebuggerWalkStackProc(CrawlFrame *pCF, void *data)
17591757

17601758
break;
17611759

1762-
// Put frames we want to ignore here:
1763-
case Frame::TYPE_MULTICAST:
1764-
LOG((LF_CORDB, LL_INFO100000, "DWSP: Frame type is TYPE_MULTICAST.\n"));
1765-
if (d->ShouldIgnoreNonmethodFrames())
1766-
{
1767-
// Multicast frames exist only to gc protect the arguments
1768-
// between invocations of a delegate. They don't have code that
1769-
// we can (currently) show the user (we could change this with
1770-
// work, but why bother? It's an internal stub, and even if the
1771-
// user could see it, they can't modify it).
1772-
LOG((LF_CORDB, LL_INFO100000, "DWSP: Skipping frame 0x%x b/c it's "
1773-
"a multicast frame!\n", frame));
1774-
use = false;
1775-
}
1776-
else
1777-
{
1778-
LOG((LF_CORDB, LL_INFO100000, "DWSP: NOT Skipping frame 0x%x even thought it's "
1779-
"a multicast frame!\n", frame));
1780-
INTERNAL_FRAME_ACTION(d, use);
1781-
}
1782-
break;
1783-
17841760
default:
17851761
_ASSERTE(!"Invalid frame type!");
17861762
break;

src/coreclr/inc/vptr_list.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ VPTR_CLASS(HelperMethodFrame_PROTECTOBJ)
6868
VPTR_CLASS(HijackFrame)
6969
#endif
7070
VPTR_CLASS(InlinedCallFrame)
71-
VPTR_CLASS(MulticastFrame)
7271
VPTR_CLASS(PInvokeCalliFrame)
7372
VPTR_CLASS(PrestubMethodFrame)
7473
VPTR_CLASS(ProtectByRefsFrame)

src/coreclr/vm/appdomain.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,18 +1582,6 @@ StackWalkAction SystemDomain::CallersMethodCallbackWithStackMark(CrawlFrame* pCf
15821582
if (SystemDomain::IsReflectionInvocationMethod(pFunc))
15831583
return SWA_CONTINUE;
15841584

1585-
if (frame && frame->GetFrameType() == Frame::TYPE_MULTICAST)
1586-
{
1587-
// This must be either a multicast delegate invocation.
1588-
1589-
_ASSERTE(pFunc->GetMethodTable()->IsDelegate());
1590-
1591-
DELEGATEREF del = (DELEGATEREF)((MulticastFrame*)frame)->GetThis(); // This can throw.
1592-
1593-
_ASSERTE(COMDelegate::IsTrueMulticastDelegate(del));
1594-
return SWA_CONTINUE;
1595-
}
1596-
15971585
// Return the first non-reflection/remoting frame if no stack mark was
15981586
// supplied.
15991587
if (!pCaller->stackMark)

src/coreclr/vm/comdelegate.cpp

Lines changed: 41 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -728,9 +728,6 @@ VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArray<S
728728

729729

730730
ShuffleThunkCache *COMDelegate::m_pShuffleThunkCache = NULL;
731-
#ifndef FEATURE_MULTICASTSTUB_AS_IL
732-
MulticastStubCache *COMDelegate::m_pMulticastStubCache = NULL;
733-
#endif
734731

735732
CrstStatic COMDelegate::s_DelegateToFPtrHashCrst;
736733
PtrHashMap* COMDelegate::s_pDelegateToFPtrHash = NULL;
@@ -755,9 +752,6 @@ void COMDelegate::Init()
755752
s_pDelegateToFPtrHash->Init(TRUE, &lock);
756753

757754
m_pShuffleThunkCache = new ShuffleThunkCache(SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap());
758-
#ifndef FEATURE_MULTICASTSTUB_AS_IL
759-
m_pMulticastStubCache = new MulticastStubCache();
760-
#endif
761755
}
762756

763757
#ifdef FEATURE_COMINTEROP
@@ -2139,7 +2133,6 @@ FCIMPL1(MethodDesc*, COMDelegate::GetInvokeMethod, Object* refThisIn)
21392133
}
21402134
FCIMPLEND
21412135

2142-
#ifdef FEATURE_MULTICASTSTUB_AS_IL
21432136
FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
21442137
{
21452138
FCALL_CONTRACT;
@@ -2166,49 +2159,34 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
21662159

21672160
ILCodeStream *pCode = sl.NewCodeStream(ILStubLinker::kDispatch);
21682161

2169-
DWORD dwInvocationCountNum = pCode->NewLocal(ELEMENT_TYPE_I4);
21702162
DWORD dwLoopCounterNum = pCode->NewLocal(ELEMENT_TYPE_I4);
21712163

21722164
DWORD dwReturnValNum = -1;
21732165
if(fReturnVal)
21742166
dwReturnValNum = pCode->NewLocal(sig.GetRetTypeHandleNT());
21752167

21762168
ILCodeLabel *nextDelegate = pCode->NewCodeLabel();
2177-
ILCodeLabel *endOfMethod = pCode->NewCodeLabel();
2178-
2179-
// Get count of delegates
2180-
pCode->EmitLoadThis();
2181-
pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT)));
2182-
pCode->EmitSTLOC(dwInvocationCountNum);
2169+
ILCodeLabel *checkCount = pCode->NewCodeLabel();
21832170

21842171
// initialize counter
21852172
pCode->EmitLDC(0);
21862173
pCode->EmitSTLOC(dwLoopCounterNum);
21872174

2175+
// Make the shape of the loop similar to what C# compiler emits
2176+
pCode->EmitBR(checkCount);
2177+
21882178
//Label_nextDelegate:
21892179
pCode->EmitLabel(nextDelegate);
21902180

2191-
#ifdef DEBUGGING_SUPPORTED
2192-
pCode->EmitLoadThis();
2193-
pCode->EmitLDLOC(dwLoopCounterNum);
2194-
pCode->EmitCALL(METHOD__STUBHELPERS__MULTICAST_DEBUGGER_TRACE_HELPER, 2, 0);
2195-
#endif // DEBUGGING_SUPPORTED
2196-
2197-
// compare LoopCounter with InvocationCount. If equal then branch to Label_endOfMethod
2198-
pCode->EmitLDLOC(dwLoopCounterNum);
2199-
pCode->EmitLDLOC(dwInvocationCountNum);
2200-
pCode->EmitBEQ(endOfMethod);
2201-
22022181
// Load next delegate from array using LoopCounter as index
22032182
pCode->EmitLoadThis();
22042183
pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_LIST)));
22052184
pCode->EmitLDLOC(dwLoopCounterNum);
22062185
pCode->EmitLDELEM_REF();
22072186

22082187
// Load the arguments
2209-
UINT paramCount = 0;
2210-
while(paramCount < sig.NumFixedArgs())
2211-
pCode->EmitLDARG(paramCount++);
2188+
for (UINT paramCount = 0; paramCount < sig.NumFixedArgs(); paramCount++)
2189+
pCode->EmitLDARG(paramCount);
22122190

22132191
// call the delegate
22142192
pCode->EmitCALL(pCode->GetToken(pMD), sig.NumFixedArgs(), fReturnVal);
@@ -2223,11 +2201,31 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
22232201
pCode->EmitADD();
22242202
pCode->EmitSTLOC(dwLoopCounterNum);
22252203

2226-
// branch to next delegate
2227-
pCode->EmitBR(nextDelegate);
2204+
//Label_checkCount
2205+
pCode->EmitLabel(checkCount);
2206+
2207+
#ifdef DEBUGGING_SUPPORTED
2208+
ILCodeLabel *invokeTraceHelper = pCode->NewCodeLabel();
2209+
ILCodeLabel *debuggerCheckEnd = pCode->NewCodeLabel();
2210+
2211+
// Call MulticastDebuggerTraceHelper only if any debugger is attached
2212+
pCode->EmitLDC((DWORD_PTR)&g_CORDebuggerControlFlags);
2213+
pCode->EmitCONV_I();
2214+
pCode->EmitLDIND_I4();
22282215

2229-
//Label_endOfMethod
2230-
pCode->EmitLabel(endOfMethod);
2216+
// (g_CORDebuggerControlFlags & DBCF_ATTACHED) != 0
2217+
pCode->EmitLDC(DBCF_ATTACHED);
2218+
pCode->EmitAND();
2219+
pCode->EmitBRTRUE(invokeTraceHelper);
2220+
2221+
pCode->EmitLabel(debuggerCheckEnd);
2222+
#endif // DEBUGGING_SUPPORTED
2223+
2224+
// compare LoopCounter with InvocationCount. If less then branch to nextDelegate
2225+
pCode->EmitLDLOC(dwLoopCounterNum);
2226+
pCode->EmitLoadThis();
2227+
pCode->EmitLDFLD(pCode->GetToken(CoreLibBinder::GetField(FIELD__MULTICAST_DELEGATE__INVOCATION_COUNT)));
2228+
pCode->EmitBLT(nextDelegate);
22312229

22322230
// load the return value. return value from the last delegate call is returned
22332231
if(fReturnVal)
@@ -2236,6 +2234,17 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
22362234
// return
22372235
pCode->EmitRET();
22382236

2237+
#ifdef DEBUGGING_SUPPORTED
2238+
// Emit debugging support at the end of the method for better perf
2239+
pCode->EmitLabel(invokeTraceHelper);
2240+
2241+
pCode->EmitLoadThis();
2242+
pCode->EmitLDLOC(dwLoopCounterNum);
2243+
pCode->EmitCALL(METHOD__STUBHELPERS__MULTICAST_DEBUGGER_TRACE_HELPER, 2, 0);
2244+
2245+
pCode->EmitBR(debuggerCheckEnd);
2246+
#endif // DEBUGGING_SUPPORTED
2247+
22392248
PCCOR_SIGNATURE pSig;
22402249
DWORD cbSig;
22412250

@@ -2260,66 +2269,6 @@ FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
22602269
}
22612270
FCIMPLEND
22622271

2263-
#else // FEATURE_MULTICASTSTUB_AS_IL
2264-
2265-
FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
2266-
{
2267-
FCALL_CONTRACT;
2268-
2269-
OBJECTREF refThis = ObjectToOBJECTREF(refThisIn);
2270-
MethodTable *pDelegateMT = refThis->GetMethodTable();
2271-
2272-
DelegateEEClass *delegateEEClass = ((DelegateEEClass*)(pDelegateMT->GetClass()));
2273-
Stub *pStub = delegateEEClass->m_pMultiCastInvokeStub;
2274-
if (pStub == NULL)
2275-
{
2276-
MethodDesc* pMD = delegateEEClass->GetInvokeMethod();
2277-
2278-
HELPER_METHOD_FRAME_BEGIN_RET_0();
2279-
2280-
GCX_PREEMP();
2281-
2282-
MetaSig sig(pMD);
2283-
2284-
UINT_PTR hash = CPUSTUBLINKER::HashMulticastInvoke(&sig);
2285-
2286-
pStub = m_pMulticastStubCache->GetStub(hash);
2287-
if (!pStub)
2288-
{
2289-
CPUSTUBLINKER sl;
2290-
2291-
LOG((LF_CORDB,LL_INFO10000, "COMD::GIMS making a multicast delegate\n"));
2292-
2293-
sl.EmitMulticastInvoke(hash);
2294-
2295-
// The cache is process-wide, based on signature. It never unloads
2296-
Stub *pCandidate = sl.Link(SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap(), NEWSTUB_FL_MULTICAST);
2297-
2298-
Stub *pWinner = m_pMulticastStubCache->AttemptToSetStub(hash,pCandidate);
2299-
ExecutableWriterHolder<Stub> candidateWriterHolder(pCandidate, sizeof(Stub));
2300-
candidateWriterHolder.GetRW()->DecRef();
2301-
2302-
if (!pWinner)
2303-
COMPlusThrowOM();
2304-
2305-
LOG((LF_CORDB,LL_INFO10000, "Putting a MC stub at 0x%p (code:0x%p)\n",
2306-
pWinner, (BYTE*)pWinner+sizeof(Stub)));
2307-
2308-
pStub = pWinner;
2309-
}
2310-
2311-
// we don't need to do an InterlockedCompareExchange here - the m_pMulticastStubCache->AttemptToSetStub
2312-
// will make sure all threads racing here will get the same stub, so they'll all store the same value
2313-
delegateEEClass->m_pMultiCastInvokeStub = pStub;
2314-
2315-
HELPER_METHOD_FRAME_END();
2316-
}
2317-
2318-
return pStub->GetEntryPoint();
2319-
}
2320-
FCIMPLEND
2321-
#endif // FEATURE_MULTICASTSTUB_AS_IL
2322-
23232272
PCODE COMDelegate::GetWrapperInvoke(MethodDesc* pMD)
23242273
{
23252274
CONTRACTL

src/coreclr/vm/comdelegate.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ class ShuffleThunkCache;
1717
#include "dllimportcallback.h"
1818
#include "stubcache.h"
1919

20-
#ifndef FEATURE_MULTICASTSTUB_AS_IL
21-
typedef ArgBasedStubCache MulticastStubCache;
22-
#endif
23-
2420
VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, struct ShuffleEntry * pShuffleEntryArray, size_t nEntries);
2521

2622
enum class ShuffleComputationType
@@ -34,15 +30,8 @@ BOOL GenerateShuffleArrayPortable(MethodDesc* pMethodSrc, MethodDesc *pMethodDst
3430
class COMDelegate
3531
{
3632
private:
37-
// friend VOID CPUSTUBLINKER::EmitMulticastInvoke(...);
3833
// friend VOID CPUSTUBLINKER::EmitShuffleThunk(...);
3934
friend class CPUSTUBLINKER;
40-
friend BOOL MulticastFrame::TraceFrame(Thread *thread, BOOL fromPatch,
41-
TraceDestination *trace, REGDISPLAY *regs);
42-
43-
#ifndef FEATURE_MULTICASTSTUB_AS_IL
44-
static MulticastStubCache* m_pMulticastStubCache;
45-
#endif
4635

4736
static CrstStatic s_DelegateToFPtrHashCrst; // Lock for the following hash.
4837
static PtrHashMap* s_pDelegateToFPtrHash; // Hash table containing the Delegate->FPtr pairs

src/coreclr/vm/corelib.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -938,9 +938,7 @@ DEFINE_METHOD(STUBHELPERS, PROFILER_BEGIN_TRANSITION_CALLBACK, Profiler
938938
DEFINE_METHOD(STUBHELPERS, PROFILER_END_TRANSITION_CALLBACK, ProfilerEndTransitionCallback, SM_IntPtr_IntPtr_RetVoid)
939939
#endif
940940

941-
#ifdef FEATURE_MULTICASTSTUB_AS_IL
942941
DEFINE_METHOD(STUBHELPERS, MULTICAST_DEBUGGER_TRACE_HELPER, MulticastDebuggerTraceHelper, SM_Obj_Int_RetVoid)
943-
#endif
944942

945943
DEFINE_CLASS(CLEANUP_WORK_LIST_ELEMENT, StubHelpers, CleanupWorkListElement)
946944

0 commit comments

Comments
 (0)