diff options
-rw-r--r-- | src/ToolBox/SOS/Strike/strike.cpp | 10 | ||||
-rw-r--r-- | src/debug/daccess/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/debug/daccess/daccess.cpp | 7 | ||||
-rw-r--r-- | src/debug/daccess/dacdbiimpl.cpp | 31 | ||||
-rw-r--r-- | src/debug/daccess/dacfn.cpp | 4 | ||||
-rw-r--r-- | src/debug/daccess/enummem.cpp | 6 | ||||
-rw-r--r-- | src/debug/daccess/gcinterface.dac.h | 5 | ||||
-rw-r--r-- | src/debug/daccess/request.cpp | 128 | ||||
-rw-r--r-- | src/debug/daccess/request_common.h | 58 | ||||
-rw-r--r-- | src/debug/daccess/request_svr.cpp | 170 | ||||
-rw-r--r-- | src/gc/env/gcenv.structs.h | 2 | ||||
-rw-r--r-- | src/gc/gc.cpp | 117 | ||||
-rw-r--r-- | src/gc/gc.h | 43 | ||||
-rw-r--r-- | src/gc/gccommon.cpp | 55 | ||||
-rw-r--r-- | src/gc/gcinterface.dac.h | 162 | ||||
-rw-r--r-- | src/gc/gcinterface.dacvars.def | 67 | ||||
-rw-r--r-- | src/gc/gcinterface.h | 7 | ||||
-rw-r--r-- | src/gc/gcpriv.h | 233 | ||||
-rw-r--r-- | src/gc/gcscan.h | 1 | ||||
-rw-r--r-- | src/gc/sample/GCSample.cpp | 7 | ||||
-rw-r--r-- | src/inc/dacprivate.h | 23 | ||||
-rw-r--r-- | src/inc/dacvars.h | 33 | ||||
-rw-r--r-- | src/vm/ceemain.cpp | 18 | ||||
-rw-r--r-- | src/vm/gcheaputilities.cpp | 5 | ||||
-rw-r--r-- | src/vm/gcheaputilities.h | 39 |
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)¶m, 0, &handleType, 1, - mGenerationFilter, GCHeapUtilities::GetMaxGeneration(), 0); + mGenerationFilter, *g_gcDacGlobals->max_gen, 0); else HndEnumHandles(hTable, &handleType, 1, callback, (LPARAM)¶m, 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_ + |