-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Remove global spinlock for EH stacktrace #103076
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 10 commits
718f638
96da965
fb8cc6b
2d63781
8eccdbc
f774c60
d056127
0fa22ad
dfe4e47
8355c30
20caf05
e989ed2
12db638
4259620
fcf6182
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 | ||||
|---|---|---|---|---|---|---|
|
|
@@ -76,75 +76,49 @@ FCIMPL0(VOID, ExceptionNative::PrepareForForeignExceptionRaise) | |||||
| } | ||||||
| FCIMPLEND | ||||||
|
|
||||||
| // Given an exception object, this method will extract the stacktrace and dynamic method array and set them up for return to the caller. | ||||||
| FCIMPL3(VOID, ExceptionNative::GetStackTracesDeepCopy, Object* pExceptionObjectUnsafe, Object **pStackTraceUnsafe, Object **pDynamicMethodsUnsafe); | ||||||
| void DeepCopyStackTrace(StackTraceArray &stackTrace, StackTraceArray &stackTraceCopy, PTRARRAYREF *pKeepAliveArray, PTRARRAYREF *pKeepAliveArrayCopy) | ||||||
janvorli marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| { | ||||||
| CONTRACTL | ||||||
| { | ||||||
| FCALL_CHECK; | ||||||
| THROWS; | ||||||
| GC_TRIGGERS; | ||||||
| MODE_COOPERATIVE; | ||||||
| PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)&stackTrace)); | ||||||
| PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)&stackTraceCopy)); | ||||||
| PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)pKeepAliveArray)); | ||||||
| PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)pKeepAliveArrayCopy)); | ||||||
| } | ||||||
| CONTRACTL_END; | ||||||
|
|
||||||
| ASSERT(pExceptionObjectUnsafe != NULL); | ||||||
| ASSERT(pStackTraceUnsafe != NULL); | ||||||
| ASSERT(pDynamicMethodsUnsafe != NULL); | ||||||
|
|
||||||
| struct | ||||||
| if (stackTrace.Get() != NULL) | ||||||
| { | ||||||
| StackTraceArray stackTrace; | ||||||
| StackTraceArray stackTraceCopy; | ||||||
| EXCEPTIONREF refException; | ||||||
| PTRARRAYREF dynamicMethodsArray; // Object array of Managed Resolvers | ||||||
| PTRARRAYREF dynamicMethodsArrayCopy; // Copy of the object array of Managed Resolvers | ||||||
| } gc; | ||||||
| gc.refException = NULL; | ||||||
| gc.dynamicMethodsArray = NULL; | ||||||
| gc.dynamicMethodsArrayCopy = NULL; | ||||||
|
|
||||||
| // GC protect the array reference | ||||||
| HELPER_METHOD_FRAME_BEGIN_PROTECT(gc); | ||||||
|
|
||||||
| // Get the exception object reference | ||||||
| gc.refException = (EXCEPTIONREF)(ObjectToOBJECTREF(pExceptionObjectUnsafe)); | ||||||
|
|
||||||
| // Fetch the stacktrace details from the exception under a lock | ||||||
| gc.refException->GetStackTrace(gc.stackTrace, &gc.dynamicMethodsArray); | ||||||
|
|
||||||
| bool fHaveStackTrace = false; | ||||||
| bool fHaveDynamicMethodArray = false; | ||||||
|
|
||||||
| if ((unsigned)gc.stackTrace.Size() > 0) | ||||||
| stackTraceCopy.CopyFrom(stackTrace); | ||||||
| } | ||||||
| else | ||||||
| { | ||||||
| // Deepcopy the array | ||||||
| gc.stackTraceCopy.CopyFrom(gc.stackTrace); | ||||||
| fHaveStackTrace = true; | ||||||
| stackTraceCopy.Set(NULL); | ||||||
| } | ||||||
|
|
||||||
| if (gc.dynamicMethodsArray != NULL) | ||||||
| if (*pKeepAliveArray != NULL) | ||||||
| { | ||||||
| // The stack trace object is the keepAlive array with its first slot set to the stack trace I1Array. | ||||||
| // Get the number of elements in the dynamic methods array | ||||||
| unsigned cOrigDynamic = gc.dynamicMethodsArray->GetNumComponents(); | ||||||
| unsigned cOrigKeepAlive = (*pKeepAliveArray)->GetNumComponents(); | ||||||
|
|
||||||
| // ..and allocate a new array. This can trigger GC or throw under OOM. | ||||||
| gc.dynamicMethodsArrayCopy = (PTRARRAYREF)AllocateObjectArray(cOrigDynamic, g_pObjectClass); | ||||||
| *pKeepAliveArrayCopy = (PTRARRAYREF)AllocateObjectArray(cOrigKeepAlive, g_pObjectClass); | ||||||
|
|
||||||
| // Deepcopy references to the new array we just allocated | ||||||
| memmoveGCRefs(gc.dynamicMethodsArrayCopy->GetDataPtr(), gc.dynamicMethodsArray->GetDataPtr(), | ||||||
| cOrigDynamic * sizeof(Object *)); | ||||||
| memmoveGCRefs((*pKeepAliveArrayCopy)->GetDataPtr(), (*pKeepAliveArray)->GetDataPtr(), | ||||||
| cOrigKeepAlive * sizeof(Object *)); | ||||||
|
|
||||||
| fHaveDynamicMethodArray = true; | ||||||
| (*pKeepAliveArrayCopy)->SetAt(0, (PTRARRAYREF)stackTraceCopy.Get()); | ||||||
| } | ||||||
|
|
||||||
| // Prep to return | ||||||
| *pStackTraceUnsafe = fHaveStackTrace?OBJECTREFToObject(gc.stackTraceCopy.Get()):NULL; | ||||||
| *pDynamicMethodsUnsafe = fHaveDynamicMethodArray?OBJECTREFToObject(gc.dynamicMethodsArrayCopy):NULL; | ||||||
|
|
||||||
| HELPER_METHOD_FRAME_END(); | ||||||
| } | ||||||
| FCIMPLEND | ||||||
|
|
||||||
| // Given an exception object and deep copied instances of a stacktrace and/or dynamic method array, this method will set the latter in the exception object instance. | ||||||
| FCIMPL3(VOID, ExceptionNative::SaveStackTracesFromDeepCopy, Object* pExceptionObjectUnsafe, Object *pStackTraceUnsafe, Object *pDynamicMethodsUnsafe); | ||||||
| // Given an exception object, this method will mark its stack trace as frozen and return it to the caller. | ||||||
| // Frozen stack traces are immutable, when a thread attempts to add a frame to it, the stack trace is cloned first. | ||||||
| FCIMPL1(Object *, ExceptionNative::GetFrozenStackTrace, Object* pExceptionObjectUnsafe); | ||||||
| { | ||||||
| CONTRACTL | ||||||
| { | ||||||
|
|
@@ -157,44 +131,39 @@ FCIMPL3(VOID, ExceptionNative::SaveStackTracesFromDeepCopy, Object* pExceptionOb | |||||
| struct | ||||||
| { | ||||||
| StackTraceArray stackTrace; | ||||||
| EXCEPTIONREF refException; | ||||||
| PTRARRAYREF dynamicMethodsArray; // Object array of Managed Resolvers | ||||||
| EXCEPTIONREF refException = NULL; | ||||||
| PTRARRAYREF keepAliveArray = NULL; // Object array of Managed Resolvers / AssemblyLoadContexts | ||||||
| OBJECTREF result = NULL; | ||||||
| } gc; | ||||||
| gc.refException = NULL; | ||||||
| gc.dynamicMethodsArray = NULL; | ||||||
|
|
||||||
| // GC protect the array reference | ||||||
| HELPER_METHOD_FRAME_BEGIN_PROTECT(gc); | ||||||
| HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); | ||||||
|
|
||||||
| // Get the exception object reference | ||||||
| gc.refException = (EXCEPTIONREF)(ObjectToOBJECTREF(pExceptionObjectUnsafe)); | ||||||
|
|
||||||
| if (pStackTraceUnsafe != NULL) | ||||||
| { | ||||||
| // Copy the stacktrace | ||||||
| StackTraceArray stackTraceArray((I1ARRAYREF)ObjectToOBJECTREF(pStackTraceUnsafe)); | ||||||
| gc.stackTrace.Swap(stackTraceArray); | ||||||
| } | ||||||
| gc.refException->GetStackTrace(gc.stackTrace, &gc.keepAliveArray); | ||||||
|
|
||||||
| gc.dynamicMethodsArray = NULL; | ||||||
| if (pDynamicMethodsUnsafe != NULL) | ||||||
| gc.stackTrace.MarkAsFrozen(); | ||||||
|
|
||||||
| if (gc.keepAliveArray != NULL) | ||||||
| { | ||||||
| gc.dynamicMethodsArray = (PTRARRAYREF)ObjectToOBJECTREF(pDynamicMethodsUnsafe); | ||||||
| gc.result = gc.keepAliveArray; | ||||||
| } | ||||||
|
|
||||||
| // If there is no stacktrace, then there cannot be any dynamic method array. Thus, | ||||||
| // save stacktrace only when we have it. | ||||||
| if (gc.stackTrace.Size() > 0) | ||||||
| else if (gc.stackTrace.Get() != NULL) | ||||||
janvorli marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| { | ||||||
| // Save the stacktrace details in the exception under a lock | ||||||
| gc.refException->SetStackTrace(gc.stackTrace.Get(), gc.dynamicMethodsArray); | ||||||
| gc.result = gc.stackTrace.Get(); | ||||||
| } | ||||||
| else | ||||||
| { | ||||||
| gc.refException->SetStackTrace(NULL, NULL); | ||||||
| gc.result = NULL; | ||||||
| } | ||||||
|
|
||||||
| // There can be no GC after setting the frozenStackTrace until the Object is returned. | ||||||
|
||||||
| // There can be no GC after setting the frozenStackTrace until the Object is returned. |
I am not sure what this comment is trying to say.
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.
Ah, I've renamed the frozenStackTrace to result and forgotten to update the comment. It is trying to say that the gc.result is not protected after the HELPER_METHOD_FRAME_END
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.
Ok, that's writing manually managed code 101.
(We will want to convert this method to QCALL in near future to get rid of the HELPER_METHOD_FRAME.)
Uh oh!
There was an error while loading. Please reload this page.