VPTR_CLASS(DebuggerU2MCatchHandlerFrame)
VPTR_CLASS(FaultingExceptionFrame)
VPTR_CLASS(FuncEvalFrame)
-VPTR_CLASS(GCFrame)
VPTR_CLASS(HelperMethodFrame)
VPTR_CLASS(HelperMethodFrame_1OBJ)
VPTR_CLASS(HelperMethodFrame_2OBJ)
typedef VPTR(class DebugInfoManager) PTR_DebugInfoManager;
typedef DPTR(class FieldDesc) PTR_FieldDesc;
typedef VPTR(class Frame) PTR_Frame;
+typedef VPTR(class GCFrame) PTR_GCFrame;
typedef VPTR(class ICodeManager) PTR_ICodeManager;
typedef VPTR(class IJitManager) PTR_IJitManager;
typedef DPTR(class InstMethodHashTable) PTR_InstMethodHashTable;
typedef VPTR(class DebugInfoManager) PTR_DebugInfoManager;
typedef DPTR(class FieldDesc) PTR_FieldDesc;
typedef VPTR(class Frame) PTR_Frame;
+typedef VPTR(class GCFrame) PTR_GCFrame;
typedef VPTR(class ICodeManager) PTR_ICodeManager;
typedef VPTR(class IJitManager) PTR_IJitManager;
typedef VPTR(struct IUnknown) PTR_IUnknown;
m_pLimitFrame = m_pThread->GetFrame();
}
-void ExceptionTracker::ResetInitialExplicitFrame()
-{
- LIMITED_METHOD_CONTRACT;
-
- m_pInitialExplicitFrame = m_pThread->GetFrame();
-}
-
//
// static
void ExceptionTracker::ResumeExecution(
return m_pInitialExplicitFrame;
}
- void ResetInitialExplicitFrame();
-
#ifdef FEATURE_PAL
// Reset the range of explicit frames, the limit frame and the scanned
// stack range before unwinding a sequence of native frames. These frames
{
#ifdef FEATURE_EH_FUNCLETS
m_pCurrentTracker = NULL;
-#else
- m_ppBottomFrameDuringUnwind = NULL;
#endif // FEATURE_EH_FUNCLETS
m_flag = TEF_None;
extern StackWalkAction COMPlusUnwindCallback(CrawlFrame *pCf, ThrowCallbackType *pData);
-typedef DPTR(PTR_Frame) PTR_PTR_Frame;
-
//
// This class serves as a forwarding and abstraction layer for the EH subsystem.
// Since we have two different implementations, this class is needed to unify
}
#else
ExInfo m_currentExInfo;
- PTR_PTR_Frame m_ppBottomFrameDuringUnwind;
public:
PTR_ExInfo GetCurrentExceptionTracker()
{
LIMITED_METHOD_CONTRACT;
return PTR_ExInfo(PTR_HOST_MEMBER_TADDR(ThreadExceptionState, this, m_currentExInfo));
}
-
- PTR_PTR_Frame GetPtrToBottomFrameDuringUnwind()
- {
- return m_ppBottomFrameDuringUnwind;
- }
-
- void SetPtrToBottomFrameDuringUnwind(PTR_PTR_Frame framePtr)
- {
- m_ppBottomFrameDuringUnwind = framePtr;
- }
-
#endif
#ifdef FEATURE_CORRUPTING_EXCEPTIONS
if (vptr == HelperMethodFrame::GetMethodFrameVPtr())
return true;
- if (vptr == GCFrame::GetMethodFrameVPtr())
- return true;
-
if (vptr == DebuggerSecurityCodeMarkFrame::GetMethodFrameVPtr())
return true;
Init(pThread, pObjRefs, numObjRefs, maybeInterior);
}
+GCFrame::~GCFrame()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Do a manual switch to the GC cooperative mode instead of using the GCX_COOP_THREAD_EXISTS
+ // macro so that this function isn't slowed down by having to deal with FS:0 chain on x86 Windows.
+ BOOL wasCoop = m_pCurThread->PreemptiveGCDisabled();
+ if (!wasCoop)
+ {
+ m_pCurThread->DisablePreemptiveGC();
+ }
+
+ // When the frame is destroyed, make sure it is no longer in the
+ // frame chain managed by the Thread.
+
+ Pop();
+
+ if (!wasCoop)
+ {
+ m_pCurThread->EnablePreemptiveGC();
+ }
+}
+
void GCFrame::Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior)
{
CONTRACTL
m_pCurThread = pThread;
m_MaybeInterior = maybeInterior;
- Frame::Push(m_pCurThread);
+ Push(m_pCurThread);
}
-
//
// GCFrame Object Scanning
//
#ifndef DACCESS_COMPILE
-//--------------------------------------------------------------------
-// Pops the GCFrame and cancels the GC protection.
-//--------------------------------------------------------------------
-VOID GCFrame::Pop()
-{
- WRAPPER_NO_CONTRACT;
- Frame::Pop(m_pCurThread);
-#ifdef _DEBUG
- m_pCurThread->EnableStressHeap();
- for(UINT i = 0; i < m_numObjRefs; i++)
- Thread::ObjectRefNew(&m_pObjRefs[i]); // Unprotect them
-#endif
-}
-
-#ifndef CROSSGEN_COMPILE
-// GCFrame destructor removes the GCFrame from the current thread's explicit frame list.
-// This prevents issues in functions that have HELPER_METHOD_FRAME_BEGIN / END around
-// GCPROTECT_BEGIN / END and where the C++ compiler places some local variables over
-// the stack location of the GCFrame local variable after the variable goes out of scope.
-GCFrame::~GCFrame()
+void GCFrame::Push(Thread *pThread)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
- MODE_ANY;
+ MODE_COOPERATIVE;
}
CONTRACTL_END;
- if (m_Next != NULL)
- {
- // Do a manual switch to the GC cooperative mode instead of using the GCX_COOP_THREAD_EXISTS
- // macro so that this function isn't slowed down by having to deal with FS:0 chain on x86 Windows.
- BOOL wasCoop = m_pCurThread->PreemptiveGCDisabled();
- if (!wasCoop)
- {
- m_pCurThread->DisablePreemptiveGC();
- }
-
- // When the frame is destroyed, make sure it is no longer in the
- // frame chain managed by the Thread.
-
- Pop();
+ m_Next = pThread->GetGCFrame();
-#ifndef FEATURE_PAL
-
- PTR_Frame frame = NULL;
-
-#ifdef FEATURE_EH_FUNCLETS
- PTR_ExceptionTracker pCurrentTracker = m_pCurThread->GetExceptionState()->GetCurrentExceptionTracker();
- if (pCurrentTracker != NULL)
- {
- frame = pCurrentTracker->GetInitialExplicitFrame();
- }
-#else
- PTR_PTR_Frame ptrToInitialFrame = m_pCurThread->GetExceptionState()->GetPtrToBottomFrameDuringUnwind();
- if (ptrToInitialFrame != NULL)
- {
- frame = *ptrToInitialFrame;
- if (frame == this)
- {
- // The current frame that was just popped was the bottom frame used
- // as an initial frame to scan stack frames.
- // Update the bottom frame pointer to point to the first valid frame.
- *ptrToInitialFrame = m_pCurThread->m_pFrame;
- }
- }
-#endif // FEATURE_EH_FUNCLETS
-
- if (frame != NULL)
- {
- // There is an initial explicit frame, so we need to scan the explicit frame chain starting at
- // that frame to see if the current frame that is being destroyed was on the chain.
-
- while ((frame != FRAME_TOP) && (frame != this))
- {
- PTR_Frame nextFrame = frame->PtrNextFrame();
- if (nextFrame == this)
- {
- // Repair frame chain from the initial explicit frame to the current frame,
- // skipping the current GCFrame that was destroyed
- frame->m_Next = m_pCurThread->m_pFrame;
- break;
- }
- frame = nextFrame;
- _ASSERTE(frame != NULL);
- }
- }
-#endif // !FEATURE_PAL
+ // GetOsPageSize() is used to relax the assert for cases where two Frames are
+ // declared in the same source function. We cannot predict the order
+ // in which the C compiler will lay them out in the stack frame.
+ // So GetOsPageSize() is a guess of the maximum stack frame size of any method
+ // with multiple Frames in mscorwks.dll
+ _ASSERTE(((m_Next == NULL) ||
+ (PBYTE(m_Next) + (2 * GetOsPageSize())) > PBYTE(this)) &&
+ "Pushing a GCFrame out of order ?");
- if (!wasCoop)
- {
- m_pCurThread->EnablePreemptiveGC();
- }
- }
+ pThread->SetGCFrame(this);
}
-ExceptionFilterFrame::~ExceptionFilterFrame()
+//--------------------------------------------------------------------
+// Pops the GCFrame and cancels the GC protection.
+//--------------------------------------------------------------------
+VOID GCFrame::Pop()
{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
+ WRAPPER_NO_CONTRACT;
- if (m_Next != NULL)
- {
- GCX_COOP();
- // When the frame is destroyed, make sure it is no longer in the
- // frame chain managed by the Thread.
- Pop();
- }
-}
+ _ASSERTE(m_pCurThread->GetGCFrame() == this && "Popping a GCFrame out of order ?");
+
+ m_pCurThread->SetGCFrame(m_Next);
+ m_Next = NULL;
-#endif // !CROSSGEN_COMPILE
+#ifdef _DEBUG
+ m_pCurThread->EnableStressHeap();
+ for(UINT i = 0; i < m_numObjRefs; i++)
+ Thread::ObjectRefNew(&m_pObjRefs[i]); // Unprotect them
+#endif
+}
#ifdef FEATURE_INTERPRETER
// Methods of IntepreterFrame.
ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE ();
IsProtectedByGCFrameStruct d = {ppObjectRef, 0};
GetThread()->StackWalkFrames(IsProtectedByGCFrameStackWalkFramesCallback, &d);
+
+ GCFrame* pGCFrame = GetThread()->GetGCFrame();
+ while (pGCFrame != NULL)
+ {
+ if (pGCFrame->Protects(ppObjectRef)) {
+ d.count++;
+ }
+
+ pGCFrame = pGCFrame->PtrNextFrame();
+ }
+
if (d.count > 1) {
_ASSERTE(!"Multiple GCFrames protecting the same pointer. This will cause GC corruption!");
}
// Frame - the root class. There are no actual instances
// | of Frames.
// |
-// +-GCFrame - this frame doesn't represent a method call.
-// | it's sole purpose is to let the EE gc-protect
-// | object references that it is manipulating.
-// |
// +- FaultingExceptionFrame - this frame was placed on a method which faulted
// | to save additional state information
// |
#if !defined(_TARGET_X86_)
FRAME_TYPE_NAME(StubHelperFrame)
#endif
-FRAME_TYPE_NAME(GCFrame)
#ifdef FEATURE_INTERPRETER
FRAME_TYPE_NAME(InterpreterFrame)
#endif // FEATURE_INTERPRETER
class Frame : public FrameBase
{
friend class CheckAsmOffsets;
- friend class GCFrame;
#ifdef DACCESS_COMPILE
friend void Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
#endif // FEATURE_COMINTEROP
-
//------------------------------------------------------------------------
// This frame protects object references for the EE's convenience.
// This frame type actually is created from C++.
+// There is a chain of GCFrames on a Thread, separate from the
+// explicit frames derived from the Frame class.
//------------------------------------------------------------------------
-class GCFrame : public Frame
+class GCFrame
{
- VPTR_VTABLE_CLASS(GCFrame, Frame)
-
public:
//--------------------------------------------------------------------
- // This constructor pushes a new GCFrame on the frame chain.
+ // This constructor pushes a new GCFrame on the GC frame chain.
//--------------------------------------------------------------------
#ifndef DACCESS_COMPILE
GCFrame() {
GCFrame(OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
-#endif
+#ifndef CROSSGEN_COMPILE
+ ~GCFrame();
+#endif // CROSSGEN_COMPILE
+
+#endif // DACCESS_COMPILE
+
void Init(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior);
+ void Push(Thread *pThread);
//--------------------------------------------------------------------
// Pops the GCFrame and cancels the GC protection. Also
//--------------------------------------------------------------------
VOID Pop();
- virtual void GcScanRoots(promote_func *fn, ScanContext* sc);
+ void GcScanRoots(promote_func *fn, ScanContext* sc);
#ifdef _DEBUG
- virtual BOOL Protects(OBJECTREF *ppORef)
+ BOOL Protects(OBJECTREF *ppORef)
{
LIMITED_METHOD_CONTRACT;
for (UINT i = 0; i < m_numObjRefs; i++) {
}
#endif
-#if defined(_DEBUG_IMPL)
- const char* GetFrameTypeName() { LIMITED_METHOD_CONTRACT; return "GCFrame"; }
-#endif
+ PTR_GCFrame PtrNextFrame()
+ {
+ WRAPPER_NO_CONTRACT;
+ return m_Next;
+ }
private:
+ PTR_GCFrame m_Next;
PTR_OBJECTREF m_pObjRefs;
UINT m_numObjRefs;
PTR_Thread m_pCurThread;
BOOL m_MaybeInterior;
-
- // Keep as last entry in class
- DEFINE_VTABLE_GETTER(GCFrame)
-
-#if !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
- ~GCFrame();
-#endif
};
#ifdef FEATURE_INTERPRETER
*m_pShadowSP |= ICodeManager::SHADOW_SP_FILTER_DONE;
}
}
-
-#ifndef CROSSGEN_COMPILE
- ~ExceptionFilterFrame();
-#endif
-
#endif
private:
// Keep as last entry in class
- DEFINE_VTABLE_GETTER_AND_CTOR(ExceptionFilterFrame)
+ DEFINE_VTABLE_GETTER_AND_CTOR_AND_DTOR(ExceptionFilterFrame)
};
#ifdef _DEBUG
#endif /*_PREFAST_ */
#define GCPROTECT_BEGIN(ObjRefStruct) do { \
- FrameWithCookie<GCFrame> __gcframe( \
+ GCFrame __gcframe( \
(OBJECTREF*)&(ObjRefStruct), \
sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
FALSE); \
if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
#define GCPROTECT_BEGIN_THREAD(pThread, ObjRefStruct) do { \
- FrameWithCookie<GCFrame> __gcframe( \
+ GCFrame __gcframe( \
pThread, \
(OBJECTREF*)&(ObjRefStruct), \
sizeof(ObjRefStruct)/sizeof(OBJECTREF), \
if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
#define GCPROTECT_ARRAY_BEGIN(ObjRefArray,cnt) do { \
- FrameWithCookie<GCFrame> __gcframe( \
+ GCFrame __gcframe( \
(OBJECTREF*)&(ObjRefArray), \
cnt * sizeof(ObjRefArray) / sizeof(OBJECTREF), \
FALSE); \
/* work around Wsizeof-pointer-div warning as we */ \
/* mean to capture pointer or object size */ \
UINT subjectSize = sizeof(ObjRefStruct); \
- FrameWithCookie<GCFrame> __gcframe( \
+ GCFrame __gcframe( \
(OBJECTREF*)&(ObjRefStruct), \
subjectSize/sizeof(OBJECTREF), \
TRUE); \
if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
#define GCPROTECT_BEGININTERIOR_ARRAY(ObjRefArray,cnt) do { \
- FrameWithCookie<GCFrame> __gcframe( \
+ GCFrame __gcframe( \
(OBJECTREF*)&(ObjRefArray), \
cnt, \
TRUE); \
#endif // !_TARGET_AMD64_ || !PLATFORM_UNIX
}
- FrameWithCookie<GCFrame> gcFrame;
+ GCFrame gcFrame;
if (numberOfRegs != 0)
{
_ASSERTE(sizeof(OBJECTREF) == sizeof(DWORD_PTR));
_ASSERTE(!"Not expected multi reg return with pointers.");
#endif // !_TARGET_AMD64_ || !PLATFORM_UNIX
}
-
- gcFrame.Pop();
}
#if !defined(USE_REDIRECT_FOR_GCSTRESS)
IsGCSpecialThread() ||
(GetThread() == ThreadSuspend::GetSuspensionThread() && ThreadStore::HoldingThreadStore()));
- pThread->SetHasPromotedBytes();
-
Frame* pTopFrame = pThread->GetFrame();
Object ** topStack = (Object **)pTopFrame;
if ((pTopFrame != ((Frame*)-1))
#endif // defined(FEATURE_EH_FUNCLETS)
pThread->StackWalkFrames( GcStackCrawlCallBack, &gcctx, flagsStackWalk);
}
+
+ GCFrame* pGCFrame = pThread->GetGCFrame();
+ while (pGCFrame != NULL)
+ {
+ pGCFrame->GcScanRoots(fn, sc);
+ pGCFrame = pGCFrame->PtrNextFrame();
+ }
}
void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc)
LOG((LF_EH|LF_CORDB, LL_INFO100, "\t\t: pFunc is 0x%X\n", tct.pFunc));
LOG((LF_EH|LF_CORDB, LL_INFO100, "\t\t: pStack is 0x%X\n", tct.pStack));
- _ASSERTE(pExState->GetPtrToBottomFrameDuringUnwind() == NULL);
- pExState->SetPtrToBottomFrameDuringUnwind(&tct.pBottomFrame);
-
CallRtlUnwindSafe(pEstablisherFrame, RtlUnwindCallback, pExceptionRecord, 0);
- _ASSERTE(pExState->GetPtrToBottomFrameDuringUnwind() == &tct.pBottomFrame);
- _ASSERTE(*pExState->GetPtrToBottomFrameDuringUnwind() == tct.pBottomFrame);
- pExState->SetPtrToBottomFrameDuringUnwind(NULL);
-
ExInfo* pExInfo = pThread->GetExceptionState()->GetCurrentExceptionTracker();
if (pExInfo->m_ValidInterceptionContext)
{
LOG((LF_EH, LL_INFO100, "CPFH_RealFirstPassHandler: handler found: %s\n", tct.pFunc->m_pszDebugMethodName));
- ThreadExceptionState* pExState = pThread->GetExceptionState();
- _ASSERTE(pExState->GetPtrToBottomFrameDuringUnwind() == NULL);
- pExState->SetPtrToBottomFrameDuringUnwind(&tct.pBottomFrame);
-
CallRtlUnwindSafe(pEstablisherFrame, RtlUnwindCallback, pExceptionRecord, 0);
// on x86 at least, RtlUnwind always returns
- _ASSERTE(pExState->GetPtrToBottomFrameDuringUnwind() == &tct.pBottomFrame);
- _ASSERTE(*pExState->GetPtrToBottomFrameDuringUnwind() == tct.pBottomFrame);
- pExState->SetPtrToBottomFrameDuringUnwind(NULL);
-
// The CallRtlUnwindSafe could have popped the explicit frame that the tct.pBottomFrame points to (UMThunkPrestubHandler
// does that). In such case, the tct.pBottomFrame needs to be updated to point to the first valid explicit frame.
Frame* frame = pThread->GetFrame();
#define NO_MAPPING ((BYTE) -1)
#define GCPROTECT_BEGIN_VARIANTDATA(/*VARIANTDATA*/vd) do { \
- FrameWithCookie<GCFrame> __gcframe(vd.GetObjRefPtr(), 1, FALSE); \
+ GCFrame __gcframe(vd.GetObjRefPtr(), 1, FALSE); \
/* work around unreachable code warning */ \
if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT);
#define GCPROTECT_END_VARIANTDATA() \
DEBUG_ASSURE_NO_RETURN_END(GCPROTECT); } \
- __gcframe.Pop(); } while(0)
+ } while(0)
//Mapping from CVType to type handle. Used for conversion between the two internally.
CONTRACTL_END;
m_pFrame = FRAME_TOP;
+ m_pGCFrame = NULL;
m_fPreemptiveGCDisabled = 0;
propSet.Call_RetArgSlot(pNewArgs);
}
-void Thread::SetHasPromotedBytes ()
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- m_fPromoted = TRUE;
-
- _ASSERTE(GCHeapUtilities::IsGCInProgress() && IsGCThread ());
-
- if (!m_fPreemptiveGCDisabled)
- {
- if (FRAME_TOP == GetFrame())
- m_fPromoted = FALSE;
- }
-}
-
BOOL ThreadStore::HoldingThreadStore(Thread *pThread)
{
CONTRACTL {
// or StressLog which may waits on a spinlock. It is unsafe to suspend a thread while it
// is in this state.
Volatile<LONG> m_dwForbidSuspendThread;
+
public:
static void IncForbidSuspendThread()
{
SUPPORTS_DAC;
-#ifndef DACCESS_COMPILE
#ifdef _DEBUG_IMPL
WRAPPER_NO_CONTRACT;
if (this == GetThreadNULLOk())
curSP = (void *)GetCurrentSP();
_ASSERTE((curSP <= m_pFrame && m_pFrame < m_CacheStackBase) || m_pFrame == (Frame*) -1);
}
-#else
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(!"NYI");
#endif
-#endif // #ifndef DACCESS_COMPILE
+
return m_pFrame;
}
//--------------------------------------------------------------
+ // Returns innermost active GCFrame.
+ //--------------------------------------------------------------
+ PTR_GCFrame GetGCFrame()
+ {
+ SUPPORTS_DAC;
+
+#ifdef _DEBUG_IMPL
+ WRAPPER_NO_CONTRACT;
+ if (this == GetThreadNULLOk())
+ {
+ void* curSP;
+ curSP = (void *)GetCurrentSP();
+ _ASSERTE((m_pGCFrame == NULL) || (curSP <= m_pGCFrame && m_pGCFrame < m_CacheStackBase));
+ }
+#endif
+
+ return m_pGCFrame;
+ }
+
+ //--------------------------------------------------------------
// Replaces innermost active Frames.
//--------------------------------------------------------------
#ifndef DACCESS_COMPILE
#endif
;
#endif
+
+ //--------------------------------------------------------------
+ // Replaces innermost active GCFrame.
+ //--------------------------------------------------------------
+#ifndef DACCESS_COMPILE
+ void SetGCFrame(GCFrame *pFrame)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pGCFrame = pFrame;
+ }
+#endif
+
inline Frame* FindFrame(SIZE_T StackPointer);
bool DetectHandleILStubsForDebugger();
LONG m_TraceCallCount;
- //-----------------------------------------------------------
- // Bytes promoted on this thread since the last GC?
- //-----------------------------------------------------------
- DWORD m_fPromoted;
-public:
- void SetHasPromotedBytes ();
- DWORD GetHasPromotedBytes ()
- {
- LIMITED_METHOD_CONTRACT;
- return m_fPromoted;
- }
-
private:
//-----------------------------------------------------------
// Last exception to be thrown.
void SetGCSpecial(bool fGCSpecial);
private:
+
+ PTR_GCFrame m_pGCFrame; // The topmost GC Frame
+
#ifndef FEATURE_PAL
WORD m_wCPUGroup;
DWORD_PTR m_pAffinityMask;