From 0fb4c666804ae443b6866b5fde5f3c1159c9a417 Mon Sep 17 00:00:00 2001
From: Max Charlamb <44248479+max-charlamb@users.noreply.github.com>
Date: Fri, 24 Oct 2025 10:03:25 -0400
Subject: [PATCH] support dynamic contracts
---
.../ContractRegistry.cs | 4 +++-
.../IContractFactory.cs | 1 +
.../CachingContractRegistry.cs | 21 +++++++++++++++----
.../ContractDescriptorTarget.cs | 3 ++-
.../Legacy/SOSDacImpl.cs | 2 +-
5 files changed, 24 insertions(+), 7 deletions(-)
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 85f4f954404536..0516c0dac2c964 100644
--- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs
+++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/ContractRegistry.cs
@@ -89,5 +89,7 @@ public abstract class ContractRegistry
///
/// Gets an instance of the SignatureDecoder contract for the target.
///
- public abstract ISignatureDecoder SignatureDecoder { get; }
+ // public abstract ISignatureDecoder SignatureDecoder { get; }
+
+ public abstract TContract GetContract() where TContract : IContract;
}
diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/IContractFactory.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/IContractFactory.cs
index ca19d7ed3d05fb..2973c86784f554 100644
--- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/IContractFactory.cs
+++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/IContractFactory.cs
@@ -8,4 +8,5 @@ namespace Microsoft.Diagnostics.DataContractReader;
public interface IContractFactory where TContract : Contracts.IContract
{
TContract CreateContract(Target target, int version);
+ Type ContractType => typeof(TContract);
}
diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs
index 0afe774efde541..210e12c8c356b0 100644
--- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs
+++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/CachingContractRegistry.cs
@@ -20,7 +20,11 @@ internal sealed class CachingContractRegistry : ContractRegistry
private readonly Target _target;
private readonly TryGetContractVersionDelegate _tryGetContractVersion;
- public CachingContractRegistry(Target target, TryGetContractVersionDelegate tryGetContractVersion, Action>>? configureFactories = null)
+ public CachingContractRegistry(
+ Target target,
+ TryGetContractVersionDelegate tryGetContractVersion,
+ IEnumerable>? additionalFactories = null,
+ Action>>? configureFactories = null)
{
_target = target;
_tryGetContractVersion = tryGetContractVersion;
@@ -45,8 +49,17 @@ public CachingContractRegistry(Target target, TryGetContractVersionDelegate tryG
[typeof(ISHash)] = new SHashFactory(),
[typeof(IGC)] = new GCFactory(),
[typeof(INotifications)] = new NotificationsFactory(),
- [typeof(ISignatureDecoder)] = new SignatureDecoderFactory(),
+ // [typeof(ISignatureDecoder)] = new SignatureDecoderFactory(),
};
+
+ if (additionalFactories != null)
+ {
+ foreach (IContractFactory factory in additionalFactories)
+ {
+ _factories[factory.ContractType] = factory;
+ }
+ }
+
configureFactories?.Invoke(_factories);
}
@@ -69,9 +82,9 @@ public CachingContractRegistry(Target target, TryGetContractVersionDelegate tryG
public override ISHash SHash => GetContract();
public override IGC GC => GetContract();
public override INotifications Notifications => GetContract();
- public override ISignatureDecoder SignatureDecoder => GetContract();
+ // public override ISignatureDecoder SignatureDecoder => GetContract();
- private TContract GetContract() where TContract : IContract
+ public override TContract GetContract()
{
if (_contracts.TryGetValue(typeof(TContract), out IContract? contractMaybe))
return (TContract)contractMaybe;
diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs
index bec5c1cb7dc3f1..62255ee52a4ea5 100644
--- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs
+++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader/ContractDescriptorTarget.cs
@@ -8,6 +8,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Text;
+using Microsoft.Diagnostics.DataContractReader.Contracts;
using Microsoft.Diagnostics.DataContractReader.Data;
namespace Microsoft.Diagnostics.DataContractReader;
@@ -108,7 +109,7 @@ public static ContractDescriptorTarget Create(
private ContractDescriptorTarget(Descriptor[] descriptors, DataTargetDelegates dataTargetDelegates)
{
- Contracts = new CachingContractRegistry(this, this.TryGetContractVersion);
+ Contracts = new CachingContractRegistry(this, this.TryGetContractVersion, [new SignatureDecoderFactory()]);
ProcessedData = new DataCache(this);
_config = descriptors[0].Config;
_dataTargetDelegates = dataTargetDelegates;
diff --git a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs
index 9061601fd126c6..8b7ee7a40933f7 100644
--- a/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs
+++ b/src/native/managed/cdac/mscordaccore_universal/Legacy/SOSDacImpl.cs
@@ -765,7 +765,7 @@ int ISOSDacInterface.GetFieldDescData(ClrDataAddress fieldDesc, DacpFieldDescDat
IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem;
IEcmaMetadata ecmaMetadataContract = _target.Contracts.EcmaMetadata;
- ISignatureDecoder signatureDecoder = _target.Contracts.SignatureDecoder;
+ ISignatureDecoder signatureDecoder = _target.Contracts.GetContract();
TargetPointer fieldDescTargetPtr = fieldDesc.ToTargetPointer(_target);
CorElementType fieldDescType = rtsContract.GetFieldDescType(fieldDescTargetPtr);