Fix DacHeapWalker for USE_REGIONS (#56796)
authorAndrew Au <andrewau@microsoft.com>
Tue, 17 Aug 2021 14:18:47 +0000 (07:18 -0700)
committerGitHub <noreply@github.com>
Tue, 17 Aug 2021 14:18:47 +0000 (07:18 -0700)
src/coreclr/debug/daccess/dacdbiimpl.cpp
src/coreclr/debug/daccess/request.cpp
src/coreclr/debug/daccess/request_common.h
src/coreclr/debug/daccess/request_svr.cpp
src/coreclr/gc/dac_gcheap_fields.h [moved from src/coreclr/gc/gc_typefields.h with 79% similarity]
src/coreclr/gc/dac_generation_fields.h [new file with mode: 0644]
src/coreclr/gc/gc.cpp
src/coreclr/gc/gcinterface.dac.h
src/coreclr/gc/gcinterface.dacvars.def
src/coreclr/gc/gcpriv.h

index d8c13be..2924be3 100644 (file)
@@ -6452,7 +6452,10 @@ HRESULT DacHeapWalker::MoveToNextObject()
         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
@@ -6541,7 +6544,10 @@ HRESULT DacHeapWalker::NextSegment()
 
         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))
@@ -6723,54 +6729,107 @@ HRESULT DacHeapWalker::ListNearObjects(CORDB_ADDRESS obj, CORDB_ADDRESS *pPrev,
 
 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
@@ -6880,6 +6939,8 @@ HRESULT DacDbiInterfaceImpl::GetHeapSegments(OUT DacDbiArrayList<COR_SEGMENT> *p
     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
@@ -6892,16 +6953,20 @@ HRESULT DacDbiInterfaceImpl::GetHeapSegments(OUT DacDbiArrayList<COR_SEGMENT> *p
     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);
@@ -6910,9 +6975,10 @@ HRESULT DacDbiInterfaceImpl::GetHeapSegments(OUT DacDbiArrayList<COR_SEGMENT> *p
     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;
@@ -6922,7 +6988,16 @@ HRESULT DacDbiInterfaceImpl::GetHeapSegments(OUT DacDbiArrayList<COR_SEGMENT> *p
 
         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.
index 4e729c8..f075dbe 100644 (file)
@@ -747,10 +747,10 @@ ClrDataAccess::GetHeapAllocData(unsigned int count, struct DacpGenerationAllocDa
 
         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;
             }
@@ -2809,12 +2809,12 @@ ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
     // 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())
@@ -3790,12 +3790,12 @@ ClrDataAccess::EnumWksGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
             // 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;
                 }
             }
     }
@@ -4619,14 +4619,14 @@ HRESULT ClrDataAccess::GetGenerationTable(unsigned int cGenerations, struct Dacp
         {
             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
@@ -4709,12 +4709,12 @@ HRESULT ClrDataAccess::GetGenerationTableSvr(CLRDATA_ADDRESS heapAddr, unsigned
         {
             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
index 1b86b46..e6c976f 100644 (file)
@@ -29,35 +29,27 @@ DPTR(T) Dereference(DPTR(T*) ptr)
 // 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)
@@ -95,16 +87,9 @@ GenerationTableIndex(DPTR(dac_generation) base, size_t index)
         }                                                                                    \
     }
 
-// 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.
@@ -119,21 +104,71 @@ LoadGcHeapData(TADDR 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
index 2d176f6..5ff14b0 100644 (file)
@@ -89,7 +89,7 @@ HRESULT ClrDataAccess::GetServerAllocData(unsigned int count, struct DacpGenerat
             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;
             }
@@ -149,12 +149,12 @@ ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapDetails *
     // 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;
@@ -268,12 +268,12 @@ ClrDataAccess::EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
         // 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;
             }
         }
     }
@@ -290,6 +290,8 @@ DWORD DacGetNumHeaps()
 
 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;
 
@@ -306,48 +308,99 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
         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
similarity index 79%
rename from src/coreclr/gc/gc_typefields.h
rename to src/coreclr/gc/dac_gcheap_fields.h
index f690a6c..1041572 100644 (file)
@@ -19,14 +19,14 @@ DEFINE_FIELD       (background_saved_highest_address,   uint8_t*)
 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
diff --git a/src/coreclr/gc/dac_generation_fields.h b/src/coreclr/gc/dac_generation_fields.h
new file mode 100644 (file)
index 0000000..c67197a
--- /dev/null
@@ -0,0 +1,7 @@
+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
index 9aada04..47ff77d 100644 (file)
@@ -46209,25 +46209,32 @@ void PopulateDacVars(GcDacVars *gcDacVars)
 {
 #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 = {};
@@ -46236,6 +46243,9 @@ void PopulateDacVars(GcDacVars *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);
@@ -46252,14 +46262,14 @@ void PopulateDacVars(GcDacVars *gcDacVars)
 #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);
@@ -46274,9 +46284,10 @@ void PopulateDacVars(GcDacVars *gcDacVars)
 #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
index 3a4697a..cfffcf1 100644 (file)
@@ -46,9 +46,15 @@ public:
 // 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.
@@ -141,7 +147,7 @@ public:
 #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
@@ -164,7 +170,14 @@ public:
 
 #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;
 };
index 2f27df7..fe7edcc 100644 (file)
@@ -36,7 +36,7 @@
 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)
@@ -53,7 +53,7 @@ GC_DAC_PTR_VAR    (uint8_t*,              internal_root_array)
 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)
@@ -61,6 +61,7 @@ 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)
+GC_DAC_ARRAY_VAR  (int,                   generation_field_offsets)
 
 #undef GC_DAC_VAR
 #undef GC_DAC_ARRAY_VAR
index a310514..cda8e68 100644 (file)
@@ -851,12 +851,6 @@ public:
 #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.