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 _GCINTERFACE_EE_H_
6#define _GCINTERFACE_EE_H_
7
8enum EtwGCRootFlags
9{
10 kEtwGCRootFlagsPinning = 0x1,
11 kEtwGCRootFlagsWeakRef = 0x2,
12 kEtwGCRootFlagsInterior = 0x4,
13 kEtwGCRootFlagsRefCounted = 0x8,
14};
15
16enum EtwGCRootKind
17{
18 kEtwGCRootKindStack = 0,
19 kEtwGCRootKindFinalizer = 1,
20 kEtwGCRootKindHandle = 2,
21 kEtwGCRootKindOther = 3,
22};
23
24// This interface provides functions that the GC can use to fire events.
25// Events fired on this interface are split into two categories: "known"
26// events and "dynamic" events. Known events are events that are baked-in
27// to the hosting runtime's event manifest and are part of the GC/EE interface.
28// There is one callback on IGCToCLREventSink for each known event.
29//
30// Dynamic events are constructed at runtime by the GC and are not known
31// to the EE. ([LOCALGC TODO dynamic event implementation])
32class IGCToCLREventSink
33{
34public:
35 // Fires a dynamic event with the given event name and payload. Dynamic
36 // events are not known to the EE and are fired as an unschematized event
37 // to the underlying eventing implementation.
38 virtual
39 void FireDynamicEvent(
40 const char* eventName,
41 void* payload,
42 uint32_t payloadSize) = 0;
43 virtual
44 void FireGCStart_V2(uint32_t count, uint32_t depth, uint32_t reason, uint32_t type) = 0;
45
46 virtual
47 void FireGCEnd_V1(uint32_t count, uint32_t depth) = 0;
48
49 virtual
50 void FireGCGenerationRange(uint8_t generation, void* rangeStart, uint64_t rangeUsedLength, uint64_t rangeReservedLength) = 0;
51
52 virtual
53 void FireGCHeapStats_V1(
54 uint64_t generationSize0,
55 uint64_t totalPromotedSize0,
56 uint64_t generationSize1,
57 uint64_t totalPromotedSize1,
58 uint64_t generationSize2,
59 uint64_t totalPromotedSize2,
60 uint64_t generationSize3,
61 uint64_t totalPromotedSize3,
62 uint64_t finalizationPromotedSize,
63 uint64_t finalizationPromotedCount,
64 uint32_t pinnedObjectCount,
65 uint32_t sinkBlockCount,
66 uint32_t gcHandleCount) = 0;
67
68 virtual
69 void FireGCCreateSegment_V1(void* address, size_t size, uint32_t type) = 0;
70
71 virtual
72 void FireGCFreeSegment_V1(void* address) = 0;
73
74 virtual
75 void FireGCCreateConcurrentThread_V1() = 0;
76
77 virtual
78 void FireGCTerminateConcurrentThread_V1() = 0;
79
80 virtual
81 void FireGCTriggered(uint32_t reason) = 0;
82
83 virtual
84 void FireGCMarkWithType(uint32_t heapNum, uint32_t type, uint64_t bytes) = 0;
85
86 virtual
87 void FireGCJoin_V2(uint32_t heap, uint32_t joinTime, uint32_t joinType, uint32_t joinId) = 0;
88
89 virtual
90 void FireGCGlobalHeapHistory_V2(uint64_t finalYoungestDesired,
91 int32_t numHeaps,
92 uint32_t condemnedGeneration,
93 uint32_t gen0reductionCount,
94 uint32_t reason,
95 uint32_t globalMechanisms,
96 uint32_t pauseMode,
97 uint32_t memoryPressure) = 0;
98
99 virtual
100 void FireGCAllocationTick_V1(uint32_t allocationAmount, uint32_t allocationKind) = 0;
101
102 virtual
103 void FireGCAllocationTick_V3(uint64_t allocationAmount, uint32_t allocationKind, uint32_t heapIndex, void* objectAddress) = 0;
104
105 virtual
106 void FirePinObjectAtGCTime(void* object, uint8_t** ppObject) = 0;
107
108 virtual
109 void FirePinPlugAtGCTime(uint8_t* plug_start, uint8_t* plug_end, uint8_t* gapBeforeSize) = 0;
110
111 virtual
112 void FireGCPerHeapHistory_V3(void *freeListAllocated,
113 void *freeListRejected,
114 void *endOfSegAllocated,
115 void *condemnedAllocated,
116 void *pinnedAllocated,
117 void *pinnedAllocatedAdvance,
118 uint32_t runningFreeListEfficiency,
119 uint32_t condemnReasons0,
120 uint32_t condemnReasons1,
121 uint32_t compactMechanisms,
122 uint32_t expandMechanisms,
123 uint32_t heapIndex,
124 void *extraGen0Commit,
125 uint32_t count,
126 uint32_t valuesLen,
127 void *values) = 0;
128 virtual
129 void FireBGCBegin() = 0;
130 virtual
131 void FireBGC1stNonConEnd() = 0;
132 virtual
133 void FireBGC1stConEnd() = 0;
134 virtual
135 void FireBGC1stSweepEnd(uint32_t genNumber) = 0;
136 virtual
137 void FireBGC2ndNonConBegin() = 0;
138 virtual
139 void FireBGC2ndNonConEnd() = 0;
140 virtual
141 void FireBGC2ndConBegin() = 0;
142 virtual
143 void FireBGC2ndConEnd() = 0;
144 virtual
145 void FireBGCDrainMark(uint64_t objects) = 0;
146 virtual
147 void FireBGCRevisit(uint64_t pages, uint64_t objects, uint32_t isLarge) = 0;
148 virtual
149 void FireBGCOverflow(uint64_t min, uint64_t max, uint64_t objects, uint32_t isLarge) = 0;
150 virtual
151 void FireBGCAllocWaitBegin(uint32_t reason) = 0;
152 virtual
153 void FireBGCAllocWaitEnd(uint32_t reason) = 0;
154 virtual
155 void FireGCFullNotify_V1(uint32_t genNumber, uint32_t isAlloc) = 0;
156 virtual
157 void FireSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation, uint64_t appDomainID) = 0;
158 virtual
159 void FirePrvSetGCHandle(void *handleID, void *objectID, uint32_t kind, uint32_t generation, uint64_t appDomainID) = 0;
160 virtual
161 void FireDestroyGCHandle(void *handleID) = 0;
162 virtual
163 void FirePrvDestroyGCHandle(void *handleID) = 0;
164};
165
166// This interface provides the interface that the GC will use to speak to the rest
167// of the execution engine. Everything that the GC does that requires the EE
168// to be informed or that requires EE action must go through this interface.
169//
170// When BUILD_AS_STANDALONE is defined, this class is named IGCToCLR and is
171// an abstract class. The EE will provide a class that fulfills this interface,
172// and the GC will dispatch virtually on it to call into the EE. When BUILD_AS_STANDALONE
173// is not defined, this class is named GCToEEInterface and the GC will dispatch statically on it.
174class IGCToCLR {
175public:
176 // Suspends the EE for the given reason.
177 virtual
178 void SuspendEE(SUSPEND_REASON reason) = 0;
179
180 // Resumes all paused threads, with a boolean indicating
181 // if the EE is being restarted because a GC is complete.
182 virtual
183 void RestartEE(bool bFinishedGC) = 0;
184
185 // Performs a stack walk of all managed threads and invokes the given promote_func
186 // on all GC roots encountered on the stack. Depending on the condemned generation,
187 // this function may also enumerate all static GC refs if necessary.
188 virtual
189 void GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc) = 0;
190
191 // Callback from the GC informing the EE that it is preparing to start working.
192 virtual
193 void GcStartWork(int condemned, int max_gen) = 0;
194
195 // Callback from the GC informing the EE that it has completed the managed stack
196 // scan. User threads are still suspended at this point.
197 virtual
198 void AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc) = 0;
199
200 // Callback from the GC informing the EE that the background sweep phase of a BGC is
201 // about to begin.
202 virtual
203 void GcBeforeBGCSweepWork() = 0;
204
205 // Callback from the GC informing the EE that a GC has completed.
206 virtual
207 void GcDone(int condemned) = 0;
208
209 // Predicate for the GC to query whether or not a given refcounted handle should
210 // be promoted.
211 virtual
212 bool RefCountedHandleCallbacks(Object * pObject) = 0;
213
214 // Performs a weak pointer scan of the sync block cache.
215 virtual
216 void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2) = 0;
217
218 // Indicates to the EE that the GC intends to demote objects in the sync block cache.
219 virtual
220 void SyncBlockCacheDemote(int max_gen) = 0;
221
222 // Indicates to the EE that the GC has granted promotion to objects in the sync block cache.
223 virtual
224 void SyncBlockCachePromotionsGranted(int max_gen) = 0;
225
226 virtual
227 uint32_t GetActiveSyncBlockCount() = 0;
228
229 // Queries whether or not the current thread has preemptive GC disabled.
230 virtual
231 bool IsPreemptiveGCDisabled() = 0;
232
233 // Enables preemptive GC on the current thread. Returns true if the thread mode
234 // was changed and false if the thread mode wasn't changed or the thread is not
235 // a managed thread.
236 virtual
237 bool EnablePreemptiveGC() = 0;
238
239 // Disables preemptive GC on the current thread.
240 virtual
241 void DisablePreemptiveGC() = 0;
242
243 // Gets the Thread instance for the current thread, or null if no thread
244 // instance is associated with this thread.
245 //
246 // If the GC created the current thread, GetThread returns null for threads
247 // that were not created as suspendable (see `IGCHeap::CreateThread`).
248 virtual
249 Thread* GetThread() = 0;
250
251 // Retrieves the alloc context associated with the current thread.
252 virtual
253 gc_alloc_context * GetAllocContext() = 0;
254
255 // Calls the given enum_alloc_context_func with every active alloc context.
256 virtual
257 void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param) = 0;
258
259 // Get the Allocator for objects from collectible assemblies
260 virtual
261 uint8_t* GetLoaderAllocatorObjectForGC(Object* pObject) = 0;
262
263 // Creates and returns a new thread.
264 // Parameters:
265 // threadStart - The function that will serve as the thread stub for the
266 // new thread. It will be invoked immediately upon the
267 // new thread upon creation.
268 // arg - The argument that will be passed verbatim to threadStart.
269 // is_suspendable - Whether or not the thread that is created should be suspendable
270 // from a runtime perspective. Threads that are suspendable have
271 // a VM Thread object associated with them that can be accessed
272 // using `IGCHeap::GetThread`.
273 // name - The name of this thread, optionally used for diagnostic purposes.
274 // Returns:
275 // true if the thread was started successfully, false if not.
276 virtual
277 bool CreateThread(void (*threadStart)(void*), void* arg, bool is_suspendable, const char* name) = 0;
278
279 // When a GC starts, gives the diagnostics code a chance to run.
280 virtual
281 void DiagGCStart(int gen, bool isInduced) = 0;
282
283 // When GC heap segments change, gives the diagnostics code a chance to run.
284 virtual
285 void DiagUpdateGenerationBounds() = 0;
286
287 // When a GC ends, gives the diagnostics code a chance to run.
288 virtual
289 void DiagGCEnd(size_t index, int gen, int reason, bool fConcurrent) = 0;
290
291 // During a GC after we discover what objects' finalizers should run, gives the diagnostics code a chance to run.
292 virtual
293 void DiagWalkFReachableObjects(void* gcContext) = 0;
294
295 // During a GC after we discover the survivors and the relocation info,
296 // gives the diagnostics code a chance to run. This includes LOH if we are
297 // compacting LOH.
298 virtual
299 void DiagWalkSurvivors(void* gcContext) = 0;
300
301 // During a full GC after we discover what objects to survive on LOH,
302 // gives the diagnostics code a chance to run.
303 virtual
304 void DiagWalkLOHSurvivors(void* gcContext) = 0;
305
306 // At the end of a background GC, gives the diagnostics code a chance to run.
307 virtual
308 void DiagWalkBGCSurvivors(void* gcContext) = 0;
309
310 // Informs the EE of changes to the location of the card table, potentially updating the write
311 // barrier if it needs to be updated.
312 virtual
313 void StompWriteBarrier(WriteBarrierParameters* args) = 0;
314
315 // Signals to the finalizer thread that there are objects ready to
316 // be finalized.
317 virtual
318 void EnableFinalization(bool foundFinalizers) = 0;
319
320 // Signals to the EE that the GC encountered a fatal error and can't recover.
321 virtual
322 void HandleFatalError(unsigned int exitCode) = 0;
323
324 // Asks the EE if it wants a particular object to be finalized when unloading
325 // an app domain.
326 virtual
327 bool ShouldFinalizeObjectForUnload(void* pDomain, Object* obj) = 0;
328
329 // Offers the EE the option to finalize the given object eagerly, i.e.
330 // not on the finalizer thread but on the current thread. The
331 // EE returns true if it finalized the object eagerly and the GC does not
332 // need to do so, and false if it chose not to eagerly finalize the object
333 // and it's up to the GC to finalize it later.
334 virtual
335 bool EagerFinalized(Object* obj) = 0;
336
337 // Retrieves the method table for the free object, a special kind of object used by the GC
338 // to keep the heap traversable. Conceptually, the free object is similar to a managed array
339 // of bytes: it consists of an object header (like all objects) and a "numComponents" field,
340 // followed by some number of bytes of space that's free on the heap.
341 //
342 // The free object allows the GC to traverse the heap because it can inspect the numComponents
343 // field to see how many bytes to skip before the next object on a heap segment begins.
344 virtual
345 MethodTable* GetFreeObjectMethodTable() = 0;
346
347 // Asks the EE for the value of a given configuration key. If the EE does not know or does not
348 // have a value for the requeested config key, false is returned and the value of the passed-in
349 // pointer is undefined. Otherwise, true is returned and the config key's value is written to
350 // the passed-in pointer.
351 virtual
352 bool GetBooleanConfigValue(const char* key, bool* value) = 0;
353
354 virtual
355 bool GetIntConfigValue(const char* key, int64_t* value) = 0;
356
357 virtual
358 bool GetStringConfigValue(const char* key, const char** value) = 0;
359
360 virtual
361 void FreeStringConfigValue(const char* value) = 0;
362
363 // Returns true if this thread is a "GC thread", or a thread capable of
364 // doing GC work. Threads are either /always/ GC threads
365 // (if they were created for this purpose - background GC threads
366 // and server GC threads) or they became GC threads by suspending the EE
367 // and initiating a collection.
368 virtual
369 bool IsGCThread() = 0;
370
371 // Returns true if the current thread is either a background GC thread
372 // or a server GC thread.
373 virtual
374 bool WasCurrentThreadCreatedByGC() = 0;
375
376 // Given an object, if this object is an instance of `System.Threading.OverlappedData`,
377 // and the runtime treats instances of this class specially, traverses the objects that
378 // are directly or (once) indirectly pinned by this object and reports them to the GC for
379 // the purposes of relocation and promotion.
380 //
381 // Overlapped objects are very special and as such the objects they wrap can't be promoted in
382 // the same manner as normal objects. This callback gives the EE the opportunity to hide these
383 // details, if they are implemented at all.
384 //
385 // This function is a no-op if "object" is not an OverlappedData object.
386 virtual
387 void WalkAsyncPinnedForPromotion(Object* object, ScanContext* sc, promote_func* callback) = 0;
388
389 // Given an object, if this object is an instance of `System.Threading.OverlappedData` and the
390 // runtime treats instances of this class specially, traverses the objects that are directly
391 // or once indirectly pinned by this object and invokes the given callback on them. The callback
392 // is passed the following arguments:
393 // Object* "from" - The object that "caused" the "to" object to be pinned. If a single object
394 // is pinned directly by this OverlappedData, this object will be the
395 // OverlappedData object itself. If an array is pinned by this OverlappedData,
396 // this object will be the pinned array.
397 // Object* "to" - The object that is pinned by the "from" object. If a single object is pinned
398 // by an OverlappedData, "to" will be that single object. If an array is pinned
399 // by an OverlappedData, the callback will be invoked on all elements of that
400 // array and each element will be a "to" object.
401 // void* "context" - Passed verbatim from "WalkOverlappedObject" to the callback function.
402 // The "context" argument will be passed directly to the callback without modification or inspection.
403 //
404 // This function is a no-op if "object" is not an OverlappedData object.
405 virtual
406 void WalkAsyncPinned(Object* object, void* context, void(*callback)(Object*, Object*, void*)) = 0;
407
408 // Returns an IGCToCLREventSink instance that can be used to fire events.
409 virtual
410 IGCToCLREventSink* EventSink() = 0;
411
412 virtual
413 uint32_t GetDefaultDomainIndex() = 0;
414
415 virtual
416 void *GetAppDomainAtIndex(uint32_t appDomainIndex) = 0;
417
418 virtual
419 uint32_t GetIndexOfAppDomainBeingUnloaded() = 0;
420
421 virtual
422 bool AppDomainCanAccessHandleTable(uint32_t appDomainID) = 0;
423
424 virtual
425 uint32_t GetTotalNumSizedRefHandles() = 0;
426
427 virtual
428 bool AppDomainIsRudeUnload(void *appDomain) = 0;
429
430 virtual
431 bool AnalyzeSurvivorsRequested(int condemnedGeneration) = 0;
432
433 virtual
434 void AnalyzeSurvivorsFinished(int condemnedGeneration) = 0;
435
436 virtual
437 void VerifySyncTableEntry() = 0;
438};
439
440#endif // _GCINTERFACE_EE_H_
441