summaryrefslogtreecommitdiff
path: root/src/vm/gcenv.ee.cpp
diff options
context:
space:
mode:
authorSean Gillespie <segilles@microsoft.com>2017-05-17 15:07:34 -0700
committerSean Gillespie <segilles@microsoft.com>2017-06-01 10:19:59 -0700
commit1a183684b1ecf63ece8a2fd80173f083c0deea52 (patch)
tree907b31b417732768b28e80adfb4d920497f0d3f0 /src/vm/gcenv.ee.cpp
parentdde63bc1aa39aabae77fb89aad583483965c523e (diff)
downloadcoreclr-1a183684b1ecf63ece8a2fd80173f083c0deea52.tar.gz
coreclr-1a183684b1ecf63ece8a2fd80173f083c0deea52.tar.bz2
coreclr-1a183684b1ecf63ece8a2fd80173f083c0deea52.zip
[Local GC] Scaffolding for loading a standalone GC (#11242)
* Configure the build system to build a CoreCLR capable of loading a standalone GC * Proto-implementation of dynamic GC loading * Build the GC with the VM's CMakeLists when doing a non-standalone build of the GC * [Local GC] Introduce a new feature define, FEATURE_STANDALONE_GC_ONLY, to be used by the CI to explicitly test local GC dynamic loading code paths * Fix the FEATURE_STANDALONE_GC_ONLY build for unix linkers * Rebase against master * Code review feedback: use the existing Unix exports file
Diffstat (limited to 'src/vm/gcenv.ee.cpp')
-rw-r--r--src/vm/gcenv.ee.cpp415
1 files changed, 0 insertions, 415 deletions
diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp
index 63c4ffea10..8be0b29d58 100644
--- a/src/vm/gcenv.ee.cpp
+++ b/src/vm/gcenv.ee.cpp
@@ -11,33 +11,6 @@
*
*/
-#include "common.h"
-
-#include "gcenv.h"
-
-#ifdef FEATURE_STANDALONE_GC
-#include "gcenv.ee.h"
-#else
-#include "../gc/env/gcenv.ee.h"
-#endif // FEATURE_STANDALONE_GC
-
-#include "threadsuspend.h"
-
-#ifdef FEATURE_COMINTEROP
-#include "runtimecallablewrapper.h"
-#include "rcwwalker.h"
-#include "comcallablewrapper.h"
-#endif // FEATURE_COMINTEROP
-
-// the method table for the WeakReference class
-extern MethodTable* pWeakReferenceMT;
-
-// The canonical method table for WeakReference<T>
-extern MethodTable* pWeakReferenceOfTCanonMT;
-
-// Finalizes a weak reference directly.
-extern void FinalizeWeakReference(Object* obj);
-
void GCToEEInterface::SuspendEE(SUSPEND_REASON reason)
{
WRAPPER_NO_CONTRACT;
@@ -57,394 +30,6 @@ void GCToEEInterface::RestartEE(bool bFinishedGC)
ThreadSuspend::RestartEE(bFinishedGC, TRUE);
}
-/*
- * GcEnumObject()
- *
- * This is the JIT compiler (or any remote code manager)
- * GC enumeration callback
- */
-
-void GcEnumObject(LPVOID pData, OBJECTREF *pObj, uint32_t flags)
-{
- Object ** ppObj = (Object **)pObj;
- GCCONTEXT * pCtx = (GCCONTEXT *) pData;
-
- // Since we may be asynchronously walking another thread's stack,
- // check (frequently) for stack-buffer-overrun corruptions after
- // any long operation
- if (pCtx->cf != NULL)
- pCtx->cf->CheckGSCookies();
-
- //
- // Sanity check that the flags contain only these three values
- //
- assert((flags & ~(GC_CALL_INTERIOR|GC_CALL_PINNED|GC_CALL_CHECK_APP_DOMAIN)) == 0);
-
- // for interior pointers, we optimize the case in which
- // it points into the current threads stack area
- //
- if (flags & GC_CALL_INTERIOR)
- PromoteCarefully(pCtx->f, ppObj, pCtx->sc, flags);
- else
- (pCtx->f)(ppObj, pCtx->sc, flags);
-}
-
-//-----------------------------------------------------------------------------
-void GcReportLoaderAllocator(promote_func* fn, ScanContext* sc, LoaderAllocator *pLoaderAllocator)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- if (pLoaderAllocator != NULL && pLoaderAllocator->IsCollectible())
- {
- Object *refCollectionObject = OBJECTREFToObject(pLoaderAllocator->GetExposedObject());
-
-#ifdef _DEBUG
- Object *oldObj = refCollectionObject;
-#endif
-
- _ASSERTE(refCollectionObject != NULL);
- fn(&refCollectionObject, sc, CHECK_APP_DOMAIN);
-
- // We are reporting the location of a local variable, assert it doesn't change.
- _ASSERTE(oldObj == refCollectionObject);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Determine whether we should report the generic parameter context
-//
-// This is meant to detect the situation where a ThreadAbortException is raised
-// in the prolog of a managed method, before the location for the generics
-// context has been initialized; when such a TAE is raised, we are open to a
-// race with the GC (e.g. while creating the managed object for the TAE).
-// The GC would cause a stack walk, and if we report the stack location for
-// the generic param context at this time we'd crash.
-// The long term solution is to avoid raising TAEs in any non-GC safe points,
-// and to additionally ensure that we do not expose the runtime to TAE
-// starvation.
-inline bool SafeToReportGenericParamContext(CrawlFrame* pCF)
-{
- LIMITED_METHOD_CONTRACT;
- if (!pCF->IsFrameless() || !(pCF->IsActiveFrame() || pCF->IsInterrupted()))
- {
- return true;
- }
-
-#ifndef USE_GC_INFO_DECODER
-
- ICodeManager * pEECM = pCF->GetCodeManager();
- if (pEECM != NULL && pEECM->IsInPrologOrEpilog(pCF->GetRelOffset(), pCF->GetGCInfoToken(), NULL))
- {
- return false;
- }
-
-#else // USE_GC_INFO_DECODER
-
- GcInfoDecoder gcInfoDecoder(pCF->GetGCInfoToken(),
- DECODE_PROLOG_LENGTH);
- UINT32 prologLength = gcInfoDecoder.GetPrologSize();
- if (pCF->GetRelOffset() < prologLength)
- {
- return false;
- }
-
-#endif // USE_GC_INFO_DECODER
-
- return true;
-}
-
-#if defined(WIN64EXCEPTIONS)
-
-struct FindFirstInterruptiblePointState
-{
- unsigned offs;
- unsigned endOffs;
- unsigned returnOffs;
-};
-
-bool FindFirstInterruptiblePointStateCB(
- UINT32 startOffset,
- UINT32 stopOffset,
- LPVOID hCallback)
-{
- FindFirstInterruptiblePointState* pState = (FindFirstInterruptiblePointState*)hCallback;
-
- _ASSERTE(startOffset < stopOffset);
- _ASSERTE(pState->offs < pState->endOffs);
-
- if (stopOffset <= pState->offs)
- {
- // The range ends before the requested offset.
- return false;
- }
-
- // The offset is in the range.
- if (startOffset <= pState->offs &&
- pState->offs < stopOffset)
- {
- pState->returnOffs = pState->offs;
- return true;
- }
-
- // The range is completely after the desired offset. We use the range start offset, if
- // it comes before the given endOffs. We assume that the callback is called with ranges
- // in increasing order, so earlier ones are reported before later ones. That is, if we
- // get to this case, it will be the closest interruptible range after the requested
- // offset.
-
- _ASSERTE(pState->offs < startOffset);
- if (startOffset < pState->endOffs)
- {
- pState->returnOffs = startOffset;
- return true;
- }
-
- return false;
-}
-
-// Find the first interruptible point in the range [offs .. endOffs) (the beginning of the range is inclusive,
-// the end is exclusive). Return -1 if no such point exists.
-unsigned FindFirstInterruptiblePoint(CrawlFrame* pCF, unsigned offs, unsigned endOffs)
-{
-#ifdef USE_GC_INFO_DECODER
- GCInfoToken gcInfoToken = pCF->GetGCInfoToken();
- GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_FOR_RANGES_CALLBACK);
-
- FindFirstInterruptiblePointState state;
- state.offs = offs;
- state.endOffs = endOffs;
- state.returnOffs = -1;
-
- gcInfoDecoder.EnumerateInterruptibleRanges(&FindFirstInterruptiblePointStateCB, &state);
-
- return state.returnOffs;
-#else
- PORTABILITY_ASSERT("FindFirstInterruptiblePoint");
- return -1;
-#endif // USE_GC_INFO_DECODER
-}
-
-#endif // WIN64EXCEPTIONS
-
-//-----------------------------------------------------------------------------
-StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData)
-{
- //
- // KEEP IN SYNC WITH DacStackReferenceWalker::Callback in debug\daccess\daccess.cpp
- //
-
- Frame *pFrame;
- GCCONTEXT *gcctx = (GCCONTEXT*) pData;
-
-#if CHECK_APP_DOMAIN_LEAKS
- gcctx->sc->pCurrentDomain = pCF->GetAppDomain();
-#endif //CHECK_APP_DOMAIN_LEAKS
-
-#ifdef FEATURE_APPDOMAIN_RESOURCE_MONITORING
- if (g_fEnableARM)
- {
- gcctx->sc->pCurrentDomain = pCF->GetAppDomain();
- }
-#endif //FEATURE_APPDOMAIN_RESOURCE_MONITORING
-
- MethodDesc *pMD = pCF->GetFunction();
-
-#ifdef GC_PROFILING
- gcctx->sc->pMD = pMD;
-#endif //GC_PROFILING
-
- // Clear it on exit so that we never have a stale CrawlFrame
- ResetPointerHolder<CrawlFrame*> rph(&gcctx->cf);
- // put it somewhere so that GcEnumObject can get to it.
- gcctx->cf = pCF;
-
- bool fReportGCReferences = true;
-#if defined(WIN64EXCEPTIONS)
- // We may have unwound this crawlFrame and thus, shouldn't report the invalid
- // references it may contain.
- fReportGCReferences = pCF->ShouldCrawlframeReportGCReferences();
-#endif // defined(WIN64EXCEPTIONS)
-
- if (fReportGCReferences)
- {
- if (pCF->IsFrameless())
- {
- ICodeManager * pCM = pCF->GetCodeManager();
- _ASSERTE(pCM != NULL);
-
- unsigned flags = pCF->GetCodeManagerFlags();
-
- #ifdef _TARGET_X86_
- STRESS_LOG3(LF_GCROOTS, LL_INFO1000, "Scanning Frameless method %pM EIP = %p &EIP = %p\n",
- pMD, GetControlPC(pCF->GetRegisterSet()), pCF->GetRegisterSet()->PCTAddr);
- #else
- STRESS_LOG2(LF_GCROOTS, LL_INFO1000, "Scanning Frameless method %pM ControlPC = %p\n",
- pMD, GetControlPC(pCF->GetRegisterSet()));
- #endif
-
- _ASSERTE(pMD != 0);
-
- #ifdef _DEBUG
- LOG((LF_GCROOTS, LL_INFO1000, "Scanning Frame for method %s:%s\n",
- pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName));
- #endif // _DEBUG
-
- DWORD relOffsetOverride = NO_OVERRIDE_OFFSET;
-#if defined(WIN64EXCEPTIONS) && defined(USE_GC_INFO_DECODER)
- if (pCF->ShouldParentToFuncletUseUnwindTargetLocationForGCReporting())
- {
- GCInfoToken gcInfoToken = pCF->GetGCInfoToken();
- GcInfoDecoder _gcInfoDecoder(
- gcInfoToken,
- DECODE_CODE_LENGTH
- );
-
- if(_gcInfoDecoder.WantsReportOnlyLeaf())
- {
- // We're in a special case of unwinding from a funclet, and resuming execution in
- // another catch funclet associated with same parent function. We need to report roots.
- // Reporting at the original throw site gives incorrect liveness information. We choose to
- // report the liveness information at the first interruptible instruction of the catch funclet
- // that we are going to execute. We also only report stack slots, since no registers can be
- // live at the first instruction of a handler, except the catch object, which the VM protects
- // specially. If the catch funclet has not interruptible point, we fall back and just report
- // what we used to: at the original throw instruction. This might lead to bad GC behavior
- // if the liveness is not correct.
- const EE_ILEXCEPTION_CLAUSE& ehClauseForCatch = pCF->GetEHClauseForCatch();
- relOffsetOverride = FindFirstInterruptiblePoint(pCF, ehClauseForCatch.HandlerStartPC,
- ehClauseForCatch.HandlerEndPC);
- _ASSERTE(relOffsetOverride != NO_OVERRIDE_OFFSET);
-
- STRESS_LOG3(LF_GCROOTS, LL_INFO1000, "Setting override offset = %u for method %pM ControlPC = %p\n",
- relOffsetOverride, pMD, GetControlPC(pCF->GetRegisterSet()));
- }
-
- }
-#endif // WIN64EXCEPTIONS && USE_GC_INFO_DECODER
-
- pCM->EnumGcRefs(pCF->GetRegisterSet(),
- pCF->GetCodeInfo(),
- flags,
- GcEnumObject,
- pData,
- relOffsetOverride);
-
- }
- else
- {
- Frame * pFrame = pCF->GetFrame();
-
- STRESS_LOG3(LF_GCROOTS, LL_INFO1000,
- "Scanning ExplicitFrame %p AssocMethod = %pM frameVTable = %pV\n",
- pFrame, pFrame->GetFunction(), *((void**) pFrame));
- pFrame->GcScanRoots( gcctx->f, gcctx->sc);
- }
- }
-
-
- // If we're executing a LCG dynamic method then we must promote the associated resolver to ensure it
- // doesn't get collected and yank the method code out from under us).
-
- // Be careful to only promote the reference -- we can also be called to relocate the reference and
- // that can lead to all sorts of problems since we could be racing for the relocation with the long
- // weak handle we recover the reference from. Promoting the reference is enough, the handle in the
- // reference will be relocated properly as long as we keep it alive till the end of the collection
- // as long as the reference is actually maintained by the long weak handle.
- if (pMD && gcctx->sc->promotion)
- {
- BOOL fMaybeCollectibleMethod = TRUE;
-
- // If this is a frameless method then the jitmanager can answer the question of whether
- // or not this is LCG simply by looking at the heap where the code lives, however there
- // is also the prestub case where we need to explicitly look at the MD for stuff that isn't
- // ngen'd
- if (pCF->IsFrameless())
- {
- fMaybeCollectibleMethod = ExecutionManager::IsCollectibleMethod(pCF->GetMethodToken());
- }
-
- if (fMaybeCollectibleMethod && pMD->IsLCGMethod())
- {
- Object *refResolver = OBJECTREFToObject(pMD->AsDynamicMethodDesc()->GetLCGMethodResolver()->GetManagedResolver());
-#ifdef _DEBUG
- Object *oldObj = refResolver;
-#endif
- _ASSERTE(refResolver != NULL);
- (*gcctx->f)(&refResolver, gcctx->sc, CHECK_APP_DOMAIN);
- _ASSERTE(!pMD->IsSharedByGenericInstantiations());
-
- // We are reporting the location of a local variable, assert it doesn't change.
- _ASSERTE(oldObj == refResolver);
- }
- else
- {
- if (fMaybeCollectibleMethod)
- {
- GcReportLoaderAllocator(gcctx->f, gcctx->sc, pMD->GetLoaderAllocator());
- }
-
- if (fReportGCReferences)
- {
- GenericParamContextType paramContextType = GENERIC_PARAM_CONTEXT_NONE;
-
- if (pCF->IsFrameless())
- {
- // We need to grab the Context Type here because there are cases where the MethodDesc
- // is shared, and thus indicates there should be an instantion argument, but the JIT
- // was still allowed to optimize it away and we won't grab it below because we're not
- // reporting any references from this frame.
- paramContextType = pCF->GetCodeManager()->GetParamContextType(pCF->GetRegisterSet(), pCF->GetCodeInfo());
- }
- else
- {
- if (pMD->RequiresInstMethodDescArg())
- paramContextType = GENERIC_PARAM_CONTEXT_METHODDESC;
- else if (pMD->RequiresInstMethodTableArg())
- paramContextType = GENERIC_PARAM_CONTEXT_METHODTABLE;
- }
-
- if (SafeToReportGenericParamContext(pCF))
- {
- // Handle the case where the method is a static shared generic method and we need to keep the type
- // of the generic parameters alive
- if (paramContextType == GENERIC_PARAM_CONTEXT_METHODDESC)
- {
- MethodDesc *pMDReal = dac_cast<PTR_MethodDesc>(pCF->GetParamTypeArg());
- _ASSERTE((pMDReal != NULL) || !pCF->IsFrameless());
- if (pMDReal != NULL)
- {
- GcReportLoaderAllocator(gcctx->f, gcctx->sc, pMDReal->GetLoaderAllocator());
- }
- }
- else if (paramContextType == GENERIC_PARAM_CONTEXT_METHODTABLE)
- {
- MethodTable *pMTReal = dac_cast<PTR_MethodTable>(pCF->GetParamTypeArg());
- _ASSERTE((pMTReal != NULL) || !pCF->IsFrameless());
- if (pMTReal != NULL)
- {
- GcReportLoaderAllocator(gcctx->f, gcctx->sc, pMTReal->GetLoaderAllocator());
- }
- }
- }
- }
- }
- }
-
- // Since we may be asynchronously walking another thread's stack,
- // check (frequently) for stack-buffer-overrun corruptions after
- // any long operation
- pCF->CheckGSCookies();
-
- return SWA_CONTINUE;
-}
-
VOID GCToEEInterface::SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2)
{
CONTRACTL