1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
7 #ifndef _METHODTABLE_H_
8 #define _METHODTABLE_H_
18 #ifdef FEATURE_COMINTEROP
19 #include "stdinterfaces.h"
23 #include "typehandle.h"
25 #include "contractimpl.h"
27 #include "gcinfotypes.h"
28 #include "enum_class_flags.h"
31 * Forward Declarations
35 class ArrayMethodDesc;
37 class FCallMethodDesc;
42 struct LayoutRawFieldInfo;
45 class MethodDescChunk;
53 class AllocMemTracker;
55 class MethodDataCache;
56 class EEClassLayoutInfo;
57 class EEClassNativeLayoutInfo;
58 #ifdef FEATURE_COMINTEROP
59 class ComCallWrapperTemplate;
61 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
62 class ClassFactoryBase;
63 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
65 enum class WellKnownAttribute : DWORD;
67 enum class ResolveVirtualStaticMethodFlags
71 VerifyImplemented = 2,
72 AllowVariantMatches = 4,
73 InstantiateResultOverFinalMethodDesc = 8,
75 support_use_as_flags // Enable the template functions in enum_class_flags.h
79 enum class FindDefaultInterfaceImplementationFlags
84 InstantiateFoundMethodDesc = 4,
86 support_use_as_flags // Enable the template functions in enum_class_flags.h
89 //============================================================================
90 // This is the in-memory structure of a class and it will evolve.
91 //============================================================================
95 // Also this class currently has everything public - this may changes
96 // Might also need to hold onto the meta data loader fot this class</TODO>
99 // A MethodTable contains an array of these structures, which describes each interface implemented
100 // by this class (directly declared or indirectly declared).
102 // Generic type instantiations (in C# syntax: C<ty_1,...,ty_n>) are represented by
103 // MethodTables, i.e. a new MethodTable gets allocated for each such instantiation.
104 // The entries in these tables (i.e. the code) are, however, often shared.
106 // In particular, a MethodTable's vtable contents (and hence method descriptors) may be
107 // shared between compatible instantiations (e.g. List<string> and List<object> have
108 // the same vtable *contents*). Likewise the EEClass will be shared between
109 // compatible instantiations whenever the vtable contents are.
111 // !!! Thus that it is _not_ generally the case that GetClass.GetMethodTable() == t. !!!
113 // Instantiated interfaces have their own method tables unique to the instantiation e.g. I<string> is
114 // distinct from I<int> and I<object>
116 // For generic types the interface map lists generic interfaces
117 // For instantiated types the interface map lists instantiated interfaces
118 // e.g. for C<T> : I<T>, J<string>
119 // the interface map for C would list I and J
120 // the interface map for C<int> would list I<int> and J<string>
122 struct InterfaceInfo_t
125 // Method table of the interface
126 PTR_MethodTable m_pMethodTable;
129 FORCEINLINE PTR_MethodTable GetMethodTable()
131 LIMITED_METHOD_CONTRACT;
132 return VolatileLoadWithoutBarrier(&m_pMethodTable);
135 #ifndef DACCESS_COMPILE
136 void SetMethodTable(MethodTable * pMT)
138 LIMITED_METHOD_CONTRACT;
139 return VolatileStoreWithoutBarrier(&m_pMethodTable, pMT);
142 // Get approximate method table. This is used by the type loader before the type is fully loaded.
143 PTR_MethodTable GetApproxMethodTable(Module * pContainingModule);
144 #endif // !DACCESS_COMPILE
146 #ifndef DACCESS_COMPILE
147 InterfaceInfo_t(InterfaceInfo_t &right)
149 VolatileStoreWithoutBarrier(&m_pMethodTable, VolatileLoadWithoutBarrier(&right.m_pMethodTable));
151 #else // !DACCESS_COMPILE
153 InterfaceInfo_t(InterfaceInfo_t &right);
154 #endif // !DACCESS_COMPILE
155 }; // struct InterfaceInfo_t
157 typedef DPTR(InterfaceInfo_t) PTR_InterfaceInfo;
159 namespace ClassCompat
161 struct InterfaceInfo_t;
164 // Data needed when simulating old VTable layout for COM Interop
165 // This is necessary as the data is saved in MethodDescs and we need
166 // to simulate different values without copying or changing the existing
169 // This will be created in a parallel array to ppMethodDescList and
170 // ppUnboxMethodDescList in the bmtMethAndFieldDescs structure below
171 struct InteropMethodTableSlotData
175 e_DUPLICATE = 0x0001 // The entry is duplicate
178 MethodDesc *pMD; // The MethodDesc for this slot
179 WORD wSlot; // The simulated slot value for the MethodDesc
180 WORD wFlags; // The simulated duplicate value
181 MethodDesc *pDeclMD; // To keep track of MethodImpl's
185 wFlags |= e_DUPLICATE;
189 return ((BOOL)(wFlags & e_DUPLICATE));
196 void SetSlot(WORD wSlot) {
199 }; // struct InteropMethodTableSlotData
201 #ifdef FEATURE_COMINTEROP
202 struct InteropMethodTableData
204 WORD cVTable; // Count of vtable slots
205 InteropMethodTableSlotData *pVTable; // Data for each slot
207 WORD cNonVTable; // Count of non-vtable slots
208 InteropMethodTableSlotData *pNonVTable; // Data for each slot
210 WORD cInterfaceMap; // Count of interfaces
211 ClassCompat::InterfaceInfo_t *
212 pInterfaceMap; // The interface map
215 static WORD GetRealMethodDesc(MethodTable *pMT, MethodDesc *pMD);
216 static WORD GetSlotForMethodDesc(MethodTable *pMT, MethodDesc *pMD);
217 ClassCompat::InterfaceInfo_t* FindInterface(MethodTable *pInterface);
218 WORD GetStartSlotForInterface(MethodTable* pInterface);
221 class InteropMethodTableSlotDataMap
224 InteropMethodTableSlotData *m_pSlotData;
229 InteropMethodTableSlotDataMap(InteropMethodTableSlotData *pSlotData, DWORD cSlotData);
230 InteropMethodTableSlotData *GetData(MethodDesc *pMD);
231 BOOL Exists(MethodDesc *pMD);
234 InteropMethodTableSlotData *Exists_Helper(MethodDesc *pMD);
235 InteropMethodTableSlotData *GetNewEntry();
236 }; // class InteropMethodTableSlotDataMap
237 #endif // FEATURE_COMINTEROP
240 // This struct contains cached information on the GUID associated with a type.
245 GUID m_Guid; // The actual guid of the type.
246 BOOL m_bGeneratedFromName; // A boolean indicating if it was generated from the
250 typedef DPTR(GuidInfo) PTR_GuidInfo;
253 // GenericsDictInfo is stored at negative offset of the dictionary
254 struct GenericsDictInfo
257 DWORD m_dwPadding; // Just to keep the size a multiple of 8
260 // Total number of instantiation dictionaries including inherited ones
261 // i.e. how many instantiated classes (including this one) are there in the hierarchy?
262 // See comments about PerInstInfo
265 // Number of type parameters (NOT including those of superclasses).
267 }; // struct GenericsDictInfo
268 typedef DPTR(GenericsDictInfo) PTR_GenericsDictInfo;
270 struct GenericsStaticsInfo
272 // Pointer to field descs for statics
273 PTR_FieldDesc m_pFieldDescs;
275 // Method table ID for statics
276 SIZE_T m_DynamicTypeID;
278 }; // struct GenericsStaticsInfo
279 typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo;
282 // This struct consolidates the writeable parts of the MethodTable
283 // so that we can layout a read-only MethodTable with a pointer
284 // to the writeable parts of the MethodTable in an ngen image
286 struct MethodTableWriteableData
288 friend class MethodTable;
289 #if defined(DACCESS_COMPILE)
290 friend class NativeImageDumper;
295 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
296 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
297 // CARRY THE CORRECT INITIAL FLAGS.
299 enum_flag_Unrestored = 0x00000004,
300 enum_flag_HasApproxParent = 0x00000010,
301 enum_flag_UnrestoredTypeKey = 0x00000020,
302 enum_flag_IsNotFullyLoaded = 0x00000040,
303 enum_flag_DependenciesLoaded = 0x00000080, // class and all dependencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED
305 // enum_unused = 0x00000100,
307 enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x00000200, // Is any field type or sub field type overrode Equals or GetHashCode
308 enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x00000400, // Whether we have checked the overridden Equals or GetHashCode
310 // enum_unused = 0x00010000,
311 // enum_unused = 0x00020000,
312 // enum_unused = 0x00040000,
313 // enum_unused = 0x00080000, // enum_unused = 0x0010000,
314 // enum_unused = 0x0020000,
315 // enum_unused = 0x0040000,
316 // enum_unused = 0x0080000,
319 enum_flag_ParentMethodTablePointerValid = 0x40000000,
320 enum_flag_HasInjectedInterfaceDuplicates = 0x80000000,
323 DWORD m_dwFlags; // Lot of empty bits here.
325 // Non-unloadable context: internal RuntimeType object handle
326 // Unloadable context: slot index in LoaderAllocator's pinned table
327 RUNTIMETYPEHANDLE m_hExposedClassObject;
330 // to avoid verify same method table too many times when it's not changing, we cache the GC count
331 // on which the method table is verified. When fast GC STRESS is turned on, we only verify the MT if
332 // current GC count is bigger than the number. Note most thing which will invalidate a MT will require a
333 // GC (like AD unload)
334 Volatile<DWORD> m_dwLastVerifedGCCnt;
337 DWORD m_dwPadding; // Just to keep the size a multiple of 8
344 inline BOOL IsParentMethodTablePointerValid() const
346 LIMITED_METHOD_DAC_CONTRACT;
348 return (m_dwFlags & enum_flag_ParentMethodTablePointerValid);
350 inline void SetParentMethodTablePointerValid()
352 LIMITED_METHOD_CONTRACT;
354 m_dwFlags |= enum_flag_ParentMethodTablePointerValid;
359 inline RUNTIMETYPEHANDLE GetExposedClassObjectHandle() const
361 LIMITED_METHOD_CONTRACT;
362 return m_hExposedClassObject;
365 void SetIsNotFullyLoadedForBuildMethodTable()
367 LIMITED_METHOD_CONTRACT;
369 // Used only during method table initialization - no need for logging or Interlocked Exchange.
370 m_dwFlags |= (MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
371 MethodTableWriteableData::enum_flag_Unrestored |
372 MethodTableWriteableData::enum_flag_IsNotFullyLoaded |
373 MethodTableWriteableData::enum_flag_HasApproxParent);
376 void SetIsRestoredForBuildMethodTable()
378 LIMITED_METHOD_CONTRACT;
380 // Used only during method table initialization - no need for logging or Interlocked Exchange.
381 m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
382 MethodTableWriteableData::enum_flag_Unrestored);
385 void SetIsRestoredForBuildArrayMethodTable()
387 LIMITED_METHOD_CONTRACT;
389 // Used only during method table initialization - no need for logging or Interlocked Exchange.
390 SetIsRestoredForBuildMethodTable();
392 // Array's parent is always precise
393 m_dwFlags &= ~(MethodTableWriteableData::enum_flag_HasApproxParent);
396 }; // struct MethodTableWriteableData
398 typedef DPTR(MethodTableWriteableData) PTR_MethodTableWriteableData;
399 typedef DPTR(MethodTableWriteableData const) PTR_Const_MethodTableWriteableData;
401 #ifdef UNIX_AMD64_ABI_ITF
403 SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeType)
405 static const SystemVClassificationType toSystemVAmd64ClassificationTypeMap[] = {
406 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_END
407 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VOID
408 SystemVClassificationTypeInteger, // ELEMENT_TYPE_BOOLEAN
409 SystemVClassificationTypeInteger, // ELEMENT_TYPE_CHAR
410 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I1
411 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U1
412 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I2
413 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U2
414 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I4
415 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U4
416 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I8
417 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U8
418 SystemVClassificationTypeSSE, // ELEMENT_TYPE_R4
419 SystemVClassificationTypeSSE, // ELEMENT_TYPE_R8
420 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_STRING
421 SystemVClassificationTypeInteger, // ELEMENT_TYPE_PTR
422 SystemVClassificationTypeIntegerByRef, // ELEMENT_TYPE_BYREF
423 SystemVClassificationTypeStruct, // ELEMENT_TYPE_VALUETYPE
424 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_CLASS
425 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_VAR (type variable)
426 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_ARRAY
427 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_GENERICINST
428 SystemVClassificationTypeStruct, // ELEMENT_TYPE_TYPEDBYREF
429 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED
430 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I
431 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U
432 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_R_UNSUPPORTED
434 // put the correct type when we know our implementation
435 SystemVClassificationTypeInteger, // ELEMENT_TYPE_FNPTR
436 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_OBJECT
437 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_SZARRAY
438 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_MVAR
440 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_REQD
441 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_OPT
442 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_INTERNAL
445 _ASSERTE(sizeof(toSystemVAmd64ClassificationTypeMap) == ELEMENT_TYPE_MAX);
446 _ASSERTE(eeType < (CorElementType) sizeof(toSystemVAmd64ClassificationTypeMap));
447 // spot check of the map
448 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_I4] == SystemVClassificationTypeInteger);
449 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_PTR] == SystemVClassificationTypeInteger);
450 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_VALUETYPE] == SystemVClassificationTypeStruct);
451 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_TYPEDBYREF] == SystemVClassificationTypeStruct);
452 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_BYREF] == SystemVClassificationTypeIntegerByRef);
454 return (((unsigned)eeType) < ELEMENT_TYPE_MAX) ? (toSystemVAmd64ClassificationTypeMap[(unsigned)eeType]) : SystemVClassificationTypeUnknown;
457 #define SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES 8 // Size of an eightbyte in bytes.
458 #define SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT 16 // Maximum number of fields in struct passed in registers
460 struct SystemVStructRegisterPassingHelper
462 SystemVStructRegisterPassingHelper(unsigned int totalStructSize) :
463 structSize(totalStructSize),
465 inEmbeddedStruct(false),
466 currentUniqueOffsetField(0),
467 largestFieldOffset(-1)
469 for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
471 eightByteClassifications[i] = SystemVClassificationTypeNoClass;
472 eightByteSizes[i] = 0;
473 eightByteOffsets[i] = 0;
476 // Initialize the work arrays
477 for (int i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++)
479 fieldClassifications[i] = SystemVClassificationTypeNoClass;
486 unsigned int structSize;
488 // These fields are the output; these are what is computed by the classification algorithm.
489 unsigned int eightByteCount;
490 SystemVClassificationType eightByteClassifications[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
491 unsigned int eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
492 unsigned int eightByteOffsets[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
494 // Helper members to track state.
495 bool inEmbeddedStruct;
496 unsigned int currentUniqueOffsetField; // A virtual field that could encompass many overlapping fields.
497 int largestFieldOffset;
498 SystemVClassificationType fieldClassifications[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
499 unsigned int fieldSizes[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
500 unsigned int fieldOffsets[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
503 typedef DPTR(SystemVStructRegisterPassingHelper) SystemVStructRegisterPassingHelperPtr;
505 #endif // UNIX_AMD64_ABI_ITF
507 //===============================================================================================
509 // GC data appears before the beginning of the MethodTable
512 // Each generic type has a corresponding "generic" method table that serves the following
514 // * The method table pointer is used as a representative for the generic type e.g. in reflection
515 // * MethodDescs for methods in the vtable are used for reflection; they should never be invoked.
516 // Some other information (e.g. BaseSize) makes no sense "generically" but unfortunately gets put in anyway.
518 // Each distinct instantiation of a generic type has its own MethodTable structure.
519 // However, the EEClass structure can be shared between compatible instantiations e.g. List<string> and List<object>.
520 // In that case, MethodDescs are also shared between compatible instantiations (but see below about generic methods).
521 // Hence the vtable entries for MethodTables belonging to such an EEClass are the same.
523 // The non-vtable section of such MethodTables are only present for one of the instantiations (the first one
524 // requested) as non-vtable entries are never accessed through the vtable pointer of an object so it's always possible
525 // to ensure that they are accessed through the representative MethodTable that contains them.
527 // A MethodTable is the fundamental representation of type in the runtime. It is this structure that
528 // objects point at (see code:Object). It holds the size and GC layout of the type, as well as the dispatch table
529 // for virtual dispach (but not interface dispatch). There is a distinct method table for every instance of
530 // a generic type. From here you can get to
535 // * code:MethodTable.m_pEEClass - pointer to the cold part of the type.
536 // * code:MethodTable.m_pParentMethodTable - the method table of the parent type.
538 class MethodTableBuilder;
541 /************************************
543 ************************************/
544 // DO NOT ADD FRIENDS UNLESS ABSOLUTELY NECESSARY
545 // USE ACCESSORS TO READ/WRITE private field members
547 // Special access for setting up String object method table correctly
548 friend class ClassLoader;
549 friend class JIT_TrialAlloc;
551 friend class EEClass;
552 friend class MethodTableBuilder;
553 friend class CheckAsmOffsets;
554 #if defined(DACCESS_COMPILE)
555 friend class NativeImageDumper;
559 // Do some sanity checking to make sure it's a method table
560 // and not pointing to some random memory. In particular
561 // check that (apart from the special case of instantiated generic types) we have
562 // GetCanonicalMethodTable() == this;
565 static void CallFinalizer(Object *obj);
568 PTR_Module GetModule();
569 Assembly *GetAssembly();
571 PTR_Module GetModuleIfLoaded();
573 // GetDomain on an instantiated type, e.g. C<ty1,ty2> returns the SharedDomain if all the
574 // constituent parts of the type are SharedDomain (i.e. domain-neutral),
575 // and returns an AppDomain if any of the parts are from an AppDomain,
576 // i.e. are domain-bound. Note that if any of the parts are domain-bound
577 // then they will all belong to the same domain.
578 PTR_BaseDomain GetDomain();
580 // For regular, non-constructed types, GetLoaderModule() == GetModule()
581 // For constructed types (e.g. int[], Dict<int[], C>) the hash table through which a type
582 // is accessed lives in a "loader module". The rule for determining the loader module must ensure
583 // that a type never outlives its loader module with respect to app-domain unloading
585 // GetModuleForStatics() is the third kind of module. GetModuleForStatics() is module that
586 // statics are attached to.
587 PTR_Module GetLoaderModule();
588 PTR_LoaderAllocator GetLoaderAllocator();
590 void SetLoaderModule(Module* pModule);
591 void SetLoaderAllocator(LoaderAllocator* pAllocator);
593 // Get the domain local module - useful for static init checks
594 PTR_DomainLocalModule GetDomainLocalModule();
596 MethodTable *LoadEnclosingMethodTable(ClassLoadLevel targetLevel = CLASS_DEPENDENCIES_LOADED);
598 LPCWSTR GetPathForErrorMessages();
600 //-------------------------------------------------------------------
604 #ifdef FEATURE_COMINTEROP
605 TypeHandle GetCoClassForInterface();
608 TypeHandle SetupCoClassForInterface();
611 DWORD IsComClassInterface();
613 // Retrieves the COM interface type.
614 CorIfaceAttr GetComInterfaceType();
615 void SetComInterfaceType(CorIfaceAttr ItfType);
617 OBJECTHANDLE GetOHDelegate();
618 void SetOHDelegate (OBJECTHANDLE _ohDelegate);
620 CorClassIfaceAttr GetComClassInterfaceType();
621 TypeHandle GetDefItfForComClassItf();
623 void GetEventInterfaceInfo(MethodTable **ppSrcItfType, MethodTable **ppEvProvType);
625 BOOL IsExtensibleRCW();
627 // Helper to get parent class skipping over COM class in
629 MethodTable* GetComPlusParentMethodTable();
633 // class is a special COM event interface
634 int IsComEventItfType();
636 //-------------------------------------------------------------------
637 // Sparse VTables. These require a SparseVTableMap in the EEClass in
638 // order to record how the CLR's vtable slots map across to COM
641 int IsSparseForCOMInterop();
643 // COM interop helpers
644 // accessors for m_pComData
645 ComCallWrapperTemplate *GetComCallWrapperTemplate();
646 BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate);
647 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
648 ClassFactoryBase *GetComClassFactory();
649 BOOL SetComClassFactory(ClassFactoryBase *pFactory);
650 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
652 OBJECTREF GetObjCreateDelegate();
653 void SetObjCreateDelegate(OBJECTREF orDelegate);
656 // This is for COM Interop backwards compatibility
657 BOOL InsertComInteropData(InteropMethodTableData *pData);
658 InteropMethodTableData *CreateComInteropData(AllocMemTracker *pamTracker);
661 InteropMethodTableData *LookupComInteropData();
662 // This is the preferable entrypoint, as it will make sure that all
663 // parent MT's have their interop data created, and will create and
664 // add this MT's data if not available. The caller should make sure that
665 // an appropriate lock is taken to prevent duplicates.
666 // NOTE: The current caller of this is ComInterop, and it makes calls
667 // under its own lock to ensure not duplicates.
668 InteropMethodTableData *GetComInteropData();
669 #endif // !FEATURE_COMINTEROP
671 // class is a com object class
672 BOOL IsComObjectType()
674 LIMITED_METHOD_DAC_CONTRACT;
675 return GetFlag(enum_flag_ComObject);
678 // mark the class type as COM object class
679 void SetComObjectType();
681 #ifdef FEATURE_ICASTABLE
685 BOOL IsICastable(); // This type implements ICastable interface
687 void SetIDynamicInterfaceCastable();
688 BOOL IsIDynamicInterfaceCastable();
690 void SetIsTrackedReferenceWithFinalizer();
691 BOOL IsTrackedReferenceWithFinalizer();
693 #ifdef FEATURE_TYPEEQUIVALENCE
694 // mark the type as opted into type equivalence
695 void SetHasTypeEquivalence()
697 LIMITED_METHOD_CONTRACT;
698 SetFlag(enum_flag_HasTypeEquivalence);
700 #endif // FEATURE_TYPEEQUIVALENCE
702 // type has opted into type equivalence or is instantiated by/derived from a type that is
703 BOOL HasTypeEquivalence()
705 LIMITED_METHOD_CONTRACT;
706 #ifdef FEATURE_TYPEEQUIVALENCE
707 return GetFlag(enum_flag_HasTypeEquivalence);
710 #endif // FEATURE_TYPEEQUIVALENCE
713 //-------------------------------------------------------------------
714 // DYNAMIC ADDITION OF INTERFACES FOR COM INTEROP
716 // Support for dynamically added interfaces on extensible RCW's.
718 #ifdef FEATURE_COMINTEROP
719 PTR_InterfaceInfo GetDynamicallyAddedInterfaceMap();
720 unsigned GetNumDynamicallyAddedInterfaces();
721 BOOL FindDynamicallyAddedInterface(MethodTable *pInterface);
722 void AddDynamicInterface(MethodTable *pItfMT);
724 BOOL HasDynamicInterfaceMap()
726 LIMITED_METHOD_DAC_CONTRACT;
728 // currently all ComObjects except
729 // for __ComObject have dynamic Interface maps
730 return GetNumInterfaces() > 0 && IsComObjectType() && !ParentEquals(g_pObjectClass);
732 #endif // FEATURE_COMINTEROP
734 #ifndef DACCESS_COMPILE
736 VOID EnsureInstanceActive();
739 CHECK CheckActivated();
740 CHECK CheckInstanceActivated();
742 //-------------------------------------------------------------------
743 // THE DEFAULT CONSTRUCTOR
747 BOOL HasDefaultConstructor();
748 void SetHasDefaultConstructor();
749 WORD GetDefaultConstructorSlot();
750 MethodDesc *GetDefaultConstructor(BOOL forceBoxedEntryPoint = FALSE);
752 BOOL HasExplicitOrImplicitPublicDefaultConstructor();
754 //-------------------------------------------------------------------
755 // THE CLASS INITIALIZATION CONDITION
756 // (and related DomainLocalModule storage)
758 // - populate the DomainLocalModule if needed
764 // checks whether the class initialiser should be run on this class, and runs it if necessary
765 void CheckRunClassInitThrowing();
767 // checks whether or not the non-beforefieldinit class initializers have been run for all types in this type's
768 // inheritance hierarchy, and runs them if necessary. This simulates the behavior of running class constructors
769 // during object construction.
770 void CheckRunClassInitAsIfConstructingThrowing();
772 #if defined(TARGET_LOONGARCH64)
773 static bool IsLoongArch64OnlyOneField(MethodTable * pMT);
774 static int GetLoongArch64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE clh);
777 #if defined(TARGET_RISCV64)
778 static bool IsRiscV64OnlyOneField(MethodTable * pMT);
779 static int GetRiscV64PassStructInRegisterFlags(CORINFO_CLASS_HANDLE clh);
782 #if defined(UNIX_AMD64_ABI_ITF)
783 // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
784 bool ClassifyEightBytes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct, MethodTable** pByValueClassCache = NULL);
785 bool ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, EEClassNativeLayoutInfo const* nativeLayoutInfo);
786 #endif // defined(UNIX_AMD64_ABI_ITF)
788 // Copy m_dwFlags from another method table
789 void CopyFlags(MethodTable * pOldMT)
791 LIMITED_METHOD_CONTRACT;
792 m_dwFlags = pOldMT->m_dwFlags;
793 m_wFlags2 = pOldMT->m_wFlags2;
796 // Init the m_dwFlags field for an array
797 void SetIsArray(CorElementType arrayType);
799 BOOL IsClassPreInited();
801 // mark the class as having its cctor run.
802 #ifndef DACCESS_COMPILE
803 void SetClassInited();
804 BOOL IsClassInited();
807 void SetClassInitError();
810 inline BOOL IsGlobalClass()
813 return (GetTypeDefRid() == RidFromToken(COR_GLOBAL_PARENT_TOKEN));
816 // uniquely identifes this type in the Domain table
817 DWORD GetClassIndex();
821 #if defined(UNIX_AMD64_ABI_ITF)
822 void AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel) const;
823 // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
824 bool ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct, MethodTable** pByValueClassCache);
825 #endif // defined(UNIX_AMD64_ABI_ITF)
827 DWORD GetClassIndexFromToken(mdTypeDef typeToken)
829 LIMITED_METHOD_CONTRACT;
830 return RidFromToken(typeToken) - 1;
833 // called from CheckRunClassInitThrowing(). The type wasn't marked as
834 // inited while we were there, so let's attempt to do the work.
835 void DoRunClassInitThrowing();
837 BOOL RunClassInitEx(OBJECTREF *pThrowable);
840 //-------------------------------------------------------------------
841 // THE CLASS CONSTRUCTOR
844 MethodDesc * GetClassConstructor();
846 BOOL HasClassConstructor();
847 void SetHasClassConstructor();
848 WORD GetClassConstructorSlot();
850 void GetSavedExtent(TADDR *ppStart, TADDR *ppEnd);
852 //-------------------------------------------------------------------
853 // Save/Fixup/Restore/NeedsRestore
855 // Restore this method table if it's not already restored
856 // This is done by forcing a class load which in turn calls the Restore method
857 // The pending list is required for restoring types that reference themselves through
858 // instantiations of the superclass or interfaces e.g. System.Int32 : IComparable<System.Int32>
860 void AllocateRegularStaticBoxes();
861 void AllocateRegularStaticBox(FieldDesc* pField, Object** boxedStaticHandle);
862 static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0, bool canBeFrozen = false);
866 inline BOOL HasUnrestoredTypeKey() const
868 LIMITED_METHOD_DAC_CONTRACT;
870 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey) != 0;
873 // Actually do the restore actions on the method table
876 void SetIsRestored();
878 inline BOOL IsRestored()
880 LIMITED_METHOD_DAC_CONTRACT;
882 return !(GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
885 //-------------------------------------------------------------------
888 // The load level of a method table is derived from various flag bits
889 // See classloadlevel.h for details of each level
891 // Level CLASS_LOADED (fully loaded) is special: a type only
892 // reaches this level once all of its dependent types are also at
893 // this level (generic arguments, parent, interfaces, etc).
894 // Fully loading a type to this level is done outside locks, hence the need for
895 // a single atomic action that sets the level.
897 inline void SetIsFullyLoaded()
907 PRECONDITION(!HasApproxParent());
908 PRECONDITION(IsRestored());
910 InterlockedAnd((LONG*)&GetWriteableDataForWrite()->m_dwFlags, ~MethodTableWriteableData::enum_flag_IsNotFullyLoaded);
913 // Equivalent to GetLoadLevel() == CLASS_LOADED
914 inline BOOL IsFullyLoaded()
918 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded) == 0;
921 inline BOOL CanCompareBitsOrUseFastGetHashCode()
923 LIMITED_METHOD_CONTRACT;
924 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode);
927 // If canCompare is true, this method ensure an atomic operation for setting
928 // enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode and enum_flag_CanCompareBitsOrUseFastGetHashCode flags.
929 inline void SetCanCompareBitsOrUseFastGetHashCode(BOOL canCompare)
934 // Set checked and canCompare flags in one interlocked operation.
935 InterlockedOr((LONG*)&GetWriteableDataForWrite()->m_dwFlags,
936 MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode | MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode);
940 SetHasCheckedCanCompareBitsOrUseFastGetHashCode();
944 inline BOOL HasCheckedCanCompareBitsOrUseFastGetHashCode()
946 LIMITED_METHOD_CONTRACT;
947 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode);
950 inline void SetHasCheckedCanCompareBitsOrUseFastGetHashCode()
953 InterlockedOr((LONG*)&GetWriteableDataForWrite()->m_dwFlags, MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode);
956 inline void SetIsDependenciesLoaded()
966 PRECONDITION(!HasApproxParent());
967 PRECONDITION(IsRestored());
969 InterlockedOr((LONG*)&GetWriteableDataForWrite()->m_dwFlags, MethodTableWriteableData::enum_flag_DependenciesLoaded);
972 inline ClassLoadLevel GetLoadLevel()
974 LIMITED_METHOD_DAC_CONTRACT;
976 DWORD dwFlags = GetWriteableData()->m_dwFlags;
978 if (dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded)
980 if (dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey)
981 return CLASS_LOAD_UNRESTOREDTYPEKEY;
983 if (dwFlags & MethodTableWriteableData::enum_flag_Unrestored)
984 return CLASS_LOAD_UNRESTORED;
986 if (dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent)
987 return CLASS_LOAD_APPROXPARENTS;
989 if (!(dwFlags & MethodTableWriteableData::enum_flag_DependenciesLoaded))
990 return CLASS_LOAD_EXACTPARENTS;
992 return CLASS_DEPENDENCIES_LOADED;
999 CHECK CheckLoadLevel(ClassLoadLevel level)
1001 LIMITED_METHOD_CONTRACT;
1002 return TypeHandle(this).CheckLoadLevel(level);
1007 void DoFullyLoad(Generics::RecursionGraph * const pVisited, const ClassLoadLevel level, DFLPendingList * const pPending, BOOL * const pfBailed,
1008 const InstantiationContext * const pInstContext);
1010 //-------------------------------------------------------------------
1011 // METHOD TABLES AS TYPE DESCRIPTORS
1013 // A MethodTable can represeent a type such as "String" or an
1014 // instantiated type such as "List<String>".
1017 inline BOOL IsInterface()
1019 LIMITED_METHOD_DAC_CONTRACT;
1020 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Interface;
1023 void SetIsInterface()
1025 LIMITED_METHOD_CONTRACT;
1027 _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
1028 SetFlag(enum_flag_Category_Interface);
1031 inline BOOL IsSealed();
1033 inline BOOL IsAbstract();
1035 BOOL IsExternallyVisible();
1037 // Get the instantiation for this instantiated type e.g. for Dict<string,int>
1038 // this would be an array {string,int}
1039 // If not instantiated, return NULL
1040 Instantiation GetInstantiation();
1042 // Get the instantiation for an instantiated type or a pointer to the
1043 // element type for an array
1044 Instantiation GetClassOrArrayInstantiation();
1045 Instantiation GetArrayInstantiation();
1047 // Does this method table require that additional modules be loaded?
1048 inline BOOL HasModuleDependencies()
1050 LIMITED_METHOD_CONTRACT;
1051 return GetFlag(enum_flag_HasModuleDependencies);
1054 inline void SetHasModuleDependencies()
1056 SetFlag(enum_flag_HasModuleDependencies);
1059 inline BOOL IsIntrinsicType()
1061 LIMITED_METHOD_DAC_CONTRACT;;
1062 return GetFlag(enum_flag_IsIntrinsicType);
1065 inline void SetIsIntrinsicType()
1067 LIMITED_METHOD_DAC_CONTRACT;;
1068 SetFlag(enum_flag_IsIntrinsicType);
1071 // Is this a method table for a generic type instantiation, e.g. List<string>?
1072 inline BOOL HasInstantiation();
1074 // Returns true for any class which is either itself a generic
1075 // instantiation or is derived from a generic
1076 // instantiation anywhere in it's class hierarchy,
1078 // e.g. class D : C<int>
1079 // or class E : D, class D : C<int>
1081 // Does not return true just because the class supports
1082 // an instantiated interface type.
1083 BOOL HasGenericClassInstantiationInHierarchy()
1085 WRAPPER_NO_CONTRACT;
1086 return GetNumDicts() != 0;
1089 // Is this an instantiation of a generic class at its formal
1090 // type parameters ie. List<T> ?
1091 inline BOOL IsGenericTypeDefinition();
1093 BOOL ContainsGenericMethodVariables();
1095 // When creating an interface map, under some circumstances the
1096 // runtime will place the special marker type in the interface map instead
1097 // of the fully loaded type. This is to reduce the amount of type loading
1098 // performed at process startup.
1100 // The current rule is that these interfaces can only appear
1101 // on valuetypes that are not shared generic, and that the special
1102 // marker type is the open generic type.
1104 inline bool IsSpecialMarkerTypeForGenericCasting()
1106 return IsGenericTypeDefinition();
1109 static const DWORD MaxGenericParametersForSpecialMarkerType = 8;
1111 static BOOL ComputeContainsGenericVariables(Instantiation inst);
1113 inline void SetContainsGenericVariables()
1115 LIMITED_METHOD_CONTRACT;
1116 SetFlag(enum_flag_ContainsGenericVariables);
1119 inline void SetHasVariance()
1121 LIMITED_METHOD_CONTRACT;
1122 SetFlag(enum_flag_HasVariance);
1125 inline BOOL HasVariance()
1127 LIMITED_METHOD_CONTRACT;
1128 return GetFlag(enum_flag_HasVariance);
1131 // Is this something like List<T> or List<Stack<T>>?
1132 // List<Blah<T>> only exists for reflection and verification.
1133 inline DWORD ContainsGenericVariables(BOOL methodVarsOnly = FALSE)
1135 WRAPPER_NO_CONTRACT;
1138 return ContainsGenericMethodVariables();
1140 return GetFlag(enum_flag_ContainsGenericVariables);
1145 LIMITED_METHOD_DAC_CONTRACT;;
1146 return GetFlag(enum_flag_IsByRefLike);
1149 void SetIsByRefLike()
1151 LIMITED_METHOD_CONTRACT;
1152 SetFlag(enum_flag_IsByRefLike);
1155 // class is a com object class
1156 Module* GetDefiningModuleForOpenType();
1158 inline BOOL IsTypicalTypeDefinition()
1160 LIMITED_METHOD_CONTRACT;
1161 return !HasInstantiation() || IsGenericTypeDefinition();
1164 BOOL HasSameTypeDefAs(MethodTable *pMT);
1166 //-------------------------------------------------------------------
1167 // GENERICS & CODE SHARING
1170 BOOL IsSharedByGenericInstantiations();
1172 // If this is a "representative" generic MT or a non-generic (regular) MT return true
1173 inline BOOL IsCanonicalMethodTable();
1175 // Return the canonical representative MT amongst the set of MT's that share
1176 // code with the given MT because of generics.
1177 PTR_MethodTable GetCanonicalMethodTable();
1179 //-------------------------------------------------------------------
1180 // Accessing methods by slot number
1182 // Some of these functions are also currently used to get non-virtual
1183 // methods, relying on the assumption that they are contiguous. This
1184 // is not true for non-virtual methods in generic instantiations, which
1185 // only live on the canonical method table.
1189 NO_SLOT = 0xffff // a unique slot number used to indicate "empty" for fields that record slot numbers
1192 PCODE GetSlot(UINT32 slotNumber)
1194 WRAPPER_NO_CONTRACT;
1195 CONSISTENCY_CHECK(slotNumber < GetNumVtableSlots());
1197 return *GetSlotPtrRaw(slotNumber);
1200 // Special-case for when we know that the slot number corresponds
1201 // to a virtual method.
1202 inline PCODE GetSlotForVirtual(UINT32 slotNum)
1204 LIMITED_METHOD_CONTRACT;
1206 CONSISTENCY_CHECK(slotNum < GetNumVirtuals());
1207 // Virtual slots live in chunks pointed to by vtable indirections
1208 return *(GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum));
1211 PTR_PCODE GetSlotPtrRaw(UINT32 slotNum)
1213 WRAPPER_NO_CONTRACT;
1214 CONSISTENCY_CHECK(slotNum < GetNumVtableSlots());
1216 if (slotNum < GetNumVirtuals())
1218 // Virtual slots live in chunks pointed to by vtable indirections
1219 return GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum);
1221 else if (HasSingleNonVirtualSlot())
1223 // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member,
1224 // except when there is only one in which case it lives in the optional member itself
1225 _ASSERTE(slotNum == GetNumVirtuals());
1226 return dac_cast<PTR_PCODE>(GetNonVirtualSlotsPtr());
1230 // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member
1231 _ASSERTE(HasNonVirtualSlotsArray());
1232 return GetNonVirtualSlotsArray() + (slotNum - GetNumVirtuals());
1236 PTR_PCODE GetSlotPtr(UINT32 slotNum)
1238 WRAPPER_NO_CONTRACT;
1239 return GetSlotPtrRaw(slotNum);
1242 void SetSlot(UINT32 slotNum, PCODE slotVal);
1244 //-------------------------------------------------------------------
1247 // Rather than the traditional array of code pointers (or "slots") we use a two-level vtable in
1248 // which slots for virtual methods live in chunks. Doing so allows the chunks to be shared among
1249 // method tables (the most common example being between parent and child classes where the child
1250 // does not override any method in the chunk). This yields substantial space savings at the fixed
1251 // cost of one additional indirection for a virtual call.
1253 // Note that none of this should be visible outside the implementation of MethodTable; all other
1254 // code continues to refer to a virtual method via the traditional slot number. This is similar to
1255 // how we refer to non-virtual methods as having a slot number despite having long ago moved their
1256 // code pointers out of the vtable.
1258 // Consider a class where GetNumVirtuals is 5 and (for the sake of the example) assume we break
1259 // the vtable into chunks of size 3. The layout would be as follows:
1261 // pMT chunk 1 chunk 2
1262 // ------------------ ------------------ ------------------
1263 // | | | M1() | | M4() |
1264 // | fixed-size | ------------------ ------------------
1265 // | portion of | | M2() | | M5() |
1266 // | MethodTable | ------------------ ------------------
1268 // ------------------ ------------------
1269 // | ptr to chunk 1 |
1270 // ------------------
1271 // | ptr to chunk 2 |
1272 // ------------------
1274 // We refer to "ptr to chunk 1" and "ptr to chunk 2" as "indirection slots."
1276 // The current chunking strategy is independent of class properties; all are of size 8. Several
1277 // other strategies were tried, and the only one that has performed better empirically is to begin
1278 // with a single chunk of size 4 (matching the number of virtuals in System.Object) and then
1279 // continue with chunks of size 8. However it was a small improvement and required the run-time
1280 // helpers listed below to be measurably slower.
1282 // If you want to change this, you should only need to modify the first four functions below
1283 // along with any assembly helper that has taken a dependency on the layout. Currently,
1284 // those consist of:
1285 // JIT_IsInstanceOfInterface
1286 // JIT_ChkCastInterface
1287 // Transparent proxy stub
1289 // This layout only applies to the virtual methods in a class (those with slot number below GetNumVirtuals).
1290 // Non-virtual methods that are in the vtable (those with slot numbers between GetNumVirtuals and
1291 // GetNumVtableSlots) are laid out in a single chunk pointed to by an optional member.
1292 // See GetSlotPtrRaw for more details.
1294 #define VTABLE_SLOTS_PER_CHUNK 8
1295 #define VTABLE_SLOTS_PER_CHUNK_LOG2 3
1297 typedef PCODE VTableIndir2_t;
1298 typedef DPTR(VTableIndir2_t) VTableIndir_t;
1300 static DWORD GetIndexOfVtableIndirection(DWORD slotNum);
1301 static DWORD GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
1302 static DWORD GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
1303 static UINT32 GetIndexAfterVtableIndirection(UINT32 slotNum);
1304 static DWORD GetNumVtableIndirections(DWORD wNumVirtuals);
1305 DPTR(VTableIndir_t) GetVtableIndirections();
1306 DWORD GetNumVtableIndirections();
1308 class VtableIndirectionSlotIterator
1310 friend class MethodTable;
1313 DPTR(VTableIndir_t) m_pSlot;
1316 PTR_MethodTable m_pMT;
1318 VtableIndirectionSlotIterator(MethodTable *pMT);
1319 VtableIndirectionSlotIterator(MethodTable *pMT, DWORD index);
1325 DWORD GetOffsetFromMethodTable();
1326 DPTR(VTableIndir2_t) GetIndirectionSlot();
1328 #ifndef DACCESS_COMPILE
1329 void SetIndirectionSlot(DPTR(VTableIndir2_t) pChunk);
1332 DWORD GetStartSlot();
1334 DWORD GetNumSlots();
1336 }; // class VtableIndirectionSlotIterator
1338 VtableIndirectionSlotIterator IterateVtableIndirectionSlots();
1339 VtableIndirectionSlotIterator IterateVtableIndirectionSlotsFrom(DWORD index);
1341 inline BOOL HasNonVirtualSlots()
1343 LIMITED_METHOD_DAC_CONTRACT;
1344 return GetFlag(enum_flag_HasNonVirtualSlots);
1347 inline BOOL HasSingleNonVirtualSlot()
1349 LIMITED_METHOD_DAC_CONTRACT;
1350 return GetFlag(enum_flag_HasSingleNonVirtualSlot);
1353 inline BOOL HasNonVirtualSlotsArray()
1355 LIMITED_METHOD_DAC_CONTRACT;
1356 return HasNonVirtualSlots() && !HasSingleNonVirtualSlot();
1359 TADDR GetNonVirtualSlotsPtr();
1361 inline PTR_PCODE GetNonVirtualSlotsArray()
1363 LIMITED_METHOD_DAC_CONTRACT;
1364 _ASSERTE(HasNonVirtualSlotsArray());
1365 return *dac_cast<PTR_PTR_PCODE>(GetNonVirtualSlotsPtr());
1368 #ifndef DACCESS_COMPILE
1369 inline void SetNonVirtualSlotsArray(PCODE *slots)
1371 LIMITED_METHOD_CONTRACT;
1372 _ASSERTE(HasNonVirtualSlotsArray());
1374 *(PCODE **)GetNonVirtualSlotsPtr() = slots;
1377 inline void SetHasSingleNonVirtualSlot()
1379 LIMITED_METHOD_CONTRACT;
1380 SetFlag(enum_flag_HasSingleNonVirtualSlot);
1384 inline unsigned GetNonVirtualSlotsArraySize()
1386 LIMITED_METHOD_DAC_CONTRACT;
1387 return GetNumNonVirtualSlots() * sizeof(PCODE);
1390 inline WORD GetNumNonVirtualSlots();
1392 inline BOOL HasVirtualStaticMethods() const;
1393 inline void SetHasVirtualStaticMethods();
1395 void VerifyThatAllVirtualStaticMethodsAreImplemented();
1397 inline WORD GetNumVirtuals()
1399 LIMITED_METHOD_DAC_CONTRACT;
1401 return m_wNumVirtuals;
1404 inline void SetNumVirtuals (WORD wNumVtableSlots)
1406 LIMITED_METHOD_CONTRACT;
1407 m_wNumVirtuals = wNumVtableSlots;
1410 unsigned GetNumParentVirtuals()
1412 LIMITED_METHOD_CONTRACT;
1413 if (IsInterface()) {
1416 MethodTable *pMTParent = GetParentMethodTable();
1417 return pMTParent == NULL ? 0 : pMTParent->GetNumVirtuals();
1420 #define SIZEOF__MethodTable_ (0x10 + (6 INDEBUG(+1)) * TARGET_POINTER_SIZE)
1422 static inline DWORD GetVtableOffset()
1424 LIMITED_METHOD_DAC_CONTRACT;
1426 return SIZEOF__MethodTable_;
1429 // Return total methods: virtual, static, and instance method slots.
1430 WORD GetNumMethods();
1432 // Return number of slots in this methodtable. This is just an information about the layout of the methodtable, it should not be used
1433 // for functionality checks. Do not confuse with GetNumVirtuals()!
1434 WORD GetNumVtableSlots()
1436 LIMITED_METHOD_DAC_CONTRACT;
1437 return GetNumVirtuals() + GetNumNonVirtualSlots();
1440 //-------------------------------------------------------------------
1441 // Slots <-> the MethodDesc associated with the slot.
1444 MethodDesc* GetMethodDescForSlot(DWORD slot);
1446 static MethodDesc* GetMethodDescForSlotAddress(PCODE addr, BOOL fSpeculative = FALSE);
1448 PCODE GetRestoredSlot(DWORD slot);
1450 // Returns MethodTable that GetRestoredSlot get its values from
1451 MethodTable * GetRestoredSlotMT(DWORD slot);
1453 // Used to map methods on the same slot between instantiations.
1454 MethodDesc * GetParallelMethodDesc(MethodDesc * pDefMD);
1456 //-------------------------------------------------------------------
1457 // BoxedEntryPoint MethodDescs.
1459 // Virtual methods on structs have BoxedEntryPoint method descs in their vtable.
1460 // See also notes for MethodDesc::FindOrCreateAssociatedMethodDesc. You should
1461 // probably be using that function if you need to map between unboxing
1462 // stubs and non-unboxing stubs.
1464 MethodDesc* GetBoxedEntryPointMD(MethodDesc *pMD);
1466 MethodDesc* GetUnboxedEntryPointMD(MethodDesc *pMD);
1467 MethodDesc* GetExistingUnboxedEntryPointMD(MethodDesc *pMD);
1469 //-------------------------------------------------------------------
1470 // FIELD LAYOUT, OBJECT SIZE ETC.
1473 inline BOOL HasLayout();
1475 inline EEClassLayoutInfo* GetLayoutInfo();
1477 EEClassNativeLayoutInfo const* GetNativeLayoutInfo();
1479 EEClassNativeLayoutInfo const* EnsureNativeLayoutInfoInitialized();
1481 inline BOOL IsBlittable();
1483 inline BOOL IsManagedSequential();
1485 inline BOOL HasExplicitSize();
1487 inline BOOL IsAutoLayoutOrHasAutoLayoutField();
1489 // Only accurate on types which are not auto layout
1490 inline BOOL IsInt128OrHasInt128Fields();
1492 UINT32 GetNativeSize();
1496 LIMITED_METHOD_DAC_CONTRACT;
1500 void SetBaseSize(DWORD baseSize)
1502 LIMITED_METHOD_CONTRACT;
1503 m_BaseSize = baseSize;
1506 BOOL IsStringOrArray() const
1508 LIMITED_METHOD_DAC_CONTRACT;
1509 return HasComponentSize();
1514 LIMITED_METHOD_DAC_CONTRACT;
1515 return HasComponentSize() && !IsArray() && RawGetComponentSize() == 2;
1518 BOOL HasComponentSize() const
1520 LIMITED_METHOD_DAC_CONTRACT;
1521 return GetFlag(enum_flag_HasComponentSize);
1524 // returns random combination of flags if this doesn't have a component size
1525 WORD RawGetComponentSize()
1527 LIMITED_METHOD_DAC_CONTRACT;
1529 return *((WORD*)&m_dwFlags + 1);
1531 return *(WORD*)&m_dwFlags;
1532 #endif // !BIGENDIAN
1535 // returns 0 if this doesn't have a component size
1537 // The component size is actually 16-bit WORD, but this method is returning SIZE_T to ensure
1538 // that SIZE_T is used everywhere for object size computation. It is necessary to support
1539 // objects bigger than 2GB.
1540 SIZE_T GetComponentSize()
1542 LIMITED_METHOD_DAC_CONTRACT;
1543 return HasComponentSize() ? RawGetComponentSize() : 0;
1546 void SetComponentSize(WORD wComponentSize)
1548 LIMITED_METHOD_CONTRACT;
1549 // it would be nice to assert here that this is either a string
1550 // or an array, but how do we know.
1552 // it would also be nice to assert that the component size is > 0,
1553 // but that would not hold for array's of System.Void and generic type parameters
1554 SetFlag(enum_flag_HasComponentSize);
1555 m_dwFlags = (m_dwFlags & ~0xFFFF) | wComponentSize;
1558 inline WORD GetNumInstanceFields();
1560 inline WORD GetNumStaticFields();
1562 inline WORD GetNumThreadStaticFields();
1564 // Note that for value types GetBaseSize returns the size of instance fields for
1565 // a boxed value, and GetNumInstanceFieldsBytes for an unboxed value.
1566 // We place methods like these on MethodTable primarily so we can choose to cache
1567 // the information within MethodTable, and so less code manipulates EEClass
1568 // objects directly, because doing so can lead to bugs related to generics.
1570 // <TODO> Use m_wBaseSize whenever this is identical to GetNumInstanceFieldBytes.
1571 // We would need to reserve a flag for this. </TODO>
1573 inline DWORD GetNumInstanceFieldBytes();
1575 int GetFieldAlignmentRequirement();
1577 inline WORD GetNumIntroducedInstanceFields();
1579 // Note: This flag MUST be available even from an unrestored MethodTable - see GcScanRoots in siginfo.cpp.
1580 DWORD ContainsPointers()
1582 LIMITED_METHOD_CONTRACT;
1583 return GetFlag(enum_flag_ContainsPointers);
1588 LIMITED_METHOD_CONTRACT;
1589 #ifdef FEATURE_COLLECTIBLE_TYPES
1590 return GetFlag(enum_flag_Collectible);
1596 BOOL ContainsPointersOrCollectible()
1598 LIMITED_METHOD_CONTRACT;
1599 return GetFlag(enum_flag_ContainsPointers) || GetFlag(enum_flag_Collectible);
1602 OBJECTHANDLE GetLoaderAllocatorObjectHandle();
1603 NOINLINE BYTE *GetLoaderAllocatorObjectForGC();
1605 BOOL IsNotTightlyPacked();
1607 BOOL IsAllGCPointers();
1609 void SetContainsPointers()
1611 LIMITED_METHOD_CONTRACT;
1612 SetFlag(enum_flag_ContainsPointers);
1615 #ifdef FEATURE_64BIT_ALIGNMENT
1616 inline bool RequiresAlign8()
1618 LIMITED_METHOD_DAC_CONTRACT;
1619 return !!GetFlag(enum_flag_RequiresAlign8);
1622 inline void SetRequiresAlign8()
1624 LIMITED_METHOD_CONTRACT;
1625 SetFlag(enum_flag_RequiresAlign8);
1627 #endif // FEATURE_64BIT_ALIGNMENT
1629 //-------------------------------------------------------------------
1630 // FIELD DESCRIPTORS
1632 // Most of this API still lives on EEClass.
1634 // ************************************ WARNING *************
1635 // ** !!!!INSTANCE FIELDDESCS ARE REPRESENTATIVES!!!!! **
1636 // ** THEY ARE SHARED BY COMPATIBLE GENERIC INSTANTIATIONS **
1637 // ************************************ WARNING *************
1639 // This goes straight to the EEClass
1640 // Careful about using this method. If it's possible that fields may have been added via EnC, then
1641 // must use the FieldDescIterator as any fields added via EnC won't be in the raw list
1642 PTR_FieldDesc GetApproxFieldDescListRaw();
1644 // This returns a type-exact FieldDesc for a static field, but may still return a representative
1645 // for a non-static field.
1646 PTR_FieldDesc GetFieldDescByIndex(DWORD fieldIndex);
1648 DWORD GetIndexForFieldDesc(FieldDesc *pField);
1650 inline bool HasPreciseInitCctors()
1652 LIMITED_METHOD_CONTRACT;
1653 return !!GetFlag(enum_flag_HasPreciseInitCctors);
1656 inline void SetHasPreciseInitCctors()
1658 LIMITED_METHOD_CONTRACT;
1659 SetFlag(enum_flag_HasPreciseInitCctors);
1662 #if defined(FEATURE_HFA)
1665 LIMITED_METHOD_CONTRACT;
1666 return !!GetFlag(enum_flag_IsHFA);
1669 inline void SetIsHFA()
1671 LIMITED_METHOD_CONTRACT;
1672 SetFlag(enum_flag_IsHFA);
1674 #else // !FEATURE_HFA
1676 #endif // FEATURE_HFA
1678 // Returns the size in bytes of this type if it is a HW vector type; 0 otherwise.
1679 int GetVectorSize();
1681 // Get the HFA type. This is supported both with FEATURE_HFA, in which case it
1682 // depends on the cached bit on the class, or without, in which case it is recomputed
1683 // for each invocation.
1684 CorInfoHFAElemType GetHFAType();
1685 // The managed and unmanaged HFA type can differ for types with layout. The following two methods return the unmanaged HFA type.
1687 CorInfoHFAElemType GetNativeHFAType();
1689 #ifdef UNIX_AMD64_ABI
1690 inline bool IsRegPassedStruct()
1692 LIMITED_METHOD_CONTRACT;
1693 return !!GetFlag(enum_flag_IsRegStructPassed);
1696 inline void SetRegPassedStruct()
1698 LIMITED_METHOD_CONTRACT;
1699 SetFlag(enum_flag_IsRegStructPassed);
1702 inline bool IsRegPassedStruct()
1708 #ifdef FEATURE_64BIT_ALIGNMENT
1709 // Returns true iff the native view of this type requires 64-bit alignment.
1710 bool NativeRequiresAlign8();
1711 #endif // FEATURE_64BIT_ALIGNMENT
1713 //-------------------------------------------------------------------
1714 // PARENT INTERFACES
1716 unsigned GetNumInterfaces()
1718 LIMITED_METHOD_DAC_CONTRACT;
1719 return m_wNumInterfaces;
1722 //-------------------------------------------------------------------
1725 BOOL CanCastToInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
1726 BOOL CanCastToClass(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
1727 BOOL CanCastTo(MethodTable* pTargetMT, TypeHandlePairList *pVisited);
1728 BOOL ArraySupportsBizarreInterface(MethodTable* pInterfaceMT, TypeHandlePairList* pVisited);
1729 BOOL ArrayIsInstanceOf(MethodTable* pTargetMT, TypeHandlePairList* pVisited);
1731 BOOL CanCastByVarianceToInterfaceOrDelegate(MethodTable* pTargetMT, TypeHandlePairList* pVisited, MethodTable* pMTInterfaceMapOwner = NULL);
1733 // The inline part of equivalence check.
1734 #ifndef DACCESS_COMPILE
1735 FORCEINLINE BOOL IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL));
1737 #ifdef FEATURE_TYPEEQUIVALENCE
1738 // This method is public so that TypeHandle has direct access to it
1739 BOOL IsEquivalentTo_Worker(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO tolerant
1741 BOOL IsEquivalentTo_WorkerInner(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO intolerant
1742 #endif // FEATURE_TYPEEQUIVALENCE
1746 //-------------------------------------------------------------------
1747 // THE METHOD TABLE PARENT (SUPERCLASS/BASE CLASS)
1749 BOOL HasApproxParent()
1751 LIMITED_METHOD_DAC_CONTRACT;
1752 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent) != 0;
1754 inline void SetHasExactParent()
1756 WRAPPER_NO_CONTRACT;
1757 InterlockedAnd((LONG*)&GetWriteableDataForWrite()->m_dwFlags, ~MethodTableWriteableData::enum_flag_HasApproxParent);
1761 // Caller must know that the parent method table is not an encoded fixup
1762 inline PTR_MethodTable GetParentMethodTable()
1764 LIMITED_METHOD_DAC_CONTRACT;
1766 PRECONDITION(IsParentMethodTablePointerValid());
1767 return m_pParentMethodTable;
1770 #ifndef DACCESS_COMPILE
1771 inline MethodTable ** GetParentMethodTableValuePtr()
1773 LIMITED_METHOD_CONTRACT;
1774 return &m_pParentMethodTable;
1776 #endif // !DACCESS_COMPILE
1778 // Is the parent method table pointer equal to the given argument?
1779 BOOL ParentEquals(PTR_MethodTable pMT)
1781 LIMITED_METHOD_DAC_CONTRACT;
1782 PRECONDITION(IsParentMethodTablePointerValid());
1783 return GetParentMethodTable() == pMT;
1787 BOOL IsParentMethodTablePointerValid();
1790 #ifndef DACCESS_COMPILE
1791 void SetParentMethodTable (MethodTable *pParentMethodTable)
1793 LIMITED_METHOD_CONTRACT;
1794 m_pParentMethodTable = pParentMethodTable;
1796 GetWriteableDataForWrite()->SetParentMethodTablePointerValid();
1799 #endif // !DACCESS_COMPILE
1800 MethodTable * GetMethodTableMatchingParentClass(MethodTable * pWhichParent);
1801 Instantiation GetInstantiationOfParentClass(MethodTable *pWhichParent);
1803 //-------------------------------------------------------------------
1804 // THE EEClass (Possibly shared between instantiations!).
1806 // Note that it is not generally the case that GetClass.GetMethodTable() == t.
1808 PTR_EEClass GetClass();
1810 PTR_EEClass GetClassWithPossibleAV();
1812 BOOL ValidateWithPossibleAV();
1814 BOOL IsClassPointerValid();
1816 static UINT32 GetOffsetOfFlags()
1818 LIMITED_METHOD_CONTRACT;
1819 return offsetof(MethodTable, m_dwFlags);
1822 static UINT32 GetIfArrayThenSzArrayFlag()
1824 LIMITED_METHOD_CONTRACT;
1825 return enum_flag_Category_IfArrayThenSzArray;
1828 //-------------------------------------------------------------------
1831 // Do not call the following at any time except when creating a method table.
1832 // One day we will have proper constructors for method tables and all these
1834 #ifndef DACCESS_COMPILE
1835 inline void SetClass(EEClass *pClass)
1837 LIMITED_METHOD_CONTRACT;
1838 m_pEEClass = pClass;
1841 inline void SetCanonicalMethodTable(MethodTable * pMT)
1843 m_pCanonMT = (TADDR)pMT | MethodTable::UNION_METHODTABLE;
1847 inline void SetHasInstantiation(BOOL fTypicalInstantiation, BOOL fSharedByGenericInstantiations);
1849 //-------------------------------------------------------------------
1850 // INTERFACE IMPLEMENTATION
1853 // Faster force-inlined version of ImplementsInterface
1854 BOOL ImplementsInterfaceInline(MethodTable *pInterface);
1856 BOOL ImplementsInterface(MethodTable *pInterface);
1857 BOOL ImplementsEquivalentInterface(MethodTable *pInterface);
1859 MethodDesc *GetMethodDescForInterfaceMethod(TypeHandle ownerType, MethodDesc *pInterfaceMD, BOOL throwOnConflict);
1860 MethodDesc *GetMethodDescForInterfaceMethod(MethodDesc *pInterfaceMD, BOOL throwOnConflict); // You can only use this one for non-generic interfaces
1862 //-------------------------------------------------------------------
1866 inline PTR_InterfaceInfo GetInterfaceMap();
1868 #ifndef DACCESS_COMPILE
1869 void SetInterfaceMap(WORD wNumInterfaces, InterfaceInfo_t* iMap);
1872 inline int HasInterfaceMap()
1874 LIMITED_METHOD_DAC_CONTRACT;
1875 return (m_wNumInterfaces != 0);
1878 // Where possible, use this iterator over the interface map instead of accessing the map directly
1879 // That way we can easily change the implementation of the map
1880 class InterfaceMapIterator
1882 friend class MethodTable;
1885 PTR_InterfaceInfo m_pMap;
1889 InterfaceMapIterator(MethodTable *pMT)
1890 : m_pMap(pMT->GetInterfaceMap()),
1892 m_count(pMT->GetNumInterfaces())
1894 WRAPPER_NO_CONTRACT;
1897 InterfaceMapIterator(MethodTable *pMT, DWORD index)
1898 : m_pMap(pMT->GetInterfaceMap() + index),
1900 m_count(pMT->GetNumInterfaces())
1902 WRAPPER_NO_CONTRACT;
1903 CONSISTENCY_CHECK(index >= 0 && index < m_count);
1907 InterfaceInfo_t* GetInterfaceInfo()
1909 LIMITED_METHOD_CONTRACT;
1913 // Move to the next item in the map, returning TRUE if an item
1914 // exists or FALSE if we've run off the end
1917 LIMITED_METHOD_CONTRACT;
1918 PRECONDITION(!Finished());
1919 if (m_i != (DWORD) -1)
1921 return (++m_i < m_count);
1924 // Have we iterated over all of the items?
1927 return (m_i == m_count);
1930 #ifndef DACCESS_COMPILE
1931 // Get the interface at the current position. This GetInterfaceMethod
1932 // will ensure that the exact correct instantiation of the interface
1933 // is found, even if the MethodTable in the interface map is the generic
1935 PTR_MethodTable GetInterface(MethodTable* pMTOwner, ClassLoadLevel loadLevel = CLASS_LOADED);
1938 // Get the interface at the current position, with whatever its normal load level is
1939 inline PTR_MethodTable GetInterfaceApprox()
1941 CONTRACT(PTR_MethodTable)
1946 PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
1947 POSTCONDITION(CheckPointer(RETVAL));
1951 RETURN (m_pMap->GetMethodTable());
1954 inline bool CurrentInterfaceMatches(MethodTable* pMTOwner, MethodTable* pMT)
1961 PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
1965 MethodTable *pCurrentMethodTable = m_pMap->GetMethodTable();
1967 bool exactMatch = pCurrentMethodTable == pMT;
1970 if (pCurrentMethodTable->HasSameTypeDefAs(pMT) &&
1971 pMT->HasInstantiation() &&
1972 pCurrentMethodTable->IsSpecialMarkerTypeForGenericCasting() &&
1973 !pMTOwner->ContainsGenericVariables() &&
1974 pMT->GetInstantiation().ContainsAllOneType(pMTOwner))
1977 #ifndef DACCESS_COMPILE
1978 // We match exactly, and have an actual pMT loaded. Insert
1979 // the searched for interface if it is fully loaded, so that
1980 // future checks are more efficient
1981 if (pMT->IsFullyLoaded())
1987 RETURN (exactMatch);
1990 inline bool HasSameTypeDefAs(MethodTable* pMT)
1997 PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
2001 RETURN (m_pMap->GetMethodTable()->HasSameTypeDefAs(pMT));
2004 #ifndef DACCESS_COMPILE
2005 void SetInterface(MethodTable *pMT)
2007 WRAPPER_NO_CONTRACT;
2008 m_pMap->SetMethodTable(pMT);
2014 LIMITED_METHOD_CONTRACT;
2017 }; // class InterfaceMapIterator
2019 // Create a new iterator over the interface map
2020 // The iterator starts just before the first item in the map
2021 InterfaceMapIterator IterateInterfaceMap()
2023 WRAPPER_NO_CONTRACT;
2024 return InterfaceMapIterator(this);
2027 // Create a new iterator over the interface map, starting at the index specified
2028 InterfaceMapIterator IterateInterfaceMapFrom(DWORD index)
2030 WRAPPER_NO_CONTRACT;
2031 return InterfaceMapIterator(this, index);
2034 //-------------------------------------------------------------------
2035 // ADDITIONAL INTERFACE MAP DATA
2038 // We store extra info (flag bits) for interfaces implemented on this MethodTable in a separate optional
2039 // location for better data density (if we put them in the interface map directly data alignment could
2040 // have us using 32 or even 64 bits to represent a single boolean value). Currently the only flag we
2041 // persist is IsDeclaredOnClass (was the interface explicitly declared by this class).
2043 // Currently we always store extra info whenever we have an interface map (in the future you could imagine
2044 // this being limited to those scenarios in which at least one of the interfaces has a non-default value
2046 inline BOOL HasExtraInterfaceInfo()
2049 return HasInterfaceMap();
2052 // Count of interfaces that can have their extra info stored inline in the optional data structure itself
2053 // (once the interface count exceeds this limit the optional data slot will instead point to a buffer with
2054 // the information).
2055 enum { kInlinedInterfaceInfoThreshold = sizeof(TADDR) * 8 };
2057 // Calculate how many bytes of storage will be required to track additional information for interfaces.
2058 // This will be zero if there are no interfaces, but can also be zero for small numbers of interfaces as
2059 // well, and callers should be ready to handle this.
2060 static SIZE_T GetExtraInterfaceInfoSize(DWORD cInterfaces);
2062 // Called after GetExtraInterfaceInfoSize above to setup a new MethodTable with the additional memory to
2063 // track extra interface info. If there are a non-zero number of interfaces implemented on this class but
2064 // GetExtraInterfaceInfoSize() returned zero, this call must still be made (with a NULL argument).
2065 void InitializeExtraInterfaceInfo(PVOID pInfo);
2067 #ifdef DACCESS_COMPILE
2068 void EnumMemoryRegionsForExtraInterfaceInfo();
2069 #endif // DACCESS_COMPILE
2071 // For the given interface in the map (specified via map index) mark the interface as declared explicitly
2072 // on this class. This is not legal for dynamically added interfaces (as used by RCWs).
2073 void SetInterfaceDeclaredOnClass(DWORD index);
2075 // For the given interface in the map (specified via map index) return true if the interface was declared
2076 // explicitly on this class.
2077 bool IsInterfaceDeclaredOnClass(DWORD index);
2079 //-------------------------------------------------------------------
2080 // VIRTUAL/INTERFACE CALL RESOLUTION
2082 // These should probably go in method.hpp since they don't have
2083 // much to do with method tables per se.
2086 // get the method desc given the interface method desc
2087 static MethodDesc *GetMethodDescForInterfaceMethodAndServer(TypeHandle ownerType, MethodDesc *pItfMD, OBJECTREF *pServer);
2089 #ifdef FEATURE_COMINTEROP
2090 // 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)
2091 MethodDesc *GetMethodDescForComInterfaceMethod(MethodDesc *pItfMD, bool fNullOk);
2092 #endif // FEATURE_COMINTEROP
2094 // Resolve virtual static interface method pInterfaceMD on this type.
2096 // Specify allowNullResult to return NULL instead of throwing if the there is no implementation
2097 // Specify verifyImplemented to verify that there is a match, but do not actually return a final usable MethodDesc
2098 // Specify allowVariantMatches to permit generic interface variance
2099 // Specify uniqueResolution to store the flag saying whether the resolution was unambiguous;
2100 // when NULL, throw an AmbiguousResolutionException upon hitting ambiguous SVM resolution.
2101 // The 'level' parameter specifies the load level for the class containing the resolved MethodDesc.
2102 MethodDesc *ResolveVirtualStaticMethod(
2103 MethodTable* pInterfaceType,
2104 MethodDesc* pInterfaceMD,
2105 ResolveVirtualStaticMethodFlags resolveVirtualStaticMethodFlags,
2106 BOOL *uniqueResolution = NULL,
2107 ClassLoadLevel level = CLASS_LOADED);
2109 // Try a partial resolve of the constraint call, up to generic code sharing.
2111 // Note that this will not necessarily resolve the call exactly, since we might be compiling
2112 // shared generic code - it may just resolve it to a candidate suitable for
2113 // JIT compilation, and require a runtime lookup for the actual code pointer
2116 // Return NULL if the call could not be resolved, e.g. because it is invoked
2117 // on a type that inherits the implementation of the method from System.Object
2118 // or System.ValueType.
2120 // Always returns an unboxed entry point with a uniform calling convention.
2121 MethodDesc * TryResolveConstraintMethodApprox(
2122 TypeHandle ownerType,
2124 BOOL * pfForceUseRuntimeLookup = NULL);
2126 //-------------------------------------------------------------------
2127 // CONTRACT IMPLEMENTATIONS
2130 inline BOOL HasDispatchMap()
2132 WRAPPER_NO_CONTRACT;
2133 return GetDispatchMap() != NULL;
2136 PTR_DispatchMap GetDispatchMap();
2138 inline BOOL HasDispatchMapSlot()
2140 LIMITED_METHOD_DAC_CONTRACT;
2141 return GetFlag(enum_flag_HasDispatchMapSlot);
2144 #ifndef DACCESS_COMPILE
2145 void SetDispatchMap(DispatchMap *pDispatchMap)
2147 LIMITED_METHOD_CONTRACT;
2148 _ASSERTE(HasDispatchMapSlot());
2150 TADDR pSlot = GetMultipurposeSlotPtr(enum_flag_HasDispatchMapSlot, c_DispatchMapSlotOffsets);
2151 *(DispatchMap **)pSlot = pDispatchMap;
2153 #endif // !DACCESS_COMPILE
2156 BOOL FindEncodedMapDispatchEntry(UINT32 typeID,
2158 DispatchMapEntry *pEntry);
2160 BOOL FindIntroducedImplementationTableDispatchEntry(UINT32 slotNumber,
2161 DispatchMapEntry *pEntry,
2162 BOOL fVirtualMethodsOnly);
2164 BOOL FindDispatchEntryForCurrentType(UINT32 typeID,
2166 DispatchMapEntry *pEntry);
2168 BOOL FindDispatchEntry(UINT32 typeID,
2170 DispatchMapEntry *pEntry);
2173 BOOL FindDispatchImpl(
2176 DispatchSlot * pImplSlot,
2177 BOOL throwOnConflict);
2180 #ifndef DACCESS_COMPILE
2181 BOOL FindDefaultInterfaceImplementation(
2182 MethodDesc *pInterfaceMD,
2183 MethodTable *pObjectMT,
2184 MethodDesc **ppDefaultMethod,
2185 FindDefaultInterfaceImplementationFlags findDefaultImplementationFlags,
2186 ClassLoadLevel level = CLASS_LOADED);
2187 #endif // DACCESS_COMPILE
2189 DispatchSlot FindDispatchSlot(UINT32 typeID, UINT32 slotNumber, BOOL throwOnConflict);
2191 // You must use the second of these two if there is any chance the pMD is a method
2192 // on a generic interface such as IComparable<T> (which it normally can be). The
2193 // ownerType is used to provide an exact qualification in the case the pMD is
2194 // a shared method descriptor.
2195 DispatchSlot FindDispatchSlotForInterfaceMD(MethodDesc *pMD, BOOL throwOnConflict);
2196 DispatchSlot FindDispatchSlotForInterfaceMD(TypeHandle ownerType, MethodDesc *pMD, BOOL throwOnConflict);
2198 MethodDesc *ReverseInterfaceMDLookup(UINT32 slotNumber);
2200 // Lookup, does not assign if not already done.
2201 UINT32 LookupTypeID();
2202 // Lookup, will assign ID if not already done.
2206 // Will return either the dispatch map type. May trigger type loader in order to get
2208 MethodTable *LookupDispatchMapType(DispatchMapTypeID typeID);
2209 bool DispatchMapTypeMatchesMethodTable(DispatchMapTypeID typeID, MethodTable* pMT);
2211 MethodDesc *GetIntroducingMethodDesc(DWORD slotNumber);
2213 // Determines whether all methods in the given interface have their final implementing
2214 // slot in a parent class. I.e. if this returns TRUE, it is trivial (no VSD lookup) to
2215 // dispatch pItfMT methods on this class if one knows how to dispatch them on pParentMT.
2216 BOOL ImplementsInterfaceWithSameSlotsAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
2218 // Determines whether all methods in the given interface have their final implementation
2219 // in a parent class. I.e. if this returns TRUE, this class behaves the same as pParentMT
2220 // when it comes to dispatching pItfMT methods.
2221 BOOL HasSameInterfaceImplementationAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
2223 // Try to resolve a given static virtual method override on this type. Return nullptr
2225 MethodDesc *TryResolveVirtualStaticMethodOnThisType(MethodTable* pInterfaceType, MethodDesc* pInterfaceMD, ResolveVirtualStaticMethodFlags resolveVirtualStaticMethodFlags, ClassLoadLevel level);
2228 static MethodDesc *MapMethodDeclToMethodImpl(MethodDesc *pMDDecl);
2230 //-------------------------------------------------------------------
2231 // FINALIZATION SEMANTICS
2234 DWORD CannotUseSuperFastHelper()
2236 WRAPPER_NO_CONTRACT;
2237 return HasFinalizer();
2240 void SetHasFinalizer()
2242 LIMITED_METHOD_CONTRACT;
2243 SetFlag(enum_flag_HasFinalizer);
2246 void SetHasCriticalFinalizer()
2248 LIMITED_METHOD_CONTRACT;
2249 SetFlag(enum_flag_HasCriticalFinalizer);
2251 // Does this class have non-trivial finalization requirements?
2252 DWORD HasFinalizer()
2254 LIMITED_METHOD_DAC_CONTRACT;
2255 return GetFlag(enum_flag_HasFinalizer);
2257 // Must this class be finalized during a rude appdomain unload, and
2258 // must it's finalizer run in a different order from normal finalizers?
2259 DWORD HasCriticalFinalizer() const
2261 LIMITED_METHOD_CONTRACT;
2262 return GetFlag(enum_flag_HasCriticalFinalizer);
2265 //-------------------------------------------------------------------
2269 DWORD GetOffsetOfFirstStaticHandle();
2270 DWORD GetOffsetOfFirstStaticMT();
2272 #ifndef DACCESS_COMPILE
2273 inline PTR_BYTE GetNonGCStaticsBasePointer();
2274 inline PTR_BYTE GetGCStaticsBasePointer();
2275 inline PTR_BYTE GetNonGCThreadStaticsBasePointer();
2276 inline PTR_BYTE GetGCThreadStaticsBasePointer();
2277 inline PTR_BYTE GetGCThreadStaticsBaseHandle();
2278 #endif //!DACCESS_COMPILE
2280 inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread);
2281 inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread);
2283 inline DWORD IsDynamicStatics()
2285 LIMITED_METHOD_DAC_CONTRACT;
2286 return !TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_NonDynamic);
2289 inline void SetDynamicStatics(BOOL fGeneric)
2291 LIMITED_METHOD_CONTRACT;
2292 SetFlag(fGeneric ? enum_flag_StaticsMask_Generics : enum_flag_StaticsMask_Dynamic);
2295 inline void SetHasBoxedRegularStatics()
2297 LIMITED_METHOD_CONTRACT;
2298 SetFlag(enum_flag_HasBoxedRegularStatics);
2301 inline DWORD HasBoxedRegularStatics()
2303 LIMITED_METHOD_CONTRACT;
2304 return GetFlag(enum_flag_HasBoxedRegularStatics);
2307 DWORD HasFixedAddressVTStatics();
2309 // Indicates if the MethodTable only contains abstract methods
2310 BOOL HasOnlyAbstractMethods();
2312 //-------------------------------------------------------------------
2313 // PER-INSTANTIATION STATICS INFO
2317 void SetupGenericsStaticsInfo(FieldDesc* pStaticFieldDescs);
2319 BOOL HasGenericsStaticsInfo()
2321 LIMITED_METHOD_DAC_CONTRACT;
2322 return GetFlag(enum_flag_StaticsMask_Generics);
2325 PTR_FieldDesc GetGenericsStaticFieldDescs()
2327 WRAPPER_NO_CONTRACT;
2328 _ASSERTE(HasGenericsStaticsInfo());
2329 return GetGenericsStaticsInfo()->m_pFieldDescs;
2332 BOOL HasCrossModuleGenericStaticsInfo()
2334 LIMITED_METHOD_DAC_CONTRACT;
2335 return TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_CrossModuleGenerics);
2338 PTR_Module GetGenericsStaticsModuleAndID(DWORD * pID);
2340 WORD GetNumHandleRegularStatics();
2342 WORD GetNumBoxedRegularStatics ();
2343 WORD GetNumBoxedThreadStatics ();
2345 //-------------------------------------------------------------------
2349 // Used for generics and reflection emit in memory
2350 DWORD GetModuleDynamicEntryID();
2351 Module* GetModuleForStatics();
2353 //-------------------------------------------------------------------
2354 // GENERICS DICT INFO
2357 // Number of generic arguments, whether this is a method table for
2358 // a generic type instantiation, e.g. List<string> or the "generic" MethodTable
2360 inline DWORD GetNumGenericArgs()
2362 LIMITED_METHOD_DAC_CONTRACT;
2363 if (HasInstantiation())
2364 return (DWORD) (GetGenericsDictInfo()->m_wNumTyPars);
2369 inline DWORD GetNumDicts()
2371 LIMITED_METHOD_DAC_CONTRACT;
2372 if (HasPerInstInfo())
2374 PTR_GenericsDictInfo pDictInfo = GetGenericsDictInfo();
2375 return (DWORD) (pDictInfo->m_wNumDicts);
2381 //-------------------------------------------------------------------
2385 OBJECTREF Allocate();
2387 // This flavor of Allocate is more efficient, but can only be used
2388 // if IsRestored(), CheckInstanceActivated(), IsClassInited() are known to be true.
2389 // A sufficient condition is that another instance of the exact same type already
2390 // exists in the same appdomain. It's currently called only from Delegate.Combine
2391 // via COMDelegate::InternalAllocLike.
2392 OBJECTREF AllocateNoChecks();
2394 OBJECTREF Box(void* data);
2395 OBJECTREF FastBox(void** data);
2396 #ifndef DACCESS_COMPILE
2397 BOOL UnBoxInto(void *dest, OBJECTREF src);
2398 void UnBoxIntoUnchecked(void *dest, OBJECTREF src);
2402 // Used for debugging class layout. Dumps to the debug console
2403 // when debug is true.
2404 void DebugDumpVtable(LPCUTF8 szClassName, BOOL fDebug);
2405 void Debug_DumpInterfaceMap(LPCSTR szInterfaceMapPrefix);
2406 void Debug_DumpDispatchMap();
2407 void DebugDumpFieldLayout(LPCUTF8 pszClassName, BOOL debug);
2408 void DebugRecursivelyDumpInstanceFields(LPCUTF8 pszClassName, BOOL debug);
2409 void DebugDumpGCDesc(LPCUTF8 pszClassName, BOOL debug);
2412 inline BOOL IsAgileAndFinalizable()
2414 LIMITED_METHOD_CONTRACT;
2415 // Right now, System.Thread is the only cases of this.
2416 // Things should stay this way - please don't change without talking to EE team.
2417 return this == g_pThreadClass;
2421 //-------------------------------------------------------------------
2422 // ENUMS, DELEGATES, VALUE TYPES, ARRAYS
2424 // #KindsOfElementTypes
2425 // GetInternalCorElementType() retrieves the internal representation of the type. It's not always
2426 // appropriate to use this. For example, we treat enums as their underlying type or some structs are
2427 // optimized to be ints. To get the signature type or the verifier type (same as signature except for
2428 // enums are normalized to the primitive type that underlies them), use the APIs in Typehandle.h
2430 // * code:TypeHandle.GetSignatureCorElementType()
2431 // * code:TypeHandle.GetVerifierCorElementType()
2432 // * code:TypeHandle.GetInternalCorElementType()
2433 CorElementType GetInternalCorElementType();
2434 void SetInternalCorElementType(CorElementType _NormType);
2436 // See code:TypeHandle::GetVerifierCorElementType for description
2437 CorElementType GetVerifierCorElementType();
2439 // See code:TypeHandle::GetSignatureCorElementType for description
2440 CorElementType GetSignatureCorElementType();
2442 // A true primitive is one who's GetVerifierCorElementType() ==
2445 // ELEMENT_TYPE_TYPEDBYREF etc.
2446 // Note that GetIntenalCorElementType might return these same values for some additional
2447 // types such as Enums and some structs.
2448 BOOL IsTruePrimitive();
2449 void SetIsTruePrimitive();
2451 // Is this delegate? Returns false for System.Delegate and System.MulticastDelegate.
2452 inline BOOL IsDelegate()
2454 LIMITED_METHOD_DAC_CONTRACT;
2455 // We do not allow single cast delegates anymore, just check for multicast delegate
2456 _ASSERTE(g_pMulticastDelegateClass);
2457 return ParentEquals(g_pMulticastDelegateClass);
2460 // Is this System.Object?
2461 inline BOOL IsObjectClass()
2463 LIMITED_METHOD_CONTRACT;
2464 _ASSERTE(g_pObjectClass);
2465 return (this == g_pObjectClass);
2468 // Is this System.ValueType?
2469 inline DWORD IsValueTypeClass()
2471 LIMITED_METHOD_CONTRACT;
2472 _ASSERTE(g_pValueTypeClass);
2473 return (this == g_pValueTypeClass);
2476 // Is this value type? Returns false for System.ValueType and System.Enum.
2477 inline BOOL IsValueType();
2479 // Is this enum? Returns false for System.Enum.
2480 inline BOOL IsEnum();
2482 // Is this array? Returns false for System.Array.
2483 inline BOOL IsArray()
2485 LIMITED_METHOD_DAC_CONTRACT;
2486 return GetFlag(enum_flag_Category_Array_Mask) == enum_flag_Category_Array;
2488 inline BOOL IsMultiDimArray()
2490 LIMITED_METHOD_DAC_CONTRACT;
2491 PRECONDITION(IsArray());
2492 return !GetFlag(enum_flag_Category_IfArrayThenSzArray);
2495 // Returns true if this type is Nullable<T> for some T.
2496 inline BOOL IsNullable()
2498 LIMITED_METHOD_DAC_CONTRACT;
2499 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Nullable;
2502 inline void SetIsNullable()
2504 LIMITED_METHOD_CONTRACT;
2505 _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType);
2506 SetFlag(enum_flag_Category_Nullable);
2509 // The following methods are only valid for the method tables for array types.
2510 CorElementType GetArrayElementType();
2513 TypeHandle GetArrayElementTypeHandle()
2515 LIMITED_METHOD_DAC_CONTRACT;
2516 _ASSERTE (IsArray());
2517 return TypeHandle::FromTAddr(m_ElementTypeHnd);
2520 void SetArrayElementTypeHandle(TypeHandle th)
2522 LIMITED_METHOD_DAC_CONTRACT;
2523 m_ElementTypeHnd = th.AsTAddr();
2526 TypeHandle * GetArrayElementTypeHandlePtr()
2528 LIMITED_METHOD_CONTRACT;
2529 return (TypeHandle *)&m_ElementTypeHnd;
2532 static inline DWORD GetOffsetOfArrayElementTypeHandle()
2534 LIMITED_METHOD_CONTRACT;
2535 return offsetof(MethodTable, m_ElementTypeHnd);
2538 //-------------------------------------------------------------------
2539 // UNDERLYING METADATA
2543 // Get the RID/token for the metadata for the corresponding type declaration
2544 unsigned GetTypeDefRid();
2546 inline mdTypeDef GetCl()
2548 LIMITED_METHOD_CONTRACT;
2549 return TokenFromRid(GetTypeDefRid(), mdtTypeDef);
2552 void SetCl(mdTypeDef token);
2555 // Make this smaller in debug builds to exercise the overflow codepath
2556 #define METHODTABLE_TOKEN_OVERFLOW 0xFFF
2558 #define METHODTABLE_TOKEN_OVERFLOW 0xFFFF
2561 BOOL HasTokenOverflow()
2563 LIMITED_METHOD_CONTRACT;
2564 return m_wToken == METHODTABLE_TOKEN_OVERFLOW;
2567 // Get the MD Import for the metadata for the corresponding type declaration
2568 IMDInternalImport* GetMDImport();
2570 HRESULT GetCustomAttribute(WellKnownAttribute attribute,
2571 const void **ppData,
2574 mdTypeDef GetEnclosingCl();
2576 CorNativeLinkType GetCharSet();
2578 #ifdef DACCESS_COMPILE
2579 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2582 //-------------------------------------------------------------------
2583 // DICTIONARIES FOR GENERIC INSTANTIATIONS
2585 // The PerInstInfo pointer is a pointer to per-instantiation pointer table,
2586 // each entry of which points to an instantiation "dictionary"
2587 // for an instantiated type; the last pointer points to a
2588 // dictionary which is specific to this method table, previous
2589 // entries point to dictionaries in superclasses. Instantiated interfaces and structs
2590 // have just single dictionary (no inheritance).
2592 // GetNumDicts() gives the number of dictionaries.
2594 //@nice GENERICS: instead of a separate table of pointers, put the pointers
2595 // in the vtable itself. Advantages:
2596 // * Time: we save an indirection as we don't need to go through PerInstInfo first.
2597 // * Space: no need for PerInstInfo (1 word)
2598 // Problem is that lots of code assumes that the vtable is filled
2599 // uniformly with pointers to MethodDesc stubs.
2601 // The dictionary for the method table is just an array of handles for
2602 // type parameters in the following cases:
2603 // * instantiated interfaces (no code)
2604 // * instantiated types whose code is not shared
2605 // Otherwise, it starts with the type parameters and then has a fixed
2606 // number of slots for handles (types & methods)
2607 // that are filled in lazily at run-time. Finally there is a "spill-bucket"
2608 // pointer used when the dictionary gets filled.
2610 // typar_1 type handle for first type parameter
2612 // typar_n type handle for last type parameter
2613 // slot_1 slot for first run-time handle (initially null)
2615 // slot_m slot for last run-time handle (initially null)
2616 // next_bucket pointer to spill bucket (possibly null)
2617 // The spill bucket contains just run-time handle slots.
2618 // (Alternative: continue chaining buckets.
2619 // Advantage: no need to deallocate when growing dictionaries.
2620 // Disadvantage: more indirections required at run-time.)
2622 // The layout of dictionaries is determined by GetClass()->GetDictionaryLayout()
2623 // Thus the layout can vary between incompatible instantiations. This is sometimes useful because individual type
2624 // parameters may or may not be shared. For example, consider a two parameter class Dict<K,D>. In instantiations shared with
2625 // Dict<double,string> any reference to K is known at JIT-compile-time (it's double) but any token containing D
2626 // must have a dictionary entry. On the other hand, for instantiations shared with Dict<string,double> the opposite holds.
2629 typedef PTR_Dictionary PerInstInfoElem_t;
2630 typedef DPTR(PerInstInfoElem_t) PerInstInfo_t;
2632 // Return a pointer to the per-instantiation information. See field itself for comments.
2633 DPTR(PerInstInfoElem_t) GetPerInstInfo()
2635 LIMITED_METHOD_DAC_CONTRACT;
2636 _ASSERTE(HasPerInstInfo());
2637 return m_pPerInstInfo;
2639 BOOL HasPerInstInfo()
2641 LIMITED_METHOD_DAC_CONTRACT;
2642 return GetFlag(enum_flag_HasPerInstInfo) && !IsArray();
2644 #ifndef DACCESS_COMPILE
2645 static inline DWORD GetOffsetOfPerInstInfo()
2647 LIMITED_METHOD_CONTRACT;
2648 return offsetof(MethodTable, m_pPerInstInfo);
2650 void SetPerInstInfo(PerInstInfoElem_t *pPerInstInfo)
2652 LIMITED_METHOD_CONTRACT;
2653 m_pPerInstInfo = pPerInstInfo;
2655 void SetDictInfo(WORD numDicts, WORD numTyPars)
2657 WRAPPER_NO_CONTRACT;
2658 GenericsDictInfo* pInfo = GetGenericsDictInfo();
2659 pInfo->m_wNumDicts = numDicts;
2660 pInfo->m_wNumTyPars = numTyPars;
2662 #endif // !DACCESS_COMPILE
2663 PTR_GenericsDictInfo GetGenericsDictInfo()
2665 LIMITED_METHOD_DAC_CONTRACT;
2666 // GenericsDictInfo is stored at negative offset of the dictionary
2667 return dac_cast<PTR_GenericsDictInfo>(GetPerInstInfo()) - 1;
2670 // Get a pointer to the dictionary for this instantiated type
2671 // (The instantiation is stored in the initial slots of the dictionary)
2672 // If not instantiated, return NULL
2673 PTR_Dictionary GetDictionary();
2675 // Return a substitution suitbale for interpreting
2676 // the metadata in parent class, assuming we already have a subst.
2677 // suitable for interpreting the current class.
2679 // If, for example, the definition for the current class is
2680 // D<T> : C<List<T>, T[] >
2681 // then this (for C<!0,!1>) will be
2684 // added to the chain of substitutions.
2686 // Subsequently, if the definition for C is
2687 // C<T, U> : B< Dictionary<T, U> >
2688 // then the next subst (for B<!0>) will be
2689 // 0 --> Dictionary< List<T>, T[] >
2691 Substitution GetSubstitutionForParent(const Substitution *pSubst);
2693 inline DWORD GetAttrClass();
2695 inline BOOL HasFieldsWhichMustBeInited();
2697 //-------------------------------------------------------------------
2698 // THE EXPOSED CLASS OBJECT
2701 * m_ExposedClassObject is a RuntimeType instance for this class. But
2702 * do NOT use it for Arrays or remoted objects! All arrays of objects
2703 * share the same MethodTable/EEClass.
2704 * @GENERICS: this is per-instantiation data
2706 // There are two version of GetManagedClassObject. The GetManagedClassObject()
2707 // method will get the class object. If it doesn't exist it will be created.
2708 // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist.
2709 OBJECTREF GetManagedClassObject();
2710 OBJECTREF GetManagedClassObjectIfExists();
2713 // ------------------------------------------------------------------
2714 // Private part of MethodTable
2715 // ------------------------------------------------------------------
2717 #ifndef DACCESS_COMPILE
2718 inline void SetWriteableData(PTR_MethodTableWriteableData pMTWriteableData)
2720 LIMITED_METHOD_CONTRACT;
2721 _ASSERTE(pMTWriteableData);
2722 m_pWriteableData = pMTWriteableData;
2726 inline PTR_Const_MethodTableWriteableData GetWriteableData() const
2728 LIMITED_METHOD_DAC_CONTRACT;
2729 return MethodTable::m_pWriteableData;
2732 inline PTR_MethodTableWriteableData GetWriteableDataForWrite()
2734 LIMITED_METHOD_DAC_CONTRACT;
2735 return MethodTable::m_pWriteableData;
2738 //-------------------------------------------------------------------
2740 // Used by COM interop to get GUIDs (IIDs and CLSIDs)
2742 // Get and cache the GUID for this interface/class
2743 HRESULT GetGuidNoThrow(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
2745 // Get and cache the GUID for this interface/class
2746 void GetGuid(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
2748 // Convenience method - determine if the interface/class has a guid specified (even if not yet cached)
2749 BOOL HasExplicitGuid();
2752 // Helper routines for the GetFullyQualifiedNameForClass macros defined at the top of class.h.
2753 // You probably should not use these functions directly.
2754 SString &_GetFullyQualifiedNameForClassNestedAware(SString &ssBuf);
2755 SString &_GetFullyQualifiedNameForClass(SString &ssBuf);
2756 LPCUTF8 GetFullyQualifiedNameInfo(LPCUTF8 *ppszNamespace);
2759 template<typename RedirectFunctor> SString &_GetFullyQualifiedNameForClassNestedAwareInternal(SString &ssBuf);
2762 //-------------------------------------------------------------------
2768 inline LPCUTF8 GetDebugClassName()
2770 LIMITED_METHOD_CONTRACT;
2771 return debug_m_szClassName;
2773 inline void SetDebugClassName(LPCUTF8 name)
2775 LIMITED_METHOD_CONTRACT;
2776 debug_m_szClassName = name;
2779 // Was the type created with injected duplicates?
2780 // TRUE means that we tried to inject duplicates (not that we found one to inject).
2781 inline BOOL Debug_HasInjectedInterfaceDuplicates() const
2783 LIMITED_METHOD_CONTRACT;
2784 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates) != 0;
2786 inline void Debug_SetHasInjectedInterfaceDuplicates()
2788 LIMITED_METHOD_CONTRACT;
2789 GetWriteableDataForWrite()->m_dwFlags |= MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates;
2794 #ifndef DACCESS_COMPILE
2796 //--------------------------------------------------------------------------------------
2800 inline ULONG AddRef()
2801 { LIMITED_METHOD_CONTRACT; return (ULONG) InterlockedIncrement((LONG*)&m_cRef); }
2805 // Since all methods that return a MethodData already AddRef'd, we do NOT
2806 // want to AddRef when putting a holder around it. We only want to release it.
2807 static void HolderAcquire(MethodData *pEntry)
2808 { LIMITED_METHOD_CONTRACT; return; }
2809 static void HolderRelease(MethodData *pEntry)
2810 { WRAPPER_NO_CONTRACT; if (pEntry != NULL) pEntry->Release(); }
2814 MethodTable *const m_pImplMT;
2815 MethodTable *const m_pDeclMT;
2818 MethodData(MethodTable *implMT, MethodTable *declMT) : m_cRef(1), m_pImplMT(implMT), m_pDeclMT(declMT) { LIMITED_METHOD_CONTRACT; }
2819 virtual ~MethodData() { LIMITED_METHOD_CONTRACT; }
2821 virtual MethodData *GetDeclMethodData() = 0;
2822 MethodTable *GetDeclMethodTable() { return m_pDeclMT; }
2823 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber) = 0;
2825 virtual MethodData *GetImplMethodData() = 0;
2826 MethodTable *GetImplMethodTable() { return m_pImplMT; }
2827 virtual DispatchSlot GetImplSlot(UINT32 slotNumber) = 0;
2828 // Returns INVALID_SLOT_NUMBER if no implementation exists.
2829 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber) = 0;
2830 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber) = 0;
2831 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber) = 0;
2833 virtual UINT32 GetNumVirtuals() = 0;
2834 virtual UINT32 GetNumMethods() = 0;
2836 virtual void UpdateImplMethodDesc(MethodDesc* pMD, UINT32 slotNumber) = 0;
2839 static const UINT32 INVALID_SLOT_NUMBER = UINT32_MAX;
2841 // This is used when building the data
2842 struct MethodDataEntry
2845 static const UINT32 INVALID_CHAIN_AND_INDEX = (UINT32)(-1);
2846 static const UINT16 INVALID_IMPL_SLOT_NUM = (UINT16)(-1);
2848 // This contains both the chain delta and the table index. The
2849 // reason that they are combined is that we need atomic update
2850 // of both, and it is convenient that both are on UINT16 in size.
2851 UINT32 m_chainDeltaAndTableIndex;
2852 UINT16 m_implSlotNum; // For virtually remapped slots
2853 DispatchSlot m_slot; // The entry in the DispatchImplTable
2854 MethodDesc *m_pMD; // The MethodDesc for this slot
2857 inline MethodDataEntry() : m_slot(NULL)
2858 { WRAPPER_NO_CONTRACT; Init(); }
2862 LIMITED_METHOD_CONTRACT;
2863 m_chainDeltaAndTableIndex = INVALID_CHAIN_AND_INDEX;
2864 m_implSlotNum = INVALID_IMPL_SLOT_NUM;
2869 inline BOOL IsDeclInit()
2870 { LIMITED_METHOD_CONTRACT; return m_chainDeltaAndTableIndex != INVALID_CHAIN_AND_INDEX; }
2871 inline BOOL IsImplInit()
2872 { LIMITED_METHOD_CONTRACT; return m_implSlotNum != INVALID_IMPL_SLOT_NUM; }
2874 inline void SetDeclData(UINT32 chainDelta, UINT32 tableIndex)
2875 { LIMITED_METHOD_CONTRACT; m_chainDeltaAndTableIndex = ((((UINT16) chainDelta) << 16) | ((UINT16) tableIndex)); }
2876 inline UINT32 GetChainDelta()
2877 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return m_chainDeltaAndTableIndex >> 16; }
2878 inline UINT32 GetTableIndex()
2879 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return (m_chainDeltaAndTableIndex & (UINT32)UINT16_MAX); }
2881 inline void SetImplData(UINT32 implSlotNum)
2882 { LIMITED_METHOD_CONTRACT; m_implSlotNum = (UINT16) implSlotNum; }
2883 inline UINT32 GetImplSlotNum()
2884 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsImplInit()); return m_implSlotNum; }
2886 inline void SetSlot(DispatchSlot slot)
2887 { LIMITED_METHOD_CONTRACT; m_slot = slot; }
2888 inline DispatchSlot GetSlot()
2889 { LIMITED_METHOD_CONTRACT; return m_slot; }
2891 inline void SetMethodDesc(MethodDesc *pMD)
2892 { LIMITED_METHOD_CONTRACT; m_pMD = pMD; }
2893 inline MethodDesc *GetMethodDesc()
2894 { LIMITED_METHOD_CONTRACT; return m_pMD; }
2898 static void ProcessMap(
2899 const DispatchMapTypeID * rgTypeIDs,
2902 UINT32 cCurrentChainDepth,
2903 MethodDataEntry * rgWorkingData,
2904 size_t cWorkingData);
2905 }; // class MethodData
2907 typedef ::Holder < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataHolder;
2908 typedef ::Wrapper < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataWrapper;
2911 //--------------------------------------------------------------------------------------
2912 class MethodDataObject final : public MethodData
2915 // Static method that returns the amount of memory to allocate for a particular type.
2916 static UINT32 GetObjectSize(MethodTable *pMT);
2918 // Constructor. Make sure you have allocated enough memory using GetObjectSize.
2919 inline MethodDataObject(MethodTable *pMT) : MethodData(pMT, pMT)
2920 { WRAPPER_NO_CONTRACT; Init(NULL); }
2922 inline MethodDataObject(MethodTable *pMT, MethodData *pParentData) : MethodData(pMT, pMT)
2923 { WRAPPER_NO_CONTRACT; Init(pParentData); }
2925 virtual ~MethodDataObject() { LIMITED_METHOD_CONTRACT; }
2927 virtual MethodData *GetDeclMethodData()
2928 { LIMITED_METHOD_CONTRACT; return this; }
2929 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
2931 virtual MethodData *GetImplMethodData()
2932 { LIMITED_METHOD_CONTRACT; return this; }
2933 virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
2934 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
2935 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
2936 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
2938 virtual UINT32 GetNumVirtuals()
2939 { LIMITED_METHOD_CONTRACT; return m_pDeclMT->GetNumVirtuals(); }
2940 virtual UINT32 GetNumMethods()
2941 { LIMITED_METHOD_CONTRACT; return m_pDeclMT->GetCanonicalMethodTable()->GetNumMethods(); }
2943 virtual void UpdateImplMethodDesc(MethodDesc* pMD, UINT32 slotNumber);
2946 void Init(MethodData *pParentData);
2948 BOOL PopulateNextLevel();
2950 // This is used in staged map decoding - it indicates which type we will next decode.
2951 UINT32 m_iNextChainDepth;
2952 static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
2954 BOOL m_containsMethodImpl;
2956 // NOTE: Use of these APIs are unlocked and may appear to be erroneous. However, since calls
2957 // to ProcessMap will result in identical values being placed in the MethodDataObjectEntry
2958 // array, it it is not a problem if there is a race, since one thread may just end up
2959 // doing some duplicate work.
2961 inline UINT32 GetNextChainDepth()
2962 { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
2964 inline void SetNextChainDepth(UINT32 iDepth)
2966 LIMITED_METHOD_CONTRACT;
2967 if (GetNextChainDepth() < iDepth) {
2968 VolatileStore(&m_iNextChainDepth, iDepth);
2972 // This is used when building the data
2973 struct MethodDataObjectEntry
2976 MethodDesc *m_pMDDecl;
2977 MethodDesc *m_pMDImpl;
2980 inline MethodDataObjectEntry() : m_pMDDecl(NULL), m_pMDImpl(NULL) {}
2982 inline void SetDeclMethodDesc(MethodDesc *pMD)
2983 { LIMITED_METHOD_CONTRACT; m_pMDDecl = pMD; }
2984 inline MethodDesc *GetDeclMethodDesc()
2985 { LIMITED_METHOD_CONTRACT; return m_pMDDecl; }
2986 inline void SetImplMethodDesc(MethodDesc *pMD)
2987 { LIMITED_METHOD_CONTRACT; m_pMDImpl = pMD; }
2988 inline MethodDesc *GetImplMethodDesc()
2989 { LIMITED_METHOD_CONTRACT; return m_pMDImpl; }
2993 inline MethodDataObjectEntry *GetEntryData()
2994 { LIMITED_METHOD_CONTRACT; return &m_rgEntries[0]; }
2996 inline MethodDataObjectEntry *GetEntry(UINT32 i)
2997 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
2999 void FillEntryDataForAncestor(MethodTable *pMT);
3002 // At the end of this object is an array
3004 MethodDataObjectEntry m_rgEntries[0];
3007 struct TargetMethodTable
3012 static void* operator new(size_t size, TargetMethodTable targetMT)
3014 _ASSERTE(size <= GetObjectSize(targetMT.pMT));
3015 return ::operator new(GetObjectSize(targetMT.pMT));
3017 static void* operator new(size_t size) = delete;
3018 }; // class MethodDataObject
3020 //--------------------------------------------------------------------------------------
3021 class MethodDataInterface : public MethodData
3024 // Static method that returns the amount of memory to allocate for a particular type.
3025 static UINT32 GetObjectSize(MethodTable *pMT)
3026 { LIMITED_METHOD_CONTRACT; return sizeof(MethodDataInterface); }
3028 // Constructor. Make sure you have allocated enough memory using GetObjectSize.
3029 MethodDataInterface(MethodTable *pMT) : MethodData(pMT, pMT)
3031 LIMITED_METHOD_CONTRACT;
3032 CONSISTENCY_CHECK(CheckPointer(pMT));
3033 CONSISTENCY_CHECK(pMT->IsInterface());
3035 virtual ~MethodDataInterface()
3036 { LIMITED_METHOD_CONTRACT; }
3041 virtual MethodData *GetDeclMethodData()
3042 { LIMITED_METHOD_CONTRACT; return this; }
3043 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
3048 virtual MethodData *GetImplMethodData()
3049 { LIMITED_METHOD_CONTRACT; return this; }
3050 virtual DispatchSlot GetImplSlot(UINT32 slotNumber)
3051 { WRAPPER_NO_CONTRACT; return DispatchSlot(m_pDeclMT->GetRestoredSlot(slotNumber)); }
3052 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber)
3053 { LIMITED_METHOD_CONTRACT; return slotNumber; }
3054 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3055 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3060 virtual UINT32 GetNumVirtuals()
3061 { LIMITED_METHOD_CONTRACT; return m_pDeclMT->GetNumVirtuals(); }
3062 virtual UINT32 GetNumMethods()
3063 { LIMITED_METHOD_CONTRACT; return m_pDeclMT->GetNumMethods(); }
3065 virtual void UpdateImplMethodDesc(MethodDesc* pMD, UINT32 slotNumber)
3066 { LIMITED_METHOD_CONTRACT; }
3068 }; // class MethodDataInterface
3070 //--------------------------------------------------------------------------------------
3071 class MethodDataInterfaceImpl final : public MethodData
3074 // Object construction-related methods
3075 static UINT32 GetObjectSize(MethodTable *pMTDecl);
3077 MethodDataInterfaceImpl(
3078 const DispatchMapTypeID * rgDeclTypeIDs,
3079 UINT32 cDeclTypeIDs,
3081 MethodData * pImpl);
3082 virtual ~MethodDataInterfaceImpl();
3084 // Decl-related methods
3085 virtual MethodData *GetDeclMethodData()
3086 { LIMITED_METHOD_CONTRACT; return m_pDecl; }
3087 virtual MethodTable *GetDeclMethodTable()
3088 { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodTable(); }
3089 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber)
3090 { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodDesc(slotNumber); }
3092 // Impl-related methods
3093 virtual MethodData *GetImplMethodData()
3094 { LIMITED_METHOD_CONTRACT; return m_pImpl; }
3095 virtual MethodTable *GetImplMethodTable()
3096 { WRAPPER_NO_CONTRACT; return m_pImpl->GetImplMethodTable(); }
3097 virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
3098 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
3099 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3100 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3102 virtual UINT32 GetNumVirtuals()
3103 { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
3104 virtual UINT32 GetNumMethods()
3105 { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
3107 virtual void UpdateImplMethodDesc(MethodDesc* pMD, UINT32 slotNumber)
3108 { LIMITED_METHOD_CONTRACT; }
3111 UINT32 MapToImplSlotNumber(UINT32 slotNumber);
3113 BOOL PopulateNextLevel();
3115 const DispatchMapTypeID * rgDeclTypeIDs,
3116 UINT32 cDeclTypeIDs,
3118 MethodData * pImpl);
3120 MethodData *m_pDecl;
3121 MethodData *m_pImpl;
3123 // This is used in staged map decoding - it indicates which type(s) we will find.
3124 const DispatchMapTypeID * m_rgDeclTypeIDs;
3125 UINT32 m_cDeclTypeIDs;
3126 UINT32 m_iNextChainDepth;
3127 static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
3129 inline UINT32 GetNextChainDepth()
3130 { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
3132 inline void SetNextChainDepth(UINT32 iDepth)
3134 LIMITED_METHOD_CONTRACT;
3135 if (GetNextChainDepth() < iDepth) {
3136 VolatileStore(&m_iNextChainDepth, iDepth);
3141 // At the end of this object is an array, so you cannot derive from this class.
3144 inline MethodDataEntry *GetEntryData()
3145 { LIMITED_METHOD_CONTRACT; return &m_rgEntries[0]; }
3147 inline MethodDataEntry *GetEntry(UINT32 i)
3148 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
3150 MethodDataEntry m_rgEntries[0];
3153 struct TargetMethodTable
3158 static void* operator new(size_t size, TargetMethodTable targetMT)
3160 _ASSERTE(size <= GetObjectSize(targetMT.pMT));
3161 return ::operator new(GetObjectSize(targetMT.pMT));
3163 static void* operator new(size_t size) = delete;
3164 }; // class MethodDataInterfaceImpl
3166 //--------------------------------------------------------------------------------------
3167 static MethodDataCache *s_pMethodDataCache;
3168 static BOOL s_fUseParentMethodData;
3169 static BOOL s_fUseMethodDataCache;
3172 static void AllowMethodDataCaching()
3173 { WRAPPER_NO_CONTRACT; CheckInitMethodDataCache(); s_fUseMethodDataCache = TRUE; }
3174 static void ClearMethodDataCache();
3175 static void AllowParentMethodDataCopy()
3176 { LIMITED_METHOD_CONTRACT; s_fUseParentMethodData = TRUE; }
3177 // NOTE: The fCanCache argument determines if the resulting MethodData object can
3178 // be added to the global MethodDataCache. This is used when requesting a
3179 // MethodData object for a type currently being built.
3180 static MethodData *GetMethodData(MethodTable *pMT, BOOL fCanCache = TRUE);
3181 static MethodData *GetMethodData(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache = TRUE);
3182 // This method is used by BuildMethodTable because the exact interface has not yet been loaded.
3183 // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
3184 static MethodData * GetMethodData(
3185 const DispatchMapTypeID * rgDeclTypeIDs,
3186 UINT32 cDeclTypeIDs,
3187 MethodTable * pMTDecl,
3188 MethodTable * pMTImpl);
3190 void CopySlotFrom(UINT32 slotNumber, MethodDataWrapper &hSourceMTData, MethodTable *pSourceMT);
3193 static void CheckInitMethodDataCache();
3194 static MethodData *FindParentMethodDataHelper(MethodTable *pMT);
3195 static MethodData *FindMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl);
3196 static MethodData *GetMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache);
3197 // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
3198 static MethodData * GetMethodDataHelper(
3199 const DispatchMapTypeID * rgDeclTypeIDs,
3200 UINT32 cDeclTypeIDs,
3201 MethodTable * pMTDecl,
3202 MethodTable * pMTImpl);
3205 //--------------------------------------------------------------------------------------
3206 class MethodIterator
3209 MethodIterator(MethodTable *pMT);
3210 MethodIterator(MethodTable *pMTDecl, MethodTable *pMTImpl);
3211 MethodIterator(MethodData *pMethodData);
3212 MethodIterator(const MethodIterator &it);
3213 inline ~MethodIterator() { WRAPPER_NO_CONTRACT; m_pMethodData->Release(); }
3214 INT32 GetNumMethods() const;
3215 inline BOOL IsValid() const;
3216 inline BOOL MoveTo(UINT32 idx);
3219 inline void MoveToBegin();
3220 inline void MoveToEnd();
3221 inline UINT32 GetSlotNumber() const;
3222 inline UINT32 GetImplSlotNumber() const;
3223 inline BOOL IsVirtual() const;
3224 inline UINT32 GetNumVirtuals() const;
3225 inline DispatchSlot GetTarget() const;
3227 // Can be called only if IsValid()=TRUE
3228 inline MethodDesc *GetMethodDesc() const;
3229 inline MethodDesc *GetDeclMethodDesc() const;
3232 void Init(MethodTable *pMTDecl, MethodTable *pMTImpl);
3234 MethodData *m_pMethodData;
3235 INT32 m_iCur; // Current logical slot index
3237 }; // class MethodIterator
3238 #endif // !DACCESS_COMPILE
3240 //--------------------------------------------------------------------------------------
3241 // This iterator lets you walk over all the method bodies introduced by this type.
3242 // This includes new static methods, new non-virtual methods, and any overrides
3243 // of the parent's virtual methods. It does not include virtual method implementations
3244 // provided by the parent
3246 class IntroducedMethodIterator
3249 IntroducedMethodIterator(MethodTable *pMT, BOOL restrictToCanonicalTypes = TRUE);
3250 inline BOOL IsValid() const;
3253 // Can be called only if IsValid()=TRUE
3254 inline MethodDesc *GetMethodDesc() const;
3256 // Static worker methods of the iterator. These are meant to be used
3257 // by RuntimeTypeHandle::GetFirstIntroducedMethod and RuntimeTypeHandle::GetNextIntroducedMethod
3258 // only to expose this iterator to managed code.
3259 static MethodDesc * GetFirst(MethodTable * pMT);
3260 static MethodDesc * GetNext(MethodDesc * pMD);
3263 MethodDesc *m_pMethodDesc; // Current method desc
3265 // Cached info about current method desc
3266 MethodDescChunk *m_pChunk;
3269 void SetChunk(MethodDescChunk * pChunk);
3270 }; // class IntroducedMethodIterator
3272 //-------------------------------------------------------------------
3273 // INSTANCE MEMBER VARIABLES
3276 #ifdef DACCESS_COMPILE
3281 enum WFLAGS_LOW_ENUM
3283 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
3284 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
3285 // CARRY THE CORECT FLAGS.
3288 // We are overloading the low 2 bytes of m_dwFlags to be a component size for Strings
3289 // and Arrays and some set of flags which we can be assured are of a specified state
3290 // for Strings / Arrays, currently these will be a bunch of generics flags which don't
3291 // apply to Strings / Arrays.
3293 enum_flag_UNUSED_ComponentSize_1 = 0x00000001,
3295 enum_flag_StaticsMask = 0x00000006,
3296 enum_flag_StaticsMask_NonDynamic = 0x00000000,
3297 enum_flag_StaticsMask_Dynamic = 0x00000002, // dynamic statics (EnC, reflection.emit)
3298 enum_flag_StaticsMask_Generics = 0x00000004, // generics statics
3299 enum_flag_StaticsMask_CrossModuleGenerics = 0x00000006, // cross module generics statics (NGen)
3300 enum_flag_StaticsMask_IfGenericsThenCrossModule = 0x00000002, // helper constant to get rid of unnecessary check
3302 enum_flag_NotInPZM = 0x00000008, // True if this type is not in its PreferredZapModule
3304 enum_flag_GenericsMask = 0x00000030,
3305 enum_flag_GenericsMask_NonGeneric = 0x00000000, // no instantiation
3306 enum_flag_GenericsMask_GenericInst = 0x00000010, // regular instantiation, e.g. List<String>
3307 enum_flag_GenericsMask_SharedInst = 0x00000020, // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
3308 enum_flag_GenericsMask_TypicalInst = 0x00000030, // the type instantiated at its formal parameters, e.g. List<T>
3310 enum_flag_HasVariance = 0x00000100, // This is an instantiated type some of whose type parameters are co- or contra-variant
3312 enum_flag_HasDefaultCtor = 0x00000200,
3313 enum_flag_HasPreciseInitCctors = 0x00000400, // Do we need to run class constructors at allocation time? (Not perf important, could be moved to EEClass
3315 #if defined(FEATURE_HFA)
3316 #if defined(UNIX_AMD64_ABI)
3317 #error "Can't define both FEATURE_HFA and UNIX_AMD64_ABI"
3319 enum_flag_IsHFA = 0x00000800, // This type is an HFA (Homogeneous Floating-point Aggregate)
3320 #endif // FEATURE_HFA
3322 #if defined(UNIX_AMD64_ABI)
3323 #if defined(FEATURE_HFA)
3324 #error "Can't define both FEATURE_HFA and UNIX_AMD64_ABI"
3326 enum_flag_IsRegStructPassed = 0x00000800, // This type is a System V register passed struct.
3327 #endif // UNIX_AMD64_ABI
3329 enum_flag_IsByRefLike = 0x00001000,
3331 // In a perfect world we would fill these flags using other flags that we already have
3332 // which have a constant value for something which has a component size.
3333 enum_flag_UNUSED_ComponentSize_5 = 0x00002000,
3334 enum_flag_UNUSED_ComponentSize_6 = 0x00004000,
3335 enum_flag_UNUSED_ComponentSize_7 = 0x00008000,
3337 #define SET_FALSE(flag) ((flag) & 0)
3338 #define SET_TRUE(flag) ((flag) & 0xffff)
3340 // IMPORTANT! IMPORTANT! IMPORTANT!
3342 // As you change the flags in WFLAGS_LOW_ENUM you also need to change this
3343 // to be up to date to reflect the default values of those flags for the
3344 // case where this MethodTable is for a String or Array
3345 enum_flag_StringArrayValues = SET_TRUE(enum_flag_StaticsMask_NonDynamic) |
3346 SET_FALSE(enum_flag_NotInPZM) |
3347 SET_TRUE(enum_flag_GenericsMask_NonGeneric) |
3348 SET_FALSE(enum_flag_HasVariance) |
3349 SET_FALSE(enum_flag_HasDefaultCtor) |
3350 SET_FALSE(enum_flag_HasPreciseInitCctors),
3352 }; // enum WFLAGS_LOW_ENUM
3354 enum WFLAGS_HIGH_ENUM
3356 // DO NOT use flags that have bits set in the low 2 bytes.
3357 // These flags are DWORD sized so that our atomic masking
3358 // operations can operate on the entire 4-byte aligned DWORD
3359 // instead of the logical non-aligned WORD of flags. The
3360 // low WORD of flags is reserved for the component size.
3362 // The following bits describe mutually exclusive locations of the type
3363 // in the type hierarchy.
3364 enum_flag_Category_Mask = 0x000F0000,
3366 enum_flag_Category_Class = 0x00000000,
3367 enum_flag_Category_Unused_1 = 0x00010000,
3368 enum_flag_Category_Unused_2 = 0x00020000,
3369 enum_flag_Category_Unused_3 = 0x00030000,
3371 enum_flag_Category_ValueType = 0x00040000,
3372 enum_flag_Category_ValueType_Mask = 0x000C0000,
3373 enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType
3374 enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or primitive value type
3375 enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.)
3377 enum_flag_Category_Array = 0x00080000,
3378 enum_flag_Category_Array_Mask = 0x000C0000,
3379 // enum_flag_Category_IfArrayThenUnused = 0x00010000, // sub-category of Array
3380 enum_flag_Category_IfArrayThenSzArray = 0x00020000, // sub-category of Array
3382 enum_flag_Category_Interface = 0x000C0000,
3383 enum_flag_Category_Unused_4 = 0x000D0000,
3384 enum_flag_Category_Unused_5 = 0x000E0000,
3385 enum_flag_Category_Unused_6 = 0x000F0000,
3387 enum_flag_Category_ElementTypeMask = 0x000E0000, // bits that matter for element type mask
3390 enum_flag_HasFinalizer = 0x00100000, // instances require finalization
3392 enum_flag_IDynamicInterfaceCastable = 0x00200000, // class implements IDynamicInterfaceCastable interface
3394 enum_flag_ICastable = 0x00400000, // class implements ICastable interface
3396 enum_flag_Unused_1 = 0x00800000,
3398 enum_flag_ContainsPointers = 0x01000000,
3400 enum_flag_HasTypeEquivalence = 0x02000000, // can be equivalent to another type
3402 enum_flag_IsTrackedReferenceWithFinalizer = 0x04000000,
3404 enum_flag_HasCriticalFinalizer = 0x08000000, // finalizer must be run on Appdomain Unload
3405 enum_flag_Collectible = 0x10000000,
3406 enum_flag_ContainsGenericVariables = 0x20000000, // we cache this flag to help detect these efficiently and
3407 // to detect this condition when restoring
3409 enum_flag_ComObject = 0x40000000, // class is a com object
3411 enum_flag_HasComponentSize = 0x80000000, // This is set if component size is used for flags.
3413 // Types that require non-trivial interface cast have this bit set in the category
3414 enum_flag_NonTrivialInterfaceCast = enum_flag_Category_Array
3415 | enum_flag_ComObject
3416 | enum_flag_ICastable
3417 | enum_flag_IDynamicInterfaceCastable
3418 | enum_flag_Category_ValueType
3420 }; // enum WFLAGS_HIGH_ENUM
3422 // NIDump needs to be able to see these flags
3423 // TODO: figure out how to make these private
3424 #if defined(DACCESS_COMPILE)
3431 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
3432 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
3433 // CARRY THE CORECT FLAGS.
3435 // The following bits describe usage of optional slots. They have to stay
3436 // together because of we index using them into offset arrays.
3437 enum_flag_MultipurposeSlotsMask = 0x001F,
3438 enum_flag_HasPerInstInfo = 0x0001,
3439 enum_flag_HasInterfaceMap = 0x0002,
3440 enum_flag_HasDispatchMapSlot = 0x0004,
3441 enum_flag_HasNonVirtualSlots = 0x0008,
3442 enum_flag_HasModuleOverride = 0x0010,
3447 enum_flag_HasModuleDependencies = 0x0080,
3449 enum_flag_IsIntrinsicType = 0x0100,
3453 enum_flag_HasCctor = 0x0400,
3454 enum_flag_HasVirtualStaticMethods = 0x0800,
3456 #ifdef FEATURE_64BIT_ALIGNMENT
3457 enum_flag_RequiresAlign8 = 0x1000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)
3460 enum_flag_HasBoxedRegularStatics = 0x2000, // GetNumBoxedRegularStatics() != 0
3462 enum_flag_HasSingleNonVirtualSlot = 0x4000,
3465 }; // enum WFLAGS2_ENUM
3467 __forceinline void ClearFlag(WFLAGS_LOW_ENUM flag)
3469 _ASSERTE(!IsStringOrArray());
3472 __forceinline void SetFlag(WFLAGS_LOW_ENUM flag)
3474 _ASSERTE(!IsStringOrArray());
3477 __forceinline DWORD GetFlag(WFLAGS_LOW_ENUM flag) const
3480 return (IsStringOrArray() ? (enum_flag_StringArrayValues & flag) : (m_dwFlags & flag));
3482 __forceinline BOOL TestFlagWithMask(WFLAGS_LOW_ENUM mask, WFLAGS_LOW_ENUM flag) const
3484 LIMITED_METHOD_DAC_CONTRACT;
3485 return (IsStringOrArray() ? (((DWORD)enum_flag_StringArrayValues & (DWORD)mask) == (DWORD)flag) :
3486 ((m_dwFlags & (DWORD)mask) == (DWORD)flag));
3489 __forceinline void ClearFlag(WFLAGS_HIGH_ENUM flag)
3493 __forceinline void SetFlag(WFLAGS_HIGH_ENUM flag)
3497 __forceinline DWORD GetFlag(WFLAGS_HIGH_ENUM flag) const
3499 LIMITED_METHOD_DAC_CONTRACT;
3500 return m_dwFlags & flag;
3502 __forceinline BOOL TestFlagWithMask(WFLAGS_HIGH_ENUM mask, WFLAGS_HIGH_ENUM flag) const
3504 LIMITED_METHOD_DAC_CONTRACT;
3505 return ((m_dwFlags & (DWORD)mask) == (DWORD)flag);
3508 __forceinline void ClearFlag(WFLAGS2_ENUM flag)
3512 __forceinline void SetFlag(WFLAGS2_ENUM flag)
3516 __forceinline DWORD GetFlag(WFLAGS2_ENUM flag) const
3518 LIMITED_METHOD_DAC_CONTRACT;
3519 return m_wFlags2 & flag;
3521 __forceinline BOOL TestFlagWithMask(WFLAGS2_ENUM mask, WFLAGS2_ENUM flag) const
3523 return (m_wFlags2 & (DWORD)mask) == (DWORD)flag;
3527 // Low WORD is component size for array and string types (HasComponentSize() returns true).
3528 // Used for flags otherwise.
3531 // Base size of instance of this class when allocated on the heap
3534 // See WFLAGS2_ENUM for values.
3537 // Class token if it fits into 16-bits. If this is (WORD)-1, the class token is stored in the TokenOverflow optional member.
3540 // <NICE> In the normal cases we shouldn't need a full word for each of these </NICE>
3541 WORD m_wNumVirtuals;
3542 WORD m_wNumInterfaces;
3545 LPCUTF8 debug_m_szClassName;
3548 PTR_MethodTable m_pParentMethodTable;
3550 PTR_Module m_pLoaderModule;
3552 PTR_MethodTableWriteableData m_pWriteableData;
3554 // The value of lowest two bits describe what the union contains
3556 UNION_EECLASS = 0, // 0 - pointer to EEClass. This MethodTable is the canonical method table.
3557 UNION_METHODTABLE = 1, // 1 - pointer to canonical MethodTable.
3559 static const TADDR UNION_MASK = 1;
3562 DPTR(EEClass) m_pEEClass;
3566 __forceinline static LowBits union_getLowBits(TADDR pCanonMT)
3568 LIMITED_METHOD_DAC_CONTRACT;
3569 return LowBits(pCanonMT & UNION_MASK);
3571 __forceinline static TADDR union_getPointer(TADDR pCanonMT)
3573 LIMITED_METHOD_DAC_CONTRACT;
3574 return (pCanonMT & ~UNION_MASK);
3577 // m_pPerInstInfo and m_pInterfaceMap have to be at fixed offsets because of performance sensitive
3578 // JITed code and JIT helpers. However, they are frequently not present. The space is used by other
3579 // multipurpose slots on first come first served basis if the fixed ones are not present. The other
3580 // multipurpose are DispatchMapSlot, NonVirtualSlots, ModuleOverride (see enum_flag_MultipurposeSlotsMask).
3581 // The multipurpose slots that do not fit are stored after vtable slots.
3585 PerInstInfo_t m_pPerInstInfo;
3586 TADDR m_ElementTypeHnd;
3587 TADDR m_pMultipurposeSlot1;
3592 PTR_InterfaceInfo m_pInterfaceMap;
3593 TADDR m_pMultipurposeSlot2;
3596 // VTable and Non-Virtual slots go here
3598 // Overflow multipurpose slots go here
3600 // Optional Members go here
3601 // See above for the list of optional members
3603 // Generic dictionary pointers go here
3605 // Interface map goes here
3607 // Generic instantiation+dictionary goes here
3611 // disallow direct creation
3612 void *operator new(size_t dummy);
3613 void operator delete(void *pData);
3616 // Optional members. These are used for fields in the data structure where
3617 // the fields are (a) known when MT is created and (b) there is a default
3618 // value for the field in the common case. That is, they are normally used
3619 // for data that is only relevant to a small number of method tables.
3621 // Optional members and multipurpose slots have similar purpose, but they differ in details:
3622 // - Multipurpose slots can only accommodate pointer sized structures right now. It is non-trivial
3623 // to add new ones, the access is faster.
3624 // - Optional members can accommodate structures of any size. It is trivial to add new ones,
3625 // the access is slower.
3627 // The following macro will automatically create GetXXX accessors for the optional members.
3628 #define METHODTABLE_OPTIONAL_MEMBERS() \
3629 /* NAME TYPE GETTER */ \
3630 /* Accessing this member efficiently is currently performance critical for static field accesses */ \
3631 /* in generic classes, so place it early in the list. */ \
3632 METHODTABLE_OPTIONAL_MEMBER(GenericsStaticsInfo, GenericsStaticsInfo, GetGenericsStaticsInfo ) \
3633 /* Accessed during x-domain transition only, so place it late in the list. */ \
3634 METHODTABLE_REMOTING_OPTIONAL_MEMBERS() \
3635 /* Accessed during certain generic type load operations only, so low priority */ \
3636 METHODTABLE_OPTIONAL_MEMBER(ExtraInterfaceInfo, TADDR, GetExtraInterfaceInfoPtr ) \
3637 /* TypeDef token for assemblies with more than 64k types. Never happens in real world. */ \
3638 METHODTABLE_OPTIONAL_MEMBER(TokenOverflow, TADDR, GetTokenOverflowPtr ) \
3640 #define METHODTABLE_REMOTING_OPTIONAL_MEMBERS()
3642 enum OptionalMemberId
3644 #undef METHODTABLE_OPTIONAL_MEMBER
3645 #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) OptionalMember_##NAME,
3646 METHODTABLE_OPTIONAL_MEMBERS()
3647 OptionalMember_Count,
3649 OptionalMember_First = OptionalMember_GenericsStaticsInfo,
3652 FORCEINLINE DWORD GetOffsetOfOptionalMember(OptionalMemberId id);
3657 // Public accessor helpers for the optional members of MethodTable
3660 #undef METHODTABLE_OPTIONAL_MEMBER
3661 #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \
3662 inline DPTR(TYPE) GETTER() \
3664 LIMITED_METHOD_CONTRACT; \
3665 _ASSERTE(Has##NAME()); \
3666 return dac_cast<DPTR(TYPE)>(dac_cast<TADDR>(this) + GetOffsetOfOptionalMember(OptionalMember_##NAME)); \
3669 METHODTABLE_OPTIONAL_MEMBERS()
3672 inline DWORD GetStartOffsetOfOptionalMembers()
3674 WRAPPER_NO_CONTRACT;
3675 return GetOffsetOfOptionalMember(OptionalMember_First);
3678 inline DWORD GetEndOffsetOfOptionalMembers()
3680 WRAPPER_NO_CONTRACT;
3681 return GetOffsetOfOptionalMember(OptionalMember_Count);
3684 inline static DWORD GetOptionalMembersAllocationSize(
3685 DWORD dwMultipurposeSlotsMask,
3686 BOOL needsGenericsStaticsInfo,
3687 BOOL needsTokenOverflow);
3688 inline DWORD GetOptionalMembersSize();
3690 // The PerInstInfo is a (possibly empty) array of pointers to
3691 // Instantiations/Dictionaries. This array comes after the optional members.
3692 inline DWORD GetPerInstInfoSize();
3694 // This is the size of the interface map chunk in the method table.
3695 // If the MethodTable has a dynamic interface map then the size includes the pointer
3696 // that stores the extra info for that map.
3697 // The interface map itself comes after the PerInstInfo (if any)
3698 inline DWORD GetInterfaceMapSize();
3700 // The instantiation/dictionary comes at the end of the MethodTable after
3701 // the interface map. This is the total number of bytes used by the dictionary.
3702 // The pSlotSize argument is used to return the size occupied by slots (not including
3703 // the optional back pointer used when expanding dictionaries).
3704 inline DWORD GetInstAndDictSize(DWORD *pSlotSize);
3707 // Helper template to compute the offsets at compile time
3709 struct MultipurposeSlotOffset;
3711 static const BYTE c_DispatchMapSlotOffsets[];
3712 static const BYTE c_NonVirtualSlotsOffsets[];
3713 static const BYTE c_ModuleOverrideOffsets[];
3715 static const BYTE c_OptionalMembersStartOffsets[]; // total sizes of optional slots
3717 TADDR GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const BYTE * offsets);
3719 void SetMultipurposeSlotsMask(DWORD dwMask)
3721 LIMITED_METHOD_CONTRACT;
3722 _ASSERTE((m_wFlags2 & enum_flag_MultipurposeSlotsMask) == 0);
3723 m_wFlags2 |= (WORD)dwMask;
3726 BOOL HasModuleOverride()
3728 LIMITED_METHOD_DAC_CONTRACT;
3729 return GetFlag(enum_flag_HasModuleOverride);
3732 DPTR(PTR_Module) GetModuleOverridePtr()
3734 LIMITED_METHOD_DAC_CONTRACT;
3735 return dac_cast<DPTR(PTR_Module)>(GetMultipurposeSlotPtr(enum_flag_HasModuleOverride, c_ModuleOverrideOffsets));
3738 void SetModule(Module * pModule);
3743 }; // class MethodTable
3745 #ifndef CROSSBITNESS_COMPILE
3746 static_assert_no_msg(sizeof(MethodTable) == SIZEOF__MethodTable_);
3748 #if defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
3749 WORD GetEquivalentMethodSlot(MethodTable * pOldMT, MethodTable * pNewMT, WORD wMTslot, BOOL *pfFound);
3750 #endif // defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
3752 MethodTable* CreateMinimalMethodTable(Module* pContainingModule,
3753 LoaderHeap* pCreationHeap,
3754 AllocMemTracker* pamTracker);
3756 #endif // !_METHODTABLE_H_