From 074c95323cc0b8d0dac0096edd03d2d829b4d78e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 16 May 2026 17:24:01 +0000 Subject: [PATCH 1/2] Implement DacDbi GetCollectibleTypeStaticAddress in cDAC Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com> --- .../design/datacontracts/RuntimeTypeSystem.md | 12 ++++++--- .../Contracts/IRuntimeTypeSystem.cs | 4 +-- .../Contracts/RuntimeTypeSystem_1.cs | 8 +++--- .../Dbi/DacDbiImpl.cs | 27 ++++++++++++++++++- 4 files changed, 40 insertions(+), 11 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 3f8e67281caa8a..f778518b10e818 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -267,8 +267,8 @@ bool IsFieldDescThreadStatic(TargetPointer fieldDescPointer); bool IsFieldDescStatic(TargetPointer fieldDescPointer); uint GetFieldDescType(TargetPointer fieldDescPointer); uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef); -TargetPointer GetFieldDescStaticAddress(TargetPointer fieldDescPointer); -TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread); +TargetPointer GetFieldDescStaticAddress(TargetPointer fieldDescPointer, bool unboxValueTypes = true); +TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread, bool unboxValueTypes = true); ``` ### Other APIs @@ -2046,17 +2046,21 @@ uint GetFieldDescOffset(TargetPointer fieldDescPointer) return DWord2 & (uint)FieldDescFlags2.OffsetMask; } -TargetPointer GetFieldDescStaticAddress(TargetPointer fieldDescPointer) +TargetPointer GetFieldDescStaticAddress(TargetPointer fieldDescPointer, bool unboxValueTypes = true) { // Resolves the base pointer (GC or non-GC statics) for the enclosing type, // then applies the field's metadata-based offset within that region. // Uses GetGCStaticsBasePointer / GetNonGCStaticsBasePointer depending on the field's CorElementType. + // When unboxValueTypes is true (default), value-type statics are dereferenced to the unboxed + // payload inside the boxed object. Pass false to obtain the address of the boxed reference itself + // (required for collectible-type static field addresses). } -TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread) +TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread, bool unboxValueTypes = true) { // Like GetFieldDescStaticAddress, but resolves thread-local base pointers instead. // Uses GetGCThreadStaticsBasePointer / GetNonGCThreadStaticsBasePointer. + // The unboxValueTypes parameter behaves the same as in GetFieldDescStaticAddress. } ``` diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs index 3c93c621120c41..680a1212214201 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs @@ -266,8 +266,8 @@ public interface IRuntimeTypeSystem : IContract CorElementType GetFieldDescType(TargetPointer fieldDescPointer) => throw new NotImplementedException(); uint GetFieldDescOffset(TargetPointer fieldDescPointer, FieldDefinition fieldDef) => throw new NotImplementedException(); TargetPointer GetFieldDescByName(TypeHandle typeHandle, string fieldName) => throw new NotImplementedException(); - TargetPointer GetFieldDescStaticAddress(TargetPointer fieldDescPointer) => throw new NotImplementedException(); - TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread) => throw new NotImplementedException(); + TargetPointer GetFieldDescStaticAddress(TargetPointer fieldDescPointer, bool unboxValueTypes = true) => throw new NotImplementedException(); + TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread, bool unboxValueTypes = true) => throw new NotImplementedException(); #endregion FieldDesc inspection APIs #region Other APIs void GetCoreLibFieldDescAndDef(string typeNamespace, string typeName, string fieldName, out TargetPointer fieldDescAddr, out FieldDefinition fieldDef) => throw new NotImplementedException(); 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 4ff9fa28275f2f..cce898033288ce 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 @@ -2084,7 +2084,7 @@ private TargetPointer GetStaticAddressHandle(TargetPointer @base, uint offset, b return new TargetPointer(@base + offset); } - private TargetPointer GetFieldDescStaticOrThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer? thread = null) + private TargetPointer GetFieldDescStaticOrThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer? thread = null, bool unboxValueTypes = true) { TargetPointer enclosingMT = ((IRuntimeTypeSystem)this).GetMTOfEnclosingClass(fieldDescPointer); TypeHandle ctx = GetTypeHandle(enclosingMT); @@ -2127,7 +2127,7 @@ private TargetPointer GetFieldDescStaticOrThreadStaticAddress(TargetPointer fiel uint offset = ((IRuntimeTypeSystem)this).GetFieldDescOffset(fieldDescPointer, fieldDef); bool isRVA = IsFieldDescRVA(fieldDescPointer); TargetPointer handleAddr = GetStaticAddressHandle(@base, offset, isRVA, fieldDescPointer, moduleHandle); - if (type == CorElementType.ValueType && !isRVA) + if (unboxValueTypes && type == CorElementType.ValueType && !isRVA) { TargetPointer objRef = _target.ReadPointer(handleAddr); Data.Object obj = _target.ProcessedData.GetOrAdd(objRef); @@ -2136,9 +2136,9 @@ private TargetPointer GetFieldDescStaticOrThreadStaticAddress(TargetPointer fiel return handleAddr; } - TargetPointer IRuntimeTypeSystem.GetFieldDescStaticAddress(TargetPointer fieldDescPointer) => GetFieldDescStaticOrThreadStaticAddress(fieldDescPointer); + TargetPointer IRuntimeTypeSystem.GetFieldDescStaticAddress(TargetPointer fieldDescPointer, bool unboxValueTypes) => GetFieldDescStaticOrThreadStaticAddress(fieldDescPointer, unboxValueTypes: unboxValueTypes); - TargetPointer IRuntimeTypeSystem.GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread) => GetFieldDescStaticOrThreadStaticAddress(fieldDescPointer, thread); + TargetPointer IRuntimeTypeSystem.GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread, bool unboxValueTypes) => GetFieldDescStaticOrThreadStaticAddress(fieldDescPointer, thread, unboxValueTypes); void IRuntimeTypeSystem.GetCoreLibFieldDescAndDef(string @namespace, string typeName, string fieldName, out TargetPointer fieldDescAddr, out FieldDefinition fieldDef) { diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index 0b9bfe91dd9785..19056136cef39f 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -1513,7 +1513,32 @@ public int GetThreadStaticAddress(ulong vmField, ulong vmRuntimeThread, ulong* p } public int GetCollectibleTypeStaticAddress(ulong vmField, ulong* pRetVal) - => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetCollectibleTypeStaticAddress(vmField, pRetVal) : HResults.E_NOTIMPL; + { + *pRetVal = 0; + int hr = HResults.S_OK; + try + { + Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; + TargetPointer fd = new TargetPointer(vmField); + Debug.Assert(rts.IsFieldDescStatic(fd) && !rts.IsFieldDescThreadStatic(fd), "BUG: Unsupported static field type for collectible types"); + *pRetVal = rts.GetFieldDescStaticAddress(fd, unboxValueTypes: false).Value; + } + catch (System.Exception ex) + { + hr = ex.HResult; + } +#if DEBUG + if (_legacy is not null) + { + ulong retValLocal; + int hrLocal = _legacy.GetCollectibleTypeStaticAddress(vmField, &retValLocal); + Debug.ValidateHResult(hr, hrLocal); + if (hr == HResults.S_OK) + Debug.Assert(*pRetVal == retValLocal, $"cDAC: {*pRetVal}, DAC: {retValLocal}"); + } +#endif + return hr; + } public int GetEnCHangingFieldInfo(nint pEnCFieldInfo, nint pFieldData, Interop.BOOL* pfStatic) => LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetEnCHangingFieldInfo(pEnCFieldInfo, pFieldData, pfStatic) : HResults.E_NOTIMPL; From c66277fc928aeb549001eda39c5733bbeb20ad6a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 16 May 2026 17:34:06 +0000 Subject: [PATCH 2/2] Address feedback: remove named-arg colon, debug assert, and comment Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com> --- docs/design/datacontracts/RuntimeTypeSystem.md | 3 +-- .../Contracts/RuntimeTypeSystem_1.cs | 2 +- .../Dbi/DacDbiImpl.cs | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index f778518b10e818..ee63c8dc890569 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -2052,8 +2052,7 @@ TargetPointer GetFieldDescStaticAddress(TargetPointer fieldDescPointer, bool unb // then applies the field's metadata-based offset within that region. // Uses GetGCStaticsBasePointer / GetNonGCStaticsBasePointer depending on the field's CorElementType. // When unboxValueTypes is true (default), value-type statics are dereferenced to the unboxed - // payload inside the boxed object. Pass false to obtain the address of the boxed reference itself - // (required for collectible-type static field addresses). + // payload inside the boxed object. Pass false to obtain the address of the boxed reference itself. } TargetPointer GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread, bool unboxValueTypes = true) 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 cce898033288ce..49dc6ac0bd2f38 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 @@ -2136,7 +2136,7 @@ private TargetPointer GetFieldDescStaticOrThreadStaticAddress(TargetPointer fiel return handleAddr; } - TargetPointer IRuntimeTypeSystem.GetFieldDescStaticAddress(TargetPointer fieldDescPointer, bool unboxValueTypes) => GetFieldDescStaticOrThreadStaticAddress(fieldDescPointer, unboxValueTypes: unboxValueTypes); + TargetPointer IRuntimeTypeSystem.GetFieldDescStaticAddress(TargetPointer fieldDescPointer, bool unboxValueTypes) => GetFieldDescStaticOrThreadStaticAddress(fieldDescPointer, null, unboxValueTypes); TargetPointer IRuntimeTypeSystem.GetFieldDescThreadStaticAddress(TargetPointer fieldDescPointer, TargetPointer thread, bool unboxValueTypes) => GetFieldDescStaticOrThreadStaticAddress(fieldDescPointer, thread, unboxValueTypes); diff --git a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs index 19056136cef39f..a1bf31b143b34c 100644 --- a/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs +++ b/src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs @@ -1520,7 +1520,6 @@ public int GetCollectibleTypeStaticAddress(ulong vmField, ulong* pRetVal) { Contracts.IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; TargetPointer fd = new TargetPointer(vmField); - Debug.Assert(rts.IsFieldDescStatic(fd) && !rts.IsFieldDescThreadStatic(fd), "BUG: Unsupported static field type for collectible types"); *pRetVal = rts.GetFieldDescStaticAddress(fd, unboxValueTypes: false).Value; } catch (System.Exception ex)