Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ partial interface IRuntimeTypeSystem : IContract
// True if the MethodTable is the System.Object MethodTable (g_pObjectClass)
public virtual bool IsObject(TypeHandle typeHandle);
public virtual bool IsString(TypeHandle typeHandle);
// True if the type is a GC-collectable object reference.
public virtual bool IsObjRef(TypeHandle typeHandle);
// True if the CorElementType represents a GC-collectable object reference.
public virtual bool IsCorElementTypeObjRef(CorElementType elementType);
// True if the MethodTable represents a type that contains managed references
public virtual bool ContainsGCPointers(TypeHandle typeHandle);
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
Expand Down Expand Up @@ -603,8 +603,12 @@ Contracts used:

public bool IsString(TypeHandle TypeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[TypeHandle.Address].Flags.IsString;

public bool IsObjRef(TypeHandle typeHandle) => // Returns true if GetSignatureCorElementType returns Class, Array, or SzArray.

public bool IsCorElementTypeObjRef(CorElementType elementType) =>
elementType is CorElementType.Class
or CorElementType.Object
or CorElementType.String
or CorElementType.Array
or CorElementType.SzArray;
public bool ContainsGCPointers(TypeHandle TypeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[TypeHandle.Address].Flags.ContainsGCPointers;

public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,8 @@ public interface IRuntimeTypeSystem : IContract
// True if the MethodTable is the System.Object MethodTable (g_pObjectClass)
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
Comment on lines 131 to 135
Comment on lines +133 to 135
bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the type requires 8-byte alignment on platforms that don't 8-byte align by default (FEATURE_64BIT_ALIGNMENT)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -560,12 +560,13 @@ private Data.EEClass GetClassData(TypeHandle typeHandle)
public bool IsObject(TypeHandle typeHandle) => ObjectMethodTablePointer != TargetPointer.Null && ObjectMethodTablePointer == typeHandle.Address;

public bool IsString(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.IsString;
public bool IsObjRef(TypeHandle typeHandle)
{
CorElementType elementType = GetSignatureCorElementType(typeHandle);
// Keep this aligned with CorTypeInfo::IsObjRef semantics for signature element types.
return elementType is CorElementType.Class or CorElementType.Array or CorElementType.SzArray;
}
public bool IsCorElementTypeObjRef(CorElementType elementType)
=> elementType is CorElementType.Class
or CorElementType.Object
or CorElementType.String
or CorElementType.Array
or CorElementType.SzArray;

public bool ContainsGCPointers(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.ContainsGCPointers;
public bool RequiresAlign8(TypeHandle typeHandle) => !typeHandle.IsMethodTable() ? false : _methodTables[typeHandle.Address].Flags.RequiresAlign8;
public bool IsContinuationWithoutMetadata(TypeHandle typeHandle) => typeHandle.IsMethodTable()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1907,8 +1907,45 @@ public int GetTypeHandle(ulong vmModule, uint metadataToken, ulong* pRetVal)
return hr;
}

public int GetApproxTypeHandle(nint pTypeData, ulong* pRetVal)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetApproxTypeHandle(pTypeData, pRetVal) : HResults.E_NOTIMPL;
public int GetApproxTypeHandle(TypeInfoList* pTypeData, ulong* pRetVal)
{
if (pTypeData == null || pRetVal == null)
return HResults.E_POINTER;
*pRetVal = 0;
int hr = HResults.S_OK;
try
{
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;

TargetPointer canonMtPtr = _target.ReadPointer(_target.ReadGlobalPointer(Constants.Globals.CanonMethodTable));
TypeHandle canonTh = rts.GetTypeHandle(canonMtPtr);

if (pTypeData->m_nEntries <= 0 || pTypeData->m_pList == null)
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;

TypeDataWalk walk = new TypeDataWalk(_target, rts, canonTh, pTypeData->m_pList, (uint)pTypeData->m_nEntries);
TypeHandle th = walk.ReadLoadedTypeHandle();
if (th.IsNull)
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;
*pRetVal = th.Address.Value;
}
catch (System.Exception ex)
{
hr = ex.HResult;
}
#if DEBUG
if (_legacy is not null)
{
ulong vmLocal;
int hrLocal = _legacy.GetApproxTypeHandle(pTypeData, &vmLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
Debug.Assert(*pRetVal == vmLocal, $"cDAC: {*pRetVal:x}, DAC: {vmLocal:x}");
}
#endif
return hr;
}
Comment thread
rcj1 marked this conversation as resolved.


public int GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData* pTypeData, ArgInfoList* pArgInfo, ulong* pVmTypeHandle)
{
Expand Down Expand Up @@ -2000,29 +2037,7 @@ private TypeHandle GetClassOrValueTypeHandle(IRuntimeTypeSystem rts, DebuggerIPC

ulong vmAssembly = ReadLittleEndian(pData->vmAssembly);
uint metadataToken = ReadLittleEndian(pData->metadataToken);
return LookupTypeDefOrRefInAssembly(rts, vmAssembly, metadataToken);
}

private TypeHandle LookupTypeDefOrRefInAssembly(IRuntimeTypeSystem rts, ulong vmAssembly, uint metadataToken)
{
Contracts.ILoader loader = _target.Contracts.Loader;
Contracts.ModuleHandle moduleHandle = loader.GetModuleHandleFromAssemblyPtr(new TargetPointer(vmAssembly));
Contracts.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:
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;
}
if (mt == TargetPointer.Null)
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;
return rts.GetTypeHandle(mt);
return DbiHelpers.LookupTypeDefOrRefInAssembly(_target, rts, vmAssembly, metadataToken);
}

private TypeHandle GetExactArrayTypeHandle(IRuntimeTypeSystem rts, DebuggerIPCE_ExpandedTypeData* pTopLevel, ArgInfoList* pArgInfo)
Expand All @@ -2048,7 +2063,7 @@ private TypeHandle GetExactClassTypeHandle(IRuntimeTypeSystem rts, DebuggerIPCE_
{
ulong vmAssembly = ReadLittleEndian(pTopLevel->ClassTypeData_vmAssembly);
uint metadataToken = ReadLittleEndian(pTopLevel->ClassTypeData_metadataToken);
TypeHandle typeConstructor = LookupTypeDefOrRefInAssembly(rts, vmAssembly, metadataToken);
TypeHandle typeConstructor = DbiHelpers.LookupTypeDefOrRefInAssembly(_target, rts, vmAssembly, metadataToken);

int argCount = pArgInfo->m_nEntries;
if (argCount == 0)
Expand Down Expand Up @@ -3228,7 +3243,7 @@ public int GetObjectFields(ulong id, uint celt, COR_FIELD* layout, uint* pceltFe
// count actually written. Preserve this behavior for compatibility w/ICorDebug.
*pceltFetched = celt;

bool isReferenceType = rts.IsObjRef(typeHandle);
bool isReferenceType = rts.IsCorElementTypeObjRef(rts.GetInternalCorElementType(typeHandle));
uint firstFieldOffset = isReferenceType ? _target.GetTypeInfo(DataType.Object).Size!.Value : 0;

TargetPointer[] fieldDescList = rts.GetFieldDescList(typeHandle).Take((int)cFields).ToArray();
Expand Down Expand Up @@ -3358,8 +3373,11 @@ public int GetTypeLayout(ulong id, COR_TYPE_LAYOUT* pLayout)
numInstanceFields -= rts.GetNumInstanceFields(parentHandle);
}
pLayout->numFields = numInstanceFields;
pLayout->boxOffset = rts.IsObjRef(typeHandle) ? 0u : (uint)_target.PointerSize;
pLayout->type = (int)(rts.IsString(typeHandle) ? CorElementType.String : rts.GetInternalCorElementType(typeHandle));
CorElementType componentType = rts.IsString(typeHandle)
? CorElementType.String
: rts.GetInternalCorElementType(typeHandle);
pLayout->type = (int)componentType;
pLayout->boxOffset = rts.IsCorElementTypeObjRef(componentType) ? 0u : (uint)_target.PointerSize;
}
catch (System.Exception ex)
{
Expand Down Expand Up @@ -4208,7 +4226,7 @@ private static void WriteLittleEndian<T>(ref T dest, T value) where T : unmanage
}
}

private static T ReadLittleEndian<T>(T value) where T : unmanaged, IBinaryInteger<T>
internal static T ReadLittleEndian<T>(T value) where T : unmanaged, IBinaryInteger<T>
{
if (BitConverter.IsLittleEndian)
return value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;
using Microsoft.Diagnostics.DataContractReader.Contracts;

namespace Microsoft.Diagnostics.DataContractReader.Legacy;
internal static class DbiHelpers
{
public static TypeHandle LookupTypeDefOrRefInAssembly(Target target, IRuntimeTypeSystem rts, ulong vmAssembly, uint metadataToken)
{
TypeHandle th = TryLookupTypeDefOrRefInAssembly(target, rts, vmAssembly, metadataToken);
if (th.IsNull)
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;
return th;
}

public static TypeHandle TryLookupTypeDefOrRefInAssembly(Target target, IRuntimeTypeSystem rts, ulong vmAssembly, uint metadataToken)
{
ILoader loader = target.Contracts.Loader;
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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,20 @@ public unsafe struct ArgInfoList
public int m_nEntries;
}

[StructLayout(LayoutKind.Sequential, Size = 48)]
public struct DebuggerIPCE_TypeArgData
{
public DebuggerIPCE_ExpandedTypeData data;
public uint numTypeArgs; // Portable<UINT>
Comment on lines +290 to +294
}

[StructLayout(LayoutKind.Sequential)]
public unsafe struct TypeInfoList
{
public DebuggerIPCE_TypeArgData* m_pList;
public int m_nEntries;
Comment on lines +297 to +301
}

public enum DynamicMethodType
{
kNone = 0,
Expand Down Expand Up @@ -551,7 +565,7 @@ public unsafe partial interface IDacDbiInterface
int GetTypeHandle(ulong vmModule, uint metadataToken, ulong* pRetVal);

[PreserveSig]
int GetApproxTypeHandle(nint pTypeData, ulong* pRetVal);
int GetApproxTypeHandle(TypeInfoList* pTypeData, ulong* pRetVal);

[PreserveSig]
int GetExactTypeHandle(DebuggerIPCE_ExpandedTypeData* pTypeData, ArgInfoList* pArgInfo, ulong* pVmTypeHandle);
Expand Down
Loading
Loading