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 #ifndef _GC_INTERFACE_H_
6 #define _GC_INTERFACE_H_
7 
8 struct ScanContext;
9 struct gc_alloc_context;
10 class CrawlFrame;
11 
12 // Callback passed to GcScanRoots.
13 typedef void promote_func(PTR_PTR_Object, ScanContext*, uint32_t);
14 
15 // Callback passed to GcEnumAllocContexts.
16 typedef void enum_alloc_context_func(gc_alloc_context*, void*);
17 
18 // Callback passed to CreateBackgroundThread.
19 typedef uint32_t (__stdcall *GCBackgroundThreadFunction)(void* param);
20 
21 // Struct often used as a parameter to callbacks.
22 typedef struct
23 {
24     promote_func*  f;
25     ScanContext*   sc;
26     CrawlFrame *   cf;
27 } GCCONTEXT;
28 
29 // SUSPEND_REASON is the reason why the GC wishes to suspend the EE,
30 // used as an argument to IGCToCLR::SuspendEE.
31 typedef enum
32 {
33     SUSPEND_FOR_GC = 1,
34     SUSPEND_FOR_GC_PREP = 6
35 } SUSPEND_REASON;
36 
37 typedef enum
38 {
39     walk_for_gc = 1,
40     walk_for_bgc = 2,
41     walk_for_loh = 3
42 } walk_surv_type;
43 
44 // Different operations that can be done by GCToEEInterface::StompWriteBarrier
45 enum class WriteBarrierOp
46 {
47     StompResize,
48     StompEphemeral,
49     Initialize,
50     SwitchToWriteWatch,
51     SwitchToNonWriteWatch
52 };
53 
54 // Arguments to GCToEEInterface::StompWriteBarrier
55 struct WriteBarrierParameters
56 {
57     // The operation that StompWriteBarrier will perform.
58     WriteBarrierOp operation;
59 
60     // Whether or not the runtime is currently suspended. If it is not,
61     // the EE will need to suspend it before bashing the write barrier.
62     // Used for all operations.
63     bool is_runtime_suspended;
64 
65     // Whether or not the GC has moved the ephemeral generation to no longer
66     // be at the top of the heap. When the ephemeral generation is at the top
67     // of the heap, and the write barrier observes that a pointer is greater than
68     // g_ephemeral_low, it does not need to check that the pointer is less than
69     // g_ephemeral_high because there is nothing in the GC heap above the ephemeral
70     // generation. When this is not the case, however, the GC must inform the EE
71     // so that the EE can switch to a write barrier that checks that a pointer
72     // is both greater than g_ephemeral_low and less than g_ephemeral_high.
73     // Used for WriteBarrierOp::StompResize.
74     bool requires_upper_bounds_check;
75 
76     // The new card table location. May or may not be the same as the previous
77     // card table. Used for WriteBarrierOp::Initialize and WriteBarrierOp::StompResize.
78     uint32_t* card_table;
79 
80     // The heap's new low boundary. May or may not be the same as the previous
81     // value. Used for WriteBarrierOp::Initialize and WriteBarrierOp::StompResize.
82     uint8_t* lowest_address;
83 
84     // The heap's new high boundary. May or may not be the same as the previous
85     // value. Used for WriteBarrierOp::Initialize and WriteBarrierOp::StompResize.
86     uint8_t* highest_address;
87 
88     // The new start of the ephemeral generation.
89     // Used for WriteBarrierOp::StompEphemeral.
90     uint8_t* ephemeral_low;
91 
92     // The new end of the ephemeral generation.
93     // Used for WriteBarrierOp::StompEphemeral.
94     uint8_t* ephemeral_high;
95 
96     // The new write watch table, if we are using our own write watch
97     // implementation. Used for WriteBarrierOp::SwitchToWriteWatch only.
98     uint8_t* write_watch_table;
99 };
100 
101 #include "gcinterface.ee.h"
102 
103 // The allocation context must be known to the VM for use in the allocation
104 // fast path and known to the GC for performing the allocation. Every Thread
105 // has its own allocation context that it hands to the GC when allocating.
106 struct gc_alloc_context
107 {
108     uint8_t*       alloc_ptr;
109     uint8_t*       alloc_limit;
110     int64_t        alloc_bytes; //Number of bytes allocated on SOH by this context
111     int64_t        alloc_bytes_loh; //Number of bytes allocated on LOH by this context
112     // These two fields are deliberately not exposed past the EE-GC interface.
113     void*          gc_reserved_1;
114     void*          gc_reserved_2;
115     int            alloc_count;
116 public:
117 
initgc_alloc_context118     void init()
119     {
120         LIMITED_METHOD_CONTRACT;
121 
122         alloc_ptr = 0;
123         alloc_limit = 0;
124         alloc_bytes = 0;
125         alloc_bytes_loh = 0;
126         gc_reserved_1 = 0;
127         gc_reserved_2 = 0;
128         alloc_count = 0;
129     }
130 };
131 
132 // stub type to abstract a heap segment
133 struct gc_heap_segment_stub;
134 typedef gc_heap_segment_stub *segment_handle;
135 
136 struct segment_info
137 {
138     void * pvMem; // base of the allocation, not the first object (must add ibFirstObject)
139     size_t ibFirstObject;   // offset to the base of the first object in the segment
140     size_t ibAllocated; // limit of allocated memory in the segment (>= firstobject)
141     size_t ibCommit; // limit of committed memory in the segment (>= alllocated)
142     size_t ibReserved; // limit of reserved memory in the segment (>= commit)
143 };
144 
145 #ifdef PROFILING_SUPPORTED
146 #define GC_PROFILING       //Turn on profiling
147 #endif // PROFILING_SUPPORTED
148 
149 #define LARGE_OBJECT_SIZE ((size_t)(85000))
150 
151 // The minimum size of an object is three pointers wide: one for the syncblock,
152 // one for the object header, and one for the first field in the object.
153 #define min_obj_size ((sizeof(uint8_t*) + sizeof(uintptr_t) + sizeof(size_t)))
154 
155 #define max_generation 2
156 
157 // The bit shift used to convert a memory address into an index into the
158 // Software Write Watch table.
159 #define SOFTWARE_WRITE_WATCH_AddressToTableByteIndexShift 0xc
160 
161 class Object;
162 class IGCHeap;
163 
164 // Initializes the garbage collector. Should only be called
165 // once, during EE startup.
166 IGCHeap* InitializeGarbageCollector(IGCToCLR* clrToGC);
167 
168 // The runtime needs to know whether we're using workstation or server GC
169 // long before the GCHeap is created. This function sets the type of
170 // heap that will be created, before InitializeGarbageCollector is called
171 // and the heap is actually recated.
172 void InitializeHeapType(bool bServerHeap);
173 
174 #ifdef WRITE_BARRIER_CHECK
175 //always defined, but should be 0 in Server GC
176 extern uint8_t* g_GCShadow;
177 extern uint8_t* g_GCShadowEnd;
178 // saves the g_lowest_address in between GCs to verify the consistency of the shadow segment
179 extern uint8_t* g_shadow_lowest_address;
180 #endif
181 
182 // For low memory notification from host
183 extern int32_t g_bLowMemoryFromHost;
184 
185 extern VOLATILE(int32_t) m_GCLock;
186 
187 // !!!!!!!!!!!!!!!!!!!!!!!
188 // make sure you change the def in bcl\system\gc.cs
189 // if you change this!
190 enum collection_mode
191 {
192     collection_non_blocking = 0x00000001,
193     collection_blocking = 0x00000002,
194     collection_optimized = 0x00000004,
195     collection_compacting = 0x00000008
196 #ifdef STRESS_HEAP
197     , collection_gcstress = 0x80000000
198 #endif // STRESS_HEAP
199 };
200 
201 // !!!!!!!!!!!!!!!!!!!!!!!
202 // make sure you change the def in bcl\system\gc.cs
203 // if you change this!
204 enum wait_full_gc_status
205 {
206     wait_full_gc_success = 0,
207     wait_full_gc_failed = 1,
208     wait_full_gc_cancelled = 2,
209     wait_full_gc_timeout = 3,
210     wait_full_gc_na = 4
211 };
212 
213 // !!!!!!!!!!!!!!!!!!!!!!!
214 // make sure you change the def in bcl\system\gc.cs
215 // if you change this!
216 enum start_no_gc_region_status
217 {
218     start_no_gc_success = 0,
219     start_no_gc_no_memory = 1,
220     start_no_gc_too_large = 2,
221     start_no_gc_in_progress = 3
222 };
223 
224 enum end_no_gc_region_status
225 {
226     end_no_gc_success = 0,
227     end_no_gc_not_in_progress = 1,
228     end_no_gc_induced = 2,
229     end_no_gc_alloc_exceeded = 3
230 };
231 
232 typedef BOOL (* walk_fn)(Object*, void*);
233 typedef void (* gen_walk_fn)(void* context, int generation, uint8_t* range_start, uint8_t* range_end, uint8_t* range_reserved);
234 typedef void (* record_surv_fn)(uint8_t* begin, uint8_t* end, ptrdiff_t reloc, size_t context, BOOL compacting_p, BOOL bgc_p);
235 typedef void (* fq_walk_fn)(BOOL, void*);
236 typedef void (* fq_scan_fn)(Object** ppObject, ScanContext *pSC, uint32_t dwFlags);
237 typedef void (* handle_scan_fn)(Object** pRef, Object* pSec, uint32_t flags, ScanContext* context, BOOL isDependent);
238 
239 // IGCHeap is the interface that the VM will use when interacting with the GC.
240 class IGCHeap {
241 public:
242     /*
243     ===========================================================================
244     Hosting APIs. These are used by GC hosting. The code that
245     calls these methods may possibly be moved behind the interface -
246     today, the VM handles the setting of segment size and max gen 0 size.
247     (See src/vm/corehost.cpp)
248     ===========================================================================
249     */
250 
251     // Returns whether or not the given size is a valid segment size.
252     virtual BOOL IsValidSegmentSize(size_t size) = 0;
253 
254     // Returns whether or not the given size is a valid gen 0 max size.
255     virtual BOOL IsValidGen0MaxSize(size_t size) = 0;
256 
257     // Gets a valid segment size.
258     virtual size_t GetValidSegmentSize(BOOL large_seg = FALSE) = 0;
259 
260     // Sets the limit for reserved virtual memory.
261     virtual void SetReservedVMLimit(size_t vmlimit) = 0;
262 
263     /*
264     ===========================================================================
265     Concurrent GC routines. These are used in various places in the VM
266     to synchronize with the GC, when the VM wants to update something that
267     the GC is potentially using, if it's doing a background GC.
268 
269     Concrete examples of this are moving async pinned handles across appdomains
270     and profiling/ETW scenarios.
271     ===========================================================================
272     */
273 
274     // Blocks until any running concurrent GCs complete.
275     virtual void WaitUntilConcurrentGCComplete() = 0;
276 
277     // Returns true if a concurrent GC is in progress, false otherwise.
278     virtual BOOL IsConcurrentGCInProgress() = 0;
279 
280     // Temporarily enables concurrent GC, used during profiling.
281     virtual void TemporaryEnableConcurrentGC() = 0;
282 
283     // Temporarily disables concurrent GC, used during profiling.
284     virtual void TemporaryDisableConcurrentGC() = 0;
285 
286     // Returns whether or not Concurrent GC is enabled.
287     virtual BOOL IsConcurrentGCEnabled() = 0;
288 
289     // Wait for a concurrent GC to complete if one is in progress, with the given timeout.
290     virtual HRESULT WaitUntilConcurrentGCCompleteAsync(int millisecondsTimeout) = 0;    // Use in native threads. TRUE if succeed. FALSE if failed or timeout
291 
292 
293     /*
294     ===========================================================================
295     Finalization routines. These are used by the finalizer thread to communicate
296     with the GC.
297     ===========================================================================
298     */
299 
300     // Finalizes an app domain by finalizing objects within that app domain.
301     virtual BOOL FinalizeAppDomain(AppDomain* pDomain, BOOL fRunFinalizers) = 0;
302 
303     // Finalizes all registered objects for shutdown, even if they are still reachable.
304     virtual void SetFinalizeQueueForShutdown(BOOL fHasLock) = 0;
305 
306     // Gets the number of finalizable objects.
307     virtual size_t GetNumberOfFinalizable() = 0;
308 
309     // Traditionally used by the finalizer thread on shutdown to determine
310     // whether or not to time out. Returns true if the GC lock has not been taken.
311     virtual BOOL ShouldRestartFinalizerWatchDog() = 0;
312 
313     // Gets the next finalizable object.
314     virtual Object* GetNextFinalizable() = 0;
315 
316     // Sets whether or not the GC should report all finalizable objects as
317     // ready to be finalized, instead of only collectable objects.
318     virtual void SetFinalizeRunOnShutdown(bool value) = 0;
319 
320     /*
321     ===========================================================================
322     BCL routines. These are routines that are directly exposed by mscorlib
323     as a part of the `System.GC` class. These routines behave in the same
324     manner as the functions on `System.GC`.
325     ===========================================================================
326     */
327 
328     // Gets the current GC latency mode.
329     virtual int GetGcLatencyMode() = 0;
330 
331     // Sets the current GC latency mode. newLatencyMode has already been
332     // verified by mscorlib to be valid.
333     virtual int SetGcLatencyMode(int newLatencyMode) = 0;
334 
335     // Gets the current LOH compaction mode.
336     virtual int GetLOHCompactionMode() = 0;
337 
338     // Sets the current LOH compaction mode. newLOHCompactionMode has
339     // already been verified by mscorlib to be valid.
340     virtual void SetLOHCompactionMode(int newLOHCompactionMode) = 0;
341 
342     // Registers for a full GC notification, raising a notification if the gen 2 or
343     // LOH object heap thresholds are exceeded.
344     virtual BOOL RegisterForFullGCNotification(uint32_t gen2Percentage, uint32_t lohPercentage) = 0;
345 
346     // Cancels a full GC notification that was requested by `RegisterForFullGCNotification`.
347     virtual BOOL CancelFullGCNotification() = 0;
348 
349     // Returns the status of a registered notification for determining whether a blocking
350     // Gen 2 collection is about to be initiated, with the given timeout.
351     virtual int WaitForFullGCApproach(int millisecondsTimeout) = 0;
352 
353     // Returns the status of a registered notification for determining whether a blocking
354     // Gen 2 collection has completed, with the given timeout.
355     virtual int WaitForFullGCComplete(int millisecondsTimeout) = 0;
356 
357     // Returns the generation in which obj is found. Also used by the VM
358     // in some places, in particular syncblk code.
359     virtual unsigned WhichGeneration(Object* obj) = 0;
360 
361     // Returns the number of GCs that have transpired in the given generation
362     // since the beginning of the life of the process. Also used by the VM
363     // for debug code and app domains.
364     virtual int CollectionCount(int generation, int get_bgc_fgc_coutn = 0) = 0;
365 
366     // Begins a no-GC region, returning a code indicating whether entering the no-GC
367     // region was successful.
368     virtual int StartNoGCRegion(uint64_t totalSize, BOOL lohSizeKnown, uint64_t lohSize, BOOL disallowFullBlockingGC) = 0;
369 
370     // Exits a no-GC region.
371     virtual int EndNoGCRegion() = 0;
372 
373     // Gets the total number of bytes in use.
374     virtual size_t GetTotalBytesInUse() = 0;
375 
376     // Forces a garbage collection of the given generation. Also used extensively
377     // throughout the VM.
378     virtual HRESULT GarbageCollect(int generation = -1, BOOL low_memory_p = FALSE, int mode = collection_blocking) = 0;
379 
380     // Gets the largest GC generation. Also used extensively throughout the VM.
381     virtual unsigned GetMaxGeneration() = 0;
382 
383     // Indicates that an object's finalizer should not be run upon the object's collection.
384     virtual void SetFinalizationRun(Object* obj) = 0;
385 
386     // Indicates that an object's finalizer should be run upon the object's collection.
387     virtual bool RegisterForFinalization(int gen, Object* obj) = 0;
388 
389     /*
390     ===========================================================================
391     Miscellaneous routines used by the VM.
392     ===========================================================================
393     */
394 
395     // Initializes the GC heap, returning whether or not the initialization
396     // was successful.
397     virtual HRESULT Initialize() = 0;
398 
399     // Returns whether nor this GC was promoted by the last GC.
400     virtual BOOL IsPromoted(Object* object) = 0;
401 
402     // Returns true if this pointer points into a GC heap, false otherwise.
403     virtual BOOL IsHeapPointer(void* object, BOOL small_heap_only = FALSE) = 0;
404 
405     // Return the generation that has been condemned by the current GC.
406     virtual unsigned GetCondemnedGeneration() = 0;
407 
408     // Returns whether or not a GC is in progress.
409     virtual BOOL IsGCInProgressHelper(BOOL bConsiderGCStart = FALSE) = 0;
410 
411     // Returns the number of GCs that have occured. Mainly used for
412     // sanity checks asserting that a GC has not occured.
413     virtual unsigned GetGcCount() = 0;
414 
415     // Gets whether or not the home heap of this alloc context matches the heap
416     // associated with this thread.
417     virtual bool IsThreadUsingAllocationContextHeap(gc_alloc_context* acontext, int thread_number) = 0;
418 
419     // Returns whether or not this object resides in an ephemeral generation.
420     virtual BOOL IsEphemeral(Object* object) = 0;
421 
422     // Blocks until a GC is complete, returning a code indicating the wait was successful.
423     virtual uint32_t WaitUntilGCComplete(BOOL bConsiderGCStart = FALSE) = 0;
424 
425     // "Fixes" an allocation context by binding its allocation pointer to a
426     // location on the heap.
427     virtual void FixAllocContext(gc_alloc_context* acontext, BOOL lockp, void* arg, void* heap) = 0;
428 
429     // Gets the total survived size plus the total allocated bytes on the heap.
430     virtual size_t GetCurrentObjSize() = 0;
431 
432     // Sets whether or not a GC is in progress.
433     virtual void SetGCInProgress(BOOL fInProgress) = 0;
434 
435     /*
436     ============================================================================
437     Add/RemoveMemoryPressure support routines. These are on the interface
438     for now, but we should move Add/RemoveMemoryPressure from the VM to the GC.
439     When that occurs, these three routines can be removed from the interface.
440     ============================================================================
441     */
442 
443     // Get the timestamp corresponding to the last GC that occured for the
444     // given generation.
445     virtual size_t GetLastGCStartTime(int generation) = 0;
446 
447     // Gets the duration of the last GC that occured for the given generation.
448     virtual size_t GetLastGCDuration(int generation) = 0;
449 
450     // Gets a timestamp for the current moment in time.
451     virtual size_t GetNow() = 0;
452 
453     /*
454     ===========================================================================
455     Allocation routines. These all call into the GC's allocator and may trigger a garbage
456     collection. All allocation routines return NULL when the allocation request
457     couldn't be serviced due to being out of memory.
458     ===========================================================================
459     */
460 
461     // Allocates an object on the given allocation context with the given size and flags.
462     virtual Object* Alloc(gc_alloc_context* acontext, size_t size, uint32_t flags) = 0;
463 
464     // Allocates an object on the default allocation context with the given size and flags.
465     virtual Object* Alloc(size_t size, uint32_t flags) = 0;
466 
467     // Allocates an object on the large object heap with the given size and flags.
468     virtual Object* AllocLHeap(size_t size, uint32_t flags) = 0;
469 
470     // Allocates an object on the default allocation context, aligned to 64 bits,
471     // with the given size and flags.
472     virtual Object* AllocAlign8 (size_t size, uint32_t flags) = 0;
473 
474     // Allocates an object on the given allocation context, aligned to 64 bits,
475     // with the given size and flags.
476     virtual Object* AllocAlign8 (gc_alloc_context* acontext, size_t size, uint32_t flags) = 0;
477 
478     // This is for the allocator to indicate it's done allocating a large object during a
479     // background GC as the BGC threads also need to walk LOH.
480     virtual void PublishObject(uint8_t* obj) = 0;
481 
482     // Gets the event that suspended threads will use to wait for the
483     // end of a GC.
484     virtual CLREventStatic* GetWaitForGCEvent() = 0;
485 
486     /*
487     ===========================================================================
488     Heap verification routines. These are used during heap verification only.
489     ===========================================================================
490     */
491     // Returns whether or not this object is in the fixed heap.
492     virtual BOOL IsObjectInFixedHeap(Object* pObj) = 0;
493 
494     // Walks an object and validates its members.
495     virtual void ValidateObjectMember(Object* obj) = 0;
496 
497     // Retrieves the next object after the given object. When the EE
498     // is not suspended, the result is not accurate - if the input argument
499     // is in Gen0, the function could return zeroed out memory as the next object.
500     virtual Object* NextObj(Object* object) = 0;
501 
502     // Given an interior pointer, return a pointer to the object
503     // containing that pointer. This is safe to call only when the EE is suspended.
504     virtual Object* GetContainingObject(void* pInteriorPtr) = 0;
505 
506     /*
507     ===========================================================================
508     Profiling routines. Used for event tracing and profiling to broadcast
509     information regarding the heap.
510     ===========================================================================
511     */
512 
513     // Walks an object, invoking a callback on each member.
514     virtual void DiagWalkObject(Object* obj, walk_fn fn, void* context) = 0;
515 
516     // Walk the heap object by object.
517     virtual void DiagWalkHeap(walk_fn fn, void* context, int gen_number, BOOL walk_large_object_heap_p) = 0;
518 
519     // Walks the survivors and get the relocation information if objects have moved.
520     virtual void DiagWalkSurvivorsWithType(void* gc_context, record_surv_fn fn, size_t diag_context, walk_surv_type type) = 0;
521 
522     // Walks the finalization queue.
523     virtual void DiagWalkFinalizeQueue(void* gc_context, fq_walk_fn fn) = 0;
524 
525     // Scan roots on finalizer queue. This is a generic function.
526     virtual void DiagScanFinalizeQueue(fq_scan_fn fn, ScanContext* context) = 0;
527 
528     // Scan handles for profiling or ETW.
529     virtual void DiagScanHandles(handle_scan_fn fn, int gen_number, ScanContext* context) = 0;
530 
531     // Scan dependent handles for profiling or ETW.
532     virtual void DiagScanDependentHandles(handle_scan_fn fn, int gen_number, ScanContext* context) = 0;
533 
534     // Describes all generations to the profiler, invoking a callback on each generation.
535     virtual void DiagDescrGenerations(gen_walk_fn fn, void* context) = 0;
536 
537     // Traces all GC segments and fires ETW events with information on them.
538     virtual void DiagTraceGCSegments() = 0;
539 
540     /*
541     ===========================================================================
542     GC Stress routines. Used only when running under GC Stress.
543     ===========================================================================
544     */
545 
546     // Returns TRUE if GC actually happens, otherwise FALSE
547     virtual BOOL StressHeap(gc_alloc_context* acontext = 0) = 0;
548 
549     /*
550     ===========================================================================
551     Routines to register read only segments for frozen objects.
552     Only valid if FEATURE_BASICFREEZE is defined.
553     ===========================================================================
554     */
555 
556     // Registers a frozen segment with the GC.
557     virtual segment_handle RegisterFrozenSegment(segment_info *pseginfo) = 0;
558 
559     // Unregisters a frozen segment.
560     virtual void UnregisterFrozenSegment(segment_handle seg) = 0;
561 
IGCHeap()562     IGCHeap() {}
~IGCHeap()563     virtual ~IGCHeap() {}
564 
565     typedef enum
566     {
567         GC_HEAP_INVALID = 0,
568         GC_HEAP_WKS     = 1,
569         GC_HEAP_SVR     = 2
570     } GC_HEAP_TYPE;
571 
572 #ifdef FEATURE_SVR_GC
573     SVAL_DECL(uint32_t, gcHeapType);
574 #endif
575 
576     SVAL_DECL(uint32_t, maxGeneration);
577 };
578 
579 #ifdef WRITE_BARRIER_CHECK
580 void updateGCShadow(Object** ptr, Object* val);
581 #endif
582 
583 //constants for the flags parameter to the gc call back
584 
585 #define GC_CALL_INTERIOR            0x1
586 #define GC_CALL_PINNED              0x2
587 #define GC_CALL_CHECK_APP_DOMAIN    0x4
588 
589 //flags for IGCHeapAlloc(...)
590 #define GC_ALLOC_FINALIZE 0x1
591 #define GC_ALLOC_CONTAINS_REF 0x2
592 #define GC_ALLOC_ALIGN8_BIAS 0x4
593 #define GC_ALLOC_ALIGN8 0x8
594 
595 struct ScanContext
596 {
597     Thread* thread_under_crawl;
598     int thread_number;
599     uintptr_t stack_limit; // Lowest point on the thread stack that the scanning logic is permitted to read
600     BOOL promotion; //TRUE: Promotion, FALSE: Relocation.
601     BOOL concurrent; //TRUE: concurrent scanning
602 #if CHECK_APP_DOMAIN_LEAKS || defined (FEATURE_APPDOMAIN_RESOURCE_MONITORING) || defined (DACCESS_COMPILE)
603     AppDomain *pCurrentDomain;
604 #endif //CHECK_APP_DOMAIN_LEAKS || FEATURE_APPDOMAIN_RESOURCE_MONITORING || DACCESS_COMPILE
605 
606 #ifndef FEATURE_REDHAWK
607 #if defined(GC_PROFILING) || defined (DACCESS_COMPILE)
608     MethodDesc *pMD;
609 #endif //GC_PROFILING || DACCESS_COMPILE
610 #endif // FEATURE_REDHAWK
611 #if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
612     EtwGCRootKind dwEtwRootKind;
613 #endif // GC_PROFILING || FEATURE_EVENT_TRACE
614 
ScanContextScanContext615     ScanContext()
616     {
617         LIMITED_METHOD_CONTRACT;
618 
619         thread_under_crawl = 0;
620         thread_number = -1;
621         stack_limit = 0;
622         promotion = FALSE;
623         concurrent = FALSE;
624 #ifdef GC_PROFILING
625         pMD = NULL;
626 #endif //GC_PROFILING
627 #ifdef FEATURE_EVENT_TRACE
628         dwEtwRootKind = kEtwGCRootKindOther;
629 #endif // FEATURE_EVENT_TRACE
630     }
631 };
632 
633 #endif // _GC_INTERFACE_H_
634