diff options
Diffstat (limited to 'src/gc/gc.h')
-rw-r--r-- | src/gc/gc.h | 571 |
1 files changed, 104 insertions, 467 deletions
diff --git a/src/gc/gc.h b/src/gc/gc.h index 14c6baee83..b7f1e956b6 100644 --- a/src/gc/gc.h +++ b/src/gc/gc.h @@ -14,9 +14,24 @@ Module Name: #ifndef __GC_H #define __GC_H -#ifdef PROFILING_SUPPORTED -#define GC_PROFILING //Turn on profiling -#endif // PROFILING_SUPPORTED +#ifdef Sleep +// This is a funny workaround for the fact that "common.h" defines Sleep to be +// Dont_Use_Sleep, with the hope of causing linker errors whenever someone tries to use sleep. +// +// However, GCToOSInterface defines a function called Sleep, which (due to this define) becomes +// "Dont_Use_Sleep", which the GC in turn happily uses. The symbol that GCToOSInterface actually +// exported was called "GCToOSInterface::Dont_Use_Sleep". While we progress in making the GC standalone, +// we'll need to break the dependency on common.h (the VM header) and this problem will become moot. +#undef Sleep +#endif // Sleep + +#include "gcinterface.h" +#include "env/gcenv.os.h" +#include "env/gcenv.ee.h" + +#ifdef FEATURE_STANDALONE_GC +#include "gcenv.ee.standalone.inl" +#endif // FEATURE_STANDALONE_GC /* * Promotion Function Prototypes @@ -26,19 +41,6 @@ typedef void enum_func (Object*); // callback functions for heap walkers typedef void object_callback_func(void * pvContext, void * pvDataLoc); -// stub type to abstract a heap segment -struct gc_heap_segment_stub; -typedef gc_heap_segment_stub *segment_handle; - -struct segment_info -{ - void * pvMem; // base of the allocation, not the first object (must add ibFirstObject) - size_t ibFirstObject; // offset to the base of the first object in the segment - size_t ibAllocated; // limit of allocated memory in the segment (>= firstobject) - size_t ibCommit; // limit of committed memory in the segment (>= alllocated) - size_t ibReserved; // limit of reserved memory in the segment (>= commit) -}; - /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ /* If you modify failure_get_memory and */ /* oom_reason be sure to make the corresponding */ @@ -80,6 +82,24 @@ enum oom_reason oom_unproductive_full_gc = 6 }; +// TODO : it would be easier to make this an ORed value +enum gc_reason +{ + reason_alloc_soh = 0, + reason_induced = 1, + reason_lowmemory = 2, + reason_empty = 3, + reason_alloc_loh = 4, + reason_oos_soh = 5, + reason_oos_loh = 6, + reason_induced_noforce = 7, // it's an induced GC and doesn't have to be blocking. + reason_gcstress = 8, // this turns into reason_induced & gc_mechanisms.stress_induced = true + reason_lowmemory_blocking = 9, + reason_induced_compacting = 10, + reason_lowmemory_host = 11, + reason_max +}; + struct oom_history { oom_reason reason; @@ -97,28 +117,16 @@ struct oom_history class CObjectHeader; class Object; -class GCHeap; +class IGCHeapInternal; /* misc defines */ #define LARGE_OBJECT_SIZE ((size_t)(85000)) -GPTR_DECL(GCHeap, g_pGCHeap); - #ifdef GC_CONFIG_DRIVEN #define MAX_GLOBAL_GC_MECHANISMS_COUNT 6 GARY_DECL(size_t, gc_global_mechanisms, MAX_GLOBAL_GC_MECHANISMS_COUNT); #endif //GC_CONFIG_DRIVEN -#ifndef DACCESS_COMPILE -extern "C" { -#endif -GPTR_DECL(uint8_t,g_lowest_address); -GPTR_DECL(uint8_t,g_highest_address); -GPTR_DECL(uint32_t,g_card_table); -#ifndef DACCESS_COMPILE -} -#endif - #ifdef DACCESS_COMPILE class DacHeapWalker; #endif @@ -127,137 +135,28 @@ class DacHeapWalker; #define _LOGALLOC #endif -#ifdef WRITE_BARRIER_CHECK -//always defined, but should be 0 in Server GC -extern uint8_t* g_GCShadow; -extern uint8_t* g_GCShadowEnd; -// saves the g_lowest_address in between GCs to verify the consistency of the shadow segment -extern uint8_t* g_shadow_lowest_address; -#endif - #define MP_LOCKS -extern "C" uint8_t* g_ephemeral_low; -extern "C" uint8_t* g_ephemeral_high; +extern "C" uint32_t* g_gc_card_table; +extern "C" uint8_t* g_gc_lowest_address; +extern "C" uint8_t* g_gc_highest_address; +extern "C" uint8_t* g_gc_ephemeral_low; +extern "C" uint8_t* g_gc_ephemeral_high; namespace WKS { - ::GCHeap* CreateGCHeap(); + ::IGCHeapInternal* CreateGCHeap(); class GCHeap; class gc_heap; } #if defined(FEATURE_SVR_GC) namespace SVR { - ::GCHeap* CreateGCHeap(); + ::IGCHeapInternal* CreateGCHeap(); class GCHeap; class gc_heap; } #endif // defined(FEATURE_SVR_GC) -/* - * Ephemeral Garbage Collected Heap Interface - */ - - -struct alloc_context -{ - friend class WKS::gc_heap; -#if defined(FEATURE_SVR_GC) - friend class SVR::gc_heap; - friend class SVR::GCHeap; -#endif // defined(FEATURE_SVR_GC) - friend struct ClassDumpInfo; - - uint8_t* alloc_ptr; - uint8_t* alloc_limit; - int64_t alloc_bytes; //Number of bytes allocated on SOH by this context - int64_t alloc_bytes_loh; //Number of bytes allocated on LOH by this context -#if defined(FEATURE_SVR_GC) - SVR::GCHeap* alloc_heap; - SVR::GCHeap* home_heap; -#endif // defined(FEATURE_SVR_GC) - int alloc_count; -public: - - void init() - { - LIMITED_METHOD_CONTRACT; - - alloc_ptr = 0; - alloc_limit = 0; - alloc_bytes = 0; - alloc_bytes_loh = 0; -#if defined(FEATURE_SVR_GC) - alloc_heap = 0; - home_heap = 0; -#endif // defined(FEATURE_SVR_GC) - alloc_count = 0; - } -}; - -struct ScanContext -{ - Thread* thread_under_crawl; - int thread_number; - uintptr_t stack_limit; // Lowest point on the thread stack that the scanning logic is permitted to read - BOOL promotion; //TRUE: Promotion, FALSE: Relocation. - BOOL concurrent; //TRUE: concurrent scanning -#if CHECK_APP_DOMAIN_LEAKS || defined (FEATURE_APPDOMAIN_RESOURCE_MONITORING) || defined (DACCESS_COMPILE) - AppDomain *pCurrentDomain; -#endif //CHECK_APP_DOMAIN_LEAKS || FEATURE_APPDOMAIN_RESOURCE_MONITORING || DACCESS_COMPILE - -#ifndef FEATURE_REDHAWK -#if defined(GC_PROFILING) || defined (DACCESS_COMPILE) - MethodDesc *pMD; -#endif //GC_PROFILING || DACCESS_COMPILE -#endif // FEATURE_REDHAWK -#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) - EtwGCRootKind dwEtwRootKind; -#endif // GC_PROFILING || FEATURE_EVENT_TRACE - - ScanContext() - { - LIMITED_METHOD_CONTRACT; - - thread_under_crawl = 0; - thread_number = -1; - stack_limit = 0; - promotion = FALSE; - concurrent = FALSE; -#ifdef GC_PROFILING - pMD = NULL; -#endif //GC_PROFILING -#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) - dwEtwRootKind = kEtwGCRootKindOther; -#endif // GC_PROFILING || FEATURE_EVENT_TRACE - } -}; - -typedef BOOL (* walk_fn)(Object*, void*); -typedef void (* gen_walk_fn)(void *context, int generation, uint8_t *range_start, uint8_t * range_end, uint8_t *range_reserved); - -#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) -struct ProfilingScanContext : ScanContext -{ - BOOL fProfilerPinned; - void * pvEtwContext; - void *pHeapId; - - ProfilingScanContext(BOOL fProfilerPinnedParam) : ScanContext() - { - LIMITED_METHOD_CONTRACT; - - pHeapId = NULL; - fProfilerPinned = fProfilerPinnedParam; - pvEtwContext = NULL; -#ifdef FEATURE_CONSERVATIVE_GC - // To not confuse GCScan::GcScanRoots - promotion = g_pConfig->GetGCConservative(); -#endif - } -}; -#endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) - #ifdef STRESS_HEAP #define IN_STRESS_HEAP(x) x #define STRESS_HEAP_ARG(x) ,x @@ -266,7 +165,6 @@ struct ProfilingScanContext : ScanContext #define STRESS_HEAP_ARG(x) #endif // STRESS_HEAP - //dynamic data interface struct gc_counters { @@ -275,51 +173,6 @@ struct gc_counters size_t collection_count; }; -// !!!!!!!!!!!!!!!!!!!!!!! -// make sure you change the def in bcl\system\gc.cs -// if you change this! -enum collection_mode -{ - collection_non_blocking = 0x00000001, - collection_blocking = 0x00000002, - collection_optimized = 0x00000004, - collection_compacting = 0x00000008 -#ifdef STRESS_HEAP - , collection_gcstress = 0x80000000 -#endif // STRESS_HEAP -}; - -// !!!!!!!!!!!!!!!!!!!!!!! -// make sure you change the def in bcl\system\gc.cs -// if you change this! -enum wait_full_gc_status -{ - wait_full_gc_success = 0, - wait_full_gc_failed = 1, - wait_full_gc_cancelled = 2, - wait_full_gc_timeout = 3, - wait_full_gc_na = 4 -}; - -// !!!!!!!!!!!!!!!!!!!!!!! -// make sure you change the def in bcl\system\gc.cs -// if you change this! -enum start_no_gc_region_status -{ - start_no_gc_success = 0, - start_no_gc_no_memory = 1, - start_no_gc_too_large = 2, - start_no_gc_in_progress = 3 -}; - -enum end_no_gc_region_status -{ - end_no_gc_success = 0, - end_no_gc_not_in_progress = 1, - end_no_gc_induced = 2, - end_no_gc_alloc_exceeded = 3 -}; - enum bgc_state { bgc_not_in_process = 0, @@ -352,321 +205,82 @@ void record_changed_seg (uint8_t* start, uint8_t* end, void record_global_mechanism (int mech_index); #endif //GC_CONFIG_DRIVEN -//constants for the flags parameter to the gc call back - -#define GC_CALL_INTERIOR 0x1 -#define GC_CALL_PINNED 0x2 -#define GC_CALL_CHECK_APP_DOMAIN 0x4 - -//flags for GCHeap::Alloc(...) -#define GC_ALLOC_FINALIZE 0x1 -#define GC_ALLOC_CONTAINS_REF 0x2 -#define GC_ALLOC_ALIGN8_BIAS 0x4 -#define GC_ALLOC_ALIGN8 0x8 - -class GCHeap { - friend struct ::_DacGlobals; -#ifdef DACCESS_COMPILE - friend class ClrDataAccess; -#endif - -public: - - virtual ~GCHeap() {} - - static GCHeap *GetGCHeap() +struct alloc_context : gc_alloc_context +{ +#ifdef FEATURE_SVR_GC + inline SVR::GCHeap* get_alloc_heap() { - LIMITED_METHOD_CONTRACT; - - _ASSERTE(g_pGCHeap != NULL); - return g_pGCHeap; + return static_cast<SVR::GCHeap*>(gc_reserved_1); } -#ifndef DACCESS_COMPILE - static BOOL IsGCInProgress(BOOL bConsiderGCStart = FALSE) + inline void set_alloc_heap(SVR::GCHeap* heap) { - WRAPPER_NO_CONTRACT; - - return (IsGCHeapInitialized() ? GetGCHeap()->IsGCInProgressHelper(bConsiderGCStart) : false); - } -#endif - - static BOOL IsGCHeapInitialized() - { - LIMITED_METHOD_CONTRACT; - - return (g_pGCHeap != NULL); + gc_reserved_1 = heap; } - static void WaitForGCCompletion(BOOL bConsiderGCStart = FALSE) + inline SVR::GCHeap* get_home_heap() { - WRAPPER_NO_CONTRACT; - - if (IsGCHeapInitialized()) - GetGCHeap()->WaitUntilGCComplete(bConsiderGCStart); - } - - // The runtime needs to know whether we're using workstation or server GC - // long before the GCHeap is created. So IsServerHeap cannot be a virtual - // method on GCHeap. Instead we make it a static method and initialize - // gcHeapType before any of the calls to IsServerHeap. Note that this also - // has the advantage of getting the answer without an indirection - // (virtual call), which is important for perf critical codepaths. - - #ifndef DACCESS_COMPILE - static void InitializeHeapType(bool bServerHeap) - { - LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_SVR_GC - gcHeapType = bServerHeap ? GC_HEAP_SVR : GC_HEAP_WKS; -#ifdef WRITE_BARRIER_CHECK - if (gcHeapType == GC_HEAP_SVR) - { - g_GCShadow = 0; - g_GCShadowEnd = 0; - } -#endif -#else // FEATURE_SVR_GC - UNREFERENCED_PARAMETER(bServerHeap); - CONSISTENCY_CHECK(bServerHeap == false); -#endif // FEATURE_SVR_GC - } - #endif - - static BOOL IsValidSegmentSize(size_t cbSize) - { - //Must be aligned on a Mb and greater than 4Mb - return (((cbSize & (1024*1024-1)) ==0) && (cbSize >> 22)); + return static_cast<SVR::GCHeap*>(gc_reserved_2); } - static BOOL IsValidGen0MaxSize(size_t cbSize) + inline void set_home_heap(SVR::GCHeap* heap) { - return (cbSize >= 64*1024); + gc_reserved_2 = heap; } - - inline static bool IsServerHeap() - { - LIMITED_METHOD_CONTRACT; -#ifdef FEATURE_SVR_GC - _ASSERTE(gcHeapType != GC_HEAP_INVALID); - return (gcHeapType == GC_HEAP_SVR); -#else // FEATURE_SVR_GC - return false; #endif // FEATURE_SVR_GC - } +}; - inline static bool UseAllocationContexts() - { - WRAPPER_NO_CONTRACT; -#ifdef FEATURE_REDHAWK - // SIMPLIFY: only use allocation contexts - return true; -#else -#if defined(_TARGET_ARM_) || defined(FEATURE_PAL) - return true; -#else - return ((IsServerHeap() ? true : (g_SystemInfo.dwNumberOfProcessors >= 2))); +class IGCHeapInternal : public IGCHeap { + friend struct ::_DacGlobals; +#ifdef DACCESS_COMPILE + friend class ClrDataAccess; #endif -#endif - } - - inline static bool MarkShouldCompeteForStatics() - { - WRAPPER_NO_CONTRACT; - - return IsServerHeap() && g_SystemInfo.dwNumberOfProcessors >= 2; - } -#ifndef DACCESS_COMPILE - static GCHeap * CreateGCHeap() - { - WRAPPER_NO_CONTRACT; - - GCHeap * pGCHeap; - -#if defined(FEATURE_SVR_GC) - pGCHeap = (IsServerHeap() ? SVR::CreateGCHeap() : WKS::CreateGCHeap()); -#else - pGCHeap = WKS::CreateGCHeap(); -#endif // defined(FEATURE_SVR_GC) - - g_pGCHeap = pGCHeap; - return pGCHeap; - } -#endif // DACCESS_COMPILE +public: -private: - typedef enum - { - GC_HEAP_INVALID = 0, - GC_HEAP_WKS = 1, - GC_HEAP_SVR = 2 - } GC_HEAP_TYPE; - -#ifdef FEATURE_SVR_GC - SVAL_DECL(uint32_t,gcHeapType); -#endif // FEATURE_SVR_GC + virtual ~IGCHeapInternal() {} -public: - // TODO Synchronization, should be moved out - virtual BOOL IsGCInProgressHelper (BOOL bConsiderGCStart = FALSE) = 0; - virtual uint32_t WaitUntilGCComplete (BOOL bConsiderGCStart = FALSE) = 0; - virtual void SetGCInProgress(BOOL fInProgress) = 0; - virtual CLREventStatic * GetWaitForGCEvent() = 0; - - virtual void SetFinalizationRun (Object* obj) = 0; - virtual Object* GetNextFinalizable() = 0; - virtual size_t GetNumberOfFinalizable() = 0; - - virtual void SetFinalizeQueueForShutdown(BOOL fHasLock) = 0; - virtual BOOL FinalizeAppDomain(AppDomain *pDomain, BOOL fRunFinalizers) = 0; - virtual BOOL ShouldRestartFinalizerWatchDog() = 0; - - //wait for concurrent GC to finish - virtual void WaitUntilConcurrentGCComplete () = 0; // Use in managed threads -#ifndef DACCESS_COMPILE - virtual HRESULT WaitUntilConcurrentGCCompleteAsync(int millisecondsTimeout) = 0; // Use in native threads. TRUE if succeed. FALSE if failed or timeout -#endif - virtual BOOL IsConcurrentGCInProgress() = 0; - - // Enable/disable concurrent GC - virtual void TemporaryEnableConcurrentGC() = 0; - virtual void TemporaryDisableConcurrentGC() = 0; - virtual BOOL IsConcurrentGCEnabled() = 0; - - virtual void FixAllocContext (alloc_context* acontext, BOOL lockp, void* arg, void *heap) = 0; - virtual Object* Alloc (alloc_context* acontext, size_t size, uint32_t flags) = 0; - - // This is safe to call only when EE is suspended. - virtual Object* GetContainingObject(void *pInteriorPtr) = 0; - - // TODO Should be folded into constructor - virtual HRESULT Initialize () = 0; - - virtual HRESULT GarbageCollect (int generation = -1, BOOL low_memory_p=FALSE, int mode = collection_blocking) = 0; - virtual Object* Alloc (size_t size, uint32_t flags) = 0; -#ifdef FEATURE_64BIT_ALIGNMENT - virtual Object* AllocAlign8 (size_t size, uint32_t flags) = 0; - virtual Object* AllocAlign8 (alloc_context* acontext, size_t size, uint32_t flags) = 0; private: - virtual Object* AllocAlign8Common (void* hp, alloc_context* acontext, size_t size, uint32_t flags) = 0; + virtual Object* AllocAlign8Common (void* hp, alloc_context* acontext, size_t size, uint32_t flags) = 0; public: -#endif // FEATURE_64BIT_ALIGNMENT - virtual Object* AllocLHeap (size_t size, uint32_t flags) = 0; - virtual void SetReservedVMLimit (size_t vmlimit) = 0; - virtual void SetCardsAfterBulkCopy( Object**, size_t ) = 0; -#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) - virtual void WalkObject (Object* obj, walk_fn fn, void* context) = 0; -#endif //defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) - - virtual bool IsThreadUsingAllocationContextHeap(alloc_context* acontext, int thread_number) = 0; virtual int GetNumberOfHeaps () = 0; virtual int GetHomeHeapNumber () = 0; - - virtual int CollectionCount (int generation, int get_bgc_fgc_count = 0) = 0; - - // Finalizer queue stuff (should stay) - virtual bool RegisterForFinalization (int gen, Object* obj) = 0; - - // General queries to the GC - virtual BOOL IsPromoted (Object *object) = 0; - virtual unsigned WhichGeneration (Object* object) = 0; - virtual BOOL IsEphemeral (Object* object) = 0; - virtual BOOL IsHeapPointer (void* object, BOOL small_heap_only = FALSE) = 0; - - virtual unsigned GetCondemnedGeneration() = 0; - virtual int GetGcLatencyMode() = 0; - virtual int SetGcLatencyMode(int newLatencyMode) = 0; - - virtual int GetLOHCompactionMode() = 0; - virtual void SetLOHCompactionMode(int newLOHCompactionyMode) = 0; - - virtual BOOL RegisterForFullGCNotification(uint32_t gen2Percentage, - uint32_t lohPercentage) = 0; - virtual BOOL CancelFullGCNotification() = 0; - virtual int WaitForFullGCApproach(int millisecondsTimeout) = 0; - virtual int WaitForFullGCComplete(int millisecondsTimeout) = 0; - - virtual int StartNoGCRegion(uint64_t totalSize, BOOL lohSizeKnown, uint64_t lohSize, BOOL disallowFullBlockingGC) = 0; - virtual int EndNoGCRegion() = 0; + virtual size_t GetPromotedBytes(int heap_index) = 0; - virtual BOOL IsObjectInFixedHeap(Object *pObj) = 0; - virtual size_t GetTotalBytesInUse () = 0; - virtual size_t GetCurrentObjSize() = 0; - virtual size_t GetLastGCStartTime(int generation) = 0; - virtual size_t GetLastGCDuration(int generation) = 0; - virtual size_t GetNow() = 0; - virtual unsigned GetGcCount() = 0; - virtual void TraceGCSegments() = 0; + unsigned GetMaxGeneration() + { + return IGCHeap::maxGeneration; + } - virtual void PublishObject(uint8_t* obj) = 0; + BOOL IsValidSegmentSize(size_t cbSize) + { + //Must be aligned on a Mb and greater than 4Mb + return (((cbSize & (1024*1024-1)) ==0) && (cbSize >> 22)); + } - // static if since restricting for all heaps is fine - virtual size_t GetValidSegmentSize(BOOL large_seg = FALSE) = 0; + BOOL IsValidGen0MaxSize(size_t cbSize) + { + return (cbSize >= 64*1024); + } - static BOOL IsLargeObject(MethodTable *mt) { + BOOL IsLargeObject(MethodTable *mt) + { WRAPPER_NO_CONTRACT; return mt->GetBaseSize() >= LARGE_OBJECT_SIZE; } - static unsigned GetMaxGeneration() { - LIMITED_METHOD_DAC_CONTRACT; - return max_generation; - } - - virtual size_t GetPromotedBytes(int heap_index) = 0; - -private: - enum { - max_generation = 2, - }; - -public: - -#ifdef FEATURE_BASICFREEZE - // frozen segment management functions - virtual segment_handle RegisterFrozenSegment(segment_info *pseginfo) = 0; - virtual void UnregisterFrozenSegment(segment_handle seg) = 0; -#endif //FEATURE_BASICFREEZE - - // debug support -#ifndef FEATURE_REDHAWK // Redhawk forces relocation a different way -#ifdef STRESS_HEAP - //return TRUE if GC actually happens, otherwise FALSE - virtual BOOL StressHeap(alloc_context * acontext = 0) = 0; -#endif -#endif // FEATURE_REDHAWK -#ifdef VERIFY_HEAP - virtual void ValidateObjectMember (Object *obj) = 0; -#endif - -#if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) - virtual void DescrGenerationsToProfiler (gen_walk_fn fn, void *context) = 0; -#endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE) - protected: -#ifdef VERIFY_HEAP public: - // Return NULL if can't find next object. When EE is not suspended, - // the result is not accurate: if the input arg is in gen0, the function could - // return zeroed out memory as next object - virtual Object * NextObj (Object * object) = 0; -#ifdef FEATURE_BASICFREEZE +#if defined(FEATURE_BASICFREEZE) && defined(VERIFY_HEAP) // Return TRUE if object lives in frozen segment virtual BOOL IsInFrozenSegment (Object * object) = 0; -#endif //FEATURE_BASICFREEZE -#endif //VERIFY_HEAP +#endif // defined(FEATURE_BASICFREEZE) && defined(VERIFY_HEAP) }; -extern VOLATILE(int32_t) m_GCLock; - // Go through and touch (read) each page straddled by a memory block. void TouchPages(void * pStart, size_t cb); -// For low memory notification from host -extern int32_t g_bLowMemoryFromHost; - #ifdef WRITE_BARRIER_CHECK void updateGCShadow(Object** ptr, Object* val); #endif @@ -677,4 +291,27 @@ extern MethodTable *pWeakReferenceMT; extern MethodTable *pWeakReferenceOfTCanonMT; extern void FinalizeWeakReference(Object * obj); +// The single GC heap instance, shared with the VM. +extern IGCHeapInternal* g_theGCHeap; + +#ifndef DACCESS_COMPILE +inline BOOL IsGCInProgress(bool bConsiderGCStart = FALSE) +{ + WRAPPER_NO_CONTRACT; + + return g_theGCHeap != nullptr ? g_theGCHeap->IsGCInProgressHelper(bConsiderGCStart) : false; +} +#endif // DACCESS_COMPILE + +inline BOOL IsServerHeap() +{ + LIMITED_METHOD_CONTRACT; +#ifdef FEATURE_SVR_GC + _ASSERTE(IGCHeap::gcHeapType != IGCHeap::GC_HEAP_INVALID); + return (IGCHeap::gcHeapType == IGCHeap::GC_HEAP_SVR); +#else // FEATURE_SVR_GC + return false; +#endif // FEATURE_SVR_GC +} + #endif // __GC_H |