mCurrObj += mCurrSize;
// Check to see if we are in the correct bounds.
- if (mHeaps[mCurrHeap].Gen0Start <= mCurrObj && mHeaps[mCurrHeap].Gen0End > mCurrObj)
+ bool isGen0 = IsRegion() ? (mHeaps[mCurrHeap].Segments[mCurrSeg].Generation == 0) :
+ (mHeaps[mCurrHeap].Gen0Start <= mCurrObj && mHeaps[mCurrHeap].Gen0End > mCurrObj);
+
+ if (isGen0)
CheckAllocAndSegmentRange();
// Check to see if we've moved off the end of a segment
mCurrObj = mHeaps[mCurrHeap].Segments[mCurrSeg].Start;
- if (mHeaps[mCurrHeap].Gen0Start <= mCurrObj && mHeaps[mCurrHeap].Gen0End > mCurrObj)
+ bool isGen0 = IsRegion() ? (mHeaps[mCurrHeap].Segments[mCurrSeg].Generation == 0) :
+ (mHeaps[mCurrHeap].Gen0Start <= mCurrObj && mHeaps[mCurrHeap].Gen0End > mCurrObj);
+
+ if (isGen0)
CheckAllocAndSegmentRange();
if (!mCache.ReadMT(mCurrObj, &mCurrMT))
HRESULT DacHeapWalker::InitHeapDataWks(HeapData *&pHeaps, size_t &pCount)
{
+ bool regions = IsRegion();
+
// Scrape basic heap details
pCount = 1;
pHeaps = new (nothrow) HeapData[1];
if (pHeaps == NULL)
return E_OUTOFMEMORY;
- dac_generation gen0 = *GenerationTableIndex(g_gcDacGlobals->generation_table, 0);
- dac_generation gen1 = *GenerationTableIndex(g_gcDacGlobals->generation_table, 1);
- dac_generation gen2 = *GenerationTableIndex(g_gcDacGlobals->generation_table, 2);
- dac_generation loh = *GenerationTableIndex(g_gcDacGlobals->generation_table, 3);
- dac_generation poh = *GenerationTableIndex(g_gcDacGlobals->generation_table, 4);
+ dac_generation gen0 = GenerationTableIndex(g_gcDacGlobals->generation_table, 0);
+ dac_generation gen1 = GenerationTableIndex(g_gcDacGlobals->generation_table, 1);
+ dac_generation gen2 = GenerationTableIndex(g_gcDacGlobals->generation_table, 2);
+ dac_generation loh = GenerationTableIndex(g_gcDacGlobals->generation_table, 3);
+ dac_generation poh = GenerationTableIndex(g_gcDacGlobals->generation_table, 4);
pHeaps[0].YoungestGenPtr = (CORDB_ADDRESS)gen0.allocation_context.alloc_ptr;
pHeaps[0].YoungestGenLimit = (CORDB_ADDRESS)gen0.allocation_context.alloc_limit;
- pHeaps[0].Gen0Start = (CORDB_ADDRESS)gen0.allocation_start;
- pHeaps[0].Gen0End = (CORDB_ADDRESS)*g_gcDacGlobals->alloc_allocated;
- pHeaps[0].Gen1Start = (CORDB_ADDRESS)gen1.allocation_start;
+ if (!regions)
+ {
+ pHeaps[0].Gen0Start = (CORDB_ADDRESS)gen0.allocation_start;
+ pHeaps[0].Gen0End = (CORDB_ADDRESS)*g_gcDacGlobals->alloc_allocated;
+ pHeaps[0].Gen1Start = (CORDB_ADDRESS)gen1.allocation_start;
+ }
// Segments
int count = GetSegmentCount(loh.start_segment);
count += GetSegmentCount(poh.start_segment);
count += GetSegmentCount(gen2.start_segment);
+ if (regions)
+ {
+ count += GetSegmentCount(gen1.start_segment);
+ count += GetSegmentCount(gen0.start_segment);
+ }
pHeaps[0].SegmentCount = count;
pHeaps[0].Segments = new (nothrow) SegmentData[count];
if (pHeaps[0].Segments == NULL)
return E_OUTOFMEMORY;
- // Small object heap segments
- DPTR(dac_heap_segment) seg = gen2.start_segment;
+ DPTR(dac_heap_segment) seg;
int i = 0;
- for (; seg && (i < count); ++i)
+
+ // Small object heap segments
+ if (regions)
{
- pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
- if (seg.GetAddr() == (TADDR)*g_gcDacGlobals->ephemeral_heap_segment)
+ seg = gen2.start_segment;
+ for (; seg && (i < count); ++i)
{
- pHeaps[0].Segments[i].End = (CORDB_ADDRESS)*g_gcDacGlobals->alloc_allocated;
- pHeaps[0].Segments[i].Generation = 1;
- pHeaps[0].EphemeralSegment = i;
+ pHeaps[0].Segments[i].Generation = 2;
+ pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
+ pHeaps[0].Segments[i].End = (CORDB_ADDRESS)seg->allocated;
+
+ seg = seg->next;
}
- else
+ seg = gen1.start_segment;
+ for (; seg && (i < count); ++i)
{
+ pHeaps[0].Segments[i].Generation = 1;
+ pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
pHeaps[0].Segments[i].End = (CORDB_ADDRESS)seg->allocated;
- pHeaps[0].Segments[i].Generation = 2;
+
+ seg = seg->next;
}
+ seg = gen0.start_segment;
+ for (; seg && (i < count); ++i)
+ {
+ pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
+ if (seg.GetAddr() == (TADDR)*g_gcDacGlobals->ephemeral_heap_segment)
+ {
+ pHeaps[0].Segments[i].End = (CORDB_ADDRESS)*g_gcDacGlobals->alloc_allocated;
+ pHeaps[0].EphemeralSegment = i;
+ }
+ else
+ {
+ pHeaps[0].Segments[i].End = (CORDB_ADDRESS)seg->allocated;
+ }
+ pHeaps[0].Segments[i].Generation = 0;
- seg = seg->next;
+ seg = seg->next;
+ }
+ }
+ else
+ {
+ DPTR(dac_heap_segment) seg = gen2.start_segment;
+ for (; seg && (i < count); ++i)
+ {
+ pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
+ if (seg.GetAddr() == (TADDR)*g_gcDacGlobals->ephemeral_heap_segment)
+ {
+ pHeaps[0].Segments[i].End = (CORDB_ADDRESS)*g_gcDacGlobals->alloc_allocated;
+ pHeaps[0].Segments[i].Generation = 1;
+ pHeaps[0].EphemeralSegment = i;
+ }
+ else
+ {
+ pHeaps[0].Segments[i].End = (CORDB_ADDRESS)seg->allocated;
+ pHeaps[0].Segments[i].Generation = 2;
+ }
+
+ seg = seg->next;
+ }
}
// Large object heap segments
size_t heapCount = 0;
HeapData *heaps = 0;
+ bool region = IsRegion();
+
#ifdef FEATURE_SVR_GC
HRESULT hr = GCHeapUtilities::IsServerHeap() ? DacHeapWalker::InitHeapDataSvr(heaps, heapCount) : DacHeapWalker::InitHeapDataWks(heaps, heapCount);
#else
int total = 0;
for (size_t i = 0; i < heapCount; ++i)
{
- // SegmentCount is +1 due to the ephemeral segment containing more than one
- // generation (Gen1 + Gen0, and sometimes part of Gen2).
- total += (int)heaps[i].SegmentCount + 1;
-
- // It's possible that part of Gen2 lives on the ephemeral segment. If so,
- // we need to add one more to the output.
- const size_t eph = heaps[i].EphemeralSegment;
- _ASSERTE(eph < heaps[i].SegmentCount);
- if (heaps[i].Segments[eph].Start != heaps[i].Gen1Start)
+ total += (int)heaps[i].SegmentCount;
+ if (!region)
+ {
+ // SegmentCount is +1 due to the ephemeral segment containing more than one
+ // generation (Gen1 + Gen0, and sometimes part of Gen2).
total++;
+
+ // It's possible that part of Gen2 lives on the ephemeral segment. If so,
+ // we need to add one more to the output.
+ const size_t eph = heaps[i].EphemeralSegment;
+ _ASSERTE(eph < heaps[i].SegmentCount);
+ if (heaps[i].Segments[eph].Start != heaps[i].Gen1Start)
+ total++;
+ }
}
pSegments->Alloc(total);
int curr = 0;
for (size_t i = 0; i < heapCount; ++i)
{
- // Generation 0 is not in the segment list.
_ASSERTE(curr < total);
+ if (!region)
{
+ // Generation 0 is not in the segment list.
COR_SEGMENT &seg = (*pSegments)[curr++];
seg.start = heaps[i].Gen0Start;
seg.end = heaps[i].Gen0End;
for (size_t j = 0; j < heaps[i].SegmentCount; ++j)
{
- if (heaps[i].Segments[j].Generation == 1)
+ if (region)
+ {
+ _ASSERTE(curr < total);
+ COR_SEGMENT &seg = (*pSegments)[curr++];
+ seg.start = heaps[i].Segments[j].Start;
+ seg.end = heaps[i].Segments[j].End;
+ seg.type = (CorDebugGenerationTypes)heaps[i].Segments[j].Generation;
+ seg.heap = (ULONG)i;
+ }
+ else if (heaps[i].Segments[j].Generation == 1)
{
// This is the ephemeral segment. We have already written Gen0,
// now write Gen1.
if (data && count >= 1)
{
- DPTR(dac_generation) table = g_gcDacGlobals->generation_table;
+ DPTR(unused_generation) table = g_gcDacGlobals->generation_table;
for (unsigned int i=0; i < *g_gcDacGlobals->max_gen + 2; i++)
{
- dac_generation entry = *GenerationTableIndex(table, i);
+ dac_generation entry = GenerationTableIndex(table, i);
data[0].allocData[i].allocBytes = (CLRDATA_ADDRESS)(ULONG_PTR) entry.allocation_context.alloc_bytes;
data[0].allocData[i].allocBytesLoh = (CLRDATA_ADDRESS)(ULONG_PTR) entry.allocation_context.alloc_bytes_uoh;
}
// 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;
+ 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;
+ gc_alloc_context alloc_context = 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;
}
if (g_gcDacGlobals->finalize_queue.IsValid())
// 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++)
{
- dac_generation *gen = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
- __DPtr<dac_heap_segment> seg = dac_cast<TADDR>(gen->start_segment);
+ dac_generation gen = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
+ __DPtr<dac_heap_segment> seg = dac_cast<TADDR>(gen.start_segment);
while (seg)
{
- DacEnumMemoryRegion(dac_cast<TADDR>(seg), sizeof(dac_heap_segment));
- seg = seg->next;
+ DacEnumMemoryRegion(dac_cast<TADDR>(seg), sizeof(dac_heap_segment));
+ seg = seg->next;
}
}
}
{
for (unsigned int i = 0; i < numGenerationTableEntries; i++)
{
- DPTR(dac_generation) generation = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
- pGenerationData[i].start_segment = (CLRDATA_ADDRESS) dac_cast<TADDR>(generation->start_segment);
+ dac_generation generation = GenerationTableIndex(g_gcDacGlobals->generation_table, i);
+ pGenerationData[i].start_segment = (CLRDATA_ADDRESS) dac_cast<TADDR>(generation.start_segment);
- pGenerationData[i].allocation_start = (CLRDATA_ADDRESS) generation->allocation_start;
+ pGenerationData[i].allocation_start = (CLRDATA_ADDRESS) generation.allocation_start;
- DPTR(gc_alloc_context) alloc_context = dac_cast<TADDR>(generation) + offsetof(dac_generation, allocation_context);
- pGenerationData[i].allocContextPtr = (CLRDATA_ADDRESS)alloc_context->alloc_ptr;
- pGenerationData[i].allocContextLimit = (CLRDATA_ADDRESS)alloc_context->alloc_limit;
+ gc_alloc_context alloc_context = generation.allocation_context;
+ pGenerationData[i].allocContextPtr = (CLRDATA_ADDRESS)alloc_context.alloc_ptr;
+ pGenerationData[i].allocContextLimit = (CLRDATA_ADDRESS)alloc_context.alloc_limit;
}
}
else
{
for (unsigned int i = 0; i < numGenerationTableEntries; ++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);
- pGenerationData[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR) alloc_context->alloc_ptr;
- pGenerationData[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR) alloc_context->alloc_limit;
+ 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;
+ gc_alloc_context alloc_context = generation.allocation_context;
+ pGenerationData[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR)alloc_context.alloc_ptr;
+ pGenerationData[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR)alloc_context.alloc_limit;
}
}
else
// 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)
+HeapTableIndex(DPTR(unused_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*));
+ DPTR(unused_gc_heap*) heap_table = Dereference(heaps);
+ DPTR(unused_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)
-GenerationTableIndex(DPTR(dac_generation) base, size_t index)
-{
- 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.
+// Starting .NET 6, it is possible for the gc_heap and generation 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 arrays of field offsets instead.
// These offsets could be -1, indicating the field does not exist in the current
-// gc_heap being used.
+// gc_heap or generation being used.
// field_offset = g_gcDacGlobals->gc_heap_field_offsets
// p_field_offset = field_offset[field_index]
-// p_field = heap + p_field_offset
+// p_field = BASE + 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; \
+ DPTR(field_type) p_##field_name = BASE + field_name##_offset; \
field_index++;
// if (field_offset != -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(TADDR heap, size_t index)
+inline bool IsRegion()
{
- 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);
+ return (g_gcDacGlobals->minor_version_number & 1) != 0;
}
// Load an instance of dac_gc_heap for the heap pointed by heap.
DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
int field_index = 0;
+#define BASE heap
#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"
+#include "../../gc/dac_gcheap_fields.h"
#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
#undef ALL_FIELDS
+#undef BASE
return result;
}
+// Load an instance of dac_generation for the generation pointed by generation.
+// Fields that does not exist in the current generation instance is zero initialized.
+// Return the dac_generation object.
+inline dac_generation
+LoadGeneration(TADDR generation)
+{
+ dac_generation result;
+ memset(&result, 0, sizeof(dac_generation));
+
+ DPTR(int) field_offsets = g_gcDacGlobals->generation_field_offsets;
+ int field_index = 0;
+
+#define BASE generation
+#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)
+
+#include "../../gc/dac_generation_fields.h"
+
+#undef DEFINE_DPTR_FIELD
+#undef DEFINE_FIELD
+#undef ALL_FIELDS
+#undef BASE
+
+ return result;
+}
+
+// Indexes into a given generation table, returning a dac_generation
+inline dac_generation
+GenerationTableIndex(DPTR(unused_generation) base, size_t index)
+{
+ return LoadGeneration(TableIndex(base, index, g_gcDacGlobals->generation_size).GetAddr());
+}
+
+// Indexes into a heap's generation table, given the heap instance
+// and the desired index. Returns a dac_generation
+inline dac_generation
+ServerGenerationTableIndex(TADDR heap, size_t index)
+{
+ DPTR(int) field_offsets = g_gcDacGlobals->gc_heap_field_offsets;
+ int field_index = GENERATION_TABLE_FIELD_INDEX;
+ #define BASE heap
+ LOAD_BASE (generation_table, unused_generation);
+ #undef BASE
+ assert (generation_table_offset != -1);
+ return LoadGeneration(TableIndex(p_generation_table, index, g_gcDacGlobals->generation_size).GetAddr());
+}
+
#undef LOAD_ARRAY
#undef LOAD_DPTR
#undef LOAD
TADDR pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, n);
for (int i=0;i<NUMBERGENERATIONS;i++)
{
- dac_generation generation = *ServerGenerationTableIndex(pHeap, i);
+ dac_generation generation = ServerGenerationTableIndex(pHeap, i);
data[n].allocData[i].allocBytes = (CLRDATA_ADDRESS)(ULONG_PTR) generation.allocation_context.alloc_bytes;
data[n].allocData[i].allocBytesLoh = (CLRDATA_ADDRESS)(ULONG_PTR) generation.allocation_context.alloc_bytes_uoh;
}
// get bounds for the different generations
for (unsigned int i=0; i < DAC_NUMBERGENERATIONS; 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);
- detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR) alloc_context->alloc_ptr;
- detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR) alloc_context->alloc_limit;
+ 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;
+ gc_alloc_context alloc_context = generation.allocation_context;
+ detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR) alloc_context.alloc_ptr;
+ detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR) alloc_context.alloc_limit;
}
DPTR(dac_finalize_queue) fq = pHeap->finalize_queue;
// 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(heapAddress, i)->start_segment;
+ dac_generation generation = ServerGenerationTableIndex(heapAddress, i);
+ DPTR(dac_heap_segment) seg = generation.start_segment;
while (seg)
{
- DacEnumMemoryRegion(PTR_HOST_TO_TADDR(seg), sizeof(dac_heap_segment));
-
- seg = seg->next;
+ DacEnumMemoryRegion(PTR_HOST_TO_TADDR(seg), sizeof(dac_heap_segment));
+ seg = seg->next;
}
}
}
HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
{
+ bool regions = IsRegion();
+
if (g_gcDacGlobals->n_heaps == nullptr || g_gcDacGlobals->g_heaps == nullptr)
return S_OK;
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);
+ 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)pHeap->alloc_allocated;
- pHeaps[i].Gen1Start = (CORDB_ADDRESS)gen1.allocation_start;
+ if (!regions)
+ {
+ pHeaps[i].Gen0Start = (CORDB_ADDRESS)gen0.allocation_start;
+ pHeaps[i].Gen0End = (CORDB_ADDRESS)pHeap->alloc_allocated;
+ pHeaps[i].Gen1Start = (CORDB_ADDRESS)gen1.allocation_start;
+ }
// Segments
int count = GetSegmentCount(loh.start_segment);
count += GetSegmentCount(poh.start_segment);
count += GetSegmentCount(gen2.start_segment);
+ if (regions)
+ {
+ count += GetSegmentCount(gen1.start_segment);
+ count += GetSegmentCount(gen0.start_segment);
+ }
pHeaps[i].SegmentCount = count;
pHeaps[i].Segments = new (nothrow) SegmentData[count];
if (pHeaps[i].Segments == NULL)
return E_OUTOFMEMORY;
- // Small object heap segments
- DPTR(dac_heap_segment) seg = gen2.start_segment;
+ DPTR(dac_heap_segment) seg;
int j = 0;
- for (; seg && (j < count); ++j)
+ // Small object heap segments
+ if (regions)
{
- pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
- if (seg.GetAddr() == pHeap->ephemeral_heap_segment.GetAddr())
+ seg = gen2.start_segment;
+ for (; seg && (j < count); ++j)
{
- pHeaps[i].Segments[j].End = (CORDB_ADDRESS)pHeap->alloc_allocated;
- pHeaps[i].EphemeralSegment = j;
- pHeaps[i].Segments[j].Generation = 1;
+ pHeaps[i].Segments[j].Generation = 2;
+ pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)seg->allocated;
+
+ seg = seg->next;
}
- else
+ seg = gen1.start_segment;
+ for (; seg && (j < count); ++j)
{
+ pHeaps[i].Segments[j].Generation = 1;
+ pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
pHeaps[i].Segments[j].End = (CORDB_ADDRESS)seg->allocated;
- pHeaps[i].Segments[j].Generation = 2;
- }
- seg = seg->next;
+ seg = seg->next;
+ }
+ seg = gen0.start_segment;
+ for (; seg && (j < count); ++j)
+ {
+ pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
+ if (seg.GetAddr() == pHeap->ephemeral_heap_segment.GetAddr())
+ {
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)pHeap->alloc_allocated;
+ pHeaps[i].EphemeralSegment = j;
+ pHeaps[i].Segments[j].Generation = 0;
+ }
+ else
+ {
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)seg->allocated;
+ pHeaps[i].Segments[j].Generation = 2;
+ }
+
+ seg = seg->next;
+ }
+ }
+ else
+ {
+ seg = gen2.start_segment;
+ for (; seg && (j < count); ++j)
+ {
+ pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
+ if (seg.GetAddr() == pHeap->ephemeral_heap_segment.GetAddr())
+ {
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)pHeap->alloc_allocated;
+ pHeaps[i].EphemeralSegment = j;
+ pHeaps[i].Segments[j].Generation = 1;
+ }
+ else
+ {
+ pHeaps[i].Segments[j].End = (CORDB_ADDRESS)seg->allocated;
+ pHeaps[i].Segments[j].Generation = 2;
+ }
+
+ seg = seg->next;
+ }
}
// Large object heap segments
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
+DEFINE_MISSING_FIELD(saved_sweep_ephemeral_seg)
+DEFINE_MISSING_FIELD(saved_sweep_ephemeral_start)
#endif
#else
-DEFINE_MISSING_FIELD
-DEFINE_MISSING_FIELD
-DEFINE_MISSING_FIELD
-DEFINE_MISSING_FIELD
-DEFINE_MISSING_FIELD
-DEFINE_MISSING_FIELD
+DEFINE_MISSING_FIELD(mark_array)
+DEFINE_MISSING_FIELD(next_sweep_obj)
+DEFINE_MISSING_FIELD(background_saved_lowest_address)
+DEFINE_MISSING_FIELD(background_saved_highest_address)
+DEFINE_MISSING_FIELD(saved_sweep_ephemeral_seg)
+DEFINE_MISSING_FIELD(saved_sweep_ephemeral_start)
#endif
--- /dev/null
+DEFINE_FIELD (allocation_context, gc_alloc_context)
+DEFINE_DPTR_FIELD (start_segment, dac_heap_segment)
+#ifndef USE_REGIONS
+DEFINE_FIELD (allocation_start, uint8_t*)
+#else
+DEFINE_MISSING_FIELD(allocation_start)
+#endif
\ No newline at end of file
{
#ifndef DACCESS_COMPILE
+#define DEFINE_FIELD(field_name, field_type) offsetof(CLASS_NAME, field_name),
+#define DEFINE_DPTR_FIELD(field_name, field_type) offsetof(CLASS_NAME, field_name),
+#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) offsetof(CLASS_NAME, field_name),
+#define DEFINE_MISSING_FIELD(field_name) -1,
+
#ifdef MULTIPLE_HEAPS
static int gc_heap_field_offsets[] = {
+#define CLASS_NAME gc_heap
+#include "dac_gcheap_fields.h"
+#undef CLASS_NAME
-#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,
+ 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
+ static int generation_field_offsets[] = {
-#include "gc_typefields.h"
+#define CLASS_NAME generation
+#include "dac_generation_fields.h"
+#undef CLASS_NAME
#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 = {};
// SOS_BREAKING_CHANGE_VERSION in both the runtime and the diagnostics repo
gcDacVars->major_version_number = 1;
gcDacVars->minor_version_number = 0;
+#ifdef USE_REGIONS
+ gcDacVars->minor_version_number |= 1;
+#endif //USE_REGIONS
gcDacVars->built_with_svr = &g_built_with_svr_gc;
gcDacVars->build_variant = &g_build_variant;
gcDacVars->gc_structures_invalid_cnt = const_cast<int32_t*>(&GCScan::m_GcStructuresInvalidCnt);
#else
gcDacVars->saved_sweep_ephemeral_seg = reinterpret_cast<dac_heap_segment**>(&gc_heap::saved_sweep_ephemeral_seg);
gcDacVars->saved_sweep_ephemeral_start = &gc_heap::saved_sweep_ephemeral_start;
-#endif //!USE_REGIONS
+#endif //USE_REGIONS
gcDacVars->background_saved_lowest_address = &gc_heap::background_saved_lowest_address;
gcDacVars->background_saved_highest_address = &gc_heap::background_saved_highest_address;
gcDacVars->alloc_allocated = &gc_heap::alloc_allocated;
gcDacVars->next_sweep_obj = &gc_heap::next_sweep_obj;
gcDacVars->oom_info = &gc_heap::oom_info;
gcDacVars->finalize_queue = reinterpret_cast<dac_finalize_queue**>(&gc_heap::finalize_queue);
- gcDacVars->generation_table = reinterpret_cast<dac_generation**>(&gc_heap::generation_table);
+ gcDacVars->generation_table = reinterpret_cast<unused_generation**>(&gc_heap::generation_table);
#ifdef GC_CONFIG_DRIVEN
gcDacVars->gc_global_mechanisms = reinterpret_cast<size_t**>(&gc_global_mechanisms);
gcDacVars->interesting_data_per_heap = reinterpret_cast<size_t**>(&gc_heap::interesting_data_per_heap);
#endif // HEAP_ANALYZE
#else
gcDacVars->n_heaps = &gc_heap::n_heaps;
- gcDacVars->g_heaps = reinterpret_cast<opaque_gc_heap***>(&gc_heap::g_heaps);
+ gcDacVars->g_heaps = reinterpret_cast<unused_gc_heap***>(&gc_heap::g_heaps);
gcDacVars->gc_heap_field_offsets = reinterpret_cast<int**>(&gc_heap_field_offsets);
#endif // MULTIPLE_HEAPS
+ gcDacVars->generation_field_offsets = reinterpret_cast<int**>(&generation_field_offsets);
#else
UNREFERENCED_PARAMETER(gcDacVars);
#endif // DACCESS_COMPILE
// 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;
+#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;
+
+#include "dac_generation_fields.h"
+
+#undef DEFINE_DPTR_FIELD
+#undef DEFINE_FIELD
+#undef ALL_FIELDS
};
// Analogue for the GC CFinalize class, containing information about the finalize queue.
#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"
+#include "dac_gcheap_fields.h"
#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#define GENERATION_TABLE_FIELD_INDEX 18
-struct opaque_gc_heap
+// Unlike other DACized structures, these types are loaded manually in the debugger.
+// To avoid misuse, pointers to them are explicitly casted to these unused type.
+struct unused_gc_heap
+{
+ uint8_t unused;
+};
+
+struct unused_generation
{
uint8_t unused;
};
GC_DAC_VAR (uint8_t, build_variant)
GC_DAC_VAR (bool, built_with_svr)
GC_DAC_ARRAY_VAR (size_t, gc_global_mechanisms)
-GC_DAC_ARRAY_VAR (dac_generation, generation_table)
+GC_DAC_ARRAY_VAR (unused_generation, generation_table)
GC_DAC_VAR (uint32_t, max_gen)
GC_DAC_PTR_VAR (uint32_t, mark_array)
GC_DAC_VAR (c_gc_state, current_c_gc_state)
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 (opaque_gc_heap*, g_heaps)
+GC_DAC_PTR_VAR (unused_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, interesting_mechanism_bits_per_heap)
GC_DAC_VAR (dac_handle_table_map, handle_table_map)
GC_DAC_ARRAY_VAR (int, gc_heap_field_offsets)
+GC_DAC_ARRAY_VAR (int, generation_field_offsets)
#undef GC_DAC_VAR
#undef GC_DAC_ARRAY_VAR
#endif //FREE_USAGE_STATS
};
-static_assert(offsetof(dac_generation, allocation_context) == offsetof(generation, allocation_context), "DAC generation offset mismatch");
-static_assert(offsetof(dac_generation, start_segment) == offsetof(generation, start_segment), "DAC generation offset mismatch");
-#ifndef USE_REGIONS
-static_assert(offsetof(dac_generation, allocation_start) == offsetof(generation, allocation_start), "DAC generation offset mismatch");
-#endif //!USE_REGIONS
-
// static data remains the same after it's initialized.
// It's per generation.
// TODO: for gen_time_tuning, we should put the multipliers in static data.