summaryrefslogtreecommitdiff
path: root/src/vm/jithelpers.cpp
diff options
context:
space:
mode:
authorKoundinya Veluri <kouvel@users.noreply.github.com>2017-09-26 13:14:53 -0700
committerGitHub <noreply@github.com>2017-09-26 13:14:53 -0700
commit8f0ac5d2041d0c577607e2f778f2fbca1f7d732e (patch)
tree23e191f0f10287d162ef53b4a2b77d9170ac7615 /src/vm/jithelpers.cpp
parent296aaf12b40ddd7478b6a14d6099f48b4b049438 (diff)
downloadcoreclr-8f0ac5d2041d0c577607e2f778f2fbca1f7d732e.tar.gz
coreclr-8f0ac5d2041d0c577607e2f778f2fbca1f7d732e.tar.bz2
coreclr-8f0ac5d2041d0c577607e2f778f2fbca1f7d732e.zip
Remove Monitor asm helpers (#14146)
- Removed asm helpers on Windows and used portable C++ helpers instead - Rearranged fast path code to improve them a bit and match the asm more closely Perf: - The asm helpers are a bit faster. The code generated for the portable helpers is almost the same now, the remaining differences are: - There were some layout issues where hot paths were in the wrong place and return paths were not cloned. Instrumenting some of the tests below with PGO on x64 resolved all of the layout issues. I couldn't get PGO instrumentation to work on x86 but I imagine it would be the same there. - Register usage - x64: All of the Enter functions are using one or two (TryEnter is using two) callee-saved registers for no apparent reason, forcing them to be saved and restored. r10 and r11 seem to be available but they're not being used. - x86: Similarly to x64, the compiled functions are pushing and popping 2-3 additional registers in the hottest fast paths. - I believe this is the main remaining gap and PGO is not helping with this - On Linux, perf is >= before for the most part - Perf tests used for below are updated in PR https://github.com/dotnet/coreclr/pull/13670
Diffstat (limited to 'src/vm/jithelpers.cpp')
-rw-r--r--src/vm/jithelpers.cpp319
1 files changed, 16 insertions, 303 deletions
diff --git a/src/vm/jithelpers.cpp b/src/vm/jithelpers.cpp
index 32be77823c..8cff03ae60 100644
--- a/src/vm/jithelpers.cpp
+++ b/src/vm/jithelpers.cpp
@@ -4472,19 +4472,18 @@ HCIMPL_MONHELPER(JIT_MonEnterWorker_Portable, Object* obj)
result = obj->EnterObjMonitorHelper(pCurThread);
if (result == AwareLock::EnterHelperResult_Entered)
{
- MONHELPER_STATE(*pbLockTaken = 1;)
+ MONHELPER_STATE(*pbLockTaken = 1);
return;
}
- else
if (result == AwareLock::EnterHelperResult_Contention)
{
- AwareLock::EnterHelperResult resultSpin = obj->EnterObjMonitorHelperSpin(pCurThread);
- if (resultSpin == AwareLock::EnterHelperResult_Entered)
+ result = obj->EnterObjMonitorHelperSpin(pCurThread);
+ if (result == AwareLock::EnterHelperResult_Entered)
{
- MONHELPER_STATE(*pbLockTaken = 1;)
+ MONHELPER_STATE(*pbLockTaken = 1);
return;
}
- if (resultSpin == AwareLock::EnterHelperResult_Contention)
+ if (result == AwareLock::EnterHelperResult_Contention)
{
FC_INNER_RETURN_VOID(JIT_MonContention_Helper(obj, MONHELPER_ARG, GetEEFuncEntryPointMacro(JIT_MonEnter)));
}
@@ -4519,15 +4518,14 @@ HCIMPL1(void, JIT_MonEnter_Portable, Object* obj)
{
return;
}
- else
if (result == AwareLock::EnterHelperResult_Contention)
{
- AwareLock::EnterHelperResult resultSpin = obj->EnterObjMonitorHelperSpin(pCurThread);
- if (resultSpin == AwareLock::EnterHelperResult_Entered)
+ result = obj->EnterObjMonitorHelperSpin(pCurThread);
+ if (result == AwareLock::EnterHelperResult_Entered)
{
return;
}
- if (resultSpin == AwareLock::EnterHelperResult_Contention)
+ if (result == AwareLock::EnterHelperResult_Contention)
{
FC_INNER_RETURN_VOID(JIT_MonContention_Helper(obj, NULL, GetEEFuncEntryPointMacro(JIT_MonEnter)));
}
@@ -4563,16 +4561,15 @@ HCIMPL2(void, JIT_MonReliableEnter_Portable, Object* obj, BYTE* pbLockTaken)
*pbLockTaken = 1;
return;
}
- else
if (result == AwareLock::EnterHelperResult_Contention)
{
- AwareLock::EnterHelperResult resultSpin = obj->EnterObjMonitorHelperSpin(pCurThread);
- if (resultSpin == AwareLock::EnterHelperResult_Entered)
+ result = obj->EnterObjMonitorHelperSpin(pCurThread);
+ if (result == AwareLock::EnterHelperResult_Entered)
{
*pbLockTaken = 1;
return;
}
- if (resultSpin == AwareLock::EnterHelperResult_Contention)
+ if (result == AwareLock::EnterHelperResult_Contention)
{
FC_INNER_RETURN_VOID(JIT_MonContention_Helper(obj, pbLockTaken, GetEEFuncEntryPointMacro(JIT_MonReliableEnter)));
}
@@ -4649,14 +4646,15 @@ HCIMPL3(void, JIT_MonTryEnter_Portable, Object* obj, INT32 timeOut, BYTE* pbLock
*pbLockTaken = 1;
return;
}
- else
if (result == AwareLock::EnterHelperResult_Contention)
{
if (timeOut == 0)
+ {
return;
+ }
- AwareLock::EnterHelperResult resultSpin = obj->EnterObjMonitorHelperSpin(pCurThread);
- if (resultSpin == AwareLock::EnterHelperResult_Entered)
+ result = obj->EnterObjMonitorHelperSpin(pCurThread);
+ if (result == AwareLock::EnterHelperResult_Entered)
{
*pbLockTaken = 1;
return;
@@ -4741,7 +4739,6 @@ FCIMPL1(void, JIT_MonExit_Portable, Object* obj)
{
return;
}
- else
if (action == AwareLock::LeaveHelperAction_Signal)
{
FC_INNER_RETURN_VOID(JIT_MonExit_Signal(obj));
@@ -4773,7 +4770,6 @@ HCIMPL_MONHELPER(JIT_MonExitWorker_Portable, Object* obj)
MONHELPER_STATE(*pbLockTaken = 0;)
return;
}
- else
if (action == AwareLock::LeaveHelperAction_Signal)
{
MONHELPER_STATE(*pbLockTaken = 0;)
@@ -4821,7 +4817,7 @@ HCIMPL_MONHELPER(JIT_MonEnterStatic_Portable, AwareLock *lock)
goto FramedLockHelper;
}
- if (lock->EnterHelper(pCurThread) == AwareLock::EnterHelperResult_Entered)
+ if (lock->EnterHelper(pCurThread, true /* checkRecursiveCase */))
{
#if defined(_DEBUG) && defined(TRACK_SYNC)
// The best place to grab this is from the ECall frame
@@ -4909,289 +4905,6 @@ HCIMPL_MONHELPER(JIT_MonExitStatic_Portable, AwareLock *lock)
HCIMPLEND
#include <optdefault.h>
-/*********************************************************************/
-// JITutil_Mon* are helpers than handle slow paths for JIT_Mon* methods
-// implemented in assembly. They are not doing any spinning compared
-// to the full fledged portable implementations above.
-/*********************************************************************/
-
-/*********************************************************************/
-HCIMPL_MONHELPER(JITutil_MonEnterWorker, Object* obj)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- OBJECTREF objRef = ObjectToOBJECTREF(obj);
-
- // The following makes sure that Monitor.Enter shows up on thread abort
- // stack walks (otherwise Monitor.Enter called within a CER can block a
- // thread abort indefinitely). Setting the __me internal variable (normally
- // only set for fcalls) will cause the helper frame below to be able to
- // backtranslate into the method desc for the Monitor.Enter fcall.
- //
- // Note that we need explicitly initialize Monitor.Enter fcall in
- // code:SystemDomain::LoadBaseSystemClasses to make this work in the case
- // where the first call ever to Monitor.Enter is done as JIT helper
- // for synchronized method.
- __me = GetEEFuncEntryPointMacro(JIT_MonEnter);
-
- // Monitor helpers are used as both hcalls and fcalls, thus we need exact depth.
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH, objRef);
-
- if (objRef == NULL)
- COMPlusThrow(kArgumentNullException);
-
- MONHELPER_STATE(GCPROTECT_BEGININTERIOR(pbLockTaken);)
-
-#ifdef _DEBUG
- Thread *pThread = GetThread();
- DWORD lockCount = pThread->m_dwLockCount;
-#endif
- if (GET_THREAD()->CatchAtSafePointOpportunistic())
- {
- GET_THREAD()->PulseGCMode();
- }
- objRef->EnterObjMonitor();
- _ASSERTE ((objRef->GetSyncBlock()->GetMonitor()->m_Recursion == 1 && pThread->m_dwLockCount == lockCount + 1) ||
- pThread->m_dwLockCount == lockCount);
- MONHELPER_STATE(if (pbLockTaken != 0) *pbLockTaken = 1;)
-
- MONHELPER_STATE(GCPROTECT_END();)
- HELPER_METHOD_FRAME_END();
-}
-HCIMPLEND
-
-/*********************************************************************/
-
-// This helper is only ever used as part of FCall, but it is implemented using HCIMPL macro
-// so that it can be tail called from assembly helper without triggering asserts in debug.
-HCIMPL2(void, JITutil_MonReliableEnter, Object* obj, BYTE* pbLockTaken)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- OBJECTREF objRef = ObjectToOBJECTREF(obj);
-
- // The following makes sure that Monitor.Enter shows up on thread abort
- // stack walks (otherwise Monitor.Enter called within a CER can block a
- // thread abort indefinitely). Setting the __me internal variable (normally
- // only set for fcalls) will cause the helper frame below to be able to
- // backtranslate into the method desc for the Monitor.Enter fcall.
- __me = GetEEFuncEntryPointMacro(JIT_MonReliableEnter);
-
- // Monitor helpers are used as both hcalls and fcalls, thus we need exact depth.
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH, objRef);
-
- if (objRef == NULL)
- COMPlusThrow(kArgumentNullException);
-
- GCPROTECT_BEGININTERIOR(pbLockTaken);
-
-#ifdef _DEBUG
- Thread *pThread = GetThread();
- DWORD lockCount = pThread->m_dwLockCount;
-#endif
- if (GET_THREAD()->CatchAtSafePointOpportunistic())
- {
- GET_THREAD()->PulseGCMode();
- }
- objRef->EnterObjMonitor();
- _ASSERTE ((objRef->GetSyncBlock()->GetMonitor()->m_Recursion == 1 && pThread->m_dwLockCount == lockCount + 1) ||
- pThread->m_dwLockCount == lockCount);
- *pbLockTaken = 1;
-
- GCPROTECT_END();
- HELPER_METHOD_FRAME_END();
-}
-HCIMPLEND
-
-
-/*********************************************************************/
-
-// This helper is only ever used as part of FCall, but it is implemented using HCIMPL macro
-// so that it can be tail called from assembly helper without triggering asserts in debug.
-HCIMPL3(void, JITutil_MonTryEnter, Object* obj, INT32 timeOut, BYTE* pbLockTaken)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- BOOL result = FALSE;
-
- OBJECTREF objRef = ObjectToOBJECTREF(obj);
-
- // The following makes sure that Monitor.TryEnter shows up on thread
- // abort stack walks (otherwise Monitor.TryEnter called within a CER can
- // block a thread abort for long periods of time). Setting the __me internal
- // variable (normally only set for fcalls) will cause the helper frame below
- // to be able to backtranslate into the method desc for the Monitor.TryEnter
- // fcall.
- __me = GetEEFuncEntryPointMacro(JIT_MonTryEnter);
-
- // Monitor helpers are used as both hcalls and fcalls, thus we need exact depth.
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH, objRef);
-
- if (objRef == NULL)
- COMPlusThrow(kArgumentNullException);
-
- if (timeOut < -1)
- COMPlusThrow(kArgumentOutOfRangeException);
-
- GCPROTECT_BEGININTERIOR(pbLockTaken);
-
- if (GET_THREAD()->CatchAtSafePointOpportunistic())
- {
- GET_THREAD()->PulseGCMode();
- }
-
- result = objRef->TryEnterObjMonitor(timeOut);
- *pbLockTaken = result != FALSE;
-
- GCPROTECT_END();
- HELPER_METHOD_FRAME_END();
-}
-HCIMPLEND
-
-/*********************************************************************/
-HCIMPL_MONHELPER(JITutil_MonExitWorker, Object* obj)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- MONHELPER_STATE(if (pbLockTaken != NULL && *pbLockTaken == 0) return;)
-
- OBJECTREF objRef = ObjectToOBJECTREF(obj);
-
- // Monitor helpers are used as both hcalls and fcalls, thus we need exact depth.
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT|Frame::FRAME_ATTR_EXACT_DEPTH, objRef);
-
- if (objRef == NULL)
- COMPlusThrow(kArgumentNullException);
-
- if (!objRef->LeaveObjMonitor())
- COMPlusThrow(kSynchronizationLockException);
-
- MONHELPER_STATE(if (pbLockTaken != 0) *pbLockTaken = 0;)
-
- TESTHOOKCALL(AppDomainCanBeUnloaded(GET_THREAD()->GetDomain()->GetId().m_dwId,FALSE));
-
- if (GET_THREAD()->IsAbortRequested()) {
- GET_THREAD()->HandleThreadAbort();
- }
-
- HELPER_METHOD_FRAME_END();
-}
-HCIMPLEND
-
-/*********************************************************************/
-// A helper for JIT_MonEnter that is on the callee side of an ecall
-// frame and handles the contention case.
-
-HCIMPL_MONHELPER(JITutil_MonContention, AwareLock* lock)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- // The following makes sure that Monitor.Enter shows up on thread abort
- // stack walks (otherwise Monitor.Enter called within a CER can block a
- // thread abort indefinitely). Setting the __me internal variable (normally
- // only set for fcalls) will cause the helper frame below to be able to
- // backtranslate into the method desc for the Monitor.Enter fcall.
- __me = GetEEFuncEntryPointMacro(JIT_MonEnter);
-
- // Monitor helpers are used as both hcalls and fcalls, thus we need exact depth.
- HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH);
- MONHELPER_STATE(GCPROTECT_BEGININTERIOR(pbLockTaken);)
-
-#ifdef _DEBUG
- Thread *pThread = GetThread();
- DWORD lockCount = pThread->m_dwLockCount;
-#endif
- lock->Contention();
- _ASSERTE (pThread->m_dwLockCount == lockCount + 1);
- MONHELPER_STATE(if (pbLockTaken != 0) *pbLockTaken = 1;)
-
- MONHELPER_STATE(GCPROTECT_END();)
- HELPER_METHOD_FRAME_END();
-}
-HCIMPLEND
-
-// This helper is only ever used as part of FCall, but it is implemented using HCIMPL macro
-// so that it can be tail called from assembly helper without triggering asserts in debug.
-HCIMPL2(void, JITutil_MonReliableContention, AwareLock* lock, BYTE* pbLockTaken)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- // The following makes sure that Monitor.Enter shows up on thread abort
- // stack walks (otherwise Monitor.Enter called within a CER can block a
- // thread abort indefinitely). Setting the __me internal variable (normally
- // only set for fcalls) will cause the helper frame below to be able to
- // backtranslate into the method desc for the Monitor.Enter fcall.
- __me = GetEEFuncEntryPointMacro(JIT_MonReliableEnter);
-
- // Monitor helpers are used as both hcalls and fcalls, thus we need exact depth.
- HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH);
- GCPROTECT_BEGININTERIOR(pbLockTaken);
-
-#ifdef _DEBUG
- Thread *pThread = GetThread();
- DWORD lockCount = pThread->m_dwLockCount;
-#endif
- lock->Contention();
- _ASSERTE (pThread->m_dwLockCount == lockCount + 1);
- *pbLockTaken = 1;
-
- GCPROTECT_END();
- HELPER_METHOD_FRAME_END();
-}
-HCIMPLEND
-
-/*********************************************************************/
-// A helper for JIT_MonExit and JIT_MonExitStatic that is on the
-// callee side of an ecall frame and handles cases that might allocate,
-// throw or block.
-HCIMPL_MONHELPER(JITutil_MonSignal, AwareLock* lock)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- // Monitor helpers are used as both hcalls and fcalls, thus we need exact depth.
- HELPER_METHOD_FRAME_BEGIN_ATTRIB(Frame::FRAME_ATTR_EXACT_DEPTH | Frame::FRAME_ATTR_NO_THREAD_ABORT);
-
- lock->Signal();
- MONHELPER_STATE(if (pbLockTaken != 0) *pbLockTaken = 0;)
-
- TESTHOOKCALL(AppDomainCanBeUnloaded(GET_THREAD()->GetDomain()->GetId().m_dwId,FALSE));
-
- if (GET_THREAD()->IsAbortRequested()) {
- GET_THREAD()->HandleThreadAbort();
- }
-
- HELPER_METHOD_FRAME_END();
-}
-HCIMPLEND
-
HCIMPL1(void *, JIT_GetSyncFromClassHandle, CORINFO_CLASS_HANDLE typeHnd_)
CONTRACTL {
FCALL_CHECK;