Skip to content

Commit dd2120b

Browse files
authored
Remove global spinlock for EH stacktrace (#103076)
* Remove global spinlock for EH stacktrace The global spinlock that was used to ensure that stack trace and the associated dynamic methods array were updated and read atomically. However, for the new EH, it has shown to cause a high contention in case many threads were handling exceptions at the same time. This change replaces the two arrays by one object member in the exception class. It contains reference to either the byte[] of the stack trace (when there are no dynamic methods on the stack trace) or an object[] where the first element contains the stack trace byte[] reference and the following elements contain what used to be in the dynamic array. That allows atomic updates and reads of the stack trace and dynamic method keepalive references without a need of a lock. The original code was quite convoluted, it was difficult to reason about and it had some races in it that were hidden behind the global lock. So I have decided to rewrite the whole thing from scratch. The way it ensures that it is race free is that whenever it updates the exception stack trace and the one that's on the exception was created by a different thread, it creates a deep copy of both the stack trace and the keepalive array. When making the copy, it also handles a case when a frame that needs a keepalive entry is on the stack trace part, but the keepalive array extracted from the exception is stale (the other thread needed to resize the keepalive array, but not the stack trace). In that case, the stack trace is trimmed at first such entry found. Since the case when multiple threads are throwing the same exception and so they are modifying its stack trace in parallel is pathological anyways, I believe the extra work spent on creating the clones of the arrays is a good tradeoff for ensuring easy to reason about thread safety. I have also removed a dead code path from the StackTraceInfo::SaveStackTrace. Finally, since with the previous iteration of this change, a bug in building the stack trace was found, I have added a coreclr test to verify stack trace for an exception matches the expectations. * Fix MUSL build * Fix x86 build * Fix several issues * Missing calls to IsOverflow at few places * Added a flag on StackTraceElement to indicate that the element needs a keepalive entry. It removes the need to call IsLCGMethod / Collectible check on the method table stored in the element and eliminates a possible problem with the method being collected in one place. * Returned missing call to StackFrameInfo::Init to the x86 code path * Removed obsolete comment and code line * Few changes based on feedback * Add keep alive items count to the stack trace header. * Implement the concept of frozen stack traces to eliminate copies in the ExceptionDispatchInfo storing / restoring exceptions. * Rename keepalive to keepAlive * Handle possible array size overflow In the StackTraceArray::Allocate * Fix typo * Change the size / keepAlive fields in stack trace to uint32_t Plus a build break fix * Remove SaveStackTracesFromDeepCopy Also rename GetStackTracesDeepCopy to GetFrozenStackTrace and move the return argument to return value. * Remove dummy field and an unused function * Cleanup based on feedback * Move the race handling into GetStackTrace only Plus an unused method removal and a little naming / contract cleanup * Add VolatileLoad/Store around the size / keep alive count Also remove the memory barrier from the StackTraceArray::Append since it is not needed after that change. * Add comment on why trimming the stack trace by keep alive is needed I have also realized that when we need to trim, the keepAlive array is always fully populated, so we don't need to check for cases where there would be NULL in an entry of the array.
1 parent 673a664 commit dd2120b

25 files changed

+845
-894
lines changed

src/coreclr/System.Private.CoreLib/src/System/Exception.CoreCLR.cs

+7-19
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,7 @@ internal void InternalPreserveStackTrace()
128128
private static extern void PrepareForForeignExceptionRaise();
129129

130130
[MethodImpl(MethodImplOptions.InternalCall)]
131-
private static extern void GetStackTracesDeepCopy(Exception exception, out byte[]? currentStackTrace, out object[]? dynamicMethodArray);
132-
133-
[MethodImpl(MethodImplOptions.InternalCall)]
134-
internal static extern void SaveStackTracesFromDeepCopy(Exception exception, byte[]? currentStackTrace, object[]? dynamicMethodArray);
131+
private static extern object? GetFrozenStackTrace(Exception exception);
135132

136133
[MethodImpl(MethodImplOptions.InternalCall)]
137134
internal static extern uint GetExceptionCount();
@@ -147,18 +144,13 @@ internal void RestoreDispatchState(in DispatchState dispatchState)
147144
// in the exception object. This will ensure that when this exception is thrown and these
148145
// fields are modified, then EDI's references remain intact.
149146
//
150-
byte[]? stackTraceCopy = (byte[]?)dispatchState.StackTrace?.Clone();
151-
object[]? dynamicMethodsCopy = (object[]?)dispatchState.DynamicMethods?.Clone();
152147

153148
// Watson buckets and remoteStackTraceString fields are captured and restored without any locks. It is possible for them to
154149
// get out of sync without violating overall integrity of the system.
155150
_watsonBuckets = dispatchState.WatsonBuckets;
156151
_ipForWatsonBuckets = dispatchState.IpForWatsonBuckets;
157152
_remoteStackTraceString = dispatchState.RemoteStackTrace;
158-
159-
// The binary stack trace and references to dynamic methods have to be restored under a lock to guarantee integrity of the system.
160-
SaveStackTracesFromDeepCopy(this, stackTraceCopy, dynamicMethodsCopy);
161-
153+
_stackTrace = dispatchState.StackTrace;
162154
_stackTraceString = null;
163155

164156
// Marks the TES state to indicate we have restored foreign exception
@@ -172,7 +164,7 @@ internal void RestoreDispatchState(in DispatchState dispatchState)
172164
private IDictionary? _data;
173165
private readonly Exception? _innerException;
174166
private string? _helpURL;
175-
private byte[]? _stackTrace;
167+
private object? _stackTrace;
176168
private byte[]? _watsonBuckets;
177169
private string? _stackTraceString; // Needed for serialization.
178170
private string? _remoteStackTraceString;
@@ -181,7 +173,6 @@ internal void RestoreDispatchState(in DispatchState dispatchState)
181173
// DynamicMethodDescs alive for the lifetime of the exception. We do this because
182174
// the _stackTrace field holds MethodDescs, and a DynamicMethodDesc can be destroyed
183175
// unless a System.Resolver object roots it.
184-
private readonly object[]? _dynamicMethods;
185176
private string? _source; // Mainly used by VB.
186177
private UIntPtr _ipForWatsonBuckets; // Used to persist the IP for Watson Bucketing
187178
private readonly IntPtr _xptrs; // Internal EE stuff
@@ -227,21 +218,18 @@ internal static string GetMessageFromNativeResources(ExceptionMessageKind kind)
227218

228219
internal readonly struct DispatchState
229220
{
230-
public readonly byte[]? StackTrace;
231-
public readonly object[]? DynamicMethods;
221+
public readonly object? StackTrace;
232222
public readonly string? RemoteStackTrace;
233223
public readonly UIntPtr IpForWatsonBuckets;
234224
public readonly byte[]? WatsonBuckets;
235225

236226
public DispatchState(
237-
byte[]? stackTrace,
238-
object[]? dynamicMethods,
227+
object? stackTrace,
239228
string? remoteStackTrace,
240229
UIntPtr ipForWatsonBuckets,
241230
byte[]? watsonBuckets)
242231
{
243232
StackTrace = stackTrace;
244-
DynamicMethods = dynamicMethods;
245233
RemoteStackTrace = remoteStackTrace;
246234
IpForWatsonBuckets = ipForWatsonBuckets;
247235
WatsonBuckets = watsonBuckets;
@@ -250,9 +238,9 @@ public DispatchState(
250238

251239
internal DispatchState CaptureDispatchState()
252240
{
253-
GetStackTracesDeepCopy(this, out byte[]? stackTrace, out object[]? dynamicMethods);
241+
object? stackTrace = GetFrozenStackTrace(this);
254242

255-
return new DispatchState(stackTrace, dynamicMethods,
243+
return new DispatchState(stackTrace,
256244
_remoteStackTraceString, _ipForWatsonBuckets, _watsonBuckets);
257245
}
258246

src/coreclr/System.Private.CoreLib/src/System/Runtime/ExceptionServices/AsmOffsets.cs

+12-12
Original file line numberDiff line numberDiff line change
@@ -166,23 +166,23 @@ class AsmOffsets
166166
public const int SIZEOF__EHEnum = 0x20;
167167
public const int OFFSETOF__StackFrameIterator__m_pRegDisplay = 0x228;
168168
public const int OFFSETOF__ExInfo__m_pPrevExInfo = 0;
169-
public const int OFFSETOF__ExInfo__m_pExContext = 0xc0;
170-
public const int OFFSETOF__ExInfo__m_exception = 0xc8;
171-
public const int OFFSETOF__ExInfo__m_kind = 0xd0;
172-
public const int OFFSETOF__ExInfo__m_passNumber = 0xd1;
173-
public const int OFFSETOF__ExInfo__m_idxCurClause = 0xd4;
174-
public const int OFFSETOF__ExInfo__m_frameIter = 0xd8;
169+
public const int OFFSETOF__ExInfo__m_pExContext = 0xa8;
170+
public const int OFFSETOF__ExInfo__m_exception = 0xb0;
171+
public const int OFFSETOF__ExInfo__m_kind = 0xb8;
172+
public const int OFFSETOF__ExInfo__m_passNumber = 0xb9;
173+
public const int OFFSETOF__ExInfo__m_idxCurClause = 0xbc;
174+
public const int OFFSETOF__ExInfo__m_frameIter = 0xc0;
175175
public const int OFFSETOF__ExInfo__m_notifyDebuggerSP = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator;
176176
#else // TARGET_64BIT
177177
public const int SIZEOF__EHEnum = 0x10;
178178
public const int OFFSETOF__StackFrameIterator__m_pRegDisplay = 0x218;
179179
public const int OFFSETOF__ExInfo__m_pPrevExInfo = 0;
180-
public const int OFFSETOF__ExInfo__m_pExContext = 0x70;
181-
public const int OFFSETOF__ExInfo__m_exception = 0x74;
182-
public const int OFFSETOF__ExInfo__m_kind = 0x78;
183-
public const int OFFSETOF__ExInfo__m_passNumber = 0x79;
184-
public const int OFFSETOF__ExInfo__m_idxCurClause = 0x7C;
185-
public const int OFFSETOF__ExInfo__m_frameIter = 0x80;
180+
public const int OFFSETOF__ExInfo__m_pExContext = 0x5c;
181+
public const int OFFSETOF__ExInfo__m_exception = 0x60;
182+
public const int OFFSETOF__ExInfo__m_kind = 0x64;
183+
public const int OFFSETOF__ExInfo__m_passNumber = 0x65;
184+
public const int OFFSETOF__ExInfo__m_idxCurClause = 0x68;
185+
public const int OFFSETOF__ExInfo__m_frameIter = 0x6c;
186186
public const int OFFSETOF__ExInfo__m_notifyDebuggerSP = OFFSETOF__ExInfo__m_frameIter + SIZEOF__StackFrameIterator;
187187
#endif // TARGET_64BIT
188188

src/coreclr/classlibnative/bcltype/system.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ FCIMPL1(ReflectMethodObject*, SystemNative::GetMethodFromStackTrace, ArrayBase*
9393
{
9494
FCALL_CONTRACT;
9595

96+
// The pStackTraceUNSAFE can be either I1Array or Object[]. In the latter case, the first entry is the actual stack trace I1Array,
97+
// the rest are pointers to the method info objects. We only care about the first entry here.
98+
if (pStackTraceUNSAFE->GetArrayElementType() != ELEMENT_TYPE_I1)
99+
{
100+
PtrArray *combinedArray = (PtrArray*)pStackTraceUNSAFE;
101+
pStackTraceUNSAFE = (ArrayBase*)OBJECTREFToObject(combinedArray->GetAt(0));
102+
}
96103
I1ARRAYREF pArray(static_cast<I1Array *>(pStackTraceUNSAFE));
97104
StackTraceArray stackArray(pArray);
98105

src/coreclr/debug/daccess/enummem.cpp

+17-1
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ HRESULT ClrDataAccess::DumpManagedExcepObject(CLRDataEnumMemoryFlags flags, OBJE
533533
DumpManagedExcepObject(flags, exceptRef->GetInnerException());
534534

535535
// Dump the stack trace array object and its underlying type
536-
I1ARRAYREF stackTraceArrayObj = exceptRef->GetStackTraceArrayObject();
536+
OBJECTREF stackTraceArrayObj = exceptRef->GetStackTraceArrayObject();
537537

538538
// There are cases where a managed exception does not have a stack trace.
539539
// These cases are:
@@ -558,6 +558,22 @@ HRESULT ClrDataAccess::DumpManagedExcepObject(CLRDataEnumMemoryFlags flags, OBJE
558558
// MD this happens.
559559
StackTraceArray stackTrace;
560560
exceptRef->GetStackTrace(stackTrace);
561+
562+
// The stackTraceArrayObj can be either a byte[] with the actual stack trace array or an object[] where the first element is the actual stack trace array.
563+
// In case it was the latter, we need to dump the actual stack trace array object here too.
564+
OBJECTREF actualStackTraceArrayObj = (OBJECTREF)stackTrace.Get();
565+
if (actualStackTraceArrayObj != stackTraceArrayObj)
566+
{
567+
// first dump the array's element type
568+
TypeHandle arrayTypeHandle = actualStackTraceArrayObj->GetTypeHandle();
569+
TypeHandle elementTypeHandle = arrayTypeHandle.GetArrayElementTypeHandle();
570+
elementTypeHandle.AsMethodTable()->EnumMemoryRegions(flags);
571+
elementTypeHandle.AsMethodTable()->GetClass()->EnumMemoryRegions(flags, elementTypeHandle.AsMethodTable());
572+
573+
// now dump the actual stack trace array object
574+
DumpManagedObject(flags, actualStackTraceArrayObj);
575+
}
576+
561577
for(size_t i = 0; i < stackTrace.Size(); i++)
562578
{
563579
MethodDesc* pMD = stackTrace[i].pFunc;

src/coreclr/vm/clrex.h

+7-19
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ enum StackTraceElementFlags
2727

2828
// Set if the "ip" field has already been adjusted (decremented)
2929
STEF_IP_ADJUSTED = 0x0002,
30+
31+
// Set if the element references a method that needs a keep alive object
32+
STEF_KEEPALIVE = 0x0004,
3033
};
3134

3235
// This struct is used by SOS in the diagnostic repo.
@@ -51,28 +54,13 @@ struct StackTraceElement
5154
}
5255
};
5356

54-
// This struct is used by SOS in the diagnostic repo.
55-
// See: https://github.com/dotnet/diagnostics/blob/9ff35f13af2f03a68a166cfd53f1a4bb32425f2f/src/SOS/Strike/strike.cpp#L2669
5657
class StackTraceInfo
5758
{
58-
private:
59-
// for building stack trace info
60-
StackTraceElement* m_pStackTrace; // pointer to stack trace storage
61-
unsigned m_cStackTrace; // size of stack trace storage
62-
unsigned m_dFrameCount; // current frame in stack trace
63-
unsigned m_cDynamicMethodItems; // number of items in the Dynamic Method array
64-
unsigned m_dCurrentDynamicIndex; // index of the next location where the resolver object will be stored
65-
59+
static OBJECTREF GetKeepAliveObject(MethodDesc* pMethod);
60+
static void EnsureStackTraceArray(StackTraceArray *pStackTrace, size_t neededSize);
61+
static void EnsureKeepAliveArray(PTRARRAYREF *ppKeepAliveArray, size_t neededSize);
6662
public:
67-
void Init();
68-
BOOL IsEmpty();
69-
void AllocateStackTrace();
70-
void ClearStackTrace();
71-
void FreeStackTrace();
72-
void SaveStackTrace(BOOL bAllowAllocMem, OBJECTHANDLE hThrowable, BOOL bReplaceStack, BOOL bSkipLastElement);
73-
BOOL AppendElement(BOOL bAllowAllocMem, UINT_PTR currentIP, UINT_PTR currentSP, MethodDesc* pFunc, CrawlFrame* pCf);
74-
75-
void GetLeafFrameInfo(StackTraceElement* pStackTraceElement);
63+
static void AppendElement(OBJECTHANDLE hThrowable, UINT_PTR currentIP, UINT_PTR currentSP, MethodDesc* pFunc, CrawlFrame* pCf);
7664
};
7765

7866

src/coreclr/vm/comutilnative.cpp

+15-92
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,9 @@ FCIMPL0(VOID, ExceptionNative::PrepareForForeignExceptionRaise)
7676
}
7777
FCIMPLEND
7878

79-
// Given an exception object, this method will extract the stacktrace and dynamic method array and set them up for return to the caller.
80-
FCIMPL3(VOID, ExceptionNative::GetStackTracesDeepCopy, Object* pExceptionObjectUnsafe, Object **pStackTraceUnsafe, Object **pDynamicMethodsUnsafe);
79+
// Given an exception object, this method will mark its stack trace as frozen and return it to the caller.
80+
// Frozen stack traces are immutable, when a thread attempts to add a frame to it, the stack trace is cloned first.
81+
FCIMPL1(Object *, ExceptionNative::GetFrozenStackTrace, Object* pExceptionObjectUnsafe);
8182
{
8283
CONTRACTL
8384
{
@@ -86,115 +87,37 @@ FCIMPL3(VOID, ExceptionNative::GetStackTracesDeepCopy, Object* pExceptionObjectU
8687
CONTRACTL_END;
8788

8889
ASSERT(pExceptionObjectUnsafe != NULL);
89-
ASSERT(pStackTraceUnsafe != NULL);
90-
ASSERT(pDynamicMethodsUnsafe != NULL);
9190

9291
struct
9392
{
9493
StackTraceArray stackTrace;
95-
StackTraceArray stackTraceCopy;
96-
EXCEPTIONREF refException;
97-
PTRARRAYREF dynamicMethodsArray; // Object array of Managed Resolvers
98-
PTRARRAYREF dynamicMethodsArrayCopy; // Copy of the object array of Managed Resolvers
94+
EXCEPTIONREF refException = NULL;
95+
PTRARRAYREF keepAliveArray = NULL; // Object array of Managed Resolvers / AssemblyLoadContexts
96+
OBJECTREF result = NULL;
9997
} gc;
100-
gc.refException = NULL;
101-
gc.dynamicMethodsArray = NULL;
102-
gc.dynamicMethodsArrayCopy = NULL;
10398

10499
// GC protect the array reference
105-
HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
100+
HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
106101

107102
// Get the exception object reference
108103
gc.refException = (EXCEPTIONREF)(ObjectToOBJECTREF(pExceptionObjectUnsafe));
109104

110-
// Fetch the stacktrace details from the exception under a lock
111-
gc.refException->GetStackTrace(gc.stackTrace, &gc.dynamicMethodsArray);
105+
gc.refException->GetStackTrace(gc.stackTrace, &gc.keepAliveArray);
112106

113-
bool fHaveStackTrace = false;
114-
bool fHaveDynamicMethodArray = false;
107+
gc.stackTrace.MarkAsFrozen();
115108

116-
if ((unsigned)gc.stackTrace.Size() > 0)
109+
if (gc.keepAliveArray != NULL)
117110
{
118-
// Deepcopy the array
119-
gc.stackTraceCopy.CopyFrom(gc.stackTrace);
120-
fHaveStackTrace = true;
121-
}
122-
123-
if (gc.dynamicMethodsArray != NULL)
124-
{
125-
// Get the number of elements in the dynamic methods array
126-
unsigned cOrigDynamic = gc.dynamicMethodsArray->GetNumComponents();
127-
128-
// ..and allocate a new array. This can trigger GC or throw under OOM.
129-
gc.dynamicMethodsArrayCopy = (PTRARRAYREF)AllocateObjectArray(cOrigDynamic, g_pObjectClass);
130-
131-
// Deepcopy references to the new array we just allocated
132-
memmoveGCRefs(gc.dynamicMethodsArrayCopy->GetDataPtr(), gc.dynamicMethodsArray->GetDataPtr(),
133-
cOrigDynamic * sizeof(Object *));
134-
135-
fHaveDynamicMethodArray = true;
136-
}
137-
138-
// Prep to return
139-
*pStackTraceUnsafe = fHaveStackTrace?OBJECTREFToObject(gc.stackTraceCopy.Get()):NULL;
140-
*pDynamicMethodsUnsafe = fHaveDynamicMethodArray?OBJECTREFToObject(gc.dynamicMethodsArrayCopy):NULL;
141-
142-
HELPER_METHOD_FRAME_END();
143-
}
144-
FCIMPLEND
145-
146-
// 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.
147-
FCIMPL3(VOID, ExceptionNative::SaveStackTracesFromDeepCopy, Object* pExceptionObjectUnsafe, Object *pStackTraceUnsafe, Object *pDynamicMethodsUnsafe);
148-
{
149-
CONTRACTL
150-
{
151-
FCALL_CHECK;
152-
}
153-
CONTRACTL_END;
154-
155-
ASSERT(pExceptionObjectUnsafe != NULL);
156-
157-
struct
158-
{
159-
StackTraceArray stackTrace;
160-
EXCEPTIONREF refException;
161-
PTRARRAYREF dynamicMethodsArray; // Object array of Managed Resolvers
162-
} gc;
163-
gc.refException = NULL;
164-
gc.dynamicMethodsArray = NULL;
165-
166-
// GC protect the array reference
167-
HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
168-
169-
// Get the exception object reference
170-
gc.refException = (EXCEPTIONREF)(ObjectToOBJECTREF(pExceptionObjectUnsafe));
171-
172-
if (pStackTraceUnsafe != NULL)
173-
{
174-
// Copy the stacktrace
175-
StackTraceArray stackTraceArray((I1ARRAYREF)ObjectToOBJECTREF(pStackTraceUnsafe));
176-
gc.stackTrace.Swap(stackTraceArray);
177-
}
178-
179-
gc.dynamicMethodsArray = NULL;
180-
if (pDynamicMethodsUnsafe != NULL)
181-
{
182-
gc.dynamicMethodsArray = (PTRARRAYREF)ObjectToOBJECTREF(pDynamicMethodsUnsafe);
183-
}
184-
185-
// If there is no stacktrace, then there cannot be any dynamic method array. Thus,
186-
// save stacktrace only when we have it.
187-
if (gc.stackTrace.Size() > 0)
188-
{
189-
// Save the stacktrace details in the exception under a lock
190-
gc.refException->SetStackTrace(gc.stackTrace.Get(), gc.dynamicMethodsArray);
111+
gc.result = gc.keepAliveArray;
191112
}
192113
else
193114
{
194-
gc.refException->SetStackTrace(NULL, NULL);
115+
gc.result = gc.stackTrace.Get();
195116
}
196-
117+
197118
HELPER_METHOD_FRAME_END();
119+
120+
return OBJECTREFToObject(gc.result);
198121
}
199122
FCIMPLEND
200123

src/coreclr/vm/comutilnative.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,7 @@ class ExceptionNative
4242
static FCDECL1(FC_BOOL_RET, IsTransient, INT32 hresult);
4343
static FCDECL3(StringObject *, StripFileInfo, Object *orefExcepUNSAFE, StringObject *orefStrUNSAFE, CLR_BOOL isRemoteStackTrace);
4444
static FCDECL0(VOID, PrepareForForeignExceptionRaise);
45-
static FCDECL3(VOID, GetStackTracesDeepCopy, Object* pExceptionObjectUnsafe, Object **pStackTraceUnsafe, Object **pDynamicMethodsUnsafe);
46-
static FCDECL3(VOID, SaveStackTracesFromDeepCopy, Object* pExceptionObjectUnsafe, Object *pStackTraceUnsafe, Object *pDynamicMethodsUnsafe);
47-
45+
static FCDECL1(Object *, GetFrozenStackTrace, Object* pExceptionObjectUnsafe);
4846

4947
#ifdef FEATURE_COMINTEROP
5048
// NOTE: caller cleans up any partially initialized BSTRs in pED

src/coreclr/vm/corelib.h

-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,6 @@ DEFINE_FIELD_U(_stackTrace, ExceptionObject, _stackTrace)
311311
DEFINE_FIELD_U(_watsonBuckets, ExceptionObject, _watsonBuckets)
312312
DEFINE_FIELD_U(_stackTraceString, ExceptionObject, _stackTraceString)
313313
DEFINE_FIELD_U(_remoteStackTraceString, ExceptionObject, _remoteStackTraceString)
314-
DEFINE_FIELD_U(_dynamicMethods, ExceptionObject, _dynamicMethods)
315314
DEFINE_FIELD_U(_source, ExceptionObject, _source)
316315
DEFINE_FIELD_U(_ipForWatsonBuckets,ExceptionObject, _ipForWatsonBuckets)
317316
DEFINE_FIELD_U(_xptrs, ExceptionObject, _xptrs)

src/coreclr/vm/debugdebugger.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1044,9 +1044,9 @@ void DebugStackTrace::GetStackFramesFromException(OBJECTREF * e,
10441044

10451045
// Now get the _stackTrace reference
10461046
StackTraceArray traceData;
1047-
EXCEPTIONREF(*e)->GetStackTrace(traceData, pDynamicMethodArray);
10481047

10491048
GCPROTECT_BEGIN(traceData);
1049+
EXCEPTIONREF(*e)->GetStackTrace(traceData, pDynamicMethodArray);
10501050
// The number of frame info elements in the stack trace info
10511051
pData->cElements = static_cast<int>(traceData.Size());
10521052

src/coreclr/vm/ecalllist.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,7 @@ FCFuncStart(gExceptionFuncs)
9494
FCFuncElement("IsImmutableAgileException", ExceptionNative::IsImmutableAgileException)
9595
FCFuncElement("GetMethodFromStackTrace", SystemNative::GetMethodFromStackTrace)
9696
FCFuncElement("PrepareForForeignExceptionRaise", ExceptionNative::PrepareForForeignExceptionRaise)
97-
FCFuncElement("GetStackTracesDeepCopy", ExceptionNative::GetStackTracesDeepCopy)
98-
FCFuncElement("SaveStackTracesFromDeepCopy", ExceptionNative::SaveStackTracesFromDeepCopy)
97+
FCFuncElement("GetFrozenStackTrace", ExceptionNative::GetFrozenStackTrace)
9998
FCFuncElement("GetExceptionCount", ExceptionNative::GetExceptionCount)
10099
FCFuncEnd()
101100

0 commit comments

Comments
 (0)