| 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 | |