From 8e7ace7f9e398383c907967f5a098a5d03beeec7 Mon Sep 17 00:00:00 2001 From: Aaron R Robinson Date: Mon, 7 Mar 2022 15:19:43 -0500 Subject: [PATCH] Stubs for register/unregister GC reporting --- .../RuntimeHelpers.CoreCLR.cs | 28 +++++++ src/coreclr/vm/ecall.h | 7 ++ src/coreclr/vm/ecalllist.h | 2 + src/coreclr/vm/eetwain.cpp | 23 +++++- src/coreclr/vm/frames.cpp | 80 ++++++++++++++----- src/coreclr/vm/frames.h | 6 +- 6 files changed, 122 insertions(+), 24 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 0fa3632b0d8359..975a626a18f1cc 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -350,6 +350,34 @@ private static unsafe void DispatchTailCalls( } } } + +#pragma warning disable 0414 + // Type that represents a managed view of the unmanaged GCFrame + // data structure in coreclr. The type layouts between the two should match. + internal unsafe ref struct GCFrameRegistration + { + private nuint m_reserved1; + private nuint m_reserved2; + private void* m_pObjRefs; + private uint m_numObjRefs; + private int m_MaybeInterior; + + public GCFrameRegistration(void* allocation, uint elemCount, bool areByRefs = true) + { + m_reserved1 = 0; + m_reserved2 = 0; + m_pObjRefs = allocation; + m_numObjRefs = elemCount; + m_MaybeInterior = areByRefs ? 1 : 0; + } + } +#pragma warning restore 0414 + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern unsafe void RegisterForGCReporting(GCFrameRegistration* pRegistration); + + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern unsafe void UnregisterForGCReporting(GCFrameRegistration* pRegistration); } // Helper class to assist with unsafe pinning of arbitrary objects. // It's used by VM code. diff --git a/src/coreclr/vm/ecall.h b/src/coreclr/vm/ecall.h index 538227cf13d6a6..bc9d63ae467137 100644 --- a/src/coreclr/vm/ecall.h +++ b/src/coreclr/vm/ecall.h @@ -129,4 +129,11 @@ class ECall extern "C" FCDECL1(VOID, FCComCtor, LPVOID pV); +class GCReporting final +{ +public: + static FCDECL1(void, Register, GCFrame*); + static FCDECL1(void, Unregister, GCFrame*); +}; + #endif // _ECALL_H_ diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 08ab8e71c868a4..c46d834f3741a5 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -609,6 +609,8 @@ FCFuncStart(gRuntimeHelpers) FCFuncElement("TryEnsureSufficientExecutionStack", ReflectionInvocation::TryEnsureSufficientExecutionStack) FCFuncElement("AllocTailCallArgBuffer", TailCallHelp::AllocTailCallArgBuffer) FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo) + FCFuncElement("RegisterForGCReporting", GCReporting::Register) + FCFuncElement("UnregisterForGCReporting", GCReporting::Unregister) FCFuncEnd() FCFuncStart(gMngdFixedArrayMarshalerFuncs) diff --git a/src/coreclr/vm/eetwain.cpp b/src/coreclr/vm/eetwain.cpp index c2fef85d92b554..ef17779910fb7d 100644 --- a/src/coreclr/vm/eetwain.cpp +++ b/src/coreclr/vm/eetwain.cpp @@ -4,6 +4,7 @@ #include "common.h" +#include "ecall.h" #include "eetwain.h" #include "dbginterface.h" #include "gcenv.h" @@ -4412,7 +4413,27 @@ void promoteVarArgs(PTR_BYTE argsStart, PTR_VASigCookie varArgSig, GCCONTEXT* ct } } -INDEBUG(void* forceStack1;) +#ifndef DACCESS_COMPILE +FCIMPL1(void, GCReporting::Register, GCFrame* frame) +{ + FCALL_CONTRACT; + + // Construct a GCFrame. + _ASSERTE(frame != NULL); + frame->Push(GetThread()); +} +FCIMPLEND + +FCIMPL1(void, GCReporting::Unregister, GCFrame* frame) +{ + FCALL_CONTRACT; + + // Destroy the GCFrame. + _ASSERTE(frame != NULL); + frame->Pop(); +} +FCIMPLEND +#endif // !DACCESS_COMPILE #ifndef USE_GC_INFO_DECODER diff --git a/src/coreclr/vm/frames.cpp b/src/coreclr/vm/frames.cpp index 9377b4ec028b72..2f810f8cff98ee 100644 --- a/src/coreclr/vm/frames.cpp +++ b/src/coreclr/vm/frames.cpp @@ -391,7 +391,7 @@ VOID Frame::Push(Thread *pThread) // 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 + // with multiple Frames in coreclr.dll _ASSERTE((pThread->IsExecutingOnAltStack() || (m_Next == FRAME_TOP) || (PBYTE(m_Next) + (2 * GetOsPageSize())) > PBYTE(this)) && @@ -903,6 +903,7 @@ GCFrame::GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL may NOTHROW; GC_NOTRIGGER; MODE_COOPERATIVE; + PRECONDITION(pThread != NULL); } CONTRACTL_END; @@ -929,19 +930,67 @@ GCFrame::GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL may #endif // USE_CHECKED_OBJECTREFS +#ifdef _DEBUG + m_Next = NULL; + m_pCurThread = NULL; +#endif // _DEBUG + m_pObjRefs = pObjRefs; m_numObjRefs = numObjRefs; - m_pCurThread = pThread; m_MaybeInterior = maybeInterior; + Push(pThread); +} + +GCFrame::~GCFrame() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + PRECONDITION(m_pCurThread != NULL); + } + 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(); + } + + Pop(); + + if (!wasCoop) + { + m_pCurThread->EnablePreemptiveGC(); + } +} + +void GCFrame::Push(Thread* pThread) +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_COOPERATIVE; + PRECONDITION(pThread != NULL); + PRECONDITION(m_Next == NULL); + PRECONDITION(m_pCurThread == NULL); + } + CONTRACTL_END; + // Push the GC frame to the per-thread list m_Next = pThread->GetGCFrame(); + m_pCurThread = pThread; // 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. + // in which the 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 + // with multiple GCFrames in coreclr.dll _ASSERTE(((m_Next == NULL) || (PBYTE(m_Next) + (2 * GetOsPageSize())) > PBYTE(this)) && "Pushing a GCFrame out of order ?"); @@ -949,24 +998,18 @@ GCFrame::GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL may pThread->SetGCFrame(this); } -GCFrame::~GCFrame() +void GCFrame::Pop() { CONTRACTL { NOTHROW; GC_NOTRIGGER; - MODE_ANY; + MODE_COOPERATIVE; + PRECONDITION(m_Next != NULL); + PRECONDITION(m_pCurThread != NULL); } 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. // It also cancels the GC protection provided by the frame. @@ -981,12 +1024,8 @@ GCFrame::~GCFrame() for(UINT i = 0; i < m_numObjRefs; i++) Thread::ObjectRefNew(&m_pObjRefs[i]); // Unprotect them #endif - - if (!wasCoop) - { - m_pCurThread->EnablePreemptiveGC(); - } } +#endif // !DACCESS_COMPILE // // GCFrame Object Scanning @@ -995,9 +1034,6 @@ GCFrame::~GCFrame() // protected by the programmer explicitly protecting it in a GC Frame // via the GCPROTECTBEGIN / GCPROTECTEND facility... // - -#endif // !DACCESS_COMPILE - void GCFrame::GcScanRoots(promote_func *fn, ScanContext* sc) { WRAPPER_NO_CONTRACT; diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 82e57cbbb04017..38bbc80cce3035 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -2421,6 +2421,10 @@ class GCFrame GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL maybeInterior); ~GCFrame(); + // Push and pop this frame from the thread's stack. + void Push(Thread* pThread); + void Pop(); + #endif // DACCESS_COMPILE void GcScanRoots(promote_func *fn, ScanContext* sc); @@ -2446,9 +2450,9 @@ class GCFrame private: PTR_GCFrame m_Next; + PTR_Thread m_pCurThread; PTR_OBJECTREF m_pObjRefs; UINT m_numObjRefs; - PTR_Thread m_pCurThread; BOOL m_MaybeInterior; };