Skip to content
Merged
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
22 changes: 22 additions & 0 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ partial interface IRuntimeTypeSystem : IContract
// True if the MethodTable is the sentinel value associated with unallocated space in the managed heap
public virtual bool IsFreeObjectMethodTable(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 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 @@ -95,6 +97,11 @@ partial interface IRuntimeTypeSystem : IContract
// HasTypeParam will return true for cases where this is the interop view, and false for normal valuetypes.
public virtual CorElementType GetSignatureCorElementType(TypeHandle typeHandle);

// Internal element type of the type. Unlike GetSignatureCorElementType, this returns the underlying
// primitive type for enums (e.g. I4 for an enum with int underlying type).
// For arrays, reference types, and TypeDescs, behaves identically to GetSignatureCorElementType.
public virtual CorElementType GetInternalCorElementType(TypeHandle typeHandle);

bool IsValueType(TypeHandle typeHandle);
// return true if the TypeHandle represents an enum type.
bool IsEnum(TypeHandle typeHandle);
Expand Down Expand Up @@ -563,6 +570,8 @@ 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 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 Expand Up @@ -823,6 +832,19 @@ Contracts used:
return default(CorElementType);
}

// Internal element type: returns the underlying primitive type for enums. For all other types, identical to GetSignatureCorElementType.
public CorElementType GetInternalCorElementType(TypeHandle typeHandle)
{
CorElementType sigType = GetSignatureCorElementType(typeHandle);
if (sigType == CorElementType.ValueType && typeHandle.IsMethodTable())
{
CorElementType internalType = (CorElementType)GetClassData(typeHandle).InternalCorElementType;
if (internalType != CorElementType.ValueType)
return internalType;
}
return sigType;
}

public bool IsValueType(TypeHandle typeHandle)
{
// if methodtable: check WFLAGS_HIGH for Category_ValueType
Expand Down
12 changes: 6 additions & 6 deletions src/coreclr/debug/daccess/dacdbiimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7353,17 +7353,17 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetObjectFields(COR_TYPEID id, UL
}


HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout)
HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTypeLayout(CORDB_ADDRESS id, COR_TYPE_LAYOUT *pLayout)
{
if (pLayout == NULL)
return E_POINTER;

if (id.token1 == 0)
if (id == 0)
return CORDBG_E_CLASS_NOT_LOADED;

DD_ENTER_MAY_THROW;

PTR_MethodTable mt = PTR_MethodTable(TO_TADDR(id.token1));
PTR_MethodTable mt = PTR_MethodTable(TO_TADDR(id));
PTR_MethodTable parentMT = mt->GetParentMethodTable();

COR_TYPEID parent = {parentMT.GetAddr(), 0};
Expand All @@ -7383,17 +7383,17 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetTypeLayout(COR_TYPEID id, COR_
return S_OK;
}

HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout)
HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetArrayLayout(CORDB_ADDRESS id, COR_ARRAY_LAYOUT *pLayout)
{
if (pLayout == NULL)
return E_POINTER;

if (id.token1 == 0)
if (id == 0)
return CORDBG_E_CLASS_NOT_LOADED;

DD_ENTER_MAY_THROW;

PTR_MethodTable mt = PTR_MethodTable(TO_TADDR(id.token1));
PTR_MethodTable mt = PTR_MethodTable(TO_TADDR(id));

if (!mt->IsStringOrArray())
return E_INVALIDARG;
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/debug/daccess/dacdbiimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,8 @@ class DacDbiInterfaceImpl :
HRESULT STDMETHODCALLTYPE GetTypeIDForType(VMPTR_TypeHandle vmTypeHandle, COR_TYPEID *pID);

HRESULT STDMETHODCALLTYPE GetObjectFields(COR_TYPEID id, ULONG32 celt, COR_FIELD *layout, ULONG32 *pceltFetched);
HRESULT STDMETHODCALLTYPE GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout);
HRESULT STDMETHODCALLTYPE GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout);
HRESULT STDMETHODCALLTYPE GetTypeLayout(CORDB_ADDRESS id, COR_TYPE_LAYOUT *pLayout);
HRESULT STDMETHODCALLTYPE GetArrayLayout(CORDB_ADDRESS id, COR_ARRAY_LAYOUT *pLayout);
HRESULT STDMETHODCALLTYPE GetGCHeapInformation(OUT COR_HEAPINFO * pHeapInfo);
HRESULT STDMETHODCALLTYPE GetPEFileMDInternalRW(VMPTR_PEAssembly vmPEAssembly, OUT TADDR* pAddrMDInternalRW);
#ifdef FEATURE_CODE_VERSIONING
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/debug/di/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2392,7 +2392,7 @@ COM_METHOD CordbProcess::GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT *pLayout
HRESULT hr = S_OK;
PUBLIC_API_BEGIN(this);

hr = GetProcess()->GetDAC()->GetArrayLayout(id, pLayout);
hr = GetProcess()->GetDAC()->GetArrayLayout((CORDB_ADDRESS)id.token1, pLayout);

PUBLIC_API_END(hr);
return hr;
Expand All @@ -2406,7 +2406,7 @@ COM_METHOD CordbProcess::GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT *pLayout)
HRESULT hr = S_OK;
PUBLIC_API_BEGIN(this);

hr = GetProcess()->GetDAC()->GetTypeLayout(id, pLayout);
hr = GetProcess()->GetDAC()->GetTypeLayout((CORDB_ADDRESS)id.token1, pLayout);

PUBLIC_API_END(hr);
return hr;
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/debug/inc/dacdbiinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -2042,9 +2042,9 @@ IDacDbiInterface : public IUnknown

virtual HRESULT STDMETHODCALLTYPE GetObjectFields(COR_TYPEID id, ULONG32 celt, OUT COR_FIELD * layout, OUT ULONG32 * pceltFetched) = 0;

virtual HRESULT STDMETHODCALLTYPE GetTypeLayout(COR_TYPEID id, COR_TYPE_LAYOUT * pLayout) = 0;
virtual HRESULT STDMETHODCALLTYPE GetTypeLayout(CORDB_ADDRESS id, COR_TYPE_LAYOUT * pLayout) = 0;

virtual HRESULT STDMETHODCALLTYPE GetArrayLayout(COR_TYPEID id, COR_ARRAY_LAYOUT * pLayout) = 0;
virtual HRESULT STDMETHODCALLTYPE GetArrayLayout(CORDB_ADDRESS id, COR_ARRAY_LAYOUT * pLayout) = 0;

virtual HRESULT STDMETHODCALLTYPE GetGCHeapInformation(OUT COR_HEAPINFO * pHeapInfo) = 0;

Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/inc/dacdbi.idl
Original file line number Diff line number Diff line change
Expand Up @@ -393,8 +393,8 @@ interface IDacDbiInterface : IUnknown
HRESULT GetTypeID([in] CORDB_ADDRESS obj, [out] COR_TYPEID * pType);
HRESULT GetTypeIDForType([in] VMPTR_TypeHandle vmTypeHandle, [out] COR_TYPEID * pId);
HRESULT GetObjectFields([in] COR_TYPEID id, [in] ULONG32 celt, [out] COR_FIELD * layout, [out] ULONG32 * pceltFetched);
HRESULT GetTypeLayout([in] COR_TYPEID id, [out] COR_TYPE_LAYOUT * pLayout);
HRESULT GetArrayLayout([in] COR_TYPEID id, [out] COR_ARRAY_LAYOUT * pLayout);
HRESULT GetTypeLayout([in] CORDB_ADDRESS id, [out] COR_TYPE_LAYOUT * pLayout);
HRESULT GetArrayLayout([in] CORDB_ADDRESS id, [out] COR_ARRAY_LAYOUT * pLayout);
HRESULT GetGCHeapInformation([out] COR_HEAPINFO * pHeapInfo);

// PE File
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ public interface IRuntimeTypeSystem : IContract
// True if the MethodTable is the sentinel value associated with unallocated space in the managed heap
bool IsFreeObjectMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
bool IsString(TypeHandle typeHandle) => throw new NotImplementedException();
bool IsObjRef(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a type that contains managed references
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 Expand Up @@ -162,6 +163,11 @@ public interface IRuntimeTypeSystem : IContract
CorElementType GetSignatureCorElementType(TypeHandle typeHandle) => throw new NotImplementedException();
bool IsValueType(TypeHandle typeHandle) => throw new NotImplementedException();

// Internal element type of the type. Unlike GetSignatureCorElementType, this returns the underlying primitive
// type for enums (e.g. I4 for an enum with int underlying type) and for PrimitiveValueType categories.
// For arrays, reference types, and TypeDescs, behaves identically to GetSignatureCorElementType.
CorElementType GetInternalCorElementType(TypeHandle typeHandle) => throw new NotImplementedException();

// return true if the TypeHandle represents an enum type.
bool IsEnum(TypeHandle typeHandle) => throw new NotImplementedException();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,12 @@ private Data.EEClass GetClassData(TypeHandle typeHandle)
public bool IsFreeObjectMethodTable(TypeHandle typeHandle) => FreeObjectMethodTablePointer == 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 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 IsContinuation(TypeHandle typeHandle) => typeHandle.IsMethodTable()
Expand Down Expand Up @@ -864,6 +870,19 @@ public CorElementType GetSignatureCorElementType(TypeHandle typeHandle)
return default;
}

public CorElementType GetInternalCorElementType(TypeHandle typeHandle)
{
CorElementType sigType = GetSignatureCorElementType(typeHandle);
if (sigType == CorElementType.ValueType && typeHandle.IsMethodTable())
{
CorElementType internalType = (CorElementType)GetClassData(typeHandle).InternalCorElementType;
if (internalType != CorElementType.ValueType)
return internalType;
}

return sigType;
}

public bool IsValueType(TypeHandle typeHandle)
{
if (typeHandle.IsMethodTable())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1681,11 +1681,135 @@ public int GetTypeIDForType(ulong vmTypeHandle, COR_TYPEID* pId)
public int GetObjectFields(nint id, uint celt, COR_FIELD* layout, uint* pceltFetched)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetObjectFields(id, celt, layout, pceltFetched) : HResults.E_NOTIMPL;

public int GetTypeLayout(nint id, COR_TYPE_LAYOUT* pLayout)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetTypeLayout(id, pLayout) : HResults.E_NOTIMPL;
public int GetTypeLayout(ulong id, COR_TYPE_LAYOUT* pLayout)
{
int hr = HResults.S_OK;
try
{
if (pLayout is null)
throw new NullReferenceException(nameof(pLayout));

if (id == 0)
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;

IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TypeHandle typeHandle = rts.GetTypeHandle(new TargetPointer((ulong)id));

TargetPointer parentMT = rts.GetParentMethodTable(typeHandle);
pLayout->parentID.token1 = parentMT.Value;
pLayout->parentID.token2 = 0;
pLayout->objectSize = rts.GetBaseSize(typeHandle);
ushort numInstanceFields = rts.GetNumInstanceFields(typeHandle);
if (parentMT != TargetPointer.Null)
{
TypeHandle parentHandle = rts.GetTypeHandle(parentMT);
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));
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

#if DEBUG
if (_legacy is not null)
{
COR_TYPE_LAYOUT resultLocal;
int hrLocal = _legacy.GetTypeLayout(id, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(pLayout->parentID.token1 == resultLocal.parentID.token1, $"cDAC: {pLayout->parentID.token1:x}, DAC: {resultLocal.parentID.token1:x}");
Debug.Assert(pLayout->parentID.token2 == resultLocal.parentID.token2, $"cDAC: {pLayout->parentID.token2:x}, DAC: {resultLocal.parentID.token2:x}");
Debug.Assert(pLayout->objectSize == resultLocal.objectSize, $"cDAC: {pLayout->objectSize}, DAC: {resultLocal.objectSize}");
Debug.Assert(pLayout->numFields == resultLocal.numFields, $"cDAC: {pLayout->numFields}, DAC: {resultLocal.numFields}");
Debug.Assert(pLayout->boxOffset == resultLocal.boxOffset, $"cDAC: {pLayout->boxOffset}, DAC: {resultLocal.boxOffset}");
Debug.Assert(pLayout->type == resultLocal.type, $"cDAC: {pLayout->type}, DAC: {resultLocal.type}");
}
}
#endif

return hr;
}

public int GetArrayLayout(ulong id, COR_ARRAY_LAYOUT* pLayout)
{
int hr = HResults.S_OK;
try
{
if (pLayout is null)
throw new NullReferenceException(nameof(pLayout));

if (id == 0)
throw Marshal.GetExceptionForHR(CorDbgHResults.CORDBG_E_CLASS_NOT_LOADED)!;
IRuntimeTypeSystem rts = _target.Contracts.RuntimeTypeSystem;
TypeHandle arrayOrStringTypeHandle = rts.GetTypeHandle(new TargetPointer(id));
uint pointerSize = (uint)_target.PointerSize;

if (rts.IsString(arrayOrStringTypeHandle))
{
TypeHandle charTypeHandle = rts.GetPrimitiveType(CorElementType.Char);
pLayout->componentID.token1 = charTypeHandle.Address.Value;
pLayout->componentID.token2 = 0;
pLayout->componentType = CorElementType.Char;
pLayout->firstElementOffset = pointerSize + 4;
pLayout->elementSize = sizeof(char);
pLayout->countOffset = pointerSize;
pLayout->rankSize = 4;
pLayout->numRanks = 1;
pLayout->rankOffset = pointerSize;
}
else
{
if (!rts.IsArray(arrayOrStringTypeHandle, out uint rank))
throw Marshal.GetExceptionForHR(HResults.E_INVALIDARG)!;

TypeHandle componentTypeHandle = rts.GetTypeParam(arrayOrStringTypeHandle);
CorElementType componentType = rts.IsString(componentTypeHandle) ? CorElementType.String : rts.GetInternalCorElementType(componentTypeHandle);
pLayout->componentID.token1 = componentTypeHandle.Address.Value;
pLayout->componentID.token2 = 0;
pLayout->componentType = componentType;
Target.TypeInfo objectHeaderTypeInfo = _target.GetTypeInfo(DataType.ObjectHeader);
uint objectHeaderSize = (uint)objectHeaderTypeInfo.Size!.Value;
pLayout->firstElementOffset = rts.GetBaseSize(arrayOrStringTypeHandle) - objectHeaderSize;
pLayout->elementSize = rts.GetComponentSize(arrayOrStringTypeHandle);
pLayout->countOffset = pointerSize;
pLayout->rankSize = 4;
pLayout->numRanks = rank;
pLayout->rankOffset = rank > 1 ? pointerSize * 2 : pointerSize;
}
}
catch (System.Exception ex)
{
hr = ex.HResult;
}

#if DEBUG
if (_legacy is not null)
{
COR_ARRAY_LAYOUT resultLocal;
int hrLocal = _legacy.GetArrayLayout(id, &resultLocal);
Debug.ValidateHResult(hr, hrLocal);
if (hr == HResults.S_OK)
{
Debug.Assert(pLayout->componentID.token1 == resultLocal.componentID.token1, $"cDAC: {pLayout->componentID.token1:x}, DAC: {resultLocal.componentID.token1:x}");
Debug.Assert(pLayout->componentID.token2 == resultLocal.componentID.token2, $"cDAC: {pLayout->componentID.token2:x}, DAC: {resultLocal.componentID.token2:x}");
Debug.Assert(pLayout->componentType == resultLocal.componentType, $"cDAC: {pLayout->componentType}, DAC: {resultLocal.componentType}");
Debug.Assert(pLayout->firstElementOffset == resultLocal.firstElementOffset, $"cDAC: {pLayout->firstElementOffset}, DAC: {resultLocal.firstElementOffset}");
Debug.Assert(pLayout->elementSize == resultLocal.elementSize, $"cDAC: {pLayout->elementSize}, DAC: {resultLocal.elementSize}");
Debug.Assert(pLayout->countOffset == resultLocal.countOffset, $"cDAC: {pLayout->countOffset}, DAC: {resultLocal.countOffset}");
Debug.Assert(pLayout->rankSize == resultLocal.rankSize, $"cDAC: {pLayout->rankSize}, DAC: {resultLocal.rankSize}");
Debug.Assert(pLayout->numRanks == resultLocal.numRanks, $"cDAC: {pLayout->numRanks}, DAC: {resultLocal.numRanks}");
Debug.Assert(pLayout->rankOffset == resultLocal.rankOffset, $"cDAC: {pLayout->rankOffset}, DAC: {resultLocal.rankOffset}");
}
}
#endif

public int GetArrayLayout(nint id, nint pLayout)
=> LegacyFallbackHelper.CanFallback() && _legacy is not null ? _legacy.GetArrayLayout(id, pLayout) : HResults.E_NOTIMPL;
return hr;
}

public int GetGCHeapInformation(COR_HEAPINFO* pHeapInfo)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
using CorElementType = Microsoft.Diagnostics.DataContractReader.Contracts.CorElementType;

namespace Microsoft.Diagnostics.DataContractReader.Legacy;

Expand Down Expand Up @@ -127,6 +128,19 @@ public struct COR_TYPE_LAYOUT
public int type;
}

[StructLayout(LayoutKind.Sequential)]
public struct COR_ARRAY_LAYOUT
{
public COR_TYPEID componentID;
public CorElementType componentType;
public uint firstElementOffset;
public uint elementSize;
public uint countOffset;
public uint rankSize;
public uint numRanks;
public uint rankOffset;
}

[StructLayout(LayoutKind.Sequential)]
public struct COR_FIELD
{
Expand Down Expand Up @@ -494,10 +508,10 @@ public unsafe partial interface IDacDbiInterface
int GetObjectFields(nint id, uint celt, COR_FIELD* layout, uint* pceltFetched);

[PreserveSig]
int GetTypeLayout(nint id, COR_TYPE_LAYOUT* pLayout);
int GetTypeLayout(ulong id, COR_TYPE_LAYOUT* pLayout);

[PreserveSig]
int GetArrayLayout(nint id, nint pLayout);
int GetArrayLayout(ulong id, COR_ARRAY_LAYOUT* pLayout);

[PreserveSig]
int GetGCHeapInformation(COR_HEAPINFO* pHeapInfo);
Expand Down
Loading
Loading