diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 3f8e67281caa8a..ee63c8dc890569 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,20 @@ 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. } -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..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 @@ -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, null, 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..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 @@ -1513,7 +1513,31 @@ 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); + *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;