// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. #ifndef GCIMPL_H_ #define GCIMPL_H_ #define CLREvent CLREventStatic #ifdef SERVER_GC #define MULTIPLE_HEAPS 1 #endif // SERVER_GC #ifdef MULTIPLE_HEAPS #define PER_HEAP #else //MULTIPLE_HEAPS #define PER_HEAP static #endif // MULTIPLE_HEAPS #define PER_HEAP_ISOLATED static #if defined(WRITE_BARRIER_CHECK) && !defined (MULTIPLE_HEAPS) void initGCShadow(); void deleteGCShadow(); void checkGCWriteBarrier(); #else inline void initGCShadow() {} inline void deleteGCShadow() {} inline void checkGCWriteBarrier() {} #endif void GCProfileWalkHeap(); class gc_heap; class CFinalize; class GCHeap : public IGCHeapInternal { protected: #ifdef MULTIPLE_HEAPS gc_heap* pGenGCHeap; #else #define pGenGCHeap ((gc_heap*)0) #endif //MULTIPLE_HEAPS friend class CFinalize; friend class gc_heap; friend struct ::alloc_context; friend void EnterAllocLock(); friend void LeaveAllocLock(); friend void ProfScanRootsHelper(Object** object, ScanContext *pSC, uint32_t dwFlags); friend void GCProfileWalkHeap(); public: //In order to keep gc.cpp cleaner, ugly EE specific code is relegated to methods. static void UpdatePreGCCounters(); static void UpdatePostGCCounters(); public: GCHeap(){}; ~GCHeap(){}; /* BaseGCHeap Methods*/ PER_HEAP_ISOLATED HRESULT Shutdown (); size_t GetTotalBytesInUse (); // Gets the amount of bytes objects currently occupy on the GC heap. size_t GetCurrentObjSize(); size_t GetLastGCStartTime(int generation); size_t GetLastGCDuration(int generation); size_t GetNow(); void DiagTraceGCSegments (); void PublishObject(uint8_t* obj); BOOL IsGCInProgressHelper (BOOL bConsiderGCStart = FALSE); uint32_t WaitUntilGCComplete (BOOL bConsiderGCStart = FALSE); void SetGCInProgress(BOOL fInProgress); CLREvent * GetWaitForGCEvent(); HRESULT Initialize (); //flags can be GC_ALLOC_CONTAINS_REF GC_ALLOC_FINALIZE Object* Alloc (size_t size, uint32_t flags); Object* AllocAlign8 (size_t size, uint32_t flags); Object* AllocAlign8 (gc_alloc_context* acontext, size_t size, uint32_t flags); private: Object* AllocAlign8Common (void* hp, alloc_context* acontext, size_t size, uint32_t flags); public: Object* AllocLHeap (size_t size, uint32_t flags); Object* Alloc (gc_alloc_context* acontext, size_t size, uint32_t flags); void FixAllocContext (gc_alloc_context* acontext, BOOL lockp, void* arg, void *heap); Object* GetContainingObject(void *pInteriorPtr); #ifdef MULTIPLE_HEAPS static void AssignHeap (alloc_context* acontext); static GCHeap* GetHeap (int); #endif //MULTIPLE_HEAPS int GetHomeHeapNumber (); bool IsThreadUsingAllocationContextHeap(gc_alloc_context* acontext, int thread_number); int GetNumberOfHeaps (); void HideAllocContext(alloc_context*); void RevealAllocContext(alloc_context*); BOOL IsObjectInFixedHeap(Object *pObj); HRESULT GarbageCollect (int generation = -1, BOOL low_memory_p=FALSE, int mode=collection_blocking); //// // GC callback functions // Check if an argument is promoted (ONLY CALL DURING // THE PROMOTIONSGRANTED CALLBACK.) BOOL IsPromoted (Object *object); size_t GetPromotedBytes (int heap_index); int CollectionCount (int generation, int get_bgc_fgc_count = 0); // promote an object PER_HEAP_ISOLATED void Promote (Object** object, ScanContext* sc, uint32_t flags=0); // Find the relocation address for an object PER_HEAP_ISOLATED void Relocate (Object** object, ScanContext* sc, uint32_t flags=0); HRESULT Init (size_t heapSize); //Register an object for finalization bool RegisterForFinalization (int gen, Object* obj); //Unregister an object for finalization void SetFinalizationRun (Object* obj); //returns the generation number of an object (not valid during relocation) unsigned WhichGeneration (Object* object); // returns TRUE is the object is ephemeral BOOL IsEphemeral (Object* object); BOOL IsHeapPointer (void* object, BOOL small_heap_only = FALSE); void ValidateObjectMember (Object *obj); PER_HEAP size_t ApproxTotalBytesInUse(BOOL small_heap_only = FALSE); PER_HEAP size_t ApproxFreeBytes(); unsigned GetCondemnedGeneration(); int GetGcLatencyMode(); int SetGcLatencyMode(int newLatencyMode); int GetLOHCompactionMode(); void SetLOHCompactionMode(int newLOHCompactionyMode); BOOL RegisterForFullGCNotification(uint32_t gen2Percentage, uint32_t lohPercentage); BOOL CancelFullGCNotification(); int WaitForFullGCApproach(int millisecondsTimeout); int WaitForFullGCComplete(int millisecondsTimeout); int StartNoGCRegion(uint64_t totalSize, BOOL lohSizeKnown, uint64_t lohSize, BOOL disallowFullBlockingGC); int EndNoGCRegion(); unsigned GetGcCount(); Object* GetNextFinalizable() { return GetNextFinalizableObject(); }; size_t GetNumberOfFinalizable() { return GetNumberFinalizableObjects(); } PER_HEAP_ISOLATED HRESULT GetGcCounters(int gen, gc_counters* counters); size_t GetValidSegmentSize(BOOL large_seg = FALSE); static size_t GetValidGen0MaxSize(size_t seg_size); void SetReservedVMLimit (size_t vmlimit); PER_HEAP_ISOLATED Object* GetNextFinalizableObject(); PER_HEAP_ISOLATED size_t GetNumberFinalizableObjects(); PER_HEAP_ISOLATED size_t GetFinalizablePromotedCount(); void SetFinalizeQueueForShutdown(BOOL fHasLock); BOOL FinalizeAppDomain(AppDomain *pDomain, BOOL fRunFinalizers); BOOL ShouldRestartFinalizerWatchDog(); void DiagWalkObject (Object* obj, walk_fn fn, void* context); public: // FIX // Lock for finalization PER_HEAP_ISOLATED VOLATILE(int32_t) m_GCFLock; PER_HEAP_ISOLATED BOOL GcCollectClasses; PER_HEAP_ISOLATED VOLATILE(BOOL) GcInProgress; // used for syncing w/GC PER_HEAP_ISOLATED VOLATILE(unsigned) GcCount; PER_HEAP_ISOLATED unsigned GcCondemnedGeneration; // calculated at the end of a GC. PER_HEAP_ISOLATED size_t totalSurvivedSize; // Use only for GC tracing. PER_HEAP unsigned int GcDuration; size_t GarbageCollectGeneration (unsigned int gen=0, gc_reason reason=reason_empty); // Interface with gc_heap size_t GarbageCollectTry (int generation, BOOL low_memory_p=FALSE, int mode=collection_blocking); // frozen segment management functions virtual segment_handle RegisterFrozenSegment(segment_info *pseginfo); virtual void UnregisterFrozenSegment(segment_handle seg); void WaitUntilConcurrentGCComplete (); // Use in managd threads #ifndef DACCESS_COMPILE HRESULT WaitUntilConcurrentGCCompleteAsync(int millisecondsTimeout); // Use in native threads. TRUE if succeed. FALSE if failed or timeout #endif BOOL IsConcurrentGCInProgress(); // Enable/disable concurrent GC void TemporaryEnableConcurrentGC(); void TemporaryDisableConcurrentGC(); BOOL IsConcurrentGCEnabled(); PER_HEAP_ISOLATED CLREvent *WaitForGCEvent; // used for syncing w/GC PER_HEAP_ISOLATED CFinalize* m_Finalize; PER_HEAP_ISOLATED gc_heap* Getgc_heap(); private: static bool SafeToRestartManagedThreads() { // Note: this routine should return true when the last barrier // to threads returning to cooperative mode is down after gc. // In other words, if the sequence in GCHeap::RestartEE changes, // the condition here may have to change as well. return g_TrapReturningThreads == 0; } public: //return TRUE if GC actually happens, otherwise FALSE BOOL StressHeap(gc_alloc_context * acontext = 0); #ifndef FEATURE_REDHAWK // Redhawk forces relocation a different way #ifdef STRESS_HEAP protected: // only used in BACKGROUND_GC, but the symbol is not defined yet... PER_HEAP_ISOLATED int gc_stress_fgcs_in_bgc; #if !defined(MULTIPLE_HEAPS) // handles to hold the string objects that will force GC movement enum { NUM_HEAP_STRESS_OBJS = 8 }; PER_HEAP OBJECTHANDLE m_StressObjs[NUM_HEAP_STRESS_OBJS]; PER_HEAP int m_CurStressObj; #endif // !defined(MULTIPLE_HEAPS) #endif // STRESS_HEAP #endif // FEATURE_REDHAWK virtual void DiagDescrGenerations (gen_walk_fn fn, void *context); virtual void DiagWalkSurvivorsWithType (void* gc_context, record_surv_fn fn, size_t diag_context, walk_surv_type type); virtual void DiagWalkFinalizeQueue (void* gc_context, fq_walk_fn fn); virtual void DiagScanFinalizeQueue (fq_scan_fn fn, ScanContext* context); virtual void DiagScanHandles (handle_scan_fn fn, int gen_number, ScanContext* context); virtual void DiagScanDependentHandles (handle_scan_fn fn, int gen_number, ScanContext* context); virtual void DiagWalkHeap(walk_fn fn, void* context, int gen_number, BOOL walk_large_object_heap_p); public: Object * NextObj (Object * object); #if defined (FEATURE_BASICFREEZE) && defined (VERIFY_HEAP) BOOL IsInFrozenSegment (Object * object); #endif // defined (FEATURE_BASICFREEZE) && defined (VERIFY_HEAP) }; #endif // GCIMPL_H_