Skip to content

Commit

Permalink
Cherrypick RuntimeTypeSystem changes from dotnet#104759
Browse files Browse the repository at this point in the history
Co-Authored-By: David Wrighton <davidwr@microsoft.com>
  • Loading branch information
lambdageek and davidwrighton committed Jul 16, 2024
1 parent a86987c commit 2d5ec4f
Show file tree
Hide file tree
Showing 17 changed files with 1,023 additions and 110 deletions.
392 changes: 349 additions & 43 deletions docs/design/datacontracts/RuntimeTypeSystem.md

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,15 +202,50 @@ CDAC_TYPE_FIELD(MethodTable, /*pointer*/, Module, cdac_offsets<MethodTable>::Mod
CDAC_TYPE_FIELD(MethodTable, /*pointer*/, ParentMethodTable, cdac_offsets<MethodTable>::ParentMethodTable)
CDAC_TYPE_FIELD(MethodTable, /*uint16*/, NumInterfaces, cdac_offsets<MethodTable>::NumInterfaces)
CDAC_TYPE_FIELD(MethodTable, /*uint16*/, NumVirtuals, cdac_offsets<MethodTable>::NumVirtuals)
CDAC_TYPE_FIELD(MethodTable, /*pointer*/, PerInstInfo, cdac_offsets<MethodTable>::PerInstInfo)
CDAC_TYPE_END(MethodTable)

CDAC_TYPE_BEGIN(EEClass)
CDAC_TYPE_INDETERMINATE(EEClass)
CDAC_TYPE_FIELD(EEClass, /*pointer*/, MethodTable, cdac_offsets<EEClass>::MethodTable)
CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumMethods, cdac_offsets<EEClass>::NumMethods)
CDAC_TYPE_FIELD(EEClass, /*uint32*/, CorTypeAttr, cdac_offsets<EEClass>::CorTypeAttr)
CDAC_TYPE_FIELD(EEClass, /*uint8*/, InternalCorElementType, cdac_offsets<EEClass>::InternalCorElementType)
CDAC_TYPE_END(EEClass)

CDAC_TYPE_BEGIN(ArrayClass)
CDAC_TYPE_INDETERMINATE(ArrayClass)
CDAC_TYPE_FIELD(ArrayClass, /*uint8*/, Rank, cdac_offsets<ArrayClass>::Rank)
CDAC_TYPE_END(ArrayClass)

CDAC_TYPE_BEGIN(GenericsDictInfo)
CDAC_TYPE_INDETERMINATE(GenericsDictInfo)
CDAC_TYPE_FIELD(GenericsDictInfo, /*uint16*/, NumTypeArgs, cdac_offsets<GenericsDictInfo>::NumTypeArgs)
CDAC_TYPE_END(GenericsDictInfo)

CDAC_TYPE_BEGIN(TypeDesc)
CDAC_TYPE_INDETERMINATE(TypeDesc)
CDAC_TYPE_FIELD(TypeDesc, /*uint32*/, TypeAndFlags, cdac_offsets<TypeDesc>::TypeAndFlags)
CDAC_TYPE_END(TypeDesc)

CDAC_TYPE_BEGIN(ParamTypeDesc)
CDAC_TYPE_INDETERMINATE(ParamTypeDesc)
CDAC_TYPE_FIELD(ParamTypeDesc, /*pointer*/, TypeArg, cdac_offsets<ParamTypeDesc>::TypeArg)
CDAC_TYPE_END(ParamTypeDesc)

CDAC_TYPE_BEGIN(TypeVarTypeDesc)
CDAC_TYPE_INDETERMINATE(TypeVarTypeDesc)
CDAC_TYPE_FIELD(TypeVarTypeDesc, /*pointer*/, Module, cdac_offsets<TypeVarTypeDesc>::Module)
CDAC_TYPE_FIELD(TypeVarTypeDesc, /*uint32*/, Token, cdac_offsets<TypeVarTypeDesc>::Token)
CDAC_TYPE_END(TypeVarTypeDesc)

CDAC_TYPE_BEGIN(FnPtrTypeDesc)
CDAC_TYPE_INDETERMINATE(FnPtrTypeDesc)
CDAC_TYPE_FIELD(FnPtrTypeDesc, /*uint32*/, NumArgs, cdac_offsets<FnPtrTypeDesc>::NumArgs)
CDAC_TYPE_FIELD(FnPtrTypeDesc, /*uint32*/, CallConv, cdac_offsets<FnPtrTypeDesc>::CallConv)
CDAC_TYPE_FIELD(FnPtrTypeDesc, /*uint32*/, RetAndArgTypes, cdac_offsets<FnPtrTypeDesc>::RetAndArgTypes)
CDAC_TYPE_END(FnPtrTypeDesc)

CDAC_TYPES_END()

CDAC_GLOBALS_BEGIN()
Expand Down
6 changes: 6 additions & 0 deletions src/coreclr/vm/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -1803,6 +1803,7 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW!

template<> struct cdac_offsets<EEClass>
{
static constexpr size_t InternalCorElementType = offsetof(EEClass, m_NormType);
static constexpr size_t MethodTable = offsetof(EEClass, m_pMethodTable);
static constexpr size_t NumMethods = offsetof(EEClass, m_NumMethods);
static constexpr size_t CorTypeAttr = offsetof(EEClass, m_dwAttrClass);
Expand Down Expand Up @@ -1995,7 +1996,12 @@ class ArrayClass : public EEClass
BOOL fForStubAsIL
);

template<typename T> friend struct ::cdac_offsets;
};

template<> struct cdac_offsets<ArrayClass>
{
static constexpr size_t Rank = offsetof(ArrayClass, m_rank);
};

inline EEClassLayoutInfo *EEClass::GetLayoutInfo()
Expand Down
14 changes: 5 additions & 9 deletions src/coreclr/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4832,7 +4832,7 @@ CorElementType MethodTable::GetSignatureCorElementType()
// common cases of ELEMENT_TYPE_CLASS and ELEMENT_TYPE_VALUETYPE.
CorElementType ret;

switch (GetFlag(enum_flag_Category_ElementTypeMask))
switch (GetFlag(enum_flag_Category_Mask))
{
case enum_flag_Category_Array:
ret = ELEMENT_TYPE_ARRAY;
Expand All @@ -4843,17 +4843,13 @@ CorElementType MethodTable::GetSignatureCorElementType()
break;

case enum_flag_Category_ValueType:
case enum_flag_Category_Nullable:
case enum_flag_Category_PrimitiveValueType:
ret = ELEMENT_TYPE_VALUETYPE;
break;

case enum_flag_Category_PrimitiveValueType:
//
// This is the only difference from MethodTable::GetInternalCorElementType()
//
if (IsTruePrimitive())
ret = GetClass()->GetInternalCorElementType();
else
ret = ELEMENT_TYPE_VALUETYPE;
case enum_flag_Category_TruePrimitive:
ret = GetClass()->GetInternalCorElementType();
break;

default:
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/vm/methodtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -293,9 +293,15 @@ struct GenericsDictInfo

// Number of type parameters (NOT including those of superclasses).
WORD m_wNumTyPars;
template<typename T> friend struct ::cdac_offsets;
}; // struct GenericsDictInfo
typedef DPTR(GenericsDictInfo) PTR_GenericsDictInfo;

template<>
struct cdac_offsets<GenericsDictInfo>
{
static constexpr size_t NumTypeArgs = offsetof(GenericsDictInfo, m_wNumTyPars);
};

// These various statics structures exist directly before the MethodTableAuxiliaryData

Expand Down Expand Up @@ -3943,6 +3949,7 @@ template<> struct cdac_offsets<MethodTable>
static constexpr size_t ParentMethodTable = offsetof(MethodTable, m_pParentMethodTable);
static constexpr size_t NumInterfaces = offsetof(MethodTable, m_wNumInterfaces);
static constexpr size_t NumVirtuals = offsetof(MethodTable, m_wNumVirtuals);
static constexpr size_t PerInstInfo = offsetof(MethodTable, m_pPerInstInfo);
};

#ifndef CROSSBITNESS_COMPILE
Expand Down
32 changes: 32 additions & 0 deletions src/coreclr/vm/typedesc.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,14 @@ class TypeDesc

// internal RuntimeType object handle
RUNTIMETYPEHANDLE m_hExposedClassObject;
template<typename T> friend struct ::cdac_offsets;
};

template<>
struct cdac_offsets<TypeDesc>
{
static constexpr size_t TypeAndFlags = offsetof(TypeDesc, m_typeAndFlags);
};

/*************************************************************************/
// This variant is used for parameterized types that have exactly one argument
Expand Down Expand Up @@ -263,6 +269,13 @@ class ParamTypeDesc : public TypeDesc {

// The type that is being modified
TypeHandle m_Arg;
template<typename T> friend struct ::cdac_offsets;
};

template<>
struct cdac_offsets<ParamTypeDesc>
{
static constexpr size_t TypeArg = offsetof(ParamTypeDesc, m_Arg);
};

/*************************************************************************/
Expand Down Expand Up @@ -381,6 +394,15 @@ class TypeVarTypeDesc : public TypeDesc

// index within declaring type or method, numbered from zero
unsigned int m_index;

template<typename T> friend struct ::cdac_offsets;
};

template<>
struct cdac_offsets<TypeVarTypeDesc>
{
static constexpr size_t Module = offsetof(TypeVarTypeDesc, m_pModule);
static constexpr size_t Token = offsetof(TypeVarTypeDesc, m_token);
};

/*************************************************************************/
Expand Down Expand Up @@ -467,6 +489,16 @@ class FnPtrTypeDesc : public TypeDesc

// Return type first, then argument types
TypeHandle m_RetAndArgTypes[1];

template<typename T> friend struct ::cdac_offsets;
}; // class FnPtrTypeDesc

template<>
struct cdac_offsets<FnPtrTypeDesc>
{
static constexpr size_t NumArgs = offsetof(FnPtrTypeDesc, m_NumArgs);
static constexpr size_t RetAndArgTypes = offsetof(FnPtrTypeDesc, m_RetAndArgTypes);
static constexpr size_t CallConv = offsetof(FnPtrTypeDesc, m_CallConv);
};

#endif // TYPEDESC_H
94 changes: 74 additions & 20 deletions src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,53 @@

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

// an opaque handle to a method table. See IMetadata.GetMethodTableData
internal readonly struct MethodTableHandle
// an opaque handle to a type handle. See IMetadata.GetMethodTableData
internal readonly struct TypeHandle
{
internal MethodTableHandle(TargetPointer address)
internal TypeHandle(TargetPointer address)
{
Address = address;
}

internal TargetPointer Address { get; }

internal bool IsNull => Address == 0;
}

internal enum CorElementType
{
Void = 1,
Boolean = 2,
Char = 3,
I1 = 4,
U1 = 5,
I2 = 6,
U2 = 7,
I4 = 8,
U4 = 9,
I8 = 0xa,
U8 = 0xb,
R4 = 0xc,
R8 = 0xd,
String = 0xe,
Ptr = 0xf,
Byref = 0x10,
ValueType = 0x11,
Class = 0x12,
Var = 0x13,
Array = 0x14,
GenericInst = 0x15,
TypedByRef = 0x16,
I = 0x18,
U = 0x19,
FnPtr = 0x1b,
Object = 0x1c,
SzArray = 0x1d,
MVar = 0x1e,
CModReqd = 0x1f,
CModOpt = 0x20,
Internal = 0x21,
Sentinel = 0x41,
}

internal interface IRuntimeTypeSystem : IContract
Expand All @@ -31,34 +69,50 @@ static IContract IContract.Create(Target target, int version)
};
}

#region MethodTable inspection APIs
public virtual MethodTableHandle GetMethodTableHandle(TargetPointer targetPointer) => throw new NotImplementedException();

public virtual TargetPointer GetModule(MethodTableHandle methodTable) => throw new NotImplementedException();
#region TypeHandle inspection APIs
public virtual TypeHandle GetTypeHandle(TargetPointer address) => throw new NotImplementedException();
public virtual TargetPointer GetModule(TypeHandle typeHandle) => throw new NotImplementedException();
// A canonical method table is either the MethodTable itself, or in the case of a generic instantiation, it is the
// MethodTable of the prototypical instance.
public virtual TargetPointer GetCanonicalMethodTable(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual TargetPointer GetParentMethodTable(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual TargetPointer GetCanonicalMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
public virtual TargetPointer GetParentMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();

public virtual uint GetBaseSize(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual uint GetBaseSize(TypeHandle typeHandle) => throw new NotImplementedException();
// The component size is only available for strings and arrays. It is the size of the element type of the array, or the size of an ECMA 335 character (2 bytes)
public virtual uint GetComponentSize(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual uint GetComponentSize(TypeHandle typeHandle) => throw new NotImplementedException();

// True if the MethodTable is the sentinel value associated with unallocated space in the managed heap
public virtual bool IsFreeObjectMethodTable(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual bool IsString(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual bool IsFreeObjectMethodTable(TypeHandle typeHandle) => throw new NotImplementedException();
public virtual bool IsString(TypeHandle typeHandle) => throw new NotImplementedException();
// True if the MethodTable represents a type that contains managed references
public virtual bool ContainsGCPointers(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual bool IsDynamicStatics(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual ushort GetNumMethods(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual ushort GetNumInterfaces(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual bool ContainsGCPointers(TypeHandle typeHandle) => throw new NotImplementedException();
public virtual bool IsDynamicStatics(TypeHandle typeHandle) => throw new NotImplementedException();
public virtual ushort GetNumMethods(TypeHandle typeHandle) => throw new NotImplementedException();
public virtual ushort GetNumInterfaces(TypeHandle typeHandle) => throw new NotImplementedException();

// Returns an ECMA-335 TypeDef table token for this type, or for its generic type definition if it is a generic instantiation
public virtual uint GetTypeDefToken(MethodTableHandle methodTable) => throw new NotImplementedException();
public virtual uint GetTypeDefToken(TypeHandle typeHandle) => throw new NotImplementedException();
// Returns the ECMA 335 TypeDef table Flags value (a bitmask of TypeAttributes) for this type,
// or for its generic type definition if it is a generic instantiation
public virtual uint GetTypeDefTypeAttributes(MethodTableHandle methodTable) => throw new NotImplementedException();
#endregion MethodTable inspection APIs
public virtual uint GetTypeDefTypeAttributes(TypeHandle typeHandle) => throw new NotImplementedException();

public virtual ReadOnlySpan<TypeHandle> GetInstantiation(TypeHandle typeHandle) => throw new NotImplementedException();
public virtual bool IsGenericTypeDefinition(TypeHandle typeHandle) => throw new NotImplementedException();

public virtual bool HasTypeParam(TypeHandle typeHandle) => throw new NotImplementedException();

// Element type of the type. NOTE: this drops the CorElementType.GenericInst, and CorElementType.String is returned as CorElementType.Class.
// If this returns CorElementType.ValueType it may be a normal valuetype or a "NATIVE" valuetype used to represent an interop view on a structure
// HasTypeParam will return true for cases where this is the interop view
public virtual CorElementType GetSignatureCorElementType(TypeHandle typeHandle) => throw new NotImplementedException();

// return true if the TypeHandle represents an array, and set the rank to either 0 (if the type is not an array), or the rank number if it is.
public virtual bool IsArray(TypeHandle typeHandle, out uint rank) => throw new NotImplementedException();
public virtual TypeHandle GetTypeParam(TypeHandle typeHandle) => throw new NotImplementedException();
public virtual bool IsGenericVariable(TypeHandle typeHandle, out TargetPointer module, out uint token) => throw new NotImplementedException();
public virtual bool IsFunctionPointer(TypeHandle typeHandle, out ReadOnlySpan<TypeHandle> retAndArgTypes, out byte callConv) => throw new NotImplementedException();
// Returns null if the TypeHandle is not a class/struct/generic variable
#endregion TypeHandle inspection APIs
}

internal struct RuntimeTypeSystem : IRuntimeTypeSystem
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ internal enum WFLAGS_LOW : uint
{
GenericsMask = 0x00000030,
GenericsMask_NonGeneric = 0x00000000, // no instantiation
GenericsMask_TypicalInstantiation = 0x00000030, // the type instantiated at its formal parameters, e.g. List<T>

StringArrayValues =
GenericsMask_NonGeneric |
Expand All @@ -26,7 +27,13 @@ internal enum WFLAGS_HIGH : uint
{
Category_Mask = 0x000F0000,
Category_Array = 0x00080000,
Category_IfArrayThenSzArray = 0x00020000,
Category_Array_Mask = 0x000C0000,
Category_ElementType_Mask = 0x000E0000,
Category_ValueType = 0x00040000,
Category_Nullable = 0x00050000,
Category_PrimitiveValueType = 0x00060000,
Category_TruePrimitive = 0x00070000,
Category_Interface = 0x000C0000,
ContainsGCPointers = 0x01000000,
HasComponentSize = 0x80000000, // This is set if lower 16 bits is used for the component size,
Expand Down Expand Up @@ -83,5 +90,6 @@ private bool TestFlagWithMask(WFLAGS2_ENUM mask, WFLAGS2_ENUM flag)
public bool HasInstantiation => !TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_NonGeneric);
public bool ContainsGCPointers => GetFlag(WFLAGS_HIGH.ContainsGCPointers) != 0;
public bool IsDynamicStatics => GetFlag(WFLAGS2_ENUM.DynamicStatics) != 0;
public bool IsGenericTypeDefinition => TestFlagWithMask(WFLAGS_LOW.GenericsMask, WFLAGS_LOW.GenericsMask_TypicalInstantiation);
}
}
Loading

0 comments on commit 2d5ec4f

Please sign in to comment.