Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cdac] start of RuntimeTypeSystem contract; implement GetMethodTableData SOS method #103444

Merged
merged 72 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
b98afa8
Implement GetThreadStoreData in cDAC
elinor-fung May 16, 2024
890f9c6
Add placeholder for getting thread data
elinor-fung May 17, 2024
41ba95c
Apply suggestions from code review
elinor-fung May 23, 2024
29214f0
WIP: Metadata contract
lambdageek May 14, 2024
8beced0
Merge remote-tracking branch 'elinor-fung/cdac-threadstore' into cdac…
lambdageek May 29, 2024
5213286
fix build
lambdageek May 29, 2024
622e01a
WIP: ValidateMethodTable
lambdageek May 29, 2024
e112416
DataCache.GetOrAdd
elinor-fung May 29, 2024
ae1eac9
wip
lambdageek May 30, 2024
79ea0d4
Merge remote-tracking branch 'elinor-fung/cdac-threadstore' into cdac…
lambdageek May 30, 2024
5c696da
checkpoint: ValidateWithPossibleAV
lambdageek May 30, 2024
6eaf80f
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek May 30, 2024
3a7808d
checkpoint EEClass from MethodTable
lambdageek May 31, 2024
66e5476
checkpoint: ValidateMethodTablePointer
lambdageek May 31, 2024
95914b8
cp: delegate from legacy dac
lambdageek May 31, 2024
2b8fda3
add Metadata to runtime contract descriptor
lambdageek Jun 11, 2024
5c7d2ac
checkpoint: more MethodTable fields
lambdageek Jun 12, 2024
7be5c60
checkpoint GetMethodTableData implemented
lambdageek Jun 13, 2024
30b7b26
checkpoint: same answer as legacy dac
lambdageek Jun 13, 2024
187bcbe
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek Jun 14, 2024
f0d1fcb
new flags for statics
lambdageek Jun 14, 2024
c53db36
fix GCC build
lambdageek Jun 14, 2024
b70bb1d
WIP: opaque MethodTableHandle
lambdageek Jun 17, 2024
a65fd50
Add contract accessors for MethodTableHandle
lambdageek Jun 18, 2024
6f844bf
fixup
lambdageek Jun 18, 2024
76e0384
simplify FreeObjectMethodTable handling
lambdageek Jun 18, 2024
cdb7543
cleanup
lambdageek Jun 18, 2024
78830ea
fixup
lambdageek Jun 18, 2024
fbbd45b
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek Jun 18, 2024
32665b2
[dac] Return canonical MethodTable instead of EEClass
lambdageek Jun 18, 2024
acf8436
Delete unreferenced MethodTable flags
lambdageek Jun 18, 2024
f246c86
add Metadata contract doc; fixups
lambdageek Jun 19, 2024
8409f3e
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek Jun 20, 2024
08d069a
rename DacpMethodTableData:klass field
lambdageek Jun 20, 2024
674655f
document GetMethodTableData string baseSize adjustment
lambdageek Jun 20, 2024
2ae4625
Apply suggestions from code review
lambdageek Jun 20, 2024
e18a2be
fix typo
lambdageek Jun 21, 2024
846e779
rename flag to ContainsGCPointers
lambdageek Jun 21, 2024
383af83
[vm] rename ContainsPointers flag to ContainsGCPointers
lambdageek Jun 21, 2024
0f8c7f1
code style suggestions from code review
lambdageek Jun 21, 2024
7a337c1
BUGFIX: read DwFlags2 from the correct offset
lambdageek Jun 21, 2024
a7c8158
hide utility methods
lambdageek Jun 21, 2024
f4a3493
remove EEClass_1 struct
lambdageek Jun 21, 2024
10624c7
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek Jun 21, 2024
65cc531
rename data descriptor members to remove prefixes
lambdageek Jun 21, 2024
d526087
cleanup the contract docs
lambdageek Jun 21, 2024
0a4112e
remove hungariant notation prefixes from data descriptors
lambdageek Jun 24, 2024
1071ca4
DAC: always set wNumVirtuals and wNumVtableSlots to 0
lambdageek Jun 25, 2024
6c5235c
Remove NumVirtuals and NumVtableSlots from Metadata.md
lambdageek Jun 27, 2024
95b728a
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek Jun 28, 2024
6573e14
"untrusted" -> "non-validated"
lambdageek Jun 28, 2024
8596892
merge fixup
lambdageek Jun 28, 2024
6eabf42
remove #if 0
lambdageek Jun 28, 2024
4d3200d
cleanup
lambdageek Jun 28, 2024
2e66740
pull test target helpers out
lambdageek Jun 28, 2024
8533148
Add one FreeObjectMethodTable unit test
lambdageek Jul 1, 2024
77cf405
clean up the test helpers a bit
lambdageek Jul 2, 2024
f9bce4c
validate that a mock system object is a valid method table
lambdageek Jul 2, 2024
3721992
code review feedback and more tests:
lambdageek Jul 2, 2024
1af7c80
Update src/coreclr/gc/env/gcenv.object.h
lambdageek Jul 2, 2024
993ae1d
Update src/native/managed/cdacreader/src/Contracts/Metadata_1.MethodT…
lambdageek Jul 2, 2024
f04d880
Address code review feedback
lambdageek Jul 2, 2024
76859d1
move non-validated MethodTable handling to a separate class
lambdageek Jul 2, 2024
a12a407
clear up ComponentSize contract spec and impl
lambdageek Jul 2, 2024
9cf4c5a
rename Metadata -> RuntimeTypeSystem
lambdageek Jul 3, 2024
1814848
add validation failure test; change validation to throw InvalidOperat…
lambdageek Jul 3, 2024
89f98a3
Merge remote-tracking branch 'origin/main' into cdac-wip
lambdageek Jul 3, 2024
a0989fa
Update src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem_…
lambdageek Jul 3, 2024
617bf62
spellcheck
lambdageek Jul 3, 2024
815ff0d
Merge branch 'cdac-wip' of github.com:lambdageek/runtime into cdac-wip
lambdageek Jul 3, 2024
1ab4f08
Add a generic instance test
lambdageek Jul 3, 2024
ee3a362
add array instance test
lambdageek Jul 3, 2024
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
1 change: 1 addition & 0 deletions src/coreclr/debug/daccess/dacimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -1231,6 +1231,7 @@ class ClrDataAccess

HRESULT GetThreadDataImpl(CLRDATA_ADDRESS threadAddr, struct DacpThreadData *threadData);
HRESULT GetThreadStoreDataImpl(struct DacpThreadStoreData *data);
HRESULT GetMethodTableDataImpl(CLRDATA_ADDRESS mt, struct DacpMethodTableData *data);

BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);
#ifndef TARGET_UNIX
Expand Down
52 changes: 49 additions & 3 deletions src/coreclr/debug/daccess/request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,14 @@ BOOL DacValidateMethodTable(PTR_MethodTable pMT, BOOL &bIsFree)
// In rare cases, we've seen the standard check above pass when it shouldn't.
// Insert additional/ad-hoc tests below.

// FIXME(cdac): ak - this check is trivially true - GetCl() runs in the DAC and synthesizes a token with a mdtTypeDef table
// so the check is always true.
#if 0
// Metadata token should look valid for a class
mdTypeDef td = pMT->GetCl();
if (td != mdTokenNil && TypeFromToken(td) != mdtTypeDef)
goto BadMethodTable;
#endif

// BaseSize should always be greater than 0 for valid objects (unless it's an interface)
// For strings, baseSize is not ptr-aligned
Expand Down Expand Up @@ -1765,12 +1769,55 @@ ClrDataAccess::GetMethodTableData(CLRDATA_ADDRESS mt, struct DacpMethodTableData
return E_INVALIDARG;

SOSDacEnter();
if (m_cdacSos != NULL)
{
// Try the cDAC first - it will return E_NOTIMPL if it doesn't support this method yet. Fall back to the DAC.
hr = m_cdacSos->GetMethodTableData(mt, MTData);
if (FAILED(hr))
{
hr = GetMethodTableDataImpl(mt, MTData);
}
#ifdef _DEBUG
else
{
// Assert that the data is the same as what we get from the DAC.
DacpMethodTableData mtDataLocal;
HRESULT hrLocal = GetMethodTableDataImpl(mt, &mtDataLocal);
_ASSERTE(hr == hrLocal);
_ASSERTE(MTData->BaseSize == mtDataLocal.BaseSize);
_ASSERTE(MTData->ComponentSize == mtDataLocal.ComponentSize);
_ASSERTE(MTData->bIsFree == mtDataLocal.bIsFree);
_ASSERTE(MTData->Module == mtDataLocal.Module);
_ASSERTE(MTData->Class == mtDataLocal.Class);
_ASSERTE(MTData->ParentMethodTable == mtDataLocal.ParentMethodTable);
_ASSERTE(MTData->wNumInterfaces == mtDataLocal.wNumInterfaces);
_ASSERTE(MTData->wNumMethods == mtDataLocal.wNumMethods);
_ASSERTE(MTData->wNumVtableSlots == mtDataLocal.wNumVtableSlots);
_ASSERTE(MTData->wNumVirtuals == mtDataLocal.wNumVirtuals);
_ASSERTE(MTData->cl == mtDataLocal.cl);
_ASSERTE(MTData->dwAttrClass = mtDataLocal.dwAttrClass);
_ASSERTE(MTData->bContainsPointers == mtDataLocal.bContainsPointers);
_ASSERTE(MTData->bIsShared == mtDataLocal.bIsShared);
_ASSERTE(MTData->bIsDynamic == mtDataLocal.bIsDynamic);
}
#endif
}
else
{
hr = GetMethodTableDataImpl (mt, MTData);
}
SOSDacLeave();
return hr;
}

HRESULT
ClrDataAccess::GetMethodTableDataImpl(CLRDATA_ADDRESS mt, struct DacpMethodTableData *MTData)
{
PTR_MethodTable pMT = PTR_MethodTable(TO_TADDR(mt));
BOOL bIsFree = FALSE;
if (!DacValidateMethodTable(pMT, bIsFree))
{
hr = E_INVALIDARG;
return E_INVALIDARG;
}
else
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
{
Expand All @@ -1797,8 +1844,7 @@ ClrDataAccess::GetMethodTableData(CLRDATA_ADDRESS mt, struct DacpMethodTableData
}
}

SOSDacLeave();
return hr;
return S_OK;
}

HRESULT
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/debug/runtimeinfo/contractpointerdata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
#include <stdint.h>

#include "threads.h"
#include "vars.hpp"

extern "C"
{

lambdageek marked this conversation as resolved.
Show resolved Hide resolved
// without an extern declaration, clang does not emit this global into the object file
extern const uintptr_t contractDescriptorPointerData[];

Expand Down
1 change: 1 addition & 0 deletions src/coreclr/debug/runtimeinfo/contracts.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
// cdac-build-tool can take multiple "-c contract_file" arguments
// so to conditionally include contracts, put additional contracts in a separate file
{
"Metadata": 1,
"Thread": 1,
"SOSBreakingChangeVersion": 1 // example contract: "runtime exports an SOS breaking change version global"
}
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "static_assert.h"

#include <sospriv.h>
#include "methodtable.h"
#include "threads.h"

// begin blob definition
Expand Down
29 changes: 29 additions & 0 deletions src/coreclr/debug/runtimeinfo/datadescriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,34 @@ CDAC_TYPE_BEGIN(GCHandle)
CDAC_TYPE_SIZE(sizeof(OBJECTHANDLE))
CDAC_TYPE_END(GCHandle)

// Metadata

CDAC_TYPE_BEGIN(MethodTable)
CDAC_TYPE_INDETERMINATE(MethodTable)
CDAC_TYPE_FIELD(MethodTable, /*uint32*/, DwFlags, cdac_offsets<MethodTable>::m_dwFlags)
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
CDAC_TYPE_FIELD(MethodTable, /*uint32*/, BaseSize, cdac_offsets<MethodTable>::m_BaseSize)
CDAC_TYPE_FIELD(MethodTable, /*uint32*/, DwFlags2, cdac_offsets<MethodTable>::m_dwFlags2)
CDAC_TYPE_FIELD(MethodTable, /*nuint*/, EEClassOrCanonMT, cdac_offsets<MethodTable>::m_pEEClassOrCanonMT)
CDAC_TYPE_FIELD(MethodTable, /*pointer*/, Module, cdac_offsets<MethodTable>::m_pModule)
CDAC_TYPE_FIELD(MethodTable, /*pointer*/, AuxiliaryData, cdac_offsets<MethodTable>::m_pAuxiliaryData)
CDAC_TYPE_FIELD(MethodTable, /*pointer*/, ParentMethodTable, cdac_offsets<MethodTable>::m_pParentMethodTable)
CDAC_TYPE_FIELD(MethodTable, /*uint16*/, NumInterfaces, cdac_offsets<MethodTable>::m_wNumInterfaces)
CDAC_TYPE_FIELD(MethodTable, /*uint16*/, NumVirtuals, cdac_offsets<MethodTable>::m_wNumVirtuals)
CDAC_TYPE_END(MethodTable)

CDAC_TYPE_BEGIN(EEClass)
CDAC_TYPE_INDETERMINATE(EEClass)
CDAC_TYPE_FIELD(EEClass, /*pointer*/, MethodTable, cdac_offsets<EEClass>::m_pMethodTable)
CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumMethods, cdac_offsets<EEClass>::m_NumMethods)
CDAC_TYPE_FIELD(EEClass, /*uint16*/, NumNonVirtualSlots, cdac_offsets<EEClass>::m_NumNonVirtualSlots)
CDAC_TYPE_FIELD(EEClass, /*uint32*/, DwAttrClass, cdac_offsets<EEClass>::m_dwAttrClass)
CDAC_TYPE_END(EEClass)

CDAC_TYPE_BEGIN(MethodTableAuxiliaryData)
CDAC_TYPE_INDETERMINATE(MethodTableAuxiliaryData)
CDAC_TYPE_FIELD(MethodTableAuxiliaryData, /*uint32*/, DwFlags, offsetof(MethodTableAuxiliaryData, m_dwFlags))
CDAC_TYPE_END(MethodTableAuxiliaryData)

CDAC_TYPES_END()

CDAC_GLOBALS_BEGIN()
Expand All @@ -138,6 +166,7 @@ CDAC_GLOBAL(FeatureEHFunclets, uint8, 1)
CDAC_GLOBAL(FeatureEHFunclets, uint8, 0)
#endif
CDAC_GLOBAL(SOSBreakingChangeVersion, uint8, SOS_BREAKING_CHANGE_VERSION)
CDAC_GLOBAL_POINTER(FreeObjectMethodTable, &::g_pFreeObjectMethodTable)
CDAC_GLOBALS_END()

#undef CDAC_BASELINE
Expand Down
4 changes: 2 additions & 2 deletions src/coreclr/vm/cdacoffsets.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
//
// If the offset of some field F in class C must be provided to cDAC, but the field is private, the
// class C should declare cdac_offsets<T> as a friend:
//
// friend template<typename T> struct cdac_offsets;
//
// template<typename T> friend struct ::cdac_offsets;
//
// and provide a specialization cdac_offsets<C> with a constexpr size_t member providing the offset:
//
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/vm/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -1817,6 +1817,15 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW!
}
#endif // !DACCESS_COMPILE

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

template<> struct ::cdac_offsets<EEClass>
{
static constexpr size_t m_pMethodTable = offsetof(EEClass, m_pMethodTable);
static constexpr size_t m_NumMethods = offsetof(EEClass, m_NumMethods);
static constexpr size_t m_NumNonVirtualSlots = offsetof(EEClass, m_NumNonVirtualSlots);
static constexpr size_t m_dwAttrClass = offsetof(EEClass, m_dwAttrClass);
};

// --------------------------------------------------------------------------------------------
Expand Down
15 changes: 15 additions & 0 deletions src/coreclr/vm/methodtable.h
Original file line number Diff line number Diff line change
Expand Up @@ -3659,8 +3659,23 @@ public :
public:

BOOL Validate ();

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

template<> struct ::cdac_offsets<MethodTable>
{
static constexpr size_t m_dwFlags = offsetof(MethodTable, m_dwFlags);
static constexpr size_t m_BaseSize = offsetof(MethodTable, m_BaseSize);
static constexpr size_t m_dwFlags2 = offsetof(MethodTable, m_dwFlags2);
static constexpr size_t m_pEEClassOrCanonMT = offsetof(MethodTable, m_pEEClass);
static constexpr size_t m_pModule = offsetof(MethodTable, m_pModule);
static constexpr size_t m_pAuxiliaryData = offsetof(MethodTable, m_pAuxiliaryData);
static constexpr size_t m_pParentMethodTable = offsetof(MethodTable, m_pParentMethodTable);
static constexpr size_t m_wNumInterfaces = offsetof(MethodTable, m_wNumInterfaces);
static constexpr size_t m_wNumVirtuals = offsetof(MethodTable, m_wNumVirtuals);
};

#ifndef CROSSBITNESS_COMPILE
static_assert_no_msg(sizeof(MethodTable) == SIZEOF__MethodTable_);
#endif
Expand Down
2 changes: 2 additions & 0 deletions src/native/managed/cdacreader/src/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,7 @@ internal static class Globals
internal const string GCThread = nameof(GCThread);

internal const string SOSBreakingChangeVersion = nameof(SOSBreakingChangeVersion);

internal const string FreeObjectMethodTable = nameof(FreeObjectMethodTable);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using UntrustedMethodTable = Microsoft.Diagnostics.DataContractReader.Contracts.UntrustedMethodTable_1;
using MethodTable = Microsoft.Diagnostics.DataContractReader.Contracts.MethodTable_1;
using UntrustedEEClass = Microsoft.Diagnostics.DataContractReader.Contracts.UntrustedEEClass_1;
using EEClass = Microsoft.Diagnostics.DataContractReader.Contracts.EEClass_1;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal partial struct Metadata_1
{
[Flags]
internal enum WFLAGS_LOW : uint
{
// We are overloading the low 2 bytes of m_dwFlags to be a component size for Strings
// and Arrays and some set of flags which we can be assured are of a specified state
// for Strings / Arrays, currently these will be a bunch of generics flags which don't
// apply to Strings / Arrays.

UNUSED_ComponentSize_1 = 0x00000001,
// GC depends on this bit
HasCriticalFinalizer = 0x00000002, // finalizer must be run on Appdomain Unload
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
StaticsMask = 0x0000000C,
StaticsMask_NonDynamic = 0x00000000,
StaticsMask_Dynamic = 0x00000008, // dynamic statics (EnC, reflection.emit)
StaticsMask_Generics = 0x00000004, // generics statics
StaticsMask_CrossModuleGenerics = 0x0000000C, // cross module generics statics (NGen)
StaticsMask_IfGenericsThenCrossModule = 0x00000008, // helper constant to get rid of unnecessary check


GenericsMask = 0x00000030,
GenericsMask_NonGeneric = 0x00000000, // no instantiation
GenericsMask_GenericInst = 0x00000010, // regular instantiation, e.g. List<String>
GenericsMask_SharedInst = 0x00000020, // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
GenericsMask_TypicalInst = 0x00000030, // the type instantiated at its formal parameters, e.g. List<T>

HasVariance = 0x00000100, // This is an instantiated type some of whose type parameters are co- or contra-variant

HasDefaultCtor = 0x00000200,
HasPreciseInitCctors = 0x00000400, // Do we need to run class constructors at allocation time? (Not perf important, could be moved to EEClass

// if FEATURE_HFA
IsHFA = 0x00000800, // This type is an HFA (Homogeneous Floating-point Aggregate)

// if UNIX_AMD64_ABI
IsRegStructPassed = 0x00000800, // This type is a System V register passed struct.

IsByRefLike = 0x00001000,

HasBoxedRegularStatics = 0x00002000,
HasBoxedThreadStatics = 0x00004000,

// In a perfect world we would fill these flags using other flags that we already have
// which have a constant value for something which has a component size.
UNUSED_ComponentSize_7 = 0x00008000,

// IMPORTANT! IMPORTANT! IMPORTANT!
//
// As you change the flags in WFLAGS_LOW_ENUM you also need to change this
// to be up to date to reflect the default values of those flags for the
// case where this MethodTable is for a String or Array
StringArrayValues = //SET_FALSE(enum_flag_HasCriticalFinalizer) |
StaticsMask_NonDynamic |
//SET_FALSE(enum_flag_HasBoxedRegularStatics) |
//SET_FALSE(enum_flag_HasBoxedThreadStatics) |
GenericsMask_NonGeneric |
//SET_FALSE(enum_flag_HasVariance) |
//SET_FALSE(enum_flag_HasDefaultCtor) |
//SET_FALSE(enum_flag_HasPreciseInitCctors)
0,
}

[Flags]
internal enum WFLAGS_HIGH : uint
{
Category_Mask = 0x000F0000,

Category_Class = 0x00000000,
Category_Unused_1 = 0x00010000,
Category_Unused_2 = 0x00020000,
Category_Unused_3 = 0x00030000,

Category_ValueType = 0x00040000,
Category_ValueType_Mask = 0x000C0000,
Category_Nullable = 0x00050000, // sub-category of ValueType
Category_PrimitiveValueType = 0x00060000, // sub-category of ValueType, Enum or primitive value type
Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.)

Category_Array = 0x00080000,
Category_Array_Mask = 0x000C0000,
// Category_IfArrayThenUnused = 0x00010000, // sub-category of Array
Category_IfArrayThenSzArray = 0x00020000, // sub-category of Array

Category_Interface = 0x000C0000,
Category_Unused_4 = 0x000D0000,
Category_Unused_5 = 0x000E0000,
Category_Unused_6 = 0x000F0000,

Category_ElementTypeMask = 0x000E0000, // bits that matter for element type mask

// GC depends on this bit
HasFinalizer = 0x00100000, // instances require finalization

IDynamicInterfaceCastable = 0x10000000, // class implements IDynamicInterfaceCastable interface

ICastable = 0x00400000, // class implements ICastable interface

RequiresAlign8 = 0x00800000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)

ContainsPointers = 0x01000000,

HasTypeEquivalence = 0x02000000, // can be equivalent to another type

IsTrackedReferenceWithFinalizer = 0x04000000,

// GC depends on this bit
Collectible = 0x00200000,
ContainsGenericVariables = 0x20000000, // we cache this flag to help detect these efficiently and
// to detect this condition when restoring

ComObject = 0x40000000, // class is a com object

HasComponentSize = 0x80000000, // This is set if component size is used for flags.

// Types that require non-trivial interface cast have this bit set in the category
NonTrivialInterfaceCast = Category_Array
| ComObject
| ICastable
| IDynamicInterfaceCastable
| Category_ValueType

}
}
internal interface IMethodTableFlags
{
public uint DwFlags { get; }
public uint DwFlags2 { get; }
public uint BaseSize { get; }

private Metadata_1.WFLAGS_HIGH FlagsHigh => (Metadata_1.WFLAGS_HIGH)DwFlags;
private Metadata_1.WFLAGS_LOW FlagsLow => (Metadata_1.WFLAGS_LOW)DwFlags;
public int GetTypeDefRid() => (int)(DwFlags2 >> Metadata_1.Constants.MethodTableDwFlags2TypeDefRidShift);

public Metadata_1.WFLAGS_LOW GetFlag(Metadata_1.WFLAGS_LOW mask) => throw new NotImplementedException("TODO");
public Metadata_1.WFLAGS_HIGH GetFlag(Metadata_1.WFLAGS_HIGH mask) => FlagsHigh & mask;
public bool IsInterface => GetFlag(Metadata_1.WFLAGS_HIGH.Category_Mask) == Metadata_1.WFLAGS_HIGH.Category_Interface;
public bool IsString => HasComponentSize && !IsArray && RawGetComponentSize() == 2;

public bool HasComponentSize => GetFlag(Metadata_1.WFLAGS_HIGH.HasComponentSize) != 0;

public bool IsArray => GetFlag(Metadata_1.WFLAGS_HIGH.Category_Array_Mask) == Metadata_1.WFLAGS_HIGH.Category_Array;

public bool IsStringOrArray => HasComponentSize;
public ushort RawGetComponentSize() => (ushort)(DwFlags >> 16);

public bool TestFlagWithMask(Metadata_1.WFLAGS_LOW mask, Metadata_1.WFLAGS_LOW flag)
{
if (IsStringOrArray)
{
return (Metadata_1.WFLAGS_LOW.StringArrayValues & mask) == flag;
}
else
{
return (FlagsLow & mask) == flag;
}
}
public bool HasInstantiation => !TestFlagWithMask(Metadata_1.WFLAGS_LOW.GenericsMask, Metadata_1.WFLAGS_LOW.GenericsMask_NonGeneric);

public bool ContainsPointers => GetFlag(Metadata_1.WFLAGS_HIGH.ContainsPointers) != 0;

public bool IsDynamicStatics => !TestFlagWithMask(Metadata_1.WFLAGS_LOW.StaticsMask, Metadata_1.WFLAGS_LOW.StaticsMask_Dynamic);
}
Loading