| 1 | // Licensed to the .NET Foundation under one or more agreements. | 
|---|
| 2 | // The .NET Foundation licenses this file to you under the MIT license. | 
|---|
| 3 | // See the LICENSE file in the project root for more information. | 
|---|
| 4 |  | 
|---|
| 5 |  | 
|---|
| 6 | /*++ | 
|---|
| 7 |  | 
|---|
| 8 | Module Name: | 
|---|
| 9 |  | 
|---|
| 10 | gc.h | 
|---|
| 11 |  | 
|---|
| 12 | --*/ | 
|---|
| 13 |  | 
|---|
| 14 | #ifndef __GC_H | 
|---|
| 15 | #define __GC_H | 
|---|
| 16 |  | 
|---|
| 17 | #include "gcinterface.h" | 
|---|
| 18 | #include "env/gcenv.os.h" | 
|---|
| 19 |  | 
|---|
| 20 | #ifdef BUILD_AS_STANDALONE | 
|---|
| 21 | #include "gcenv.ee.standalone.inl" | 
|---|
| 22 |  | 
|---|
| 23 | // GCStress does not currently work with Standalone GC | 
|---|
| 24 | #ifdef STRESS_HEAP | 
|---|
| 25 | #undef STRESS_HEAP | 
|---|
| 26 | #endif // STRESS_HEAP | 
|---|
| 27 | #else | 
|---|
| 28 | #include "env/gcenv.ee.h" | 
|---|
| 29 | #endif // BUILD_AS_STANDALONE | 
|---|
| 30 | #include "gcconfig.h" | 
|---|
| 31 |  | 
|---|
| 32 | /* | 
|---|
| 33 | * Promotion Function Prototypes | 
|---|
| 34 | */ | 
|---|
| 35 | typedef void enum_func (Object*); | 
|---|
| 36 |  | 
|---|
| 37 | // callback functions for heap walkers | 
|---|
| 38 | typedef void object_callback_func(void * pvContext, void * pvDataLoc); | 
|---|
| 39 |  | 
|---|
| 40 | struct fgm_history | 
|---|
| 41 | { | 
|---|
| 42 | failure_get_memory fgm; | 
|---|
| 43 | size_t size; | 
|---|
| 44 | size_t available_pagefile_mb; | 
|---|
| 45 | BOOL loh_p; | 
|---|
| 46 |  | 
|---|
| 47 | void set_fgm (failure_get_memory f, size_t s, BOOL l) | 
|---|
| 48 | { | 
|---|
| 49 | fgm = f; | 
|---|
| 50 | size = s; | 
|---|
| 51 | loh_p = l; | 
|---|
| 52 | } | 
|---|
| 53 | }; | 
|---|
| 54 |  | 
|---|
| 55 | // These values should be in sync with the GC_REASONs (in eventtrace.h) used for ETW. | 
|---|
| 56 | // TODO : it would be easier to make this an ORed value | 
|---|
| 57 | enum gc_reason | 
|---|
| 58 | { | 
|---|
| 59 | reason_alloc_soh = 0, | 
|---|
| 60 | reason_induced = 1, | 
|---|
| 61 | reason_lowmemory = 2, | 
|---|
| 62 | reason_empty = 3, | 
|---|
| 63 | reason_alloc_loh = 4, | 
|---|
| 64 | reason_oos_soh = 5, | 
|---|
| 65 | reason_oos_loh = 6, | 
|---|
| 66 | reason_induced_noforce = 7, // it's an induced GC and doesn't have to be blocking. | 
|---|
| 67 | reason_gcstress = 8,        // this turns into reason_induced & gc_mechanisms.stress_induced = true | 
|---|
| 68 | reason_lowmemory_blocking = 9, | 
|---|
| 69 | reason_induced_compacting = 10, | 
|---|
| 70 | reason_lowmemory_host = 11, | 
|---|
| 71 | reason_pm_full_gc = 12, // provisional mode requested to trigger full GC | 
|---|
| 72 | reason_lowmemory_host_blocking = 13, | 
|---|
| 73 | reason_max | 
|---|
| 74 | }; | 
|---|
| 75 |  | 
|---|
| 76 | // Types of GCs, emitted by the GCStart ETW event. | 
|---|
| 77 | enum gc_etw_type | 
|---|
| 78 | { | 
|---|
| 79 | gc_etw_type_ngc = 0, | 
|---|
| 80 | gc_etw_type_bgc = 1, | 
|---|
| 81 | gc_etw_type_fgc = 2 | 
|---|
| 82 | }; | 
|---|
| 83 |  | 
|---|
| 84 | // Types of segments, emitted by the GCCreateSegment ETW event. | 
|---|
| 85 | enum gc_etw_segment_type | 
|---|
| 86 | { | 
|---|
| 87 | gc_etw_segment_small_object_heap = 0, | 
|---|
| 88 | gc_etw_segment_large_object_heap = 1, | 
|---|
| 89 | gc_etw_segment_read_only_heap = 2 | 
|---|
| 90 | }; | 
|---|
| 91 |  | 
|---|
| 92 | // Types of allocations, emitted by the GCAllocationTick ETW event. | 
|---|
| 93 | enum gc_etw_alloc_kind | 
|---|
| 94 | { | 
|---|
| 95 | gc_etw_alloc_soh = 0, | 
|---|
| 96 | gc_etw_alloc_loh = 1 | 
|---|
| 97 | }; | 
|---|
| 98 |  | 
|---|
| 99 | /* forward declerations */ | 
|---|
| 100 | class ; | 
|---|
| 101 | class Object; | 
|---|
| 102 |  | 
|---|
| 103 | class IGCHeapInternal; | 
|---|
| 104 |  | 
|---|
| 105 | /* misc defines */ | 
|---|
| 106 | #define LARGE_OBJECT_SIZE ((size_t)(85000)) | 
|---|
| 107 | #define max_generation 2 | 
|---|
| 108 |  | 
|---|
| 109 | #ifdef GC_CONFIG_DRIVEN | 
|---|
| 110 | #define MAX_GLOBAL_GC_MECHANISMS_COUNT 6 | 
|---|
| 111 | extern size_t gc_global_mechanisms[MAX_GLOBAL_GC_MECHANISMS_COUNT]; | 
|---|
| 112 | #endif //GC_CONFIG_DRIVEN | 
|---|
| 113 |  | 
|---|
| 114 | #ifdef DACCESS_COMPILE | 
|---|
| 115 | class DacHeapWalker; | 
|---|
| 116 | #endif | 
|---|
| 117 |  | 
|---|
| 118 | #ifdef _DEBUG | 
|---|
| 119 | #define  _LOGALLOC | 
|---|
| 120 | #endif | 
|---|
| 121 |  | 
|---|
| 122 | #define MP_LOCKS | 
|---|
| 123 |  | 
|---|
| 124 | #ifdef FEATURE_MANUALLY_MANAGED_CARD_BUNDLES | 
|---|
| 125 | extern "C"uint32_t* g_gc_card_bundle_table; | 
|---|
| 126 | #endif | 
|---|
| 127 |  | 
|---|
| 128 | #if defined(ENABLE_PERF_COUNTERS) || defined(FEATURE_EVENT_TRACE) | 
|---|
| 129 | // Note this is not updated in a thread safe way so the value may not be accurate. We get | 
|---|
| 130 | // it accurately in full GCs if the handle count is requested. | 
|---|
| 131 | extern DWORD g_dwHandles; | 
|---|
| 132 | #endif // ENABLE_PERF_COUNTERS || FEATURE_EVENT_TRACE | 
|---|
| 133 |  | 
|---|
| 134 | extern "C"uint32_t* g_gc_card_table; | 
|---|
| 135 | extern "C"uint8_t* g_gc_lowest_address; | 
|---|
| 136 | extern "C"uint8_t* g_gc_highest_address; | 
|---|
| 137 | extern "C"GCHeapType g_gc_heap_type; | 
|---|
| 138 | extern "C"uint32_t g_max_generation; | 
|---|
| 139 | extern "C"MethodTable* g_gc_pFreeObjectMethodTable; | 
|---|
| 140 | extern "C"uint32_t g_num_processors; | 
|---|
| 141 |  | 
|---|
| 142 | extern VOLATILE(int32_t) g_fSuspensionPending; | 
|---|
| 143 |  | 
|---|
| 144 | extern uint32_t g_yieldProcessorScalingFactor; | 
|---|
| 145 |  | 
|---|
| 146 | ::IGCHandleManager*  CreateGCHandleManager(); | 
|---|
| 147 |  | 
|---|
| 148 | namespace WKS { | 
|---|
| 149 | ::IGCHeapInternal* CreateGCHeap(); | 
|---|
| 150 | class GCHeap; | 
|---|
| 151 | class gc_heap; | 
|---|
| 152 | } | 
|---|
| 153 |  | 
|---|
| 154 | #if defined(FEATURE_SVR_GC) | 
|---|
| 155 | namespace SVR { | 
|---|
| 156 | ::IGCHeapInternal* CreateGCHeap(); | 
|---|
| 157 | class GCHeap; | 
|---|
| 158 | class gc_heap; | 
|---|
| 159 | } | 
|---|
| 160 | #endif // defined(FEATURE_SVR_GC) | 
|---|
| 161 |  | 
|---|
| 162 | #ifdef STRESS_HEAP | 
|---|
| 163 | #define IN_STRESS_HEAP(x) x | 
|---|
| 164 | #define STRESS_HEAP_ARG(x) ,x | 
|---|
| 165 | #else // STRESS_HEAP | 
|---|
| 166 | #define IN_STRESS_HEAP(x) | 
|---|
| 167 | #define STRESS_HEAP_ARG(x) | 
|---|
| 168 | #endif // STRESS_HEAP | 
|---|
| 169 |  | 
|---|
| 170 | //dynamic data interface | 
|---|
| 171 | struct gc_counters | 
|---|
| 172 | { | 
|---|
| 173 | size_t current_size; | 
|---|
| 174 | size_t promoted_size; | 
|---|
| 175 | size_t collection_count; | 
|---|
| 176 | }; | 
|---|
| 177 |  | 
|---|
| 178 | enum bgc_state | 
|---|
| 179 | { | 
|---|
| 180 | bgc_not_in_process = 0, | 
|---|
| 181 | bgc_initialized, | 
|---|
| 182 | bgc_reset_ww, | 
|---|
| 183 | bgc_mark_handles, | 
|---|
| 184 | bgc_mark_stack, | 
|---|
| 185 | bgc_revisit_soh, | 
|---|
| 186 | bgc_revisit_loh, | 
|---|
| 187 | bgc_overflow_soh, | 
|---|
| 188 | bgc_overflow_loh, | 
|---|
| 189 | bgc_final_marking, | 
|---|
| 190 | bgc_sweep_soh, | 
|---|
| 191 | bgc_sweep_loh, | 
|---|
| 192 | bgc_plan_phase | 
|---|
| 193 | }; | 
|---|
| 194 |  | 
|---|
| 195 | enum changed_seg_state | 
|---|
| 196 | { | 
|---|
| 197 | seg_deleted, | 
|---|
| 198 | seg_added | 
|---|
| 199 | }; | 
|---|
| 200 |  | 
|---|
| 201 | void record_changed_seg (uint8_t* start, uint8_t* end, | 
|---|
| 202 | size_t current_gc_index, | 
|---|
| 203 | bgc_state current_bgc_state, | 
|---|
| 204 | changed_seg_state changed_state); | 
|---|
| 205 |  | 
|---|
| 206 | #ifdef GC_CONFIG_DRIVEN | 
|---|
| 207 | void record_global_mechanism (int mech_index); | 
|---|
| 208 | #endif //GC_CONFIG_DRIVEN | 
|---|
| 209 |  | 
|---|
| 210 | struct alloc_context : gc_alloc_context | 
|---|
| 211 | { | 
|---|
| 212 | #ifdef FEATURE_SVR_GC | 
|---|
| 213 | inline SVR::GCHeap* get_alloc_heap() | 
|---|
| 214 | { | 
|---|
| 215 | return static_cast<SVR::GCHeap*>(gc_reserved_1); | 
|---|
| 216 | } | 
|---|
| 217 |  | 
|---|
| 218 | inline void set_alloc_heap(SVR::GCHeap* heap) | 
|---|
| 219 | { | 
|---|
| 220 | gc_reserved_1 = heap; | 
|---|
| 221 | } | 
|---|
| 222 |  | 
|---|
| 223 | inline SVR::GCHeap* get_home_heap() | 
|---|
| 224 | { | 
|---|
| 225 | return static_cast<SVR::GCHeap*>(gc_reserved_2); | 
|---|
| 226 | } | 
|---|
| 227 |  | 
|---|
| 228 | inline void set_home_heap(SVR::GCHeap* heap) | 
|---|
| 229 | { | 
|---|
| 230 | gc_reserved_2 = heap; | 
|---|
| 231 | } | 
|---|
| 232 | #endif // FEATURE_SVR_GC | 
|---|
| 233 | }; | 
|---|
| 234 |  | 
|---|
| 235 | class IGCHeapInternal : public IGCHeap { | 
|---|
| 236 | public: | 
|---|
| 237 |  | 
|---|
| 238 | virtual ~IGCHeapInternal() {} | 
|---|
| 239 |  | 
|---|
| 240 | private: | 
|---|
| 241 | virtual Object* AllocAlign8Common (void* hp, alloc_context* acontext, size_t size, uint32_t flags) = 0; | 
|---|
| 242 | public: | 
|---|
| 243 | virtual int GetNumberOfHeaps () = 0; | 
|---|
| 244 | virtual int GetHomeHeapNumber () = 0; | 
|---|
| 245 | virtual size_t GetPromotedBytes(int heap_index) = 0; | 
|---|
| 246 |  | 
|---|
| 247 | unsigned GetMaxGeneration() | 
|---|
| 248 | { | 
|---|
| 249 | return max_generation; | 
|---|
| 250 | } | 
|---|
| 251 |  | 
|---|
| 252 | bool IsValidSegmentSize(size_t cbSize) | 
|---|
| 253 | { | 
|---|
| 254 | //Must be aligned on a Mb and greater than 4Mb | 
|---|
| 255 | return (((cbSize & (1024*1024-1)) ==0) && (cbSize >> 22)); | 
|---|
| 256 | } | 
|---|
| 257 |  | 
|---|
| 258 | bool IsValidGen0MaxSize(size_t cbSize) | 
|---|
| 259 | { | 
|---|
| 260 | return (cbSize >= 64*1024); | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | BOOL IsLargeObject(MethodTable *mt) | 
|---|
| 264 | { | 
|---|
| 265 | return mt->GetBaseSize() >= LARGE_OBJECT_SIZE; | 
|---|
| 266 | } | 
|---|
| 267 |  | 
|---|
| 268 | protected: | 
|---|
| 269 | public: | 
|---|
| 270 | #if defined(FEATURE_BASICFREEZE) && defined(VERIFY_HEAP) | 
|---|
| 271 | // Return TRUE if object lives in frozen segment | 
|---|
| 272 | virtual BOOL IsInFrozenSegment (Object * object) = 0; | 
|---|
| 273 | #endif // defined(FEATURE_BASICFREEZE) && defined(VERIFY_HEAP) | 
|---|
| 274 | }; | 
|---|
| 275 |  | 
|---|
| 276 | // Go through and touch (read) each page straddled by a memory block. | 
|---|
| 277 | void TouchPages(void * pStart, size_t cb); | 
|---|
| 278 |  | 
|---|
| 279 | #ifdef WRITE_BARRIER_CHECK | 
|---|
| 280 | void updateGCShadow(Object** ptr, Object* val); | 
|---|
| 281 | #endif | 
|---|
| 282 |  | 
|---|
| 283 | #ifndef DACCESS_COMPILE | 
|---|
| 284 | // The single GC heap instance, shared with the VM. | 
|---|
| 285 | extern IGCHeapInternal* g_theGCHeap; | 
|---|
| 286 |  | 
|---|
| 287 | // The single GC handle manager instance, shared with the VM. | 
|---|
| 288 | extern IGCHandleManager* g_theGCHandleManager; | 
|---|
| 289 | #endif // DACCESS_COMPILE | 
|---|
| 290 |  | 
|---|
| 291 | #ifndef DACCESS_COMPILE | 
|---|
| 292 | inline bool IsGCInProgress(bool bConsiderGCStart = false) | 
|---|
| 293 | { | 
|---|
| 294 | return g_theGCHeap != nullptr ? g_theGCHeap->IsGCInProgressHelper(bConsiderGCStart) : false; | 
|---|
| 295 | } | 
|---|
| 296 | #endif // DACCESS_COMPILE | 
|---|
| 297 |  | 
|---|
| 298 | inline bool IsServerHeap() | 
|---|
| 299 | { | 
|---|
| 300 | #ifdef FEATURE_SVR_GC | 
|---|
| 301 | assert(g_gc_heap_type != GC_HEAP_INVALID); | 
|---|
| 302 | return g_gc_heap_type == GC_HEAP_SVR; | 
|---|
| 303 | #else // FEATURE_SVR_GC | 
|---|
| 304 | return false; | 
|---|
| 305 | #endif // FEATURE_SVR_GC | 
|---|
| 306 | } | 
|---|
| 307 |  | 
|---|
| 308 | #endif // __GC_H | 
|---|
| 309 |  | 
|---|