summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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_
+