Skip to content

Commit

Permalink
Enable FEATURE_MULTICASTSTUB_AS_IL for Windows x86 (#104192)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
huoyaoyuan authored Jul 1, 2024
1 parent fcdb6db commit 3dd3488
Show file tree
Hide file tree
Showing 23 changed files with 44 additions and 915 deletions.
2 changes: 0 additions & 2 deletions src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
3 changes: 0 additions & 3 deletions src/coreclr/clr.featuredefines.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@

<PropertyGroup Condition="'$(TargetsUnix)' == 'true'">
<FeatureXplatEventSource Condition="'$(TargetOS)' == 'linux'">true</FeatureXplatEventSource>
<FeatureMulticastStubAsIL>true</FeatureMulticastStubAsIL>
<FeatureComWrappers>true</FeatureComWrappers>
</PropertyGroup>

<PropertyGroup Condition="'$(TargetsWindows)' == 'true'">
<FeatureMulticastStubAsIL Condition="'$(Platform)' != 'x86'">true</FeatureMulticastStubAsIL>
<FeatureComWrappers>true</FeatureComWrappers>
<FeatureCominterop>true</FeatureCominterop>
<FeatureCominteropApartmentSupport>true</FeatureCominteropApartmentSupport>
Expand All @@ -30,7 +28,6 @@
</PropertyGroup>

<PropertyGroup>
<DefineConstants Condition="'$(FeatureMulticastStubAsIL)' == 'true'">$(DefineConstants);FEATURE_MULTICASTSTUB_AS_IL</DefineConstants>
<DefineConstants Condition="'$(FeatureComWrappers)' == 'true'">$(DefineConstants);FEATURE_COMWRAPPERS</DefineConstants>
<DefineConstants Condition="'$(FeatureCominterop)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP</DefineConstants>
<DefineConstants Condition="'$(FeatureCominteropApartmentSupport)' == 'true'">$(DefineConstants);FEATURE_COMINTEROP_APARTMENT_SUPPORT</DefineConstants>
Expand Down
9 changes: 0 additions & 9 deletions src/coreclr/clrdefinitions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
7 changes: 2 additions & 5 deletions src/coreclr/debug/ee/controller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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
Expand Down
24 changes: 0 additions & 24 deletions src/coreclr/debug/ee/frameinfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/inc/vptr_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
12 changes: 0 additions & 12 deletions src/coreclr/vm/appdomain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
133 changes: 41 additions & 92 deletions src/coreclr/vm/comdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,9 +728,6 @@ VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArray<S


ShuffleThunkCache *COMDelegate::m_pShuffleThunkCache = NULL;
#ifndef FEATURE_MULTICASTSTUB_AS_IL
MulticastStubCache *COMDelegate::m_pMulticastStubCache = NULL;
#endif

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

m_pShuffleThunkCache = new ShuffleThunkCache(SystemDomain::GetGlobalLoaderAllocator()->GetStubHeap());
#ifndef FEATURE_MULTICASTSTUB_AS_IL
m_pMulticastStubCache = new MulticastStubCache();
#endif
}

#ifdef FEATURE_COMINTEROP
Expand Down Expand Up @@ -2139,7 +2133,6 @@ FCIMPL1(MethodDesc*, COMDelegate::GetInvokeMethod, Object* refThisIn)
}
FCIMPLEND

#ifdef FEATURE_MULTICASTSTUB_AS_IL
FCIMPL1(PCODE, COMDelegate::GetMulticastInvoke, Object* refThisIn)
{
FCALL_CONTRACT;
Expand All @@ -2166,49 +2159,34 @@ 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;
if(fReturnVal)
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)));
pCode->EmitLDLOC(dwLoopCounterNum);
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);
Expand All @@ -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)
Expand All @@ -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;

Expand All @@ -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<Stub> 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
Expand Down
11 changes: 0 additions & 11 deletions src/coreclr/vm/comdelegate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/vm/corelib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
4 changes: 0 additions & 4 deletions src/coreclr/vm/dllimport.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 3dd3488

Please sign in to comment.