Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,9 @@ public abstract void Register<TContract>(string version, Func<Target, TContract>
where TContract : IContract;

/// <summary>
/// Flush all cached data held by contracts in this registry.
/// Called when the target process state may have changed (e.g. on resume).
/// Flush all cached data held by contracts in this registry for the given
/// <paramref name="scope"/>. Called when the target process state may have changed
/// (e.g. on resume) or as part of a stress-harness re-read of live target state.
/// </summary>
public abstract void Flush();
public abstract void Flush(FlushScope scope);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ public interface IContract
static virtual string Name => throw new NotImplementedException();

/// <summary>
/// Clear any cached data held by this contract.
/// Called when the target process state may have changed (e.g. on resume).
/// Clear cached data held by this contract for the given <paramref name="scope"/>.
/// Called when the target process state may have changed (e.g. on resume) or as
/// part of a stress-harness re-read of live target state.
/// <para>
/// Default implementation is a no-op. Contracts that maintain caches or capture
/// target-memory snapshots at construction must override this method and handle
/// each <see cref="FlushScope"/> value appropriately.
/// </para>
/// </summary>
void Flush() { }
void Flush(FlushScope scope) { }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.Diagnostics.DataContractReader;

/// <summary>
/// Scope of a <see cref="Target.Flush(FlushScope)"/> operation.
/// </summary>
public enum FlushScope
{
/// <summary>
/// Clear every cache held by the target, including immutable metadata caches
/// (type layouts, contract instances, ECMA metadata, execution-manager ranges).
Comment thread
max-charlamb marked this conversation as resolved.
/// This is the safe default and matches the historical no-argument Flush behavior.
/// </summary>
All,

/// <summary>
/// Flush only caches that may have become stale because the target process
/// has executed forward in time since the last flush (e.g. a debugger
/// resume/continue/step). Caches of immutable state that the runtime loads
/// once and never unloads (modules, types, code metadata, ECMA metadata,
/// execution-manager ranges, etc.) may be retained.
Comment thread
max-charlamb marked this conversation as resolved.
/// <para>
/// This corresponds to ICorDebug's <c>CorDebugStateChange.PROCESS_RUNNING</c>:
/// see <see href="https://learn.microsoft.com/dotnet/core/unmanaged-api/debugging/icordebug/cordebugstatechange-enumeration"/>.
/// Use <see cref="All"/> instead for arbitrary state snapshots where no
/// continuity with the previous target state can be assumed.
/// </para>
/// <para>
/// Each contract is responsible for its own correctness under this scope: a
/// contract that captures a target-memory snapshot at construction MUST
/// re-read that snapshot in its
/// <see cref="Contracts.IContract.Flush(FlushScope)"/> implementation when
/// called with <see cref="ForwardExecution"/>, otherwise the snapshot
/// becomes stale across the flush.
/// </para>
/// </summary>
ForwardExecution,
}
Comment thread
max-charlamb marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,12 @@ public readonly record struct FieldInfo
public abstract ContractRegistry Contracts { get; }

/// <summary>
/// Clear all cached data held by this target, including processed data and contract caches.
/// Clear cached data held by this target for the given <paramref name="scope"/>.
/// Called when the target process state may have changed (e.g. on resume).
/// </summary>
public virtual void Flush()
public virtual void Flush(FlushScope scope)
{
ProcessedData.Clear();
Contracts.Flush();
Contracts.Flush(scope);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ internal sealed class EcmaMetadata_1(Target target) : IEcmaMetadata
private readonly Dictionary<ModuleHandle, MetadataReaderProvider?> _metadata = [];
private readonly Dictionary<ModuleHandle, TargetSpan> _readOnlyMetadataAddress = [];

public void Flush()
public void Flush(FlushScope scope)
{
_metadata.Clear();
_readOnlyMetadataAddress.Clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,27 @@ internal sealed partial class ExecutionManagerCore<T> : IExecutionManager

// maps CodeBlockHandle.Address (which is the CodeHeaderAddress) to the CodeBlock
private readonly Dictionary<TargetPointer, CodeBlock> _codeInfos = new();
private readonly Data.RangeSectionMap _topRangeSectionMap;
private readonly TargetPointer _topRangeSectionMapAddress;
private readonly ExecutionManagerHelpers.RangeSectionMap _rangeSectionMapLookup;
private readonly EEJitManager _eeJitManager;
private readonly ReadyToRunJitManager _r2rJitManager;
private readonly InterpreterJitManager _interpreterJitManager;

public ExecutionManagerCore(Target target, Data.RangeSectionMap topRangeSectionMap)
private Data.RangeSectionMap _topRangeSectionMap
=> _target.ProcessedData.GetOrAdd<Data.RangeSectionMap>(_topRangeSectionMapAddress);

public ExecutionManagerCore(Target target, TargetPointer topRangeSectionMapAddress)
{
_target = target;
_topRangeSectionMap = topRangeSectionMap;
_topRangeSectionMapAddress = topRangeSectionMapAddress;
_rangeSectionMapLookup = ExecutionManagerHelpers.RangeSectionMap.Create(_target);
INibbleMap nibbleMap = T.Create(_target);
_eeJitManager = new EEJitManager(_target, nibbleMap);
_r2rJitManager = new ReadyToRunJitManager(_target);
_interpreterJitManager = new InterpreterJitManager(_target, nibbleMap);
}

public void Flush()
public void Flush(FlushScope scope)
{
_codeInfos.Clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ public sealed class ExecutionManager_1 : IExecutionManager
internal ExecutionManager_1(Target target)
{
TargetPointer addr = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress);
Data.RangeSectionMap map = target.ProcessedData.GetOrAdd<Data.RangeSectionMap>(addr);
_executionManagerCore = new ExecutionManagerCore<NibbleMapLinearLookup>(target, map);
_executionManagerCore = new ExecutionManagerCore<NibbleMapLinearLookup>(target, addr);
}

public CodeBlockHandle? GetCodeBlockHandle(TargetCodePointer ip) => _executionManagerCore.GetCodeBlockHandle(ip);
Expand All @@ -36,5 +35,5 @@ internal ExecutionManager_1(Target target)
public IEnumerable<ICodeHeapInfo> GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos();
public CodeKind GetCodeKind(TargetCodePointer codeAddress) => _executionManagerCore.GetCodeKind(codeAddress);
public TargetPointer FindReadyToRunModule(TargetPointer address) => _executionManagerCore.FindReadyToRunModule(address);
public void Flush() => _executionManagerCore.Flush();
public void Flush(FlushScope scope) => _executionManagerCore.Flush(scope);
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ public sealed class ExecutionManager_2 : IExecutionManager
internal ExecutionManager_2(Target target)
{
TargetPointer addr = target.ReadGlobalPointer(Constants.Globals.ExecutionManagerCodeRangeMapAddress);
Data.RangeSectionMap map = target.ProcessedData.GetOrAdd<Data.RangeSectionMap>(addr);
_executionManagerCore = new ExecutionManagerCore<NibbleMapConstantLookup>(target, map);
_executionManagerCore = new ExecutionManagerCore<NibbleMapConstantLookup>(target, addr);
}

public CodeBlockHandle? GetCodeBlockHandle(TargetCodePointer ip) => _executionManagerCore.GetCodeBlockHandle(ip);
Expand All @@ -36,5 +35,5 @@ internal ExecutionManager_2(Target target)
public IEnumerable<ICodeHeapInfo> GetCodeHeapInfos() => _executionManagerCore.GetCodeHeapInfos();
public CodeKind GetCodeKind(TargetCodePointer codeAddress) => _executionManagerCore.GetCodeKind(codeAddress);
public TargetPointer FindReadyToRunModule(TargetPointer address) => _executionManagerCore.FindReadyToRunModule(address);
public void Flush() => _executionManagerCore.Flush();
public void Flush(FlushScope scope) => _executionManagerCore.Flush(scope);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,15 @@ public ManagedTypeSource_1(Target target)
_target = target;
}

public void Flush()
public void Flush(FlushScope scope)
{
// They are safe to retain across FlushScope.ForwardExecution because
// ManagedTypeSource_1 only resolves names in System.Private.CoreLib, which
// is loaded into the non-collectible default AssemblyLoadContext at runtime
// startup and whose ECMA metadata never changes for the process lifetime.
if (scope != FlushScope.All)
return;
Comment thread
max-charlamb marked this conversation as resolved.

_typeInfoCache.Clear();
_typeHandleCache.Clear();
_fieldDescCache.Clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal readonly partial struct PlatformMetadata_1 : IPlatformMetadata
internal readonly struct PlatformMetadata_1 : IPlatformMetadata
{
internal readonly Target _target;
private readonly Data.PlatformMetadata _cdacMetadata;
private readonly TargetPointer _cdacMetadataAddress;
private Data.PlatformMetadata _cdacMetadata
=> _target.ProcessedData.GetOrAdd<Data.PlatformMetadata>(_cdacMetadataAddress);

public PlatformMetadata_1(Target target)
{
_target = target;
TargetPointer cdacMetadataAddress = target.ReadGlobalPointer(Constants.Globals.PlatformMetadata);
_cdacMetadata = target.ProcessedData.GetOrAdd<Data.PlatformMetadata>(cdacMetadataAddress);
_cdacMetadataAddress = target.ReadGlobalPointer(Constants.Globals.PlatformMetadata);
}

TargetPointer IPlatformMetadata.GetPrecodeMachineDescriptor()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal readonly partial struct ReJIT_1 : IReJIT
internal readonly struct ReJIT_1 : IReJIT
{
internal readonly Target _target;
private readonly Data.ProfControlBlock _profControlBlock;
private readonly TargetPointer _profControlBlockAddress;
private Data.ProfControlBlock _profControlBlock
=> _target.ProcessedData.GetOrAdd<Data.ProfControlBlock>(_profControlBlockAddress);

// see src/coreclr/inc/corprof.idl
[Flags]
Expand All @@ -33,8 +35,7 @@ public enum RejitFlags : uint
public ReJIT_1(Target target)
{
_target = target;
TargetPointer profControlBlockAddress = target.ReadGlobalPointer(Constants.Globals.ProfilerControlBlock);
_profControlBlock = target.ProcessedData.GetOrAdd<Data.ProfControlBlock>(profControlBlockAddress);
_profControlBlockAddress = target.ReadGlobalPointer(Constants.Globals.ProfilerControlBlock);
}

bool IReJIT.IsEnabled()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ internal partial struct RuntimeTypeSystem_1 : IRuntimeTypeSystem
private readonly Dictionary<TargetPointer, MethodDesc> _methodDescs = new();
private readonly Dictionary<TypeKey, TypeHandle> _typeHandles = new();

public void Flush()
public void Flush(FlushScope scope)
{
_methodTables.Clear();
_methodDescs.Clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal Signature_1(Target target)
_target = target;
}

public void Flush()
public void Flush(FlushScope scope)
{
_thProviders.Clear();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public int CheckDbiVersion(DbiVersion* pVersion)

public int FlushCache()
{
_target.Flush();
_target.Flush(FlushScope.All);
return _legacy is not null ? _legacy.FlushCache() : HResults.S_OK;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public sealed unsafe partial class SOSDacImpl : IXCLRDataProcess, IXCLRDataProce
{
int IXCLRDataProcess.Flush()
{
_target.Flush();
_target.Flush(FlushScope.All);

// Flush is always propagated — it's cache management, not data retrieval.
if (_legacyProcess is not null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6712,7 +6712,7 @@ int ISOSDacInterface13.GetGCFreeRegions(DacComNullableByRef<ISOSMemoryEnum> ppEn
}
int ISOSDacInterface13.LockedFlush()
{
_target.Flush();
_target.Flush(FlushScope.All);

// 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ public override bool TryGetContract<TContract>([NotNullWhen(true)] out TContract
return true;
}

public override void Flush()
public override void Flush(FlushScope scope)
{
foreach (IContract contract in _contracts.Values)
{
contract.Flush();
Comment thread
max-charlamb marked this conversation as resolved.
contract.Flush(scope);
Comment thread
max-charlamb marked this conversation as resolved.
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,9 @@ private ContractDescriptorTarget(Descriptor mainDescriptor, DataTargetDelegates
BuildDescriptors(forceBuild: true);
}

public override void Flush()
public override void Flush(FlushScope scope)
{
base.Flush();
base.Flush(scope);

BuildDescriptors();
}
Expand Down
2 changes: 1 addition & 1 deletion src/native/managed/cdac/tests/DataGenerator/TestTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ public override bool TryGetContract<TContract>([NotNullWhen(true)] out TContract
public override void Register<TContract>(string version, Func<Target, TContract> creator)
=> throw new NotImplementedException();

public override void Flush() { }
public override void Flush(FlushScope scope) { }
}

// --- Trivial IDataCache for ReadDataField support ----------------
Expand Down
2 changes: 1 addition & 1 deletion src/native/managed/cdac/tests/TestPlaceholderTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -625,7 +625,7 @@ public override bool TryGetContract<TContract>([NotNullWhen(true)] out TContract
return true;
}

public override void Flush() { }
public override void Flush(FlushScope scope) { }
}

}