summaryrefslogtreecommitdiff
path: root/src/gc/gcinterface.dac.h
blob: 93698c05a9981fd09b24101e063f92bda3b8f7fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#ifndef _GC_INTERFACE_DAC_H_
#define _GC_INTERFACE_DAC_H_

// This file defines the interface between the GC and the DAC. The interface consists of two things:
//   1. A number of variables ("DAC vars") whose addresses are exposed to the DAC (see "struct GcDacVars")
//   2. A number of types that are analogues to GC-internal types. These types expose a subset of the
//      GC-internal type's fields, while still maintaining the same layout.
// This interface is strictly versioned, see gcinterface.dacvars.def for more information.

#define NUM_GC_DATA_POINTS              9
#define MAX_COMPACT_REASONS_COUNT       11
#define MAX_EXPAND_MECHANISMS_COUNT     6
#define MAX_GC_MECHANISM_BITS_COUNT     2
#define MAX_GLOBAL_GC_MECHANISMS_COUNT  6
#define NUMBERGENERATIONS               4
#define INITIAL_HANDLE_TABLE_ARRAY_SIZE 10
#define HANDLE_MAX_INTERNAL_TYPES       12

// Analogue for the GC heap_segment class, containing information regarding a single
// heap segment.
class dac_heap_segment {
public:
    uint8_t* allocated;
    uint8_t* committed;
    uint8_t* reserved;
    uint8_t* used;
    uint8_t* mem;
    size_t flags;
    DPTR(dac_heap_segment) next;
    uint8_t* background_allocated;
    class dac_gc_heap* heap;
};

// Analogue for the GC generation class, containing information about the start segment
// of a generation and its allocation context.
class dac_generation {
public:
    gc_alloc_context allocation_context;
    DPTR(dac_heap_segment) start_segment;
    uint8_t* allocation_start;
};

// Analogue for the GC CFinalize class, containing information about the finalize queue.
class dac_finalize_queue {
public:
    static const int ExtraSegCount = 2;
    uint8_t** m_FillPointers[NUMBERGENERATIONS + ExtraSegCount];
};

class dac_handle_table {
public:
    // On the handle table side, this is an ADIndex. They should still have
    // the same layout.
    //
    // We do try to keep everything that the DAC knows about as close to the
    // start of the struct as possible to avoid having padding members. However,
    // HandleTable has rgTypeFlags at offset 0 for performance reasons and
    // we don't want to disrupt that.
    uint32_t padding[HANDLE_MAX_INTERNAL_TYPES];
    DWORD uADIndex;
};

class dac_handle_table_bucket {
public:
    DPTR(DPTR(dac_handle_table)) pTable;
    uint32_t HandleTableIndex;
};

class dac_handle_table_map {
public:
    DPTR(DPTR(dac_handle_table_bucket)) pBuckets;
    DPTR(dac_handle_table_map) pNext;
    uint32_t dwMaxIndex;
};

// Possible values of the current_c_gc_state dacvar, indicating the state of
// a background GC.
enum c_gc_state
{
    c_gc_state_marking,
    c_gc_state_planning,
    c_gc_state_free
};

// Reasons why an OOM might occur, recorded in the oom_history
// struct below.
enum oom_reason
{
    oom_no_failure = 0,
    oom_budget = 1,
    oom_cant_commit = 2,
    oom_cant_reserve = 3,
    oom_loh = 4,
    oom_low_mem = 5,
    oom_unproductive_full_gc = 6
};

/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
/* If you modify failure_get_memory and         */
/* oom_reason be sure to make the corresponding */
/* changes in toolbox\sos\strike\strike.cpp.    */
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
enum failure_get_memory
{
    fgm_no_failure = 0,
    fgm_reserve_segment = 1,
    fgm_commit_segment_beg = 2,
    fgm_commit_eph_segment = 3,
    fgm_grow_table = 4,
    fgm_commit_table = 5
};

// A record of the last OOM that occured in the GC, with some
// additional information as to what triggered the OOM.
struct oom_history
{
    oom_reason reason;
    size_t alloc_size;
    uint8_t* reserved;
    uint8_t* allocated;
    size_t gc_index;
    failure_get_memory fgm;
    size_t size;
    size_t available_pagefile_mb;
    BOOL loh_p;
};

// Analogue for the GC gc_heap class, containing information regarding a single
// GC heap (of which there are multiple, with server GC).
class dac_gc_heap {
public:
    uint8_t* alloc_allocated;
    DPTR(dac_heap_segment) ephemeral_heap_segment;
    DPTR(dac_finalize_queue) finalize_queue;
    oom_history oom_info;
    size_t interesting_data_per_heap[NUM_GC_DATA_POINTS];
    size_t compact_reasons_per_heap[MAX_COMPACT_REASONS_COUNT];
    size_t expand_mechanisms_per_heap[MAX_EXPAND_MECHANISMS_COUNT];
    size_t interesting_mechanism_bits_per_heap[MAX_GC_MECHANISM_BITS_COUNT];
    uint8_t* internal_root_array;
    size_t internal_root_array_index;
    BOOL heap_analyze_success;

    // The generation table must always be last, because the size of this array
    // (stored inline in the gc_heap class) can vary.
    //
    // The size of the generation class is not part of the GC-DAC interface, 
    // despite being embedded by-value into the gc_heap class. The DAC variable
    // "generation_size" stores the size of the generation class, so the DAC can
    // use it and pointer arithmetic to calculate correct offsets into the generation
    // table. (See "GenerationTableIndex" function in the DAC for details)
    //
    // Also note that this array has length 1 because the C++ standard doesn't allow
    // for 0-length arrays, although every major compiler is willing to tolerate it.
    dac_generation generation_table[1];
};


// The DAC links against six symbols that build as part of the VM DACCESS_COMPILE
// build. These symbols are considered to be GC-private functions, but the DAC needs
// to use them in order to perform some handle-related functions. These six functions
// are adorned by this macro to make clear that their implementations must be versioned
// alongside the rest of this file.
//
// Practically, this macro ensures that the target symbols aren't mangled, since the
// DAC calls them with a signature slightly different than the one used when they
// were defined.
#define GC_DAC_VISIBLE

#ifdef DACCESS_COMPILE
#define GC_DAC_VISIBLE_NO_MANGLE extern "C"
#else
#define GC_DAC_VISIBLE_NO_MANGLE
#endif // DACCESS_COMPILE

// The actual structure containing the DAC variables. When DACCESS_COMPILE is not
// defined (i.e. the normal runtime build), this structure contains pointers to the
// GC's global DAC variabels. When DACCESS_COMPILE is defined (i.e. the DAC build),
// this structure contains __DPtrs for every DAC variable that will marshal values
// from the debugee process to the debugger process when dereferenced.
struct GcDacVars {
  uint8_t major_version_number;
  uint8_t minor_version_number;
  size_t generation_size;
#ifdef DACCESS_COMPILE
 #define GC_DAC_VAR(type, name)       DPTR(type) name;
 #define GC_DAC_PTR_VAR(type, name)   DPTR(type*) name;
 #define GC_DAC_ARRAY_VAR(type, name) DPTR(type) name;
#else
 #define GC_DAC_VAR(type, name) type *name;
#endif
#include "gcinterface.dacvars.def"
};

#endif // _GC_INTERFACE_DAC_H_