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_DAC_H_ |
6 | #define _GC_INTERFACE_DAC_H_ |
7 | |
8 | // This file defines the interface between the GC and the DAC. The interface consists of two things: |
9 | // 1. A number of variables ("DAC vars") whose addresses are exposed to the DAC (see "struct GcDacVars") |
10 | // 2. A number of types that are analogues to GC-internal types. These types expose a subset of the |
11 | // GC-internal type's fields, while still maintaining the same layout. |
12 | // This interface is strictly versioned, see gcinterface.dacvars.def for more information. |
13 | |
14 | #define NUM_GC_DATA_POINTS 9 |
15 | #define MAX_COMPACT_REASONS_COUNT 11 |
16 | #define MAX_EXPAND_MECHANISMS_COUNT 6 |
17 | #define MAX_GC_MECHANISM_BITS_COUNT 2 |
18 | #define MAX_GLOBAL_GC_MECHANISMS_COUNT 6 |
19 | #define NUMBERGENERATIONS 4 |
20 | #define INITIAL_HANDLE_TABLE_ARRAY_SIZE 10 |
21 | #define HANDLE_MAX_INTERNAL_TYPES 12 |
22 | |
23 | // Analogue for the GC heap_segment class, containing information regarding a single |
24 | // heap segment. |
25 | class dac_heap_segment { |
26 | public: |
27 | uint8_t* allocated; |
28 | uint8_t* committed; |
29 | uint8_t* reserved; |
30 | uint8_t* used; |
31 | uint8_t* mem; |
32 | size_t flags; |
33 | DPTR(dac_heap_segment) next; |
34 | uint8_t* background_allocated; |
35 | class dac_gc_heap* heap; |
36 | }; |
37 | |
38 | // Analogue for the GC generation class, containing information about the start segment |
39 | // of a generation and its allocation context. |
40 | class dac_generation { |
41 | public: |
42 | gc_alloc_context allocation_context; |
43 | DPTR(dac_heap_segment) start_segment; |
44 | uint8_t* allocation_start; |
45 | }; |
46 | |
47 | // Analogue for the GC CFinalize class, containing information about the finalize queue. |
48 | class dac_finalize_queue { |
49 | public: |
50 | static const int = 2; |
51 | uint8_t** m_FillPointers[NUMBERGENERATIONS + ExtraSegCount]; |
52 | }; |
53 | |
54 | class dac_handle_table { |
55 | public: |
56 | // On the handle table side, this is an ADIndex. They should still have |
57 | // the same layout. |
58 | // |
59 | // We do try to keep everything that the DAC knows about as close to the |
60 | // start of the struct as possible to avoid having padding members. However, |
61 | // HandleTable has rgTypeFlags at offset 0 for performance reasons and |
62 | // we don't want to disrupt that. |
63 | uint32_t padding[HANDLE_MAX_INTERNAL_TYPES]; |
64 | DWORD uADIndex; |
65 | }; |
66 | |
67 | class dac_handle_table_bucket { |
68 | public: |
69 | DPTR(DPTR(dac_handle_table)) pTable; |
70 | uint32_t HandleTableIndex; |
71 | }; |
72 | |
73 | class dac_handle_table_map { |
74 | public: |
75 | DPTR(DPTR(dac_handle_table_bucket)) pBuckets; |
76 | DPTR(dac_handle_table_map) pNext; |
77 | uint32_t dwMaxIndex; |
78 | }; |
79 | |
80 | // Possible values of the current_c_gc_state dacvar, indicating the state of |
81 | // a background GC. |
82 | enum c_gc_state |
83 | { |
84 | c_gc_state_marking, |
85 | c_gc_state_planning, |
86 | c_gc_state_free |
87 | }; |
88 | |
89 | // Reasons why an OOM might occur, recorded in the oom_history |
90 | // struct below. |
91 | enum oom_reason |
92 | { |
93 | oom_no_failure = 0, |
94 | oom_budget = 1, |
95 | oom_cant_commit = 2, |
96 | oom_cant_reserve = 3, |
97 | oom_loh = 4, |
98 | oom_low_mem = 5, |
99 | oom_unproductive_full_gc = 6 |
100 | }; |
101 | |
102 | /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ |
103 | /* If you modify failure_get_memory and */ |
104 | /* oom_reason be sure to make the corresponding */ |
105 | /* changes in toolbox\sos\strike\strike.cpp. */ |
106 | /*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ |
107 | enum failure_get_memory |
108 | { |
109 | fgm_no_failure = 0, |
110 | fgm_reserve_segment = 1, |
111 | fgm_commit_segment_beg = 2, |
112 | fgm_commit_eph_segment = 3, |
113 | fgm_grow_table = 4, |
114 | fgm_commit_table = 5 |
115 | }; |
116 | |
117 | // A record of the last OOM that occured in the GC, with some |
118 | // additional information as to what triggered the OOM. |
119 | struct oom_history |
120 | { |
121 | oom_reason reason; |
122 | size_t alloc_size; |
123 | uint8_t* reserved; |
124 | uint8_t* allocated; |
125 | size_t gc_index; |
126 | failure_get_memory fgm; |
127 | size_t size; |
128 | size_t available_pagefile_mb; |
129 | BOOL loh_p; |
130 | }; |
131 | |
132 | // Analogue for the GC gc_heap class, containing information regarding a single |
133 | // GC heap (of which there are multiple, with server GC). |
134 | class dac_gc_heap { |
135 | public: |
136 | uint8_t* alloc_allocated; |
137 | DPTR(dac_heap_segment) ephemeral_heap_segment; |
138 | DPTR(dac_finalize_queue) finalize_queue; |
139 | oom_history oom_info; |
140 | size_t interesting_data_per_heap[NUM_GC_DATA_POINTS]; |
141 | size_t compact_reasons_per_heap[MAX_COMPACT_REASONS_COUNT]; |
142 | size_t expand_mechanisms_per_heap[MAX_EXPAND_MECHANISMS_COUNT]; |
143 | size_t interesting_mechanism_bits_per_heap[MAX_GC_MECHANISM_BITS_COUNT]; |
144 | uint8_t* internal_root_array; |
145 | size_t internal_root_array_index; |
146 | BOOL heap_analyze_success; |
147 | |
148 | // The generation table must always be last, because the size of this array |
149 | // (stored inline in the gc_heap class) can vary. |
150 | // |
151 | // The size of the generation class is not part of the GC-DAC interface, |
152 | // despite being embedded by-value into the gc_heap class. The DAC variable |
153 | // "generation_size" stores the size of the generation class, so the DAC can |
154 | // use it and pointer arithmetic to calculate correct offsets into the generation |
155 | // table. (See "GenerationTableIndex" function in the DAC for details) |
156 | // |
157 | // Also note that this array has length 1 because the C++ standard doesn't allow |
158 | // for 0-length arrays, although every major compiler is willing to tolerate it. |
159 | dac_generation generation_table[1]; |
160 | }; |
161 | |
162 | |
163 | // The DAC links against six symbols that build as part of the VM DACCESS_COMPILE |
164 | // build. These symbols are considered to be GC-private functions, but the DAC needs |
165 | // to use them in order to perform some handle-related functions. These six functions |
166 | // are adorned by this macro to make clear that their implementations must be versioned |
167 | // alongside the rest of this file. |
168 | // |
169 | // Practically, this macro ensures that the target symbols aren't mangled, since the |
170 | // DAC calls them with a signature slightly different than the one used when they |
171 | // were defined. |
172 | #define GC_DAC_VISIBLE |
173 | |
174 | #ifdef DACCESS_COMPILE |
175 | #define GC_DAC_VISIBLE_NO_MANGLE extern "C" |
176 | #else |
177 | #define GC_DAC_VISIBLE_NO_MANGLE |
178 | #endif // DACCESS_COMPILE |
179 | |
180 | // The actual structure containing the DAC variables. When DACCESS_COMPILE is not |
181 | // defined (i.e. the normal runtime build), this structure contains pointers to the |
182 | // GC's global DAC variabels. When DACCESS_COMPILE is defined (i.e. the DAC build), |
183 | // this structure contains __DPtrs for every DAC variable that will marshal values |
184 | // from the debugee process to the debugger process when dereferenced. |
185 | struct GcDacVars { |
186 | uint8_t major_version_number; |
187 | uint8_t minor_version_number; |
188 | size_t generation_size; |
189 | #ifdef DACCESS_COMPILE |
190 | #define GC_DAC_VAR(type, name) DPTR(type) name; |
191 | #define GC_DAC_PTR_VAR(type, name) DPTR(type*) name; |
192 | #define GC_DAC_ARRAY_VAR(type, name) DPTR(type) name; |
193 | #else |
194 | #define GC_DAC_VAR(type, name) type *name; |
195 | #endif |
196 | #include "gcinterface.dacvars.def" |
197 | }; |
198 | |
199 | #endif // _GC_INTERFACE_DAC_H_ |
200 | |