summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSean Gillespie <sean@swgillespie.me>2017-02-24 10:12:26 -0800
committerGitHub <noreply@github.com>2017-02-24 10:12:26 -0800
commit6f6fda958dac38896abe9487def2242add822809 (patch)
treee9b2eed3562a07635a868c01289f3732b609dc38 /src
parent3392356945aabd5a3ebac5317ff4a0e0361dc9ad (diff)
downloadcoreclr-6f6fda958dac38896abe9487def2242add822809.tar.gz
coreclr-6f6fda958dac38896abe9487def2242add822809.tar.bz2
coreclr-6f6fda958dac38896abe9487def2242add822809.zip
[Local GC] Move workstation GC DAC globals to a struct shared between GC and DAC (#9255)
* [Local GC] Move workstation GC DAC globals to a struct shared between the GC and the DAC * (Some) code review feedback and bug fixes for issues found while debugging on OSX * Address some code review feedback: 1. Make g_gcDacGlobals a pointer and dacvar on the VM side, so that publishing the GC dac vars is done atomically (through a pointer assignment). This fixes a race that Noah noticed. 2. Remove the requirement for the GC's generation class struct to be known at compile-time, by using a dacvar as the size of the generation class at run-time (for pointer arithmetic) 3. Move all DAC-interesting fields to be at the start of GC internal classes, so that the DAC does not need to know the size or exact layout of the class past the fields it cares about. * Split the definition of the size of several arrays across the SOS/DAC and GC/DAC interfaces, and add static asserts that they are the same * Repair the Windows Release build * Implement the GC DAC scheme for Server GC and eliminate the duplicate GC dac vars * Some work * Decouple use of the GC generation table from a write barrier by having the EE store a copy of the global during initialization * Actually make it work with server GC * Checkpoint * Checkpoint where everything works * Code cleanup * Fix debugger test failures * Additional code cleanup * Address code review feedback by adding a static assert and standardizing the way that we iterate over the generation table * Repair the Windows x86 build * Revert "Decouple use of the GC generation table from a write barrier by having the EE store a copy of the global during initialization" This reverts commit 573f61a16b4fa8c2fc4c568c0b968a921230f31c. * Revert "Repair the Windows x86 build" This reverts commit 188c22d87e1d65abf00ab8fa28f46ad607a9028f. * Partial revert, move `generation_table` back the global namespace for a single-proc allocation helper * Fix a debugger test failure * Repair crash dump scenarios
Diffstat (limited to 'src')
-rw-r--r--src/ToolBox/SOS/Strike/strike.cpp10
-rw-r--r--src/debug/daccess/CMakeLists.txt1
-rw-r--r--src/debug/daccess/daccess.cpp7
-rw-r--r--src/debug/daccess/dacdbiimpl.cpp31
-rw-r--r--src/debug/daccess/dacfn.cpp4
-rw-r--r--src/debug/daccess/enummem.cpp6
-rw-r--r--src/debug/daccess/gcinterface.dac.h5
-rw-r--r--src/debug/daccess/request.cpp128
-rw-r--r--src/debug/daccess/request_common.h58
-rw-r--r--src/debug/daccess/request_svr.cpp170
-rw-r--r--src/gc/env/gcenv.structs.h2
-rw-r--r--src/gc/gc.cpp117
-rw-r--r--src/gc/gc.h43
-rw-r--r--src/gc/gccommon.cpp55
-rw-r--r--src/gc/gcinterface.dac.h162
-rw-r--r--src/gc/gcinterface.dacvars.def67
-rw-r--r--src/gc/gcinterface.h7
-rw-r--r--src/gc/gcpriv.h233
-rw-r--r--src/gc/gcscan.h1
-rw-r--r--src/gc/sample/GCSample.cpp7
-rw-r--r--src/inc/dacprivate.h23
-rw-r--r--src/inc/dacvars.h33
-rw-r--r--src/vm/ceemain.cpp18
-rw-r--r--src/vm/gcheaputilities.cpp5
-rw-r--r--src/vm/gcheaputilities.h39
25 files changed, 764 insertions, 468 deletions
diff --git a/src/ToolBox/SOS/Strike/strike.cpp b/src/ToolBox/SOS/Strike/strike.cpp
index 31c58dfe4d..2b54b4f037 100644
--- a/src/ToolBox/SOS/Strike/strike.cpp
+++ b/src/ToolBox/SOS/Strike/strike.cpp
@@ -8838,28 +8838,28 @@ void PrintInterestingGCInfo(DacpGCInterestingInfoData* dataPerHeap)
{
ExtOut("Interesting data points\n");
size_t* data = dataPerHeap->interestingDataPoints;
- for (int i = 0; i < NUM_GC_DATA_POINTS; i++)
+ for (int i = 0; i < DAC_NUM_GC_DATA_POINTS; i++)
{
ExtOut("%20s: %d\n", str_interesting_data_points[i], data[i]);
}
ExtOut("\nCompacting reasons\n");
data = dataPerHeap->compactReasons;
- for (int i = 0; i < MAX_COMPACT_REASONS_COUNT; i++)
+ for (int i = 0; i < DAC_MAX_COMPACT_REASONS_COUNT; i++)
{
ExtOut("[%s]%35s: %d\n", (gc_heap_compact_reason_mandatory_p[i] ? "M" : "W"), str_heap_compact_reasons[i], data[i]);
}
ExtOut("\nExpansion mechanisms\n");
data = dataPerHeap->expandMechanisms;
- for (int i = 0; i < MAX_EXPAND_MECHANISMS_COUNT; i++)
+ for (int i = 0; i < DAC_MAX_EXPAND_MECHANISMS_COUNT; i++)
{
ExtOut("%30s: %d\n", str_heap_expand_mechanisms[i], data[i]);
}
ExtOut("\nOther mechanisms enabled\n");
data = dataPerHeap->bitMechanisms;
- for (int i = 0; i < MAX_GC_MECHANISM_BITS_COUNT; i++)
+ for (int i = 0; i < DAC_MAX_GC_MECHANISM_BITS_COUNT; i++)
{
ExtOut("%20s: %d\n", str_bit_mechanisms[i], data[i]);
}
@@ -8881,7 +8881,7 @@ DECLARE_API(DumpGCData)
DacpGCInterestingInfoData interestingInfo;
interestingInfo.RequestGlobal(g_sos);
- for (int i = 0; i < MAX_GLOBAL_GC_MECHANISMS_COUNT; i++)
+ for (int i = 0; i < DAC_MAX_GLOBAL_GC_MECHANISMS_COUNT; i++)
{
ExtOut("%-30s: %d\n", str_gc_global_mechanisms[i], interestingInfo.globalMechanisms[i]);
}
diff --git a/src/debug/daccess/CMakeLists.txt b/src/debug/daccess/CMakeLists.txt
index 30068450b4..daf2773261 100644
--- a/src/debug/daccess/CMakeLists.txt
+++ b/src/debug/daccess/CMakeLists.txt
@@ -7,7 +7,6 @@ include_directories(BEFORE ${VM_DIR})
include_directories(BEFORE ${VM_DIR}/${ARCH_SOURCES_DIR})
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CLR_DIR}/src/debug/ee)
-include_directories(${CLR_DIR}/src/gc)
include_directories(${CLR_DIR}/src/gcdump)
if(CLR_CMAKE_PLATFORM_UNIX)
diff --git a/src/debug/daccess/daccess.cpp b/src/debug/daccess/daccess.cpp
index 69167ab07e..841d31c889 100644
--- a/src/debug/daccess/daccess.cpp
+++ b/src/debug/daccess/daccess.cpp
@@ -7934,7 +7934,8 @@ STDAPI OutOfProcessExceptionEventDebuggerLaunchCallback(__in PDWORD pContext,
// DacHandleEnum
-#include "handletablepriv.h"
+// TODO(Local GC) - The DAC should not include GC headers
+#include "../../gc/handletablepriv.h"
#include "comcallablewrapper.h"
DacHandleWalker::DacHandleWalker()
@@ -7976,7 +7977,7 @@ HRESULT DacHandleWalker::Init(ClrDataAccess *dac, UINT types[], UINT typeCount,
{
SUPPORTS_DAC;
- if (gen < 0 || gen > (int)GCHeapUtilities::GetMaxGeneration())
+ if (gen < 0 || gen > (int)*g_gcDacGlobals->max_gen)
return E_INVALIDARG;
mGenerationFilter = gen;
@@ -8091,7 +8092,7 @@ bool DacHandleWalker::FetchMoreHandles(HANDLESCANPROC callback)
HndScanHandlesForGC(hTable, callback,
(LPARAM)&param, 0,
&handleType, 1,
- mGenerationFilter, GCHeapUtilities::GetMaxGeneration(), 0);
+ mGenerationFilter, *g_gcDacGlobals->max_gen, 0);
else
HndEnumHandles(hTable, &handleType, 1, callback, (LPARAM)&param, 0, FALSE);
}
diff --git a/src/debug/daccess/dacdbiimpl.cpp b/src/debug/daccess/dacdbiimpl.cpp
index c6c71a28ff..6618eb57b9 100644
--- a/src/debug/daccess/dacdbiimpl.cpp
+++ b/src/debug/daccess/dacdbiimpl.cpp
@@ -31,6 +31,8 @@
#include "comcallablewrapper.h"
#endif // FEATURE_COMINTEROP
+#include "request_common.h"
+
//-----------------------------------------------------------------------------
// Have standard enter and leave macros at the DacDbi boundary to enforce
// standard behavior.
@@ -6578,7 +6580,6 @@ HRESULT DacHeapWalker::ListNearObjects(CORDB_ADDRESS obj, CORDB_ADDRESS *pPrev,
return hr;
}
-#include "gceewks.cpp"
HRESULT DacHeapWalker::InitHeapDataWks(HeapData *&pHeaps, size_t &pCount)
{
// Scrape basic heap details
@@ -6587,16 +6588,20 @@ HRESULT DacHeapWalker::InitHeapDataWks(HeapData *&pHeaps, size_t &pCount)
if (pHeaps == NULL)
return E_OUTOFMEMORY;
- pHeaps[0].YoungestGenPtr = (CORDB_ADDRESS)WKS::generation_table[0].allocation_context.alloc_ptr;
- pHeaps[0].YoungestGenLimit = (CORDB_ADDRESS)WKS::generation_table[0].allocation_context.alloc_limit;
+ 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);
+ 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)WKS::generation_table[0].allocation_start;
- pHeaps[0].Gen0End = (CORDB_ADDRESS)WKS::gc_heap::alloc_allocated.GetAddr();
- pHeaps[0].Gen1Start = (CORDB_ADDRESS)WKS::generation_table[1].allocation_start;
+ 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(WKS::generation_table[NUMBERGENERATIONS-1].start_segment);
- count += GetSegmentCount(WKS::generation_table[NUMBERGENERATIONS-2].start_segment);
+ int count = GetSegmentCount(loh.start_segment);
+ count += GetSegmentCount(gen2.start_segment);
pHeaps[0].SegmentCount = count;
pHeaps[0].Segments = new (nothrow) SegmentData[count];
@@ -6604,14 +6609,14 @@ HRESULT DacHeapWalker::InitHeapDataWks(HeapData *&pHeaps, size_t &pCount)
return E_OUTOFMEMORY;
// Small object heap segments
- WKS::heap_segment *seg = WKS::generation_table[NUMBERGENERATIONS-2].start_segment;
+ DPTR(dac_heap_segment) seg = gen2.start_segment;
int i = 0;
for (; seg && (i < count); ++i)
{
pHeaps[0].Segments[i].Start = (CORDB_ADDRESS)seg->mem;
- if (seg == WKS::gc_heap::ephemeral_heap_segment)
+ if (seg.GetAddr() == (TADDR)*g_gcDacGlobals->ephemeral_heap_segment)
{
- pHeaps[0].Segments[i].End = (CORDB_ADDRESS)WKS::gc_heap::alloc_allocated.GetAddr();
+ pHeaps[0].Segments[i].End = (CORDB_ADDRESS)*g_gcDacGlobals->alloc_allocated;
pHeaps[0].Segments[i].Generation = 1;
pHeaps[0].EphemeralSegment = i;
}
@@ -6625,7 +6630,7 @@ HRESULT DacHeapWalker::InitHeapDataWks(HeapData *&pHeaps, size_t &pCount)
}
// Large object heap segments
- seg = WKS::generation_table[NUMBERGENERATIONS-1].start_segment;
+ seg = loh.start_segment;
for (; seg && (i < count); ++i)
{
pHeaps[0].Segments[i].Generation = 3;
@@ -7127,7 +7132,7 @@ void DacDbiInterfaceImpl::GetGCHeapInformation(COR_HEAPINFO * pHeapInfo)
DD_ENTER_MAY_THROW;
size_t heapCount = 0;
- pHeapInfo->areGCStructuresValid = GCScan::GetGcRuntimeStructuresValid();
+ pHeapInfo->areGCStructuresValid = *g_gcDacGlobals->gc_structures_invalid_cnt == 0;
#ifdef FEATURE_SVR_GC
if (GCHeapUtilities::IsServerHeap())
diff --git a/src/debug/daccess/dacfn.cpp b/src/debug/daccess/dacfn.cpp
index 3d729ba371..0a167418a1 100644
--- a/src/debug/daccess/dacfn.cpp
+++ b/src/debug/daccess/dacfn.cpp
@@ -19,6 +19,10 @@
#include <virtualcallstub.h>
#include "peimagelayout.inl"
+#include "gcinterface.h"
+#include "gcinterface.dac.h"
+
+
DacTableInfo g_dacTableInfo;
DacGlobals g_dacGlobals;
diff --git a/src/debug/daccess/enummem.cpp b/src/debug/daccess/enummem.cpp
index 7e29fcdfc4..4a217d022f 100644
--- a/src/debug/daccess/enummem.cpp
+++ b/src/debug/daccess/enummem.cpp
@@ -266,6 +266,12 @@ HRESULT ClrDataAccess::EnumMemCLRStatic(IN CLRDataEnumMemoryFlags flags)
ReportMem( m_globalBase + g_dacGlobals.dac__g_FCDynamicallyAssignedImplementations,
sizeof(TADDR)*ECall::NUM_DYNAMICALLY_ASSIGNED_FCALL_IMPLEMENTATIONS);
+
+ // We need all of the dac variables referenced by the GC DAC global struct.
+ // This struct contains pointers to pointers, so we first dereference the pointers
+ // to obtain the location of the variable that's reported.
+#define GC_DAC_VAR(type, name) ReportMem(g_gcDacGlobals->name.GetAddr(), sizeof(type));
+#include "../../gc/gcinterface.dacvars.def"
}
EX_CATCH_RETHROW_ONLY_COR_E_OPERATIONCANCELLED
diff --git a/src/debug/daccess/gcinterface.dac.h b/src/debug/daccess/gcinterface.dac.h
new file mode 100644
index 0000000000..031ec36f30
--- /dev/null
+++ b/src/debug/daccess/gcinterface.dac.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "../../gc/gcinterface.dac.h"
diff --git a/src/debug/daccess/request.cpp b/src/debug/daccess/request.cpp
index 5c0f021f70..88efe22c16 100644
--- a/src/debug/daccess/request.cpp
+++ b/src/debug/daccess/request.cpp
@@ -13,8 +13,8 @@
#include "stdafx.h"
#include <win32threadpool.h>
-#include <gceewks.cpp>
-#include <handletablepriv.h>
+// TODO(Local GC) - The DAC should not include GC headers
+#include <../../gc/handletablepriv.h>
#include "typestring.h"
#include <gccover.h>
#include <virtualcallstub.h>
@@ -31,7 +31,7 @@
#include <exstatecommon.h>
#include "rejit.h"
-
+#include "request_common.h"
// GC headers define these to EE-specific stuff that we don't want.
#undef EnterCriticalSection
@@ -264,7 +264,6 @@ VOID GetJITMethodInfo (EECodeInfo * pCodeInfo, JITTypes *pJITType, CLRDATA_ADDRE
*pGCInfo = (CLRDATA_ADDRESS)PTR_TO_TADDR(pCodeInfo->GetGCInfo());
}
-
HRESULT
ClrDataAccess::GetWorkRequestData(CLRDATA_ADDRESS addr, struct DacpWorkRequestData *workRequestData)
{
@@ -737,10 +736,12 @@ ClrDataAccess::GetHeapAllocData(unsigned int count, struct DacpGenerationAllocDa
if (data && count >= 1)
{
- for (int i=0;i<NUMBERGENERATIONS;i++)
+ DPTR(dac_generation) table = g_gcDacGlobals->generation_table;
+ for (unsigned int i=0; i < *g_gcDacGlobals->max_gen + 2; i++)
{
- data[0].allocData[i].allocBytes = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_context.alloc_bytes;
- data[0].allocData[i].allocBytesLoh = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_context.alloc_bytes_loh;
+ 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_loh;
}
}
}
@@ -2810,43 +2811,34 @@ ClrDataAccess::GetGCHeapStaticData(struct DacpGcHeapDetails *detailsData)
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->alloc_allocated = (CLRDATA_ADDRESS)*g_gcDacGlobals->alloc_allocated;
+ detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)*g_gcDacGlobals->ephemeral_heap_segment;
+ 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;
+ detailsData->saved_sweep_ephemeral_seg = (CLRDATA_ADDRESS)*g_gcDacGlobals->saved_sweep_ephemeral_seg;
+ detailsData->saved_sweep_ephemeral_start = (CLRDATA_ADDRESS)*g_gcDacGlobals->saved_sweep_ephemeral_start;
+ 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;
- detailsData->alloc_allocated = PTR_CDADDR(WKS::gc_heap::alloc_allocated);
- detailsData->ephemeral_heap_segment = PTR_CDADDR(WKS::gc_heap::ephemeral_heap_segment);
+ for (unsigned int i=0; i < *g_gcDacGlobals->max_gen + 2; 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);
-#ifdef BACKGROUND_GC
- detailsData->mark_array = PTR_CDADDR(WKS::gc_heap::mark_array);
- detailsData->current_c_gc_state = (CLRDATA_ADDRESS)(ULONG_PTR)WKS::gc_heap::current_c_gc_state;
- detailsData->next_sweep_obj = PTR_CDADDR(WKS::gc_heap::next_sweep_obj);
- detailsData->saved_sweep_ephemeral_seg = PTR_CDADDR(WKS::gc_heap::saved_sweep_ephemeral_seg);
- detailsData->saved_sweep_ephemeral_start = PTR_CDADDR(WKS::gc_heap::saved_sweep_ephemeral_start);
- detailsData->background_saved_lowest_address = PTR_CDADDR(WKS::gc_heap::background_saved_lowest_address);
- detailsData->background_saved_highest_address = PTR_CDADDR(WKS::gc_heap::background_saved_highest_address);
-#endif //BACKGROUND_GC
+ detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS) generation->allocation_start;
- for (int i=0;i<NUMBERGENERATIONS;i++)
- {
- detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(WKS::generation_table[i].start_segment);
- detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_start;
- detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_context.alloc_ptr;
- detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR) WKS::generation_table[i].allocation_context.alloc_limit;
+ 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;
}
- TADDR pFillPointerArray = TO_TADDR(WKS::gc_heap::finalize_queue.GetAddr()) + offsetof(WKS::CFinalize,m_FillPointers);
- for(int i=0;i<(NUMBERGENERATIONS+WKS::CFinalize::ExtraSegCount);i++)
+ 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++)
{
- ULONG32 returned = 0;
- size_t pValue;
- hr = m_pTarget->ReadVirtual(pFillPointerArray+(i*sizeof(size_t)), (PBYTE)&pValue, sizeof(size_t), &returned);
- if (SUCCEEDED(hr))
- {
- if (returned == sizeof(size_t))
- detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pValue;
- else
- hr = E_FAIL;
- }
+ detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS)*TableIndex(fillPointersTable, i, sizeof(uint8_t*));
}
SOSDacLeave();
@@ -2871,7 +2863,7 @@ ClrDataAccess::GetHeapSegmentData(CLRDATA_ADDRESS seg, struct DacpHeapSegmentDat
}
else
{
- WKS::heap_segment *pSegment = __DPtr<WKS::heap_segment>(TO_TADDR(seg));
+ dac_heap_segment *pSegment = __DPtr<dac_heap_segment>(TO_TADDR(seg));
if (!pSegment)
{
hr = E_INVALIDARG;
@@ -2941,7 +2933,7 @@ ClrDataAccess::GetGCHeapData(struct DacpGcHeapData *gcheapData)
// is GC_HEAP_INVALID, in which case we fail.
// IGCHeap::gcHeapType doesn't exist on non-server-GC capable builds.
#ifdef FEATURE_SVR_GC
- ULONG32 gcHeapValue = IGCHeap::gcHeapType;
+ ULONG32 gcHeapValue = *g_gcDacGlobals->gc_heap_type;
// GC_HEAP_TYPE has three possible values:
// GC_HEAP_INVALID = 0,
@@ -2959,9 +2951,9 @@ ClrDataAccess::GetGCHeapData(struct DacpGcHeapData *gcheapData)
#endif
// Now we can get other important information about the heap
- gcheapData->g_max_generation = GCHeapUtilities::GetMaxGeneration();
- gcheapData->bServerMode = GCHeapUtilities::IsServerHeap();
- gcheapData->bGcStructuresValid = GCScan::GetGcRuntimeStructuresValid();
+ gcheapData->g_max_generation = *g_gcDacGlobals->max_gen;
+ gcheapData->bServerMode = gcHeapValue == IGCHeap::GC_HEAP_SVR;
+ gcheapData->bGcStructuresValid = *g_gcDacGlobals->gc_structures_invalid_cnt == 0;
if (GCHeapUtilities::IsServerHeap())
{
#if !defined (FEATURE_SVR_GC)
@@ -2997,7 +2989,7 @@ ClrDataAccess::GetOOMStaticData(struct DacpOomData *oomData)
if (!GCHeapUtilities::IsServerHeap())
{
- oom_history* pOOMInfo = &(WKS::gc_heap::oom_info);
+ oom_history* pOOMInfo = g_gcDacGlobals->oom_info;
oomData->reason = pOOMInfo->reason;
oomData->alloc_size = pOOMInfo->alloc_size;
oomData->available_pagefile_mb = pOOMInfo->available_pagefile_mb;
@@ -3051,7 +3043,7 @@ ClrDataAccess::GetGCGlobalMechanisms(size_t* globalMechanisms)
for (int i = 0; i < MAX_GLOBAL_GC_MECHANISMS_COUNT; i++)
{
- globalMechanisms[i] = gc_global_mechanisms[i];
+ globalMechanisms[i] = g_gcDacGlobals->gc_global_mechanisms[i];
}
SOSDacLeave();
@@ -3068,19 +3060,25 @@ ClrDataAccess::GetGCInterestingInfoStaticData(struct DacpGCInterestingInfoData *
if (data == NULL)
return E_INVALIDARG;
+ static_assert_no_msg(DAC_NUMBERGENERATIONS == NUMBERGENERATIONS);
+ static_assert_no_msg(DAC_NUM_GC_DATA_POINTS == NUM_GC_DATA_POINTS);
+ static_assert_no_msg(DAC_MAX_COMPACT_REASONS_COUNT == MAX_COMPACT_REASONS_COUNT);
+ static_assert_no_msg(DAC_MAX_EXPAND_MECHANISMS_COUNT == MAX_EXPAND_MECHANISMS_COUNT);
+ static_assert_no_msg(DAC_MAX_GC_MECHANISM_BITS_COUNT == MAX_GC_MECHANISM_BITS_COUNT);
+
SOSDacEnter();
memset(data, 0, sizeof(DacpGCInterestingInfoData));
- if (!GCHeapUtilities::IsServerHeap())
+ if (*g_gcDacGlobals->gc_heap_type != IGCHeap::GC_HEAP_SVR)
{
for (int i = 0; i < NUM_GC_DATA_POINTS; i++)
- data->interestingDataPoints[i] = WKS::interesting_data_per_heap[i];
+ data->interestingDataPoints[i] = g_gcDacGlobals->interesting_data_per_heap[i];
for (int i = 0; i < MAX_COMPACT_REASONS_COUNT; i++)
- data->compactReasons[i] = WKS::compact_reasons_per_heap[i];
+ data->compactReasons[i] = g_gcDacGlobals->compact_reasons_per_heap[i];
for (int i = 0; i < MAX_EXPAND_MECHANISMS_COUNT; i++)
- data->expandMechanisms[i] = WKS::expand_mechanisms_per_heap[i];
+ data->expandMechanisms[i] = g_gcDacGlobals->expand_mechanisms_per_heap[i];
for (int i = 0; i < MAX_GC_MECHANISM_BITS_COUNT; i++)
- data->bitMechanisms[i] = WKS::interesting_mechanism_bits_per_heap[i];
+ data->bitMechanisms[i] = g_gcDacGlobals->interesting_mechanism_bits_per_heap[i];
}
else
{
@@ -3153,9 +3151,9 @@ ClrDataAccess::GetHeapAnalyzeStaticData(struct DacpGcHeapAnalyzeData *analyzeDat
SOSDacEnter();
- analyzeData->internal_root_array = PTR_CDADDR(WKS::gc_heap::internal_root_array);
- analyzeData->internal_root_array_index = (size_t) WKS::gc_heap::internal_root_array_index;
- analyzeData->heap_analyze_success = (BOOL) WKS::gc_heap::heap_analyze_success;
+ analyzeData->internal_root_array = dac_cast<TADDR>(g_gcDacGlobals->internal_root_array);
+ analyzeData->internal_root_array_index = *g_gcDacGlobals->internal_root_array_index;
+ analyzeData->heap_analyze_success = *g_gcDacGlobals->heap_analyze_success;
SOSDacLeave();
return hr;
@@ -3826,25 +3824,29 @@ void
ClrDataAccess::EnumWksGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
{
SUPPORTS_DAC;
- WKS::gc_heap::ephemeral_heap_segment.EnumMem();
- WKS::gc_heap::alloc_allocated.EnumMem();
- WKS::gc_heap::finalize_queue.EnumMem();
- WKS::generation_table.EnumMem();
- WKS::gc_heap::oom_info.EnumMem();
- if (WKS::generation_table.IsValid())
+ Dereference(g_gcDacGlobals->ephemeral_heap_segment).EnumMem();
+ g_gcDacGlobals->alloc_allocated.EnumMem();
+ Dereference(g_gcDacGlobals->finalize_queue).EnumMem();
+
+ // Enumerate the entire generation table, which has variable size
+ size_t gen_table_size = g_gcDacGlobals->generation_size * (*g_gcDacGlobals->max_gen + 1);
+ DacEnumMemoryRegion(dac_cast<TADDR>(g_gcDacGlobals->generation_table), gen_table_size);
+
+ if (g_gcDacGlobals->generation_table.IsValid())
{
// enumerating the generations from max (which is normally gen2) to max+1 gives you
// the segment list for all the normal segements plus the large heap segment (max+1)
// this is the convention in the GC so it is repeated here
- for (ULONG i = GCHeapUtilities::GetMaxGeneration(); i <= GCHeapUtilities::GetMaxGeneration()+1; i++)
+ for (ULONG i = *g_gcDacGlobals->max_gen; i <= *g_gcDacGlobals->max_gen +1; i++)
{
- __DPtr<WKS::heap_segment> seg = dac_cast<TADDR>(WKS::generation_table[i].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(WKS::heap_segment));
+ DacEnumMemoryRegion(dac_cast<TADDR>(seg), sizeof(dac_heap_segment));
- seg = __DPtr<WKS::heap_segment>(dac_cast<TADDR>(seg->next));
+ seg = seg->next;
}
}
}
@@ -4355,4 +4357,4 @@ HRESULT ClrDataAccess::GetClrNotification(CLRDATA_ADDRESS arguments[], int count
SOSDacLeave();
return hr;;
-} \ No newline at end of file
+}
diff --git a/src/debug/daccess/request_common.h b/src/debug/daccess/request_common.h
new file mode 100644
index 0000000000..aef46b14ff
--- /dev/null
+++ b/src/debug/daccess/request_common.h
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// This file contains functions used by both request.cpp and request_svr.cpp
+// to communicate with the debuggee's GC.
+
+#ifndef _REQUEST_COMMON_H_
+#define _REQUEST_COMMON_H_
+
+// Indexes into an array of elements of type T, where the size of type
+// T is not (or may not be) known at compile-time.
+// Returns a DPTR to the requested element (the element at the given index).
+template<typename T>
+DPTR(T) TableIndex(DPTR(T) base, size_t index, size_t t_size)
+{
+ TADDR base_addr = base.GetAddr();
+ TADDR element_addr = DacTAddrOffset(base_addr, index, t_size);
+ return __DPtr<T>(element_addr);
+}
+
+// Dereferences a DPTR(T*), yielding a DPTR(T).
+template<typename T>
+DPTR(T) Dereference(DPTR(T*) ptr)
+{
+ TADDR ptr_base = (TADDR)*ptr;
+ return __DPtr<T>(ptr_base);
+}
+
+// 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);
+}
+
+// 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)
+{
+ 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);
+}
+
+// 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)
+{
+ DPTR(dac_gc_heap*) heap_table = Dereference(heaps);
+ DPTR(dac_gc_heap*) ptr = TableIndex(heap_table, index, sizeof(dac_gc_heap*));
+ return Dereference(ptr);
+}
+
+#endif // _REQUEST_COMMON_H_
diff --git a/src/debug/daccess/request_svr.cpp b/src/debug/daccess/request_svr.cpp
index 1fe20e2b60..4a90ec1b8e 100644
--- a/src/debug/daccess/request_svr.cpp
+++ b/src/debug/daccess/request_svr.cpp
@@ -18,13 +18,11 @@
#include <sigformat.h>
#include <win32threadpool.h>
-
-#include <gceesvr.cpp>
-
+#include "request_common.h"
int GCHeapCount()
{
- return SVR::gc_heap::n_heaps;
+ return *g_gcDacGlobals->n_heaps;
}
HRESULT GetServerHeapData(CLRDATA_ADDRESS addr, DacpHeapSegmentData *pSegment)
@@ -37,8 +35,7 @@ HRESULT GetServerHeapData(CLRDATA_ADDRESS addr, DacpHeapSegmentData *pSegment)
}
// marshal the segment from target to host
- SVR::heap_segment *pHeapSegment =
- __DPtr<SVR::heap_segment>(TO_TADDR(addr));
+ dac_heap_segment *pHeapSegment = __DPtr<dac_heap_segment>(TO_TADDR(addr));
// initialize fields by copying from the marshaled segment (note that these are all target addresses)
pSegment->segmentAddr = addr;
@@ -48,7 +45,7 @@ HRESULT GetServerHeapData(CLRDATA_ADDRESS addr, DacpHeapSegmentData *pSegment)
pSegment->used = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->used;
pSegment->mem = (CLRDATA_ADDRESS)(ULONG_PTR) (pHeapSegment->mem);
pSegment->next = (CLRDATA_ADDRESS)dac_cast<TADDR>(pHeapSegment->next);
- pSegment->gc_heap = (CLRDATA_ADDRESS)(ULONG_PTR) pHeapSegment->heap;
+ pSegment->gc_heap = (CLRDATA_ADDRESS)pHeapSegment->heap;
return S_OK;
}
@@ -64,42 +61,20 @@ HRESULT GetServerHeaps(CLRDATA_ADDRESS pGCHeaps[], ICorDebugDataTarget * pTarget
// a DAC global (__GlobalPtr). The __GlobalPtr<...>::GetAddr() function gets the starting address of that global, but
// be sure to note this is a target address. We'll use this as our source for getting our local list of
// heap addresses.
- TADDR ptr = SVR::gc_heap::g_heaps.GetAddr();
- ULONG32 bytesRead = 0;
-
- for (int i=0;i<GCHeapCount();i++)
+ for (int i = 0; i < GCHeapCount(); i++)
{
-
- LPVOID pGCHeapAddr;
-
- // read the i-th element of g_heaps into pGCHeapAddr
- // @todo Microsoft: Again, if we capture the HRESULT from ReadVirtual, we can print a more explanatory
- // failure message.
- if (pTarget->ReadVirtual(ptr + i*sizeof(TADDR),
- (PBYTE) &pGCHeapAddr, sizeof(TADDR),
- &bytesRead) != S_OK)
- {
- return E_FAIL;
- }
- if (bytesRead != sizeof(LPVOID))
- {
- return E_FAIL;
- }
-
- // store the heap's starting address in our array.
- pGCHeaps[i] = (CLRDATA_ADDRESS)(ULONG_PTR) pGCHeapAddr;
+ pGCHeaps[i] = (CLRDATA_ADDRESS)HeapTableIndex(g_gcDacGlobals->g_heaps, i).GetAddr();
}
+
return S_OK;
}
#define PTR_CDADDR(ptr) TO_CDADDR(PTR_TO_TADDR(ptr))
#define HOST_CDADDR(host) TO_CDADDR(PTR_HOST_TO_TADDR(host))
-typedef DPTR(class SVR::gc_heap) PTR_SVR_gc_heap;
-
HRESULT ClrDataAccess::GetServerAllocData(unsigned int count, struct DacpGenerationAllocData *data, unsigned int *pNeeded)
{
- unsigned int heaps = (unsigned int)SVR::gc_heap::n_heaps;
+ unsigned int heaps = (unsigned int)GCHeapCount();
if (pNeeded)
*pNeeded = heaps;
@@ -108,13 +83,14 @@ HRESULT ClrDataAccess::GetServerAllocData(unsigned int count, struct DacpGenerat
if (count > heaps)
count = heaps;
- for (int n=0;n<SVR::gc_heap::n_heaps;n++)
+ for (unsigned int n=0; n < heaps; n++)
{
- PTR_SVR_gc_heap pHeap = PTR_SVR_gc_heap(SVR::gc_heap::g_heaps[n]);
+ DPTR(dac_gc_heap) pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, n);
for (int i=0;i<NUMBERGENERATIONS;i++)
{
- data[n].allocData[i].allocBytes = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_context.alloc_bytes;
- data[n].allocData[i].allocBytesLoh = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_context.alloc_bytes_loh;
+ 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_loh;
}
}
}
@@ -130,7 +106,7 @@ HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapD
return E_INVALIDARG;
}
- SVR::gc_heap *pHeap = PTR_SVR_gc_heap(TO_TADDR(heapAddr));
+ DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
int i;
//get global information first
@@ -142,35 +118,25 @@ HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapD
// 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)(ULONG_PTR) pHeap->alloc_allocated;
- detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->ephemeral_heap_segment;
+ detailsData->alloc_allocated = (CLRDATA_ADDRESS)pHeap->alloc_allocated;
+ detailsData->ephemeral_heap_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(pHeap->ephemeral_heap_segment);
// get bounds for the different generations
for (i=0; i<NUMBERGENERATIONS; i++)
{
- detailsData->generation_table[i].start_segment = (CLRDATA_ADDRESS)dac_cast<TADDR>(pHeap->generation_table[i].start_segment);
- detailsData->generation_table[i].allocation_start = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_start;
- detailsData->generation_table[i].allocContextPtr = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_context.alloc_ptr;
- detailsData->generation_table[i].allocContextLimit = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->generation_table[i].allocation_context.alloc_limit;
+ DPTR(dac_generation) generation = ServerGenerationTableIndex(pHeap, 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;
}
- // since these are all TADDRS, we have to compute the address of the m_FillPointers field explicitly
- TADDR pFillPointerArray = dac_cast<TADDR>(pHeap->finalize_queue) + offsetof(SVR::CFinalize,m_FillPointers);
-
- for(i=0; i<(NUMBERGENERATIONS+SVR::CFinalize::ExtraSegCount); i++)
+ 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++)
{
- ULONG32 returned = 0;
- size_t pValue;
- HRESULT hr = m_pTarget->ReadVirtual(pFillPointerArray+(i*sizeof(TADDR)),
- (PBYTE)&pValue,
- sizeof(TADDR),
- &returned);
- if (FAILED(hr) || (returned != sizeof(TADDR)))
- {
- return E_FAIL;
- }
-
- detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pValue;
+ detailsData->finalization_fill_pointers[i] = (CLRDATA_ADDRESS) pFillPointerArray[i];
}
return S_OK;
@@ -179,16 +145,16 @@ HRESULT ClrDataAccess::ServerGCHeapDetails(CLRDATA_ADDRESS heapAddr, DacpGcHeapD
HRESULT
ClrDataAccess::ServerOomData(CLRDATA_ADDRESS addr, DacpOomData *oomData)
{
- SVR::gc_heap *pHeap = PTR_SVR_gc_heap(TO_TADDR(addr));
+ DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(addr));
- oom_history* pOOMInfo = (oom_history*)((TADDR)pHeap + offsetof(SVR::gc_heap,oom_info));
- oomData->reason = pOOMInfo->reason;
- oomData->alloc_size = pOOMInfo->alloc_size;
- oomData->available_pagefile_mb = pOOMInfo->available_pagefile_mb;
- oomData->gc_index = pOOMInfo->gc_index;
- oomData->fgm = pOOMInfo->fgm;
- oomData->size = pOOMInfo->size;
- oomData->loh_p = pOOMInfo->loh_p;
+ oom_history pOOMInfo = pHeap->oom_info;
+ oomData->reason = pOOMInfo.reason;
+ oomData->alloc_size = pOOMInfo.alloc_size;
+ oomData->available_pagefile_mb = pOOMInfo.available_pagefile_mb;
+ oomData->gc_index = pOOMInfo.gc_index;
+ oomData->fgm = pOOMInfo.fgm;
+ oomData->size = pOOMInfo.size;
+ oomData->loh_p = pOOMInfo.loh_p;
return S_OK;
}
@@ -197,7 +163,7 @@ HRESULT
ClrDataAccess::ServerGCInterestingInfoData(CLRDATA_ADDRESS addr, DacpGCInterestingInfoData *interestingInfoData)
{
#ifdef GC_CONFIG_DRIVEN
- SVR::gc_heap *pHeap = PTR_SVR_gc_heap(TO_TADDR(addr));
+ dac_gc_heap *pHeap = __DPtr<dac_gc_heap>(TO_TADDR(addr));
size_t* dataPoints = (size_t*)&(pHeap->interesting_data_per_heap);
for (int i = 0; i < NUM_GC_DATA_POINTS; i++)
@@ -226,11 +192,11 @@ HRESULT ClrDataAccess::ServerGCHeapAnalyzeData(CLRDATA_ADDRESS heapAddr, DacpGcH
return E_INVALIDARG;
}
- SVR::gc_heap *pHeap = PTR_SVR_gc_heap(TO_TADDR(heapAddr));
+ DPTR(dac_gc_heap) pHeap = __DPtr<dac_gc_heap>(TO_TADDR(heapAddr));
analyzeData->heapAddr = heapAddr;
- analyzeData->internal_root_array = (CLRDATA_ADDRESS)(ULONG_PTR) pHeap->internal_root_array;
- analyzeData->internal_root_array_index = (size_t) pHeap->internal_root_array_index;
+ analyzeData->internal_root_array = (CLRDATA_ADDRESS)pHeap->internal_root_array;
+ analyzeData->internal_root_array_index = (size_t)pHeap->internal_root_array_index;
analyzeData->heap_analyze_success = (BOOL)pHeap->heap_analyze_success;
return S_OK;
@@ -240,30 +206,32 @@ void
ClrDataAccess::EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
{
SUPPORTS_DAC;
- SVR::gc_heap::n_heaps.EnumMem();
- DacEnumMemoryRegion(SVR::gc_heap::g_heaps.GetAddr(),
- sizeof(TADDR) * SVR::gc_heap::n_heaps);
+ g_gcDacGlobals->n_heaps.EnumMem();
+ DacEnumMemoryRegion(g_gcDacGlobals->g_heaps.GetAddr(),
+ sizeof(TADDR) * *g_gcDacGlobals->n_heaps);
- SVR::gc_heap::g_heaps.EnumMem();
+ g_gcDacGlobals->g_heaps.EnumMem();
- for (int i=0;i<SVR::gc_heap::n_heaps;i++)
+ for (int i=0; i < *g_gcDacGlobals->n_heaps; i++)
{
- PTR_SVR_gc_heap pHeap = PTR_SVR_gc_heap(SVR::gc_heap::g_heaps[i]);
+ DPTR(dac_gc_heap) pHeap = HeapTableIndex(g_gcDacGlobals->g_heaps, i);
- DacEnumMemoryRegion(dac_cast<TADDR>(pHeap), sizeof(SVR::gc_heap));
- DacEnumMemoryRegion(dac_cast<TADDR>(pHeap->finalize_queue), sizeof(SVR::CFinalize));
+ size_t gen_table_size = g_gcDacGlobals->generation_size * (*g_gcDacGlobals->max_gen + 1);
+ DacEnumMemoryRegion(dac_cast<TADDR>(pHeap), sizeof(dac_gc_heap));
+ DacEnumMemoryRegion(dac_cast<TADDR>(pHeap->finalize_queue), sizeof(dac_finalize_queue));
+ DacEnumMemoryRegion(dac_cast<TADDR>(pHeap->generation_table), gen_table_size);
// enumerating the generations from max (which is normally gen2) to max+1 gives you
// the segment list for all the normal segements plus the large heap segment (max+1)
// this is the convention in the GC so it is repeated here
- for (ULONG i = GCHeapUtilities::GetMaxGeneration(); i <= GCHeapUtilities::GetMaxGeneration()+1; i++)
+ for (ULONG i = *g_gcDacGlobals->max_gen; i <= *g_gcDacGlobals->max_gen +1; i++)
{
- __DPtr<SVR::heap_segment> seg = dac_cast<TADDR>(pHeap->generation_table[i].start_segment);
+ DPTR(dac_heap_segment) seg = ServerGenerationTableIndex(pHeap, i)->start_segment;
while (seg)
{
- DacEnumMemoryRegion(PTR_HOST_TO_TADDR(seg), sizeof(SVR::heap_segment));
+ DacEnumMemoryRegion(PTR_HOST_TO_TADDR(seg), sizeof(dac_heap_segment));
- seg = __DPtr<SVR::heap_segment>(dac_cast<TADDR>(seg->next));
+ seg = seg->next;
}
}
}
@@ -271,9 +239,9 @@ ClrDataAccess::EnumSvrGlobalMemoryRegions(CLRDataEnumMemoryFlags flags)
DWORD DacGetNumHeaps()
{
- if (GCHeapUtilities::IsServerHeap())
- return (DWORD)SVR::gc_heap::n_heaps;
-
+ if (g_gcDacGlobals->gc_heap_type == IGCHeap::GC_HEAP_SVR)
+ return (DWORD)*g_gcDacGlobals->n_heaps;
+
// workstation gc
return 1;
}
@@ -281,7 +249,7 @@ DWORD DacGetNumHeaps()
HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
{
// Scrape basic heap details
- int heaps = SVR::gc_heap::n_heaps;
+ int heaps = *g_gcDacGlobals->n_heaps;
pCount = heaps;
pHeaps = new (nothrow) HeapData[heaps];
if (pHeaps == NULL)
@@ -290,18 +258,22 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
for (int i = 0; i < heaps; ++i)
{
// Basic heap info.
- PTR_SVR_gc_heap heap = PTR_SVR_gc_heap(SVR::gc_heap::g_heaps[i]);
+ 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);
- pHeaps[i].YoungestGenPtr = (CORDB_ADDRESS)heap->generation_table[0].allocation_context.alloc_ptr;
- pHeaps[i].YoungestGenLimit = (CORDB_ADDRESS)heap->generation_table[0].allocation_context.alloc_limit;
+ 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)heap->generation_table[0].allocation_start;
+ pHeaps[i].Gen0Start = (CORDB_ADDRESS)gen0.allocation_start;
pHeaps[i].Gen0End = (CORDB_ADDRESS)heap->alloc_allocated;
- pHeaps[i].Gen1Start = (CORDB_ADDRESS)heap->generation_table[1].allocation_start;
+ pHeaps[i].Gen1Start = (CORDB_ADDRESS)gen1.allocation_start;
// Segments
- int count = GetSegmentCount(heap->generation_table[NUMBERGENERATIONS-1].start_segment);
- count += GetSegmentCount(heap->generation_table[NUMBERGENERATIONS-2].start_segment);
+ int count = GetSegmentCount(loh.start_segment);
+ count += GetSegmentCount(gen2.start_segment);
pHeaps[i].SegmentCount = count;
pHeaps[i].Segments = new (nothrow) SegmentData[count];
@@ -309,12 +281,12 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
return E_OUTOFMEMORY;
// Small object heap segments
- SVR::PTR_heap_segment seg = heap->generation_table[NUMBERGENERATIONS-2].start_segment;
+ DPTR(dac_heap_segment) seg = gen2.start_segment;
int j = 0;
for (; seg && (j < count); ++j)
{
pHeaps[i].Segments[j].Start = (CORDB_ADDRESS)seg->mem;
- if (seg.GetAddr() == TO_TADDR(heap->ephemeral_heap_segment))
+ if (seg.GetAddr() == heap->ephemeral_heap_segment.GetAddr())
{
pHeaps[i].Segments[j].End = (CORDB_ADDRESS)heap->alloc_allocated;
pHeaps[i].EphemeralSegment = j;
@@ -331,7 +303,7 @@ HRESULT DacHeapWalker::InitHeapDataSvr(HeapData *&pHeaps, size_t &pCount)
// Large object heap segments
- seg = heap->generation_table[NUMBERGENERATIONS-1].start_segment;
+ seg = loh.start_segment;
for (; seg && (j < count); ++j)
{
pHeaps[i].Segments[j].Generation = 3;
diff --git a/src/gc/env/gcenv.structs.h b/src/gc/env/gcenv.structs.h
index 5887dd7852..bb503e36e8 100644
--- a/src/gc/env/gcenv.structs.h
+++ b/src/gc/env/gcenv.structs.h
@@ -65,7 +65,7 @@ extern "C" uint32_t __stdcall GetCurrentThreadId();
class EEThreadId
{
- uint32_t m_uiId;
+ uint64_t m_uiId;
public:
bool IsCurrentThread()
diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp
index 9f098fe510..966c158684 100644
--- a/src/gc/gc.cpp
+++ b/src/gc/gc.cpp
@@ -2257,8 +2257,8 @@ void virtual_free (void* add, size_t size);
/* per heap static initialization */
#ifdef MARK_ARRAY
#ifndef MULTIPLE_HEAPS
-SPTR_IMPL_NS(uint32_t, WKS, gc_heap, mark_array);
-#endif //!MULTIPLE_HEAPS
+uint32_t* gc_heap::mark_array;
+#endif //MULTIPLE_HEAPS
#endif //MARK_ARRAY
#ifdef MARK_LIST
@@ -2292,8 +2292,9 @@ CLREvent gc_heap::gc_start_event;
bool gc_heap::gc_thread_no_affinitize_p = false;
-SVAL_IMPL_NS(int, SVR, gc_heap, n_heaps);
-SPTR_IMPL_NS(PTR_gc_heap, SVR, gc_heap, g_heaps);
+int gc_heap::n_heaps;
+
+gc_heap** gc_heap::g_heaps;
size_t* gc_heap::g_promoted;
@@ -2384,11 +2385,7 @@ size_t gc_heap::ephemeral_fgc_counts[max_generation];
BOOL gc_heap::alloc_wait_event_p = FALSE;
-#if defined (DACCESS_COMPILE) && !defined (MULTIPLE_HEAPS)
-SVAL_IMPL_NS_INIT(gc_heap::c_gc_state, WKS, gc_heap, current_c_gc_state, c_gc_state_free);
-#else
-VOLATILE(gc_heap::c_gc_state) gc_heap::current_c_gc_state = c_gc_state_free;
-#endif //DACCESS_COMPILE && !MULTIPLE_HEAPS
+VOLATILE(c_gc_state) gc_heap::current_c_gc_state = c_gc_state_free;
#endif //BACKGROUND_GC
@@ -2409,14 +2406,14 @@ BOOL gc_heap::elevation_requested = FALSE;
BOOL gc_heap::last_gc_before_oom = FALSE;
#ifdef BACKGROUND_GC
-SPTR_IMPL_NS_INIT(uint8_t, WKS, gc_heap, background_saved_lowest_address, 0);
-SPTR_IMPL_NS_INIT(uint8_t, WKS, gc_heap, background_saved_highest_address, 0);
-SPTR_IMPL_NS_INIT(uint8_t, WKS, gc_heap, next_sweep_obj, 0);
+uint8_t* gc_heap::background_saved_lowest_address = 0;
+uint8_t* gc_heap::background_saved_highest_address = 0;
+uint8_t* gc_heap::next_sweep_obj = 0;
uint8_t* gc_heap::current_sweep_pos = 0;
exclusive_sync* gc_heap::bgc_alloc_lock;
#endif //BACKGROUND_GC
-SVAL_IMPL_NS(oom_history, WKS, gc_heap, oom_info);
+oom_history gc_heap::oom_info;
fgm_history gc_heap::fgm_result;
@@ -2467,7 +2464,7 @@ size_t gc_heap::allocation_running_time;
size_t gc_heap::allocation_running_amount;
-SPTR_IMPL_NS_INIT(heap_segment, WKS, gc_heap, ephemeral_heap_segment, 0);
+heap_segment* gc_heap::ephemeral_heap_segment = 0;
BOOL gc_heap::blocking_collection = FALSE;
@@ -2542,8 +2539,9 @@ uint8_t* gc_heap::background_min_soh_overflow_address =0;
uint8_t* gc_heap::background_max_soh_overflow_address =0;
-SPTR_IMPL_NS_INIT(heap_segment, WKS, gc_heap, saved_sweep_ephemeral_seg, 0);
-SPTR_IMPL_NS_INIT(uint8_t, WKS, gc_heap, saved_sweep_ephemeral_start, 0);
+heap_segment* gc_heap::saved_sweep_ephemeral_seg = 0;
+
+uint8_t* gc_heap::saved_sweep_ephemeral_start = 0;
heap_segment* gc_heap::saved_overflow_ephemeral_seg = 0;
@@ -2619,9 +2617,11 @@ size_t gc_heap::total_ephemeral_size = 0;
size_t gc_heap::internal_root_array_length = initial_internal_roots;
-SPTR_IMPL_NS_INIT(PTR_uint8_t, WKS, gc_heap, internal_root_array, 0);
-SVAL_IMPL_NS_INIT(size_t, WKS, gc_heap, internal_root_array_index, 0);
-SVAL_IMPL_NS_INIT(BOOL, WKS, gc_heap, heap_analyze_success, TRUE);
+uint8_t** gc_heap::internal_root_array = 0;
+
+size_t gc_heap::internal_root_array_index = 0;
+
+BOOL gc_heap::heap_analyze_success = TRUE;
uint8_t* gc_heap::current_obj = 0;
size_t gc_heap::current_obj_size = 0;
@@ -2681,23 +2681,9 @@ BOOL gc_heap::heap_analyze_enabled = FALSE;
#ifndef MULTIPLE_HEAPS
-#ifndef DACCESS_COMPILE
extern "C" {
-#endif //!DACCESS_COMPILE
-GARY_IMPL(generation, generation_table,NUMBERGENERATIONS+1);
-#ifdef GC_CONFIG_DRIVEN
-GARY_IMPL(size_t, interesting_data_per_heap, max_idp_count);
-GARY_IMPL(size_t, compact_reasons_per_heap, max_compact_reasons_count);
-GARY_IMPL(size_t, expand_mechanisms_per_heap, max_expand_mechanisms_count);
-GARY_IMPL(size_t, interesting_mechanism_bits_per_heap, max_gc_mechanism_bits_count);
-#endif //GC_CONFIG_DRIVEN
-#ifndef DACCESS_COMPILE
+ generation generation_table[NUMBERGENERATIONS + 1];
}
-#endif //!DACCESS_COMPILE
-
-#endif //MULTIPLE_HEAPS
-
-#ifndef MULTIPLE_HEAPS
alloc_list gc_heap::loh_alloc_list [NUM_LOH_ALIST-1];
alloc_list gc_heap::gen2_alloc_list[NUM_GEN2_ALIST-1];
@@ -2706,7 +2692,7 @@ dynamic_data gc_heap::dynamic_data_table [NUMBERGENERATIONS+1];
gc_history_per_heap gc_heap::gc_data_per_heap;
size_t gc_heap::maxgen_pinned_compact_before_advance = 0;
-SPTR_IMPL_NS_INIT(uint8_t, WKS, gc_heap, alloc_allocated, 0);
+uint8_t* gc_heap::alloc_allocated = 0;
size_t gc_heap::allocation_quantum = CLR_SIZE;
@@ -2737,9 +2723,21 @@ int gc_heap::gen0_must_clear_bricks = 0;
#endif //FFIND_OBJECT
#ifdef FEATURE_PREMORTEM_FINALIZATION
-SPTR_IMPL_NS_INIT(CFinalize, WKS, gc_heap, finalize_queue, 0);
+CFinalize* gc_heap::finalize_queue = 0;
#endif // FEATURE_PREMORTEM_FINALIZATION
+#ifdef MULTIPLE_HEAPS
+generation gc_heap::generation_table [NUMBERGENERATIONS + 1];
+#endif // MULTIPLE_HEAPS
+
+size_t gc_heap::interesting_data_per_heap[max_idp_count];
+
+size_t gc_heap::compact_reasons_per_heap[max_compact_reasons_count];
+
+size_t gc_heap::expand_mechanisms_per_heap[max_expand_mechanisms_count];
+
+size_t gc_heap::interesting_mechanism_bits_per_heap[max_gc_mechanism_bits_count];
+
#endif // MULTIPLE_HEAPS
/* end of per heap static initialization */
@@ -36785,3 +36783,50 @@ BOOL GCHeap::IsConcurrentGCEnabled()
return FALSE;
#endif //BACKGROUND_GC
}
+
+void PopulateDacVars(GcDacVars *gcDacVars)
+{
+#ifndef DACCESS_COMPILE
+ assert(gcDacVars != nullptr);
+ *gcDacVars = {};
+ gcDacVars->major_version_number = 1;
+ gcDacVars->minor_version_number = 0;
+ 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);
+ gcDacVars->generation_size = sizeof(generation);
+#ifdef FEATURE_SVR_GC
+ gcDacVars->gc_heap_type = &IGCHeap::gcHeapType;
+#endif // FEATURE_SVR_GC
+ gcDacVars->max_gen = &IGCHeap::maxGeneration;
+#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);
+ 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;
+ 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**>(&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);
+ gcDacVars->compact_reasons_per_heap = reinterpret_cast<size_t**>(&gc_heap::compact_reasons_per_heap);
+ gcDacVars->expand_mechanisms_per_heap = reinterpret_cast<size_t**>(&gc_heap::expand_mechanisms_per_heap);
+ gcDacVars->interesting_mechanism_bits_per_heap = reinterpret_cast<size_t**>(&gc_heap::interesting_mechanism_bits_per_heap);
+#endif // GC_CONFIG_DRIVEN
+#ifdef HEAP_ANALYZE
+ gcDacVars->internal_root_array = &gc_heap::internal_root_array;
+ gcDacVars->internal_root_array_index = &gc_heap::internal_root_array_index;
+ gcDacVars->heap_analyze_success = &gc_heap::heap_analyze_success;
+#endif // HEAP_ANALYZE
+#else
+ gcDacVars->n_heaps = &gc_heap::n_heaps;
+ gcDacVars->g_heaps = reinterpret_cast<dac_gc_heap***>(&gc_heap::g_heaps);
+#endif // MULTIPLE_HEAPS
+#endif // DACCESS_COMPILE
+}
diff --git a/src/gc/gc.h b/src/gc/gc.h
index 7332e42885..ab36c8de27 100644
--- a/src/gc/gc.h
+++ b/src/gc/gc.h
@@ -41,21 +41,6 @@ typedef void enum_func (Object*);
// callback functions for heap walkers
typedef void object_callback_func(void * pvContext, void * pvDataLoc);
-/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
-/* If you modify failure_get_memory and */
-/* oom_reason be sure to make the corresponding */
-/* changes in toolbox\sos\strike\strike.cpp. */
-/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
-enum failure_get_memory
-{
- fgm_no_failure = 0,
- fgm_reserve_segment = 1,
- fgm_commit_segment_beg = 2,
- fgm_commit_eph_segment = 3,
- fgm_grow_table = 4,
- fgm_commit_table = 5
-};
-
struct fgm_history
{
failure_get_memory fgm;
@@ -71,17 +56,6 @@ struct fgm_history
}
};
-enum oom_reason
-{
- oom_no_failure = 0,
- oom_budget = 1,
- oom_cant_commit = 2,
- oom_cant_reserve = 3,
- oom_loh = 4,
- oom_low_mem = 5,
- oom_unproductive_full_gc = 6
-};
-
// TODO : it would be easier to make this an ORed value
enum gc_reason
{
@@ -100,19 +74,6 @@ enum gc_reason
reason_max
};
-struct oom_history
-{
- oom_reason reason;
- size_t alloc_size;
- uint8_t* reserved;
- uint8_t* allocated;
- size_t gc_index;
- failure_get_memory fgm;
- size_t size;
- size_t available_pagefile_mb;
- BOOL loh_p;
-};
-
/* forward declerations */
class CObjectHeader;
class Object;
@@ -124,7 +85,7 @@ class IGCHeapInternal;
#ifdef GC_CONFIG_DRIVEN
#define MAX_GLOBAL_GC_MECHANISMS_COUNT 6
-GARY_DECL(size_t, gc_global_mechanisms, MAX_GLOBAL_GC_MECHANISMS_COUNT);
+extern size_t gc_global_mechanisms[MAX_GLOBAL_GC_MECHANISMS_COUNT];
#endif //GC_CONFIG_DRIVEN
#ifdef DACCESS_COMPILE
@@ -141,6 +102,8 @@ extern "C" uint32_t* g_gc_card_table;
extern "C" uint8_t* g_gc_lowest_address;
extern "C" uint8_t* g_gc_highest_address;
extern "C" bool g_fFinalizerRunOnShutDown;
+extern "C" bool g_built_with_svr_gc;
+extern "C" uint8_t g_build_variant;
namespace WKS {
::IGCHeapInternal* CreateGCHeap();
diff --git a/src/gc/gccommon.cpp b/src/gc/gccommon.cpp
index 133f05e490..e816d02e70 100644
--- a/src/gc/gccommon.cpp
+++ b/src/gc/gccommon.cpp
@@ -27,7 +27,7 @@ IGCToCLR* g_theGCToCLR;
#endif // FEATURE_STANDALONE_GC
#ifdef GC_CONFIG_DRIVEN
-GARY_IMPL(size_t, gc_global_mechanisms, MAX_GLOBAL_GC_MECHANISMS_COUNT);
+size_t gc_global_mechanisms[MAX_GLOBAL_GC_MECHANISMS_COUNT];
#endif //GC_CONFIG_DRIVEN
#ifndef DACCESS_COMPILE
@@ -43,12 +43,26 @@ uint8_t* g_gc_lowest_address = 0;
uint8_t* g_gc_highest_address = 0;
bool g_fFinalizerRunOnShutDown = false;
+#ifdef FEATURE_SVR_GC
+bool g_built_with_svr_gc = true;
+#else
+bool g_built_with_svr_gc = false;
+#endif // FEATURE_SVR_GC
+
+#if defined(BUILDENV_DEBUG)
+uint8_t g_build_variant = 0;
+#elif defined(BUILDENV_CHECKED)
+uint8_t g_build_variant = 1;
+#else
+uint8_t g_build_variant = 2;
+#endif // defined(BUILDENV_DEBUG)
+
VOLATILE(int32_t) m_GCLock = -1;
#ifdef GC_CONFIG_DRIVEN
void record_global_mechanism (int mech_index)
{
- (gc_global_mechanisms[mech_index])++;
+ (gc_global_mechanisms[mech_index])++;
}
#endif //GC_CONFIG_DRIVEN
@@ -133,18 +147,48 @@ void InitializeHeapType(bool bServerHeap)
#endif // FEATURE_SVR_GC
}
-IGCHeap* InitializeGarbageCollector(IGCToCLR* clrToGC)
+namespace WKS
+{
+ extern void PopulateDacVars(GcDacVars* dacVars);
+}
+
+namespace SVR
+{
+ extern void PopulateDacVars(GcDacVars* dacVars);
+}
+
+bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap** gcHeap, GcDacVars* gcDacVars)
{
LIMITED_METHOD_CONTRACT;
IGCHeapInternal* heap;
+
+ assert(gcDacVars != nullptr);
+ assert(gcHeap != nullptr);
#ifdef FEATURE_SVR_GC
assert(IGCHeap::gcHeapType != IGCHeap::GC_HEAP_INVALID);
- heap = IGCHeap::gcHeapType == IGCHeap::GC_HEAP_SVR ? SVR::CreateGCHeap() : WKS::CreateGCHeap();
+
+ if (IGCHeap::gcHeapType == IGCHeap::GC_HEAP_SVR)
+ {
+ heap = SVR::CreateGCHeap();
+ SVR::PopulateDacVars(gcDacVars);
+ }
+ else
+ {
+ heap = WKS::CreateGCHeap();
+ WKS::PopulateDacVars(gcDacVars);
+ }
#else
heap = WKS::CreateGCHeap();
+ WKS::PopulateDacVars(gcDacVars);
+
#endif
+ if (heap == nullptr)
+ {
+ return false;
+ }
+
g_theGCHeap = heap;
#ifdef FEATURE_STANDALONE_GC
@@ -155,7 +199,8 @@ IGCHeap* InitializeGarbageCollector(IGCToCLR* clrToGC)
assert(clrToGC == nullptr);
#endif
- return heap;
+ *gcHeap = heap;
+ return true;
}
#endif // !DACCESS_COMPILE
diff --git a/src/gc/gcinterface.dac.h b/src/gc/gcinterface.dac.h
new file mode 100644
index 0000000000..84c8ffb36a
--- /dev/null
+++ b/src/gc/gcinterface.dac.h
@@ -0,0 +1,162 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _GC_INTERFACE_DAC_H_
+#define _GC_INTERFACE_DAC_H_
+
+// This file defines the interface between the GC and the DAC. The interface consists of two things:
+// 1. A number of variables ("DAC vars") whose addresses are exposed to the DAC (see "struct GcDacVars")
+// 2. A number of types that are analogues to GC-internal types. These types expose a subset of the
+// GC-internal type's fields, while still maintaining the same layout.
+// This interface is strictly versioned, see gcinterface.dacvars.def for more information.
+
+#define NUM_GC_DATA_POINTS 9
+#define MAX_COMPACT_REASONS_COUNT 11
+#define MAX_EXPAND_MECHANISMS_COUNT 6
+#define MAX_GC_MECHANISM_BITS_COUNT 2
+#define MAX_GLOBAL_GC_MECHANISMS_COUNT 6
+#define NUMBERGENERATIONS 4
+
+// TODO(segilles) - Implement this scheme for Server GC
+namespace SVR {
+ class heap_segment;
+ class gc_heap;
+}
+
+// Analogue for the GC heap_segment class, containing information regarding a single
+// heap segment.
+class dac_heap_segment {
+public:
+ uint8_t* allocated;
+ uint8_t* committed;
+ uint8_t* reserved;
+ uint8_t* used;
+ uint8_t* mem;
+ size_t flags;
+ DPTR(dac_heap_segment) next;
+ uint8_t* background_allocated;
+ class dac_gc_heap* heap;
+};
+
+// Analogue for the GC generation class, containing information about the start segment
+// of a generation and its allocation context.
+class dac_generation {
+public:
+ gc_alloc_context allocation_context;
+ DPTR(dac_heap_segment) start_segment;
+ uint8_t* allocation_start;
+};
+
+// Analogue for the GC CFinalize class, containing information about the finalize queue.
+class dac_finalize_queue {
+public:
+ static const int ExtraSegCount = 2;
+ uint8_t** m_FillPointers[NUMBERGENERATIONS + ExtraSegCount];
+};
+
+// Possible values of the current_c_gc_state dacvar, indicating the state of
+// a background GC.
+enum c_gc_state
+{
+ c_gc_state_marking,
+ c_gc_state_planning,
+ c_gc_state_free
+};
+
+// Reasons why an OOM might occur, recorded in the oom_history
+// struct below.
+enum oom_reason
+{
+ oom_no_failure = 0,
+ oom_budget = 1,
+ oom_cant_commit = 2,
+ oom_cant_reserve = 3,
+ oom_loh = 4,
+ oom_low_mem = 5,
+ oom_unproductive_full_gc = 6
+};
+
+/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
+/* If you modify failure_get_memory and */
+/* oom_reason be sure to make the corresponding */
+/* changes in toolbox\sos\strike\strike.cpp. */
+/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
+enum failure_get_memory
+{
+ fgm_no_failure = 0,
+ fgm_reserve_segment = 1,
+ fgm_commit_segment_beg = 2,
+ fgm_commit_eph_segment = 3,
+ fgm_grow_table = 4,
+ fgm_commit_table = 5
+};
+
+// A record of the last OOM that occured in the GC, with some
+// additional information as to what triggered the OOM.
+struct oom_history
+{
+ oom_reason reason;
+ size_t alloc_size;
+ uint8_t* reserved;
+ uint8_t* allocated;
+ size_t gc_index;
+ failure_get_memory fgm;
+ size_t size;
+ size_t available_pagefile_mb;
+ BOOL loh_p;
+};
+
+// Analogue for the GC gc_heap class, containing information regarding a single
+// GC heap (of which there are multiple, with server GC).
+class dac_gc_heap {
+public:
+ uint8_t* alloc_allocated;
+ DPTR(dac_heap_segment) ephemeral_heap_segment;
+ DPTR(dac_finalize_queue) finalize_queue;
+ oom_history oom_info;
+ size_t interesting_data_per_heap[NUM_GC_DATA_POINTS];
+ size_t compact_reasons_per_heap[MAX_COMPACT_REASONS_COUNT];
+ size_t expand_mechanisms_per_heap[MAX_EXPAND_MECHANISMS_COUNT];
+ size_t interesting_mechanism_bits_per_heap[MAX_GC_MECHANISM_BITS_COUNT];
+ uint8_t* internal_root_array;
+ size_t internal_root_array_index;
+ BOOL heap_analyze_success;
+
+ // The generation table must always be last, because the size of this array
+ // (stored inline in the gc_heap class) can vary.
+ //
+ // The size of the generation class is not part of the GC-DAC interface,
+ // despite being embedded by-value into the gc_heap class. The DAC variable
+ // "generation_size" stores the size of the generation class, so the DAC can
+ // use it and pointer arithmetic to calculate correct offsets into the generation
+ // table. (See "GenerationTableIndex" function in the DAC for details)
+ //
+ // Also note that this array has length 1 because the C++ standard doesn't allow
+ // for 0-length arrays, although every major compiler is willing to tolerate it.
+ dac_generation generation_table[1];
+};
+
+
+// The actual structure containing the DAC variables. When DACCESS_COMPILE is not
+// defined (i.e. the normal runtime build), this structure contains pointers to the
+// GC's global DAC variabels. When DACCESS_COMPILE is defined (i.e. the DAC build),
+// this structure contains __DPtrs for every DAC variable that will marshal values
+// from the debugee process to the debugger process when dereferenced.
+struct GcDacVars {
+ uint8_t major_version_number;
+ uint8_t minor_version_number;
+ size_t generation_size;
+#ifdef DACCESS_COMPILE
+ #define GC_DAC_VAR(type, name) DPTR(type) name;
+ // ArrayDPTR doesn't allow decaying arrays to pointers, which
+ // avoids some accidental errors.
+ #define GC_DAC_PTR_VAR(type, name) DPTR(type*) name;
+ #define GC_DAC_ARRAY_VAR(type, name) DPTR(type) name;
+#else
+ #define GC_DAC_VAR(type, name) type *name;
+#endif
+#include "gcinterface.dacvars.def"
+};
+
+#endif // _GC_INTERFACE_DAC_H_
diff --git a/src/gc/gcinterface.dacvars.def b/src/gc/gcinterface.dacvars.def
new file mode 100644
index 0000000000..f9c2078ee3
--- /dev/null
+++ b/src/gc/gcinterface.dacvars.def
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// This file contains the defintions of all DAC variables that the G
+// exports and that the DAC uses to interface with the GC.
+//
+// This interface has a strict semantic versioning. The following changes require
+// a bump to the major version number:
+// 1. Changing the type of any of these variables,
+// 2. Changing the type layouts of any of the types in gcinterface.dac.h,
+// (dac_generation, dac_heap_segment, dac_finalize_queue)
+// 3. Changing the semantic meaning of any of these variables, such that the DAC's
+// use of them is no longer correct,
+//
+// The following change requires a bump to the minor version number:
+// 1. Adding additional DAC variables.
+//
+// Minor version mismatches are tolerated by the DAC, at the risk of a possibly
+// degraded debugging experience.
+// Major version mismatches are not tolerated by the DAC and will be rejected upon load.
+
+#ifndef GC_DAC_VAR
+ #define GC_DAC_VAR(type, name)
+#endif // GC_DAC_VAR
+
+#ifndef GC_DAC_ARRAY_VAR
+ #define GC_DAC_ARRAY_VAR(type, name) GC_DAC_VAR(type*, name)
+#endif // GC_DAC_ARRAY_VAR
+
+#ifndef GC_DAC_PTR_VAR
+ #define GC_DAC_PTR_VAR(type, name) GC_DAC_VAR(type*, name)
+#endif // GC_DAC_PTR_VAR
+
+// This sequence of macros defines the specific variables that are exposed by the
+// GC to the DAC.
+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_VAR (uint32_t, gc_heap_type)
+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_PTR_VAR (dac_heap_segment, ephemeral_heap_segment)
+GC_DAC_PTR_VAR (dac_heap_segment, saved_sweep_ephemeral_seg)
+GC_DAC_PTR_VAR (uint8_t, saved_sweep_ephemeral_start)
+GC_DAC_PTR_VAR (uint8_t, background_saved_lowest_address)
+GC_DAC_PTR_VAR (uint8_t, background_saved_highest_address)
+GC_DAC_PTR_VAR (uint8_t, alloc_allocated)
+GC_DAC_PTR_VAR (uint8_t, next_sweep_obj)
+GC_DAC_VAR (oom_history, oom_info)
+GC_DAC_PTR_VAR (dac_finalize_queue, finalize_queue)
+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_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)
+
+#undef GC_DAC_VAR
+#undef GC_DAC_ARRAY_VAR
+#undef GC_DAC_PTR_VAR
diff --git a/src/gc/gcinterface.h b/src/gc/gcinterface.h
index 99d79df633..0192a8233a 100644
--- a/src/gc/gcinterface.h
+++ b/src/gc/gcinterface.h
@@ -129,6 +129,8 @@ public:
}
};
+#include "gcinterface.dac.h"
+
// stub type to abstract a heap segment
struct gc_heap_segment_stub;
typedef gc_heap_segment_stub *segment_handle;
@@ -162,8 +164,9 @@ class Object;
class IGCHeap;
// Initializes the garbage collector. Should only be called
-// once, during EE startup.
-IGCHeap* InitializeGarbageCollector(IGCToCLR* clrToGC);
+// once, during EE startup. Returns true if the initialization
+// was successful, false otherwise.
+bool InitializeGarbageCollector(IGCToCLR* clrToGC, IGCHeap **gcHeap, GcDacVars* gcDacVars);
// The runtime needs to know whether we're using workstation or server GC
// long before the GCHeap is created. This function sets the type of
diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h
index 1f97d7f2d5..d4cb0aefc9 100644
--- a/src/gc/gcpriv.h
+++ b/src/gc/gcpriv.h
@@ -167,8 +167,6 @@ void GCLogConfig (const char *fmt, ... );
#define TRACE_GC
#endif
-#define NUMBERGENERATIONS 4 //Max number of generations
-
// For the bestfit algorithm when we relocate ephemeral generations into an
// existing gen2 segment.
// We recorded sizes from 2^6, 2^7, 2^8...up to 2^30 (1GB). So that's 25 sizes total.
@@ -759,10 +757,10 @@ public:
// Don't move these first two fields without adjusting the references
// from the __asm in jitinterface.cpp.
alloc_context allocation_context;
- heap_segment* allocation_segment;
PTR_heap_segment start_segment;
- uint8_t* allocation_context_start_region;
uint8_t* allocation_start;
+ heap_segment* allocation_segment;
+ uint8_t* allocation_context_start_region;
allocator free_list_allocator;
size_t free_list_allocated;
size_t end_seg_allocated;
@@ -792,6 +790,11 @@ 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");
+static_assert(offsetof(dac_generation, allocation_start) == offsetof(generation, allocation_start), "DAC generation offset mismatch");
+
+
// The dynamic data fields are grouped into 3 categories:
//
// calculated logical data (like desired_allocation)
@@ -1104,6 +1107,8 @@ class gc_heap
friend void initGCShadow();
#endif //defined (WRITE_BARRIER_CHECK) && !defined (SERVER_GC)
+ friend void PopulateDacVars(GcDacVars *gcDacVars);
+
#ifdef MULTIPLE_HEAPS
typedef void (gc_heap::* card_fn) (uint8_t**, int);
#define call_fn(fn) (this->*fn)
@@ -1550,13 +1555,6 @@ protected:
alloc_context* acontext,
int align_const);
- enum c_gc_state
- {
- c_gc_state_marking,
- c_gc_state_planning,
- c_gc_state_free
- };
-
#ifdef RECORD_LOH_STATE
#define max_saved_loh_states 12
PER_HEAP
@@ -2753,9 +2751,6 @@ public:
PER_HEAP_ISOLATED
uint32_t cm_in_progress;
- PER_HEAP
- BOOL expanded_in_fgc;
-
// normally this is FALSE; we set it to TRUE at the end of the gen1 GC
// we do right before the bgc starts.
PER_HEAP_ISOLATED
@@ -2765,6 +2760,58 @@ public:
CLREvent 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;
+
+ // The ephemeral heap segment
+ PER_HEAP
+ heap_segment* ephemeral_heap_segment;
+
+ // The finalize queue.
+ PER_HEAP
+ CFinalize* finalize_queue;
+
+ // OOM info.
+ PER_HEAP
+ oom_history oom_info;
+
+ // Interesting data, recorded per-heap.
+ PER_HEAP
+ size_t interesting_data_per_heap[max_idp_count];
+
+ PER_HEAP
+ size_t compact_reasons_per_heap[max_compact_reasons_count];
+
+ PER_HEAP
+ size_t expand_mechanisms_per_heap[max_expand_mechanisms_count];
+
+ PER_HEAP
+ size_t interesting_mechanism_bits_per_heap[max_gc_mechanism_bits_count];
+
+ PER_HEAP
+ uint8_t** internal_root_array;
+
+ PER_HEAP
+ size_t internal_root_array_index;
+
+ PER_HEAP
+ BOOL heap_analyze_success;
+
+#ifdef MULTIPLE_HEAPS
+ // The generation table. Must always be last.
+ PER_HEAP
+ generation generation_table [NUMBERGENERATIONS + 1];
+#endif // MULTIPLE_HEAPS
+
+ // End DAC zone
+
+ PER_HEAP
+ BOOL expanded_in_fgc;
+
PER_HEAP_ISOLATED
uint32_t wait_for_gc_done(int32_t timeOut = INFINITE);
@@ -2815,12 +2862,8 @@ public:
short* brick_table;
#ifdef MARK_ARRAY
-#ifdef MULTIPLE_HEAPS
PER_HEAP
uint32_t* mark_array;
-#else
- SPTR_DECL(uint32_t, mark_array);
-#endif //MULTIPLE_HEAPS
#endif //MARK_ARRAY
#ifdef CARD_BUNDLE
@@ -2984,13 +3027,6 @@ protected:
#define heap_number (0)
#endif //MULTIPLE_HEAPS
-#ifndef MULTIPLE_HEAPS
- SPTR_DECL(heap_segment,ephemeral_heap_segment);
-#else
- PER_HEAP
- heap_segment* ephemeral_heap_segment;
-#endif // !MULTIPLE_HEAPS
-
PER_HEAP
size_t time_bgc_last;
@@ -3065,14 +3101,9 @@ protected:
uint8_t* background_written_addresses [array_size+2];
#endif //WRITE_WATCH
-#if defined (DACCESS_COMPILE) && !defined (MULTIPLE_HEAPS)
- // doesn't need to be volatile for DAC.
- SVAL_DECL(c_gc_state, current_c_gc_state);
-#else
PER_HEAP_ISOLATED
VOLATILE(c_gc_state) current_c_gc_state; //tells the large object allocator to
//mark the object as new since the start of gc.
-#endif //DACCESS_COMPILE && !MULTIPLE_HEAPS
PER_HEAP_ISOLATED
gc_mechanisms saved_bgc_settings;
@@ -3229,16 +3260,6 @@ protected:
PER_HEAP
heap_segment* saved_overflow_ephemeral_seg;
-#ifndef MULTIPLE_HEAPS
- SPTR_DECL(heap_segment, saved_sweep_ephemeral_seg);
-
- SPTR_DECL(uint8_t, saved_sweep_ephemeral_start);
-
- SPTR_DECL(uint8_t, background_saved_lowest_address);
-
- SPTR_DECL(uint8_t, background_saved_highest_address);
-#else
-
PER_HEAP
heap_segment* saved_sweep_ephemeral_seg;
@@ -3250,7 +3271,6 @@ protected:
PER_HEAP
uint8_t* background_saved_highest_address;
-#endif //!MULTIPLE_HEAPS
// This is used for synchronization between the bgc thread
// for this heap and the user threads allocating on this
@@ -3334,14 +3354,6 @@ protected:
#define youngest_generation (generation_of (0))
#define large_object_generation (generation_of (max_generation+1))
-#ifndef MULTIPLE_HEAPS
- SPTR_DECL(uint8_t,alloc_allocated);
-#else
- PER_HEAP
- uint8_t* alloc_allocated; //keeps track of the highest
- //address allocated by alloc
-#endif // !MULTIPLE_HEAPS
-
// The more_space_lock and gc_lock is used for 3 purposes:
//
// 1) to coordinate threads that exceed their quantum (UP & MP) (more_space_lock)
@@ -3411,12 +3423,6 @@ protected:
#endif //SYNCHRONIZATION_STATS
-#ifdef MULTIPLE_HEAPS
- PER_HEAP
- generation generation_table [NUMBERGENERATIONS+1];
-#endif
-
-
#define NUM_LOH_ALIST (7)
#define BASE_LOH_ALIST (64*1024)
PER_HEAP
@@ -3493,34 +3499,14 @@ protected:
PER_HEAP_ISOLATED
BOOL alloc_wait_event_p;
-#ifndef MULTIPLE_HEAPS
- SPTR_DECL(uint8_t, next_sweep_obj);
-#else
PER_HEAP
uint8_t* next_sweep_obj;
-#endif //MULTIPLE_HEAPS
PER_HEAP
uint8_t* current_sweep_pos;
#endif //BACKGROUND_GC
-#ifndef MULTIPLE_HEAPS
- SVAL_DECL(oom_history, oom_info);
-#ifdef FEATURE_PREMORTEM_FINALIZATION
- SPTR_DECL(CFinalize,finalize_queue);
-#endif //FEATURE_PREMORTEM_FINALIZATION
-#else
-
- PER_HEAP
- oom_history oom_info;
-
-#ifdef FEATURE_PREMORTEM_FINALIZATION
- PER_HEAP
- PTR_CFinalize finalize_queue;
-#endif //FEATURE_PREMORTEM_FINALIZATION
-#endif // !MULTIPLE_HEAPS
-
PER_HEAP
fgm_history fgm_result;
@@ -3542,19 +3528,6 @@ protected:
PER_HEAP
size_t interesting_data_per_gc[max_idp_count];
-#ifdef MULTIPLE_HEAPS
- PER_HEAP
- size_t interesting_data_per_heap[max_idp_count];
-
- PER_HEAP
- size_t compact_reasons_per_heap[max_compact_reasons_count];
-
- PER_HEAP
- size_t expand_mechanisms_per_heap[max_expand_mechanisms_count];
-
- PER_HEAP
- size_t interesting_mechanism_bits_per_heap[max_gc_mechanism_bits_count];
-#endif //MULTIPLE_HEAPS
#endif //GC_CONFIG_DRIVEN
PER_HEAP
@@ -3635,21 +3608,6 @@ public:
PER_HEAP
size_t internal_root_array_length;
-#ifndef MULTIPLE_HEAPS
- SPTR_DECL(PTR_uint8_t, internal_root_array);
- SVAL_DECL(size_t, internal_root_array_index);
- SVAL_DECL(BOOL, heap_analyze_success);
-#else
- PER_HEAP
- uint8_t** internal_root_array;
-
- PER_HEAP
- size_t internal_root_array_index;
-
- PER_HEAP
- BOOL heap_analyze_success;
-#endif // !MULTIPLE_HEAPS
-
// next two fields are used to optimize the search for the object
// enclosing the current reference handled by ha_mark_object_simple.
PER_HEAP
@@ -3670,8 +3628,11 @@ public:
BOOL blocking_collection;
#ifdef MULTIPLE_HEAPS
- SVAL_DECL(int, n_heaps);
- SPTR_DECL(PTR_gc_heap, g_heaps);
+ static
+ int n_heaps;
+
+ static
+ gc_heap** g_heaps;
static
size_t* g_promoted;
@@ -3705,6 +3666,23 @@ protected:
}; // class gc_heap
+#define ASSERT_OFFSETS_MATCH(field) \
+ static_assert_no_msg(offsetof(dac_gc_heap, field) == offsetof(gc_heap, field))
+
+#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
#ifdef FEATURE_PREMORTEM_FINALIZATION
class CFinalize
@@ -3712,6 +3690,9 @@ class CFinalize
#ifdef DACCESS_COMPILE
friend class ::ClrDataAccess;
#endif // DACCESS_COMPILE
+
+ friend class CFinalizeStaticAsserts;
+
private:
//adjust the count and add a constant to add a segment
@@ -3721,8 +3702,8 @@ private:
//Does not correspond to a segment
static const int FreeList = NUMBERGENERATIONS+ExtraSegCount;
- PTR_PTR_Object m_Array;
PTR_PTR_Object m_FillPointers[NUMBERGENERATIONS+ExtraSegCount];
+ PTR_PTR_Object m_Array;
PTR_PTR_Object m_EndArray;
size_t m_PromotedCount;
@@ -3779,7 +3760,15 @@ public:
BOOL FinalizeAppDomain (AppDomain *pDomain, BOOL fRunFinalizers);
void CheckFinalizerObjects();
+
+};
+
+class CFinalizeStaticAsserts {
+ static_assert(dac_finalize_queue::ExtraSegCount == CFinalize::ExtraSegCount, "ExtraSegCount mismatch");
+ static_assert(offsetof(dac_finalize_queue, m_FillPointers) == offsetof(CFinalize, m_FillPointers), "CFinalize layout mismatch");
};
+
+
#endif // FEATURE_PREMORTEM_FINALIZATION
inline
@@ -4171,11 +4160,9 @@ public:
uint8_t* mem;
size_t flags;
PTR_heap_segment next;
- uint8_t* plan_allocated;
-#ifdef BACKGROUND_GC
uint8_t* background_allocated;
+ uint8_t* plan_allocated;
uint8_t* saved_bg_allocated;
-#endif //BACKGROUND_GC
#ifdef MULTIPLE_HEAPS
gc_heap* heap;
@@ -4191,6 +4178,15 @@ public:
#endif
};
+static_assert(offsetof(dac_heap_segment, allocated) == offsetof(heap_segment, allocated), "DAC heap segment layout mismatch");
+static_assert(offsetof(dac_heap_segment, committed) == offsetof(heap_segment, committed), "DAC heap segment layout mismatch");
+static_assert(offsetof(dac_heap_segment, reserved) == offsetof(heap_segment, reserved), "DAC heap segment layout mismatch");
+static_assert(offsetof(dac_heap_segment, used) == offsetof(heap_segment, used), "DAC heap segment layout mismatch");
+static_assert(offsetof(dac_heap_segment, mem) == offsetof(heap_segment, mem), "DAC heap segment layout mismatch");
+static_assert(offsetof(dac_heap_segment, flags) == offsetof(heap_segment, flags), "DAC heap segment layout mismatch");
+static_assert(offsetof(dac_heap_segment, next) == offsetof(heap_segment, next), "DAC heap segment layout mismatch");
+static_assert(offsetof(dac_heap_segment, background_allocated) == offsetof(heap_segment, background_allocated), "DAC heap segment layout mismatch");
+
inline
uint8_t*& heap_segment_reserved (heap_segment* inst)
{
@@ -4284,25 +4280,10 @@ gc_heap*& heap_segment_heap (heap_segment* inst)
#endif //MULTIPLE_HEAPS
#ifndef MULTIPLE_HEAPS
-
-#ifndef DACCESS_COMPILE
extern "C" {
-#endif //!DACCESS_COMPILE
-
-GARY_DECL(generation,generation_table,NUMBERGENERATIONS+1);
-
-#ifdef GC_CONFIG_DRIVEN
-GARY_DECL(size_t, interesting_data_per_heap, max_idp_count);
-GARY_DECL(size_t, compact_reasons_per_heap, max_compact_reasons_count);
-GARY_DECL(size_t, expand_mechanisms_per_heap, max_expand_mechanisms_count);
-GARY_DECL(size_t, interesting_mechanism_bits_per_heap, max_gc_mechanism_bits_count);
-#endif //GC_CONFIG_DRIVEN
-
-#ifndef DACCESS_COMPILE
+ extern generation generation_table[NUMBERGENERATIONS + 1];
}
-#endif //!DACCESS_COMPILE
-
-#endif //MULTIPLE_HEAPS
+#endif // MULTIPLE_HEAPS
inline
generation* gc_heap::generation_of (int n)
diff --git a/src/gc/gcscan.h b/src/gc/gcscan.h
index 362370fa4a..c17f0ce006 100644
--- a/src/gc/gcscan.h
+++ b/src/gc/gcscan.h
@@ -89,7 +89,6 @@ class GCScan
static void VerifyHandleTable(int condemned, int max_gen, ScanContext* sc);
-private:
#ifdef DACCESS_COMPILE
SVAL_DECL(int32_t, m_GcStructuresInvalidCnt);
#else
diff --git a/src/gc/sample/GCSample.cpp b/src/gc/sample/GCSample.cpp
index 112d291420..2c32048bbb 100644
--- a/src/gc/sample/GCSample.cpp
+++ b/src/gc/sample/GCSample.cpp
@@ -134,9 +134,12 @@ int __cdecl main(int argc, char* argv[])
//
// Initialize GC heap
//
- IGCHeap *pGCHeap = InitializeGarbageCollector(nullptr);
- if (!pGCHeap)
+ GcDacVars dacVars;
+ IGCHeap *pGCHeap;
+ if (!InitializeGarbageCollector(nullptr, &pGCHeap, &dacVars))
+ {
return -1;
+ }
if (FAILED(pGCHeap->Initialize()))
return -1;
diff --git a/src/inc/dacprivate.h b/src/inc/dacprivate.h
index 0db4affcfc..a419c47fef 100644
--- a/src/inc/dacprivate.h
+++ b/src/inc/dacprivate.h
@@ -776,21 +776,18 @@ struct MSLAYOUT DacpOomData : ZeroInit<DacpOomData>
}
};
-// This is the value of max_idp_count in ndp\clr\src\vm\gcpriv.h
-#define NUM_GC_DATA_POINTS 9
-// These are from ndp\clr\src\vm\gcrecord.h
-#define MAX_COMPACT_REASONS_COUNT 11
-#define MAX_EXPAND_MECHANISMS_COUNT 6
-#define MAX_GC_MECHANISM_BITS_COUNT 2
-// This is from ndp\clr\src\vm\common.h
-#define MAX_GLOBAL_GC_MECHANISMS_COUNT 6
+#define DAC_NUM_GC_DATA_POINTS 9
+#define DAC_MAX_COMPACT_REASONS_COUNT 11
+#define DAC_MAX_EXPAND_MECHANISMS_COUNT 6
+#define DAC_MAX_GC_MECHANISM_BITS_COUNT 2
+#define DAC_MAX_GLOBAL_GC_MECHANISMS_COUNT 6
struct MSLAYOUT DacpGCInterestingInfoData : ZeroInit<DacpGCInterestingInfoData>
{
- size_t interestingDataPoints[NUM_GC_DATA_POINTS];
- size_t compactReasons[MAX_COMPACT_REASONS_COUNT];
- size_t expandMechanisms[MAX_EXPAND_MECHANISMS_COUNT];
- size_t bitMechanisms[MAX_GC_MECHANISM_BITS_COUNT];
- size_t globalMechanisms[MAX_GLOBAL_GC_MECHANISMS_COUNT];
+ size_t interestingDataPoints[DAC_NUM_GC_DATA_POINTS];
+ size_t compactReasons[DAC_MAX_COMPACT_REASONS_COUNT];
+ size_t expandMechanisms[DAC_MAX_EXPAND_MECHANISMS_COUNT];
+ size_t bitMechanisms[DAC_MAX_GC_MECHANISM_BITS_COUNT];
+ size_t globalMechanisms[DAC_MAX_GLOBAL_GC_MECHANISMS_COUNT];
HRESULT RequestGlobal(ISOSDacInterface *sos)
{
diff --git a/src/inc/dacvars.h b/src/inc/dacvars.h
index 12d875af8f..6180210fd6 100644
--- a/src/inc/dacvars.h
+++ b/src/inc/dacvars.h
@@ -125,18 +125,8 @@ DEFINE_DACVAR(ULONG, PTR_Thread, dac__g_pSuspensionThread, ::g_pSuspensionThread
DEFINE_DACVAR(ULONG, DWORD, IGCHeap__gcHeapType, IGCHeap::gcHeapType)
#endif // FEATURE_SVR_GC
+DEFINE_DACVAR(ULONG, PTR_GcDacVars, dac__g_gcDacGlobals, g_gcDacGlobals)
DEFINE_DACVAR(ULONG, DWORD, IGCHeap__maxGeneration, IGCHeap::maxGeneration)
-DEFINE_DACVAR(ULONG, PTR_BYTE, WKS__gc_heap__alloc_allocated, WKS::gc_heap::alloc_allocated)
-DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE /*PTR_heap_segment*/, WKS__gc_heap__ephemeral_heap_segment, WKS::gc_heap::ephemeral_heap_segment)
-DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE /*PTR_CFinalize*/, WKS__gc_heap__finalize_queue, WKS::gc_heap::finalize_queue)
-
-// Can not use MULTIPLE_HEAPS here because desktop build contains it is not defined for workstation GC
-// but we include workstation GC in mscorwks.dll.
-#ifdef FEATURE_SVR_GC
-DEFINE_DACVAR_SVR(ULONG, int, SVR__gc_heap__n_heaps, SVR::gc_heap::n_heaps)
-DEFINE_DACVAR_SVR(ULONG, UNKNOWN_POINTER_TYPE /*(PTR_gc_heap*)*/, SVR__gc_heap__g_heaps, SVR::gc_heap::g_heaps)
-#endif // FEATURE_SVR_GC
-DEFINE_DACVAR(ULONG, oom_history, WKS__gc_heap__oom_info, WKS::gc_heap::oom_info)
DEFINE_DACVAR(ULONG, PTR_SystemDomain, SystemDomain__m_pSystemDomain, SystemDomain::m_pSystemDomain)
DEFINE_DACVAR(ULONG, ArrayListStatic, SystemDomain__m_appDomainIndexList, SystemDomain::m_appDomainIndexList)
@@ -184,21 +174,12 @@ DEFINE_DACVAR(ULONG, MscorlibBinder, dac__g_Mscorlib, ::g_Mscorlib)
DEFINE_DACVAR(ULONG, ProfControlBlock, dac__g_profControlBlock, ::g_profControlBlock)
#endif // defined(PROFILING_SUPPORTED) || defined(PROFILING_SUPPORTED_DATA)
-DEFINE_DACVAR_NO_DUMP(ULONG, SIZE_T, dac__generation_table, WKS::generation_table)
DEFINE_DACVAR(ULONG, PTR_DWORD, dac__g_card_table, ::g_card_table)
DEFINE_DACVAR(ULONG, PTR_BYTE, dac__g_lowest_address, ::g_lowest_address)
DEFINE_DACVAR(ULONG, PTR_BYTE, dac__g_highest_address, ::g_highest_address)
DEFINE_DACVAR(ULONG, IGCHeap, dac__g_pGCHeap, ::g_pGCHeap)
-#ifdef GC_CONFIG_DRIVEN
-DEFINE_DACVAR_NO_DUMP(ULONG, SIZE_T, dac__interesting_data_per_heap, WKS::interesting_data_per_heap)
-DEFINE_DACVAR_NO_DUMP(ULONG, SIZE_T, dac__compact_reasons_per_heap, WKS::compact_reasons_per_heap)
-DEFINE_DACVAR_NO_DUMP(ULONG, SIZE_T, dac__expand_mechanisms_per_heap, WKS::expand_mechanisms_per_heap)
-DEFINE_DACVAR_NO_DUMP(ULONG, SIZE_T, dac__interesting_mechanism_bits_per_heap, WKS::interesting_mechanism_bits_per_heap)
-DEFINE_DACVAR_NO_DUMP(ULONG, SIZE_T, dac__gc_global_mechanisms, ::gc_global_mechanisms)
-#endif //GC_CONFIG_DRIVEN
-
DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pThinLockThreadIdDispenser, ::g_pThinLockThreadIdDispenser)
DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pModuleIndexDispenser, ::g_pModuleIndexDispenser)
DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pObjectClass, ::g_pObjectClass)
@@ -283,18 +264,6 @@ DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pIPCManagerInterface, ::g_pIPC
DEFINE_DACVAR_NO_DUMP(ULONG, SIZE_T, dac__g_FCDynamicallyAssignedImplementations, ::g_FCDynamicallyAssignedImplementations)
-DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE /*BYTE**/, WKS__gc_heap__internal_root_array, WKS::gc_heap::internal_root_array)
-DEFINE_DACVAR(ULONG, size_t, WKS__gc_heap__internal_root_array_index, WKS::gc_heap::internal_root_array_index)
-DEFINE_DACVAR(ULONG, ULONG, WKS__gc_heap__heap_analyze_success, WKS::gc_heap::heap_analyze_success)
-
-DEFINE_DACVAR(ULONG, SIZE_T, WKS__gc_heap__mark_array, WKS::gc_heap::mark_array)
-DEFINE_DACVAR(ULONG, SIZE_T, WKS__gc_heap__current_c_gc_state, WKS::gc_heap::current_c_gc_state)
-DEFINE_DACVAR(ULONG, PTR_BYTE, WKS__gc_heap__next_sweep_obj, WKS::gc_heap::next_sweep_obj)
-DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE /* PTR_heap_segment */, WKS__gc_heap__saved_sweep_ephemeral_seg, WKS::gc_heap::saved_sweep_ephemeral_seg)
-DEFINE_DACVAR(ULONG, PTR_BYTE, WKS__gc_heap__saved_sweep_ephemeral_start, WKS::gc_heap::saved_sweep_ephemeral_start)
-DEFINE_DACVAR(ULONG, PTR_BYTE, WKS__gc_heap__background_saved_lowest_address, WKS::gc_heap::background_saved_lowest_address)
-DEFINE_DACVAR(ULONG, PTR_BYTE, WKS__gc_heap__background_saved_highest_address, WKS::gc_heap::background_saved_highest_address)
-
#ifndef FEATURE_PAL
DEFINE_DACVAR(ULONG, HANDLE, dac__g_hContinueStartupEvent, ::g_hContinueStartupEvent)
#endif // !FEATURE_PAL
diff --git a/src/vm/ceemain.cpp b/src/vm/ceemain.cpp
index 59ad618249..86ae7f1059 100644
--- a/src/vm/ceemain.cpp
+++ b/src/vm/ceemain.cpp
@@ -2473,10 +2473,22 @@ void InitializeGarbageCollector()
IGCToCLR* gcToClr = nullptr;
#endif
- IGCHeap *pGCHeap = InitializeGarbageCollector(gcToClr);
- g_pGCHeap = pGCHeap;
- if (!pGCHeap)
+
+ IGCHeap *pGCHeap;
+ if (!InitializeGarbageCollector(gcToClr, &pGCHeap, &g_gc_dac_vars))
+ {
ThrowOutOfMemory();
+ }
+
+ assert(pGCHeap != nullptr);
+ g_pGCHeap = pGCHeap;
+ g_gcDacGlobals = &g_gc_dac_vars;
+
+ // Apparently the Windows linker removes global variables if they are never
+ // read from, which is a problem for g_gcDacGlobals since it's expected that
+ // only the DAC will read from it. This forces the linker to include
+ // g_gcDacGlobals.
+ volatile void* _dummy = g_gcDacGlobals;
hr = pGCHeap->Initialize();
IfFailThrow(hr);
diff --git a/src/vm/gcheaputilities.cpp b/src/vm/gcheaputilities.cpp
index 91f259d275..f76e4bcb10 100644
--- a/src/vm/gcheaputilities.cpp
+++ b/src/vm/gcheaputilities.cpp
@@ -18,9 +18,12 @@ uint8_t* g_ephemeral_high = (uint8_t*)~0;
// This is the global GC heap, maintained by the VM.
GPTR_IMPL(IGCHeap, g_pGCHeap);
+GcDacVars g_gc_dac_vars;
+GPTR_IMPL(GcDacVars, g_gcDacGlobals);
+
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
uint8_t* g_sw_ww_table = nullptr;
bool g_sw_ww_enabled_for_gc_heap = false;
-#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP \ No newline at end of file
+#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
diff --git a/src/vm/gcheaputilities.h b/src/vm/gcheaputilities.h
index e76a21173c..f85bd73fed 100644
--- a/src/vm/gcheaputilities.h
+++ b/src/vm/gcheaputilities.h
@@ -34,6 +34,21 @@ extern "C" bool g_sw_ww_enabled_for_gc_heap;
#endif // FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
+// g_gc_dac_vars is a structure of pointers to GC globals that the
+// DAC uses. It is not exposed directly to the DAC.
+extern GcDacVars g_gc_dac_vars;
+
+// Instead of exposing g_gc_dac_vars to the DAC, a pointer to it
+// is exposed here (g_gcDacGlobals). The reason for this is to avoid
+// a problem in which a debugger attaches to a program while the program
+// is in the middle of initializing the GC DAC vars - if the "publishing"
+// of DAC vars isn't atomic, the debugger could see a partially initialized
+// GcDacVars structure.
+//
+// Instead, the debuggee "publishes" GcDacVars by assigning a pointer to g_gc_dac_vars
+// to this global, and the DAC will read this global.
+typedef DPTR(GcDacVars) PTR_GcDacVars;
+GPTR_DECL(GcDacVars, g_gcDacGlobals);
// GCHeapUtilities provides a number of static methods
// that operate on the global heap instance. It can't be
@@ -112,27 +127,6 @@ public:
#endif // FEATURE_SVR_GC
}
- // Gets the maximum generation number by reading the static field
- // on IGCHeap. This should only be done by the DAC code paths - all other code
- // should go through IGCHeap::GetMaxGeneration.
- //
- // The reason for this is that, while we are in the early stages of
- // decoupling the GC, the GC and the DAC still remain tightly coupled
- // and, in particular, the DAC needs to know how many generations the GC
- // has. However, it is not permitted to invoke virtual methods on g_pGCHeap
- // while on a DAC code path. Therefore, we need to determine the max generation
- // non-virtually, while still in a manner consistent with the interface -
- // therefore, a static field is used.
- //
- // This is not without precedent - IGCHeap::gcHeapType is a static field used
- // for a similar reason (the DAC needs to know what kind of heap it's looking at).
- inline static unsigned GetMaxGeneration()
- {
- WRAPPER_NO_CONTRACT;
-
- return IGCHeap::maxGeneration;
- }
-
#ifdef FEATURE_USE_SOFTWARE_WRITE_WATCH_FOR_GC_HEAP
// Returns True if software write watch is currently enabled for the GC Heap,
@@ -203,4 +197,5 @@ private:
GCHeapUtilities() = delete;
};
-#endif // _GCHEAPUTILITIES_H_ \ No newline at end of file
+#endif // _GCHEAPUTILITIES_H_
+