HRESULT
ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
{
+ // Make sure ClrDataAccess::ServerGCHeapDetails() is updated as well.
if (detailsData == NULL)
+ {
return E_INVALIDARG;
+ }
SOSDacEnter();
+ detailsData->heapAddr = NULL;
+
detailsData->lowest_address = PTR_CDADDR(g_lowest_address);
detailsData->highest_address = PTR_CDADDR(g_highest_address);
- detailsData->card_table = PTR_CDADDR(g_card_table);
- detailsData->heapAddr = NULL;
+ detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;
+
detailsData->alloc_allocated = (CLRDATA_ADDRESS)*g_gcDacGlobals->alloc_allocated;
detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)*g_gcDacGlobals->ephemeral_heap_segment;
+ detailsData->card_table = PTR_CDADDR(g_card_table);
detailsData->mark_array = (CLRDATA_ADDRESS)*g_gcDacGlobals->mark_array;
- detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;
detailsData->next_sweep_obj = (CLRDATA_ADDRESS)*g_gcDacGlobals->next_sweep_obj;
if (g_gcDacGlobals->saved_sweep_ephemeral_seg != nullptr)
{
detailsData->background_saved_lowest_address = (CLRDATA_ADDRESS)*g_gcDacGlobals->background_saved_lowest_address;
detailsData->background_saved_highest_address = (CLRDATA_ADDRESS)*g_gcDacGlobals->background_saved_highest_address;
- for (unsigned int i=0; i < *g_gcDacGlobals->max_gen + 2; i++)
+ // get bounds for the different generations
+ for (unsigned int i=0; i < DAC_NUMBERGENERATIONS; i++)
{
DPTR(dac_generation) generation = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS) dac_cast<TADDR>(generation->start_segment);
-
detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS) generation->allocation_start;
-
DPTR(gc_alloc_context) alloc_context = dac_cast<TADDR>(generation) + offsetof(dac_generation, allocation_context);
detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)alloc_context->alloc_ptr;
detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)alloc_context->alloc_limit;
{
DPTR(dac_finalize_queue) fq = Dereference(g_gcDacGlobals->finalize_queue);
DPTR(uint8_t*) fillPointersTable = dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers);
- for (unsigned int i = 0; i<(*g_gcDacGlobals->max_gen + 2 + dac_finalize_queue::ExtraSegCount); i++)
+ for (unsigned int i = 0; i < DAC_NUMBERGENERATIONS + 3; i++)
{
detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS)*TableIndex(fillPointersTable, i, sizeof(uint8_t*));
}
}
else
{
- DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
+ TADDR heapAddress = TO_TADDR(heapAddr);
- if (pHeap.IsValid())
+ if (heapAddress != 0)
{
for (unsigned int i = 0; i < numGenerationTableEntries; ++i)
{
- DPTR(dac_generation) generation = ServerGenerationTableIndex(pHeap, i);
+ DPTR(dac_generation) generation = ServerGenerationTableIndex(heapAddress, i);
pGenerationData[i].start_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(generation->start_segment);
pGenerationData[i].allocation_start = (CLRDATA_ADDRESS)(ULONG_PTR)generation->allocation_start;
DPTR(gc_alloc_context) alloc_context = dac_cast<TADDR>(generation) + offsetof(dac_generation, allocation_context);
}
else
{
- DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
-
- if (pHeap.IsValid())
+ TADDR heapAddress = TO_TADDR(heapAddr);
+ if (heapAddress != 0)
{
+ dac_gc_heap heap = LoadGcHeapData(heapAddress);
+ dac_gc_heap* pHeap = &heap;
DPTR(dac_finalize_queue) fq = pHeap->finalize_queue;
DPTR(uint8_t*) pFillPointerArray= dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers);
for (unsigned int i = 0; i < numFillPointers; ++i)
return __DPtr<T>(ptr_base);
}
+// Indexes into the global heap table, returning a TADDR to the requested
+// heap instance.
+inline TADDR
+HeapTableIndex(DPTR(opaque_gc_heap**) heaps, size_t index)
+{
+ DPTR(opaque_gc_heap*) heap_table = Dereference(heaps);
+ DPTR(opaque_gc_heap*) ptr = TableIndex(heap_table, index, sizeof(void*));
+ return Dereference(ptr).GetAddr();
+}
+
// Indexes into a given generation table, returning a DPTR to the
// requested element (the element at the given index) of the table.
inline DPTR(dac_generation)
return TableIndex(base, index, g_gcDacGlobals->generation_size);
}
+// Starting .NET 6, it is possible for the gc_heap object to have different layouts
+// for coreclr.dll and clrgc.dll. Instead of using assuming dac_gc_heap and gc_heap
+// have identical layout, we have the gc exported an array of field offsets instead.
+// These offsets could be -1, indicating the field does not exist in the current
+// gc_heap being used.
+
+// field_offset = g_gcDacGlobals->gc_heap_field_offsets
+// p_field_offset = field_offset[field_index]
+// p_field = heap + p_field_offset
+// field_index++
+#define LOAD_BASE(field_name, field_type) \
+ DPTR(int) p_##field_name##_offset = TableIndex(field_offsets, field_index, sizeof(int)); \
+ int field_name##_offset = *p_##field_name##_offset; \
+ DPTR(field_type) p_##field_name = heap + field_name##_offset; \
+ field_index++;
+
+// if (field_offset != -1)
+// result.field = *p_field
+#define LOAD(field_name, field_type) \
+ LOAD_BASE(field_name, field_type) \
+ if (field_name##_offset != -1) \
+ { \
+ field_type field_name = *p_##field_name; \
+ result.field_name = field_name; \
+ }
+
+// if (field_offset != -1)
+// result.field = DPTR(field_type)field_name
+#define LOAD_DPTR(field_name, field_type) \
+ LOAD_BASE(field_name, field_type*) \
+ if (field_name##_offset != -1) \
+ { \
+ field_type* field_name = *p_##field_name; \
+ result.field_name = DPTR(field_type)((TADDR)field_name); \
+ }
+
+// if (field_offset != -1)
+// for i from 0 to array_length - 1
+// result.field[i] = *p_field
+// p_field = p_field + 1
+#define LOAD_ARRAY(field_name, field_type, array_length) \
+ LOAD_BASE(field_name, field_type) \
+ if (field_name##_offset != -1) \
+ { \
+ for (int i = 0; i < array_length; i++) \
+ { \
+ result.field_name[i] = *p_##field_name; \
+ p_##field_name = p_##field_name + 1; \
+ } \
+ }
+
// Indexes into a heap's generation table, given the heap instance
// and the desired index. Returns a DPTR to the requested element.
inline DPTR(dac_generation)
-ServerGenerationTableIndex(DPTR(dac_gc_heap) heap, size_t index)
+ServerGenerationTableIndex(TADDR heap, size_t index)
{
- TADDR base_addr = dac_cast<TADDR>(heap) + offsetof(dac_gc_heap, generation_table);
- DPTR(dac_generation) base = __DPtr<dac_generation>(base_addr);
- return TableIndex(base, index, g_gcDacGlobals->generation_size);
+ DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
+ int field_index = GENERATION_TABLE_FIELD_INDEX;
+ LOAD_BASE (generation_table, dac_generation);
+ assert (generation_table_offset != -1);
+ return TableIndex(p_generation_table, index, g_gcDacGlobals->generation_size);
}
-// Indexes into the global heap table, returning a DPTR to the requested
-// heap instance.
-inline DPTR(dac_gc_heap)
-HeapTableIndex(DPTR(dac_gc_heap**) heaps, size_t index)
+// Load an instance of dac_gc_heap for the heap pointed by heap.
+// Fields that does not exist in the current gc_heap instance is zero initialized.
+// Return the dac_gc_heap object.
+inline dac_gc_heap
+LoadGcHeapData(TADDR heap)
{
- DPTR(dac_gc_heap*) heap_table = Dereference(heaps);
- DPTR(dac_gc_heap*) ptr = TableIndex(heap_table, index, sizeof(dac_gc_heap*));
- return Dereference(ptr);
+ dac_gc_heap result;
+ memset(&result, 0, sizeof(dac_gc_heap));
+
+ DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
+ int field_index = 0;
+
+#define ALL_FIELDS
+#define DEFINE_FIELD(field_name, field_type) LOAD(field_name, field_type)
+#define DEFINE_DPTR_FIELD(field_name, field_type) LOAD_DPTR(field_name, field_type)
+#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) LOAD_ARRAY(field_name, field_type, array_length);
+
+#include "../../gc/gc_typefields.h"
+
+#undef DEFINE_ARRAY_FIELD
+#undef DEFINE_DPTR_FIELD
+#undef DEFINE_FIELD
+#undef ALL_FIELDS
+
+ return result;
}
+#undef LOAD_ARRAY
+#undef LOAD_DPTR
+#undef LOAD
+#undef LOAD_BASE
+
#endif // _REQUEST_COMMON_H_
// heap addresses.
for (int i = 0; i < GCHeapCount(); i++)
{
- pGCHeaps[i] = (CLRDATA_ADDRESS)HeapTableIndex(g_gcDacGlobals->g_heaps, i).GetAddr();
+ pGCHeaps[i] = (CLRDATA_ADDRESS)HeapTableIndex(g_gcDacGlobals->g_heaps, i);
}
return S_OK;
for (unsigned int n=0; n < heaps; n++)
{
- DPTR(dac_gc_heap) pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, n);
+ TADDR pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, n);
for (int i=0;i<NUMBERGENERATIONS;i++)
{
dac_generation generation = *ServerGenerationTableIndex(pHeap, i);
return S_OK;
}
-HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapDetails *detailsData)
+HRESULT
+ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapDetails *detailsData)
{
+ // Make sure ClrDataAccess::GetGCHeapStaticData() is updated as well.
if (!heapAddr)
{
// PREfix.
return E_INVALIDARG;
}
+ if (detailsData == NULL)
+ {
+ return E_INVALIDARG;
+ }
- DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
- int i;
+ TADDR heapAddress = TO_TADDR(heapAddr);
+ dac_gc_heap heap = LoadGcHeapData(heapAddress);
+ dac_gc_heap* pHeap = &heap;
//get global information first
detailsData->heapAddr = heapAddr;
detailsData->lowest_address = PTR_CDADDR(g_lowest_address);
detailsData->highest_address = PTR_CDADDR(g_highest_address);
- detailsData->card_table = PTR_CDADDR(g_card_table);
+ detailsData->current_c_gc_state = (CLRDATA_ADDRESS)*g_gcDacGlobals->current_c_gc_state;
// now get information specific to this heap (server mode gives us several heaps; we're getting
// information about only one of them.
detailsData->alloc_allocated = (CLRDATA_ADDRESS)pHeap->alloc_allocated;
detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(pHeap->ephemeral_heap_segment);
+ detailsData->card_table = (CLRDATA_ADDRESS)pHeap->card_table;
+ detailsData->mark_array = (CLRDATA_ADDRESS)pHeap->mark_array;
+ detailsData->next_sweep_obj = (CLRDATA_ADDRESS)pHeap->next_sweep_obj;
+ if (pHeap->saved_sweep_ephemeral_seg.IsValid())
+ {
+ detailsData->saved_sweep_ephemeral_seg = (CLRDATA_ADDRESS)dac_cast<TADDR>(pHeap->saved_sweep_ephemeral_seg);
+ detailsData->saved_sweep_ephemeral_start = (CLRDATA_ADDRESS)*pHeap->saved_sweep_ephemeral_start;
+ }
+ else
+ {
+ // with regions, we don't have these variables anymore
+ // use special value -1 in saved_sweep_ephemeral_seg to signal the region case
+ detailsData->saved_sweep_ephemeral_seg = (CLRDATA_ADDRESS)-1;
+ detailsData->saved_sweep_ephemeral_start = 0;
+ }
+ detailsData->background_saved_lowest_address = (CLRDATA_ADDRESS)pHeap->background_saved_lowest_address;
+ detailsData->background_saved_highest_address = (CLRDATA_ADDRESS)pHeap->background_saved_highest_address;
// get bounds for the different generations
- for (i=0; i<NUMBERGENERATIONS; i++)
+ for (unsigned int i=0; i < DAC_NUMBERGENERATIONS; i++)
{
- DPTR(dac_generation) generation = ServerGenerationTableIndex(pHeap, i);
+ DPTR(dac_generation) generation = ServerGenerationTableIndex(heapAddress, i);
detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(generation->start_segment);
detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS)(ULONG_PTR)generation->allocation_start;
DPTR(gc_alloc_context) alloc_context = dac_cast<TADDR>(generation) + offsetof(dac_generation, allocation_context);
}
DPTR(dac_finalize_queue) fq = pHeap->finalize_queue;
- DPTR(uint8_t*) pFillPointerArray= dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers);
- for(i=0; i<(NUMBERGENERATIONS+dac_finalize_queue::ExtraSegCount); i++)
+ if (fq.IsValid())
{
- detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pFillPointerArray[i];
+ DPTR(uint8_t*) fillPointersTable = dac_cast<TADDR>(fq) + offsetof(dac_finalize_queue, m_FillPointers);
+ for (unsigned int i = 0; i < DAC_NUMBERGENERATIONS + 3; i++)
+ {
+ detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS)*TableIndex(fillPointersTable, i, sizeof(uint8_t*));
+ }
}
return S_OK;
HRESULT
ClrDataAccess::ServerOomData(CLRDATA_ADDRESS addr, DacpOomData *oomData)
{
- DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(addr));
+ TADDR heapAddress = TO_TADDR(addr);
+ dac_gc_heap heap = LoadGcHeapData(heapAddress);
+ dac_gc_heap* pHeap = &heap;
oom_history pOOMInfo = pHeap->oom_info;
oomData->reason = pOOMInfo.reason;
return E_INVALIDARG;
}
- DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
+ TADDR heapAddress = TO_TADDR(heapAddr);
+ dac_gc_heap heap = LoadGcHeapData(heapAddress);
+ dac_gc_heap* pHeap = &heap;
analyzeData->heapAddr = heapAddr;
analyzeData->internal_root_array = (CLRDATA_ADDRESS)pHeap->internal_root_array;
for (int i = 0; i < heaps; i++)
{
- DPTR(dac_gc_heap) pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
+ TADDR heapAddress = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
+ dac_gc_heap heap = LoadGcHeapData(heapAddress);
+ dac_gc_heap* pHeap = &heap;
size_t gen_table_size = g_gcDacGlobals->generation_size * (*g_gcDacGlobals->max_gen + 2);
DacEnumMemoryRegion(dac_cast<TADDR>(pHeap), sizeof(dac_gc_heap));
// this is the convention in the GC so it is repeated here
for (ULONG i = *g_gcDacGlobals->max_gen; i <= *g_gcDacGlobals->max_gen +1; i++)
{
- DPTR(dac_heap_segment) seg = ServerGenerationTableIndex(pHeap, i)->start_segment;
+ DPTR(dac_heap_segment) seg = ServerGenerationTableIndex(heapAddress, i)->start_segment;
while (seg)
{
DacEnumMemoryRegion(PTR_HOST_TO_TADDR(seg), sizeof(dac_heap_segment));
for (int i = 0; i < heaps; ++i)
{
// Basic heap info.
- DPTR(dac_gc_heap) heap = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
- dac_generation gen0 = *ServerGenerationTableIndex(heap, 0);
- dac_generation gen1 = *ServerGenerationTableIndex(heap, 1);
- dac_generation gen2 = *ServerGenerationTableIndex(heap, 2);
- dac_generation loh = *ServerGenerationTableIndex(heap, 3);
- dac_generation poh = *ServerGenerationTableIndex(heap, 4);
+ TADDR heapAddress = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
+ dac_gc_heap heap = LoadGcHeapData(heapAddress);
+ dac_gc_heap* pHeap = &heap;
+ dac_generation gen0 = *ServerGenerationTableIndex(heapAddress, 0);
+ dac_generation gen1 = *ServerGenerationTableIndex(heapAddress, 1);
+ dac_generation gen2 = *ServerGenerationTableIndex(heapAddress, 2);
+ dac_generation loh = *ServerGenerationTableIndex(heapAddress, 3);
+ dac_generation poh = *ServerGenerationTableIndex(heapAddress, 4);
pHeaps[i].YoungestGenPtr = (CORDB_ADDRESS)gen0.allocation_context.alloc_ptr;
pHeaps[i].YoungestGenLimit = (CORDB_ADDRESS)gen0.allocation_context.alloc_limit;
pHeaps[i].Gen0Start = (CORDB_ADDRESS)gen0.allocation_start;
- pHeaps[i].Gen0End = (CORDB_ADDRESS)heap->alloc_allocated;
+ pHeaps[i].Gen0End = (CORDB_ADDRESS)pHeap->alloc_allocated;
pHeaps[i].Gen1Start = (CORDB_ADDRESS)gen1.allocation_start;
// Segments
for (; seg && (j < count); ++j)
{
pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
- if (seg.GetAddr() == heap->ephemeral_heap_segment.GetAddr())
+ if (seg.GetAddr() == pHeap->ephemeral_heap_segment.GetAddr())
{
- pHeaps[i].Segments[j].End = (CORDB_ADDRESS)heap->alloc_allocated;
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)pHeap->alloc_allocated;
pHeaps[i].EphemeralSegment = j;
pHeaps[i].Segments[j].Generation = 1;
}
void PopulateDacVars(GcDacVars *gcDacVars)
{
#ifndef DACCESS_COMPILE
+
+#ifdef MULTIPLE_HEAPS
+ static int gc_heap_field_offsets[] = {
+
+#define DEFINE_FIELD(field_name, field_type) offsetof(gc_heap, field_name),
+#define DEFINE_DPTR_FIELD(field_name, field_type) offsetof(gc_heap, field_name),
+#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) offsetof(gc_heap, field_name),
+#define DEFINE_MISSING_FIELD -1,
+
+#include "gc_typefields.h"
+
+#undef DEFINE_MISSING_FIELD
+#undef DEFINE_ARRAY_FIELD
+#undef DEFINE_DPTR_FIELD
+#undef DEFINE_FIELD
+
+ offsetof(gc_heap, generation_table)
+ };
+ static_assert(sizeof(gc_heap_field_offsets) == (GENERATION_TABLE_FIELD_INDEX + 1) * sizeof(int), "GENERATION_TABLE_INDEX mismatch");
+#endif //MULTIPLE_HEAPS
+
assert(gcDacVars != nullptr);
*gcDacVars = {};
// Note: these version numbers are not actually checked by SOS, so if you change
gcDacVars->generation_size = sizeof(generation);
gcDacVars->total_generation_count = total_generation_count;
gcDacVars->max_gen = &g_max_generation;
+ gcDacVars->current_c_gc_state = const_cast<c_gc_state*>(&gc_heap::current_c_gc_state);
#ifndef MULTIPLE_HEAPS
gcDacVars->mark_array = &gc_heap::mark_array;
gcDacVars->ephemeral_heap_segment = reinterpret_cast<dac_heap_segment**>(&gc_heap::ephemeral_heap_segment);
- gcDacVars->current_c_gc_state = const_cast<c_gc_state*>(&gc_heap::current_c_gc_state);
#ifdef USE_REGIONS
gcDacVars->saved_sweep_ephemeral_seg = 0;
gcDacVars->saved_sweep_ephemeral_start = 0;
#endif // HEAP_ANALYZE
#else
gcDacVars->n_heaps = &gc_heap::n_heaps;
- gcDacVars->g_heaps = reinterpret_cast<dac_gc_heap***>(&gc_heap::g_heaps);
+ gcDacVars->g_heaps = reinterpret_cast<opaque_gc_heap***>(&gc_heap::g_heaps);
+ gcDacVars->gc_heap_field_offsets = reinterpret_cast<int**>(&gc_heap_field_offsets);
#endif // MULTIPLE_HEAPS
#else
UNREFERENCED_PARAMETER(gcDacVars);
--- /dev/null
+DEFINE_FIELD (alloc_allocated, uint8_t*)
+DEFINE_DPTR_FIELD (ephemeral_heap_segment, dac_heap_segment)
+DEFINE_DPTR_FIELD (finalize_queue, dac_finalize_queue)
+DEFINE_FIELD (oom_info, oom_history)
+DEFINE_ARRAY_FIELD (interesting_data_per_heap, size_t, NUM_GC_DATA_POINTS)
+DEFINE_ARRAY_FIELD (compact_reasons_per_heap, size_t, MAX_COMPACT_REASONS_COUNT)
+DEFINE_ARRAY_FIELD (expand_mechanisms_per_heap, size_t, MAX_EXPAND_MECHANISMS_COUNT)
+DEFINE_ARRAY_FIELD (interesting_mechanism_bits_per_heap,size_t, MAX_GC_MECHANISM_BITS_COUNT)
+DEFINE_FIELD (internal_root_array, uint8_t*)
+DEFINE_FIELD (internal_root_array_index, size_t)
+DEFINE_FIELD (heap_analyze_success, BOOL)
+DEFINE_FIELD (card_table, uint32_t*)
+#if defined(ALL_FIELDS) || defined(BACKGROUND_GC)
+DEFINE_FIELD (mark_array, uint32_t*)
+DEFINE_FIELD (next_sweep_obj, uint8_t*)
+DEFINE_FIELD (background_saved_lowest_address, uint8_t*)
+DEFINE_FIELD (background_saved_highest_address, uint8_t*)
+#if defined(ALL_FIELDS) || !defined(USE_REGIONS)
+DEFINE_DPTR_FIELD (saved_sweep_ephemeral_seg, dac_heap_segment)
+DEFINE_FIELD (saved_sweep_ephemeral_start, uint8_t*)
+#else
+DEFINE_MISSING_FIELD
+DEFINE_MISSING_FIELD
+#endif
+#else
+DEFINE_MISSING_FIELD
+DEFINE_MISSING_FIELD
+DEFINE_MISSING_FIELD
+DEFINE_MISSING_FIELD
+DEFINE_MISSING_FIELD
+DEFINE_MISSING_FIELD
+#endif
// 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;
+#define ALL_FIELDS
+#define DEFINE_FIELD(field_name, field_type) field_type field_name;
+#define DEFINE_DPTR_FIELD(field_name, field_type) DPTR(field_type) field_name;
+#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) field_type field_name[array_length];
+
+#include "gc_typefields.h"
+
+#undef DEFINE_ARRAY_FIELD
+#undef DEFINE_DPTR_FIELD
+#undef DEFINE_FIELD
+#undef ALL_FIELDS
// The generation table must always be last, because the size of this array
// (stored inline in the gc_heap class) can vary.
dac_generation generation_table[1];
};
+#define GENERATION_TABLE_FIELD_INDEX 18
+
+struct opaque_gc_heap
+{
+ uint8_t unused;
+};
// 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
GC_DAC_VAR (size_t, internal_root_array_index)
GC_DAC_VAR (BOOL, heap_analyze_success)
GC_DAC_VAR (int, n_heaps)
-GC_DAC_PTR_VAR (dac_gc_heap*, g_heaps)
+GC_DAC_PTR_VAR (opaque_gc_heap*, g_heaps)
GC_DAC_VAR (int32_t, gc_structures_invalid_cnt)
GC_DAC_ARRAY_VAR (size_t, interesting_data_per_heap)
GC_DAC_ARRAY_VAR (size_t, compact_reasons_per_heap)
GC_DAC_ARRAY_VAR (size_t, expand_mechanisms_per_heap)
GC_DAC_ARRAY_VAR (size_t, interesting_mechanism_bits_per_heap)
GC_DAC_VAR (dac_handle_table_map, handle_table_map)
+GC_DAC_ARRAY_VAR (int, gc_heap_field_offsets)
#undef GC_DAC_VAR
#undef GC_DAC_ARRAY_VAR
GCEvent bgc_start_event;
#endif //BACKGROUND_GC
- // The variables in this block are known to the DAC and must come first
- // in the gc_heap class.
-
// Keeps track of the highest address allocated by Alloc
PER_HEAP
uint8_t* alloc_allocated;
PER_HEAP
BOOL heap_analyze_success;
- // The generation table. Must always be last.
PER_HEAP
generation generation_table [total_generation_count];
- // End DAC zone
-
#ifdef USE_REGIONS
#ifdef STRESS_REGIONS
// TODO: could consider dynamically grow this.
void update_collection_counts ();
}; // class gc_heap
-#define ASSERT_OFFSETS_MATCH(field) \
- static_assert(offsetof(dac_gc_heap, field) == offsetof(gc_heap, field), #field " offset mismatch")
-
-#ifndef USE_REGIONS
-#ifdef MULTIPLE_HEAPS
-ASSERT_OFFSETS_MATCH(alloc_allocated);
-ASSERT_OFFSETS_MATCH(ephemeral_heap_segment);
-ASSERT_OFFSETS_MATCH(finalize_queue);
-ASSERT_OFFSETS_MATCH(oom_info);
-ASSERT_OFFSETS_MATCH(interesting_data_per_heap);
-ASSERT_OFFSETS_MATCH(compact_reasons_per_heap);
-ASSERT_OFFSETS_MATCH(expand_mechanisms_per_heap);
-ASSERT_OFFSETS_MATCH(interesting_mechanism_bits_per_heap);
-ASSERT_OFFSETS_MATCH(internal_root_array);
-ASSERT_OFFSETS_MATCH(internal_root_array_index);
-ASSERT_OFFSETS_MATCH(heap_analyze_success);
-ASSERT_OFFSETS_MATCH(generation_table);
-#endif // MULTIPLE_HEAPS
-#endif //USE_REGIONS
-
#ifdef FEATURE_PREMORTEM_FINALIZATION
class CFinalize
{