summaryrefslogtreecommitdiff
path: root/src/vm/methodtable.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/methodtable.h')
-rw-r--r--src/vm/methodtable.h4416
1 files changed, 4416 insertions, 0 deletions
diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h
new file mode 100644
index 0000000000..529145a726
--- /dev/null
+++ b/src/vm/methodtable.h
@@ -0,0 +1,4416 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: methodtable.h
+//
+
+
+//
+
+//
+// ============================================================================
+
+#ifndef _METHODTABLE_H_
+#define _METHODTABLE_H_
+
+/*
+ * Include Files
+ */
+#include "vars.hpp"
+#include "cor.h"
+#include "hash.h"
+#include "crst.h"
+#include "objecthandle.h"
+#include "cgensys.h"
+#include "declsec.h"
+#ifdef FEATURE_COMINTEROP
+#include "stdinterfaces.h"
+#endif
+#include "slist.h"
+#include "spinlock.h"
+#include "typehandle.h"
+#include "eehash.h"
+#include "contractimpl.h"
+#include "generics.h"
+#include "fixuppointer.h"
+
+/*
+ * Forward Declarations
+ */
+class AppDomain;
+class ArrayClass;
+class ArrayMethodDesc;
+struct ClassCtorInfoEntry;
+class ClassLoader;
+class DomainLocalBlock;
+class FCallMethodDesc;
+class EEClass;
+class EnCFieldDesc;
+class FieldDesc;
+class JIT_TrialAlloc;
+struct LayoutRawFieldInfo;
+class MetaSig;
+class MethodDesc;
+class MethodDescChunk;
+class MethodTable;
+class Module;
+class Object;
+class Stub;
+class Substitution;
+class TypeHandle;
+#ifdef FEATURE_REMOTING
+class CrossDomainOptimizationInfo;
+typedef DPTR(CrossDomainOptimizationInfo) PTR_CrossDomainOptimizationInfo;
+#endif
+class Dictionary;
+class AllocMemTracker;
+class SimpleRWLock;
+class MethodDataCache;
+class EEClassLayoutInfo;
+#ifdef FEATURE_COMINTEROP
+class ComCallWrapperTemplate;
+#endif
+#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
+class ClassFactoryBase;
+#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
+class ArgDestination;
+
+//============================================================================
+// This is the in-memory structure of a class and it will evolve.
+//============================================================================
+
+// <TODO>
+// Add a sync block
+// Also this class currently has everything public - this may changes
+// Might also need to hold onto the meta data loader fot this class</TODO>
+
+//
+// A MethodTable contains an array of these structures, which describes each interface implemented
+// by this class (directly declared or indirectly declared).
+//
+// Generic type instantiations (in C# syntax: C<ty_1,...,ty_n>) are represented by
+// MethodTables, i.e. a new MethodTable gets allocated for each such instantiation.
+// The entries in these tables (i.e. the code) are, however, often shared.
+//
+// In particular, a MethodTable's vtable contents (and hence method descriptors) may be
+// shared between compatible instantiations (e.g. List<string> and List<object> have
+// the same vtable *contents*). Likewise the EEClass will be shared between
+// compatible instantiations whenever the vtable contents are.
+//
+// !!! Thus that it is _not_ generally the case that GetClass.GetMethodTable() == t. !!!
+//
+// Instantiated interfaces have their own method tables unique to the instantiation e.g. I<string> is
+// distinct from I<int> and I<object>
+//
+// For generic types the interface map lists generic interfaces
+// For instantiated types the interface map lists instantiated interfaces
+// e.g. for C<T> : I<T>, J<string>
+// the interface map for C would list I and J
+// the interface map for C<int> would list I<int> and J<string>
+//
+struct InterfaceInfo_t
+{
+#ifdef DACCESS_COMPILE
+ friend class NativeImageDumper;
+#endif
+
+ FixupPointer<PTR_MethodTable> m_pMethodTable; // Method table of the interface
+
+public:
+ FORCEINLINE PTR_MethodTable GetMethodTable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pMethodTable.GetValue();
+ }
+
+#ifndef DACCESS_COMPILE
+ void SetMethodTable(MethodTable * pMT)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pMethodTable.SetValue(pMT);
+ }
+
+ // Get approximate method table. This is used by the type loader before the type is fully loaded.
+ PTR_MethodTable GetApproxMethodTable(Module * pContainingModule);
+#endif
+}; // struct InterfaceInfo_t
+
+typedef DPTR(InterfaceInfo_t) PTR_InterfaceInfo;
+
+namespace ClassCompat
+{
+ struct InterfaceInfo_t;
+};
+
+// Data needed when simulating old VTable layout for COM Interop
+// This is necessary as the data is saved in MethodDescs and we need
+// to simulate different values without copying or changing the existing
+// MethodDescs
+//
+// This will be created in a parallel array to ppMethodDescList and
+// ppUnboxMethodDescList in the bmtMethAndFieldDescs structure below
+struct InteropMethodTableSlotData
+{
+ enum
+ {
+ e_DUPLICATE = 0x0001 // The entry is duplicate
+ };
+
+ MethodDesc *pMD; // The MethodDesc for this slot
+ WORD wSlot; // The simulated slot value for the MethodDesc
+ WORD wFlags; // The simulated duplicate value
+ MethodDesc *pDeclMD; // To keep track of MethodImpl's
+
+ void SetDuplicate()
+ {
+ wFlags |= e_DUPLICATE;
+ }
+
+ BOOL IsDuplicate() {
+ return ((BOOL)(wFlags & e_DUPLICATE));
+ }
+
+ WORD GetSlot() {
+ return wSlot;
+ }
+
+ void SetSlot(WORD wSlot) {
+ this->wSlot = wSlot;
+ }
+}; // struct InteropMethodTableSlotData
+
+#ifdef FEATURE_COMINTEROP
+struct InteropMethodTableData
+{
+ WORD cVTable; // Count of vtable slots
+ InteropMethodTableSlotData *pVTable; // Data for each slot
+
+ WORD cNonVTable; // Count of non-vtable slots
+ InteropMethodTableSlotData *pNonVTable; // Data for each slot
+
+ WORD cInterfaceMap; // Count of interfaces
+ ClassCompat::InterfaceInfo_t *
+ pInterfaceMap; // The interface map
+
+ // Utility methods
+ static WORD GetRealMethodDesc(MethodTable *pMT, MethodDesc *pMD);
+ static WORD GetSlotForMethodDesc(MethodTable *pMT, MethodDesc *pMD);
+ ClassCompat::InterfaceInfo_t* FindInterface(MethodTable *pInterface);
+ WORD GetStartSlotForInterface(MethodTable* pInterface);
+};
+
+class InteropMethodTableSlotDataMap
+{
+protected:
+ InteropMethodTableSlotData *m_pSlotData;
+ DWORD m_cSlotData;
+ DWORD m_iCurSlot;
+
+public:
+ InteropMethodTableSlotDataMap(InteropMethodTableSlotData *pSlotData, DWORD cSlotData);
+ InteropMethodTableSlotData *GetData(MethodDesc *pMD);
+ BOOL Exists(MethodDesc *pMD);
+
+protected:
+ InteropMethodTableSlotData *Exists_Helper(MethodDesc *pMD);
+ InteropMethodTableSlotData *GetNewEntry();
+}; // class InteropMethodTableSlotDataMap
+#endif // FEATURE_COMINTEROP
+
+//
+// This struct contains cached information on the GUID associated with a type.
+//
+
+struct GuidInfo
+{
+ GUID m_Guid; // The actual guid of the type.
+ BOOL m_bGeneratedFromName; // A boolean indicating if it was generated from the
+ // name of the type.
+};
+
+typedef DPTR(GuidInfo) PTR_GuidInfo;
+
+
+// GenericsDictInfo is stored at negative offset of the dictionary
+struct GenericsDictInfo
+{
+#ifdef _WIN64
+ DWORD m_dwPadding; // Just to keep the size a multiple of 8
+#endif
+
+ // Total number of instantiation dictionaries including inherited ones
+ // i.e. how many instantiated classes (including this one) are there in the hierarchy?
+ // See comments about PerInstInfo
+ WORD m_wNumDicts;
+
+ // Number of type parameters (NOT including those of superclasses).
+ WORD m_wNumTyPars;
+}; // struct GenericsDictInfo
+typedef DPTR(GenericsDictInfo) PTR_GenericsDictInfo;
+
+struct GenericsStaticsInfo
+{
+ // Pointer to field descs for statics
+ PTR_FieldDesc m_pFieldDescs;
+
+ // Method table ID for statics
+ SIZE_T m_DynamicTypeID;
+
+}; // struct GenericsStaticsInfo
+typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo;
+
+
+// CrossModuleGenericsStaticsInfo is used in NGen images for statics of cross-module
+// generic instantiations. CrossModuleGenericsStaticsInfo is optional member of
+// MethodTableWriteableData.
+struct CrossModuleGenericsStaticsInfo
+{
+ // Module this method table statics are attached to.
+ //
+ // The statics has to be attached to module referenced from the generic instantiation
+ // in domain-neutral code. We need to guarantee that the module for the statics
+ // has a valid local represenation in an appdomain.
+ //
+ PTR_Module m_pModuleForStatics;
+
+ // Method table ID for statics
+ SIZE_T m_DynamicTypeID;
+}; // struct CrossModuleGenericsStaticsInfo
+typedef DPTR(CrossModuleGenericsStaticsInfo) PTR_CrossModuleGenericsStaticsInfo;
+
+// This structure records methods and fields which are interesting for VTS
+// (Version Tolerant Serialization). A pointer to it is optionally appended to
+// MethodTables with VTS event methods or NotSerialized or OptionallySerialized
+// fields. The structure is variable length to incorporate a packed array of
+// data describing the disposition of fields in the type.
+struct RemotingVtsInfo
+{
+ enum VtsCallbackType
+ {
+ VTS_CALLBACK_ON_SERIALIZING = 0,
+ VTS_CALLBACK_ON_SERIALIZED,
+ VTS_CALLBACK_ON_DESERIALIZING,
+ VTS_CALLBACK_ON_DESERIALIZED,
+ VTS_NUM_CALLBACK_TYPES
+ };
+
+ FixupPointer<PTR_MethodDesc> m_pCallbacks[VTS_NUM_CALLBACK_TYPES];
+#ifdef _DEBUG
+ DWORD m_dwNumFields;
+#endif
+ DWORD m_rFieldTypes[1];
+
+ static DWORD GetSize(DWORD dwNumFields)
+ {
+ LIMITED_METHOD_CONTRACT;
+ // Encode each field in two bits. Round up allocation to the nearest DWORD.
+ DWORD dwBitsRequired = dwNumFields * 2;
+ DWORD dwBytesRequired = (dwBitsRequired + 7) / 8;
+ return (DWORD)(offsetof(RemotingVtsInfo, m_rFieldTypes[0]) + ALIGN_UP(dwBytesRequired, sizeof(DWORD)));
+ }
+
+ void SetIsNotSerialized(DWORD dwFieldIndex)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(dwFieldIndex < m_dwNumFields);
+ DWORD dwRecordIndex = dwFieldIndex * 2;
+ DWORD dwOffset = dwRecordIndex / (sizeof(DWORD) * 8);
+ DWORD dwMask = 1 << (dwRecordIndex % (sizeof(DWORD) * 8));
+ m_rFieldTypes[dwOffset] |= dwMask;
+ }
+
+ BOOL IsNotSerialized(DWORD dwFieldIndex)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(dwFieldIndex < m_dwNumFields);
+ DWORD dwRecordIndex = dwFieldIndex * 2;
+ DWORD dwOffset = dwRecordIndex / (sizeof(DWORD) * 8);
+ DWORD dwMask = 1 << (dwRecordIndex % (sizeof(DWORD) * 8));
+ return m_rFieldTypes[dwOffset] & dwMask;
+ }
+
+ void SetIsOptionallySerialized(DWORD dwFieldIndex)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(dwFieldIndex < m_dwNumFields);
+ DWORD dwRecordIndex = dwFieldIndex * 2;
+ DWORD dwOffset = dwRecordIndex / (sizeof(DWORD) * 8);
+ DWORD dwMask = 2 << (dwRecordIndex % (sizeof(DWORD) * 8));
+ m_rFieldTypes[dwOffset] |= dwMask;
+ }
+
+ BOOL IsOptionallySerialized(DWORD dwFieldIndex)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(dwFieldIndex < m_dwNumFields);
+ DWORD dwRecordIndex = dwFieldIndex * 2;
+ DWORD dwOffset = dwRecordIndex / (sizeof(DWORD) * 8);
+ DWORD dwMask = 2 << (dwRecordIndex % (sizeof(DWORD) * 8));
+ return m_rFieldTypes[dwOffset] & dwMask;
+ }
+}; // struct RemotingVtsInfo
+typedef DPTR(RemotingVtsInfo) PTR_RemotingVtsInfo;
+
+
+struct ContextStaticsBucket
+{
+ // Offset which points to the CLS storage. Allocated lazily - -1 means no offset allocated yet.
+ DWORD m_dwContextStaticsOffset;
+ // Size of CLS fields
+ WORD m_wContextStaticsSize;
+};
+typedef DPTR(ContextStaticsBucket) PTR_ContextStaticsBucket;
+
+#ifdef FEATURE_COMINTEROP
+struct RCWPerTypeData;
+#endif // FEATURE_COMINTEROP
+
+//
+// This struct consolidates the writeable parts of the MethodTable
+// so that we can layout a read-only MethodTable with a pointer
+// to the writeable parts of the MethodTable in an ngen image
+//
+struct MethodTableWriteableData
+{
+ friend class MethodTable;
+#if defined(DACCESS_COMPILE)
+ friend class NativeImageDumper;
+#endif
+
+ enum
+ {
+ // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
+ // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
+ // CARRY THE CORRECT INITIAL FLAGS.
+
+ enum_flag_RemotingConfigChecked = 0x00000001,
+ enum_flag_RequiresManagedActivation = 0x00000002,
+ enum_flag_Unrestored = 0x00000004,
+ enum_flag_CriticalTypePrepared = 0x00000008, // CriticalFinalizerObject derived type has had backout routines prepared
+ enum_flag_HasApproxParent = 0x00000010,
+ enum_flag_UnrestoredTypeKey = 0x00000020,
+ enum_flag_IsNotFullyLoaded = 0x00000040,
+ enum_flag_DependenciesLoaded = 0x00000080, // class and all depedencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED
+
+ enum_flag_SkipWinRTOverride = 0x00000100, // No WinRT override is needed
+
+#ifdef FEATURE_PREJIT
+ // These flags are used only at ngen time. We store them here since
+ // we are running out of available flags in MethodTable. They may eventually
+ // go into ngen speficic state.
+ enum_flag_NGEN_IsFixedUp = 0x00010000, // This MT has been fixed up during NGEN
+ enum_flag_NGEN_IsNeedsRestoreCached = 0x00020000, // Set if we have cached the results of needs restore computation
+ enum_flag_NGEN_CachedNeedsRestore = 0x00040000, // The result of the needs restore computation
+ enum_flag_NGEN_OverridingInterface = 0x00080000, // Overriding interface that we should generate WinRT CCW stubs for.
+
+#ifdef FEATURE_READYTORUN_COMPILER
+ enum_flag_NGEN_IsLayoutFixedComputed = 0x0010000, // Set if we have cached the result of IsLayoutFixed computation
+ enum_flag_NGEN_IsLayoutFixed = 0x0020000, // The result of the IsLayoutFixed computation
+#endif
+
+#endif // FEATURE_PREJIT
+
+#ifdef _DEBUG
+ enum_flag_ParentMethodTablePointerValid = 0x40000000,
+ enum_flag_HasInjectedInterfaceDuplicates = 0x80000000,
+#endif
+ };
+ DWORD m_dwFlags; // Lot of empty bits here.
+
+private:
+ /*
+ * m_hExposedClassObject is LoaderAllocator slot index to
+ * a RuntimeType instance for this class. But
+ * do NOT use it for Arrays or remoted objects! All arrays of objects
+ * share the same MethodTable/EEClass.
+ * @GENERICS: this used to live in EEClass but now lives here because it is per-instantiation data
+ * only set in code:MethodTable.GetManagedClassObject
+ */
+ LOADERHANDLE m_hExposedClassObject;
+
+#ifdef _DEBUG
+public:
+ // to avoid verify same method table too many times when it's not changing, we cache the GC count
+ // on which the method table is verified. When fast GC STRESS is turned on, we only verify the MT if
+ // current GC count is bigger than the number. Note most thing which will invalidate a MT will require a
+ // GC (like AD unload)
+ Volatile<DWORD> m_dwLastVerifedGCCnt;
+
+#ifdef _WIN64
+ DWORD m_dwPadding; // Just to keep the size a multiple of 8
+#endif
+
+#endif
+
+ // Optional CrossModuleGenericsStaticsInfo may be here.
+
+public:
+#ifdef _DEBUG
+ inline BOOL IsParentMethodTablePointerValid() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return (m_dwFlags & enum_flag_ParentMethodTablePointerValid);
+ }
+ inline void SetParentMethodTablePointerValid()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= enum_flag_ParentMethodTablePointerValid;
+ }
+#endif
+
+#ifdef FEATURE_PREJIT
+
+ void Save(DataImage *image, MethodTable *pMT, DWORD profilingFlags) const;
+ void Fixup(DataImage *image, MethodTable *pMT, BOOL needsRestore);
+
+ inline BOOL IsFixedUp() const
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_dwFlags & enum_flag_NGEN_IsFixedUp);
+ }
+ inline void SetFixedUp()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_dwFlags |= enum_flag_NGEN_IsFixedUp;
+ }
+
+ inline BOOL IsNeedsRestoreCached() const
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (m_dwFlags & enum_flag_NGEN_IsNeedsRestoreCached);
+ }
+
+ inline BOOL GetCachedNeedsRestore() const
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(IsNeedsRestoreCached());
+ return (m_dwFlags & enum_flag_NGEN_CachedNeedsRestore);
+ }
+
+ inline void SetCachedNeedsRestore(BOOL fNeedsRestore)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(!IsNeedsRestoreCached());
+ m_dwFlags |= enum_flag_NGEN_IsNeedsRestoreCached;
+ if (fNeedsRestore) m_dwFlags |= enum_flag_NGEN_CachedNeedsRestore;
+ }
+
+ inline void SetIsOverridingInterface()
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if ((m_dwFlags & enum_flag_NGEN_OverridingInterface) != 0) return;
+ FastInterlockOr(EnsureWritablePages((ULONG *) &m_dwFlags), enum_flag_NGEN_OverridingInterface);
+ }
+
+ inline BOOL IsOverridingInterface() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (m_dwFlags & enum_flag_NGEN_OverridingInterface);
+ }
+#endif // FEATURE_PREJIT
+
+ inline BOOL IsRemotingConfigChecked() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_dwFlags & enum_flag_RemotingConfigChecked;
+ }
+ inline void SetRemotingConfigChecked()
+ {
+ WRAPPER_NO_CONTRACT;
+ // remembers that we went through the rigorous
+ // checks to decide whether this class should be
+ // activated locally or remote
+ FastInterlockOr(EnsureWritablePages((ULONG *)&m_dwFlags), enum_flag_RemotingConfigChecked);
+ }
+ inline void TrySetRemotingConfigChecked()
+ {
+ WRAPPER_NO_CONTRACT;
+ // remembers that we went through the rigorous
+ // checks to decide whether this class should be
+ // activated locally or remote
+ if (EnsureWritablePagesNoThrow(&m_dwFlags, sizeof(m_dwFlags)))
+ FastInterlockOr((ULONG *)&m_dwFlags, enum_flag_RemotingConfigChecked);
+ }
+ inline BOOL RequiresManagedActivation() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_dwFlags & enum_flag_RequiresManagedActivation;
+ }
+ inline void SetRequiresManagedActivation()
+ {
+ WRAPPER_NO_CONTRACT;
+ FastInterlockOr(EnsureWritablePages((ULONG *) &m_dwFlags), enum_flag_RequiresManagedActivation|enum_flag_RemotingConfigChecked);
+ }
+
+ inline LOADERHANDLE GetExposedClassObjectHandle() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_hExposedClassObject;
+ }
+
+ void SetIsNotFullyLoadedForBuildMethodTable()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // Used only during method table initialization - no need for logging or Interlocked Exchange.
+ m_dwFlags |= (MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
+ MethodTableWriteableData::enum_flag_Unrestored |
+ MethodTableWriteableData::enum_flag_IsNotFullyLoaded |
+ MethodTableWriteableData::enum_flag_HasApproxParent);
+ }
+
+ void SetIsRestoredForBuildMethodTable()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // Used only during method table initialization - no need for logging or Interlocked Exchange.
+ m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
+ MethodTableWriteableData::enum_flag_Unrestored);
+ }
+
+ void SetIsFullyLoadedForBuildMethodTable()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ // Used only during method table initialization - no need for logging or Interlocked Exchange.
+ m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
+ MethodTableWriteableData::enum_flag_Unrestored |
+ MethodTableWriteableData::enum_flag_IsNotFullyLoaded |
+ MethodTableWriteableData::enum_flag_HasApproxParent);
+ }
+
+ // Have the backout methods (Finalizer, Dispose, ReleaseHandle etc.) been prepared for this type? This currently only happens
+ // for types derived from CriticalFinalizerObject.
+ inline BOOL CriticalTypeHasBeenPrepared() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_dwFlags & enum_flag_CriticalTypePrepared;
+ }
+ inline void SetCriticalTypeHasBeenPrepared()
+ {
+ WRAPPER_NO_CONTRACT;
+ FastInterlockOr(EnsureWritablePages((ULONG*)&m_dwFlags), enum_flag_CriticalTypePrepared);
+ }
+
+ inline CrossModuleGenericsStaticsInfo * GetCrossModuleGenericsStaticsInfo()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ SIZE_T size = sizeof(MethodTableWriteableData);
+ return PTR_CrossModuleGenericsStaticsInfo(dac_cast<TADDR>(this) + size);
+ }
+
+}; // struct MethodTableWriteableData
+
+typedef DPTR(MethodTableWriteableData) PTR_MethodTableWriteableData;
+typedef DPTR(MethodTableWriteableData const) PTR_Const_MethodTableWriteableData;
+
+#ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF
+inline
+SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeType)
+{
+ static const SystemVClassificationType toSystemVAmd64ClassificationTypeMap[] = {
+ SystemVClassificationTypeUnknown, // ELEMENT_TYPE_END
+ SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VOID
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_BOOLEAN
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_CHAR
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_I1
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_U1
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_I2
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_U2
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_I4
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_U4
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_I8
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_U8
+ SystemVClassificationTypeSSE, // ELEMENT_TYPE_R4
+ SystemVClassificationTypeSSE, // ELEMENT_TYPE_R8
+ SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_STRING
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_PTR
+ SystemVClassificationTypeIntegerByRef, // ELEMENT_TYPE_BYREF
+ SystemVClassificationTypeStruct, // ELEMENT_TYPE_VALUETYPE
+ SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_CLASS
+ SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_VAR (type variable)
+ SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_ARRAY
+ SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_GENERICINST
+ SystemVClassificationTypeTypedReference, // ELEMENT_TYPE_TYPEDBYREF
+ SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_I
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_U
+ SystemVClassificationTypeUnknown, // ELEMENT_TYPE_R_UNSUPPORTED
+
+ // put the correct type when we know our implementation
+ SystemVClassificationTypeInteger, // ELEMENT_TYPE_FNPTR
+ SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_OBJECT
+ SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_SZARRAY
+ SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_MVAR
+
+ SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_REQD
+ SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_OPT
+ SystemVClassificationTypeUnknown, // ELEMENT_TYPE_INTERNAL
+ };
+
+ _ASSERTE(sizeof(toSystemVAmd64ClassificationTypeMap) == ELEMENT_TYPE_MAX);
+ _ASSERTE(eeType < (CorElementType) sizeof(toSystemVAmd64ClassificationTypeMap));
+ // spot check of the map
+ _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_I4] == SystemVClassificationTypeInteger);
+ _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_PTR] == SystemVClassificationTypeInteger);
+ _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_VALUETYPE] == SystemVClassificationTypeStruct);
+ _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_TYPEDBYREF] == SystemVClassificationTypeTypedReference);
+ _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_BYREF] == SystemVClassificationTypeIntegerByRef);
+
+ return (((int)eeType) < ELEMENT_TYPE_MAX) ? (toSystemVAmd64ClassificationTypeMap[eeType]) : SystemVClassificationTypeUnknown;
+};
+
+#define SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES 8 // Size of an eightbyte in bytes.
+#define SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT 16 // Maximum number of fields in struct passed in registers
+
+struct SystemVStructRegisterPassingHelper
+{
+ SystemVStructRegisterPassingHelper(unsigned int totalStructSize) :
+ structSize(totalStructSize),
+ eightByteCount(0),
+ inEmbeddedStruct(false),
+ currentUniqueOffsetField(0),
+ largestFieldOffset(-1)
+ {
+ for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
+ {
+ eightByteClassifications[i] = SystemVClassificationTypeNoClass;
+ eightByteSizes[i] = 0;
+ eightByteOffsets[i] = 0;
+ }
+
+ // Initialize the work arrays
+ for (int i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++)
+ {
+ fieldClassifications[i] = SystemVClassificationTypeNoClass;
+ fieldSizes[i] = 0;
+ fieldOffsets[i] = 0;
+ }
+ }
+
+ // Input state.
+ unsigned int structSize;
+
+ // These fields are the output; these are what is computed by the classification algorithm.
+ unsigned int eightByteCount;
+ SystemVClassificationType eightByteClassifications[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
+ unsigned int eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
+ unsigned int eightByteOffsets[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
+
+ // Helper members to track state.
+ bool inEmbeddedStruct;
+ unsigned int currentUniqueOffsetField; // A virtual field that could encompass many overlapping fields.
+ int largestFieldOffset;
+ SystemVClassificationType fieldClassifications[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
+ unsigned int fieldSizes[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
+ unsigned int fieldOffsets[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
+};
+
+typedef DPTR(SystemVStructRegisterPassingHelper) SystemVStructRegisterPassingHelperPtr;
+
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF
+
+//===============================================================================================
+//
+// GC data appears before the beginning of the MethodTable
+//
+//@GENERICS:
+// Each generic type has a corresponding "generic" method table that serves the following
+// purposes:
+// * The method table pointer is used as a representative for the generic type e.g. in reflection
+// * MethodDescs for methods in the vtable are used for reflection; they should never be invoked.
+// Some other information (e.g. BaseSize) makes no sense "generically" but unfortunately gets put in anyway.
+//
+// Each distinct instantiation of a generic type has its own MethodTable structure.
+// However, the EEClass structure can be shared between compatible instantiations e.g. List<string> and List<object>.
+// In that case, MethodDescs are also shared between compatible instantiations (but see below about generic methods).
+// Hence the vtable entries for MethodTables belonging to such an EEClass are the same.
+//
+// The non-vtable section of such MethodTables are only present for one of the instantiations (the first one
+// requested) as non-vtable entries are never accessed through the vtable pointer of an object so it's always possible
+// to ensure that they are accessed through the representative MethodTable that contains them.
+
+// A MethodTable is the fundamental representation of type in the runtime. It is this structure that
+// objects point at (see code:Object). It holds the size and GC layout of the type, as well as the dispatch table
+// for virtual dispach (but not interface dispatch). There is a distinct method table for every instance of
+// a generic type. From here you can get to
+//
+// * code:EEClass
+//
+// Important fields
+// * code:MethodTable.m_pEEClass - pointer to the cold part of the type.
+// * code:MethodTable.m_pParentMethodTable - the method table of the parent type.
+//
+class MethodTableBuilder;
+class MethodTable
+{
+ /************************************
+ * FRIEND FUNCTIONS
+ ************************************/
+ // DO NOT ADD FRIENDS UNLESS ABSOLUTELY NECESSARY
+ // USE ACCESSORS TO READ/WRITE private field members
+
+ // Special access for setting up String object method table correctly
+ friend class ClassLoader;
+ friend class JIT_TrialAlloc;
+ friend class Module;
+ 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
+ // and not pointing to some random memory. In particular
+ // check that (apart from the special case of instantiated generic types) we have
+ // GetCanonicalMethodTable() == this;
+ BOOL SanityCheck();
+
+ static void CallFinalizer(Object *obj);
+
+public:
+ PTR_Module GetModule();
+ PTR_Module GetModule_NoLogging();
+ Assembly *GetAssembly();
+
+ PTR_Module GetModuleIfLoaded();
+
+ // GetDomain on an instantiated type, e.g. C<ty1,ty2> returns the SharedDomain if all the
+ // constituent parts of the type are SharedDomain (i.e. domain-neutral),
+ // and returns an AppDomain if any of the parts are from an AppDomain,
+ // i.e. are domain-bound. Note that if any of the parts are domain-bound
+ // then they will all belong to the same domain.
+ PTR_BaseDomain GetDomain();
+
+ // Does this immediate item live in an NGEN module?
+ BOOL IsZapped();
+
+ // For types that are part of an ngen-ed assembly this gets the
+ // Module* that contains this methodtable.
+ PTR_Module GetZapModule();
+
+ // For regular, non-constructed types, GetLoaderModule() == GetModule()
+ // For constructed types (e.g. int[], Dict<int[], C>) the hash table through which a type
+ // is accessed lives in a "loader module". The rule for determining the loader module must ensure
+ // that a type never outlives its loader module with respect to app-domain unloading
+ //
+ // GetModuleForStatics() is the third kind of module. GetModuleForStatics() is module that
+ // statics are attached to.
+ PTR_Module GetLoaderModule();
+ PTR_LoaderAllocator GetLoaderAllocator();
+
+ void SetLoaderModule(Module* pModule);
+ void SetLoaderAllocator(LoaderAllocator* pAllocator);
+
+ // Get the domain local module - useful for static init checks
+ PTR_DomainLocalModule GetDomainLocalModule(AppDomain * pAppDomain);
+
+#ifndef DACCESS_COMPILE
+ // Version of GetDomainLocalModule which relies on the current AppDomain
+ PTR_DomainLocalModule GetDomainLocalModule();
+#endif
+
+ // Return whether the type lives in the shared domain.
+ BOOL IsDomainNeutral();
+
+ MethodTable *LoadEnclosingMethodTable(ClassLoadLevel targetLevel = CLASS_DEPENDENCIES_LOADED);
+
+ LPCWSTR GetPathForErrorMessages();
+
+ //-------------------------------------------------------------------
+ // COM INTEROP
+ //
+ BOOL IsProjectedFromWinRT();
+ BOOL IsExportedToWinRT();
+ BOOL IsWinRTDelegate();
+ BOOL IsWinRTRedirectedInterface(TypeHandle::InteropKind interopKind);
+ BOOL IsWinRTRedirectedDelegate();
+
+#ifdef FEATURE_COMINTEROP
+ TypeHandle GetCoClassForInterface();
+
+private:
+ TypeHandle SetupCoClassForInterface();
+
+public:
+ DWORD IsComClassInterface();
+
+ // Retrieves the COM interface type.
+ CorIfaceAttr GetComInterfaceType();
+ void SetComInterfaceType(CorIfaceAttr ItfType);
+
+ // Determines whether this is a WinRT-legal type
+ BOOL IsLegalWinRTType(OBJECTREF *poref);
+
+ // Determines whether this is a WinRT-legal type - don't use it with array
+ BOOL IsLegalNonArrayWinRTType();
+
+ MethodTable *GetDefaultWinRTInterface();
+
+ OBJECTHANDLE GetOHDelegate();
+ void SetOHDelegate (OBJECTHANDLE _ohDelegate);
+
+ CorClassIfaceAttr GetComClassInterfaceType();
+ TypeHandle GetDefItfForComClassItf();
+
+ void GetEventInterfaceInfo(MethodTable **ppSrcItfType, MethodTable **ppEvProvType);
+
+ BOOL IsExtensibleRCW();
+
+ // mark the class type as COM object class
+ void SetComObjectType();
+
+#if defined(FEATURE_TYPEEQUIVALENCE) || defined(FEATURE_REMOTING)
+ // mark the type as opted into type equivalence
+ void SetHasTypeEquivalence();
+#endif
+
+ // Helper to get parent class skipping over COM class in
+ // the hierarchy
+ MethodTable* GetComPlusParentMethodTable();
+
+ // class is a com object class
+ BOOL IsComObjectType()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_ComObject);
+ }
+ // class is a WinRT object class (is itself or derives from a ProjectedFromWinRT class)
+ BOOL IsWinRTObjectType();
+
+ DWORD IsComImport();
+
+ // class is a special COM event interface
+ int IsComEventItfType();
+
+ //-------------------------------------------------------------------
+ // Sparse VTables. These require a SparseVTableMap in the EEClass in
+ // order to record how the CLR's vtable slots map across to COM
+ // Interop slots.
+ //
+ int IsSparseForCOMInterop();
+
+ // COM interop helpers
+ // accessors for m_pComData
+ ComCallWrapperTemplate *GetComCallWrapperTemplate();
+ BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate);
+#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
+ ClassFactoryBase *GetComClassFactory();
+ BOOL SetComClassFactory(ClassFactoryBase *pFactory);
+#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
+
+ OBJECTREF GetObjCreateDelegate();
+ void SetObjCreateDelegate(OBJECTREF orDelegate);
+
+private:
+ // This is for COM Interop backwards compatibility
+ BOOL InsertComInteropData(InteropMethodTableData *pData);
+ InteropMethodTableData *CreateComInteropData(AllocMemTracker *pamTracker);
+
+public:
+ InteropMethodTableData *LookupComInteropData();
+ // This is the preferable entrypoint, as it will make sure that all
+ // parent MT's have their interop data created, and will create and
+ // add this MT's data if not available. The caller should make sure that
+ // an appropriate lock is taken to prevent duplicates.
+ // NOTE: The current caller of this is ComInterop, and it makes calls
+ // under its own lock to ensure not duplicates.
+ InteropMethodTableData *GetComInteropData();
+
+#else // !FEATURE_COMINTEROP
+ BOOL IsComObjectType()
+ {
+ SUPPORTS_DAC;
+ return FALSE;
+ }
+ BOOL IsWinRTObjectType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return FALSE;
+ }
+#endif // !FEATURE_COMINTEROP
+
+#ifdef FEATURE_ICASTABLE
+ void SetICastable();
+#endif
+
+ BOOL IsICastable(); // This type implements ICastable interface
+
+#ifdef FEATURE_TYPEEQUIVALENCE
+ // type has opted into type equivalence or is instantiated by/derived from a type that is
+ BOOL HasTypeEquivalence()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_HasTypeEquivalence);
+ }
+#else
+ BOOL HasTypeEquivalence()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return FALSE;
+ }
+#endif
+
+ //-------------------------------------------------------------------
+ // DYNAMIC ADDITION OF INTERFACES FOR COM INTEROP
+ //
+ // Support for dynamically added interfaces on extensible RCW's.
+
+#ifdef FEATURE_COMINTEROP
+ PTR_InterfaceInfo GetDynamicallyAddedInterfaceMap();
+ unsigned GetNumDynamicallyAddedInterfaces();
+ BOOL FindDynamicallyAddedInterface(MethodTable *pInterface);
+ void AddDynamicInterface(MethodTable *pItfMT);
+
+ BOOL HasDynamicInterfaceMap()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ // currently all ComObjects except
+ // for __ComObject have dynamic Interface maps
+ return GetNumInterfaces() > 0 && IsComObjectType() && !ParentEquals(g_pObjectClass);
+ }
+#endif // FEATURE_COMINTEROP
+
+ BOOL IsIntrospectionOnly();
+
+ // Checks this type and its instantiation for "IsIntrospectionOnly"
+ BOOL ContainsIntrospectionOnlyTypes();
+
+#ifndef DACCESS_COMPILE
+ VOID EnsureActive();
+ VOID EnsureInstanceActive();
+#endif
+
+ CHECK CheckActivated();
+ CHECK CheckInstanceActivated();
+
+ //-------------------------------------------------------------------
+ // THE DEFAULT CONSTRUCTOR
+ //
+
+public:
+ BOOL HasDefaultConstructor();
+ void SetHasDefaultConstructor();
+ WORD GetDefaultConstructorSlot();
+ MethodDesc *GetDefaultConstructor();
+
+ BOOL HasExplicitOrImplicitPublicDefaultConstructor();
+
+ //-------------------------------------------------------------------
+ // THE CLASS INITIALIZATION CONDITION
+ // (and related DomainLocalBlock/DomainLocalModule storage)
+ //
+ // - populate the DomainLocalModule if needed
+ // - run the cctor
+ //
+
+public:
+
+ // checks whether the class initialiser should be run on this class, and runs it if necessary
+ void CheckRunClassInitThrowing();
+
+ // checks whether or not the non-beforefieldinit class initializers have been run for all types in this type's
+ // inheritance hierarchy, and runs them if necessary. This simulates the behavior of running class constructors
+ // during object construction.
+ void CheckRunClassInitAsIfConstructingThrowing();
+
+#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
+ // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
+ bool ClassifyEightBytes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
+#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
+
+ // Copy m_dwFlags from another method table
+ void CopyFlags(MethodTable * pOldMT)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_dwFlags = pOldMT->m_dwFlags;
+ m_wFlags2 = pOldMT->m_wFlags2;
+ }
+
+ // Init the m_dwFlags field for an array
+ void SetIsArray(CorElementType arrayType, CorElementType elementType);
+
+ BOOL IsClassPreInited();
+
+ // mark the class as having its cctor run.
+#ifndef DACCESS_COMPILE
+ void SetClassInited();
+ BOOL IsClassInited(AppDomain* pAppDomain = NULL);
+
+ BOOL IsInitError();
+ void SetClassInitError();
+#endif
+
+ inline BOOL IsGlobalClass()
+ {
+ WRAPPER_NO_CONTRACT;
+ return (GetTypeDefRid() == RidFromToken(COR_GLOBAL_PARENT_TOKEN));
+ }
+
+ // uniquely identifes this type in the Domain table
+ DWORD GetClassIndex();
+
+ bool ClassRequiresUnmanagedCodeCheck();
+
+private:
+
+#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
+ void AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel);
+ // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
+ bool ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
+ bool ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
+#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
+
+ DWORD GetClassIndexFromToken(mdTypeDef typeToken)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return RidFromToken(typeToken) - 1;
+ }
+
+ // called from CheckRunClassInitThrowing(). The type wasn't marked as
+ // inited while we were there, so let's attempt to do the work.
+ void DoRunClassInitThrowing();
+
+ BOOL RunClassInitEx(OBJECTREF *pThrowable);
+
+public:
+ //-------------------------------------------------------------------
+ // THE CLASS CONSTRUCTOR
+ //
+
+ MethodDesc * GetClassConstructor();
+
+ BOOL HasClassConstructor();
+ void SetHasClassConstructor();
+ WORD GetClassConstructorSlot();
+ void SetClassConstructorSlot (WORD wCCtorSlot);
+
+ ClassCtorInfoEntry* GetClassCtorInfoIfExists();
+
+
+ void GetSavedExtent(TADDR *ppStart, TADDR *ppEnd);
+
+ //-------------------------------------------------------------------
+ // Save/Fixup/Restore/NeedsRestore
+ //
+ // Restore this method table if it's not already restored
+ // This is done by forcing a class load which in turn calls the Restore method
+ // The pending list is required for restoring types that reference themselves through
+ // instantiations of the superclass or interfaces e.g. System.Int32 : IComparable<System.Int32>
+
+
+#ifdef FEATURE_PREJIT
+
+ void Save(DataImage *image, DWORD profilingFlags);
+ void Fixup(DataImage *image);
+
+ // This is different from !IsRestored() in that it checks if restoring
+ // will ever be needed for this ngened data-structure.
+ // This is to be used at ngen time of a dependent module to determine
+ // if it can be accessed directly, or if the restoring mechanism needs
+ // to be hooked in.
+ BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited);
+
+ BOOL NeedsRestore(DataImage *image)
+ {
+ WRAPPER_NO_CONTRACT;
+ return ComputeNeedsRestore(image, NULL);
+ }
+
+private:
+ BOOL ComputeNeedsRestoreWorker(DataImage *image, TypeHandleList *pVisited);
+
+public:
+ // This returns true at NGen time if we can eager bind to all dictionaries along the inheritance chain
+ BOOL CanEagerBindToParentDictionaries(DataImage *image, TypeHandleList *pVisited);
+
+ // This returns true at NGen time if we may need to attach statics to
+ // other module than current loader module at runtime
+ BOOL NeedsCrossModuleGenericsStaticsInfo();
+
+ // Returns true at NGen time if we may need to write into the MethodTable at runtime
+ BOOL IsWriteable();
+
+#endif // FEATURE_PREJIT
+
+ void AllocateRegularStaticBoxes();
+ static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0);
+
+ void CheckRestore();
+
+ // Perform restore actions on type key components of method table (EEClass pointer + Module, generic args)
+ void DoRestoreTypeKey();
+
+ inline BOOL HasUnrestoredTypeKey() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return !IsPreRestored() &&
+ (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey) != 0;
+ }
+
+ // Actually do the restore actions on the method table
+ void Restore();
+
+ void SetIsRestored();
+
+ inline BOOL IsRestored_NoLogging()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ // If we are prerestored then we are considered a restored methodtable.
+ // Note that IsPreRestored is always false for jitted code.
+ if (IsPreRestored())
+ return TRUE;
+
+ return !(GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
+ }
+ inline BOOL IsRestored()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ g_IBCLogger.LogMethodTableAccess(this);
+
+ // If we are prerestored then we are considered a restored methodtable.
+ // Note that IsPreRestored is always false for jitted code.
+ if (IsPreRestored())
+ return TRUE;
+
+ return !(GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
+ }
+
+ //-------------------------------------------------------------------
+ // LOAD LEVEL
+ //
+ // The load level of a method table is derived from various flag bits
+ // See classloadlevel.h for details of each level
+ //
+ // Level CLASS_LOADED (fully loaded) is special: a type only
+ // reaches this level once all of its dependent types are also at
+ // this level (generic arguments, parent, interfaces, etc).
+ // Fully loading a type to this level is done outside locks, hence the need for
+ // a single atomic action that sets the level.
+ //
+ inline void SetIsFullyLoaded()
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ PRECONDITION(!HasApproxParent());
+ PRECONDITION(IsRestored_NoLogging());
+
+ FastInterlockAnd(EnsureWritablePages(&GetWriteableDataForWrite()->m_dwFlags), ~MethodTableWriteableData::enum_flag_IsNotFullyLoaded);
+ }
+
+ // Equivalent to GetLoadLevel() == CLASS_LOADED
+ inline BOOL IsFullyLoaded()
+ {
+ WRAPPER_NO_CONTRACT;
+
+ return (IsPreRestored())
+ || (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded) == 0;
+ }
+
+ inline BOOL IsSkipWinRTOverride()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_SkipWinRTOverride);
+ }
+
+ inline void SetSkipWinRTOverride()
+ {
+ WRAPPER_NO_CONTRACT;
+ FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite_NoLogging()->m_dwFlags), MethodTableWriteableData::enum_flag_SkipWinRTOverride);
+ }
+
+ inline void SetIsDependenciesLoaded()
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ PRECONDITION(!HasApproxParent());
+ PRECONDITION(IsRestored_NoLogging());
+
+ FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite()->m_dwFlags), MethodTableWriteableData::enum_flag_DependenciesLoaded);
+ }
+
+ inline ClassLoadLevel GetLoadLevel()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ g_IBCLogger.LogMethodTableAccess(this);
+
+ // Fast path for zapped images
+ if (IsPreRestored())
+ return CLASS_LOADED;
+
+ DWORD dwFlags = GetWriteableData()->m_dwFlags;
+
+ if (dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded)
+ {
+ if (dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey)
+ return CLASS_LOAD_UNRESTOREDTYPEKEY;
+
+ if (dwFlags & MethodTableWriteableData::enum_flag_Unrestored)
+ return CLASS_LOAD_UNRESTORED;
+
+ if (dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent)
+ return CLASS_LOAD_APPROXPARENTS;
+
+ if (!(dwFlags & MethodTableWriteableData::enum_flag_DependenciesLoaded))
+ return CLASS_LOAD_EXACTPARENTS;
+
+ return CLASS_DEPENDENCIES_LOADED;
+ }
+
+ return CLASS_LOADED;
+ }
+
+#ifdef _DEBUG
+ CHECK CheckLoadLevel(ClassLoadLevel level)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return TypeHandle(this).CheckLoadLevel(level);
+ }
+#endif
+
+
+ void DoFullyLoad(Generics::RecursionGraph * const pVisited, const ClassLoadLevel level, DFLPendingList * const pPending, BOOL * const pfBailed,
+ const InstantiationContext * const pInstContext);
+
+ //-------------------------------------------------------------------
+ // METHOD TABLES AS TYPE DESCRIPTORS
+ //
+ // A MethodTable can represeent a type such as "String" or an
+ // instantiated type such as "List<String>".
+ //
+
+ inline BOOL IsInterface()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Interface;
+ }
+
+ void SetIsInterface()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
+ SetFlag(enum_flag_Category_Interface);
+ }
+
+ inline BOOL IsSealed();
+
+ inline BOOL IsAbstract();
+
+ BOOL IsExternallyVisible();
+
+ // Get the instantiation for this instantiated type e.g. for Dict<string,int>
+ // this would be an array {string,int}
+ // If not instantiated, return NULL
+ Instantiation GetInstantiation();
+
+ // Get the instantiation for an instantiated type or a pointer to the
+ // element type for an array
+ Instantiation GetClassOrArrayInstantiation();
+ Instantiation GetArrayInstantiation();
+
+ // Does this method table require that additional modules be loaded?
+ inline BOOL HasModuleDependencies()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_HasModuleDependencies);
+ }
+
+ inline void SetHasModuleDependencies()
+ {
+ SetFlag(enum_flag_HasModuleDependencies);
+ }
+
+ // See the comment in code:MethodTable.DoFullyLoad for detailed description.
+ inline BOOL DependsOnEquivalentOrForwardedStructs()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_DependsOnEquivalentOrForwardedStructs);
+ }
+
+ inline void SetDependsOnEquivalentOrForwardedStructs()
+ {
+ SetFlag(enum_flag_DependsOnEquivalentOrForwardedStructs);
+ }
+
+ // Is this a method table for a generic type instantiation, e.g. List<string>?
+ inline BOOL HasInstantiation();
+
+ // Returns true for any class which is either itself a generic
+ // instantiation or is derived from a generic
+ // instantiation anywhere in it's class hierarchy,
+ //
+ // e.g. class D : C<int>
+ // or class E : D, class D : C<int>
+ //
+ // Does not return true just because the class supports
+ // an instantiated interface type.
+ BOOL HasGenericClassInstantiationInHierarchy()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetNumDicts() != 0;
+ }
+
+ // Is this an instantiation of a generic class at its formal
+ // type parameters ie. List<T> ?
+ inline BOOL IsGenericTypeDefinition();
+
+ BOOL ContainsGenericMethodVariables();
+
+ static BOOL ComputeContainsGenericVariables(Instantiation inst);
+
+ inline void SetContainsGenericVariables()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_ContainsGenericVariables);
+ }
+
+ inline void SetHasVariance()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_HasVariance);
+ }
+
+ inline BOOL HasVariance()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_HasVariance);
+ }
+
+ // Is this something like List<T> or List<Stack<T>>?
+ // List<Blah<T>> only exists for reflection and verification.
+ inline DWORD ContainsGenericVariables(BOOL methodVarsOnly = FALSE)
+ {
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+ if (methodVarsOnly)
+ return ContainsGenericMethodVariables();
+ else
+ return GetFlag(enum_flag_ContainsGenericVariables);
+ }
+
+ BOOL IsByRefLike()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;;
+ return GetFlag(enum_flag_IsByRefLike);
+ }
+
+ void SetIsByRefLike()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_IsByRefLike);
+ }
+
+ // class is a com object class
+ Module* GetDefiningModuleForOpenType();
+
+ inline BOOL IsTypicalTypeDefinition()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return !HasInstantiation() || IsGenericTypeDefinition();
+ }
+
+ typedef enum
+ {
+ modeProjected = 0x1,
+ modeRedirected = 0x2,
+ modeAll = modeProjected|modeRedirected
+ } Mode;
+
+ // Is this a generic interface/delegate that can be used for COM interop?
+ inline BOOL SupportsGenericInterop(TypeHandle::InteropKind interopKind, Mode = modeAll);
+
+ BOOL HasSameTypeDefAs(MethodTable *pMT);
+ BOOL HasSameTypeDefAs_NoLogging(MethodTable *pMT);
+
+ //-------------------------------------------------------------------
+ // GENERICS & CODE SHARING
+ //
+
+ BOOL IsSharedByGenericInstantiations();
+
+ // If this is a "representative" generic MT or a non-generic (regular) MT return true
+ inline BOOL IsCanonicalMethodTable();
+
+ // Return the canonical representative MT amongst the set of MT's that share
+ // code with the given MT because of generics.
+ PTR_MethodTable GetCanonicalMethodTable();
+
+ // Returns fixup if canonical method table needs fixing up, NULL otherwise
+ TADDR GetCanonicalMethodTableFixup();
+
+ //-------------------------------------------------------------------
+ // Accessing methods by slot number
+ //
+ // Some of these functions are also currently used to get non-virtual
+ // methods, relying on the assumption that they are contiguous. This
+ // is not true for non-virtual methods in generic instantiations, which
+ // only live on the canonical method table.
+
+ enum
+ {
+ NO_SLOT = 0xffff // a unique slot number used to indicate "empty" for fields that record slot numbers
+ };
+
+ PCODE GetSlot(UINT32 slotNumber)
+ {
+ WRAPPER_NO_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ CONSISTENCY_CHECK(slotNumber < GetNumVtableSlots());
+ PTR_PCODE pSlot = GetSlotPtrRaw(slotNumber);
+ if (IsZapped() && slotNumber >= GetNumVirtuals())
+ {
+ // Non-virtual slots in NGened images are relative pointers
+ return RelativePointer<PCODE>::GetValueAtPtr(dac_cast<TADDR>(pSlot));
+ }
+ return *pSlot;
+ }
+
+ // Special-case for when we know that the slot number corresponds
+ // to a virtual method.
+ inline PCODE GetSlotForVirtual(UINT32 slotNum)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ CONSISTENCY_CHECK(slotNum < GetNumVirtuals());
+ // Virtual slots live in chunks pointed to by vtable indirections
+ return *(GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum));
+ }
+
+ PTR_PCODE GetSlotPtrRaw(UINT32 slotNum)
+ {
+ WRAPPER_NO_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ CONSISTENCY_CHECK(slotNum < GetNumVtableSlots());
+
+ if (slotNum < GetNumVirtuals())
+ {
+ // Virtual slots live in chunks pointed to by vtable indirections
+ return GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum);
+ }
+ else if (HasSingleNonVirtualSlot())
+ {
+ // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member,
+ // except when there is only one in which case it lives in the optional member itself
+ _ASSERTE(slotNum == GetNumVirtuals());
+ return dac_cast<PTR_PCODE>(GetNonVirtualSlotsPtr());
+ }
+ else
+ {
+ // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member
+ _ASSERTE(HasNonVirtualSlotsArray());
+ g_IBCLogger.LogMethodTableNonVirtualSlotsAccess(this);
+ return GetNonVirtualSlotsArray() + (slotNum - GetNumVirtuals());
+ }
+ }
+
+ PTR_PCODE GetSlotPtr(UINT32 slotNum)
+ {
+ WRAPPER_NO_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+
+ // Slots in NGened images are relative pointers
+ CONSISTENCY_CHECK(!IsZapped());
+
+ return GetSlotPtrRaw(slotNum);
+ }
+
+ void SetSlot(UINT32 slotNum, PCODE slotVal);
+
+ //-------------------------------------------------------------------
+ // The VTABLE
+ //
+ // Rather than the traditional array of code pointers (or "slots") we use a two-level vtable in
+ // which slots for virtual methods live in chunks. Doing so allows the chunks to be shared among
+ // method tables (the most common example being between parent and child classes where the child
+ // does not override any method in the chunk). This yields substantial space savings at the fixed
+ // cost of one additional indirection for a virtual call.
+ //
+ // Note that none of this should be visible outside the implementation of MethodTable; all other
+ // code continues to refer to a virtual method via the traditional slot number. This is similar to
+ // how we refer to non-virtual methods as having a slot number despite having long ago moved their
+ // code pointers out of the vtable.
+ //
+ // Consider a class where GetNumVirtuals is 5 and (for the sake of the example) assume we break
+ // the vtable into chunks of size 3. The layout would be as follows:
+ //
+ // pMT chunk 1 chunk 2
+ // ------------------ ------------------ ------------------
+ // | | | M1() | | M4() |
+ // | fixed-size | ------------------ ------------------
+ // | portion of | | M2() | | M5() |
+ // | MethodTable | ------------------ ------------------
+ // | | | M3() |
+ // ------------------ ------------------
+ // | ptr to chunk 1 |
+ // ------------------
+ // | ptr to chunk 2 |
+ // ------------------
+ //
+ // We refer to "ptr to chunk 1" and "ptr to chunk 2" as "indirection slots."
+ //
+ // The current chunking strategy is independent of class properties; all are of size 8. Several
+ // other strategies were tried, and the only one that has performed better empirically is to begin
+ // with a single chunk of size 4 (matching the number of virtuals in System.Object) and then
+ // continue with chunks of size 8. However it was a small improvement and required the run-time
+ // helpers listed below to be measurably slower.
+ //
+ // If you want to change this, you should only need to modify the first four functions below
+ // along with any assembly helper that has taken a dependency on the layout. Currently,
+ // those consist of:
+ // JIT_IsInstanceOfInterface
+ // JIT_ChkCastInterface
+ // Transparent proxy stub
+ //
+ // This layout only applies to the virtual methods in a class (those with slot number below GetNumVirtuals).
+ // Non-virtual methods that are in the vtable (those with slot numbers between GetNumVirtuals and
+ // GetNumVtableSlots) are laid out in a single chunk pointed to by an optional member.
+ // See GetSlotPtrRaw for more details.
+
+ #define VTABLE_SLOTS_PER_CHUNK 8
+ #define VTABLE_SLOTS_PER_CHUNK_LOG2 3
+
+ static DWORD GetIndexOfVtableIndirection(DWORD slotNum);
+ static DWORD GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
+ static DWORD GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
+ static UINT32 GetIndexAfterVtableIndirection(UINT32 slotNum);
+ static DWORD GetNumVtableIndirections(DWORD wNumVirtuals);
+ PTR_PTR_PCODE GetVtableIndirections();
+ DWORD GetNumVtableIndirections();
+
+ class VtableIndirectionSlotIterator
+ {
+ friend class MethodTable;
+
+ private:
+ PTR_PTR_PCODE m_pSlot;
+ DWORD m_i;
+ DWORD m_count;
+ PTR_MethodTable m_pMT;
+
+ VtableIndirectionSlotIterator(MethodTable *pMT);
+ VtableIndirectionSlotIterator(MethodTable *pMT, DWORD index);
+
+ public:
+ BOOL Next();
+ BOOL Finished();
+ DWORD GetIndex();
+ DWORD GetOffsetFromMethodTable();
+ PTR_PCODE GetIndirectionSlot();
+
+#ifndef DACCESS_COMPILE
+ void SetIndirectionSlot(PTR_PCODE pChunk);
+#endif
+
+ DWORD GetStartSlot();
+ DWORD GetEndSlot();
+ DWORD GetNumSlots();
+ DWORD GetSize();
+ }; // class VtableIndirectionSlotIterator
+
+ VtableIndirectionSlotIterator IterateVtableIndirectionSlots();
+ VtableIndirectionSlotIterator IterateVtableIndirectionSlotsFrom(DWORD index);
+
+#ifdef FEATURE_PREJIT
+ static BOOL CanShareVtableChunksFrom(MethodTable *pTargetMT, Module *pCurrentLoaderModule, Module *pCurrentPreferredZapModule);
+ BOOL CanInternVtableChunk(DataImage *image, VtableIndirectionSlotIterator it);
+#else
+ static BOOL CanShareVtableChunksFrom(MethodTable *pTargetMT, Module *pCurrentLoaderModule);
+#endif
+
+ inline BOOL HasNonVirtualSlots()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_HasNonVirtualSlots);
+ }
+
+ inline BOOL HasSingleNonVirtualSlot()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_HasSingleNonVirtualSlot);
+ }
+
+ inline BOOL HasNonVirtualSlotsArray()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return HasNonVirtualSlots() && !HasSingleNonVirtualSlot();
+ }
+
+ TADDR GetNonVirtualSlotsPtr();
+
+ inline PTR_PCODE GetNonVirtualSlotsArray()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(HasNonVirtualSlotsArray());
+ return RelativePointer<PTR_PCODE>::GetValueAtPtr(GetNonVirtualSlotsPtr());
+ }
+
+#ifndef DACCESS_COMPILE
+ inline void SetNonVirtualSlotsArray(PTR_PCODE slots)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(HasNonVirtualSlotsArray());
+
+ RelativePointer<PTR_PCODE>::SetValueAtPtr(GetNonVirtualSlotsPtr(), slots);
+ }
+
+ inline void SetHasSingleNonVirtualSlot()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_HasSingleNonVirtualSlot);
+ }
+#endif
+
+ inline unsigned GetNonVirtualSlotsArraySize()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetNumNonVirtualSlots() * sizeof(PCODE);
+ }
+
+ inline WORD GetNumNonVirtualSlots();
+
+ inline WORD GetNumVirtuals()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ g_IBCLogger.LogMethodTableAccess(this);
+ return GetNumVirtuals_NoLogging();
+ }
+
+ inline WORD GetNumVirtuals_NoLogging()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return m_wNumVirtuals;
+ }
+
+ inline void SetNumVirtuals (WORD wNumVtableSlots)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_wNumVirtuals = wNumVtableSlots;
+ }
+
+ unsigned GetNumParentVirtuals()
+ {
+ LIMITED_METHOD_CONTRACT;
+ if (IsInterface() || IsTransparentProxy()) {
+ return 0;
+ }
+ MethodTable *pMTParent = GetParentMethodTable();
+ g_IBCLogger.LogMethodTableAccess(this);
+ return pMTParent == NULL ? 0 : pMTParent->GetNumVirtuals();
+ }
+
+ static inline DWORD GetVtableOffset()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return (sizeof(MethodTable));
+ }
+
+ // Return total methods: virtual, static, and instance method slots.
+ WORD GetNumMethods();
+
+ // Return number of slots in this methodtable. This is just an information about the layout of the methodtable, it should not be used
+ // for functionality checks. Do not confuse with GetNumVirtuals()!
+ WORD GetNumVtableSlots()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetNumVirtuals() + GetNumNonVirtualSlots();
+ }
+
+ //-------------------------------------------------------------------
+ // Slots <-> the MethodDesc associated with the slot.
+ //
+
+ MethodDesc* GetMethodDescForSlot(DWORD slot);
+
+ static MethodDesc* GetMethodDescForSlotAddress(PCODE addr, BOOL fSpeculative = FALSE);
+
+ PCODE GetRestoredSlot(DWORD slot);
+
+ // Returns MethodTable that GetRestoredSlot get its values from
+ MethodTable * GetRestoredSlotMT(DWORD slot);
+
+ // Used to map methods on the same slot between instantiations.
+ MethodDesc * GetParallelMethodDesc(MethodDesc * pDefMD);
+
+ //-------------------------------------------------------------------
+ // BoxedEntryPoint MethodDescs.
+ //
+ // Virtual methods on structs have BoxedEntryPoint method descs in their vtable.
+ // See also notes for MethodDesc::FindOrCreateAssociatedMethodDesc. You should
+ // probably be using that function if you need to map between unboxing
+ // stubs and non-unboxing stubs.
+
+ MethodDesc* GetBoxedEntryPointMD(MethodDesc *pMD);
+
+ MethodDesc* GetUnboxedEntryPointMD(MethodDesc *pMD);
+ MethodDesc* GetExistingUnboxedEntryPointMD(MethodDesc *pMD);
+
+ //-------------------------------------------------------------------
+ // FIELD LAYOUT, OBJECT SIZE ETC.
+ //
+
+ inline BOOL HasLayout();
+
+ inline EEClassLayoutInfo *GetLayoutInfo();
+
+ inline BOOL IsBlittable();
+
+ inline BOOL IsManagedSequential();
+
+ inline BOOL HasExplicitSize();
+
+ UINT32 GetNativeSize();
+
+ DWORD GetBaseSize()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return(m_BaseSize);
+ }
+
+ void SetBaseSize(DWORD baseSize)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_BaseSize = baseSize;
+ }
+
+ BOOL IsStringOrArray() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return HasComponentSize();
+ }
+
+ BOOL IsString()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return HasComponentSize() && !IsArray();
+ }
+
+ BOOL HasComponentSize() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_HasComponentSize);
+ }
+
+ // returns random combination of flags if this doesn't have a component size
+ WORD RawGetComponentSize()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+#if BIGENDIAN
+ return *((WORD*)&m_dwFlags + 1);
+#else // !BIGENDIAN
+ return *(WORD*)&m_dwFlags;
+#endif // !BIGENDIAN
+ }
+
+ // returns 0 if this doesn't have a component size
+
+ // The component size is actually 16-bit WORD, but this method is returning SIZE_T to ensure
+ // that SIZE_T is used everywhere for object size computation. It is necessary to support
+ // objects bigger than 2GB.
+ SIZE_T GetComponentSize()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return HasComponentSize() ? RawGetComponentSize() : 0;
+ }
+
+ void SetComponentSize(WORD wComponentSize)
+ {
+ LIMITED_METHOD_CONTRACT;
+ // it would be nice to assert here that this is either a string
+ // or an array, but how do we know.
+ //
+ // it would also be nice to assert that the component size is > 0,
+ // but it turns out that for array's of System.Void we cannot do
+ // that b/c the component size is 0 (?)
+ SetFlag(enum_flag_HasComponentSize);
+ m_dwFlags = (m_dwFlags & ~0xFFFF) | wComponentSize;
+ }
+
+ inline WORD GetNumInstanceFields();
+
+ inline WORD GetNumStaticFields();
+
+ inline WORD GetNumThreadStaticFields();
+
+ // Note that for value types GetBaseSize returns the size of instance fields for
+ // a boxed value, and GetNumInstanceFieldsBytes for an unboxed value.
+ // We place methods like these on MethodTable primarily so we can choose to cache
+ // the information within MethodTable, and so less code manipulates EEClass
+ // objects directly, because doing so can lead to bugs related to generics.
+ //
+ // <TODO> Use m_wBaseSize whenever this is identical to GetNumInstanceFieldBytes.
+ // We would need to reserve a flag for this. </TODO>
+ //
+ inline DWORD GetNumInstanceFieldBytes();
+
+ inline WORD GetNumIntroducedInstanceFields();
+
+ // <TODO> Does this always return the same (or related) size as GetBaseSize()? </TODO>
+ inline DWORD GetAlignedNumInstanceFieldBytes();
+
+
+ // Note: This flag MUST be available even from an unrestored MethodTable - see GcScanRoots in siginfo.cpp.
+ DWORD ContainsPointers()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_ContainsPointers);
+ }
+ BOOL Collectible()
+ {
+ LIMITED_METHOD_CONTRACT;
+#ifdef FEATURE_COLLECTIBLE_TYPES
+ return GetFlag(enum_flag_Collectible);
+#else
+ return FALSE;
+#endif
+ }
+ BOOL ContainsPointersOrCollectible()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_ContainsPointers) || GetFlag(enum_flag_Collectible);
+ }
+
+ OBJECTHANDLE GetLoaderAllocatorObjectHandle();
+ NOINLINE BYTE *GetLoaderAllocatorObjectForGC();
+
+ BOOL IsNotTightlyPacked();
+
+ void SetContainsPointers()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_ContainsPointers);
+ }
+
+#ifdef FEATURE_64BIT_ALIGNMENT
+ inline bool RequiresAlign8()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return !!GetFlag(enum_flag_RequiresAlign8);
+ }
+
+ inline void SetRequiresAlign8()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_RequiresAlign8);
+ }
+#endif // FEATURE_64BIT_ALIGNMENT
+
+ //-------------------------------------------------------------------
+ // FIELD DESCRIPTORS
+ //
+ // Most of this API still lives on EEClass.
+ //
+ // ************************************ WARNING *************
+ // ** !!!!INSTANCE FIELDDESCS ARE REPRESENTATIVES!!!!! **
+ // ** THEY ARE SHARED BY COMPATIBLE GENERIC INSTANTIATIONS **
+ // ************************************ WARNING *************
+
+ // This goes straight to the EEClass
+ // Careful about using this method. If it's possible that fields may have been added via EnC, then
+ // must use the FieldDescIterator as any fields added via EnC won't be in the raw list
+ PTR_FieldDesc GetApproxFieldDescListRaw();
+
+ // This returns a type-exact FieldDesc for a static field, but may still return a representative
+ // for a non-static field.
+ PTR_FieldDesc GetFieldDescByIndex(DWORD fieldIndex);
+
+ DWORD GetIndexForFieldDesc(FieldDesc *pField);
+
+ //-------------------------------------------------------------------
+ // REMOTING and THUNKING.
+ //
+ // We find a lot of information from the VTable. But sometimes the VTable is a
+ // thunking layer rather than the true type's VTable. For instance, context
+ // proxies use a single VTable for proxies to all the types we've loaded.
+ // The following service adjusts a MethodTable based on the supplied instance. As
+ // we add new thunking layers, we just need to teach this service how to navigate
+ // through them.
+#ifdef FEATURE_REMOTING
+ inline BOOL IsTransparentProxy()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_TransparentProxy;
+ }
+ inline void SetTransparentProxy()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
+ SetFlag(enum_flag_Category_TransparentProxy);
+ }
+
+ inline BOOL IsMarshaledByRef()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_Category_MarshalByRef_Mask) == enum_flag_Category_MarshalByRef;
+ }
+ inline void SetMarshaledByRef()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
+ SetFlag(enum_flag_Category_MarshalByRef);
+ }
+
+ inline BOOL IsContextful()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Contextful;
+ }
+ inline void SetIsContextful()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
+ SetFlag(enum_flag_Category_Contextful);
+ }
+#else // FEATURE_REMOTING
+ inline BOOL IsTransparentProxy()
+ {
+ return FALSE;
+ }
+
+ BOOL IsMarshaledByRef()
+ {
+ return FALSE;
+ }
+
+ BOOL IsContextful()
+ {
+ return FALSE;
+ }
+#endif // FEATURE_REMOTING
+
+ inline bool RequiresFatDispatchTokens()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return !!GetFlag(enum_flag_RequiresDispatchTokenFat);
+ }
+
+ inline void SetRequiresFatDispatchTokens()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_RequiresDispatchTokenFat);
+ }
+
+ inline bool HasPreciseInitCctors()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return !!GetFlag(enum_flag_HasPreciseInitCctors);
+ }
+
+ inline void SetHasPreciseInitCctors()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_HasPreciseInitCctors);
+ }
+
+#if defined(FEATURE_HFA)
+ inline bool IsHFA()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return !!GetFlag(enum_flag_IsHFA);
+ }
+
+ inline void SetIsHFA()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_IsHFA);
+ }
+#endif // FEATURE_HFA
+
+#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
+ inline bool IsRegPassedStruct()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return !!GetFlag(enum_flag_IsRegStructPassed);
+ }
+
+ inline void SetRegPassedStruct()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_IsRegStructPassed);
+ }
+#endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
+
+#ifdef FEATURE_HFA
+
+ CorElementType GetHFAType();
+
+ // The managed and unmanaged HFA type can differ for types with layout. The following two methods return the unmanaged HFA type.
+ bool IsNativeHFA();
+ CorElementType GetNativeHFAType();
+#endif // FEATURE_HFA
+
+#ifdef FEATURE_64BIT_ALIGNMENT
+ // Returns true iff the native view of this type requires 64-bit aligment.
+ bool NativeRequiresAlign8();
+#endif // FEATURE_64BIT_ALIGNMENT
+
+ // True if interface casts for an object having this type require more
+ // than a simple scan of the interface map
+ // See JIT_IsInstanceOfInterface
+ inline BOOL InstanceRequiresNonTrivialInterfaceCast()
+ {
+ STATIC_CONTRACT_SO_TOLERANT;
+ LIMITED_METHOD_CONTRACT;
+
+ return GetFlag(enum_flag_NonTrivialInterfaceCast);
+ }
+
+
+ //-------------------------------------------------------------------
+ // PARENT INTERFACES
+ //
+ unsigned GetNumInterfaces()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return m_wNumInterfaces;
+ }
+
+ //-------------------------------------------------------------------
+ // CASTING
+ //
+ // There are two variants of each of these methods:
+ //
+ // CanCastToX
+ // - restore encoded pointers on demand
+ // - might throw, might trigger GC
+ // - return type is boolean (FALSE = cannot cast, TRUE = can cast)
+ //
+ // CanCastToXNoGC
+ // - do not restore encoded pointers on demand
+ // - does not throw, does not trigger GC
+ // - return type is three-valued (CanCast, CannotCast, MaybeCast)
+ // - MaybeCast indicates that the test tripped on an encoded pointer
+ // so the caller should now call CanCastToXRestoring if it cares
+ //
+ BOOL CanCastToInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
+ BOOL CanCastToClass(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
+ BOOL CanCastToClassOrInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited);
+ BOOL CanCastByVarianceToInterfaceOrDelegate(MethodTable *pTargetMT, TypeHandlePairList *pVisited);
+
+ BOOL CanCastToNonVariantInterface(MethodTable *pTargetMT);
+
+ TypeHandle::CastResult CanCastToInterfaceNoGC(MethodTable *pTargetMT);
+ TypeHandle::CastResult CanCastToClassNoGC(MethodTable *pTargetMT);
+ TypeHandle::CastResult CanCastToClassOrInterfaceNoGC(MethodTable *pTargetMT);
+
+ // The inline part of equivalence check.
+#ifndef DACCESS_COMPILE
+ FORCEINLINE BOOL IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL));
+
+#ifdef FEATURE_COMINTEROP
+ // This method is public so that TypeHandle has direct access to it
+ BOOL IsEquivalentTo_Worker(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO tolerant
+private:
+ BOOL IsEquivalentTo_WorkerInner(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO intolerant
+#endif // FEATURE_COMINTEROP
+#endif
+
+public:
+ //-------------------------------------------------------------------
+ // THE METHOD TABLE PARENT (SUPERCLASS/BASE CLASS)
+ //
+
+ BOOL HasApproxParent()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent) != 0;
+ }
+ inline void SetHasExactParent()
+ {
+ WRAPPER_NO_CONTRACT;
+ FastInterlockAnd(&(GetWriteableDataForWrite()->m_dwFlags), ~MethodTableWriteableData::enum_flag_HasApproxParent);
+ }
+
+
+ // Caller must know that the parent method table is not an encoded fixup
+ inline PTR_MethodTable GetParentMethodTable()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ PRECONDITION(IsParentMethodTablePointerValid());
+
+ TADDR pMT = m_pParentMethodTable;
+#ifdef FEATURE_PREJIT
+ if (GetFlag(enum_flag_HasIndirectParent))
+ pMT = *PTR_TADDR(m_pParentMethodTable + offsetof(MethodTable, m_pParentMethodTable));
+#endif
+ return PTR_MethodTable(pMT);
+ }
+
+ inline static PTR_VOID GetParentMethodTableOrIndirection(PTR_VOID pMT)
+ {
+ WRAPPER_NO_CONTRACT;
+ return PTR_VOID(*PTR_TADDR(dac_cast<TADDR>(pMT) + offsetof(MethodTable, m_pParentMethodTable)));
+ }
+
+ inline MethodTable ** GetParentMethodTablePtr()
+ {
+ WRAPPER_NO_CONTRACT;
+
+#ifdef FEATURE_PREJIT
+ return GetFlag(enum_flag_HasIndirectParent) ?
+ (MethodTable **)(m_pParentMethodTable + offsetof(MethodTable, m_pParentMethodTable)) :(MethodTable **)&m_pParentMethodTable;
+#else
+ return (MethodTable **)&m_pParentMethodTable;
+#endif
+ }
+
+ // Is the parent method table pointer equal to the given argument?
+ BOOL ParentEquals(PTR_MethodTable pMT)
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ PRECONDITION(IsParentMethodTablePointerValid());
+ g_IBCLogger.LogMethodTableAccess(this);
+ return GetParentMethodTable() == pMT;
+ }
+
+#ifdef _DEBUG
+ BOOL IsParentMethodTablePointerValid();
+#endif
+
+#ifndef DACCESS_COMPILE
+ void SetParentMethodTable (MethodTable *pParentMethodTable)
+ {
+ LIMITED_METHOD_CONTRACT;
+ PRECONDITION(!GetFlag(enum_flag_HasIndirectParent));
+ m_pParentMethodTable = (TADDR)pParentMethodTable;
+#ifdef _DEBUG
+ GetWriteableDataForWrite_NoLogging()->SetParentMethodTablePointerValid();
+#endif
+ }
+#endif // !DACCESS_COMPILE
+ MethodTable * GetMethodTableMatchingParentClass(MethodTable * pWhichParent);
+ Instantiation GetInstantiationOfParentClass(MethodTable *pWhichParent);
+
+ //-------------------------------------------------------------------
+ // THE EEClass (Possibly shared between instantiations!).
+ //
+ // Note that it is not generally the case that GetClass.GetMethodTable() == t.
+
+ PTR_EEClass GetClass();
+
+ inline PTR_EEClass GetClass_NoLogging();
+
+ PTR_EEClass GetClassWithPossibleAV();
+
+ BOOL ValidateWithPossibleAV();
+
+ BOOL IsClassPointerValid();
+
+ static UINT32 GetOffsetOfFlags()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return offsetof(MethodTable, m_dwFlags);
+ }
+
+ static UINT32 GetIfArrayThenSzArrayFlag()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return enum_flag_Category_IfArrayThenSzArray;
+ }
+
+ //-------------------------------------------------------------------
+ // CONSTRUCTION
+ //
+ // Do not call the following at any time except when creating a method table.
+ // One day we will have proper constructors for method tables and all these
+ // will disappear.
+#ifndef DACCESS_COMPILE
+ inline void SetClass(EEClass *pClass)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pEEClass = pClass;
+ }
+
+ inline void SetCanonicalMethodTable(MethodTable * pMT)
+ {
+ m_pCanonMT = (TADDR)pMT | MethodTable::UNION_METHODTABLE;
+ }
+#endif
+
+ inline void SetHasInstantiation(BOOL fTypicalInstantiation, BOOL fSharedByGenericInstantiations);
+
+ //-------------------------------------------------------------------
+ // INTERFACE IMPLEMENTATION
+ //
+ public:
+ // Faster force-inlined version of ImplementsInterface
+ BOOL ImplementsInterfaceInline(MethodTable *pInterface);
+
+ BOOL ImplementsInterface(MethodTable *pInterface);
+ BOOL ImplementsEquivalentInterface(MethodTable *pInterface);
+
+ MethodDesc *GetMethodDescForInterfaceMethod(TypeHandle ownerType, MethodDesc *pInterfaceMD);
+ MethodDesc *GetMethodDescForInterfaceMethod(MethodDesc *pInterfaceMD); // You can only use this one for non-generic interfaces
+
+ //-------------------------------------------------------------------
+ // INTERFACE MAP.
+ //
+
+ inline PTR_InterfaceInfo GetInterfaceMap();
+
+#ifndef DACCESS_COMPILE
+ void SetInterfaceMap(WORD wNumInterfaces, InterfaceInfo_t* iMap);
+#endif
+
+ inline int HasInterfaceMap()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return (m_wNumInterfaces != 0);
+ }
+
+ // Where possible, use this iterator over the interface map instead of accessing the map directly
+ // That way we can easily change the implementation of the map
+ class InterfaceMapIterator
+ {
+ friend class MethodTable;
+
+ private:
+ PTR_InterfaceInfo m_pMap;
+ DWORD m_i;
+ DWORD m_count;
+
+ InterfaceMapIterator(MethodTable *pMT)
+ : m_pMap(pMT->GetInterfaceMap()),
+ m_i((DWORD) -1),
+ m_count(pMT->GetNumInterfaces())
+ {
+ WRAPPER_NO_CONTRACT;
+ }
+
+ InterfaceMapIterator(MethodTable *pMT, DWORD index)
+ : m_pMap(pMT->GetInterfaceMap() + index),
+ m_i(index),
+ m_count(pMT->GetNumInterfaces())
+ {
+ WRAPPER_NO_CONTRACT;
+ CONSISTENCY_CHECK(index >= 0 && index < m_count);
+ }
+
+ public:
+ InterfaceInfo_t* GetInterfaceInfo()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_pMap;
+ }
+
+ // Move to the next item in the map, returning TRUE if an item
+ // exists or FALSE if we've run off the end
+ inline BOOL Next()
+ {
+ LIMITED_METHOD_CONTRACT;
+ PRECONDITION(!Finished());
+ if (m_i != (DWORD) -1)
+ m_pMap++;
+ return (++m_i < m_count);
+ }
+
+ // Have we iterated over all of the items?
+ BOOL Finished()
+ {
+ return (m_i == m_count);
+ }
+
+ // Get the interface at the current position
+ inline PTR_MethodTable GetInterface()
+ {
+ CONTRACT(PTR_MethodTable)
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ SUPPORTS_DAC;
+ PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ RETURN (m_pMap->GetMethodTable());
+ }
+
+#ifndef DACCESS_COMPILE
+ void SetInterface(MethodTable *pMT)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_pMap->SetMethodTable(pMT);
+ }
+#endif
+
+ DWORD GetIndex()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_i;
+ }
+ }; // class InterfaceMapIterator
+
+ // Create a new iterator over the interface map
+ // The iterator starts just before the first item in the map
+ InterfaceMapIterator IterateInterfaceMap()
+ {
+ WRAPPER_NO_CONTRACT;
+ return InterfaceMapIterator(this);
+ }
+
+ // Create a new iterator over the interface map, starting at the index specified
+ InterfaceMapIterator IterateInterfaceMapFrom(DWORD index)
+ {
+ WRAPPER_NO_CONTRACT;
+ return InterfaceMapIterator(this, index);
+ }
+
+ //-------------------------------------------------------------------
+ // ADDITIONAL INTERFACE MAP DATA
+ //
+
+ // We store extra info (flag bits) for interfaces implemented on this MethodTable in a separate optional
+ // location for better data density (if we put them in the interface map directly data alignment could
+ // have us using 32 or even 64 bits to represent a single boolean value). Currently the only flag we
+ // persist is IsDeclaredOnClass (was the interface explicitly declared by this class).
+
+ // Currently we always store extra info whenever we have an interface map (in the future you could imagine
+ // this being limited to those scenarios in which at least one of the interfaces has a non-default value
+ // for a flag).
+ inline BOOL HasExtraInterfaceInfo()
+ {
+ SUPPORTS_DAC;
+ return HasInterfaceMap();
+ }
+
+ // Count of interfaces that can have their extra info stored inline in the optional data structure itself
+ // (once the interface count exceeds this limit the optional data slot will instead point to a buffer with
+ // the information).
+ enum { kInlinedInterfaceInfoThreshhold = sizeof(TADDR) * 8 };
+
+ // Calculate how many bytes of storage will be required to track additional information for interfaces.
+ // This will be zero if there are no interfaces, but can also be zero for small numbers of interfaces as
+ // well, and callers should be ready to handle this.
+ static SIZE_T GetExtraInterfaceInfoSize(DWORD cInterfaces);
+
+ // Called after GetExtraInterfaceInfoSize above to setup a new MethodTable with the additional memory to
+ // track extra interface info. If there are a non-zero number of interfaces implemented on this class but
+ // GetExtraInterfaceInfoSize() returned zero, this call must still be made (with a NULL argument).
+ void InitializeExtraInterfaceInfo(PVOID pInfo);
+
+#ifdef FEATURE_PREJIT
+ // Ngen support.
+ void SaveExtraInterfaceInfo(DataImage *pImage);
+ void FixupExtraInterfaceInfo(DataImage *pImage);
+#endif // FEATURE_PREJIT
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegionsForExtraInterfaceInfo();
+#endif // DACCESS_COMPILE
+
+ // For the given interface in the map (specified via map index) mark the interface as declared explicitly
+ // on this class. This is not legal for dynamically added interfaces (as used by RCWs).
+ void SetInterfaceDeclaredOnClass(DWORD index);
+
+ // For the given interface in the map (specified via map index) return true if the interface was declared
+ // explicitly on this class.
+ bool IsInterfaceDeclaredOnClass(DWORD index);
+
+ //-------------------------------------------------------------------
+ // VIRTUAL/INTERFACE CALL RESOLUTION
+ //
+ // These should probably go in method.hpp since they don't have
+ // much to do with method tables per se.
+ //
+
+ // get the method desc given the interface method desc
+ static MethodDesc *GetMethodDescForInterfaceMethodAndServer(TypeHandle ownerType, MethodDesc *pItfMD, OBJECTREF *pServer);
+
+#ifdef FEATURE_COMINTEROP
+ // get the method desc given the interface method desc on a COM implemented server (if fNullOk is set then NULL is an allowable return value)
+ MethodDesc *GetMethodDescForComInterfaceMethod(MethodDesc *pItfMD, bool fNullOk);
+#endif // FEATURE_COMINTEROP
+
+
+ // Try a partial resolve of the constraint call, up to generic code sharing.
+ //
+ // Note that this will not necessarily resolve the call exactly, since we might be compiling
+ // shared generic code - it may just resolve it to a candidate suitable for
+ // JIT compilation, and require a runtime lookup for the actual code pointer
+ // to call.
+ //
+ // Return NULL if the call could not be resolved, e.g. because it is invoked
+ // on a type that inherits the implementation of the method from System.Object
+ // or System.ValueType.
+ //
+ // Always returns an unboxed entry point with a uniform calling convention.
+ MethodDesc * TryResolveConstraintMethodApprox(
+ TypeHandle ownerType,
+ MethodDesc * pMD,
+ BOOL * pfForceUseRuntimeLookup = NULL);
+
+ //-------------------------------------------------------------------
+ // CONTRACT IMPLEMENTATIONS
+ //
+
+ inline BOOL HasDispatchMap()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetDispatchMap() != NULL;
+ }
+
+ PTR_DispatchMap GetDispatchMap();
+
+ inline BOOL HasDispatchMapSlot()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_HasDispatchMapSlot);
+ }
+
+#ifndef DACCESS_COMPILE
+ void SetDispatchMap(DispatchMap *pDispatchMap)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(HasDispatchMapSlot());
+
+ TADDR pSlot = GetMultipurposeSlotPtr(enum_flag_HasDispatchMapSlot, c_DispatchMapSlotOffsets);
+ RelativePointer<PTR_DispatchMap>::SetValueAtPtr(pSlot, pDispatchMap);
+ }
+#endif // !DACCESS_COMPILE
+
+protected:
+ BOOL FindEncodedMapDispatchEntry(UINT32 typeID,
+ UINT32 slotNumber,
+ DispatchMapEntry *pEntry);
+
+ BOOL FindIntroducedImplementationTableDispatchEntry(UINT32 slotNumber,
+ DispatchMapEntry *pEntry,
+ BOOL fVirtualMethodsOnly);
+
+ BOOL FindDispatchEntryForCurrentType(UINT32 typeID,
+ UINT32 slotNumber,
+ DispatchMapEntry *pEntry);
+
+ BOOL FindDispatchEntry(UINT32 typeID,
+ UINT32 slotNumber,
+ DispatchMapEntry *pEntry);
+
+public:
+ BOOL FindDispatchImpl(
+ UINT32 typeID,
+ UINT32 slotNumber,
+ DispatchSlot * pImplSlot);
+
+ DispatchSlot FindDispatchSlot(UINT32 typeID, UINT32 slotNumber);
+
+ DispatchSlot FindDispatchSlot(DispatchToken tok);
+
+ // You must use the second of these two if there is any chance the pMD is a method
+ // on a generic interface such as IComparable<T> (which it normally can be). The
+ // ownerType is used to provide an exact qualification in the case the pMD is
+ // a shared method descriptor.
+ DispatchSlot FindDispatchSlotForInterfaceMD(MethodDesc *pMD);
+ DispatchSlot FindDispatchSlotForInterfaceMD(TypeHandle ownerType, MethodDesc *pMD);
+
+ MethodDesc *ReverseInterfaceMDLookup(UINT32 slotNumber);
+
+ // Lookup, does not assign if not already done.
+ UINT32 LookupTypeID();
+ // Lookup, will assign ID if not already done.
+ UINT32 GetTypeID();
+
+
+ MethodTable *LookupDispatchMapType(DispatchMapTypeID typeID);
+
+ MethodDesc *GetIntroducingMethodDesc(DWORD slotNumber);
+
+ // Determines whether all methods in the given interface have their final implementing
+ // slot in a parent class. I.e. if this returns TRUE, it is trivial (no VSD lookup) to
+ // dispatch pItfMT methods on this class if one knows how to dispatch them on pParentMT.
+ BOOL ImplementsInterfaceWithSameSlotsAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
+
+ // Determines whether all methods in the given interface have their final implementation
+ // in a parent class. I.e. if this returns TRUE, this class behaves the same as pParentMT
+ // when it comes to dispatching pItfMT methods.
+ BOOL HasSameInterfaceImplementationAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
+
+public:
+ static MethodDesc *MapMethodDeclToMethodImpl(MethodDesc *pMDDecl);
+
+ //-------------------------------------------------------------------
+ // FINALIZATION SEMANTICS
+ //
+
+ DWORD CannotUseSuperFastHelper()
+ {
+ WRAPPER_NO_CONTRACT;
+ return HasFinalizer();
+ }
+
+ void SetHasFinalizer()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_HasFinalizer);
+ }
+
+ void SetHasCriticalFinalizer()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_HasCriticalFinalizer);
+ }
+ // Does this class have non-trivial finalization requirements?
+ DWORD HasFinalizer()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_HasFinalizer);
+ }
+ // Must this class be finalized during a rude appdomain unload, and
+ // must it's finalizer run in a different order from normal finalizers?
+ DWORD HasCriticalFinalizer() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_HasCriticalFinalizer);
+ }
+
+ // Have the backout methods (Finalizer, Dispose, ReleaseHandle etc.) been prepared for this type? This currently only happens
+ // for types derived from CriticalFinalizerObject.
+ BOOL CriticalTypeHasBeenPrepared()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(HasCriticalFinalizer());
+ return GetWriteableData()->CriticalTypeHasBeenPrepared();
+ }
+
+ void SetCriticalTypeHasBeenPrepared()
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(HasCriticalFinalizer());
+ GetWriteableDataForWrite()->SetCriticalTypeHasBeenPrepared();
+ }
+
+ //-------------------------------------------------------------------
+ // STATIC FIELDS
+ //
+
+ DWORD GetOffsetOfFirstStaticHandle();
+ DWORD GetOffsetOfFirstStaticMT();
+
+#ifndef DACCESS_COMPILE
+ inline PTR_BYTE GetNonGCStaticsBasePointer();
+ inline PTR_BYTE GetGCStaticsBasePointer();
+ inline PTR_BYTE GetNonGCThreadStaticsBasePointer();
+ inline PTR_BYTE GetGCThreadStaticsBasePointer();
+#endif //!DACCESS_COMPILE
+
+ inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain);
+ inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain);
+
+ inline DWORD IsDynamicStatics()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return !TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_NonDynamic);
+ }
+
+ inline void SetDynamicStatics(BOOL fGeneric)
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(fGeneric ? enum_flag_StaticsMask_Generics : enum_flag_StaticsMask_Dynamic);
+ }
+
+ inline void SetHasBoxedRegularStatics()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_HasBoxedRegularStatics);
+ }
+
+ inline DWORD HasBoxedRegularStatics()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_HasBoxedRegularStatics);
+ }
+
+ DWORD HasFixedAddressVTStatics();
+
+ //-------------------------------------------------------------------
+ // PER-INSTANTIATION STATICS INFO
+ //
+
+
+ void SetupGenericsStaticsInfo(FieldDesc* pStaticFieldDescs);
+
+ BOOL HasGenericsStaticsInfo()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_StaticsMask_Generics);
+ }
+
+ PTR_FieldDesc GetGenericsStaticFieldDescs()
+ {
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(HasGenericsStaticsInfo());
+ return GetGenericsStaticsInfo()->m_pFieldDescs;
+ }
+
+ BOOL HasCrossModuleGenericStaticsInfo()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_CrossModuleGenerics);
+ }
+
+ PTR_Module GetGenericsStaticsModuleAndID(DWORD * pID);
+
+ WORD GetNumHandleRegularStatics();
+
+ WORD GetNumBoxedRegularStatics ();
+ WORD GetNumBoxedThreadStatics ();
+
+ //-------------------------------------------------------------------
+ // DYNAMIC ID
+ //
+
+ // Used for generics and reflection emit in memory
+ DWORD GetModuleDynamicEntryID();
+ Module* GetModuleForStatics();
+
+ //-------------------------------------------------------------------
+ // GENERICS DICT INFO
+ //
+
+ // Number of generic arguments, whether this is a method table for
+ // a generic type instantiation, e.g. List<string> or the "generic" MethodTable
+ // e.g. for List.
+ inline DWORD GetNumGenericArgs()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ if (HasInstantiation())
+ return (DWORD) (GetGenericsDictInfo()->m_wNumTyPars);
+ else
+ return 0;
+ }
+
+ inline DWORD GetNumDicts()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ if (HasPerInstInfo())
+ {
+ PTR_GenericsDictInfo pDictInfo = GetGenericsDictInfo();
+ return (DWORD) (pDictInfo->m_wNumDicts);
+ }
+ else
+ return 0;
+ }
+
+ //-------------------------------------------------------------------
+ // OBJECTS
+ //
+
+ OBJECTREF Allocate();
+
+ // This flavor of Allocate is more efficient, but can only be used
+ // if IsRestored(), CheckInstanceActivated(), IsClassInited() are known to be true.
+ // A sufficient condition is that another instance of the exact same type already
+ // exists in the same appdomain. It's currently called only from Delegate.Combine
+ // via COMDelegate::InternalAllocLike.
+ OBJECTREF AllocateNoChecks();
+
+ OBJECTREF Box(void* data);
+ OBJECTREF FastBox(void** data);
+#ifndef DACCESS_COMPILE
+ BOOL UnBoxInto(void *dest, OBJECTREF src);
+ BOOL UnBoxIntoArg(ArgDestination *argDest, OBJECTREF src);
+ void UnBoxIntoUnchecked(void *dest, OBJECTREF src);
+#endif
+
+#ifdef _DEBUG
+ // Used for debugging class layout. Dumps to the debug console
+ // when debug is true.
+ void DebugDumpVtable(LPCUTF8 szClassName, BOOL fDebug);
+ void Debug_DumpInterfaceMap(LPCSTR szInterfaceMapPrefix);
+ void Debug_DumpDispatchMap();
+ void DebugDumpFieldLayout(LPCUTF8 pszClassName, BOOL debug);
+ void DebugRecursivelyDumpInstanceFields(LPCUTF8 pszClassName, BOOL debug);
+ void DebugDumpGCDesc(LPCUTF8 pszClassName, BOOL debug);
+#endif //_DEBUG
+
+ inline BOOL IsAgileAndFinalizable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ // Right now, System.Thread is the only cases of this.
+ // Things should stay this way - please don't change without talking to EE team.
+ return this == g_pThreadClass;
+ }
+
+
+ //-------------------------------------------------------------------
+ // ENUMS, DELEGATES, VALUE TYPES, ARRAYS
+ //
+ // #KindsOfElementTypes
+ // GetInternalCorElementType() retrieves the internal representation of the type. It's not always
+ // appropiate to use this. For example, we treat enums as their underlying type or some structs are
+ // optimized to be ints. To get the signature type or the verifier type (same as signature except for
+ // enums are normalized to the primtive type that underlies them), use the APIs in Typehandle.h
+ //
+ // * code:TypeHandle.GetSignatureCorElementType()
+ // * code:TypeHandle.GetVerifierCorElementType()
+ // * code:TypeHandle.GetInternalCorElementType()
+ CorElementType GetInternalCorElementType();
+ void SetInternalCorElementType(CorElementType _NormType);
+
+ // See code:TypeHandle::GetVerifierCorElementType for description
+ CorElementType GetVerifierCorElementType();
+
+ // See code:TypeHandle::GetSignatureCorElementType for description
+ CorElementType GetSignatureCorElementType();
+
+ // A true primitive is one who's GetVerifierCorElementType() ==
+ // ELEMENT_TYPE_I,
+ // ELEMENT_TYPE_I4,
+ // ELEMENT_TYPE_TYPEDBYREF etc.
+ // Note that GetIntenalCorElementType might return these same values for some additional
+ // types such as Enums and some structs.
+ BOOL IsTruePrimitive();
+ void SetIsTruePrimitive();
+
+ // Is this delegate? Returns false for System.Delegate and System.MulticastDelegate.
+ inline BOOL IsDelegate()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ // We do not allow single cast delegates anymore, just check for multicast delegate
+ _ASSERTE(g_pMulticastDelegateClass);
+ return ParentEquals(g_pMulticastDelegateClass);
+ }
+
+ // Is this System.Object?
+ inline BOOL IsObjectClass()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(g_pObjectClass);
+ return (this == g_pObjectClass);
+ }
+
+ // Is this System.ValueType?
+ inline DWORD IsValueTypeClass()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(g_pValueTypeClass);
+ return (this == g_pValueTypeClass);
+ }
+
+ // Is this value type? Returns false for System.ValueType and System.Enum.
+ inline BOOL IsValueType();
+
+ // Returns "TRUE" iff "this" is a struct type such that return buffers used for returning a value
+ // of this type must be stack-allocated. This will generally be true only if the struct
+ // contains GC pointers, and does not exceed some size limit. Maintaining this as an invariant allows
+ // an optimization: the JIT may assume that return buffer pointers for return types for which this predicate
+ // returns TRUE are always stack allocated, and thus, that stores to the GC-pointer fields of such return
+ // buffers do not require GC write barriers.
+ BOOL IsStructRequiringStackAllocRetBuf();
+
+ // Is this enum? Returns false for System.Enum.
+ inline BOOL IsEnum();
+
+ // Is this array? Returns false for System.Array.
+ inline BOOL IsArray()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_Category_Array_Mask) == enum_flag_Category_Array;
+ }
+ inline BOOL IsMultiDimArray()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ PRECONDITION(IsArray());
+ return !GetFlag(enum_flag_Category_IfArrayThenSzArray);
+ }
+
+ // Returns true if this type is Nullable<T> for some T.
+ inline BOOL IsNullable()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Nullable;
+ }
+
+ inline void SetIsNullable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType);
+ SetFlag(enum_flag_Category_Nullable);
+ }
+
+ inline BOOL IsStructMarshalable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ PRECONDITION(!IsInterface());
+ return GetFlag(enum_flag_IfNotInterfaceThenMarshalable);
+ }
+
+ inline void SetStructMarshalable()
+ {
+ LIMITED_METHOD_CONTRACT;
+ PRECONDITION(!IsInterface());
+ SetFlag(enum_flag_IfNotInterfaceThenMarshalable);
+ }
+
+ // The following methods are only valid for the
+ // method tables for array types. These MTs may
+ // be shared between array types and thus GetArrayElementTypeHandle
+ // may only be approximate. If you need the exact element type handle then
+ // you should probably be calling GetArrayElementTypeHandle on a TypeHandle,
+ // or an ArrayTypeDesc, or on an object reference that is known to be an array,
+ // e.g. a BASEARRAYREF.
+ //
+ // At the moment only the object[] MethodTable is shared between array types.
+ // In the future the amount of sharing of method tables is likely to be increased.
+ CorElementType GetArrayElementType();
+ DWORD GetRank();
+
+ TypeHandle GetApproxArrayElementTypeHandle()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE (IsArray());
+ return TypeHandle::FromTAddr(m_ElementTypeHnd);
+ }
+
+ void SetApproxArrayElementTypeHandle(TypeHandle th)
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ m_ElementTypeHnd = th.AsTAddr();
+ }
+
+ TypeHandle * GetApproxArrayElementTypeHandlePtr()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (TypeHandle *)&m_ElementTypeHnd;
+ }
+
+ static inline DWORD GetOffsetOfArrayElementTypeHandle()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return offsetof(MethodTable, m_ElementTypeHnd);
+ }
+
+ //-------------------------------------------------------------------
+ // UNDERLYING METADATA
+ //
+
+
+ // Get the RID/token for the metadata for the corresponding type declaration
+ unsigned GetTypeDefRid();
+ unsigned GetTypeDefRid_NoLogging();
+
+ inline mdTypeDef GetCl()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return TokenFromRid(GetTypeDefRid(), mdtTypeDef);
+ }
+
+ inline mdTypeDef GetCl_NoLogging()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return TokenFromRid(GetTypeDefRid_NoLogging(), mdtTypeDef);
+ }
+
+ void SetCl(mdTypeDef token);
+
+#ifdef _DEBUG
+// Make this smaller in debug builds to exercise the overflow codepath
+#define METHODTABLE_TOKEN_OVERFLOW 0xFFF
+#else
+#define METHODTABLE_TOKEN_OVERFLOW 0xFFFF
+#endif
+
+ BOOL HasTokenOverflow()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return m_wToken == METHODTABLE_TOKEN_OVERFLOW;
+ }
+
+ // Get the MD Import for the metadata for the corresponding type declaration
+ IMDInternalImport* GetMDImport();
+
+ mdTypeDef GetEnclosingCl();
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
+#endif
+
+ //-------------------------------------------------------------------
+ // REMOTEABLE METHOD INFO
+ //
+#ifdef FEATURE_REMOTING
+ BOOL HasRemotableMethodInfo();
+
+ PTR_CrossDomainOptimizationInfo GetRemotableMethodInfo()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ _ASSERTE(HasRemotableMethodInfo());
+ return *GetRemotableMethodInfoPtr();
+ }
+ void SetupRemotableMethodInfo(AllocMemTracker *pamTracker);
+
+ //-------------------------------------------------------------------
+ // REMOTING VTS INFO
+ //
+ // This optional addition to MethodTables allows us to locate VTS (Version
+ // Tolerant Serialization) event callback methods and optionally
+ // serializable fields quickly. We also store the NotSerialized field
+ // information in here so remoting can avoid one more touch of the metadata
+ // during cross appdomain cloning.
+ //
+
+ void SetHasRemotingVtsInfo();
+ BOOL HasRemotingVtsInfo();
+ PTR_RemotingVtsInfo GetRemotingVtsInfo();
+ PTR_RemotingVtsInfo AllocateRemotingVtsInfo( AllocMemTracker *pamTracker, DWORD dwNumFields);
+#endif // FEATURE_REMOTING
+
+#ifdef FEATURE_COMINTEROP
+ void SetHasGuidInfo();
+ BOOL HasGuidInfo();
+ void SetHasCCWTemplate();
+ BOOL HasCCWTemplate();
+ void SetHasRCWPerTypeData();
+ BOOL HasRCWPerTypeData();
+#endif // FEATURE_COMINTEROP
+
+ // The following two methods produce correct results only if this type is
+ // marked Serializable (verified by assert in checked builds) and the field
+ // in question was introduced in this type (the index is the FieldDesc
+ // index).
+ BOOL IsFieldNotSerialized(DWORD dwFieldIndex);
+ BOOL IsFieldOptionallySerialized(DWORD dwFieldIndex);
+
+ //-------------------------------------------------------------------
+ // DICTIONARIES FOR GENERIC INSTANTIATIONS
+ //
+ // The PerInstInfo pointer is a pointer to per-instantiation pointer table,
+ // each entry of which points to an instantiation "dictionary"
+ // for an instantiated type; the last pointer points to a
+ // dictionary which is specific to this method table, previous
+ // entries point to dictionaries in superclasses. Instantiated interfaces and structs
+ // have just single dictionary (no inheritance).
+ //
+ // GetNumDicts() gives the number of dictionaries.
+ //
+ //@nice GENERICS: instead of a separate table of pointers, put the pointers
+ // in the vtable itself. Advantages:
+ // * Time: we save an indirection as we don't need to go through PerInstInfo first.
+ // * Space: no need for PerInstInfo (1 word)
+ // Problem is that lots of code assumes that the vtable is filled
+ // uniformly with pointers to MethodDesc stubs.
+ //
+ // The dictionary for the method table is just an array of handles for
+ // type parameters in the following cases:
+ // * instantiated interfaces (no code)
+ // * instantiated types whose code is not shared
+ // Otherwise, it starts with the type parameters and then has a fixed
+ // number of slots for handles (types & methods)
+ // that are filled in lazily at run-time. Finally there is a "spill-bucket"
+ // pointer used when the dictionary gets filled.
+ // In summary:
+ // typar_1 type handle for first type parameter
+ // ...
+ // typar_n type handle for last type parameter
+ // slot_1 slot for first run-time handle (initially null)
+ // ...
+ // slot_m slot for last run-time handle (initially null)
+ // next_bucket pointer to spill bucket (possibly null)
+ // The spill bucket contains just run-time handle slots.
+ // (Alternative: continue chaining buckets.
+ // Advantage: no need to deallocate when growing dictionaries.
+ // Disadvantage: more indirections required at run-time.)
+ //
+ // The layout of dictionaries is determined by GetClass()->GetDictionaryLayout()
+ // Thus the layout can vary between incompatible instantiations. This is sometimes useful because individual type
+ // parameters may or may not be shared. For example, consider a two parameter class Dict<K,D>. In instantiations shared with
+ // Dict<double,string> any reference to K is known at JIT-compile-time (it's double) but any token containing D
+ // must have a dictionary entry. On the other hand, for instantiations shared with Dict<string,double> the opposite holds.
+ //
+
+ // Return a pointer to the per-instantiation information. See field itself for comments.
+ DPTR(PTR_Dictionary) GetPerInstInfo()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(HasPerInstInfo());
+ return dac_cast<DPTR(PTR_Dictionary)>(m_pMultipurposeSlot1);
+ }
+ BOOL HasPerInstInfo()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_HasPerInstInfo) && !IsArray();
+ }
+#ifndef DACCESS_COMPILE
+ static inline DWORD GetOffsetOfPerInstInfo()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return offsetof(MethodTable, m_pPerInstInfo);
+ }
+ void SetPerInstInfo(Dictionary** pPerInstInfo)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pPerInstInfo = pPerInstInfo;
+ }
+ void SetDictInfo(WORD numDicts, WORD numTyPars)
+ {
+ WRAPPER_NO_CONTRACT;
+ GenericsDictInfo* pInfo = GetGenericsDictInfo();
+ pInfo->m_wNumDicts = numDicts;
+ pInfo->m_wNumTyPars = numTyPars;
+ }
+#endif // !DACCESS_COMPILE
+ PTR_GenericsDictInfo GetGenericsDictInfo()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ // GenericsDictInfo is stored at negative offset of the dictionary
+ return dac_cast<PTR_GenericsDictInfo>(GetPerInstInfo()) - 1;
+ }
+
+ // Get a pointer to the dictionary for this instantiated type
+ // (The instantiation is stored in the initial slots of the dictionary)
+ // If not instantiated, return NULL
+ Dictionary* GetDictionary();
+
+#ifdef FEATURE_PREJIT
+ //
+ // After the zapper compiles all code in a module it may attempt
+ // to populate entries in all dictionaries
+ // associated with generic types. This is an optional step - nothing will
+ // go wrong at runtime except we may get more one-off calls to JIT_GenericHandle.
+ // Although these are one-off we prefer to avoid them since they touch metadata
+ // pages.
+ //
+ // Fully populating a dictionary may in theory load more types. However
+ // for the moment only those entries that refer to types that
+ // are already loaded will be filled in.
+ void PrepopulateDictionary(DataImage * image, BOOL nonExpansive);
+#endif // FEATURE_PREJIT
+
+ // Return a substitution suitbale for interpreting
+ // the metadata in parent class, assuming we already have a subst.
+ // suitable for interpreting the current class.
+ //
+ // If, for example, the definition for the current class is
+ // D<T> : C<List<T>, T[] >
+ // then this (for C<!0,!1>) will be
+ // 0 --> List<T>
+ // 1 --> T[]
+ // added to the chain of substitutions.
+ //
+ // Subsequently, if the definition for C is
+ // C<T, U> : B< Dictionary<T, U> >
+ // then the next subst (for B<!0>) will be
+ // 0 --> Dictionary< List<T>, T[] >
+
+ Substitution GetSubstitutionForParent(const Substitution *pSubst);
+
+ inline DWORD GetAttrClass();
+
+ inline BOOL IsSerializable();
+#ifdef FEATURE_REMOTING
+ inline BOOL CannotBeBlittedByObjectCloner();
+#endif
+ inline BOOL HasFieldsWhichMustBeInited();
+ inline BOOL SupportsAutoNGen();
+ inline BOOL RunCCTorAsIfNGenImageExists();
+
+ //-------------------------------------------------------------------
+ // SECURITY SEMANTICS
+ //
+
+
+ BOOL IsNoSecurityProperties()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return GetFlag(enum_flag_NoSecurityProperties);
+ }
+
+ void SetNoSecurityProperties()
+ {
+ LIMITED_METHOD_CONTRACT;
+ SetFlag(enum_flag_NoSecurityProperties);
+ }
+
+ void SetIsAsyncPinType()
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
+ SetFlag(enum_flag_Category_AsyncPin);
+ }
+
+ BOOL IsAsyncPinType()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_AsyncPin;
+ }
+
+ inline BOOL IsPreRestored() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return GetFlag(enum_flag_IsPreRestored);
+ }
+
+ //-------------------------------------------------------------------
+ // THE EXPOSED CLASS OBJECT
+ //
+ /*
+ * m_ExposedClassObject is a RuntimeType instance for this class. But
+ * do NOT use it for Arrays or remoted objects! All arrays of objects
+ * share the same MethodTable/EEClass.
+ * @GENERICS: this is per-instantiation data
+ */
+ // There are two version of GetManagedClassObject. The GetManagedClassObject()
+ // method will get the class object. If it doesn't exist it will be created.
+ // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist.
+ OBJECTREF GetManagedClassObject();
+ OBJECTREF GetManagedClassObjectIfExists();
+
+
+ // ------------------------------------------------------------------
+ // Private part of MethodTable
+ // ------------------------------------------------------------------
+
+ inline void SetWriteableData(PTR_MethodTableWriteableData pMTWriteableData)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(pMTWriteableData);
+ m_pWriteableData = pMTWriteableData;
+ }
+
+ inline PTR_Const_MethodTableWriteableData GetWriteableData() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ g_IBCLogger.LogMethodTableWriteableDataAccess(this);
+ return m_pWriteableData;
+ }
+
+ inline PTR_Const_MethodTableWriteableData GetWriteableData_NoLogging() const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return m_pWriteableData;
+ }
+
+ inline PTR_MethodTableWriteableData GetWriteableDataForWrite()
+ {
+ LIMITED_METHOD_CONTRACT;
+ g_IBCLogger.LogMethodTableWriteableDataWriteAccess(this);
+ return m_pWriteableData;
+ }
+
+ inline PTR_MethodTableWriteableData GetWriteableDataForWrite_NoLogging()
+ {
+ return m_pWriteableData;
+ }
+
+ //-------------------------------------------------------------------
+ // Remoting related
+ //
+ inline BOOL IsRemotingConfigChecked()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetWriteableData()->IsRemotingConfigChecked();
+ }
+ inline void SetRemotingConfigChecked()
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ GetWriteableDataForWrite()->SetRemotingConfigChecked();
+ }
+ inline void TrySetRemotingConfigChecked()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SO_TOLERANT;
+ }
+ CONTRACTL_END;
+
+ GetWriteableDataForWrite()->TrySetRemotingConfigChecked();
+ }
+ inline BOOL RequiresManagedActivation()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetWriteableData()->RequiresManagedActivation();
+ }
+ inline void SetRequiresManagedActivation()
+ {
+ CONTRACTL
+ {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ GetWriteableDataForWrite()->SetRequiresManagedActivation();
+ }
+
+ // Determines whether the type may require managed activation. The actual answer is known later
+ // once the remoting config is checked.
+ inline BOOL MayRequireManagedActivation()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return IsMarshaledByRef();
+ }
+
+ //-------------------------------------------------------------------
+ // The GUID Info
+ // Used by COM interop to get GUIDs (IIDs and CLSIDs)
+
+ // Get/store cached GUID information
+ PTR_GuidInfo GetGuidInfo();
+ void SetGuidInfo(GuidInfo* pGuidInfo);
+
+ // Get and cache the GUID for this interface/class
+ HRESULT GetGuidNoThrow(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
+
+ // Get and cache the GUID for this interface/class
+ void GetGuid(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
+
+#ifdef FEATURE_COMINTEROP
+ // Get the GUID used for WinRT interop
+ // * for projection generic interfaces returns the equivalent WinRT type's GUID
+ // * for everything else returns the GetGuid(, TRUE)
+ BOOL GetGuidForWinRT(GUID *pGuid);
+
+private:
+ // Create RCW data associated with this type.
+ RCWPerTypeData *CreateRCWPerTypeData(bool bThrowOnOOM);
+
+public:
+ // Get the RCW data associated with this type or NULL if the type does not need such data or allocation
+ // failed (only if bThrowOnOOM is false).
+ RCWPerTypeData *GetRCWPerTypeData(bool bThrowOnOOM = true);
+#endif // FEATURE_COMINTEROP
+
+ // Convenience method - determine if the interface/class has a guid specified (even if not yet cached)
+ BOOL HasExplicitGuid();
+
+public :
+ // Helper routines for the GetFullyQualifiedNameForClass macros defined at the top of class.h.
+ // You probably should not use these functions directly.
+ SString &_GetFullyQualifiedNameForClassNestedAware(SString &ssBuf);
+ SString &_GetFullyQualifiedNameForClass(SString &ssBuf);
+ LPCUTF8 GetFullyQualifiedNameInfo(LPCUTF8 *ppszNamespace);
+
+private:
+ template<typename RedirectFunctor> SString &_GetFullyQualifiedNameForClassNestedAwareInternal(SString &ssBuf);
+
+public :
+ //-------------------------------------------------------------------
+ // Debug Info
+ //
+
+
+#ifdef _DEBUG
+ inline LPCUTF8 GetDebugClassName()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return debug_m_szClassName;
+ }
+ inline void SetDebugClassName(LPCUTF8 name)
+ {
+ LIMITED_METHOD_CONTRACT;
+ debug_m_szClassName = name;
+ }
+
+ // Was the type created with injected duplicates?
+ // TRUE means that we tried to inject duplicates (not that we found one to inject).
+ inline BOOL Debug_HasInjectedInterfaceDuplicates() const
+ {
+ LIMITED_METHOD_CONTRACT;
+ return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates) != 0;
+ }
+ inline void Debug_SetHasInjectedInterfaceDuplicates()
+ {
+ LIMITED_METHOD_CONTRACT;
+ GetWriteableDataForWrite()->m_dwFlags |= MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates;
+ }
+#endif // _DEBUG
+
+
+#ifndef DACCESS_COMPILE
+public:
+ //--------------------------------------------------------------------------------------
+ class MethodData
+ {
+ public:
+ inline ULONG AddRef()
+ { LIMITED_METHOD_CONTRACT; return (ULONG) InterlockedIncrement((LONG*)&m_cRef); }
+
+ ULONG Release();
+
+ // Since all methods that return a MethodData already AddRef'd, we do NOT
+ // want to AddRef when putting a holder around it. We only want to release it.
+ static void HolderAcquire(MethodData *pEntry)
+ { LIMITED_METHOD_CONTRACT; return; }
+ static void HolderRelease(MethodData *pEntry)
+ { WRAPPER_NO_CONTRACT; if (pEntry != NULL) pEntry->Release(); }
+
+ protected:
+ ULONG m_cRef;
+
+ public:
+ MethodData() : m_cRef(1) { LIMITED_METHOD_CONTRACT; }
+ virtual ~MethodData() { LIMITED_METHOD_CONTRACT; }
+
+ virtual MethodData *GetDeclMethodData() = 0;
+ virtual MethodTable *GetDeclMethodTable() = 0;
+ virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber) = 0;
+
+ virtual MethodData *GetImplMethodData() = 0;
+ virtual MethodTable *GetImplMethodTable() = 0;
+ virtual DispatchSlot GetImplSlot(UINT32 slotNumber) = 0;
+ // Returns INVALID_SLOT_NUMBER if no implementation exists.
+ virtual UINT32 GetImplSlotNumber(UINT32 slotNumber) = 0;
+ virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber) = 0;
+ virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber) = 0;
+
+ virtual UINT32 GetNumVirtuals() = 0;
+ virtual UINT32 GetNumMethods() = 0;
+
+ protected:
+ static const UINT32 INVALID_SLOT_NUMBER = UINT32_MAX;
+
+ // This is used when building the data
+ struct MethodDataEntry
+ {
+ private:
+ static const UINT32 INVALID_CHAIN_AND_INDEX = (UINT32)(-1);
+ static const UINT16 INVALID_IMPL_SLOT_NUM = (UINT16)(-1);
+
+ // This contains both the chain delta and the table index. The
+ // reason that they are combined is that we need atomic update
+ // of both, and it is convenient that both are on UINT16 in size.
+ UINT32 m_chainDeltaAndTableIndex;
+ UINT16 m_implSlotNum; // For virtually remapped slots
+ DispatchSlot m_slot; // The entry in the DispatchImplTable
+ MethodDesc *m_pMD; // The MethodDesc for this slot
+
+ public:
+ inline MethodDataEntry() : m_slot(NULL)
+ { WRAPPER_NO_CONTRACT; Init(); }
+
+ inline void Init()
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_chainDeltaAndTableIndex = INVALID_CHAIN_AND_INDEX;
+ m_implSlotNum = INVALID_IMPL_SLOT_NUM;
+ m_slot = NULL;
+ m_pMD = NULL;
+ }
+
+ inline BOOL IsDeclInit()
+ { LIMITED_METHOD_CONTRACT; return m_chainDeltaAndTableIndex != INVALID_CHAIN_AND_INDEX; }
+ inline BOOL IsImplInit()
+ { LIMITED_METHOD_CONTRACT; return m_implSlotNum != INVALID_IMPL_SLOT_NUM; }
+
+ inline void SetDeclData(UINT32 chainDelta, UINT32 tableIndex)
+ { LIMITED_METHOD_CONTRACT; m_chainDeltaAndTableIndex = ((((UINT16) chainDelta) << 16) | ((UINT16) tableIndex)); }
+ inline UINT32 GetChainDelta()
+ { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return m_chainDeltaAndTableIndex >> 16; }
+ inline UINT32 GetTableIndex()
+ { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return (m_chainDeltaAndTableIndex & (UINT32)UINT16_MAX); }
+
+ inline void SetImplData(UINT32 implSlotNum)
+ { LIMITED_METHOD_CONTRACT; m_implSlotNum = (UINT16) implSlotNum; }
+ inline UINT32 GetImplSlotNum()
+ { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsImplInit()); return m_implSlotNum; }
+
+ inline void SetSlot(DispatchSlot slot)
+ { LIMITED_METHOD_CONTRACT; m_slot = slot; }
+ inline DispatchSlot GetSlot()
+ { LIMITED_METHOD_CONTRACT; return m_slot; }
+
+ inline void SetMethodDesc(MethodDesc *pMD)
+ { LIMITED_METHOD_CONTRACT; m_pMD = pMD; }
+ inline MethodDesc *GetMethodDesc()
+ { LIMITED_METHOD_CONTRACT; return m_pMD; }
+
+ };
+
+ static void ProcessMap(
+ const DispatchMapTypeID * rgTypeIDs,
+ UINT32 cTypeIDs,
+ MethodTable * pMT,
+ UINT32 cCurrentChainDepth,
+ MethodDataEntry * rgWorkingData);
+ }; // class MethodData
+
+ typedef ::Holder < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataHolder;
+ typedef ::Wrapper < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataWrapper;
+
+protected:
+ //--------------------------------------------------------------------------------------
+ class MethodDataObject : public MethodData
+ {
+ public:
+ // Static method that returns the amount of memory to allocate for a particular type.
+ static UINT32 GetObjectSize(MethodTable *pMT);
+
+ // Constructor. Make sure you have allocated enough memory using GetObjectSize.
+ inline MethodDataObject(MethodTable *pMT)
+ { WRAPPER_NO_CONTRACT; Init(pMT, NULL); }
+
+ inline MethodDataObject(MethodTable *pMT, MethodData *pParentData)
+ { WRAPPER_NO_CONTRACT; Init(pMT, pParentData); }
+
+ virtual ~MethodDataObject() { LIMITED_METHOD_CONTRACT; }
+
+ virtual MethodData *GetDeclMethodData()
+ { LIMITED_METHOD_CONTRACT; return this; }
+ virtual MethodTable *GetDeclMethodTable()
+ { LIMITED_METHOD_CONTRACT; return m_pMT; }
+ virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
+
+ virtual MethodData *GetImplMethodData()
+ { LIMITED_METHOD_CONTRACT; return this; }
+ virtual MethodTable *GetImplMethodTable()
+ { LIMITED_METHOD_CONTRACT; return m_pMT; }
+ virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
+ virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
+ virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
+ virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
+
+ virtual UINT32 GetNumVirtuals()
+ { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumVirtuals(); }
+ virtual UINT32 GetNumMethods()
+ { LIMITED_METHOD_CONTRACT; return m_pMT->GetCanonicalMethodTable()->GetNumMethods(); }
+
+ protected:
+ void Init(MethodTable *pMT, MethodData *pParentData);
+
+ BOOL PopulateNextLevel();
+
+ // This is the method table for the actual type we're gathering the data for
+ MethodTable *m_pMT;
+
+ // This is used in staged map decoding - it indicates which type we will next decode.
+ UINT32 m_iNextChainDepth;
+ static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
+
+ BOOL m_containsMethodImpl;
+
+ // NOTE: Use of these APIs are unlocked and may appear to be erroneous. However, since calls
+ // to ProcessMap will result in identical values being placed in the MethodDataObjectEntry
+ // array, it it is not a problem if there is a race, since one thread may just end up
+ // doing some duplicate work.
+
+ inline UINT32 GetNextChainDepth()
+ { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
+
+ inline void SetNextChainDepth(UINT32 iDepth)
+ {
+ LIMITED_METHOD_CONTRACT;
+ if (GetNextChainDepth() < iDepth) {
+ VolatileStore(&m_iNextChainDepth, iDepth);
+ }
+ }
+
+ // This is used when building the data
+ struct MethodDataObjectEntry
+ {
+ private:
+ MethodDesc *m_pMDDecl;
+ MethodDesc *m_pMDImpl;
+
+ public:
+ inline MethodDataObjectEntry() : m_pMDDecl(NULL), m_pMDImpl(NULL) {}
+
+ inline void SetDeclMethodDesc(MethodDesc *pMD)
+ { LIMITED_METHOD_CONTRACT; m_pMDDecl = pMD; }
+ inline MethodDesc *GetDeclMethodDesc()
+ { LIMITED_METHOD_CONTRACT; return m_pMDDecl; }
+ inline void SetImplMethodDesc(MethodDesc *pMD)
+ { LIMITED_METHOD_CONTRACT; m_pMDImpl = pMD; }
+ inline MethodDesc *GetImplMethodDesc()
+ { LIMITED_METHOD_CONTRACT; return m_pMDImpl; }
+ };
+
+ //
+ // At the end of this object is an array, so you cannot derive from this class.
+ //
+
+ inline MethodDataObjectEntry *GetEntryData()
+ { LIMITED_METHOD_CONTRACT; return (MethodDataObjectEntry *)(this + 1); }
+
+ inline MethodDataObjectEntry *GetEntry(UINT32 i)
+ { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
+
+ void FillEntryDataForAncestor(MethodTable *pMT);
+
+ // MethodDataObjectEntry m_rgEntries[...];
+ }; // class MethodDataObject
+
+ //--------------------------------------------------------------------------------------
+ class MethodDataInterface : public MethodData
+ {
+ public:
+ // Static method that returns the amount of memory to allocate for a particular type.
+ static UINT32 GetObjectSize(MethodTable *pMT)
+ { LIMITED_METHOD_CONTRACT; return sizeof(MethodDataInterface); }
+
+ // Constructor. Make sure you have allocated enough memory using GetObjectSize.
+ MethodDataInterface(MethodTable *pMT)
+ {
+ LIMITED_METHOD_CONTRACT;
+ CONSISTENCY_CHECK(CheckPointer(pMT));
+ CONSISTENCY_CHECK(pMT->IsInterface());
+ m_pMT = pMT;
+ }
+ virtual ~MethodDataInterface()
+ { LIMITED_METHOD_CONTRACT; }
+
+ //
+ // Decl data
+ //
+ virtual MethodData *GetDeclMethodData()
+ { LIMITED_METHOD_CONTRACT; return this; }
+ virtual MethodTable *GetDeclMethodTable()
+ { LIMITED_METHOD_CONTRACT; return m_pMT; }
+ virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
+
+ //
+ // Impl data
+ //
+ virtual MethodData *GetImplMethodData()
+ { LIMITED_METHOD_CONTRACT; return this; }
+ virtual MethodTable *GetImplMethodTable()
+ { LIMITED_METHOD_CONTRACT; return m_pMT; }
+ virtual DispatchSlot GetImplSlot(UINT32 slotNumber)
+ { WRAPPER_NO_CONTRACT; return DispatchSlot(m_pMT->GetRestoredSlot(slotNumber)); }
+ virtual UINT32 GetImplSlotNumber(UINT32 slotNumber)
+ { LIMITED_METHOD_CONTRACT; return slotNumber; }
+ virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
+ virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
+
+ //
+ // Slot count data
+ //
+ virtual UINT32 GetNumVirtuals()
+ { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumVirtuals(); }
+ virtual UINT32 GetNumMethods()
+ { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumMethods(); }
+
+ protected:
+ // This is the method table for the actual type we're gathering the data for
+ MethodTable *m_pMT;
+ }; // class MethodDataInterface
+
+ //--------------------------------------------------------------------------------------
+ class MethodDataInterfaceImpl : public MethodData
+ {
+ public:
+ // Object construction-related methods
+ static UINT32 GetObjectSize(MethodTable *pMTDecl);
+
+ MethodDataInterfaceImpl(
+ const DispatchMapTypeID * rgDeclTypeIDs,
+ UINT32 cDeclTypeIDs,
+ MethodData * pDecl,
+ MethodData * pImpl);
+ virtual ~MethodDataInterfaceImpl();
+
+ // Decl-related methods
+ virtual MethodData *GetDeclMethodData()
+ { LIMITED_METHOD_CONTRACT; return m_pDecl; }
+ virtual MethodTable *GetDeclMethodTable()
+ { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodTable(); }
+ virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber)
+ { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodDesc(slotNumber); }
+
+ // Impl-related methods
+ virtual MethodData *GetImplMethodData()
+ { LIMITED_METHOD_CONTRACT; return m_pImpl; }
+ virtual MethodTable *GetImplMethodTable()
+ { WRAPPER_NO_CONTRACT; return m_pImpl->GetImplMethodTable(); }
+ virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
+ virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
+ virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
+ virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
+
+ virtual UINT32 GetNumVirtuals()
+ { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
+ virtual UINT32 GetNumMethods()
+ { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
+
+ protected:
+ UINT32 MapToImplSlotNumber(UINT32 slotNumber);
+
+ BOOL PopulateNextLevel();
+ void Init(
+ const DispatchMapTypeID * rgDeclTypeIDs,
+ UINT32 cDeclTypeIDs,
+ MethodData * pDecl,
+ MethodData * pImpl);
+
+ MethodData *m_pDecl;
+ MethodData *m_pImpl;
+
+ // This is used in staged map decoding - it indicates which type(s) we will find.
+ const DispatchMapTypeID * m_rgDeclTypeIDs;
+ UINT32 m_cDeclTypeIDs;
+ UINT32 m_iNextChainDepth;
+ static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
+
+ inline UINT32 GetNextChainDepth()
+ { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
+
+ inline void SetNextChainDepth(UINT32 iDepth)
+ {
+ LIMITED_METHOD_CONTRACT;
+ if (GetNextChainDepth() < iDepth) {
+ VolatileStore(&m_iNextChainDepth, iDepth);
+ }
+ }
+
+ //
+ // At the end of this object is an array, so you cannot derive from this class.
+ //
+
+ inline MethodDataEntry *GetEntryData()
+ { LIMITED_METHOD_CONTRACT; return (MethodDataEntry *)(this + 1); }
+
+ inline MethodDataEntry *GetEntry(UINT32 i)
+ { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
+
+ // MethodDataEntry m_rgEntries[...];
+ }; // class MethodDataInterfaceImpl
+
+ //--------------------------------------------------------------------------------------
+ static MethodDataCache *s_pMethodDataCache;
+ static BOOL s_fUseParentMethodData;
+ static BOOL s_fUseMethodDataCache;
+
+public:
+ static void AllowMethodDataCaching()
+ { WRAPPER_NO_CONTRACT; CheckInitMethodDataCache(); s_fUseMethodDataCache = TRUE; }
+ static void ClearMethodDataCache();
+ static void AllowParentMethodDataCopy()
+ { LIMITED_METHOD_CONTRACT; s_fUseParentMethodData = TRUE; }
+ // NOTE: The fCanCache argument determines if the resulting MethodData object can
+ // be added to the global MethodDataCache. This is used when requesting a
+ // MethodData object for a type currently being built.
+ static MethodData *GetMethodData(MethodTable *pMT, BOOL fCanCache = TRUE);
+ static MethodData *GetMethodData(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache = TRUE);
+ // This method is used by BuildMethodTable because the exact interface has not yet been loaded.
+ // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
+ static MethodData * GetMethodData(
+ const DispatchMapTypeID * rgDeclTypeIDs,
+ UINT32 cDeclTypeIDs,
+ MethodTable * pMTDecl,
+ MethodTable * pMTImpl);
+
+protected:
+ static void CheckInitMethodDataCache();
+ static MethodData *FindParentMethodDataHelper(MethodTable *pMT);
+ static MethodData *FindMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl);
+ static MethodData *GetMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache);
+ // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
+ static MethodData * GetMethodDataHelper(
+ const DispatchMapTypeID * rgDeclTypeIDs,
+ UINT32 cDeclTypeIDs,
+ MethodTable * pMTDecl,
+ MethodTable * pMTImpl);
+
+public:
+ //--------------------------------------------------------------------------------------
+ class MethodIterator
+ {
+ public:
+ MethodIterator(MethodTable *pMT);
+ MethodIterator(MethodTable *pMTDecl, MethodTable *pMTImpl);
+ MethodIterator(MethodData *pMethodData);
+ MethodIterator(const MethodIterator &it);
+ inline ~MethodIterator() { WRAPPER_NO_CONTRACT; m_pMethodData->Release(); }
+ INT32 GetNumMethods() const;
+ inline BOOL IsValid() const;
+ inline BOOL MoveTo(UINT32 idx);
+ inline BOOL Prev();
+ inline BOOL Next();
+ inline void MoveToBegin();
+ inline void MoveToEnd();
+ inline UINT32 GetSlotNumber() const;
+ inline UINT32 GetImplSlotNumber() const;
+ inline BOOL IsVirtual() const;
+ inline UINT32 GetNumVirtuals() const;
+ inline DispatchSlot GetTarget() const;
+
+ // Can be called only if IsValid()=TRUE
+ inline MethodDesc *GetMethodDesc() const;
+ inline MethodDesc *GetDeclMethodDesc() const;
+
+ protected:
+ void Init(MethodTable *pMTDecl, MethodTable *pMTImpl);
+
+ MethodData *m_pMethodData;
+ INT32 m_iCur; // Current logical slot index
+ INT32 m_iMethods;
+ }; // class MethodIterator
+#endif // !DACCESS_COMPILE
+
+ //--------------------------------------------------------------------------------------
+ // This iterator lets you walk over all the method bodies introduced by this type.
+ // This includes new static methods, new non-virtual methods, and any overrides
+ // of the parent's virtual methods. It does not include virtual method implementations
+ // provided by the parent
+
+ class IntroducedMethodIterator
+ {
+ public:
+ IntroducedMethodIterator(MethodTable *pMT, BOOL restrictToCanonicalTypes = TRUE);
+ inline BOOL IsValid() const;
+ BOOL Next();
+
+ // Can be called only if IsValid()=TRUE
+ inline MethodDesc *GetMethodDesc() const;
+
+ // Static worker methods of the iterator. These are meant to be used
+ // by RuntimeTypeHandle::GetFirstIntroducedMethod and RuntimeTypeHandle::GetNextIntroducedMethod
+ // only to expose this iterator to managed code.
+ static MethodDesc * GetFirst(MethodTable * pMT);
+ static MethodDesc * GetNext(MethodDesc * pMD);
+
+ protected:
+ MethodDesc *m_pMethodDesc; // Current method desc
+
+ // Cached info about current method desc
+ MethodDescChunk *m_pChunk;
+ TADDR m_pChunkEnd;
+
+ void SetChunk(MethodDescChunk * pChunk);
+ }; // class IntroducedMethodIterator
+
+ //-------------------------------------------------------------------
+ // INSTANCE MEMBER VARIABLES
+ //
+
+#ifdef DACCESS_COMPILE
+public:
+#else
+private:
+#endif
+ enum WFLAGS_LOW_ENUM
+ {
+ // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
+ // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
+ // CARRY THE CORECT FLAGS.
+ //
+
+ // 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.
+
+ enum_flag_UNUSED_ComponentSize_1 = 0x00000001,
+
+ enum_flag_StaticsMask = 0x00000006,
+ enum_flag_StaticsMask_NonDynamic = 0x00000000,
+ enum_flag_StaticsMask_Dynamic = 0x00000002, // dynamic statics (EnC, reflection.emit)
+ enum_flag_StaticsMask_Generics = 0x00000004, // generics statics
+ enum_flag_StaticsMask_CrossModuleGenerics = 0x00000006, // cross module generics statics (NGen)
+ enum_flag_StaticsMask_IfGenericsThenCrossModule = 0x00000002, // helper constant to get rid of unnecessary check
+
+ enum_flag_NotInPZM = 0x00000008, // True if this type is not in its PreferredZapModule
+
+ enum_flag_GenericsMask = 0x00000030,
+ enum_flag_GenericsMask_NonGeneric = 0x00000000, // no instantiation
+ enum_flag_GenericsMask_GenericInst = 0x00000010, // regular instantiation, e.g. List<String>
+ enum_flag_GenericsMask_SharedInst = 0x00000020, // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
+ enum_flag_GenericsMask_TypicalInst = 0x00000030, // the type instantiated at its formal parameters, e.g. List<T>
+
+#ifdef FEATURE_REMOTING
+ enum_flag_ContextStatic = 0x00000040,
+#endif
+ enum_flag_HasRemotingVtsInfo = 0x00000080, // Optional data present indicating VTS methods and optional fields
+
+ enum_flag_HasVariance = 0x00000100, // This is an instantiated type some of whose type parameters are co or contra-variant
+
+ enum_flag_HasDefaultCtor = 0x00000200,
+ enum_flag_HasPreciseInitCctors = 0x00000400, // Do we need to run class constructors at allocation time? (Not perf important, could be moved to EEClass
+
+#if defined(FEATURE_HFA)
+#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
+#error Can't define both FEATURE_HFA and FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF
+#endif
+ enum_flag_IsHFA = 0x00000800, // This type is an HFA (Homogenous Floating-point Aggregate)
+#endif // FEATURE_HFA
+
+#if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
+#if defined(FEATURE_HFA)
+#error Can't define both FEATURE_HFA and FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF
+#endif
+ enum_flag_IsRegStructPassed = 0x00000800, // This type is a System V register passed struct.
+#endif // FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF
+
+ enum_flag_IsByRefLike = 0x00001000,
+
+ // 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.
+ enum_flag_UNUSED_ComponentSize_5 = 0x00002000,
+ enum_flag_UNUSED_ComponentSize_6 = 0x00004000,
+ enum_flag_UNUSED_ComponentSize_7 = 0x00008000,
+
+#define SET_FALSE(flag) (flag & 0)
+#define SET_TRUE(flag) (flag & 0xffff)
+
+ // 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
+ enum_flag_StringArrayValues = SET_TRUE(enum_flag_StaticsMask_NonDynamic) |
+ SET_FALSE(enum_flag_NotInPZM) |
+ SET_TRUE(enum_flag_GenericsMask_NonGeneric) |
+#ifdef FEATURE_REMOTING
+ SET_FALSE(enum_flag_ContextStatic) |
+#endif
+ SET_FALSE(enum_flag_HasVariance) |
+ SET_FALSE(enum_flag_HasDefaultCtor) |
+ SET_FALSE(enum_flag_HasPreciseInitCctors),
+
+ }; // enum WFLAGS_LOW_ENUM
+
+ enum WFLAGS_HIGH_ENUM
+ {
+ // DO NOT use flags that have bits set in the low 2 bytes.
+ // These flags are DWORD sized so that our atomic masking
+ // operations can operate on the entire 4-byte aligned DWORD
+ // instead of the logical non-aligned WORD of flags. The
+ // low WORD of flags is reserved for the component size.
+
+ // The following bits describe mutually exclusive locations of the type
+ // in the type hiearchy.
+ enum_flag_Category_Mask = 0x000F0000,
+
+ enum_flag_Category_Class = 0x00000000,
+ enum_flag_Category_Unused_1 = 0x00010000,
+
+ enum_flag_Category_MarshalByRef_Mask= 0x000E0000,
+ enum_flag_Category_MarshalByRef = 0x00020000,
+ enum_flag_Category_Contextful = 0x00030000, // sub-category of MarshalByRef
+
+ enum_flag_Category_ValueType = 0x00040000,
+ enum_flag_Category_ValueType_Mask = 0x000C0000,
+ enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType
+ enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or primitive value type
+ enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.)
+
+ enum_flag_Category_Array = 0x00080000,
+ enum_flag_Category_Array_Mask = 0x000C0000,
+ // enum_flag_Category_IfArrayThenUnused = 0x00010000, // sub-category of Array
+ enum_flag_Category_IfArrayThenSzArray = 0x00020000, // sub-category of Array
+
+ enum_flag_Category_Interface = 0x000C0000,
+ enum_flag_Category_Unused_2 = 0x000D0000,
+ enum_flag_Category_TransparentProxy = 0x000E0000,
+ enum_flag_Category_AsyncPin = 0x000F0000,
+
+ enum_flag_Category_ElementTypeMask = 0x000E0000, // bits that matter for element type mask
+
+
+ enum_flag_HasFinalizer = 0x00100000, // instances require finalization
+
+ enum_flag_IfNotInterfaceThenMarshalable = 0x00200000, // Is this type marshalable by the pinvoke marshalling layer
+#ifdef FEATURE_COMINTEROP
+ enum_flag_IfInterfaceThenHasGuidInfo = 0x00200000, // Does the type has optional GuidInfo
+#endif // FEATURE_COMINTEROP
+
+ enum_flag_ICastable = 0x00400000, // class implements ICastable interface
+
+ enum_flag_HasIndirectParent = 0x00800000, // m_pParentMethodTable has double indirection
+
+ enum_flag_ContainsPointers = 0x01000000,
+
+ enum_flag_HasTypeEquivalence = 0x02000000, // can be equivalent to another type
+
+#ifdef FEATURE_COMINTEROP
+ enum_flag_HasRCWPerTypeData = 0x04000000, // has optional pointer to RCWPerTypeData
+#endif // FEATURE_COMINTEROP
+
+ enum_flag_HasCriticalFinalizer = 0x08000000, // finalizer must be run on Appdomain Unload
+ enum_flag_Collectible = 0x10000000,
+ enum_flag_ContainsGenericVariables = 0x20000000, // we cache this flag to help detect these efficiently and
+ // to detect this condition when restoring
+
+ enum_flag_ComObject = 0x40000000, // class is a com object
+
+ enum_flag_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
+ enum_flag_NonTrivialInterfaceCast = enum_flag_Category_Array
+ | enum_flag_ComObject
+ | enum_flag_ICastable
+
+ }; // enum WFLAGS_HIGH_ENUM
+
+// NIDump needs to be able to see these flags
+// TODO: figure out how to make these private
+#if defined(DACCESS_COMPILE)
+public:
+#else
+private:
+#endif
+ enum WFLAGS2_ENUM
+ {
+ // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
+ // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
+ // CARRY THE CORECT FLAGS.
+
+ // The following bits describe usage of optional slots. They have to stay
+ // together because of we index using them into offset arrays.
+ enum_flag_MultipurposeSlotsMask = 0x001F,
+ enum_flag_HasPerInstInfo = 0x0001,
+ enum_flag_HasInterfaceMap = 0x0002,
+ enum_flag_HasDispatchMapSlot = 0x0004,
+ enum_flag_HasNonVirtualSlots = 0x0008,
+ enum_flag_HasModuleOverride = 0x0010,
+
+ enum_flag_IsZapped = 0x0020, // This could be fetched from m_pLoaderModule if we run out of flags
+
+ enum_flag_IsPreRestored = 0x0040, // Class does not need restore
+ // This flag is set only for NGENed classes (IsZapped is true)
+
+ enum_flag_HasModuleDependencies = 0x0080,
+
+ enum_flag_NoSecurityProperties = 0x0100, // Class does not have security properties (that is,
+ // GetClass()->GetSecurityProperties will return 0).
+
+ enum_flag_RequiresDispatchTokenFat = 0x0200,
+
+ enum_flag_HasCctor = 0x0400,
+ enum_flag_HasCCWTemplate = 0x0800, // Has an extra field pointing to a CCW template
+
+#ifdef FEATURE_64BIT_ALIGNMENT
+ enum_flag_RequiresAlign8 = 0x1000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)
+#endif
+
+ enum_flag_HasBoxedRegularStatics = 0x2000, // GetNumBoxedRegularStatics() != 0
+
+ enum_flag_HasSingleNonVirtualSlot = 0x4000,
+
+ enum_flag_DependsOnEquivalentOrForwardedStructs= 0x8000, // Declares methods that have type equivalent or type forwarded structures in their signature
+
+ }; // enum WFLAGS2_ENUM
+
+ __forceinline void ClearFlag(WFLAGS_LOW_ENUM flag)
+ {
+ _ASSERTE(!IsStringOrArray());
+ m_dwFlags &= ~flag;
+ }
+ __forceinline void SetFlag(WFLAGS_LOW_ENUM flag)
+ {
+ _ASSERTE(!IsStringOrArray());
+ m_dwFlags |= flag;
+ }
+ __forceinline DWORD GetFlag(WFLAGS_LOW_ENUM flag) const
+ {
+ SUPPORTS_DAC;
+ return (IsStringOrArray() ? (enum_flag_StringArrayValues & flag) : (m_dwFlags & flag));
+ }
+ __forceinline BOOL TestFlagWithMask(WFLAGS_LOW_ENUM mask, WFLAGS_LOW_ENUM flag) const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return (IsStringOrArray() ? (((DWORD)enum_flag_StringArrayValues & (DWORD)mask) == (DWORD)flag) :
+ ((m_dwFlags & (DWORD)mask) == (DWORD)flag));
+ }
+
+ __forceinline void ClearFlag(WFLAGS_HIGH_ENUM flag)
+ {
+ m_dwFlags &= ~flag;
+ }
+ __forceinline void SetFlag(WFLAGS_HIGH_ENUM flag)
+ {
+ m_dwFlags |= flag;
+ }
+ __forceinline DWORD GetFlag(WFLAGS_HIGH_ENUM flag) const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return m_dwFlags & flag;
+ }
+ __forceinline BOOL TestFlagWithMask(WFLAGS_HIGH_ENUM mask, WFLAGS_HIGH_ENUM flag) const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return ((m_dwFlags & (DWORD)mask) == (DWORD)flag);
+ }
+
+ __forceinline void ClearFlag(WFLAGS2_ENUM flag)
+ {
+ m_wFlags2 &= ~flag;
+ }
+ __forceinline void SetFlag(WFLAGS2_ENUM flag)
+ {
+ m_wFlags2 |= flag;
+ }
+ __forceinline DWORD GetFlag(WFLAGS2_ENUM flag) const
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return m_wFlags2 & flag;
+ }
+ __forceinline BOOL TestFlagWithMask(WFLAGS2_ENUM mask, WFLAGS2_ENUM flag) const
+ {
+ return (m_wFlags2 & (DWORD)mask) == (DWORD)flag;
+ }
+
+ // Just exposing a couple of these for x86 asm versions of JIT_IsInstanceOfClass and JIT_IsInstanceOfInterface
+public:
+ enum
+ {
+ public_enum_flag_HasTypeEquivalence = enum_flag_HasTypeEquivalence,
+ public_enum_flag_NonTrivialInterfaceCast = enum_flag_NonTrivialInterfaceCast,
+ };
+
+private:
+ /*
+ * This stuff must be first in the struct and should fit on a cache line - don't move it. Used by the GC.
+ */
+ // struct
+ // {
+
+ // Low WORD is component size for array and string types (HasComponentSize() returns true).
+ // Used for flags otherwise.
+ DWORD m_dwFlags;
+
+ // Base size of instance of this class when allocated on the heap
+ DWORD m_BaseSize;
+ // }
+
+ WORD m_wFlags2;
+
+ // Class token if it fits into 16-bits. If this is (WORD)-1, the class token is stored in the TokenOverflow optional member.
+ WORD m_wToken;
+
+ // <NICE> In the normal cases we shouldn't need a full word for each of these </NICE>
+ WORD m_wNumVirtuals;
+ WORD m_wNumInterfaces;
+
+#ifdef _DEBUG
+ LPCUTF8 debug_m_szClassName;
+#endif //_DEBUG
+
+ // Parent PTR_MethodTable if enum_flag_HasIndirectParent is not set. Pointer to indirection cell
+ // if enum_flag_enum_flag_HasIndirectParent is set. The indirection is offset by offsetof(MethodTable, m_pParentMethodTable).
+ // It allows casting helpers to go through parent chain natually. Casting helper do not need need the explicit check
+ // for enum_flag_HasIndirectParentMethodTable.
+ TADDR m_pParentMethodTable;
+
+ PTR_Module m_pLoaderModule; // LoaderModule. It is equal to the ZapModule in ngened images
+
+ PTR_MethodTableWriteableData m_pWriteableData;
+
+ // The value of lowest two bits describe what the union contains
+ enum LowBits {
+ UNION_EECLASS = 0, // 0 - pointer to EEClass. This MethodTable is the canonical method table.
+ UNION_INVALID = 1, // 1 - not used
+ UNION_METHODTABLE = 2, // 2 - pointer to canonical MethodTable.
+ UNION_INDIRECTION = 3 // 3 - pointer to indirection cell that points to canonical MethodTable.
+ }; // (used only if FEATURE_PREJIT is defined)
+ static const TADDR UNION_MASK = 3;
+
+ union {
+ EEClass * m_pEEClass;
+ TADDR m_pCanonMT;
+ };
+
+ __forceinline static LowBits union_getLowBits(TADDR pCanonMT)
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return LowBits(pCanonMT & UNION_MASK);
+ }
+ __forceinline static TADDR union_getPointer(TADDR pCanonMT)
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return (pCanonMT & ~UNION_MASK);
+ }
+
+ // m_pPerInstInfo and m_pInterfaceMap have to be at fixed offsets because of performance sensitive
+ // JITed code and JIT helpers. However, they are frequently not present. The space is used by other
+ // multipurpose slots on first come first served basis if the fixed ones are not present. The other
+ // multipurpose are DispatchMapSlot, NonVirtualSlots, ModuleOverride (see enum_flag_MultipurposeSlotsMask).
+ // The multipurpose slots that do not fit are stored after vtable slots.
+
+ union
+ {
+ PTR_Dictionary * m_pPerInstInfo;
+ TADDR m_ElementTypeHnd;
+ TADDR m_pMultipurposeSlot1;
+ };
+ public:
+ union
+ {
+ InterfaceInfo_t * m_pInterfaceMap;
+ TADDR m_pMultipurposeSlot2;
+ };
+
+ // VTable and Non-Virtual slots go here
+
+ // Overflow multipurpose slots go here
+
+ // Optional Members go here
+ // See above for the list of optional members
+
+ // Generic dictionary pointers go here
+
+ // Interface map goes here
+
+ // Generic instantiation+dictionary goes here
+
+private:
+
+ // disallow direct creation
+ void *operator new(size_t dummy);
+ void operator delete(void *pData);
+ MethodTable();
+
+ // Optional members. These are used for fields in the data structure where
+ // the fields are (a) known when MT is created and (b) there is a default
+ // value for the field in the common case. That is, they are normally used
+ // for data that is only relevant to a small number of method tables.
+
+ // Optional members and multipurpose slots have similar purpose, but they differ in details:
+ // - Multipurpose slots can only accomodate pointer sized structures right now. It is non-trivial
+ // to add new ones, the access is faster.
+ // - Optional members can accomodate structures of any size. It is trivial to add new ones,
+ // the access is slower.
+
+ // The following macro will automatically create GetXXX accessors for the optional members.
+#define METHODTABLE_OPTIONAL_MEMBERS() \
+ /* NAME TYPE GETTER */ \
+ /* Accessing this member efficiently is currently performance critical for static field accesses */ \
+ /* in generic classes, so place it early in the list. */ \
+ METHODTABLE_OPTIONAL_MEMBER(GenericsStaticsInfo, GenericsStaticsInfo, GetGenericsStaticsInfo ) \
+ /* Accessed by interop, fairly frequently. */ \
+ METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS() \
+ /* Accessed during x-domain transition only, so place it late in the list. */ \
+ METHODTABLE_REMOTING_OPTIONAL_MEMBERS() \
+ /* Accessed during certain generic type load operations only, so low priority */ \
+ METHODTABLE_OPTIONAL_MEMBER(ExtraInterfaceInfo, TADDR, GetExtraInterfaceInfoPtr ) \
+ /* TypeDef token for assemblies with more than 64k types. Never happens in real world. */ \
+ METHODTABLE_OPTIONAL_MEMBER(TokenOverflow, TADDR, GetTokenOverflowPtr ) \
+
+#ifdef FEATURE_COMINTEROP
+#define METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS() \
+ METHODTABLE_OPTIONAL_MEMBER(GuidInfo, PTR_GuidInfo, GetGuidInfoPtr ) \
+ METHODTABLE_OPTIONAL_MEMBER(RCWPerTypeData, RCWPerTypeData *, GetRCWPerTypeDataPtr ) \
+ METHODTABLE_OPTIONAL_MEMBER(CCWTemplate, ComCallWrapperTemplate *, GetCCWTemplatePtr )
+#else
+#define METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS()
+#endif
+
+#ifdef FEATURE_REMOTING
+#define METHODTABLE_REMOTING_OPTIONAL_MEMBERS() \
+ METHODTABLE_OPTIONAL_MEMBER(RemotingVtsInfo, PTR_RemotingVtsInfo, GetRemotingVtsInfoPtr ) \
+ METHODTABLE_OPTIONAL_MEMBER(RemotableMethodInfo, PTR_CrossDomainOptimizationInfo,GetRemotableMethodInfoPtr ) \
+ METHODTABLE_OPTIONAL_MEMBER(ContextStatics, PTR_ContextStaticsBucket, GetContextStaticsBucketPtr )
+#else
+#define METHODTABLE_REMOTING_OPTIONAL_MEMBERS()
+#endif
+
+ enum OptionalMemberId
+ {
+#undef METHODTABLE_OPTIONAL_MEMBER
+#define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) OptionalMember_##NAME,
+ METHODTABLE_OPTIONAL_MEMBERS()
+ OptionalMember_Count,
+
+ OptionalMember_First = OptionalMember_GenericsStaticsInfo,
+ };
+
+ FORCEINLINE DWORD GetOffsetOfOptionalMember(OptionalMemberId id);
+
+public:
+
+ //
+ // Public accessor helpers for the optional members of MethodTable
+ //
+
+#undef METHODTABLE_OPTIONAL_MEMBER
+#define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \
+ inline DPTR(TYPE) GETTER() \
+ { \
+ LIMITED_METHOD_CONTRACT; \
+ STATIC_CONTRACT_SO_TOLERANT; \
+ _ASSERTE(Has##NAME()); \
+ return dac_cast<DPTR(TYPE)>(dac_cast<TADDR>(this) + GetOffsetOfOptionalMember(OptionalMember_##NAME)); \
+ }
+
+ METHODTABLE_OPTIONAL_MEMBERS()
+
+private:
+ inline DWORD GetStartOffsetOfOptionalMembers()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetOffsetOfOptionalMember(OptionalMember_First);
+ }
+
+ inline DWORD GetEndOffsetOfOptionalMembers()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetOffsetOfOptionalMember(OptionalMember_Count);
+ }
+
+ inline static DWORD GetOptionalMembersAllocationSize(
+ DWORD dwMultipurposeSlotsMask,
+ BOOL needsRemotableMethodInfo,
+ BOOL needsGenericsStaticsInfo,
+ BOOL needsGuidInfo,
+ BOOL needsCCWTemplate,
+ BOOL needsRCWPerTypeData,
+ BOOL needsRemotingVtsInfo,
+ BOOL needsContextStatic,
+ BOOL needsTokenOverflow);
+ inline DWORD GetOptionalMembersSize();
+
+ // The PerInstInfo is a (possibly empty) array of pointers to
+ // Instantiations/Dictionaries. This array comes after the optional members.
+ inline DWORD GetPerInstInfoSize();
+
+ // This is the size of the interface map chunk in the method table.
+ // If the MethodTable has a dynamic interface map then the size includes the pointer
+ // that stores the extra info for that map.
+ // The interface map itself comes after the PerInstInfo (if any)
+ inline DWORD GetInterfaceMapSize();
+
+ // The instantiation/dictionary comes at the end of the MethodTable after
+ // the interface map.
+ inline DWORD GetInstAndDictSize();
+
+private:
+ // Helper template to compute the offsets at compile time
+ template<int mask>
+ struct MultipurposeSlotOffset;
+
+ static const BYTE c_DispatchMapSlotOffsets[];
+ static const BYTE c_NonVirtualSlotsOffsets[];
+ static const BYTE c_ModuleOverrideOffsets[];
+
+ static const BYTE c_OptionalMembersStartOffsets[]; // total sizes of optional slots
+
+ TADDR GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const BYTE * offsets);
+
+ void SetMultipurposeSlotsMask(DWORD dwMask)
+ {
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE((m_wFlags2 & enum_flag_MultipurposeSlotsMask) == 0);
+ m_wFlags2 |= (WORD)dwMask;
+ }
+
+ BOOL HasModuleOverride()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return GetFlag(enum_flag_HasModuleOverride);
+ }
+
+ DPTR(RelativeFixupPointer<PTR_Module>) GetModuleOverridePtr()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return dac_cast<DPTR(RelativeFixupPointer<PTR_Module>)>(GetMultipurposeSlotPtr(enum_flag_HasModuleOverride, c_ModuleOverrideOffsets));
+ }
+
+ void SetModule(Module * pModule);
+
+ /************************************
+ //
+ // CONTEXT STATIC
+ //
+ ************************************/
+
+public:
+#ifdef FEATURE_REMOTING
+ inline BOOL HasContextStatics();
+ inline void SetHasContextStatics();
+
+ inline PTR_ContextStaticsBucket GetContextStaticsBucket()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(HasContextStatics());
+ PTR_ContextStaticsBucket pBucket = *GetContextStaticsBucketPtr();
+ _ASSERTE(pBucket != NULL);
+ return pBucket;
+ }
+
+ inline DWORD GetContextStaticsOffset();
+ inline WORD GetContextStaticsSize();
+
+ void SetupContextStatics(AllocMemTracker *pamTracker, WORD dwContextStaticsSize);
+ DWORD AllocateContextStaticsOffset();
+#endif
+
+ BOOL Validate ();
+
+#ifdef FEATURE_READYTORUN_COMPILER
+ //
+ // Is field layout in this type fixed within the current version bubble?
+ // This check does not take the inheritance chain into account.
+ //
+ BOOL IsLayoutFixedInCurrentVersionBubble();
+
+ //
+ // Is field layout of the inheritance chain fixed within the current version bubble?
+ //
+ BOOL IsInheritanceChainLayoutFixedInCurrentVersionBubble();
+#endif
+
+}; // class MethodTable
+
+#if defined(FEATURE_COMINTEROP) && !defined(DACCESS_COMPILE)
+WORD GetEquivalentMethodSlot(MethodTable * pOldMT, MethodTable * pNewMT, WORD wMTslot, BOOL *pfFound);
+#endif // defined(FEATURE_COMINTEROP) && !defined(DACCESS_COMPILE)
+
+MethodTable* CreateMinimalMethodTable(Module* pContainingModule,
+ LoaderHeap* pCreationHeap,
+ AllocMemTracker* pamTracker);
+
+#endif // !_METHODTABLE_H_