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
7 changes: 4 additions & 3 deletions docs/design/datacontracts/RuntimeTypeSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ The contract depends on the following globals
| --- | --- |
| `FreeObjectMethodTablePointer` | A pointer to the address of a `MethodTable` used by the GC to indicate reclaimed memory
| `StaticsPointerMask` | For masking out a bit of DynamicStaticsInfo pointer fields
| `ArrayBaseSize` | The base size of an array object; used to compute multidimensional array rank from `MethodTable::BaseSize`

The contract additionally depends on these data descriptors

Expand Down Expand Up @@ -403,7 +404,6 @@ The contract additionally depends on these data descriptors
| `EEClass` | `NumStaticFields` | Count of static fields of the EEClass |
| `EEClass` | `NumThreadStaticFields` | Count of threadstatic fields of the EEClass |
| `EEClass` | `FieldDescList` | A list of fields in the type |
| `ArrayClass` | `Rank` | Rank of the associated array MethodTable |
| `TypeDesc` | `TypeAndFlags` | The lower 8 bits are the CorElementType of the `TypeDesc`, the upper 24 bits are reserved for flags |
| `ParamTypeDesc` | `TypeArg` | Associated type argument |
| `TypeVarTypeDesc` | `Module` | Pointer to module which defines the type variable |
Expand Down Expand Up @@ -695,8 +695,9 @@ Contracts used:
switch (typeHandle.Flags.GetFlag(WFLAGS_HIGH.Category_Mask))
{
case WFLAGS_HIGH.Category_Array:
TargetPointer clsPtr = GetClassPointer(typeHandle);
rank = // Read Rank field from ArrayClass contract using address clsPtr
// Multidim array: BaseSize = ArrayBaseSize + Rank * sizeof(uint) * 2
uint arrayBaseSize = target.ReadGlobal<uint>("ArrayBaseSize");
rank = (typeHandle.Flags.BaseSize - arrayBaseSize) / (sizeof(uint) * 2);
return true;

case WFLAGS_HIGH.Category_Array | WFLAGS_HIGH.Category_IfArrayThenSzArray:
Expand Down
48 changes: 23 additions & 25 deletions src/coreclr/vm/array.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ DWORD ArrayMethodDesc::GetAttrs()
// Generate a short sig (descr) for an array accessors
//

VOID ArrayClass::GenerateArrayAccessorCallSig(
static void GenerateArrayAccessorCallSig(
DWORD dwRank,
DWORD dwFuncType, // Load, store, or <init>
PCCOR_SIGNATURE *ppSig,// Generated signature
Expand Down Expand Up @@ -180,7 +180,7 @@ VOID ArrayClass::GenerateArrayAccessorCallSig(
//
// Based on code in class.cpp.
//
void ArrayClass::InitArrayMethodDesc(
static void InitArrayMethodDesc(
ArrayMethodDesc *pNewMD,
PCCOR_SIGNATURE pShortSig,
DWORD cShortSig,
Expand All @@ -200,9 +200,9 @@ void ArrayClass::InitArrayMethodDesc(
pNewMD->SetTemporaryEntryPoint(pamTracker);

#ifdef _DEBUG
_ASSERTE(pNewMD->GetMethodName() && GetDebugClassName());
_ASSERTE(pNewMD->GetMethodName() && pNewMD->GetMethodTable()->GetClass()->GetDebugClassName());
pNewMD->m_pszDebugMethodName = pNewMD->GetMethodName();
pNewMD->m_pszDebugClassName = GetDebugClassName();
pNewMD->m_pszDebugClassName = pNewMD->GetMethodTable()->GetClass()->GetDebugClassName();
pNewMD->m_pDebugMethodTable = pNewMD->GetMethodTable();
#endif // _DEBUG
}
Expand Down Expand Up @@ -294,33 +294,32 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy
cbMT += pParentClass->GetNumInterfaces() * sizeof(InterfaceInfo_t);


size_t cbArrayClass = 0;
size_t cbEEClass = 0;

if (pCanonMT == NULL)
{
// Allocate ArrayClass, MethodTable, and class name in one alloc.
// Remember to pad allocation size for ArrayClass portion to ensure MethodTable is pointer aligned.
cbArrayClass = ALIGN_UP(sizeof(ArrayClass), sizeof(void*));
// Allocate EEClass, MethodTable, and class name in one alloc.
// Remember to pad allocation size for EEClass portion to ensure MethodTable is pointer aligned.
cbEEClass = ALIGN_UP(sizeof(EEClass), sizeof(void*));
}

// ArrayClass already includes one void*
LoaderAllocator* pAllocator= this->GetLoaderAllocator();
BYTE* pMemory = (BYTE *)pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbArrayClass) +
BYTE* pMemory = (BYTE *)pamTracker->Track(pAllocator->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbEEClass) +
S_SIZE_T(cbMT)));

// Note: Memory allocated on loader heap is zero filled
// memset(pMemory, 0, sizeof(ArrayClass) + cbMT);
// memset(pMemory, 0, sizeof(EEClass) + cbMT);

ArrayClass* pClass = NULL;
EEClass* pClass = NULL;

if (pCanonMT == NULL)
{
pClass = ::new (pMemory) ArrayClass();
pClass = ::new (pMemory) EEClass();
}

// Head of MethodTable memory (starts after ArrayClass), this points at the GCDesc stuff in front
// Head of MethodTable memory (starts after EEClass), this points at the GCDesc stuff in front
// of a method table (if needed)
BYTE* pMTHead = pMemory + cbArrayClass + cbCGCDescData;
BYTE* pMTHead = pMemory + cbEEClass + cbCGCDescData;

MethodTable* pMT = (MethodTable *) pMTHead;

Expand All @@ -336,7 +335,6 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy
{
pClass->SetInternalCorElementType(arrayKind);
pClass->SetAttrClass (tdPublic | tdSerializable | tdSealed); // This class is public, serializable, sealed
pClass->SetRank (Rank);
pClass->SetMethodTable (pMT);

// Fill In the method table
Expand Down Expand Up @@ -505,9 +503,9 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy
PCCOR_SIGNATURE pSig;
DWORD cSig;

pClass->GenerateArrayAccessorCallSig(dwFuncRank, dwFuncType, &pSig, &cSig, pAllocator, pamTracker, FALSE);
GenerateArrayAccessorCallSig(dwFuncRank, dwFuncType, &pSig, &cSig, pAllocator, pamTracker, FALSE);

pClass->InitArrayMethodDesc(pNewMD, pSig, cSig, numVirtuals + dwMethodIndex, pamTracker);
InitArrayMethodDesc(pNewMD, pSig, cSig, numVirtuals + dwMethodIndex, pamTracker);

dwMethodIndex++;
}
Expand Down Expand Up @@ -882,13 +880,13 @@ Stub *GenerateArrayOpStub(ArrayMethodDesc* pMD)
{
// The stub has to have signature with explicit hidden argument instead of CORINFO_CALLCONV_PARAMTYPE.
// Generate a new signature for the stub here.
((ArrayClass*)(pMD->GetMethodTable()->GetClass()))->GenerateArrayAccessorCallSig(pMD->GetMethodTable()->GetRank(),
ArrayMethodDesc::ARRAY_FUNC_ADDRESS,
&pSig,
&cbSig,
pMD->GetLoaderAllocator(),
&amTracker,
1);
GenerateArrayAccessorCallSig(pMD->GetMethodTable()->GetRank(),
ArrayMethodDesc::ARRAY_FUNC_ADDRESS,
&pSig,
&cbSig,
pMD->GetLoaderAllocator(),
&amTracker,
1);
}
else
{
Expand Down
2 changes: 0 additions & 2 deletions src/coreclr/vm/ceeload.h
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ class ModuleBase
{
#ifdef DACCESS_COMPILE
friend class ClrDataAccess;
friend class NativeImageDumper;
#endif

friend class DataImage;
Expand Down Expand Up @@ -603,7 +602,6 @@ class Module : public ModuleBase
{
#ifdef DACCESS_COMPILE
friend class ClrDataAccess;
friend class NativeImageDumper;
#endif

friend class DataImage;
Expand Down
60 changes: 1 addition & 59 deletions src/coreclr/vm/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowHR(HRESULT hr);
* Forward declarations
*/
class AppDomain;
class ArrayClass;
class ArrayMethodDesc;
class Assembly;
class ClassLoader;
Expand Down Expand Up @@ -726,6 +725,7 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
friend class FieldDesc;
friend class CheckAsmOffsets;
friend class ClrDataAccess;
friend MethodTable* Module::CreateArrayMethodTable(TypeHandle, CorElementType, unsigned, AllocMemTracker*);

/************************************
* PUBLIC INSTANCE METHODS
Expand Down Expand Up @@ -1913,64 +1913,6 @@ class DelegateEEClass : public EEClass
};


typedef DPTR(ArrayClass) PTR_ArrayClass;


// Dynamically generated array class structure
class ArrayClass : public EEClass
{
friend MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementType arrayKind, unsigned Rank, AllocMemTracker *pamTracker);

#ifndef DACCESS_COMPILE
ArrayClass() { LIMITED_METHOD_CONTRACT; }
#else
friend class NativeImageDumper;
#endif

private:

DAC_ALIGNAS(EEClass) // Align the first member to the alignment of the base class
unsigned char m_rank;

public:
DWORD GetRank() {
LIMITED_METHOD_CONTRACT;
SUPPORTS_DAC;
return m_rank;
}
void SetRank (unsigned Rank) {
LIMITED_METHOD_CONTRACT;
// The only code path calling this function is code:ClassLoader::CreateTypeHandleForTypeKey, which has
// checked the rank already. Assert that the rank is less than MAX_RANK and that it fits in one byte.
_ASSERTE((Rank <= MAX_RANK) && (Rank <= (unsigned char)(-1)));
m_rank = (unsigned char)Rank;
}

// Allocate a new MethodDesc for the methods we add to this class
void InitArrayMethodDesc(
ArrayMethodDesc* pNewMD,
PCCOR_SIGNATURE pShortSig,
DWORD cShortSig,
DWORD dwVtableSlot,
AllocMemTracker *pamTracker);

// Generate a short sig for an array accessor
VOID GenerateArrayAccessorCallSig(DWORD dwRank,
DWORD dwFuncType, // Load, store, or <init>
PCCOR_SIGNATURE *ppSig, // Generated signature
DWORD * pcSig, // Generated signature size
LoaderAllocator *pLoaderAllocator,
AllocMemTracker *pamTracker,
BOOL fForStubAsIL
);

friend struct ::cdac_data<ArrayClass>;
};

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

inline EEClassLayoutInfo *EEClass::GetLayoutInfo()
{
Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/classcompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
* Forward declarations
*/
class AppDomain;
class ArrayClass;
class ArrayMethodDesc;
class Assembly;
class ClassLoader;
Expand Down
6 changes: 1 addition & 5 deletions src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -343,11 +343,6 @@ CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumThreadStaticFields, cdac_data<EEClass>::
CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumNonVirtualSlots, cdac_data<EEClass>::NumNonVirtualSlots)
CDAC_TYPE_END(EEClass)

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

CDAC_TYPE_BEGIN(GenericsDictInfo)
CDAC_TYPE_INDETERMINATE(GenericsDictInfo)
CDAC_TYPE_FIELD(GenericsDictInfo, /*uint16*/, NumDicts, offsetof(GenericsDictInfo, m_wNumDicts))
Expand Down Expand Up @@ -1162,6 +1157,7 @@ CDAC_GLOBAL(HashMapSlotsPerBucket, uint32, SLOTS_PER_BUCKET)
CDAC_GLOBAL(HashMapValueMask, uint64, VALUE_MASK)
CDAC_GLOBAL(MethodDescAlignment, uint64, MethodDesc::ALIGNMENT)
CDAC_GLOBAL(ObjectHeaderSize, uint64, OBJHEADER_SIZE)
CDAC_GLOBAL(ArrayBaseSize, uint32, ARRAYBASE_BASESIZE)
CDAC_GLOBAL(SyncBlockValueToObjectOffset, uint16, OBJHEADER_SIZE - cdac_data<ObjHeader>::SyncBlockValue)
CDAC_GLOBAL(StubCodeBlockLast, uint8, STUB_CODE_BLOCK_LAST)
CDAC_GLOBAL(DefaultADID, uint32, DefaultADID)
Expand Down
12 changes: 1 addition & 11 deletions src/coreclr/vm/methodtable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1460,8 +1460,7 @@ BOOL MethodTable::ArrayIsInstanceOf(MethodTable* pTargetMT, TypeHandlePairList*
PRECONDITION(pTargetMT->IsArray());
} CONTRACTL_END;

// GetRank touches EEClass. Try to avoid it for SZArrays.
if (pTargetMT->GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY)
if (!pTargetMT->IsMultiDimArray())
{
if (this->IsMultiDimArray())
{
Expand Down Expand Up @@ -7790,15 +7789,6 @@ MethodTable::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)

if (pClass.IsValid())
{
if (IsArray())
{
// This is kind of a workaround, in that ArrayClass is derived from EEClass, but
// it's not virtual, we only cast if the IsArray() predicate holds above.
// For minidumps, DAC will choke if we don't have the full size given
// by ArrayClass available. If ArrayClass becomes more complex, it
// should get it's own EnumMemoryRegions().
DacEnumMemoryRegion(dac_cast<TADDR>(pClass), sizeof(ArrayClass));
}
pClass->EnumMemoryRegions(flags, this);
}
else
Expand Down
7 changes: 0 additions & 7 deletions src/coreclr/vm/methodtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
* Forward Declarations
*/
class AppDomain;
class ArrayClass;
class ArrayMethodDesc;
class ClassLoader;
class FCallMethodDesc;
Expand Down Expand Up @@ -316,9 +315,6 @@ typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo;
struct MethodTableAuxiliaryData
{
friend class MethodTable;
#if defined(DACCESS_COMPILE)
friend class NativeImageDumper;
#endif

enum
{
Expand Down Expand Up @@ -970,9 +966,6 @@ class MethodTable
friend class EEClass;
friend class MethodTableBuilder;
friend class CheckAsmOffsets;
#if defined(DACCESS_COMPILE)
friend class NativeImageDumper;
#endif

public:
// Do some sanity checking to make sure it's a method table
Expand Down
6 changes: 5 additions & 1 deletion src/coreclr/vm/methodtable.inl
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,11 @@ inline DWORD MethodTable::GetRank()
if (GetFlag(enum_flag_Category_IfArrayThenSzArray))
return 1; // ELEMENT_TYPE_SZARRAY
else
return dac_cast<PTR_ArrayClass>(GetClass())->GetRank();
{
// Multidim array: BaseSize = ARRAYBASE_BASESIZE + Rank * sizeof(DWORD) * 2
DWORD boundsSize = GetBaseSize() - ARRAYBASE_BASESIZE;
return boundsSize / (sizeof(DWORD) * 2);
}
}

//==========================================================================================
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/object.inl
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ inline /* static */ unsigned ArrayBase::GetLowerBoundsOffset(MethodTable* pMT)
// Lower bounds info is after total bounds info
// and total bounds info has rank elements
return GetBoundsOffset(pMT) +
dac_cast<PTR_ArrayClass>(pMT->GetClass())->GetRank() *
pMT->GetRank() *
sizeof(INT32);
}

Expand Down
1 change: 0 additions & 1 deletion src/coreclr/vm/vars.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ class LoaderHeap;
class IGCHeap;
class Object;
class StringObject;
class ArrayClass;
class MethodTable;
class MethodDesc;
class SyncBlockCache;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ public enum DataType
DynamicStaticsInfo,
EEClass,
CoreLibBinder,
ArrayClass,
MethodTableAuxiliaryData,
GenericsDictInfo,
TypeDesc,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public static class Globals

public const string MethodDescAlignment = nameof(MethodDescAlignment);
public const string ObjectHeaderSize = nameof(ObjectHeaderSize);
public const string ArrayBaseSize = nameof(ArrayBaseSize);
public const string SyncBlockValueToObjectOffset = nameof(SyncBlockValueToObjectOffset);

public const string SyncTableEntries = nameof(SyncTableEntries);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,8 +731,10 @@ public bool IsArray(TypeHandle typeHandle, out uint rank)
switch (methodTable.Flags.GetFlag(MethodTableFlags_1.WFLAGS_HIGH.Category_Mask))
{
case MethodTableFlags_1.WFLAGS_HIGH.Category_Array:
TargetPointer clsPtr = GetClassPointer(typeHandle);
rank = _target.ProcessedData.GetOrAdd<Data.ArrayClass>(clsPtr).Rank;
// Multidim array: BaseSize = ArrayBaseSize + Rank * sizeof(uint) * 2
uint arrayBaseSize = _target.ReadGlobal<uint>(Constants.Globals.ArrayBaseSize);
uint boundsSize = methodTable.Flags.BaseSize - arrayBaseSize;
rank = boundsSize / (sizeof(uint) * 2);
return true;

case MethodTableFlags_1.WFLAGS_HIGH.Category_Array | MethodTableFlags_1.WFLAGS_HIGH.Category_IfArrayThenSzArray:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,3 @@ public EEClass(Target target, TargetPointer address)
public TargetPointer FieldDescList { get; init; }
public ushort NumNonVirtualSlots { get; init; }
}

internal sealed class ArrayClass : IData<ArrayClass>
{
static ArrayClass IData<ArrayClass>.Create(Target target, TargetPointer address) => new ArrayClass(target, address);
public ArrayClass(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.ArrayClass);

Rank = target.Read<byte>(address + (ulong)type.Fields[nameof(Rank)].Offset);
}

public byte Rank { get; init; }
}
Loading
Loading