Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/vm/ecall.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_
2 changes: 2 additions & 0 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 22 additions & 1 deletion src/coreclr/vm/eetwain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "common.h"

#include "ecall.h"
#include "eetwain.h"
#include "dbginterface.h"
#include "gcenv.h"
Expand Down Expand Up @@ -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

Expand Down
80 changes: 58 additions & 22 deletions src/coreclr/vm/frames.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) &&
Expand Down Expand Up @@ -903,6 +903,7 @@ GCFrame::GCFrame(Thread *pThread, OBJECTREF *pObjRefs, UINT numObjRefs, BOOL may
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
PRECONDITION(pThread != NULL);
}
CONTRACTL_END;

Expand All @@ -929,44 +930,86 @@ 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 ?");

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.
Expand All @@ -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
Expand All @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/vm/frames.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;
};

Expand Down