Add GetApproxTypeHandle dump tests#128921
Conversation
Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com>
Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com>
|
Tagging subscribers to this area: @steveisok, @tommcdon, @dotnet/dotnet-diag |
…y+metadataToken Co-authored-by: rcj1 <77995559+rcj1@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR adds dump-based coverage for DacDbiImpl.GetApproxTypeHandle by mirroring the existing exact-type-handle dump tests: it enumerates heap objects reachable from GC handles in the ExactTypeHandle debuggee, constructs the flattened DebuggerIPCE_TypeArgData[] tree (a managed port of CordbType::GatherTypeData), round-trips that through GetApproxTypeHandle, and asserts the returned vmTypeHandle matches an independently canonicalized expected MethodTable. To support this, it also adds a managed TypeDataWalk implementation and refactors some type lookup logic into a helper.
Changes:
- Add a new dump test suite
DacDbiApproxTypeHandleDumpTestsimplementing the right-side “gather type data” flattening and expected-handle canonicalization. - Implement managed
GetApproxTypeHandlesupport via a newTypeDataWalkport and supporting helper types. - Replace
IsObjRef(TypeHandle)usage with a newIsCorElementTypeObjRef(CorElementType)helper across tests, the contract, and documentation.
Show a summary per file
| File | Description |
|---|---|
| src/native/managed/cdac/tests/MethodTableTests.cs | Updates objref classification assertions to use IsCorElementTypeObjRef(GetInternalCorElementType(...)). |
| src/native/managed/cdac/tests/DumpTests/RuntimeTypeSystemDumpTests.cs | Updates dump-based RTS “objref consistency” test to use the new helper. |
| src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiObjectDumpTests.cs | Updates reference-type offset logic to use the new helper. |
| src/native/managed/cdac/tests/DumpTests/DacDbi/DacDbiApproxTypeHandleDumpTests.cs | New dump test covering round-trip behavior for GetApproxTypeHandle across reachable handle objects. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/TypeDataWalk.cs | New managed port of the native flattened-type-data walker used by GetApproxTypeHandle. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/IDacDbiInterface.cs | Adds DebuggerIPCE_TypeArgData / TypeInfoList and tightens GetApproxTypeHandle signature to a typed pointer. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DbiHelpers.cs | New helper for resolving typeDef/typeRef MethodTables from an assembly+token via loader lookup tables. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Legacy/Dbi/DacDbiImpl.cs | Implements managed GetApproxTypeHandle and switches some ref-type checks to IsCorElementTypeObjRef. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Contracts/Contracts/RuntimeTypeSystem_1.cs | Replaces IsObjRef with IsCorElementTypeObjRef implementation used by the contract. |
| src/native/managed/cdac/Microsoft.Diagnostics.DataContractReader.Abstractions/Contracts/IRuntimeTypeSystem.cs | Changes the contract surface by removing IsObjRef(TypeHandle) and adding IsCorElementTypeObjRef(CorElementType). |
| docs/design/datacontracts/RuntimeTypeSystem.md | Updates contract documentation to match the new helper. |
Copilot's findings
- Files reviewed: 11/11 changed files
- Comments generated: 5
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| [StructLayout(LayoutKind.Sequential, Size = 48)] | ||
| public struct DebuggerIPCE_TypeArgData | ||
| { | ||
| public DebuggerIPCE_ExpandedTypeData data; | ||
| public uint numTypeArgs; // Portable<UINT> |
| [StructLayout(LayoutKind.Sequential)] | ||
| public unsafe struct TypeInfoList | ||
| { | ||
| public DebuggerIPCE_TypeArgData* m_pList; | ||
| public int m_nEntries; |
| Assert.True(rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(objectHandle))); | ||
| Assert.True(rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(stringHandle))); | ||
| Assert.True(rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(objectArrayHandle))); | ||
| Assert.False(rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(intPtrHandle))); |
| Assert.True(contract.IsCorElementTypeObjRef(contract.GetInternalCorElementType(contract.GetTypeHandle(objectTypePtr)))); | ||
| Assert.True(contract.IsCorElementTypeObjRef(contract.GetInternalCorElementType(contract.GetTypeHandle(stringTypePtr)))); | ||
| Assert.True(contract.IsCorElementTypeObjRef(contract.GetInternalCorElementType(contract.GetTypeHandle(szArrayTypePtr)))); | ||
| Assert.False(contract.IsCorElementTypeObjRef(contract.GetInternalCorElementType(contract.GetTypeHandle(truePrimitiveTypePtr)))); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| case CorElementType.Array: | ||
| case CorElementType.SzArray: | ||
| case CorElementType.Ptr: | ||
| case CorElementType.Byref: | ||
| pSelf->numTypeArgs = 1; | ||
| FillTypeNodes(dbi, rts, rts.GetTypeParam(th), nodes, ref idx); | ||
| break; | ||
|
|
||
| case CorElementType.Class: | ||
| case CorElementType.ValueType: | ||
| { | ||
| ReadOnlySpan<TypeHandle> inst = rts.GetInstantiation(th); | ||
| pSelf->numTypeArgs = (uint)inst.Length; | ||
| for (int i = 0; i < inst.Length; i++) | ||
| FillTypeNodes(dbi, rts, inst[i], nodes, ref idx); | ||
| break; | ||
| } |
| bool IsObject(TypeHandle typeHandle) => throw new NotImplementedException(); | ||
| bool IsString(TypeHandle typeHandle) => throw new NotImplementedException(); | ||
| bool IsObjRef(TypeHandle typeHandle) => throw new NotImplementedException(); | ||
| // True if the CorElementType represents a GC-collectable object reference. | ||
| bool IsCorElementTypeObjRef(CorElementType elementType) => throw new NotImplementedException(); | ||
| // True if the MethodTable represents a type that contains managed references |
| Assert.True(rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(objectHandle))); | ||
| Assert.True(rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(stringHandle))); | ||
| Assert.True(rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(objectArrayHandle))); | ||
| Assert.False(rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(intPtrHandle))); |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
| // True if the CorElementType represents a GC-collectable object reference. | ||
| bool IsCorElementTypeObjRef(CorElementType elementType) => throw new NotImplementedException(); | ||
| // True if the MethodTable represents a type that contains managed references |
| CorElementType et = GetElementType(rts, th); | ||
| switch (et) | ||
| { | ||
| case CorElementType.Array: | ||
| case CorElementType.SzArray: | ||
| case CorElementType.Ptr: | ||
| case CorElementType.Byref: | ||
| pSelf->numTypeArgs = 1; | ||
| FillTypeNodes(dbi, rts, rts.GetTypeParam(th), nodes, ref idx); | ||
| break; | ||
|
|
||
| case CorElementType.Class: | ||
| case CorElementType.ValueType: | ||
| { | ||
| ReadOnlySpan<TypeHandle> inst = rts.GetInstantiation(th); | ||
| pSelf->numTypeArgs = (uint)inst.Length; | ||
| for (int i = 0; i < inst.Length; i++) | ||
| FillTypeNodes(dbi, rts, inst[i], nodes, ref idx); | ||
| break; | ||
| } | ||
|
|
||
| default: | ||
| pSelf->numTypeArgs = 0; | ||
| break; | ||
| } |
No description provided.