diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs index a4e33db17c7fcf..37a84a10dd225b 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs @@ -104,4 +104,10 @@ public abstract class ContractRegistry public virtual IBuiltInCOM BuiltInCOM => GetContract(); public abstract TContract GetContract() where TContract : IContract; + + /// + /// Flush all cached data held by contracts in this registry. + /// Called when the target process state may have changed (e.g. on resume). + /// + public abstract void Flush(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IContract.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IContract.cs index 68b76a010d8653..27f72d3bccddfc 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IContract.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IContract.cs @@ -8,4 +8,10 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts; public interface IContract { static virtual string Name => throw new NotImplementedException(); + + /// + /// Clear any cached data held by this contract. + /// Called when the target process state may have changed (e.g. on resume). + /// + void Flush() { } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs index 850aab0f488320..d0d691f242c3a5 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Target.cs @@ -289,4 +289,14 @@ public readonly record struct FieldInfo /// A cache of the contracts for the target process /// public abstract ContractRegistry Contracts { get; } + + /// + /// Clear all cached data held by this target, including processed data and contract caches. + /// Called when the target process state may have changed (e.g. on resume). + /// + public void Flush() + { + ProcessedData.Clear(); + Contracts.Flush(); + } } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs index 2e00ce75b93f70..41af68d190c2de 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/EcmaMetadata_1.cs @@ -15,6 +15,11 @@ internal sealed class EcmaMetadata_1(Target target) : IEcmaMetadata { private Dictionary _metadata = new(); + public void Flush() + { + _metadata.Clear(); + } + public TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) { ILoader loader = target.Contracts.Loader; diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs index ad9d24248d3972..e7a980a7b0f639 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManagerCore.cs @@ -32,6 +32,11 @@ public ExecutionManagerCore(Target target, Data.RangeSectionMap topRangeSectionM _r2rJitManager = new ReadyToRunJitManager(_target); } + public void Flush() + { + _codeInfos.Clear(); + } + // Note, because of RelativeOffset, this code info is per code pointer, not per method private sealed class CodeBlock { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs index 76faf0d050c02a..236e017ac6b5c2 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_1.cs @@ -29,4 +29,5 @@ internal ExecutionManager_1(Target target, Data.RangeSectionMap topRangeSectionM public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle); public List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle); public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); + public void Flush() => _executionManagerCore.Flush(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs index 8e7f6bb5267510..ab5dea03e96066 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/ExecutionManager/ExecutionManager_2.cs @@ -29,4 +29,5 @@ internal ExecutionManager_2(Target target, Data.RangeSectionMap topRangeSectionM public TargetNUInt GetRelativeOffset(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetRelativeOffset(codeInfoHandle); public List GetExceptionClauses(CodeBlockHandle codeInfoHandle) => _executionManagerCore.GetExceptionClauses(codeInfoHandle); public JitManagerInfo GetEEJitManagerInfo() => _executionManagerCore.GetEEJitManagerInfo(); + public void Flush() => _executionManagerCore.Flush(); } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs index 160fa9c19024d7..6bdc4bc751d818 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs @@ -30,6 +30,14 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem private readonly Dictionary _typeHandles = new(); private readonly Dictionary _typeHandlesByName = new(); + public void Flush() + { + _methodTables.Clear(); + _methodDescs.Clear(); + _typeHandles.Clear(); + _typeHandlesByName.Clear(); + } + internal struct MethodTable { internal MethodTableFlags_1 Flags { get; } diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs index 4ca665fab31915..adfdbeca340134 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/Signature/SignatureDecoder_1.cs @@ -28,6 +28,12 @@ internal SignatureDecoder_1(Target target) _target = target; } + public void Flush() + { + _thProviders.Clear(); + _mdhProviders.Clear(); + } + private SignatureTypeProvider GetTypeHandleProvider(ModuleHandle moduleHandle) { if (_thProviders.TryGetValue(moduleHandle, out SignatureTypeProvider? thProvider)) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs index bb76867fd06a14..76d9aa1290ce2f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.IXCLRDataProcess.cs @@ -20,7 +20,7 @@ public sealed unsafe partial class SOSDacImpl : IXCLRDataProcess, IXCLRDataProce { int IXCLRDataProcess.Flush() { - _target.ProcessedData.Clear(); + _target.Flush(); // As long as any part of cDAC falls back to the legacy DAC, we need to propagate the Flush call if (_legacyProcess is not null) diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs index 7fa746bcc54d4f..41f2f5ec085aa0 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/SOSDacImpl.cs @@ -5785,7 +5785,15 @@ int ISOSDacInterface13.GetGCBookkeepingMemoryRegions(DacComNullableByRef ppEnum) => _legacyImpl13 is not null ? _legacyImpl13.GetGCFreeRegions(ppEnum) : HResults.E_NOTIMPL; int ISOSDacInterface13.LockedFlush() - => _legacyImpl13 is not null ? _legacyImpl13.LockedFlush() : HResults.E_NOTIMPL; + { + _target.Flush(); + + // As long as any part of cDAC falls back to the legacy DAC, we need to propagate the Flush call + if (_legacyImpl13 is not null) + return _legacyImpl13.LockedFlush(); + + return HResults.S_OK; + } #endregion ISOSDacInterface13 #region ISOSDacInterface14 diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs index 1a29993494081f..f2d0d1855ac306 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs @@ -76,4 +76,12 @@ public override TContract GetContract() // Contract was already registered by someone else return (TContract)_contracts[typeof(TContract)]; } + + public override void Flush() + { + foreach (IContract contract in _contracts.Values) + { + contract.Flush(); + } + } } diff --git a/src/native/managed/cdac/tests/TestPlaceholderTarget.cs b/src/native/managed/cdac/tests/TestPlaceholderTarget.cs index 3b7595e1ccc129..b8e7017885cbdd 100644 --- a/src/native/managed/cdac/tests/TestPlaceholderTarget.cs +++ b/src/native/managed/cdac/tests/TestPlaceholderTarget.cs @@ -450,6 +450,8 @@ public override TContract GetContract() throw new NotImplementedException($"Contract {typeof(TContract).Name} is not registered."); } + + public override void Flush() { } } }