// 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_ #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; extern bool g_fFinalizerRunOnShutDown; extern bool g_built_with_svr_gc; extern uint8_t g_build_variant; extern VOLATILE(int32_t) g_no_gc_lock; 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(); uint64_t GetTotalAllocatedBytes(); 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); bool RuntimeStructuresValid(); void SetSuspensionPending(bool fSuspensionPending); void SetYieldProcessorScalingFactor(float yieldProcessorScalingFactor); void SetWaitForGCEvent(); void ResetWaitForGCEvent(); HRESULT Initialize (); //flags can be GC_ALLOC_CONTAINS_REF GC_ALLOC_FINALIZE 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, void* arg, void *heap); Object* GetContainingObject(void *pInteriorPtr, bool fCollectedGenOnly); #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(); void GetMemoryInfo(uint64_t* highMemLoadThresholdBytes, uint64_t* totalAvailableMemoryBytes, uint64_t* lastRecordedMemLoadBytes, uint32_t* lastRecordedMemLoadPct, size_t* lastRecordedHeapSizeBytes, size_t* lastRecordedFragmentationBytes); 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); 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 ShouldRestartFinalizerWatchDog(); void DiagWalkObject (Object* obj, walk_fn fn, void* context); void DiagWalkObject2 (Object* obj, walk_fn2 fn, void* context); void SetFinalizeRunOnShutdown(bool value); 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); virtual bool IsInFrozenSegment(Object *object); // Event control functions void ControlEvents(GCEventKeyword keyword, GCEventLevel level); void ControlPrivateEvents(GCEventKeyword keyword, GCEventLevel level); 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 GCEvent *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_fSuspensionPending == 0; } public: //return TRUE if GC actually happens, otherwise FALSE bool StressHeap(gc_alloc_context * acontext); #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, void* 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); int GetLastGCPercentTimeInGC(); size_t GetLastGCGenerationSize(int gen); }; #endif // GCIMPL_H_