[cDAC] Add EnC metadata and caching#129935
Conversation
There was a problem hiding this comment.
Pull request overview
This PR expands the cDAC EcmaMetadata contract to support Edit-and-Continue (EnC) and read-write (RW) metadata scenarios by adding new VM data descriptors, walking RW metadata structures (MDInternalRW → CLiteWeightStgdbRW → CMiniMdRW), and caching metadata readers based on generation/edit counters.
Changes:
- Add new CoreCLR data descriptors and managed contract data models for RW metadata structures and EnC module state.
- Implement RW metadata reconstruction/serialization into a contiguous ECMA-335 metadata image, including heap/table coalescing.
- Adjust caching/flush behavior and update design documentation to reflect the new metadata sources and invalidation signals.
Show a summary per file
| File | Description |
|---|---|
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/EcmaMetadataUtils.cs | Adds helper to read metadata version string from a metadata root. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/DataType.cs | Adds new public DataType enum entries for RW metadata and EnC module types. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/StgPoolSeg.cs | New contract data model for StgPoolSeg. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/StgPool.cs | New contract data model for StgPool. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/PEAssembly.cs | Extends PEAssembly contract data to expose RW importer state/pointer. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/Module.cs | Adds MetadataGeneration for dynamic module saved-metadata invalidation. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/MDInternalRW.cs | New contract data model for MDInternalRW (RW metadata entrypoint). |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/EditAndContinueModule.cs | New contract data model for EnC edit counter (ApplyChangesCount). |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CMiniMdSchema.cs | New contract data model for CMiniMd schema fields (heaps/sorted/row counts). |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CMiniMdRW.cs | New contract data model for CMiniMdRW fields plus computed table segment addresses. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Data/CLiteWeightStgdbRW.cs | New contract data model for RW stgdb pointers and metadata image address. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs | Implements RW metadata reading/serialization and generation-based caching. |
| src/coreclr/vm/peassembly.h | Exposes MDImport RW flag and MDImport pointer offsets to cDAC. |
| src/coreclr/vm/encee.h | Adds cDAC data exposure for EditAndContinueModule::m_applyChangesCount. |
| src/coreclr/vm/datadescriptor/datadescriptor.inc | Registers new cDAC types/fields for RW metadata and EnC module. |
| src/coreclr/vm/datadescriptor/datadescriptor.h | Adds metadata header includes needed for RW metadata descriptors. |
| src/coreclr/vm/datadescriptor/CMakeLists.txt | Adds compile definition enabling internal metadata API exposure for descriptor build. |
| src/coreclr/vm/ceeload.h | Adds Module::m_dwMetadataGeneration and exposes it via cDAC. |
| src/coreclr/vm/ceeload.cpp | Initializes/increments dynamic metadata generation counter. |
| src/coreclr/md/inc/stgpool.h | Adds cdac_data mappings for StgPool/StgPoolSeg fields. |
| src/coreclr/md/inc/metamodelrw.h | Adds m_fAll4ByteColumns and exposes RW heap/table offsets for cDAC. |
| src/coreclr/md/inc/metamodel.h | Adds cdac_data mapping for CMiniMdBase schema/tablecount fields. |
| src/coreclr/md/inc/liteweightstgdb.h | Adds cdac_data mapping for RW stgdb miniMd and metadata address. |
| src/coreclr/md/enc/metamodelrw.cpp | Initializes/sets m_fAll4ByteColumns under growth/expansion paths. |
| src/coreclr/md/enc/liteweightstgdbrw.cpp | Marks minimal-delta load as “all 4-byte columns” for RW model. |
| docs/design/datacontracts/EcmaMetadata.md | Updates the contract documentation and descriptor listing for RW metadata support. |
Copilot's findings
Comments suppressed due to low confidence (1)
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs:381
GetReadWriteSavedMetadataAddressusesProcessedData.GetOrAddforModuleandDynamicMetadata. Those structures can change when a dynamic module re-serializes its metadata; ifGetMetadatais called again without an interveningTarget.Flush, the cached descriptors can cause the updated metadata generation to be detected but the old address/size to still be used. Consider reading these descriptor types uncached for this mutable path.
private TargetSpan GetReadWriteSavedMetadataAddress(ModuleHandle handle)
{
Data.Module module = target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Data.DynamicMetadata dynamicMetadata = target.ProcessedData.GetOrAdd<Data.DynamicMetadata>(module.DynamicMetadata);
return new TargetSpan(dynamicMetadata.Data, dynamicMetadata.Size);
- Files reviewed: 26/26 changed files
- Comments generated: 8
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Copilot's findings
Comments suppressed due to low confidence (1)
src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs:380
- GetReadWriteSavedMetadataAddress uses ProcessedData.GetOrAdd for Module/DynamicMetadata. Dynamic modules can re-serialize and replace the DynamicMetadata buffer while the debuggee is paused (no Target.Flush), so cached IData snapshots can become stale even though GetMetadataGeneration detects a new generation. Use uncached IData reads here so the updated DynamicMetadata pointer/size is observed.
Data.Module module = target.ProcessedData.GetOrAdd<Data.Module>(handle.Address);
Data.DynamicMetadata dynamicMetadata = target.ProcessedData.GetOrAdd<Data.DynamicMetadata>(module.DynamicMetadata);
- Files reviewed: 26/26 changed files
- Comments generated: 6
|
|
||
| private: | ||
| BOOL m_fMinimalDelta; | ||
| BOOL m_fAll4ByteColumns; |
There was a problem hiding this comment.
Do we need this new field? It seems that All4ByteColumns = (m_eGrow == eg_grown || m_fMinimalDelta == TRUE)
There was a problem hiding this comment.
No, we do not, but I think this is a cleaner approach to have this dedicated field for diagnostic purposes.
There was a problem hiding this comment.
Instead of creating a new field that stores redundant information, maybe we can make a runtime helper that computes this from the two fields and do the same on the cDAC. That way we don't have any risk of the two sources being out of sync.
There was a problem hiding this comment.
I think it would be a greater risk of being out of sync if we, say, add a third source of truth and have to update the algorithm in the cDAC, as opposed to adding the third source of truth and there being a clearly named field that we know to update in the runtime source.
There was a problem hiding this comment.
If we want to go with this, we also need to update the field offsets as required by the instructions in VerifyLayouts.h. This is a breaking change and would require updating the m_mdDataStructureVersion and verification.
There was a problem hiding this comment.
The versioning scheme can be deleted in a follow-up.
|
|
||
| private: | ||
| BOOL m_fMinimalDelta; | ||
| BOOL m_fAll4ByteColumns; |
There was a problem hiding this comment.
If we want to go with this, we also need to update the field offsets as required by the instructions in VerifyLayouts.h. This is a breaking change and would require updating the m_mdDataStructureVersion and verification.
Fixes #129557