| File: Dbi\TypeDataWalk.cs | Web Access |
| Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Legacy\Microsoft.Diagnostics.DataContractReader.Legacy.csproj (Microsoft.Diagnostics.DataContractReader.Legacy) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Immutable; using System.Runtime.InteropServices; using Microsoft.Diagnostics.DataContractReader.Contracts; namespace Microsoft.Diagnostics.DataContractReader.Legacy; // Port of native DacDbiInterfaceImpl::TypeDataWalk // // Walks the flattened DebuggerIPCE_TypeArgData[] tree that the right side built in // CordbType::GatherTypeData and produces a TypeHandle for the loaded representation // (exact, or canonical when generic code-sharing collapses reference type-args to // System.__Canon and value type-args to their canonical form). // internal unsafe ref struct TypeDataWalk { private readonly Target _target; private readonly IRuntimeTypeSystem _rts; private readonly TypeHandle _canonTh; private DebuggerIPCE_TypeArgData* _pCurrent; private uint _remaining; public TypeDataWalk(Target target, IRuntimeTypeSystem rts, TypeHandle canonTh, DebuggerIPCE_TypeArgData* pData, uint nData) { _target = target; _rts = rts; _canonTh = canonTh; _pCurrent = pData; _remaining = nData; } // Pop a single node from the head of the list, or null if exhausted. private DebuggerIPCE_TypeArgData* ReadOne() { if (_remaining == 0) return null; _remaining--; DebuggerIPCE_TypeArgData* p = _pCurrent; _pCurrent++; return p; } // Skip a single node and all of its descendants. private void Skip() { DebuggerIPCE_TypeArgData* p = ReadOne(); if (p != null) { uint n = DacDbiImpl.ReadLittleEndian(p->numTypeArgs); for (uint i = 0; i < n; i++) Skip(); } } public TypeHandle ReadLoadedTypeHandle() { DebuggerIPCE_TypeArgData* p = ReadOne(); if (p == null) return default; CorElementType et = (CorElementType)DacDbiImpl.ReadLittleEndian(p->data.elementType); switch (et) { case CorElementType.Array: case CorElementType.SzArray: return ArrayTypeArg(p); case CorElementType.Ptr: case CorElementType.Byref: return PtrOrByRefTypeArg(p); case CorElementType.Class: case CorElementType.ValueType: { ulong vmAssembly = DacDbiImpl.ReadLittleEndian(p->data.ClassTypeData_vmAssembly); uint metadataToken = DacDbiImpl.ReadLittleEndian(p->data.ClassTypeData_metadataToken); return ReadLoadedInstantiation(vmAssembly, metadataToken, DacDbiImpl.ReadLittleEndian(p->numTypeArgs)); } case CorElementType.FnPtr: return FnPtrTypeArg(p); default: return _rts.GetPrimitiveType(et); } } // Read a single type argument in canonicalization-aware fashion. private TypeHandle ReadLoadedTypeArg() { DebuggerIPCE_TypeArgData* p = ReadOne(); if (p == null) return default; CorElementType et = (CorElementType)DacDbiImpl.ReadLittleEndian(p->data.elementType); switch (et) { case CorElementType.Ptr: return PtrOrByRefTypeArg(p); case CorElementType.Class: case CorElementType.ValueType: return ClassTypeArg(p); case CorElementType.FnPtr: return FnPtrTypeArg(p); default: return ObjRefOrPrimitiveTypeArg(p, et); } } // Read an instantiation and ask the runtime-type-system for the loaded handle. private TypeHandle ReadLoadedInstantiation(ulong vmAssembly, uint metadataToken, uint nTypeArgs) { TypeHandle typeDef = TryLookupTypeDefOrRefInAssembly(vmAssembly, metadataToken); if (typeDef.IsNull) return default; if (nTypeArgs == 0) return typeDef; ImmutableArray<TypeHandle>.Builder builder = ImmutableArray.CreateBuilder<TypeHandle>((int)nTypeArgs); bool allOK = true; for (uint i = 0; i < nTypeArgs; i++) { TypeHandle th = ReadLoadedTypeArg(); allOK &= !th.IsNull; builder.Add(th); } if (!allOK) return default; return _rts.GetConstructedType(typeDef, CorElementType.GenericInst, 0, builder.MoveToImmutable()); } private TypeHandle ArrayTypeArg(DebuggerIPCE_TypeArgData* pInfo) { TypeHandle elem = ReadLoadedTypeArg(); if (elem.IsNull) return default; CorElementType et = (CorElementType)DacDbiImpl.ReadLittleEndian(pInfo->data.elementType); int rank = (int)DacDbiImpl.ReadLittleEndian(pInfo->data.ArrayTypeData_arrayRank); return _rts.GetConstructedType(elem, et, rank, ImmutableArray<TypeHandle>.Empty); } private TypeHandle PtrOrByRefTypeArg(DebuggerIPCE_TypeArgData* pInfo) { TypeHandle referent = ReadLoadedTypeArg(); if (referent.IsNull) return default; CorElementType et = (CorElementType)DacDbiImpl.ReadLittleEndian(pInfo->data.elementType); return _rts.GetConstructedType(referent, et, 0, ImmutableArray<TypeHandle>.Empty); } // A generic reference type collapses to System.__Canon // (and its type arguments are skipped); a value-type instantiation is recursively // resolved. private TypeHandle ClassTypeArg(DebuggerIPCE_TypeArgData* pInfo) { ulong vmAssembly = DacDbiImpl.ReadLittleEndian(pInfo->data.ClassTypeData_vmAssembly); uint metadataToken = DacDbiImpl.ReadLittleEndian(pInfo->data.ClassTypeData_metadataToken); uint numTypeArgs = DacDbiImpl.ReadLittleEndian(pInfo->numTypeArgs); CorElementType et = (CorElementType)DacDbiImpl.ReadLittleEndian(pInfo->data.elementType); TypeHandle typeDef = TryLookupTypeDefOrRefInAssembly(vmAssembly, metadataToken); if ((!typeDef.IsNull && _rts.IsValueType(typeDef)) || et == CorElementType.ValueType) { return ReadLoadedInstantiation(vmAssembly, metadataToken, numTypeArgs); } else { for (uint i = 0; i < numTypeArgs; i++) Skip(); return _canonTh; } } private TypeHandle FnPtrTypeArg(DebuggerIPCE_TypeArgData* pInfo) { uint numTypeArgs = DacDbiImpl.ReadLittleEndian(pInfo->numTypeArgs); ImmutableArray<TypeHandle>.Builder builder = ImmutableArray.CreateBuilder<TypeHandle>((int)numTypeArgs); bool allOK = true; for (uint i = 0; i < numTypeArgs; i++) { TypeHandle th = ReadLoadedTypeArg(); allOK &= !th.IsNull; builder.Add(th); } if (!allOK) return default; // Non-default calling conventions are not supported (matches the exact-handle path). return _rts.GetConstructedType(default, CorElementType.FnPtr, 0, builder.MoveToImmutable()); } private TypeHandle ObjRefOrPrimitiveTypeArg(DebuggerIPCE_TypeArgData* pInfo, CorElementType elementType) { // Skip any children: they are part of a reference-typed argument that canonicalizes to __Canon. uint numTypeArgs = DacDbiImpl.ReadLittleEndian(pInfo->numTypeArgs); for (uint i = 0; i < numTypeArgs; i++) Skip(); if (_rts.IsCorElementTypeObjRef(elementType)) return _canonTh; return _rts.GetPrimitiveType(elementType); } private TypeHandle TryLookupTypeDefOrRefInAssembly(ulong vmAssembly, uint metadataToken) { ILoader loader = _target.Contracts.Loader; IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem; Contracts.ModuleHandle moduleHandle = loader.GetModuleHandleFromAssemblyPtr(new TargetPointer(vmAssembly)); ModuleLookupTables lookupTables = loader.GetLookupTables(moduleHandle); TargetPointer mt; switch ((EcmaMetadataUtils.TokenType)(metadataToken & EcmaMetadataUtils.TokenTypeMask)) { case EcmaMetadataUtils.TokenType.mdtTypeDef: mt = loader.GetModuleLookupMapElement(lookupTables.TypeDefToMethodTable, metadataToken, out _); break; case EcmaMetadataUtils.TokenType.mdtTypeRef: mt = loader.GetModuleLookupMapElement(lookupTables.TypeRefToMethodTable, metadataToken, out _); break; default: return default; } if (mt == TargetPointer.Null) return default; return rts.GetTypeHandle(mt); } }