-
Notifications
You must be signed in to change notification settings - Fork 5.5k
Micro optimizations to improve the performance of EH stackwalking, particularly in the X86 with Funclets model #114582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e3ac237
72e890d
d899e0b
cc6d9b5
c1f6101
8548bd6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,8 +56,18 @@ struct StackTraceElement | |
|
|
||
| class StackTraceInfo | ||
| { | ||
| struct StackTraceArrayProtect | ||
|
||
| { | ||
| // Stores the current stack trace array. This array may be accessed by multiple threads | ||
| // during exception handling, and needs to be protected from concurrent modifications. | ||
| StackTraceArray m_pStackTraceArray; | ||
|
|
||
| // Used as a temporary buffer when resizing the stack trace array. | ||
| // This allows atomic replacement of the original array with the newly sized array. | ||
| StackTraceArray m_pStackTraceArrayNew; | ||
| }; | ||
| static OBJECTREF GetKeepAliveObject(MethodDesc* pMethod); | ||
| static void EnsureStackTraceArray(StackTraceArray *pStackTrace, size_t neededSize); | ||
| static void EnsureStackTraceArray(StackTraceArrayProtect *pStackTraceArrayProtected, size_t neededSize); | ||
| static void EnsureKeepAliveArray(PTRARRAYREF *ppKeepAliveArray, size_t neededSize); | ||
| public: | ||
| static void AppendElement(OBJECTHANDLE hThrowable, UINT_PTR currentIP, UINT_PTR currentSP, MethodDesc* pFunc, CrawlFrame* pCf); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -494,7 +494,7 @@ OBJECTREF PossiblyUnwrapThrowable(OBJECTREF throwable, Assembly *pAssembly) | |
| } | ||
| CONTRACTL_END; | ||
|
|
||
| if (fIsRuntimeWrappedException && (!pAssembly->GetModule()->IsRuntimeWrapExceptions())) | ||
| if (fIsRuntimeWrappedException && (!pAssembly->GetModule()->IsRuntimeWrapExceptionsDuringEH())) | ||
| { | ||
| // We already created the instance, fetched the field. We know it is | ||
| // not marshal by ref, or any of the other cases that might trigger GC. | ||
|
|
@@ -2876,20 +2876,17 @@ void SetupWatsonBucket(UINT_PTR currentIP, CrawlFrame* pCf) | |
| #endif // !TARGET_UNIX | ||
|
|
||
| // Ensure that there is space for neededSize elements in the stack trace array. | ||
| void StackTraceInfo::EnsureStackTraceArray(StackTraceArray *pStackTrace, size_t neededSize) | ||
| void StackTraceInfo::EnsureStackTraceArray(StackTraceArrayProtect *pStackTraceProtected, size_t neededSize) | ||
| { | ||
| CONTRACTL | ||
| { | ||
| GC_TRIGGERS; | ||
| THROWS; | ||
| PRECONDITION(CheckPointer(pStackTrace)); | ||
| PRECONDITION(CheckPointer(pStackTraceProtected)); | ||
| } | ||
| CONTRACTL_END; | ||
|
|
||
| StackTraceArray newStackTrace; | ||
| GCPROTECT_BEGIN(newStackTrace); | ||
|
|
||
| size_t stackTraceCapacity = pStackTrace->Capacity(); | ||
| size_t stackTraceCapacity = pStackTraceProtected->m_pStackTraceArray.Capacity(); | ||
|
||
| if (neededSize > stackTraceCapacity) | ||
| { | ||
| S_SIZE_T newCapacity = S_SIZE_T(stackTraceCapacity) * S_SIZE_T(2); | ||
|
|
@@ -2905,17 +2902,16 @@ void StackTraceInfo::EnsureStackTraceArray(StackTraceArray *pStackTrace, size_t | |
| stackTraceCapacity = newCapacity.Value(); | ||
|
|
||
| // Allocate a new array with the needed size | ||
| newStackTrace.Allocate(stackTraceCapacity); | ||
| if (pStackTrace->Get() != NULL) | ||
| pStackTraceProtected->m_pStackTraceArrayNew.Allocate(stackTraceCapacity); | ||
| if (pStackTraceProtected->m_pStackTraceArray.Get() != NULL) | ||
| { | ||
| // Copy the original array to the new one | ||
| newStackTrace.CopyDataFrom(*pStackTrace); | ||
| _ASSERTE(newStackTrace.Size() == (neededSize - 1)); | ||
| pStackTraceProtected->m_pStackTraceArrayNew.CopyDataFrom(pStackTraceProtected->m_pStackTraceArray); | ||
| _ASSERTE(pStackTraceProtected->m_pStackTraceArrayNew.Size() == (neededSize - 1)); | ||
| } | ||
| // Update the stack trace array | ||
| pStackTrace->Set(newStackTrace.Get()); | ||
| pStackTraceProtected->m_pStackTraceArray.Set(pStackTraceProtected->m_pStackTraceArrayNew.Get()); | ||
| } | ||
| GCPROTECT_END(); | ||
| } | ||
|
|
||
| // Ensure that there is space for the neededSize elements in the keepAlive array. | ||
|
|
@@ -3073,7 +3069,7 @@ void StackTraceInfo::AppendElement(OBJECTHANDLE hThrowable, UINT_PTR currentIP, | |
| { | ||
| struct | ||
| { | ||
| StackTraceArray stackTrace; | ||
| StackTraceArrayProtect stackTrace; | ||
| PTRARRAYREF pKeepAliveArray = NULL; // Object array of Managed Resolvers / Loader Allocators of methods that can be collected | ||
| OBJECTREF keepAliveObject = NULL; | ||
| } gc; | ||
|
|
@@ -3082,30 +3078,30 @@ void StackTraceInfo::AppendElement(OBJECTHANDLE hThrowable, UINT_PTR currentIP, | |
|
|
||
| // Fetch the stacktrace and the keepAlive array from the exception object. It returns clones of those arrays in case the | ||
| // stack trace was created by a different thread. | ||
| ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->GetStackTrace(gc.stackTrace, &gc.pKeepAliveArray); | ||
| ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->GetStackTrace(gc.stackTrace.m_pStackTraceArray, &gc.pKeepAliveArray, pThread); | ||
|
|
||
| // The stack trace returned by the GetStackTrace has to be created by the current thread or be NULL. | ||
| _ASSERTE((gc.stackTrace.Get() == NULL) || (gc.stackTrace.GetObjectThread() == pThread)); | ||
| _ASSERTE((gc.stackTrace.m_pStackTraceArray.Get() == NULL) || (gc.stackTrace.m_pStackTraceArray.GetObjectThread() == pThread)); | ||
|
|
||
| EnsureStackTraceArray(&gc.stackTrace, gc.stackTrace.Size() + 1); | ||
| EnsureStackTraceArray(&gc.stackTrace, gc.stackTrace.m_pStackTraceArray.Size() + 1); | ||
|
|
||
| if (fRaisingForeignException) | ||
| { | ||
| // Just before we append to the stack trace, mark the last recorded frame to be from | ||
| // the foreign thread so that we can insert an annotation indicating so when building | ||
| // the stack trace string. | ||
| size_t numCurrentFrames = gc.stackTrace.Size(); | ||
| size_t numCurrentFrames = gc.stackTrace.m_pStackTraceArray.Size(); | ||
| if (numCurrentFrames > 0) | ||
| { | ||
| // "numCurrentFrames" can be zero if the user created an EDI using | ||
| // an unthrown exception. | ||
| StackTraceElement & refLastElementFromForeignStackTrace = gc.stackTrace[numCurrentFrames - 1]; | ||
| StackTraceElement & refLastElementFromForeignStackTrace = gc.stackTrace.m_pStackTraceArray[numCurrentFrames - 1]; | ||
| refLastElementFromForeignStackTrace.flags |= STEF_LAST_FRAME_FROM_FOREIGN_STACK_TRACE; | ||
| } | ||
| } | ||
|
|
||
| uint32_t keepAliveItemsCount = gc.stackTrace.GetKeepAliveItemsCount(); | ||
| _ASSERTE(keepAliveItemsCount == gc.stackTrace.ComputeKeepAliveItemsCount()); | ||
| uint32_t keepAliveItemsCount = gc.stackTrace.m_pStackTraceArray.GetKeepAliveItemsCount(); | ||
| _ASSERTE(keepAliveItemsCount == gc.stackTrace.m_pStackTraceArray.ComputeKeepAliveItemsCount()); | ||
|
|
||
| gc.keepAliveObject = GetKeepAliveObject(pFunc); | ||
| if (gc.keepAliveObject != NULL) | ||
|
|
@@ -3131,21 +3127,21 @@ void StackTraceInfo::AppendElement(OBJECTHANDLE hThrowable, UINT_PTR currentIP, | |
| gc.pKeepAliveArray = NULL; | ||
| } | ||
|
|
||
| gc.stackTrace.SetKeepAliveItemsCount(keepAliveItemsCount); | ||
| gc.stackTrace.m_pStackTraceArray.SetKeepAliveItemsCount(keepAliveItemsCount); | ||
|
|
||
| gc.stackTrace.Append(&stackTraceElem); | ||
| _ASSERTE(gc.stackTrace.ComputeKeepAliveItemsCount() == keepAliveItemsCount); | ||
| gc.stackTrace.m_pStackTraceArray.Append(&stackTraceElem); | ||
| _ASSERTE(gc.stackTrace.m_pStackTraceArray.ComputeKeepAliveItemsCount() == keepAliveItemsCount); | ||
|
|
||
| if (gc.pKeepAliveArray != NULL) | ||
| { | ||
| _ASSERTE(keepAliveItemsCount > 0); | ||
| gc.pKeepAliveArray->SetAt(0, gc.stackTrace.Get()); | ||
| gc.pKeepAliveArray->SetAt(0, gc.stackTrace.m_pStackTraceArray.Get()); | ||
| ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->SetStackTrace(dac_cast<OBJECTREF>(gc.pKeepAliveArray)); | ||
| } | ||
| else | ||
| { | ||
| _ASSERTE(keepAliveItemsCount == 0); | ||
| ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->SetStackTrace(dac_cast<OBJECTREF>(gc.stackTrace.Get())); | ||
| ((EXCEPTIONREF)ObjectFromHandle(hThrowable))->SetStackTrace(dac_cast<OBJECTREF>(gc.stackTrace.m_pStackTraceArray.Get())); | ||
| } | ||
|
|
||
| // Clear the _stackTraceString field as it no longer matches the stack trace | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It may be helpful to document the assumption that the runtime wrap exception status is computed before calling IsRuntimeWrapExceptionsDuringEH, to aid future maintainers in understanding the precondition.