Skip to content
Open
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
13 changes: 9 additions & 4 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ 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 CorElementType represents a GC-collectable object reference.
public virtual bool IsCorElementTypeObjRef(CorElementType elementType);
// Returns the address of one of the runtime's well-known singleton MethodTables, or
// TargetPointer.Null if the runtime has not yet initialized that global.
public virtual TargetPointer GetWellKnownMethodTable(WellKnownMethodTable kind);
// True if the type is a GC-collectable object reference.
public virtual bool IsObjRef(TypeHandle typeHandle);
// 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 @@ -635,6 +635,13 @@ Contracts used:

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

public bool IsCorElementTypeObjRef(CorElementType elementType) =>
elementType is CorElementType.Class
or CorElementType.Object
or CorElementType.String
or CorElementType.Array
or CorElementType.SzArray;

public TargetPointer GetWellKnownMethodTable(WellKnownMethodTable kind)
{
// Map the well-known kind to the corresponding runtime global. Returns
Expand All @@ -657,8 +664,6 @@ Contracts used:
return value;
}

public bool IsObjRef(TypeHandle typeHandle) => // Returns true if GetSignatureCorElementType returns Class, Array, or 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 @@ -143,10 +143,11 @@ 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();
// True if the CorElementType represents a GC-collectable object reference.
bool IsCorElementTypeObjRef(CorElementType elementType) => throw new NotImplementedException();
Comment thread
rcj1 marked this conversation as resolved.
// Returns the address of one of the runtime's well-known singleton MethodTables,
// or TargetPointer.Null if the runtime has not yet initialized that global.
TargetPointer GetWellKnownMethodTable(WellKnownMethodTable kind) => throw new NotImplementedException();
bool IsObjRef(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a type that contains managed references
Comment thread
rcj1 marked this conversation as resolved.
Comment thread
rcj1 marked this conversation as resolved.
Comment on lines +146 to 151
Comment on lines 143 to 151
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 @@ -585,6 +585,13 @@ private Data.EEClass GetClassData(TypeHandle typeHandle)

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

public bool IsCorElementTypeObjRef(CorElementType elementType)
=> elementType is CorElementType.Class
or CorElementType.Object
or CorElementType.String
or CorElementType.Array
or CorElementType.SzArray;

public TargetPointer GetWellKnownMethodTable(WellKnownMethodTable kind)
{
string globalName = kind switch
Expand All @@ -605,12 +612,6 @@ public TargetPointer GetWellKnownMethodTable(WellKnownMethodTable kind)
return value;
}

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 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 @@ -2609,8 +2609,44 @@ 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 = rts.GetWellKnownMethodTable(WellKnownMethodTable.Canon);
if (canonMtPtr == TargetPointer.Null)
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;
Comment thread
Copilot marked this conversation as resolved.
TypeHandle canonTh = rts.GetTypeHandle(canonMtPtr);

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 @@ -2702,29 +2738,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 LookupTypeDefOrRefInAssembly(vmAssembly, metadataToken);
}

private TypeHandle GetExactArrayTypeHandle(IRuntimeTypeSystem rts, DebuggerIPCE_ExpandedTypeData* pTopLevel, ArgInfoList* pArgInfo)
Expand All @@ -2750,7 +2764,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 = LookupTypeDefOrRefInAssembly(vmAssembly, metadataToken);

int argCount = pArgInfo->m_nEntries;
if (argCount == 0)
Expand Down Expand Up @@ -3000,7 +3014,7 @@ public int GetEnCHangingFieldInfo(EnCHangingFieldInfo* pEnCFieldInfo, FieldData*
uint metadataToken = ReadLittleEndian(pEnCFieldInfo->objectTypeData.metadataToken);
uint fldToken = pEnCFieldInfo->fldToken;

_ = LookupTypeDefOrRefInAssembly(rts, vmAssembly, metadataToken);
_ = LookupTypeDefOrRefInAssembly(vmAssembly, metadataToken);
Contracts.ModuleHandle moduleHandle = loader.GetModuleHandleFromAssemblyPtr(new TargetPointer(vmAssembly));
Contracts.ModuleLookupTables lookupTables = loader.GetLookupTables(moduleHandle);
TargetPointer fieldDescPointer = loader.GetModuleLookupMapElement(lookupTables.FieldDefToDesc, fldToken, out _);
Expand Down Expand Up @@ -3082,6 +3096,37 @@ public int GetEnCHangingFieldInfo(EnCHangingFieldInfo* pEnCFieldInfo, FieldData*
return hr;
}

internal TypeHandle LookupTypeDefOrRefInAssembly(ulong vmAssembly, uint metadataToken)
{
TypeHandle th = TryLookupTypeDefOrRefInAssembly(vmAssembly, metadataToken);
if (th.IsNull)
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;
return th;
}

internal 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);
}

public int EnumerateTypeHandleParams(ulong vmTypeHandle,
delegate* unmanaged<DebuggerIPCE_ExpandedTypeData*, nint, void> fpCallback, nint pUserData)
{
Expand Down Expand Up @@ -4254,7 +4299,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 @@ -4384,8 +4429,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 @@ -5371,7 +5419,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
Expand Up @@ -314,6 +314,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 thread
rcj1 marked this conversation as resolved.
}

[StructLayout(LayoutKind.Sequential)]
public unsafe struct TypeInfoList
{
public DebuggerIPCE_TypeArgData* m_pList;
public int m_nEntries;
Comment thread
rcj1 marked this conversation as resolved.
}

[StructLayout(LayoutKind.Sequential)]
public struct DacDbiArrayInfo
{
Expand Down Expand Up @@ -595,7 +609,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