Make sure ServerGCHeapDetails is up to date (#56056)
authorAndrew Au <andrewau@microsoft.com>
Mon, 2 Aug 2021 23:39:24 +0000 (16:39 -0700)
committerGitHub <noreply@github.com>
Mon, 2 Aug 2021 23:39:24 +0000 (16:39 -0700)
src/coreclr/debug/daccess/request.cpp
src/coreclr/debug/daccess/request_common.h
src/coreclr/debug/daccess/request_svr.cpp
src/coreclr/gc/gc.cpp
src/coreclr/gc/gc_typefields.h [new file with mode: 0644]
src/coreclr/gc/gcinterface.dac.h
src/coreclr/gc/gcinterface.dacvars.def
src/coreclr/gc/gcpriv.h

index 9686644..4e729c8 100644 (file)
@@ -2772,19 +2772,24 @@ ClrDataAccess::GetGCHeapDetails(CLRDATA_ADDRESS heap, struct DacpGcHeapDetails *
 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)
     {
@@ -2801,13 +2806,12 @@ ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
     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;
@@ -2817,7 +2821,7 @@ ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
     {
         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*));
         }
@@ -4699,13 +4703,13 @@ HRESULT ClrDataAccess::GetGenerationTableSvr(CLRDATA_ADDRESS heapAddr, unsigned
     }
     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);
@@ -4749,10 +4753,11 @@ HRESULT ClrDataAccess::GetFinalizationFillPointersSvr(CLRDATA_ADDRESS heapAddr,
     }
     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)
index d5f60df..1b86b46 100644 (file)
@@ -26,6 +26,16 @@ DPTR(T) Dereference(DPTR(T*) ptr)
     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)
@@ -34,24 +44,99 @@ 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.
+// 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_
index 558ac0c..691171f 100644 (file)
@@ -64,7 +64,7 @@ HRESULT GetServerHeaps(CLRDATA_ADDRESS pGCHeaps[], ICorDebugDataTarget * pTarget
     // 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;
@@ -86,7 +86,7 @@ HRESULT ClrDataAccess::GetServerAllocData(unsigned int count, struct DacpGenerat
 
         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);
@@ -99,33 +99,57 @@ HRESULT ClrDataAccess::GetServerAllocData(unsigned int count, struct DacpGenerat
     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);
@@ -134,10 +158,13 @@ HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapD
     }
 
     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;
@@ -146,7 +173,9 @@ HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapD
 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;
@@ -193,7 +222,9 @@ HRESULT ClrDataAccess::ServerGCHeapAnalyzeData(CLRDATA_ADDRESS heapAddr, DacpGcH
         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;
@@ -221,7 +252,9 @@ ClrDataAccess::EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
 
     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));
@@ -235,7 +268,7 @@ 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(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));
@@ -270,18 +303,20 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
     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
@@ -300,9 +335,9 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
         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;
             }
index 51af192..9c8acf3 100644 (file)
@@ -45569,6 +45569,27 @@ bool GCHeap::IsConcurrentGCEnabled()
 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
@@ -45582,10 +45603,10 @@ void PopulateDacVars(GcDacVars *gcDacVars)
     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;
@@ -45614,7 +45635,8 @@ void PopulateDacVars(GcDacVars *gcDacVars)
 #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);
diff --git a/src/coreclr/gc/gc_typefields.h b/src/coreclr/gc/gc_typefields.h
new file mode 100644 (file)
index 0000000..f690a6c
--- /dev/null
@@ -0,0 +1,32 @@
+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
index 348279b..3a4697a 100644 (file)
@@ -136,17 +136,17 @@ struct oom_history
 // 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.
@@ -162,6 +162,12 @@ public:
     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
index b572e6c..2f27df7 100644 (file)
@@ -53,13 +53,14 @@ 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    (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
index 36a1e83..bbc7e05 100644 (file)
@@ -3426,9 +3426,6 @@ public:
     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;
@@ -3468,12 +3465,9 @@ public:
     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.
@@ -4941,26 +4935,6 @@ protected:
     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
 {