Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure GCHeap related debugging still works even when we use newer CLRGC to target older runtimes #88457

Merged
merged 4 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 27 additions & 4 deletions src/coreclr/gc/dac_gcheap_fields.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
// Whenever we add field here, we need to bare in mind that we have a scenario for a new clrgc
cshung marked this conversation as resolved.
Show resolved Hide resolved
// is used in an old runtime. In that case, the old runtime's DAC will have to interpret the
// fields the way it was. So fields should only be added at the end of the struct.

#ifndef DEFINE_OFFSET_ONLY_FIELD
#define DEFINE_OFFSET_ONLY_FIELD_IGNORED
#define DEFINE_OFFSET_ONLY_FIELD(name)
#endif

DEFINE_FIELD (alloc_allocated, uint8_t*)
DEFINE_DPTR_FIELD (ephemeral_heap_segment, dac_heap_segment)
DEFINE_DPTR_FIELD (finalize_queue, dac_finalize_queue)
Expand All @@ -16,8 +25,6 @@ DEFINE_FIELD (mark_array, uint32_t*)
DEFINE_FIELD (next_sweep_obj, uint8_t*)
DEFINE_FIELD (background_saved_lowest_address, uint8_t*)
DEFINE_FIELD (background_saved_highest_address, uint8_t*)
DEFINE_DPTR_FIELD (freeable_soh_segment, dac_heap_segment)
DEFINE_DPTR_FIELD (freeable_uoh_segment, dac_heap_segment)
#if defined(ALL_FIELDS) || !defined(USE_REGIONS)
DEFINE_DPTR_FIELD (saved_sweep_ephemeral_seg, dac_heap_segment)
DEFINE_FIELD (saved_sweep_ephemeral_start, uint8_t*)
Expand All @@ -30,14 +37,30 @@ DEFINE_MISSING_FIELD(mark_array)
DEFINE_MISSING_FIELD(next_sweep_obj)
DEFINE_MISSING_FIELD(background_saved_lowest_address)
DEFINE_MISSING_FIELD(background_saved_highest_address)
DEFINE_MISSING_FIELD(freeable_soh_segment)
DEFINE_MISSING_FIELD(freeable_uoh_segment)
DEFINE_MISSING_FIELD(saved_sweep_ephemeral_seg)
DEFINE_MISSING_FIELD(saved_sweep_ephemeral_start)
#endif // defined(ALL_FIELDS) || defined(BACKGROUND_GC)

// generation_table is a special field, it is not included in dac_gcheap
// but its offset need to be right at this spot in order to match the
// layout we had in .NET 6+
DEFINE_OFFSET_ONLY_FIELD(generation_table)
cshung marked this conversation as resolved.
Show resolved Hide resolved

#if defined(ALL_FIELDS) || defined(BACKGROUND_GC)
DEFINE_DPTR_FIELD (freeable_soh_segment, dac_heap_segment)
DEFINE_DPTR_FIELD (freeable_uoh_segment, dac_heap_segment)
#else
DEFINE_MISSING_FIELD(freeable_soh_segment)
DEFINE_MISSING_FIELD(freeable_uoh_segment)
#endif // defined(ALL_FIELDS) || defined(BACKGROUND_GC)

#if defined(ALL_FIELDS) || defined(USE_REGIONS)
DEFINE_ARRAY_FIELD (free_regions, dac_region_free_list, FREE_REGION_KINDS)
#else
DEFINE_MISSING_FIELD(free_regions)
#endif // ALL_FIELDS

#ifdef DEFINE_OFFSET_ONLY_FIELD_IGNORED
#undef DEFINE_OFFSET_ONLY_FIELD_IGNORED
#undef DEFINE_OFFSET_ONLY_FIELD
#endif
20 changes: 13 additions & 7 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51916,36 +51916,36 @@ bool GCHeap::IsConcurrentGCEnabled()

void PopulateDacVars(GcDacVars *gcDacVars)
{
bool v2 = gcDacVars->minor_version_number >= 2;

#define DEFINE_FIELD(field_name, field_type) offsetof(CLASS_NAME, field_name),
#define DEFINE_DPTR_FIELD(field_name, field_type) offsetof(CLASS_NAME, field_name),
#define DEFINE_ARRAY_FIELD(field_name, field_type, array_length) offsetof(CLASS_NAME, field_name),
#define DEFINE_MISSING_FIELD(field_name) -1,
#define DEFINE_OFFSET_ONLY_FIELD(field_name) offsetof(CLASS_NAME, field_name),

#ifdef MULTIPLE_HEAPS
static int gc_heap_field_offsets[] = {
#define CLASS_NAME gc_heap
#include "dac_gcheap_fields.h"
#undef CLASS_NAME

offsetof(gc_heap, generation_table)
};
static_assert(sizeof(gc_heap_field_offsets) == (GENERATION_TABLE_FIELD_INDEX + 1) * sizeof(int), "GENERATION_TABLE_INDEX mismatch");
#endif //MULTIPLE_HEAPS
static int generation_field_offsets[] = {

#define CLASS_NAME generation
#include "dac_generation_fields.h"
#undef CLASS_NAME

#undef DEFINE_OFFSET_ONLY_FIELD
#undef DEFINE_MISSING_FIELD
#undef DEFINE_ARRAY_FIELD
#undef DEFINE_DPTR_FIELD
#undef DEFINE_FIELD
};

assert(gcDacVars != nullptr);
*gcDacVars = {};

// Note: These version numbers do not need to be checked in the .Net dac/SOS because
// we always match the compiled dac and GC to the version used. NativeAOT's SOS may
// work differently than .Net SOS. When making breaking changes here you may need to
Expand Down Expand Up @@ -51984,8 +51984,11 @@ void PopulateDacVars(GcDacVars *gcDacVars)
gcDacVars->mark_array = &gc_heap::mark_array;
gcDacVars->background_saved_lowest_address = &gc_heap::background_saved_lowest_address;
gcDacVars->background_saved_highest_address = &gc_heap::background_saved_highest_address;
gcDacVars->freeable_soh_segment = reinterpret_cast<dac_heap_segment**>(&gc_heap::freeable_soh_segment);
gcDacVars->freeable_uoh_segment = reinterpret_cast<dac_heap_segment**>(&gc_heap::freeable_uoh_segment);
if (v2)
{
gcDacVars->freeable_soh_segment = reinterpret_cast<dac_heap_segment**>(&gc_heap::freeable_soh_segment);
gcDacVars->freeable_uoh_segment = reinterpret_cast<dac_heap_segment**>(&gc_heap::freeable_uoh_segment);
}
gcDacVars->next_sweep_obj = &gc_heap::next_sweep_obj;
#ifdef USE_REGIONS
gcDacVars->saved_sweep_ephemeral_seg = 0;
Expand Down Expand Up @@ -52026,7 +52029,10 @@ void PopulateDacVars(GcDacVars *gcDacVars)
gcDacVars->gc_heap_field_offsets = reinterpret_cast<int**>(&gc_heap_field_offsets);
#endif // MULTIPLE_HEAPS
gcDacVars->generation_field_offsets = reinterpret_cast<int**>(&generation_field_offsets);
gcDacVars->bookkeeping_start = &gc_heap::bookkeeping_start;
if (v2)
{
gcDacVars->bookkeeping_start = &gc_heap::bookkeeping_start;
}
}

int GCHeap::RefreshMemoryLimit()
Expand Down
11 changes: 3 additions & 8 deletions src/coreclr/gc/gcinterface.dac.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ class dac_gc_heap {
dac_generation generation_table[1];
};

#define GENERATION_TABLE_FIELD_INDEX 21
#define GENERATION_TABLE_FIELD_INDEX 18

// Unlike other DACized structures, these types are loaded manually in the debugger.
// To avoid misuse, pointers to them are explicitly casted to these unused type.
Expand Down Expand Up @@ -242,13 +242,7 @@ struct unused_generation
// 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;
size_t total_generation_count;
int total_bookkeeping_elements;
int count_free_region_kinds;
size_t card_table_info_size;
#define GC_DAC_VAL(type, name) type name;
#ifdef DACCESS_COMPILE
#define GC_DAC_VAR(type, name) DPTR(type) name;
#define GC_DAC_PTR_VAR(type, name) DPTR(type*) name;
Expand All @@ -257,6 +251,7 @@ struct GcDacVars {
#define GC_DAC_VAR(type, name) type *name;
#endif
#include "gcinterface.dacvars.def"
#undef GC_DAC_VAL
};

#endif // _GC_INTERFACE_DAC_H_
20 changes: 18 additions & 2 deletions src/coreclr/gc/gcinterface.dacvars.def
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@
// degraded debugging experience.
// Major version mismatches are not tolerated by the DAC and will be rejected upon load.

// Whenever we add field here, we need to bare in mind that we have a scenario for a new clrgc
cshung marked this conversation as resolved.
Show resolved Hide resolved
// is used in an old runtime. In that case, the old runtime's DAC will have to interpret the
// fields the way it was. So fields should only be added at the end of the struct, and their
// loading in PopulateDacVars need to be version checked against a bumped up minor version.

#ifndef GC_DAC_VAL
#define GC_DAC_VAL(type, name)
#endif // GC_DAC_VAL

#ifndef GC_DAC_VAR
#define GC_DAC_VAR(type, name)
#endif // GC_DAC_VAR
Expand All @@ -33,6 +42,10 @@

// This sequence of macros defines the specific variables that are exposed by the
// GC to the DAC.
GC_DAC_VAL (uint8_t, major_version_number)
GC_DAC_VAL (uint8_t, minor_version_number)
GC_DAC_VAL (size_t, generation_size)
GC_DAC_VAL (size_t, total_generation_count)
GC_DAC_VAR (uint8_t, build_variant)
GC_DAC_VAR (bool, built_with_svr)
GC_DAC_ARRAY_VAR (size_t, gc_global_mechanisms)
Expand All @@ -42,8 +55,6 @@ 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 (dac_heap_segment, freeable_soh_segment)
GC_DAC_PTR_VAR (dac_heap_segment, freeable_uoh_segment)
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)
Expand All @@ -68,6 +79,11 @@ GC_DAC_PTR_VAR (uint8_t, bookkeeping_start)
GC_DAC_ARRAY_VAR (dac_region_free_list, global_regions_to_decommit)
GC_DAC_PTR_VAR (dac_region_free_list, global_free_huge_regions)
GC_DAC_ARRAY_VAR (dac_region_free_list, free_regions)
GC_DAC_PTR_VAR (dac_heap_segment, freeable_soh_segment)
cshung marked this conversation as resolved.
Show resolved Hide resolved
GC_DAC_PTR_VAR (dac_heap_segment, freeable_uoh_segment)
GC_DAC_VAL (int, total_bookkeeping_elements)
GC_DAC_VAL (int, count_free_region_kinds)
GC_DAC_VAL (size_t, card_table_info_size)

#undef GC_DAC_VAR
#undef GC_DAC_ARRAY_VAR
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/gc/gcinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
// The minor version of the IGCHeap interface. Non-breaking changes are required
// to bump the minor version number. GCs and EEs with minor version number
// mismatches can still interoperate correctly, with some care.
#define GC_INTERFACE_MINOR_VERSION 1
#define GC_INTERFACE_MINOR_VERSION 2

// The major version of the IGCToCLR interface. Breaking changes to this interface
// require bumps in the major version number.
Expand Down
2 changes: 2 additions & 0 deletions src/coreclr/vm/gcheaputilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@ HRESULT GCHeapUtilities::LoadAndInitialize()
g_gc_load_status = GC_LOAD_STATUS_START;

LPCWSTR standaloneGcLocation = Configuration::GetKnobStringValue(W("System.GC.Name"), CLRConfig::EXTERNAL_GCName);
g_gc_dac_vars.major_version_number = GC_INTERFACE_MAJOR_VERSION;
g_gc_dac_vars.minor_version_number = GC_INTERFACE_MINOR_VERSION;
if (!standaloneGcLocation)
{
return InitializeDefaultGC();
Expand Down