Skip to content

Commit 61b5219

Browse files
authored
[cDAC] GC Contract (#118050)
* Modify cDAC datadescriptor spec to support sub-descriptors * Modify cdac-build-tool to support sub-descriptors * Implement GC sub-descriptor * Implement cDAC GC API GetGCHeapData and GetGCHeapList * gcinterface minor version bump
1 parent 89ccd55 commit 61b5219

File tree

40 files changed

+1385
-268
lines changed

40 files changed

+1385
-268
lines changed

docs/design/datacontracts/GC.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# Contract GC
2+
3+
This contract is for getting information about the garbage collector configuration and state.
4+
5+
## APIs of contract
6+
7+
8+
```csharp
9+
// Return an array of strings identifying the GC type.
10+
// Current return values can include:
11+
// "workstation" or "server"
12+
// "segments" or "regions"
13+
string[] GetGCIdentifiers();
14+
// Return the number of GC heaps
15+
uint GetGCHeapCount();
16+
// Return true if the GC structure is valid, otherwise return false
17+
bool GetGCStructuresValid();
18+
// Return the maximum generation of the current GC
19+
uint GetMaxGeneration();
20+
```
21+
22+
## Version 1
23+
24+
Data descriptors used:
25+
| Data Descriptor Name | Field | Meaning |
26+
| --- | --- | --- |
27+
| _(none)_ | | |
28+
29+
Global variables used:
30+
| Global Name | Type | Purpose |
31+
| --- | --- | --- |
32+
| `GCIdentifiers` | string | CSV string containing identifiers of the GC. Current values are "server", "workstation", "regions", and "segments" |
33+
| `NumHeaps` | TargetPointer | Pointer to the number of heaps for server GC (int) |
34+
| `StructureInvalidCount` | TargetPointer | Pointer to the count of invalid GC structures (int) |
35+
| `MaxGeneration` | TargetPointer | Pointer to the maximum generation number (uint) |
36+
37+
Contracts used:
38+
| Contract Name |
39+
| --- |
40+
| _(none)_ |
41+
42+
43+
Constants used:
44+
| Name | Type | Purpose | Value |
45+
| --- | --- | --- | --- |
46+
| `WRK_HEAP_COUNT` | uint | The number of heaps in the `workstation` GC type | `1` |
47+
48+
```csharp
49+
GCHeapType GetGCIdentifiers()
50+
{
51+
string gcIdentifiers = _target.ReadGlobalString("GCIdentifiers");
52+
return gcIdentifiers.Split(", ");
53+
}
54+
55+
uint GetGCHeapCount()
56+
{
57+
string[] gcIdentifiers = GetGCIdentifiers()
58+
if (gcType.Contains("workstation"))
59+
{
60+
return WRK_HEAP_COUNT;
61+
}
62+
if (gcType.Contains("server"))
63+
{
64+
TargetPointer pNumHeaps = target.ReadGlobalPointer("NumHeaps");
65+
return (uint)target.Read<int>(pNumHeaps);
66+
}
67+
68+
throw new NotImplementedException("Unknown GC heap type");
69+
}
70+
71+
bool GetGCStructuresValid()
72+
{
73+
TargetPointer pInvalidCount = target.ReadGlobalPointer("StructureInvalidCount");
74+
int invalidCount = target.Read<int>(pInvalidCount);
75+
return invalidCount == 0; // Structures are valid if the count of invalid structures is zero
76+
}
77+
78+
uint GetMaxGeneration()
79+
{
80+
TargetPointer pMaxGeneration = target.ReadGlobalPointer("MaxGeneration");
81+
return target.Read<uint>(pMaxGeneration);
82+
}
83+
```

src/coreclr/clrdefinitions.cmake

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ if (FEATURE_ENABLE_NO_ADDRESS_SPACE_RANDOMIZATION)
170170
add_definitions(-DFEATURE_ENABLE_NO_ADDRESS_SPACE_RANDOMIZATION)
171171
endif(FEATURE_ENABLE_NO_ADDRESS_SPACE_RANDOMIZATION)
172172
if (NOT CLR_CMAKE_HOST_ANDROID)
173+
set(FEATURE_SVR_GC 1)
173174
add_definitions(-DFEATURE_SVR_GC)
174175
endif(NOT CLR_CMAKE_HOST_ANDROID)
175176
add_definitions(-DFEATURE_SYMDIFF)

src/coreclr/debug/datadescriptor-shared/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,12 @@ The build system uses a two-phase approach:
8282
- Defines a global string value
8383
- `stringValue` must be a compile-time string literal
8484

85+
**`CDAC_GLOBAL_SUB_DESCRIPTOR(globalName, address)`**
86+
- Defines a reference to another contract descriptor
87+
- `address` must be a compile-time constant pointer to a pointer to a contract descriptor
88+
- Used for multi-contract scenarios where one contract references another
89+
- Example: `CDAC_GLOBAL_SUB_DESCRIPTOR(GC, &(g_gc_dac_vars.gc_descriptor))`
90+
8591

8692
## Current Implementation
8793

src/coreclr/debug/datadescriptor-shared/contractpointerdata.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,3 @@ extern "C"
1414
#include "wrappeddatadescriptor.inc"
1515
};
1616
};
17-

src/coreclr/debug/datadescriptor-shared/datadescriptor.cpp

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33

44
#include "datadescriptor.h"
55

6+
#ifndef DLLEXPORT
7+
#ifdef _MSC_VER
8+
#define DLLEXPORT __declspec(dllexport)
9+
#else
10+
#define DLLEXPORT __attribute__ ((visibility ("default")))
11+
#endif // _MSC_VER
12+
#endif // DLLEXPORT
13+
614
// begin blob definition
715

816
extern "C"
@@ -52,7 +60,8 @@ struct GlobalStringSpec
5260
#define MAKE_GLOBALVALUELEN_NAME(globalname) CONCAT(cdac_string_pool_globalvalue__, globalname)
5361

5462
// used to stringify the result of a macros expansion
55-
#define STRINGIFY(x) #x
63+
// __VA_ARGS__ is the argument list comma separated
64+
#define STRINGIFY(...) #__VA_ARGS__
5665

5766
// define a struct where the size of each field is the length of some string. we will use offsetof to get
5867
// the offset of each struct element, which will be equal to the offset of the beginning of that string in the
@@ -68,6 +77,7 @@ struct CDacStringPoolSizes
6877
#define CDAC_GLOBAL_STRING(name, stringval) DECL_LEN(MAKE_GLOBALLEN_NAME(name), sizeof(#name)) \
6978
DECL_LEN(MAKE_GLOBALVALUELEN_NAME(name), sizeof(STRINGIFY(stringval)))
7079
#define CDAC_GLOBAL_POINTER(name,value) DECL_LEN(MAKE_GLOBALLEN_NAME(name), sizeof(#name))
80+
#define CDAC_GLOBAL_SUB_DESCRIPTOR(name,value) DECL_LEN(MAKE_GLOBALLEN_NAME(name), sizeof(#name))
7181
#define CDAC_GLOBAL(name,tyname,value) DECL_LEN(MAKE_GLOBALLEN_NAME(name), sizeof(#name)) \
7282
DECL_LEN(MAKE_GLOBALTYPELEN_NAME(name), sizeof(#tyname))
7383
#include "wrappeddatadescriptor.inc"
@@ -129,6 +139,15 @@ enum
129139
#include "wrappeddatadescriptor.inc"
130140
};
131141

142+
// count the global sub-descriptors
143+
enum
144+
{
145+
CDacBlobGlobalSubDescriptorsCount =
146+
#define CDAC_GLOBALS_BEGIN() 0
147+
#define CDAC_GLOBAL_SUB_DESCRIPTOR(name,value) + 1
148+
#include "wrappeddatadescriptor.inc"
149+
};
150+
132151

133152
#define MAKE_TYPEFIELDS_TYNAME(tyname) CONCAT(CDacFieldsPoolTypeStart__, tyname)
134153

@@ -178,6 +197,7 @@ struct CDacGlobalPointerIndex
178197
#define DECL_LEN(membername) char membername;
179198
#define CDAC_GLOBALS_BEGIN() DECL_LEN(cdac_global_pointer_index_start_placeholder__)
180199
#define CDAC_GLOBAL_POINTER(name,value) DECL_LEN(CONCAT(cdac_global_pointer_index__, name))
200+
#define CDAC_GLOBAL_SUB_DESCRIPTOR(name,value) DECL_LEN(CONCAT(cdac_global_pointer_index__, name))
181201
#include "wrappeddatadescriptor.inc"
182202
#undef DECL_LEN
183203
};
@@ -204,6 +224,8 @@ struct BinaryBlobDataDescriptor
204224

205225
uint32_t GlobalPointersStart;
206226
uint32_t GlobalStringValuesStart;
227+
228+
uint32_t GlobalSubDescriptorsStart;
207229
uint32_t NamesPoolStart;
208230

209231
uint32_t TypeCount;
@@ -212,6 +234,7 @@ struct BinaryBlobDataDescriptor
212234
uint32_t GlobalLiteralValuesCount;
213235
uint32_t GlobalPointerValuesCount;
214236
uint32_t GlobalStringValuesCount;
237+
uint32_t GlobalSubDescriptorsCount;
215238

216239
uint32_t NamesPoolCount;
217240

@@ -223,11 +246,13 @@ struct BinaryBlobDataDescriptor
223246
} Directory;
224247
uint32_t PlatformFlags;
225248
uint32_t BaselineName;
226-
struct TypeSpec Types[CDacBlobTypesCount];
227-
struct FieldSpec FieldsPool[CDacBlobFieldsPoolCount];
228-
struct GlobalLiteralSpec GlobalLiteralValues[CDacBlobGlobalLiteralsCount];
229-
struct GlobalPointerSpec GlobalPointerValues[CDacBlobGlobalPointersCount];
230-
struct GlobalStringSpec GlobalStringValues[CDacBlobGlobalStringsCount];
249+
// cpp does not allow zero-length arrays, so we add one extra element to allow having zero of a given type of descriptor
250+
struct TypeSpec Types[CDacBlobTypesCount + 1];
251+
struct FieldSpec FieldsPool[CDacBlobFieldsPoolCount + 1];
252+
struct GlobalLiteralSpec GlobalLiteralValues[CDacBlobGlobalLiteralsCount + 1];
253+
struct GlobalPointerSpec GlobalPointerValues[CDacBlobGlobalPointersCount + 1];
254+
struct GlobalStringSpec GlobalStringValues[CDacBlobGlobalStringsCount + 1];
255+
struct GlobalPointerSpec GlobalSubDescriptorValues[CDacBlobGlobalSubDescriptorsCount + 1];
231256
uint8_t NamesPool[sizeof(struct CDacStringPoolSizes)];
232257
uint8_t EndMagic[4];
233258
};
@@ -253,12 +278,14 @@ struct MagicAndBlob BlobDataDescriptor = {
253278
/* .GlobalLiteralValuesStart = */ offsetof(struct BinaryBlobDataDescriptor, GlobalLiteralValues),
254279
/* .GlobalPointersStart = */ offsetof(struct BinaryBlobDataDescriptor, GlobalPointerValues),
255280
/* .GlobalStringValuesStart = */ offsetof(struct BinaryBlobDataDescriptor, GlobalStringValues),
281+
/* .GlobalSubDescriptorsStart = */ offsetof(struct BinaryBlobDataDescriptor, GlobalSubDescriptorValues),
256282
/* .NamesPoolStart = */ offsetof(struct BinaryBlobDataDescriptor, NamesPool),
257283
/* .TypeCount = */ CDacBlobTypesCount,
258284
/* .FieldsPoolCount = */ CDacBlobFieldsPoolCount,
259285
/* .GlobalLiteralValuesCount = */ CDacBlobGlobalLiteralsCount,
260286
/* .GlobalPointerValuesCount = */ CDacBlobGlobalPointersCount,
261287
/* .GlobalStringValuesCount = */ CDacBlobGlobalStringsCount,
288+
/* .GlobalSubDescriptorsCount = */ CDacBlobGlobalSubDescriptorsCount,
262289
/* .NamesPoolCount = */ sizeof(struct CDacStringPoolSizes),
263290
/* .TypeSpecSize = */ sizeof(struct TypeSpec),
264291
/* .FieldSpecSize = */ sizeof(struct FieldSpec),
@@ -305,12 +332,18 @@ struct MagicAndBlob BlobDataDescriptor = {
305332
#include "wrappeddatadescriptor.inc"
306333
},
307334

335+
/* .GlobalSubDescriptorValues = */ {
336+
#define CDAC_GLOBAL_SUB_DESCRIPTOR(name,value) { /* .Name = */ GET_GLOBAL_NAME(name), /* .PointerDataIndex = */ GET_GLOBAL_POINTER_INDEX(name) },
337+
#include "wrappeddatadescriptor.inc"
338+
},
339+
308340
/* .NamesPool = */ ("\0" // starts with a nul
309341
#define CDAC_BASELINE(name) name "\0"
310342
#define CDAC_TYPE_BEGIN(name) #name "\0"
311343
#define CDAC_TYPE_FIELD(tyname,membertyname,membername,offset) #membername "\0" #membertyname "\0"
312344
#define CDAC_GLOBAL_STRING(name,value) #name "\0" STRINGIFY(value) "\0"
313345
#define CDAC_GLOBAL_POINTER(name,value) #name "\0"
346+
#define CDAC_GLOBAL_SUB_DESCRIPTOR(name,value) #name "\0"
314347
#define CDAC_GLOBAL(name,tyname,value) #name "\0" #tyname "\0"
315348
#include "wrappeddatadescriptor.inc"
316349
),

src/coreclr/debug/datadescriptor-shared/wrappeddatadescriptor.inc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
#ifndef CDAC_GLOBAL_STRING
4141
#define CDAC_GLOBAL_STRING(globalname,stringval)
4242
#endif
43+
#ifndef CDAC_GLOBAL_SUB_DESCRIPTOR
44+
#define CDAC_GLOBAL_SUB_DESCRIPTOR(globalname,addr)
45+
#endif
4346
#ifndef CDAC_GLOBALS_END
4447
#define CDAC_GLOBALS_END()
4548
#endif
@@ -58,4 +61,5 @@
5861
#undef CDAC_GLOBAL
5962
#undef CDAC_GLOBAL_POINTER
6063
#undef CDAC_GLOBAL_STRING
64+
#undef CDAC_GLOBAL_SUB_DESCRIPTOR
6165
#undef CDAC_GLOBALS_END

src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ if (NOT CLR_CMAKE_HOST_ARCH_WASM)
7373
set(LIB_CORDBEE cordbee_wks)
7474
set(LIB_INTEROP interop)
7575
set(LIB_CDAC_CONTRACT_DESCRIPTOR cdac_contract_descriptor)
76+
set(LIB_CDAC_GC_WKS_DESCRIPTOR gc_wks_descriptor)
77+
set(LIB_CDAC_GC_SVR_DESCRIPTOR gc_svr_descriptor)
7678
endif(NOT CLR_CMAKE_HOST_ARCH_WASM)
7779

7880
if (CLR_CMAKE_HOST_UNIX AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
@@ -104,8 +106,15 @@ set(CORECLR_LIBRARIES
104106
coreclrminipal
105107
gc_pal
106108
${LIB_CDAC_CONTRACT_DESCRIPTOR}
109+
${LIB_CDAC_GC_WKS_DESCRIPTOR}
107110
)
108111

112+
if (FEATURE_SVR_GC)
113+
list(APPEND CORECLR_LIBRARIES
114+
${LIB_CDAC_GC_SVR_DESCRIPTOR}
115+
)
116+
endif(FEATURE_SVR_GC)
117+
109118
if(CLR_CMAKE_TARGET_ARCH_AMD64)
110119
list(APPEND CORECLR_LIBRARIES
111120
gc_vxsort

src/coreclr/gc/CMakeLists.txt

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ endif (CLR_CMAKE_TARGET_ARCH_AMD64)
4141

4242
if (CLR_CMAKE_TARGET_WIN32)
4343
set(GC_HEADERS
44+
env/cdacdata.h
4445
env/common.h
4546
env/etmdummy.h
4647
env/gcenv.base.h
@@ -104,19 +105,31 @@ list(APPEND GC_SOURCES ${GC_HEADERS})
104105
convert_to_absolute_path(GC_SOURCES ${GC_SOURCES})
105106

106107
if(FEATURE_STANDALONE_GC)
107-
# clrgcexp is build with standalone+regions
108108
if (CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_AMD64)
109+
set(BUILD_EXP_GC 1)
110+
endif()
111+
112+
# clrgcexp is build with standalone+regions
113+
if (BUILD_EXP_GC)
109114
add_library_clr(clrgcexp SHARED ${GC_SOURCES})
110115
add_dependencies(clrgcexp eventing_headers)
111116
target_link_libraries(clrgcexp PRIVATE ${GC_LINK_LIBRARIES})
117+
target_link_libraries(clrgcexp PRIVATE gcexp_dll_wks_descriptor)
118+
if (FEATURE_SVR_GC)
119+
target_link_libraries(clrgcexp PRIVATE gcexp_dll_svr_descriptor)
120+
endif()
112121
target_compile_definitions(clrgcexp PRIVATE -DUSE_REGIONS)
113122
install_clr(TARGETS clrgcexp DESTINATIONS . COMPONENT runtime)
114-
endif (CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_AMD64)
123+
endif (BUILD_EXP_GC)
115124

116125
# clrgc is build with standalone+segments
117126
add_library_clr(clrgc SHARED ${GC_SOURCES})
118127
add_dependencies(clrgc eventing_headers)
119128
target_link_libraries(clrgc PRIVATE ${GC_LINK_LIBRARIES})
129+
target_link_libraries(clrgc PRIVATE gc_dll_wks_descriptor)
130+
if(FEATURE_SVR_GC)
131+
target_link_libraries(clrgc PRIVATE gc_dll_svr_descriptor)
132+
endif()
120133
install_clr(TARGETS clrgc DESTINATIONS . COMPONENT runtime)
121134

122135
add_definitions(-DBUILD_AS_STANDALONE)
@@ -134,6 +147,9 @@ if(FEATURE_STANDALONE_GC)
134147
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
135148
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/env)
136149

150+
add_definitions(-DGC_DESCRIPTOR)
151+
add_subdirectory(datadescriptor)
152+
137153
install_clr(TARGETS clrgc DESTINATIONS . sharedFramework COMPONENT runtime)
138154
if (CLR_CMAKE_TARGET_ARCH_ARM64 OR CLR_CMAKE_TARGET_ARCH_AMD64)
139155
install_clr(TARGETS clrgcexp DESTINATIONS . sharedFramework COMPONENT runtime)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[contracts.jsonc]
2+
indent_size = 2
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# cDAC GC contract descriptor
2+
3+
# Up to four separate descriptors can be generated:
4+
# 1. gc_dll_wks_descriptor - WKS GC contract descriptor for the GC DLL
5+
# 2. gc_dll_svr_descriptor - SVR GC contract descriptor for the GC DLL (if FEATURE_SVR_GC is enabled)
6+
# 3. gcexp_dll_wks_descriptor - WKS GC contract descriptor for the GC EXP DLL (if BUILD_EXP_GC is enabled)
7+
# 4. gcexp_dll_svr_descriptor - SVR GC contract descriptor for the GC EXP DLL (if BUILD_EXP_GC and FEATURE_SVR_GC are enabled)
8+
9+
add_library(gc_dll_wks_descriptor_interface INTERFACE)
10+
target_include_directories(gc_dll_wks_descriptor_interface INTERFACE
11+
${CMAKE_CURRENT_SOURCE_DIR})
12+
add_dependencies(gc_dll_wks_descriptor_interface eventing_headers)
13+
generate_data_descriptors(
14+
LIBRARY_NAME gc_dll_wks_descriptor
15+
CONTRACT_NAME "GCContractDescriptorWKS"
16+
CONTRACT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/contracts.jsonc"
17+
INTERFACE_TARGET gc_dll_wks_descriptor_interface)
18+
19+
if (FEATURE_SVR_GC)
20+
add_library(gc_dll_svr_descriptor_interface INTERFACE)
21+
target_include_directories(gc_dll_svr_descriptor_interface INTERFACE
22+
${CMAKE_CURRENT_SOURCE_DIR})
23+
add_dependencies(gc_dll_svr_descriptor_interface eventing_headers)
24+
target_compile_definitions(gc_dll_svr_descriptor_interface INTERFACE -DSERVER_GC)
25+
generate_data_descriptors(
26+
LIBRARY_NAME gc_dll_svr_descriptor
27+
CONTRACT_NAME "GCContractDescriptorSVR"
28+
CONTRACT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/contracts.jsonc"
29+
INTERFACE_TARGET gc_dll_svr_descriptor_interface)
30+
endif()
31+
32+
if(BUILD_EXP_GC)
33+
add_library(gcexp_dll_wks_descriptor_interface INTERFACE)
34+
target_include_directories(gcexp_dll_wks_descriptor_interface INTERFACE
35+
${CMAKE_CURRENT_SOURCE_DIR})
36+
add_dependencies(gcexp_dll_wks_descriptor_interface eventing_headers)
37+
target_compile_definitions(gcexp_dll_wks_descriptor_interface INTERFACE -DUSE_REGIONS)
38+
generate_data_descriptors(
39+
LIBRARY_NAME gcexp_dll_wks_descriptor
40+
CONTRACT_NAME "GCContractDescriptorWKS"
41+
CONTRACT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/contracts.jsonc"
42+
INTERFACE_TARGET gcexp_dll_wks_descriptor_interface)
43+
44+
if (FEATURE_SVR_GC)
45+
add_library(gcexp_dll_svr_descriptor_interface INTERFACE)
46+
target_include_directories(gcexp_dll_svr_descriptor_interface INTERFACE
47+
${CMAKE_CURRENT_SOURCE_DIR})
48+
add_dependencies(gcexp_dll_svr_descriptor_interface eventing_headers)
49+
target_compile_definitions(gcexp_dll_svr_descriptor_interface INTERFACE -DUSE_REGIONS)
50+
target_compile_definitions(gcexp_dll_svr_descriptor_interface INTERFACE -DSERVER_GC)
51+
generate_data_descriptors(
52+
LIBRARY_NAME gcexp_dll_svr_descriptor
53+
CONTRACT_NAME "GCContractDescriptorSVR"
54+
CONTRACT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/contracts.jsonc"
55+
INTERFACE_TARGET gcexp_dll_svr_descriptor_interface)
56+
endif()
57+
endif()

0 commit comments

Comments
 (0)