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 int GetLoongArch64PassStructInRegisterFlags(TypeHandle th);
774 #elif defined(TARGET_RISCV64)
775 static int GetRiscV64PassStructInRegisterFlags(TypeHandle th);
778 #if defined(UNIX_AMD64_ABI_ITF)
779 // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
780 bool ClassifyEightBytes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct, MethodTable** pByValueClassCache = NULL);
781 bool ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, EEClassNativeLayoutInfo const* nativeLayoutInfo);
782 #endif // defined(UNIX_AMD64_ABI_ITF)
784 // Copy m_dwFlags from another method table
785 void CopyFlags(MethodTable * pOldMT)
787 LIMITED_METHOD_CONTRACT;
788 m_dwFlags = pOldMT->m_dwFlags;
789 m_wFlags2 = pOldMT->m_wFlags2;
792 // Init the m_dwFlags field for an array
793 void SetIsArray(CorElementType arrayType);
795 BOOL IsClassPreInited();
797 // mark the class as having its cctor run.
798 #ifndef DACCESS_COMPILE
799 void SetClassInited();
800 BOOL IsClassInited();
803 void SetClassInitError();
806 inline BOOL IsGlobalClass()
809 return (GetTypeDefRid() == RidFromToken(COR_GLOBAL_PARENT_TOKEN));
812 // uniquely identifes this type in the Domain table
813 DWORD GetClassIndex();
817 #if defined(UNIX_AMD64_ABI_ITF)
818 void AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel) const;
819 // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
820 bool ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct, MethodTable** pByValueClassCache);
821 #endif // defined(UNIX_AMD64_ABI_ITF)
823 DWORD GetClassIndexFromToken(mdTypeDef typeToken)
825 LIMITED_METHOD_CONTRACT;
826 return RidFromToken(typeToken) - 1;
829 // called from CheckRunClassInitThrowing(). The type wasn't marked as
830 // inited while we were there, so let's attempt to do the work.
831 void DoRunClassInitThrowing();
833 BOOL RunClassInitEx(OBJECTREF *pThrowable);
836 //-------------------------------------------------------------------
837 // THE CLASS CONSTRUCTOR
840 MethodDesc * GetClassConstructor();
842 BOOL HasClassConstructor();
843 void SetHasClassConstructor();
844 WORD GetClassConstructorSlot();
846 void GetSavedExtent(TADDR *ppStart, TADDR *ppEnd);
848 //-------------------------------------------------------------------
849 // Save/Fixup/Restore/NeedsRestore
851 // Restore this method table if it's not already restored
852 // This is done by forcing a class load which in turn calls the Restore method
853 // The pending list is required for restoring types that reference themselves through
854 // instantiations of the superclass or interfaces e.g. System.Int32 : IComparable<System.Int32>
856 void AllocateRegularStaticBoxes();
857 void AllocateRegularStaticBox(FieldDesc* pField, Object** boxedStaticHandle);
858 static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0, bool canBeFrozen = false);
862 inline BOOL HasUnrestoredTypeKey() const
864 LIMITED_METHOD_DAC_CONTRACT;
866 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey) != 0;
869 // Actually do the restore actions on the method table
872 void SetIsRestored();
874 inline BOOL IsRestored()
876 LIMITED_METHOD_DAC_CONTRACT;
878 return !(GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
881 //-------------------------------------------------------------------
884 // The load level of a method table is derived from various flag bits
885 // See classloadlevel.h for details of each level
887 // Level CLASS_LOADED (fully loaded) is special: a type only
888 // reaches this level once all of its dependent types are also at
889 // this level (generic arguments, parent, interfaces, etc).
890 // Fully loading a type to this level is done outside locks, hence the need for
891 // a single atomic action that sets the level.
893 inline void SetIsFullyLoaded()
903 PRECONDITION(!HasApproxParent());
904 PRECONDITION(IsRestored());
906 InterlockedAnd((LONG*)&GetWriteableDataForWrite()->m_dwFlags, ~MethodTableWriteableData::enum_flag_IsNotFullyLoaded);
909 // Equivalent to GetLoadLevel() == CLASS_LOADED
910 inline BOOL IsFullyLoaded()
914 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded) == 0;
917 inline BOOL CanCompareBitsOrUseFastGetHashCode()
919 LIMITED_METHOD_CONTRACT;
920 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode);
923 // If canCompare is true, this method ensure an atomic operation for setting
924 // enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode and enum_flag_CanCompareBitsOrUseFastGetHashCode flags.
925 inline void SetCanCompareBitsOrUseFastGetHashCode(BOOL canCompare)
930 // Set checked and canCompare flags in one interlocked operation.
931 InterlockedOr((LONG*)&GetWriteableDataForWrite()->m_dwFlags,
932 MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode | MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode);
936 SetHasCheckedCanCompareBitsOrUseFastGetHashCode();
940 inline BOOL HasCheckedCanCompareBitsOrUseFastGetHashCode()
942 LIMITED_METHOD_CONTRACT;
943 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode);
946 inline void SetHasCheckedCanCompareBitsOrUseFastGetHashCode()
949 InterlockedOr((LONG*)&GetWriteableDataForWrite()->m_dwFlags, MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode);
952 inline void SetIsDependenciesLoaded()
962 PRECONDITION(!HasApproxParent());
963 PRECONDITION(IsRestored());
965 InterlockedOr((LONG*)&GetWriteableDataForWrite()->m_dwFlags, MethodTableWriteableData::enum_flag_DependenciesLoaded);
968 inline ClassLoadLevel GetLoadLevel()
970 LIMITED_METHOD_DAC_CONTRACT;
972 DWORD dwFlags = GetWriteableData()->m_dwFlags;
974 if (dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded)
976 if (dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey)
977 return CLASS_LOAD_UNRESTOREDTYPEKEY;
979 if (dwFlags & MethodTableWriteableData::enum_flag_Unrestored)
980 return CLASS_LOAD_UNRESTORED;
982 if (dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent)
983 return CLASS_LOAD_APPROXPARENTS;
985 if (!(dwFlags & MethodTableWriteableData::enum_flag_DependenciesLoaded))
986 return CLASS_LOAD_EXACTPARENTS;
988 return CLASS_DEPENDENCIES_LOADED;
995 CHECK CheckLoadLevel(ClassLoadLevel level)
997 LIMITED_METHOD_CONTRACT;
998 return TypeHandle(this).CheckLoadLevel(level);
1003 void DoFullyLoad(Generics::RecursionGraph * const pVisited, const ClassLoadLevel level, DFLPendingList * const pPending, BOOL * const pfBailed,
1004 const InstantiationContext * const pInstContext);
1006 //-------------------------------------------------------------------
1007 // METHOD TABLES AS TYPE DESCRIPTORS
1009 // A MethodTable can represeent a type such as "String" or an
1010 // instantiated type such as "List<String>".
1013 inline BOOL IsInterface()
1015 LIMITED_METHOD_DAC_CONTRACT;
1016 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Interface;
1019 void SetIsInterface()
1021 LIMITED_METHOD_CONTRACT;
1023 _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
1024 SetFlag(enum_flag_Category_Interface);
1027 inline BOOL IsSealed();
1029 inline BOOL IsAbstract();
1031 BOOL IsExternallyVisible();
1033 // Get the instantiation for this instantiated type e.g. for Dict<string,int>
1034 // this would be an array {string,int}
1035 // If not instantiated, return NULL
1036 Instantiation GetInstantiation();
1038 // Get the instantiation for an instantiated type or a pointer to the
1039 // element type for an array
1040 Instantiation GetClassOrArrayInstantiation();
1041 Instantiation GetArrayInstantiation();
1043 // Does this method table require that additional modules be loaded?
1044 inline BOOL HasModuleDependencies()
1046 LIMITED_METHOD_CONTRACT;
1047 return GetFlag(enum_flag_HasModuleDependencies);
1050 inline void SetHasModuleDependencies()
1052 SetFlag(enum_flag_HasModuleDependencies);
1055 inline BOOL IsIntrinsicType()
1057 LIMITED_METHOD_DAC_CONTRACT;;
1058 return GetFlag(enum_flag_IsIntrinsicType);
1061 inline void SetIsIntrinsicType()
1063 LIMITED_METHOD_DAC_CONTRACT;;
1064 SetFlag(enum_flag_IsIntrinsicType);
1067 // Is this a method table for a generic type instantiation, e.g. List<string>?
1068 inline BOOL HasInstantiation();
1070 // Returns true for any class which is either itself a generic
1071 // instantiation or is derived from a generic
1072 // instantiation anywhere in it's class hierarchy,
1074 // e.g. class D : C<int>
1075 // or class E : D, class D : C<int>
1077 // Does not return true just because the class supports
1078 // an instantiated interface type.
1079 BOOL HasGenericClassInstantiationInHierarchy()
1081 WRAPPER_NO_CONTRACT;
1082 return GetNumDicts() != 0;
1085 // Is this an instantiation of a generic class at its formal
1086 // type parameters ie. List<T> ?
1087 inline BOOL IsGenericTypeDefinition();
1089 BOOL ContainsGenericMethodVariables();
1091 // When creating an interface map, under some circumstances the
1092 // runtime will place the special marker type in the interface map instead
1093 // of the fully loaded type. This is to reduce the amount of type loading
1094 // performed at process startup.
1096 // The current rule is that these interfaces can only appear
1097 // on valuetypes that are not shared generic, and that the special
1098 // marker type is the open generic type.
1100 inline bool IsSpecialMarkerTypeForGenericCasting()
1102 return IsGenericTypeDefinition();
1105 static const DWORD MaxGenericParametersForSpecialMarkerType = 8;
1107 static BOOL ComputeContainsGenericVariables(Instantiation inst);
1109 inline void SetContainsGenericVariables()
1111 LIMITED_METHOD_CONTRACT;
1112 SetFlag(enum_flag_ContainsGenericVariables);
1115 inline void SetHasVariance()
1117 LIMITED_METHOD_CONTRACT;
1118 SetFlag(enum_flag_HasVariance);
1121 inline BOOL HasVariance()
1123 LIMITED_METHOD_CONTRACT;
1124 return GetFlag(enum_flag_HasVariance);
1127 // Is this something like List<T> or List<Stack<T>>?
1128 // List<Blah<T>> only exists for reflection and verification.
1129 inline DWORD ContainsGenericVariables(BOOL methodVarsOnly = FALSE)
1131 WRAPPER_NO_CONTRACT;
1134 return ContainsGenericMethodVariables();
1136 return GetFlag(enum_flag_ContainsGenericVariables);
1141 LIMITED_METHOD_DAC_CONTRACT;;
1142 return GetFlag(enum_flag_IsByRefLike);
1145 void SetIsByRefLike()
1147 LIMITED_METHOD_CONTRACT;
1148 SetFlag(enum_flag_IsByRefLike);
1151 // class is a com object class
1152 Module* GetDefiningModuleForOpenType();
1154 inline BOOL IsTypicalTypeDefinition()
1156 LIMITED_METHOD_CONTRACT;
1157 return !HasInstantiation() || IsGenericTypeDefinition();
1160 BOOL HasSameTypeDefAs(MethodTable *pMT);
1162 //-------------------------------------------------------------------
1163 // GENERICS & CODE SHARING
1166 BOOL IsSharedByGenericInstantiations();
1168 // If this is a "representative" generic MT or a non-generic (regular) MT return true
1169 inline BOOL IsCanonicalMethodTable();
1171 // Return the canonical representative MT amongst the set of MT's that share
1172 // code with the given MT because of generics.
1173 PTR_MethodTable GetCanonicalMethodTable();
1175 //-------------------------------------------------------------------
1176 // Accessing methods by slot number
1178 // Some of these functions are also currently used to get non-virtual
1179 // methods, relying on the assumption that they are contiguous. This
1180 // is not true for non-virtual methods in generic instantiations, which
1181 // only live on the canonical method table.
1185 NO_SLOT = 0xffff // a unique slot number used to indicate "empty" for fields that record slot numbers
1188 PCODE GetSlot(UINT32 slotNumber)
1190 WRAPPER_NO_CONTRACT;
1191 CONSISTENCY_CHECK(slotNumber < GetNumVtableSlots());
1193 return *GetSlotPtrRaw(slotNumber);
1196 // Special-case for when we know that the slot number corresponds
1197 // to a virtual method.
1198 inline PCODE GetSlotForVirtual(UINT32 slotNum)
1200 LIMITED_METHOD_CONTRACT;
1202 CONSISTENCY_CHECK(slotNum < GetNumVirtuals());
1203 // Virtual slots live in chunks pointed to by vtable indirections
1204 return *(GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum));
1207 PTR_PCODE GetSlotPtrRaw(UINT32 slotNum)
1209 WRAPPER_NO_CONTRACT;
1210 CONSISTENCY_CHECK(slotNum < GetNumVtableSlots());
1212 if (slotNum < GetNumVirtuals())
1214 // Virtual slots live in chunks pointed to by vtable indirections
1215 return GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum);
1217 else if (HasSingleNonVirtualSlot())
1219 // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member,
1220 // except when there is only one in which case it lives in the optional member itself
1221 _ASSERTE(slotNum == GetNumVirtuals());
1222 return dac_cast<PTR_PCODE>(GetNonVirtualSlotsPtr());
1226 // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member
1227 _ASSERTE(HasNonVirtualSlotsArray());
1228 return GetNonVirtualSlotsArray() + (slotNum - GetNumVirtuals());
1232 PTR_PCODE GetSlotPtr(UINT32 slotNum)
1234 WRAPPER_NO_CONTRACT;
1235 return GetSlotPtrRaw(slotNum);
1238 void SetSlot(UINT32 slotNum, PCODE slotVal);
1240 //-------------------------------------------------------------------
1243 // Rather than the traditional array of code pointers (or "slots") we use a two-level vtable in
1244 // which slots for virtual methods live in chunks. Doing so allows the chunks to be shared among
1245 // method tables (the most common example being between parent and child classes where the child
1246 // does not override any method in the chunk). This yields substantial space savings at the fixed
1247 // cost of one additional indirection for a virtual call.
1249 // Note that none of this should be visible outside the implementation of MethodTable; all other
1250 // code continues to refer to a virtual method via the traditional slot number. This is similar to
1251 // how we refer to non-virtual methods as having a slot number despite having long ago moved their
1252 // code pointers out of the vtable.
1254 // Consider a class where GetNumVirtuals is 5 and (for the sake of the example) assume we break
1255 // the vtable into chunks of size 3. The layout would be as follows:
1257 // pMT chunk 1 chunk 2
1258 // ------------------ ------------------ ------------------
1259 // | | | M1() | | M4() |
1260 // | fixed-size | ------------------ ------------------
1261 // | portion of | | M2() | | M5() |
1262 // | MethodTable | ------------------ ------------------
1264 // ------------------ ------------------
1265 // | ptr to chunk 1 |
1266 // ------------------
1267 // | ptr to chunk 2 |
1268 // ------------------
1270 // We refer to "ptr to chunk 1" and "ptr to chunk 2" as "indirection slots."
1272 // The current chunking strategy is independent of class properties; all are of size 8. Several
1273 // other strategies were tried, and the only one that has performed better empirically is to begin
1274 // with a single chunk of size 4 (matching the number of virtuals in System.Object) and then
1275 // continue with chunks of size 8. However it was a small improvement and required the run-time
1276 // helpers listed below to be measurably slower.
1278 // If you want to change this, you should only need to modify the first four functions below
1279 // along with any assembly helper that has taken a dependency on the layout. Currently,
1280 // those consist of:
1281 // JIT_IsInstanceOfInterface
1282 // JIT_ChkCastInterface
1283 // Transparent proxy stub
1285 // This layout only applies to the virtual methods in a class (those with slot number below GetNumVirtuals).
1286 // Non-virtual methods that are in the vtable (those with slot numbers between GetNumVirtuals and
1287 // GetNumVtableSlots) are laid out in a single chunk pointed to by an optional member.
1288 // See GetSlotPtrRaw for more details.
1290 #define VTABLE_SLOTS_PER_CHUNK 8
1291 #define VTABLE_SLOTS_PER_CHUNK_LOG2 3
1293 typedef PCODE VTableIndir2_t;
1294 typedef DPTR(VTableIndir2_t) VTableIndir_t;
1296 static DWORD GetIndexOfVtableIndirection(DWORD slotNum);
1297 static DWORD GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
1298 static DWORD GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
1299 static UINT32 GetIndexAfterVtableIndirection(UINT32 slotNum);
1300 static DWORD GetNumVtableIndirections(DWORD wNumVirtuals);
1301 DPTR(VTableIndir_t) GetVtableIndirections();
1302 DWORD GetNumVtableIndirections();
1304 class VtableIndirectionSlotIterator
1306 friend class MethodTable;
1309 DPTR(VTableIndir_t) m_pSlot;
1312 PTR_MethodTable m_pMT;
1314 VtableIndirectionSlotIterator(MethodTable *pMT);
1315 VtableIndirectionSlotIterator(MethodTable *pMT, DWORD index);
1321 DWORD GetOffsetFromMethodTable();
1322 DPTR(VTableIndir2_t) GetIndirectionSlot();
1324 #ifndef DACCESS_COMPILE
1325 void SetIndirectionSlot(DPTR(VTableIndir2_t) pChunk);
1328 DWORD GetStartSlot();
1330 DWORD GetNumSlots();
1332 }; // class VtableIndirectionSlotIterator
1334 VtableIndirectionSlotIterator IterateVtableIndirectionSlots();
1335 VtableIndirectionSlotIterator IterateVtableIndirectionSlotsFrom(DWORD index);
1337 inline BOOL HasNonVirtualSlots()
1339 LIMITED_METHOD_DAC_CONTRACT;
1340 return GetFlag(enum_flag_HasNonVirtualSlots);
1343 inline BOOL HasSingleNonVirtualSlot()
1345 LIMITED_METHOD_DAC_CONTRACT;
1346 return GetFlag(enum_flag_HasSingleNonVirtualSlot);
1349 inline BOOL HasNonVirtualSlotsArray()
1351 LIMITED_METHOD_DAC_CONTRACT;
1352 return HasNonVirtualSlots() && !HasSingleNonVirtualSlot();
1355 TADDR GetNonVirtualSlotsPtr();
1357 inline PTR_PCODE GetNonVirtualSlotsArray()
1359 LIMITED_METHOD_DAC_CONTRACT;
1360 _ASSERTE(HasNonVirtualSlotsArray());
1361 return *dac_cast<PTR_PTR_PCODE>(GetNonVirtualSlotsPtr());
1364 #ifndef DACCESS_COMPILE
1365 inline void SetNonVirtualSlotsArray(PCODE *slots)
1367 LIMITED_METHOD_CONTRACT;
1368 _ASSERTE(HasNonVirtualSlotsArray());
1370 *(PCODE **)GetNonVirtualSlotsPtr() = slots;
1373 inline void SetHasSingleNonVirtualSlot()
1375 LIMITED_METHOD_CONTRACT;
1376 SetFlag(enum_flag_HasSingleNonVirtualSlot);
1380 inline unsigned GetNonVirtualSlotsArraySize()
1382 LIMITED_METHOD_DAC_CONTRACT;
1383 return GetNumNonVirtualSlots() * sizeof(PCODE);
1386 inline WORD GetNumNonVirtualSlots();
1388 inline BOOL HasVirtualStaticMethods() const;
1389 inline void SetHasVirtualStaticMethods();
1391 void VerifyThatAllVirtualStaticMethodsAreImplemented();
1393 inline WORD GetNumVirtuals()
1395 LIMITED_METHOD_DAC_CONTRACT;
1397 return m_wNumVirtuals;
1400 inline void SetNumVirtuals (WORD wNumVtableSlots)
1402 LIMITED_METHOD_CONTRACT;
1403 m_wNumVirtuals = wNumVtableSlots;
1406 unsigned GetNumParentVirtuals()
1408 LIMITED_METHOD_CONTRACT;
1409 if (IsInterface()) {
1412 MethodTable *pMTParent = GetParentMethodTable();
1413 return pMTParent == NULL ? 0 : pMTParent->GetNumVirtuals();
1416 #define SIZEOF__MethodTable_ (0x10 + (6 INDEBUG(+1)) * TARGET_POINTER_SIZE)
1418 static inline DWORD GetVtableOffset()
1420 LIMITED_METHOD_DAC_CONTRACT;
1422 return SIZEOF__MethodTable_;
1425 // Return total methods: virtual, static, and instance method slots.
1426 WORD GetNumMethods();
1428 // Return number of slots in this methodtable. This is just an information about the layout of the methodtable, it should not be used
1429 // for functionality checks. Do not confuse with GetNumVirtuals()!
1430 WORD GetNumVtableSlots()
1432 LIMITED_METHOD_DAC_CONTRACT;
1433 return GetNumVirtuals() + GetNumNonVirtualSlots();
1436 //-------------------------------------------------------------------
1437 // Slots <-> the MethodDesc associated with the slot.
1440 MethodDesc* GetMethodDescForSlot(DWORD slot);
1442 static MethodDesc* GetMethodDescForSlotAddress(PCODE addr, BOOL fSpeculative = FALSE);
1444 PCODE GetRestoredSlot(DWORD slot);
1446 // Returns MethodTable that GetRestoredSlot get its values from
1447 MethodTable * GetRestoredSlotMT(DWORD slot);
1449 // Used to map methods on the same slot between instantiations.
1450 MethodDesc * GetParallelMethodDesc(MethodDesc * pDefMD);
1452 //-------------------------------------------------------------------
1453 // BoxedEntryPoint MethodDescs.
1455 // Virtual methods on structs have BoxedEntryPoint method descs in their vtable.
1456 // See also notes for MethodDesc::FindOrCreateAssociatedMethodDesc. You should
1457 // probably be using that function if you need to map between unboxing
1458 // stubs and non-unboxing stubs.
1460 MethodDesc* GetBoxedEntryPointMD(MethodDesc *pMD);
1462 MethodDesc* GetUnboxedEntryPointMD(MethodDesc *pMD);
1463 MethodDesc* GetExistingUnboxedEntryPointMD(MethodDesc *pMD);
1465 //-------------------------------------------------------------------
1466 // FIELD LAYOUT, OBJECT SIZE ETC.
1469 inline BOOL HasLayout();
1471 inline EEClassLayoutInfo* GetLayoutInfo();
1473 EEClassNativeLayoutInfo const* GetNativeLayoutInfo();
1475 EEClassNativeLayoutInfo const* EnsureNativeLayoutInfoInitialized();
1477 inline BOOL IsBlittable();
1479 inline BOOL IsManagedSequential();
1481 inline BOOL HasExplicitSize();
1483 inline BOOL IsAutoLayoutOrHasAutoLayoutField();
1485 // Only accurate on types which are not auto layout
1486 inline BOOL IsInt128OrHasInt128Fields();
1488 UINT32 GetNativeSize();
1492 LIMITED_METHOD_DAC_CONTRACT;
1496 void SetBaseSize(DWORD baseSize)
1498 LIMITED_METHOD_CONTRACT;
1499 m_BaseSize = baseSize;
1502 BOOL IsStringOrArray() const
1504 LIMITED_METHOD_DAC_CONTRACT;
1505 return HasComponentSize();
1510 LIMITED_METHOD_DAC_CONTRACT;
1511 return HasComponentSize() && !IsArray() && RawGetComponentSize() == 2;
1514 BOOL HasComponentSize() const
1516 LIMITED_METHOD_DAC_CONTRACT;
1517 return GetFlag(enum_flag_HasComponentSize);
1520 // returns random combination of flags if this doesn't have a component size
1521 WORD RawGetComponentSize()
1523 LIMITED_METHOD_DAC_CONTRACT;
1525 return *((WORD*)&m_dwFlags + 1);
1527 return *(WORD*)&m_dwFlags;
1528 #endif // !BIGENDIAN
1531 // returns 0 if this doesn't have a component size
1533 // The component size is actually 16-bit WORD, but this method is returning SIZE_T to ensure
1534 // that SIZE_T is used everywhere for object size computation. It is necessary to support
1535 // objects bigger than 2GB.
1536 SIZE_T GetComponentSize()
1538 LIMITED_METHOD_DAC_CONTRACT;
1539 return HasComponentSize() ? RawGetComponentSize() : 0;
1542 void SetComponentSize(WORD wComponentSize)
1544 LIMITED_METHOD_CONTRACT;
1545 // it would be nice to assert here that this is either a string
1546 // or an array, but how do we know.
1548 // it would also be nice to assert that the component size is > 0,
1549 // but that would not hold for array's of System.Void and generic type parameters
1550 SetFlag(enum_flag_HasComponentSize);
1551 m_dwFlags = (m_dwFlags & ~0xFFFF) | wComponentSize;
1554 inline WORD GetNumInstanceFields();
1556 inline WORD GetNumStaticFields();
1558 inline WORD GetNumThreadStaticFields();
1560 // Note that for value types GetBaseSize returns the size of instance fields for
1561 // a boxed value, and GetNumInstanceFieldsBytes for an unboxed value.
1562 // We place methods like these on MethodTable primarily so we can choose to cache
1563 // the information within MethodTable, and so less code manipulates EEClass
1564 // objects directly, because doing so can lead to bugs related to generics.
1566 // <TODO> Use m_wBaseSize whenever this is identical to GetNumInstanceFieldBytes.
1567 // We would need to reserve a flag for this. </TODO>
1569 inline DWORD GetNumInstanceFieldBytes();
1571 int GetFieldAlignmentRequirement();
1573 inline WORD GetNumIntroducedInstanceFields();
1575 // Note: This flag MUST be available even from an unrestored MethodTable - see GcScanRoots in siginfo.cpp.
1576 DWORD ContainsPointers()
1578 LIMITED_METHOD_CONTRACT;
1579 return GetFlag(enum_flag_ContainsPointers);
1584 LIMITED_METHOD_CONTRACT;
1585 #ifdef FEATURE_COLLECTIBLE_TYPES
1586 return GetFlag(enum_flag_Collectible);
1592 BOOL ContainsPointersOrCollectible()
1594 LIMITED_METHOD_CONTRACT;
1595 return GetFlag(enum_flag_ContainsPointers) || GetFlag(enum_flag_Collectible);
1598 OBJECTHANDLE GetLoaderAllocatorObjectHandle();
1599 NOINLINE BYTE *GetLoaderAllocatorObjectForGC();
1601 BOOL IsNotTightlyPacked();
1603 BOOL IsAllGCPointers();
1605 void SetContainsPointers()
1607 LIMITED_METHOD_CONTRACT;
1608 SetFlag(enum_flag_ContainsPointers);
1611 #ifdef FEATURE_64BIT_ALIGNMENT
1612 inline bool RequiresAlign8()
1614 LIMITED_METHOD_DAC_CONTRACT;
1615 return !!GetFlag(enum_flag_RequiresAlign8);
1618 inline void SetRequiresAlign8()
1620 LIMITED_METHOD_CONTRACT;
1621 SetFlag(enum_flag_RequiresAlign8);
1623 #endif // FEATURE_64BIT_ALIGNMENT
1625 //-------------------------------------------------------------------
1626 // FIELD DESCRIPTORS
1628 // Most of this API still lives on EEClass.
1630 // ************************************ WARNING *************
1631 // ** !!!!INSTANCE FIELDDESCS ARE REPRESENTATIVES!!!!! **
1632 // ** THEY ARE SHARED BY COMPATIBLE GENERIC INSTANTIATIONS **
1633 // ************************************ WARNING *************
1635 // This goes straight to the EEClass
1636 // Careful about using this method. If it's possible that fields may have been added via EnC, then
1637 // must use the FieldDescIterator as any fields added via EnC won't be in the raw list
1638 PTR_FieldDesc GetApproxFieldDescListRaw();
1640 // This returns a type-exact FieldDesc for a static field, but may still return a representative
1641 // for a non-static field.
1642 PTR_FieldDesc GetFieldDescByIndex(DWORD fieldIndex);
1644 DWORD GetIndexForFieldDesc(FieldDesc *pField);
1646 inline bool HasPreciseInitCctors()
1648 LIMITED_METHOD_CONTRACT;
1649 return !!GetFlag(enum_flag_HasPreciseInitCctors);
1652 inline void SetHasPreciseInitCctors()
1654 LIMITED_METHOD_CONTRACT;
1655 SetFlag(enum_flag_HasPreciseInitCctors);
1658 #if defined(FEATURE_HFA)
1661 LIMITED_METHOD_CONTRACT;
1662 return !!GetFlag(enum_flag_IsHFA);
1665 inline void SetIsHFA()
1667 LIMITED_METHOD_CONTRACT;
1668 SetFlag(enum_flag_IsHFA);
1670 #else // !FEATURE_HFA
1672 #endif // FEATURE_HFA
1674 // Returns the size in bytes of this type if it is a HW vector type; 0 otherwise.
1675 int GetVectorSize();
1677 // Get the HFA type. This is supported both with FEATURE_HFA, in which case it
1678 // depends on the cached bit on the class, or without, in which case it is recomputed
1679 // for each invocation.
1680 CorInfoHFAElemType GetHFAType();
1681 // The managed and unmanaged HFA type can differ for types with layout. The following two methods return the unmanaged HFA type.
1683 CorInfoHFAElemType GetNativeHFAType();
1685 #ifdef UNIX_AMD64_ABI
1686 inline bool IsRegPassedStruct()
1688 LIMITED_METHOD_CONTRACT;
1689 return !!GetFlag(enum_flag_IsRegStructPassed);
1692 inline void SetRegPassedStruct()
1694 LIMITED_METHOD_CONTRACT;
1695 SetFlag(enum_flag_IsRegStructPassed);
1698 inline bool IsRegPassedStruct()
1704 #ifdef FEATURE_64BIT_ALIGNMENT
1705 // Returns true iff the native view of this type requires 64-bit alignment.
1706 bool NativeRequiresAlign8();
1707 #endif // FEATURE_64BIT_ALIGNMENT
1709 //-------------------------------------------------------------------
1710 // PARENT INTERFACES
1712 unsigned GetNumInterfaces()
1714 LIMITED_METHOD_DAC_CONTRACT;
1715 return m_wNumInterfaces;
1718 //-------------------------------------------------------------------
1721 BOOL CanCastToInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
1722 BOOL CanCastToClass(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
1723 BOOL CanCastTo(MethodTable* pTargetMT, TypeHandlePairList *pVisited);
1724 BOOL ArraySupportsBizarreInterface(MethodTable* pInterfaceMT, TypeHandlePairList* pVisited);
1725 BOOL ArrayIsInstanceOf(MethodTable* pTargetMT, TypeHandlePairList* pVisited);
1727 BOOL CanCastByVarianceToInterfaceOrDelegate(MethodTable* pTargetMT, TypeHandlePairList* pVisited, MethodTable* pMTInterfaceMapOwner = NULL);
1729 // The inline part of equivalence check.
1730 #ifndef DACCESS_COMPILE
1731 FORCEINLINE BOOL IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL));
1733 #ifdef FEATURE_TYPEEQUIVALENCE
1734 // This method is public so that TypeHandle has direct access to it
1735 BOOL IsEquivalentTo_Worker(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO tolerant
1737 BOOL IsEquivalentTo_WorkerInner(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO intolerant
1738 #endif // FEATURE_TYPEEQUIVALENCE
1742 //-------------------------------------------------------------------
1743 // THE METHOD TABLE PARENT (SUPERCLASS/BASE CLASS)
1745 BOOL HasApproxParent()
1747 LIMITED_METHOD_DAC_CONTRACT;
1748 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent) != 0;
1750 inline void SetHasExactParent()
1752 WRAPPER_NO_CONTRACT;
1753 InterlockedAnd((LONG*)&GetWriteableDataForWrite()->m_dwFlags, ~MethodTableWriteableData::enum_flag_HasApproxParent);
1757 // Caller must know that the parent method table is not an encoded fixup
1758 inline PTR_MethodTable GetParentMethodTable()
1760 LIMITED_METHOD_DAC_CONTRACT;
1762 PRECONDITION(IsParentMethodTablePointerValid());
1763 return m_pParentMethodTable;
1766 #ifndef DACCESS_COMPILE
1767 inline MethodTable ** GetParentMethodTableValuePtr()
1769 LIMITED_METHOD_CONTRACT;
1770 return &m_pParentMethodTable;
1772 #endif // !DACCESS_COMPILE
1774 // Is the parent method table pointer equal to the given argument?
1775 BOOL ParentEquals(PTR_MethodTable pMT)
1777 LIMITED_METHOD_DAC_CONTRACT;
1778 PRECONDITION(IsParentMethodTablePointerValid());
1779 return GetParentMethodTable() == pMT;
1783 BOOL IsParentMethodTablePointerValid();
1786 #ifndef DACCESS_COMPILE
1787 void SetParentMethodTable (MethodTable *pParentMethodTable)
1789 LIMITED_METHOD_CONTRACT;
1790 m_pParentMethodTable = pParentMethodTable;
1792 GetWriteableDataForWrite()->SetParentMethodTablePointerValid();
1795 #endif // !DACCESS_COMPILE
1796 MethodTable * GetMethodTableMatchingParentClass(MethodTable * pWhichParent);
1797 Instantiation GetInstantiationOfParentClass(MethodTable *pWhichParent);
1799 //-------------------------------------------------------------------
1800 // THE EEClass (Possibly shared between instantiations!).
1802 // Note that it is not generally the case that GetClass.GetMethodTable() == t.
1804 PTR_EEClass GetClass();
1806 PTR_EEClass GetClassWithPossibleAV();
1808 BOOL ValidateWithPossibleAV();
1810 BOOL IsClassPointerValid();
1812 static UINT32 GetOffsetOfFlags()
1814 LIMITED_METHOD_CONTRACT;
1815 return offsetof(MethodTable, m_dwFlags);
1818 static UINT32 GetIfArrayThenSzArrayFlag()
1820 LIMITED_METHOD_CONTRACT;
1821 return enum_flag_Category_IfArrayThenSzArray;
1824 //-------------------------------------------------------------------
1827 // Do not call the following at any time except when creating a method table.
1828 // One day we will have proper constructors for method tables and all these
1830 #ifndef DACCESS_COMPILE
1831 inline void SetClass(EEClass *pClass)
1833 LIMITED_METHOD_CONTRACT;
1834 m_pEEClass = pClass;
1837 inline void SetCanonicalMethodTable(MethodTable * pMT)
1839 m_pCanonMT = (TADDR)pMT | MethodTable::UNION_METHODTABLE;
1843 inline void SetHasInstantiation(BOOL fTypicalInstantiation, BOOL fSharedByGenericInstantiations);
1845 //-------------------------------------------------------------------
1846 // INTERFACE IMPLEMENTATION
1849 // Faster force-inlined version of ImplementsInterface
1850 BOOL ImplementsInterfaceInline(MethodTable *pInterface);
1852 BOOL ImplementsInterface(MethodTable *pInterface);
1853 BOOL ImplementsEquivalentInterface(MethodTable *pInterface);
1855 MethodDesc *GetMethodDescForInterfaceMethod(TypeHandle ownerType, MethodDesc *pInterfaceMD, BOOL throwOnConflict);
1856 MethodDesc *GetMethodDescForInterfaceMethod(MethodDesc *pInterfaceMD, BOOL throwOnConflict); // You can only use this one for non-generic interfaces
1858 //-------------------------------------------------------------------
1862 inline PTR_InterfaceInfo GetInterfaceMap();
1864 #ifndef DACCESS_COMPILE
1865 void SetInterfaceMap(WORD wNumInterfaces, InterfaceInfo_t* iMap);
1868 inline int HasInterfaceMap()
1870 LIMITED_METHOD_DAC_CONTRACT;
1871 return (m_wNumInterfaces != 0);
1874 // Where possible, use this iterator over the interface map instead of accessing the map directly
1875 // That way we can easily change the implementation of the map
1876 class InterfaceMapIterator
1878 friend class MethodTable;
1881 PTR_InterfaceInfo m_pMap;
1885 InterfaceMapIterator(MethodTable *pMT)
1886 : m_pMap(pMT->GetInterfaceMap()),
1888 m_count(pMT->GetNumInterfaces())
1890 WRAPPER_NO_CONTRACT;
1893 InterfaceMapIterator(MethodTable *pMT, DWORD index)
1894 : m_pMap(pMT->GetInterfaceMap() + index),
1896 m_count(pMT->GetNumInterfaces())
1898 WRAPPER_NO_CONTRACT;
1899 CONSISTENCY_CHECK(index >= 0 && index < m_count);
1903 InterfaceInfo_t* GetInterfaceInfo()
1905 LIMITED_METHOD_CONTRACT;
1909 // Move to the next item in the map, returning TRUE if an item
1910 // exists or FALSE if we've run off the end
1913 LIMITED_METHOD_CONTRACT;
1914 PRECONDITION(!Finished());
1915 if (m_i != (DWORD) -1)
1917 return (++m_i < m_count);
1920 // Have we iterated over all of the items?
1923 return (m_i == m_count);
1926 #ifndef DACCESS_COMPILE
1927 // Get the interface at the current position. This GetInterfaceMethod
1928 // will ensure that the exact correct instantiation of the interface
1929 // is found, even if the MethodTable in the interface map is the generic
1931 PTR_MethodTable GetInterface(MethodTable* pMTOwner, ClassLoadLevel loadLevel = CLASS_LOADED);
1934 // Get the interface at the current position, with whatever its normal load level is
1935 inline PTR_MethodTable GetInterfaceApprox()
1937 CONTRACT(PTR_MethodTable)
1942 PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
1943 POSTCONDITION(CheckPointer(RETVAL));
1947 RETURN (m_pMap->GetMethodTable());
1950 inline bool CurrentInterfaceMatches(MethodTable* pMTOwner, MethodTable* pMT)
1957 PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
1961 MethodTable *pCurrentMethodTable = m_pMap->GetMethodTable();
1963 bool exactMatch = pCurrentMethodTable == pMT;
1966 if (pCurrentMethodTable->HasSameTypeDefAs(pMT) &&
1967 pMT->HasInstantiation() &&
1968 pCurrentMethodTable->IsSpecialMarkerTypeForGenericCasting() &&
1969 !pMTOwner->ContainsGenericVariables() &&
1970 pMT->GetInstantiation().ContainsAllOneType(pMTOwner))
1973 #ifndef DACCESS_COMPILE
1974 // We match exactly, and have an actual pMT loaded. Insert
1975 // the searched for interface if it is fully loaded, so that
1976 // future checks are more efficient
1977 if (pMT->IsFullyLoaded())
1983 RETURN (exactMatch);
1986 inline bool HasSameTypeDefAs(MethodTable* pMT)
1993 PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
1997 RETURN (m_pMap->GetMethodTable()->HasSameTypeDefAs(pMT));
2000 #ifndef DACCESS_COMPILE
2001 void SetInterface(MethodTable *pMT)
2003 WRAPPER_NO_CONTRACT;
2004 m_pMap->SetMethodTable(pMT);
2010 LIMITED_METHOD_CONTRACT;
2013 }; // class InterfaceMapIterator
2015 // Create a new iterator over the interface map
2016 // The iterator starts just before the first item in the map
2017 InterfaceMapIterator IterateInterfaceMap()
2019 WRAPPER_NO_CONTRACT;
2020 return InterfaceMapIterator(this);
2023 // Create a new iterator over the interface map, starting at the index specified
2024 InterfaceMapIterator IterateInterfaceMapFrom(DWORD index)
2026 WRAPPER_NO_CONTRACT;
2027 return InterfaceMapIterator(this, index);
2030 //-------------------------------------------------------------------
2031 // ADDITIONAL INTERFACE MAP DATA
2034 // We store extra info (flag bits) for interfaces implemented on this MethodTable in a separate optional
2035 // location for better data density (if we put them in the interface map directly data alignment could
2036 // have us using 32 or even 64 bits to represent a single boolean value). Currently the only flag we
2037 // persist is IsDeclaredOnClass (was the interface explicitly declared by this class).
2039 // Currently we always store extra info whenever we have an interface map (in the future you could imagine
2040 // this being limited to those scenarios in which at least one of the interfaces has a non-default value
2042 inline BOOL HasExtraInterfaceInfo()
2045 return HasInterfaceMap();
2048 // Count of interfaces that can have their extra info stored inline in the optional data structure itself
2049 // (once the interface count exceeds this limit the optional data slot will instead point to a buffer with
2050 // the information).
2051 enum { kInlinedInterfaceInfoThreshold = sizeof(TADDR) * 8 };
2053 // Calculate how many bytes of storage will be required to track additional information for interfaces.
2054 // This will be zero if there are no interfaces, but can also be zero for small numbers of interfaces as
2055 // well, and callers should be ready to handle this.
2056 static SIZE_T GetExtraInterfaceInfoSize(DWORD cInterfaces);
2058 // Called after GetExtraInterfaceInfoSize above to setup a new MethodTable with the additional memory to
2059 // track extra interface info. If there are a non-zero number of interfaces implemented on this class but
2060 // GetExtraInterfaceInfoSize() returned zero, this call must still be made (with a NULL argument).
2061 void InitializeExtraInterfaceInfo(PVOID pInfo);
2063 #ifdef DACCESS_COMPILE
2064 void EnumMemoryRegionsForExtraInterfaceInfo();
2065 #endif // DACCESS_COMPILE
2067 // For the given interface in the map (specified via map index) mark the interface as declared explicitly
2068 // on this class. This is not legal for dynamically added interfaces (as used by RCWs).
2069 void SetInterfaceDeclaredOnClass(DWORD index);
2071 // For the given interface in the map (specified via map index) return true if the interface was declared
2072 // explicitly on this class.
2073 bool IsInterfaceDeclaredOnClass(DWORD index);
2075 //-------------------------------------------------------------------
2076 // VIRTUAL/INTERFACE CALL RESOLUTION
2078 // These should probably go in method.hpp since they don't have
2079 // much to do with method tables per se.
2082 // get the method desc given the interface method desc
2083 static MethodDesc *GetMethodDescForInterfaceMethodAndServer(TypeHandle ownerType, MethodDesc *pItfMD, OBJECTREF *pServer);
2085 #ifdef FEATURE_COMINTEROP
2086 // 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)
2087 MethodDesc *GetMethodDescForComInterfaceMethod(MethodDesc *pItfMD, bool fNullOk);
2088 #endif // FEATURE_COMINTEROP
2090 // Resolve virtual static interface method pInterfaceMD on this type.
2092 // Specify allowNullResult to return NULL instead of throwing if the there is no implementation
2093 // Specify verifyImplemented to verify that there is a match, but do not actually return a final usable MethodDesc
2094 // Specify allowVariantMatches to permit generic interface variance
2095 // Specify uniqueResolution to store the flag saying whether the resolution was unambiguous;
2096 // when NULL, throw an AmbiguousResolutionException upon hitting ambiguous SVM resolution.
2097 // The 'level' parameter specifies the load level for the class containing the resolved MethodDesc.
2098 MethodDesc *ResolveVirtualStaticMethod(
2099 MethodTable* pInterfaceType,
2100 MethodDesc* pInterfaceMD,
2101 ResolveVirtualStaticMethodFlags resolveVirtualStaticMethodFlags,
2102 BOOL *uniqueResolution = NULL,
2103 ClassLoadLevel level = CLASS_LOADED);
2105 // Try a partial resolve of the constraint call, up to generic code sharing.
2107 // Note that this will not necessarily resolve the call exactly, since we might be compiling
2108 // shared generic code - it may just resolve it to a candidate suitable for
2109 // JIT compilation, and require a runtime lookup for the actual code pointer
2112 // Return NULL if the call could not be resolved, e.g. because it is invoked
2113 // on a type that inherits the implementation of the method from System.Object
2114 // or System.ValueType.
2116 // Always returns an unboxed entry point with a uniform calling convention.
2117 MethodDesc * TryResolveConstraintMethodApprox(
2118 TypeHandle ownerType,
2120 BOOL * pfForceUseRuntimeLookup = NULL);
2122 //-------------------------------------------------------------------
2123 // CONTRACT IMPLEMENTATIONS
2126 inline BOOL HasDispatchMap()
2128 WRAPPER_NO_CONTRACT;
2129 return GetDispatchMap() != NULL;
2132 PTR_DispatchMap GetDispatchMap();
2134 inline BOOL HasDispatchMapSlot()
2136 LIMITED_METHOD_DAC_CONTRACT;
2137 return GetFlag(enum_flag_HasDispatchMapSlot);
2140 #ifndef DACCESS_COMPILE
2141 void SetDispatchMap(DispatchMap *pDispatchMap)
2143 LIMITED_METHOD_CONTRACT;
2144 _ASSERTE(HasDispatchMapSlot());
2146 TADDR pSlot = GetMultipurposeSlotPtr(enum_flag_HasDispatchMapSlot, c_DispatchMapSlotOffsets);
2147 *(DispatchMap **)pSlot = pDispatchMap;
2149 #endif // !DACCESS_COMPILE
2152 BOOL FindEncodedMapDispatchEntry(UINT32 typeID,
2154 DispatchMapEntry *pEntry);
2156 BOOL FindIntroducedImplementationTableDispatchEntry(UINT32 slotNumber,
2157 DispatchMapEntry *pEntry,
2158 BOOL fVirtualMethodsOnly);
2160 BOOL FindDispatchEntryForCurrentType(UINT32 typeID,
2162 DispatchMapEntry *pEntry);
2164 BOOL FindDispatchEntry(UINT32 typeID,
2166 DispatchMapEntry *pEntry);
2169 BOOL FindDispatchImpl(
2172 DispatchSlot * pImplSlot,
2173 BOOL throwOnConflict);
2176 #ifndef DACCESS_COMPILE
2177 BOOL FindDefaultInterfaceImplementation(
2178 MethodDesc *pInterfaceMD,
2179 MethodTable *pObjectMT,
2180 MethodDesc **ppDefaultMethod,
2181 FindDefaultInterfaceImplementationFlags findDefaultImplementationFlags,
2182 ClassLoadLevel level = CLASS_LOADED);
2183 #endif // DACCESS_COMPILE
2185 DispatchSlot FindDispatchSlot(UINT32 typeID, UINT32 slotNumber, BOOL throwOnConflict);
2187 // You must use the second of these two if there is any chance the pMD is a method
2188 // on a generic interface such as IComparable<T> (which it normally can be). The
2189 // ownerType is used to provide an exact qualification in the case the pMD is
2190 // a shared method descriptor.
2191 DispatchSlot FindDispatchSlotForInterfaceMD(MethodDesc *pMD, BOOL throwOnConflict);
2192 DispatchSlot FindDispatchSlotForInterfaceMD(TypeHandle ownerType, MethodDesc *pMD, BOOL throwOnConflict);
2194 MethodDesc *ReverseInterfaceMDLookup(UINT32 slotNumber);
2196 // Lookup, does not assign if not already done.
2197 UINT32 LookupTypeID();
2198 // Lookup, will assign ID if not already done.
2202 // Will return either the dispatch map type. May trigger type loader in order to get
2204 MethodTable *LookupDispatchMapType(DispatchMapTypeID typeID);
2205 bool DispatchMapTypeMatchesMethodTable(DispatchMapTypeID typeID, MethodTable* pMT);
2207 MethodDesc *GetIntroducingMethodDesc(DWORD slotNumber);
2209 // Determines whether all methods in the given interface have their final implementing
2210 // slot in a parent class. I.e. if this returns TRUE, it is trivial (no VSD lookup) to
2211 // dispatch pItfMT methods on this class if one knows how to dispatch them on pParentMT.
2212 BOOL ImplementsInterfaceWithSameSlotsAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
2214 // Determines whether all methods in the given interface have their final implementation
2215 // in a parent class. I.e. if this returns TRUE, this class behaves the same as pParentMT
2216 // when it comes to dispatching pItfMT methods.
2217 BOOL HasSameInterfaceImplementationAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
2219 // Try to resolve a given static virtual method override on this type. Return nullptr
2221 MethodDesc *TryResolveVirtualStaticMethodOnThisType(MethodTable* pInterfaceType, MethodDesc* pInterfaceMD, ResolveVirtualStaticMethodFlags resolveVirtualStaticMethodFlags, ClassLoadLevel level);
2224 static MethodDesc *MapMethodDeclToMethodImpl(MethodDesc *pMDDecl);
2226 //-------------------------------------------------------------------
2227 // FINALIZATION SEMANTICS
2230 DWORD CannotUseSuperFastHelper()
2232 WRAPPER_NO_CONTRACT;
2233 return HasFinalizer();
2236 void SetHasFinalizer()
2238 LIMITED_METHOD_CONTRACT;
2239 SetFlag(enum_flag_HasFinalizer);
2242 void SetHasCriticalFinalizer()
2244 LIMITED_METHOD_CONTRACT;
2245 SetFlag(enum_flag_HasCriticalFinalizer);
2247 // Does this class have non-trivial finalization requirements?
2248 DWORD HasFinalizer()
2250 LIMITED_METHOD_DAC_CONTRACT;
2251 return GetFlag(enum_flag_HasFinalizer);
2253 // Must this class be finalized during a rude appdomain unload, and
2254 // must it's finalizer run in a different order from normal finalizers?
2255 DWORD HasCriticalFinalizer() const
2257 LIMITED_METHOD_CONTRACT;
2258 return GetFlag(enum_flag_HasCriticalFinalizer);
2261 //-------------------------------------------------------------------
2265 DWORD GetOffsetOfFirstStaticHandle();
2266 DWORD GetOffsetOfFirstStaticMT();
2268 #ifndef DACCESS_COMPILE
2269 inline PTR_BYTE GetNonGCStaticsBasePointer();
2270 inline PTR_BYTE GetGCStaticsBasePointer();
2271 inline PTR_BYTE GetNonGCThreadStaticsBasePointer();
2272 inline PTR_BYTE GetGCThreadStaticsBasePointer();
2273 inline PTR_BYTE GetGCThreadStaticsBaseHandle();
2274 #endif //!DACCESS_COMPILE
2276 inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread);
2277 inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread);
2279 inline DWORD IsDynamicStatics()
2281 LIMITED_METHOD_DAC_CONTRACT;
2282 return !TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_NonDynamic);
2285 inline void SetDynamicStatics(BOOL fGeneric)
2287 LIMITED_METHOD_CONTRACT;
2288 SetFlag(fGeneric ? enum_flag_StaticsMask_Generics : enum_flag_StaticsMask_Dynamic);
2291 inline void SetHasBoxedRegularStatics()
2293 LIMITED_METHOD_CONTRACT;
2294 SetFlag(enum_flag_HasBoxedRegularStatics);
2297 inline DWORD HasBoxedRegularStatics()
2299 LIMITED_METHOD_CONTRACT;
2300 return GetFlag(enum_flag_HasBoxedRegularStatics);
2303 DWORD HasFixedAddressVTStatics();
2305 // Indicates if the MethodTable only contains abstract methods
2306 BOOL HasOnlyAbstractMethods();
2308 //-------------------------------------------------------------------
2309 // PER-INSTANTIATION STATICS INFO
2313 void SetupGenericsStaticsInfo(FieldDesc* pStaticFieldDescs);
2315 BOOL HasGenericsStaticsInfo()
2317 LIMITED_METHOD_DAC_CONTRACT;
2318 return GetFlag(enum_flag_StaticsMask_Generics);
2321 PTR_FieldDesc GetGenericsStaticFieldDescs()
2323 WRAPPER_NO_CONTRACT;
2324 _ASSERTE(HasGenericsStaticsInfo());
2325 return GetGenericsStaticsInfo()->m_pFieldDescs;
2328 BOOL HasCrossModuleGenericStaticsInfo()
2330 LIMITED_METHOD_DAC_CONTRACT;
2331 return TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_CrossModuleGenerics);
2334 PTR_Module GetGenericsStaticsModuleAndID(DWORD * pID);
2336 WORD GetNumHandleRegularStatics();
2338 WORD GetNumBoxedRegularStatics ();
2339 WORD GetNumBoxedThreadStatics ();
2341 //-------------------------------------------------------------------
2345 // Used for generics and reflection emit in memory
2346 DWORD GetModuleDynamicEntryID();
2347 Module* GetModuleForStatics();
2349 //-------------------------------------------------------------------
2350 // GENERICS DICT INFO
2353 // Number of generic arguments, whether this is a method table for
2354 // a generic type instantiation, e.g. List<string> or the "generic" MethodTable
2356 inline DWORD GetNumGenericArgs()
2358 LIMITED_METHOD_DAC_CONTRACT;
2359 if (HasInstantiation())
2360 return (DWORD) (GetGenericsDictInfo()->m_wNumTyPars);
2365 inline DWORD GetNumDicts()
2367 LIMITED_METHOD_DAC_CONTRACT;
2368 if (HasPerInstInfo())
2370 PTR_GenericsDictInfo pDictInfo = GetGenericsDictInfo();
2371 return (DWORD) (pDictInfo->m_wNumDicts);
2377 //-------------------------------------------------------------------
2381 OBJECTREF Allocate();
2383 // This flavor of Allocate is more efficient, but can only be used
2384 // if IsRestored(), CheckInstanceActivated(), IsClassInited() are known to be true.
2385 // A sufficient condition is that another instance of the exact same type already
2386 // exists in the same appdomain. It's currently called only from Delegate.Combine
2387 // via COMDelegate::InternalAllocLike.
2388 OBJECTREF AllocateNoChecks();
2390 OBJECTREF Box(void* data);
2391 OBJECTREF FastBox(void** data);
2392 #ifndef DACCESS_COMPILE
2393 BOOL UnBoxInto(void *dest, OBJECTREF src);
2394 void UnBoxIntoUnchecked(void *dest, OBJECTREF src);
2398 // Used for debugging class layout. Dumps to the debug console
2399 // when debug is true.
2400 void DebugDumpVtable(LPCUTF8 szClassName, BOOL fDebug);
2401 void Debug_DumpInterfaceMap(LPCSTR szInterfaceMapPrefix);
2402 void Debug_DumpDispatchMap();
2403 void DebugDumpFieldLayout(LPCUTF8 pszClassName, BOOL debug);
2404 void DebugRecursivelyDumpInstanceFields(LPCUTF8 pszClassName, BOOL debug);
2405 void DebugDumpGCDesc(LPCUTF8 pszClassName, BOOL debug);
2408 inline BOOL IsAgileAndFinalizable()
2410 LIMITED_METHOD_CONTRACT;
2411 // Right now, System.Thread is the only cases of this.
2412 // Things should stay this way - please don't change without talking to EE team.
2413 return this == g_pThreadClass;
2417 //-------------------------------------------------------------------
2418 // ENUMS, DELEGATES, VALUE TYPES, ARRAYS
2420 // #KindsOfElementTypes
2421 // GetInternalCorElementType() retrieves the internal representation of the type. It's not always
2422 // appropriate to use this. For example, we treat enums as their underlying type or some structs are
2423 // optimized to be ints. To get the signature type or the verifier type (same as signature except for
2424 // enums are normalized to the primitive type that underlies them), use the APIs in Typehandle.h
2426 // * code:TypeHandle.GetSignatureCorElementType()
2427 // * code:TypeHandle.GetVerifierCorElementType()
2428 // * code:TypeHandle.GetInternalCorElementType()
2429 CorElementType GetInternalCorElementType();
2430 void SetInternalCorElementType(CorElementType _NormType);
2432 // See code:TypeHandle::GetVerifierCorElementType for description
2433 CorElementType GetVerifierCorElementType();
2435 // See code:TypeHandle::GetSignatureCorElementType for description
2436 CorElementType GetSignatureCorElementType();
2438 // A true primitive is one who's GetVerifierCorElementType() ==
2441 // ELEMENT_TYPE_TYPEDBYREF etc.
2442 // Note that GetIntenalCorElementType might return these same values for some additional
2443 // types such as Enums and some structs.
2444 BOOL IsTruePrimitive();
2445 void SetIsTruePrimitive();
2447 // Is this delegate? Returns false for System.Delegate and System.MulticastDelegate.
2448 inline BOOL IsDelegate()
2450 LIMITED_METHOD_DAC_CONTRACT;
2451 // We do not allow single cast delegates anymore, just check for multicast delegate
2452 _ASSERTE(g_pMulticastDelegateClass);
2453 return ParentEquals(g_pMulticastDelegateClass);
2456 // Is this System.Object?
2457 inline BOOL IsObjectClass()
2459 LIMITED_METHOD_CONTRACT;
2460 _ASSERTE(g_pObjectClass);
2461 return (this == g_pObjectClass);
2464 // Is this System.ValueType?
2465 inline DWORD IsValueTypeClass()
2467 LIMITED_METHOD_CONTRACT;
2468 _ASSERTE(g_pValueTypeClass);
2469 return (this == g_pValueTypeClass);
2472 // Is this value type? Returns false for System.ValueType and System.Enum.
2473 inline BOOL IsValueType();
2475 // Is this enum? Returns false for System.Enum.
2476 inline BOOL IsEnum();
2478 // Is this array? Returns false for System.Array.
2479 inline BOOL IsArray()
2481 LIMITED_METHOD_DAC_CONTRACT;
2482 return GetFlag(enum_flag_Category_Array_Mask) == enum_flag_Category_Array;
2484 inline BOOL IsMultiDimArray()
2486 LIMITED_METHOD_DAC_CONTRACT;
2487 PRECONDITION(IsArray());
2488 return !GetFlag(enum_flag_Category_IfArrayThenSzArray);
2491 // Returns true if this type is Nullable<T> for some T.
2492 inline BOOL IsNullable()
2494 LIMITED_METHOD_DAC_CONTRACT;
2495 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Nullable;
2498 inline void SetIsNullable()
2500 LIMITED_METHOD_CONTRACT;
2501 _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType);
2502 SetFlag(enum_flag_Category_Nullable);
2505 // The following methods are only valid for the method tables for array types.
2506 CorElementType GetArrayElementType();
2509 TypeHandle GetArrayElementTypeHandle()
2511 LIMITED_METHOD_DAC_CONTRACT;
2512 _ASSERTE (IsArray());
2513 return TypeHandle::FromTAddr(m_ElementTypeHnd);
2516 void SetArrayElementTypeHandle(TypeHandle th)
2518 LIMITED_METHOD_DAC_CONTRACT;
2519 m_ElementTypeHnd = th.AsTAddr();
2522 TypeHandle * GetArrayElementTypeHandlePtr()
2524 LIMITED_METHOD_CONTRACT;
2525 return (TypeHandle *)&m_ElementTypeHnd;
2528 static inline DWORD GetOffsetOfArrayElementTypeHandle()
2530 LIMITED_METHOD_CONTRACT;
2531 return offsetof(MethodTable, m_ElementTypeHnd);
2534 //-------------------------------------------------------------------
2535 // UNDERLYING METADATA
2539 // Get the RID/token for the metadata for the corresponding type declaration
2540 unsigned GetTypeDefRid();
2542 inline mdTypeDef GetCl()
2544 LIMITED_METHOD_CONTRACT;
2545 return TokenFromRid(GetTypeDefRid(), mdtTypeDef);
2548 void SetCl(mdTypeDef token);
2551 // Make this smaller in debug builds to exercise the overflow codepath
2552 #define METHODTABLE_TOKEN_OVERFLOW 0xFFF
2554 #define METHODTABLE_TOKEN_OVERFLOW 0xFFFF
2557 BOOL HasTokenOverflow()
2559 LIMITED_METHOD_CONTRACT;
2560 return m_wToken == METHODTABLE_TOKEN_OVERFLOW;
2563 // Get the MD Import for the metadata for the corresponding type declaration
2564 IMDInternalImport* GetMDImport();
2566 HRESULT GetCustomAttribute(WellKnownAttribute attribute,
2567 const void **ppData,
2570 mdTypeDef GetEnclosingCl();
2572 CorNativeLinkType GetCharSet();
2574 #ifdef DACCESS_COMPILE
2575 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2578 //-------------------------------------------------------------------
2579 // DICTIONARIES FOR GENERIC INSTANTIATIONS
2581 // The PerInstInfo pointer is a pointer to per-instantiation pointer table,
2582 // each entry of which points to an instantiation "dictionary"
2583 // for an instantiated type; the last pointer points to a
2584 // dictionary which is specific to this method table, previous
2585 // entries point to dictionaries in superclasses. Instantiated interfaces and structs
2586 // have just single dictionary (no inheritance).
2588 // GetNumDicts() gives the number of dictionaries.
2590 //@nice GENERICS: instead of a separate table of pointers, put the pointers
2591 // in the vtable itself. Advantages:
2592 // * Time: we save an indirection as we don't need to go through PerInstInfo first.
2593 // * Space: no need for PerInstInfo (1 word)
2594 // Problem is that lots of code assumes that the vtable is filled
2595 // uniformly with pointers to MethodDesc stubs.
2597 // The dictionary for the method table is just an array of handles for
2598 // type parameters in the following cases:
2599 // * instantiated interfaces (no code)
2600 // * instantiated types whose code is not shared
2601 // Otherwise, it starts with the type parameters and then has a fixed
2602 // number of slots for handles (types & methods)
2603 // that are filled in lazily at run-time. Finally there is a "spill-bucket"
2604 // pointer used when the dictionary gets filled.
2606 // typar_1 type handle for first type parameter
2608 // typar_n type handle for last type parameter
2609 // slot_1 slot for first run-time handle (initially null)
2611 // slot_m slot for last run-time handle (initially null)
2612 // next_bucket pointer to spill bucket (possibly null)
2613 // The spill bucket contains just run-time handle slots.
2614 // (Alternative: continue chaining buckets.
2615 // Advantage: no need to deallocate when growing dictionaries.
2616 // Disadvantage: more indirections required at run-time.)
2618 // The layout of dictionaries is determined by GetClass()->GetDictionaryLayout()
2619 // Thus the layout can vary between incompatible instantiations. This is sometimes useful because individual type
2620 // parameters may or may not be shared. For example, consider a two parameter class Dict<K,D>. In instantiations shared with
2621 // Dict<double,string> any reference to K is known at JIT-compile-time (it's double) but any token containing D
2622 // must have a dictionary entry. On the other hand, for instantiations shared with Dict<string,double> the opposite holds.
2625 typedef PTR_Dictionary PerInstInfoElem_t;
2626 typedef DPTR(PerInstInfoElem_t) PerInstInfo_t;
2628 // Return a pointer to the per-instantiation information. See field itself for comments.
2629 DPTR(PerInstInfoElem_t) GetPerInstInfo()
2631 LIMITED_METHOD_DAC_CONTRACT;
2632 _ASSERTE(HasPerInstInfo());
2633 return m_pPerInstInfo;
2635 BOOL HasPerInstInfo()
2637 LIMITED_METHOD_DAC_CONTRACT;
2638 return GetFlag(enum_flag_HasPerInstInfo) && !IsArray();
2640 #ifndef DACCESS_COMPILE
2641 static inline DWORD GetOffsetOfPerInstInfo()
2643 LIMITED_METHOD_CONTRACT;
2644 return offsetof(MethodTable, m_pPerInstInfo);
2646 void SetPerInstInfo(PerInstInfoElem_t *pPerInstInfo)
2648 LIMITED_METHOD_CONTRACT;
2649 m_pPerInstInfo = pPerInstInfo;
2651 void SetDictInfo(WORD numDicts, WORD numTyPars)
2653 WRAPPER_NO_CONTRACT;
2654 GenericsDictInfo* pInfo = GetGenericsDictInfo();
2655 pInfo->m_wNumDicts = numDicts;
2656 pInfo->m_wNumTyPars = numTyPars;
2658 #endif // !DACCESS_COMPILE
2659 PTR_GenericsDictInfo GetGenericsDictInfo()
2661 LIMITED_METHOD_DAC_CONTRACT;
2662 // GenericsDictInfo is stored at negative offset of the dictionary
2663 return dac_cast<PTR_GenericsDictInfo>(GetPerInstInfo()) - 1;
2666 // Get a pointer to the dictionary for this instantiated type
2667 // (The instantiation is stored in the initial slots of the dictionary)
2668 // If not instantiated, return NULL
2669 PTR_Dictionary GetDictionary();
2671 // Return a substitution suitbale for interpreting
2672 // the metadata in parent class, assuming we already have a subst.
2673 // suitable for interpreting the current class.
2675 // If, for example, the definition for the current class is
2676 // D<T> : C<List<T>, T[] >
2677 // then this (for C<!0,!1>) will be
2680 // added to the chain of substitutions.
2682 // Subsequently, if the definition for C is
2683 // C<T, U> : B< Dictionary<T, U> >
2684 // then the next subst (for B<!0>) will be
2685 // 0 --> Dictionary< List<T>, T[] >
2687 Substitution GetSubstitutionForParent(const Substitution *pSubst);
2689 inline DWORD GetAttrClass();
2691 inline BOOL HasFieldsWhichMustBeInited();
2693 //-------------------------------------------------------------------
2694 // THE EXPOSED CLASS OBJECT
2697 * m_ExposedClassObject is a RuntimeType instance for this class. But
2698 * do NOT use it for Arrays or remoted objects! All arrays of objects
2699 * share the same MethodTable/EEClass.
2700 * @GENERICS: this is per-instantiation data
2702 // There are two version of GetManagedClassObject. The GetManagedClassObject()
2703 // method will get the class object. If it doesn't exist it will be created.
2704 // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist.
2705 OBJECTREF GetManagedClassObject();
2706 OBJECTREF GetManagedClassObjectIfExists();
2709 // ------------------------------------------------------------------
2710 // Private part of MethodTable
2711 // ------------------------------------------------------------------
2713 #ifndef DACCESS_COMPILE
2714 inline void SetWriteableData(PTR_MethodTableWriteableData pMTWriteableData)
2716 LIMITED_METHOD_CONTRACT;
2717 _ASSERTE(pMTWriteableData);
2718 m_pWriteableData = pMTWriteableData;
2722 inline PTR_Const_MethodTableWriteableData GetWriteableData() const
2724 LIMITED_METHOD_DAC_CONTRACT;
2725 return MethodTable::m_pWriteableData;
2728 inline PTR_MethodTableWriteableData GetWriteableDataForWrite()
2730 LIMITED_METHOD_DAC_CONTRACT;
2731 return MethodTable::m_pWriteableData;
2734 //-------------------------------------------------------------------
2736 // Used by COM interop to get GUIDs (IIDs and CLSIDs)
2738 // Get and cache the GUID for this interface/class
2739 HRESULT GetGuidNoThrow(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
2741 // Get and cache the GUID for this interface/class
2742 void GetGuid(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
2744 // Convenience method - determine if the interface/class has a guid specified (even if not yet cached)
2745 BOOL HasExplicitGuid();
2748 // Helper routines for the GetFullyQualifiedNameForClass macros defined at the top of class.h.
2749 // You probably should not use these functions directly.
2750 SString &_GetFullyQualifiedNameForClassNestedAware(SString &ssBuf);
2751 SString &_GetFullyQualifiedNameForClass(SString &ssBuf);
2752 LPCUTF8 GetFullyQualifiedNameInfo(LPCUTF8 *ppszNamespace);
2755 template<typename RedirectFunctor> SString &_GetFullyQualifiedNameForClassNestedAwareInternal(SString &ssBuf);
2758 //-------------------------------------------------------------------
2764 inline LPCUTF8 GetDebugClassName()
2766 LIMITED_METHOD_CONTRACT;
2767 return debug_m_szClassName;
2769 inline void SetDebugClassName(LPCUTF8 name)
2771 LIMITED_METHOD_CONTRACT;
2772 debug_m_szClassName = name;
2775 // Was the type created with injected duplicates?
2776 // TRUE means that we tried to inject duplicates (not that we found one to inject).
2777 inline BOOL Debug_HasInjectedInterfaceDuplicates() const
2779 LIMITED_METHOD_CONTRACT;
2780 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates) != 0;
2782 inline void Debug_SetHasInjectedInterfaceDuplicates()
2784 LIMITED_METHOD_CONTRACT;
2785 GetWriteableDataForWrite()->m_dwFlags |= MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates;
2790 #ifndef DACCESS_COMPILE
2792 //--------------------------------------------------------------------------------------
2796 inline ULONG AddRef()
2797 { LIMITED_METHOD_CONTRACT; return (ULONG) InterlockedIncrement((LONG*)&m_cRef); }
2801 // Since all methods that return a MethodData already AddRef'd, we do NOT
2802 // want to AddRef when putting a holder around it. We only want to release it.
2803 static void HolderAcquire(MethodData *pEntry)
2804 { LIMITED_METHOD_CONTRACT; return; }
2805 static void HolderRelease(MethodData *pEntry)
2806 { WRAPPER_NO_CONTRACT; if (pEntry != NULL) pEntry->Release(); }
2810 MethodTable *const m_pImplMT;
2811 MethodTable *const m_pDeclMT;
2814 MethodData(MethodTable *implMT, MethodTable *declMT) : m_cRef(1), m_pImplMT(implMT), m_pDeclMT(declMT) { LIMITED_METHOD_CONTRACT; }
2815 virtual ~MethodData() { LIMITED_METHOD_CONTRACT; }
2817 virtual MethodData *GetDeclMethodData() = 0;
2818 MethodTable *GetDeclMethodTable() { return m_pDeclMT; }
2819 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber) = 0;
2821 virtual MethodData *GetImplMethodData() = 0;
2822 MethodTable *GetImplMethodTable() { return m_pImplMT; }
2823 virtual DispatchSlot GetImplSlot(UINT32 slotNumber) = 0;
2824 // Returns INVALID_SLOT_NUMBER if no implementation exists.
2825 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber) = 0;
2826 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber) = 0;
2827 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber) = 0;
2829 virtual UINT32 GetNumVirtuals() = 0;
2830 virtual UINT32 GetNumMethods() = 0;
2832 virtual void UpdateImplMethodDesc(MethodDesc* pMD, UINT32 slotNumber) = 0;
2835 static const UINT32 INVALID_SLOT_NUMBER = UINT32_MAX;
2837 // This is used when building the data
2838 struct MethodDataEntry
2841 static const UINT32 INVALID_CHAIN_AND_INDEX = (UINT32)(-1);
2842 static const UINT16 INVALID_IMPL_SLOT_NUM = (UINT16)(-1);
2844 // This contains both the chain delta and the table index. The
2845 // reason that they are combined is that we need atomic update
2846 // of both, and it is convenient that both are on UINT16 in size.
2847 UINT32 m_chainDeltaAndTableIndex;
2848 UINT16 m_implSlotNum; // For virtually remapped slots
2849 DispatchSlot m_slot; // The entry in the DispatchImplTable
2850 MethodDesc *m_pMD; // The MethodDesc for this slot
2853 inline MethodDataEntry() : m_slot(NULL)
2854 { WRAPPER_NO_CONTRACT; Init(); }
2858 LIMITED_METHOD_CONTRACT;
2859 m_chainDeltaAndTableIndex = INVALID_CHAIN_AND_INDEX;
2860 m_implSlotNum = INVALID_IMPL_SLOT_NUM;
2865 inline BOOL IsDeclInit()
2866 { LIMITED_METHOD_CONTRACT; return m_chainDeltaAndTableIndex != INVALID_CHAIN_AND_INDEX; }
2867 inline BOOL IsImplInit()
2868 { LIMITED_METHOD_CONTRACT; return m_implSlotNum != INVALID_IMPL_SLOT_NUM; }
2870 inline void SetDeclData(UINT32 chainDelta, UINT32 tableIndex)
2871 { LIMITED_METHOD_CONTRACT; m_chainDeltaAndTableIndex = ((((UINT16) chainDelta) << 16) | ((UINT16) tableIndex)); }
2872 inline UINT32 GetChainDelta()
2873 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return m_chainDeltaAndTableIndex >> 16; }
2874 inline UINT32 GetTableIndex()
2875 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return (m_chainDeltaAndTableIndex & (UINT32)UINT16_MAX); }
2877 inline void SetImplData(UINT32 implSlotNum)
2878 { LIMITED_METHOD_CONTRACT; m_implSlotNum = (UINT16) implSlotNum; }
2879 inline UINT32 GetImplSlotNum()
2880 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsImplInit()); return m_implSlotNum; }
2882 inline void SetSlot(DispatchSlot slot)
2883 { LIMITED_METHOD_CONTRACT; m_slot = slot; }
2884 inline DispatchSlot GetSlot()
2885 { LIMITED_METHOD_CONTRACT; return m_slot; }
2887 inline void SetMethodDesc(MethodDesc *pMD)
2888 { LIMITED_METHOD_CONTRACT; m_pMD = pMD; }
2889 inline MethodDesc *GetMethodDesc()
2890 { LIMITED_METHOD_CONTRACT; return m_pMD; }
2894 static void ProcessMap(
2895 const DispatchMapTypeID * rgTypeIDs,
2898 UINT32 cCurrentChainDepth,
2899 MethodDataEntry * rgWorkingData,
2900 size_t cWorkingData);
2901 }; // class MethodData
2903 typedef ::Holder < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataHolder;
2904 typedef ::Wrapper < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataWrapper;
2907 //--------------------------------------------------------------------------------------
2908 class MethodDataObject final : public MethodData
2911 // Static method that returns the amount of memory to allocate for a particular type.
2912 static UINT32 GetObjectSize(MethodTable *pMT);
2914 // Constructor. Make sure you have allocated enough memory using GetObjectSize.
2915 inline MethodDataObject(MethodTable *pMT) : MethodData(pMT, pMT)
2916 { WRAPPER_NO_CONTRACT; Init(NULL); }
2918 inline MethodDataObject(MethodTable *pMT, MethodData *pParentData) : MethodData(pMT, pMT)
2919 { WRAPPER_NO_CONTRACT; Init(pParentData); }
2921 virtual ~MethodDataObject() { LIMITED_METHOD_CONTRACT; }
2923 virtual MethodData *GetDeclMethodData()
2924 { LIMITED_METHOD_CONTRACT; return this; }
2925 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
2927 virtual MethodData *GetImplMethodData()
2928 { LIMITED_METHOD_CONTRACT; return this; }
2929 virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
2930 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
2931 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
2932 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
2934 virtual UINT32 GetNumVirtuals()
2935 { LIMITED_METHOD_CONTRACT; return m_pDeclMT->GetNumVirtuals(); }
2936 virtual UINT32 GetNumMethods()
2937 { LIMITED_METHOD_CONTRACT; return m_pDeclMT->GetCanonicalMethodTable()->GetNumMethods(); }
2939 virtual void UpdateImplMethodDesc(MethodDesc* pMD, UINT32 slotNumber);
2942 void Init(MethodData *pParentData);
2944 BOOL PopulateNextLevel();
2946 // This is used in staged map decoding - it indicates which type we will next decode.
2947 UINT32 m_iNextChainDepth;
2948 static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
2950 BOOL m_containsMethodImpl;
2952 // NOTE: Use of these APIs are unlocked and may appear to be erroneous. However, since calls
2953 // to ProcessMap will result in identical values being placed in the MethodDataObjectEntry
2954 // array, it it is not a problem if there is a race, since one thread may just end up
2955 // doing some duplicate work.
2957 inline UINT32 GetNextChainDepth()
2958 { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
2960 inline void SetNextChainDepth(UINT32 iDepth)
2962 LIMITED_METHOD_CONTRACT;
2963 if (GetNextChainDepth() < iDepth) {
2964 VolatileStore(&m_iNextChainDepth, iDepth);
2968 // This is used when building the data
2969 struct MethodDataObjectEntry
2972 MethodDesc *m_pMDDecl;
2973 MethodDesc *m_pMDImpl;
2976 inline MethodDataObjectEntry() : m_pMDDecl(NULL), m_pMDImpl(NULL) {}
2978 inline void SetDeclMethodDesc(MethodDesc *pMD)
2979 { LIMITED_METHOD_CONTRACT; m_pMDDecl = pMD; }
2980 inline MethodDesc *GetDeclMethodDesc()
2981 { LIMITED_METHOD_CONTRACT; return m_pMDDecl; }
2982 inline void SetImplMethodDesc(MethodDesc *pMD)
2983 { LIMITED_METHOD_CONTRACT; m_pMDImpl = pMD; }
2984 inline MethodDesc *GetImplMethodDesc()
2985 { LIMITED_METHOD_CONTRACT; return m_pMDImpl; }
2989 inline MethodDataObjectEntry *GetEntryData()
2990 { LIMITED_METHOD_CONTRACT; return &m_rgEntries[0]; }
2992 inline MethodDataObjectEntry *GetEntry(UINT32 i)
2993 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
2995 void FillEntryDataForAncestor(MethodTable *pMT);
2998 // At the end of this object is an array
3000 MethodDataObjectEntry m_rgEntries[0];
3003 struct TargetMethodTable
3008 static void* operator new(size_t size, TargetMethodTable targetMT)
3010 _ASSERTE(size <= GetObjectSize(targetMT.pMT));
3011 return ::operator new(GetObjectSize(targetMT.pMT));
3013 static void* operator new(size_t size) = delete;
3014 }; // class MethodDataObject
3016 //--------------------------------------------------------------------------------------
3017 class MethodDataInterface : public MethodData
3020 // Static method that returns the amount of memory to allocate for a particular type.
3021 static UINT32 GetObjectSize(MethodTable *pMT)
3022 { LIMITED_METHOD_CONTRACT; return sizeof(MethodDataInterface); }
3024 // Constructor. Make sure you have allocated enough memory using GetObjectSize.
3025 MethodDataInterface(MethodTable *pMT) : MethodData(pMT, pMT)
3027 LIMITED_METHOD_CONTRACT;
3028 CONSISTENCY_CHECK(CheckPointer(pMT));
3029 CONSISTENCY_CHECK(pMT->IsInterface());
3031 virtual ~MethodDataInterface()
3032 { LIMITED_METHOD_CONTRACT; }
3037 virtual MethodData *GetDeclMethodData()
3038 { LIMITED_METHOD_CONTRACT; return this; }
3039 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
3044 virtual MethodData *GetImplMethodData()
3045 { LIMITED_METHOD_CONTRACT; return this; }
3046 virtual DispatchSlot GetImplSlot(UINT32 slotNumber)
3047 { WRAPPER_NO_CONTRACT; return DispatchSlot(m_pDeclMT->GetRestoredSlot(slotNumber)); }
3048 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber)
3049 { LIMITED_METHOD_CONTRACT; return slotNumber; }
3050 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3051 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3056 virtual UINT32 GetNumVirtuals()
3057 { LIMITED_METHOD_CONTRACT; return m_pDeclMT->GetNumVirtuals(); }
3058 virtual UINT32 GetNumMethods()
3059 { LIMITED_METHOD_CONTRACT; return m_pDeclMT->GetNumMethods(); }
3061 virtual void UpdateImplMethodDesc(MethodDesc* pMD, UINT32 slotNumber)
3062 { LIMITED_METHOD_CONTRACT; }
3064 }; // class MethodDataInterface
3066 //--------------------------------------------------------------------------------------
3067 class MethodDataInterfaceImpl final : public MethodData
3070 // Object construction-related methods
3071 static UINT32 GetObjectSize(MethodTable *pMTDecl);
3073 MethodDataInterfaceImpl(
3074 const DispatchMapTypeID * rgDeclTypeIDs,
3075 UINT32 cDeclTypeIDs,
3077 MethodData * pImpl);
3078 virtual ~MethodDataInterfaceImpl();
3080 // Decl-related methods
3081 virtual MethodData *GetDeclMethodData()
3082 { LIMITED_METHOD_CONTRACT; return m_pDecl; }
3083 virtual MethodTable *GetDeclMethodTable()
3084 { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodTable(); }
3085 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber)
3086 { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodDesc(slotNumber); }
3088 // Impl-related methods
3089 virtual MethodData *GetImplMethodData()
3090 { LIMITED_METHOD_CONTRACT; return m_pImpl; }
3091 virtual MethodTable *GetImplMethodTable()
3092 { WRAPPER_NO_CONTRACT; return m_pImpl->GetImplMethodTable(); }
3093 virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
3094 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
3095 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3096 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3098 virtual UINT32 GetNumVirtuals()
3099 { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
3100 virtual UINT32 GetNumMethods()
3101 { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
3103 virtual void UpdateImplMethodDesc(MethodDesc* pMD, UINT32 slotNumber)
3104 { LIMITED_METHOD_CONTRACT; }
3107 UINT32 MapToImplSlotNumber(UINT32 slotNumber);
3109 BOOL PopulateNextLevel();
3111 const DispatchMapTypeID * rgDeclTypeIDs,
3112 UINT32 cDeclTypeIDs,
3114 MethodData * pImpl);
3116 MethodData *m_pDecl;
3117 MethodData *m_pImpl;
3119 // This is used in staged map decoding - it indicates which type(s) we will find.
3120 const DispatchMapTypeID * m_rgDeclTypeIDs;
3121 UINT32 m_cDeclTypeIDs;
3122 UINT32 m_iNextChainDepth;
3123 static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
3125 inline UINT32 GetNextChainDepth()
3126 { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
3128 inline void SetNextChainDepth(UINT32 iDepth)
3130 LIMITED_METHOD_CONTRACT;
3131 if (GetNextChainDepth() < iDepth) {
3132 VolatileStore(&m_iNextChainDepth, iDepth);
3137 // At the end of this object is an array, so you cannot derive from this class.
3140 inline MethodDataEntry *GetEntryData()
3141 { LIMITED_METHOD_CONTRACT; return &m_rgEntries[0]; }
3143 inline MethodDataEntry *GetEntry(UINT32 i)
3144 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
3146 MethodDataEntry m_rgEntries[0];
3149 struct TargetMethodTable
3154 static void* operator new(size_t size, TargetMethodTable targetMT)
3156 _ASSERTE(size <= GetObjectSize(targetMT.pMT));
3157 return ::operator new(GetObjectSize(targetMT.pMT));
3159 static void* operator new(size_t size) = delete;
3160 }; // class MethodDataInterfaceImpl
3162 //--------------------------------------------------------------------------------------
3163 static MethodDataCache *s_pMethodDataCache;
3164 static BOOL s_fUseParentMethodData;
3165 static BOOL s_fUseMethodDataCache;
3168 static void AllowMethodDataCaching()
3169 { WRAPPER_NO_CONTRACT; CheckInitMethodDataCache(); s_fUseMethodDataCache = TRUE; }
3170 static void ClearMethodDataCache();
3171 static void AllowParentMethodDataCopy()
3172 { LIMITED_METHOD_CONTRACT; s_fUseParentMethodData = TRUE; }
3173 // NOTE: The fCanCache argument determines if the resulting MethodData object can
3174 // be added to the global MethodDataCache. This is used when requesting a
3175 // MethodData object for a type currently being built.
3176 static MethodData *GetMethodData(MethodTable *pMT, BOOL fCanCache = TRUE);
3177 static MethodData *GetMethodData(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache = TRUE);
3178 // This method is used by BuildMethodTable because the exact interface has not yet been loaded.
3179 // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
3180 static MethodData * GetMethodData(
3181 const DispatchMapTypeID * rgDeclTypeIDs,
3182 UINT32 cDeclTypeIDs,
3183 MethodTable * pMTDecl,
3184 MethodTable * pMTImpl);
3186 void CopySlotFrom(UINT32 slotNumber, MethodDataWrapper &hSourceMTData, MethodTable *pSourceMT);
3189 static void CheckInitMethodDataCache();
3190 static MethodData *FindParentMethodDataHelper(MethodTable *pMT);
3191 static MethodData *FindMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl);
3192 static MethodData *GetMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache);
3193 // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
3194 static MethodData * GetMethodDataHelper(
3195 const DispatchMapTypeID * rgDeclTypeIDs,
3196 UINT32 cDeclTypeIDs,
3197 MethodTable * pMTDecl,
3198 MethodTable * pMTImpl);
3201 //--------------------------------------------------------------------------------------
3202 class MethodIterator
3205 MethodIterator(MethodTable *pMT);
3206 MethodIterator(MethodTable *pMTDecl, MethodTable *pMTImpl);
3207 MethodIterator(MethodData *pMethodData);
3208 MethodIterator(const MethodIterator &it);
3209 inline ~MethodIterator() { WRAPPER_NO_CONTRACT; m_pMethodData->Release(); }
3210 INT32 GetNumMethods() const;
3211 inline BOOL IsValid() const;
3212 inline BOOL MoveTo(UINT32 idx);
3215 inline void MoveToBegin();
3216 inline void MoveToEnd();
3217 inline UINT32 GetSlotNumber() const;
3218 inline UINT32 GetImplSlotNumber() const;
3219 inline BOOL IsVirtual() const;
3220 inline UINT32 GetNumVirtuals() const;
3221 inline DispatchSlot GetTarget() const;
3223 // Can be called only if IsValid()=TRUE
3224 inline MethodDesc *GetMethodDesc() const;
3225 inline MethodDesc *GetDeclMethodDesc() const;
3228 void Init(MethodTable *pMTDecl, MethodTable *pMTImpl);
3230 MethodData *m_pMethodData;
3231 INT32 m_iCur; // Current logical slot index
3233 }; // class MethodIterator
3234 #endif // !DACCESS_COMPILE
3236 //--------------------------------------------------------------------------------------
3237 // This iterator lets you walk over all the method bodies introduced by this type.
3238 // This includes new static methods, new non-virtual methods, and any overrides
3239 // of the parent's virtual methods. It does not include virtual method implementations
3240 // provided by the parent
3242 class IntroducedMethodIterator
3245 IntroducedMethodIterator(MethodTable *pMT, BOOL restrictToCanonicalTypes = TRUE);
3246 inline BOOL IsValid() const;
3249 // Can be called only if IsValid()=TRUE
3250 inline MethodDesc *GetMethodDesc() const;
3252 // Static worker methods of the iterator. These are meant to be used
3253 // by RuntimeTypeHandle::GetFirstIntroducedMethod and RuntimeTypeHandle::GetNextIntroducedMethod
3254 // only to expose this iterator to managed code.
3255 static MethodDesc * GetFirst(MethodTable * pMT);
3256 static MethodDesc * GetNext(MethodDesc * pMD);
3259 MethodDesc *m_pMethodDesc; // Current method desc
3261 // Cached info about current method desc
3262 MethodDescChunk *m_pChunk;
3265 void SetChunk(MethodDescChunk * pChunk);
3266 }; // class IntroducedMethodIterator
3268 //-------------------------------------------------------------------
3269 // INSTANCE MEMBER VARIABLES
3272 #ifdef DACCESS_COMPILE
3277 enum WFLAGS_LOW_ENUM
3279 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
3280 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
3281 // CARRY THE CORECT FLAGS.
3284 // We are overloading the low 2 bytes of m_dwFlags to be a component size for Strings
3285 // and Arrays and some set of flags which we can be assured are of a specified state
3286 // for Strings / Arrays, currently these will be a bunch of generics flags which don't
3287 // apply to Strings / Arrays.
3289 enum_flag_UNUSED_ComponentSize_1 = 0x00000001,
3291 enum_flag_StaticsMask = 0x00000006,
3292 enum_flag_StaticsMask_NonDynamic = 0x00000000,
3293 enum_flag_StaticsMask_Dynamic = 0x00000002, // dynamic statics (EnC, reflection.emit)
3294 enum_flag_StaticsMask_Generics = 0x00000004, // generics statics
3295 enum_flag_StaticsMask_CrossModuleGenerics = 0x00000006, // cross module generics statics (NGen)
3296 enum_flag_StaticsMask_IfGenericsThenCrossModule = 0x00000002, // helper constant to get rid of unnecessary check
3298 enum_flag_NotInPZM = 0x00000008, // True if this type is not in its PreferredZapModule
3300 enum_flag_GenericsMask = 0x00000030,
3301 enum_flag_GenericsMask_NonGeneric = 0x00000000, // no instantiation
3302 enum_flag_GenericsMask_GenericInst = 0x00000010, // regular instantiation, e.g. List<String>
3303 enum_flag_GenericsMask_SharedInst = 0x00000020, // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
3304 enum_flag_GenericsMask_TypicalInst = 0x00000030, // the type instantiated at its formal parameters, e.g. List<T>
3306 enum_flag_HasVariance = 0x00000100, // This is an instantiated type some of whose type parameters are co- or contra-variant
3308 enum_flag_HasDefaultCtor = 0x00000200,
3309 enum_flag_HasPreciseInitCctors = 0x00000400, // Do we need to run class constructors at allocation time? (Not perf important, could be moved to EEClass
3311 #if defined(FEATURE_HFA)
3312 #if defined(UNIX_AMD64_ABI)
3313 #error "Can't define both FEATURE_HFA and UNIX_AMD64_ABI"
3315 enum_flag_IsHFA = 0x00000800, // This type is an HFA (Homogeneous Floating-point Aggregate)
3316 #endif // FEATURE_HFA
3318 #if defined(UNIX_AMD64_ABI)
3319 #if defined(FEATURE_HFA)
3320 #error "Can't define both FEATURE_HFA and UNIX_AMD64_ABI"
3322 enum_flag_IsRegStructPassed = 0x00000800, // This type is a System V register passed struct.
3323 #endif // UNIX_AMD64_ABI
3325 enum_flag_IsByRefLike = 0x00001000,
3327 // In a perfect world we would fill these flags using other flags that we already have
3328 // which have a constant value for something which has a component size.
3329 enum_flag_UNUSED_ComponentSize_5 = 0x00002000,
3330 enum_flag_UNUSED_ComponentSize_6 = 0x00004000,
3331 enum_flag_UNUSED_ComponentSize_7 = 0x00008000,
3333 #define SET_FALSE(flag) ((flag) & 0)
3334 #define SET_TRUE(flag) ((flag) & 0xffff)
3336 // IMPORTANT! IMPORTANT! IMPORTANT!
3338 // As you change the flags in WFLAGS_LOW_ENUM you also need to change this
3339 // to be up to date to reflect the default values of those flags for the
3340 // case where this MethodTable is for a String or Array
3341 enum_flag_StringArrayValues = SET_TRUE(enum_flag_StaticsMask_NonDynamic) |
3342 SET_FALSE(enum_flag_NotInPZM) |
3343 SET_TRUE(enum_flag_GenericsMask_NonGeneric) |
3344 SET_FALSE(enum_flag_HasVariance) |
3345 SET_FALSE(enum_flag_HasDefaultCtor) |
3346 SET_FALSE(enum_flag_HasPreciseInitCctors),
3348 }; // enum WFLAGS_LOW_ENUM
3350 enum WFLAGS_HIGH_ENUM
3352 // DO NOT use flags that have bits set in the low 2 bytes.
3353 // These flags are DWORD sized so that our atomic masking
3354 // operations can operate on the entire 4-byte aligned DWORD
3355 // instead of the logical non-aligned WORD of flags. The
3356 // low WORD of flags is reserved for the component size.
3358 // The following bits describe mutually exclusive locations of the type
3359 // in the type hierarchy.
3360 enum_flag_Category_Mask = 0x000F0000,
3362 enum_flag_Category_Class = 0x00000000,
3363 enum_flag_Category_Unused_1 = 0x00010000,
3364 enum_flag_Category_Unused_2 = 0x00020000,
3365 enum_flag_Category_Unused_3 = 0x00030000,
3367 enum_flag_Category_ValueType = 0x00040000,
3368 enum_flag_Category_ValueType_Mask = 0x000C0000,
3369 enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType
3370 enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or primitive value type
3371 enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.)
3373 enum_flag_Category_Array = 0x00080000,
3374 enum_flag_Category_Array_Mask = 0x000C0000,
3375 // enum_flag_Category_IfArrayThenUnused = 0x00010000, // sub-category of Array
3376 enum_flag_Category_IfArrayThenSzArray = 0x00020000, // sub-category of Array
3378 enum_flag_Category_Interface = 0x000C0000,
3379 enum_flag_Category_Unused_4 = 0x000D0000,
3380 enum_flag_Category_Unused_5 = 0x000E0000,
3381 enum_flag_Category_Unused_6 = 0x000F0000,
3383 enum_flag_Category_ElementTypeMask = 0x000E0000, // bits that matter for element type mask
3386 enum_flag_HasFinalizer = 0x00100000, // instances require finalization
3388 enum_flag_IDynamicInterfaceCastable = 0x00200000, // class implements IDynamicInterfaceCastable interface
3390 enum_flag_ICastable = 0x00400000, // class implements ICastable interface
3392 enum_flag_Unused_1 = 0x00800000,
3394 enum_flag_ContainsPointers = 0x01000000,
3396 enum_flag_HasTypeEquivalence = 0x02000000, // can be equivalent to another type
3398 enum_flag_IsTrackedReferenceWithFinalizer = 0x04000000,
3400 enum_flag_HasCriticalFinalizer = 0x08000000, // finalizer must be run on Appdomain Unload
3401 enum_flag_Collectible = 0x10000000,
3402 enum_flag_ContainsGenericVariables = 0x20000000, // we cache this flag to help detect these efficiently and
3403 // to detect this condition when restoring
3405 enum_flag_ComObject = 0x40000000, // class is a com object
3407 enum_flag_HasComponentSize = 0x80000000, // This is set if component size is used for flags.
3409 // Types that require non-trivial interface cast have this bit set in the category
3410 enum_flag_NonTrivialInterfaceCast = enum_flag_Category_Array
3411 | enum_flag_ComObject
3412 | enum_flag_ICastable
3413 | enum_flag_IDynamicInterfaceCastable
3414 | enum_flag_Category_ValueType
3416 }; // enum WFLAGS_HIGH_ENUM
3418 // NIDump needs to be able to see these flags
3419 // TODO: figure out how to make these private
3420 #if defined(DACCESS_COMPILE)
3427 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
3428 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
3429 // CARRY THE CORECT FLAGS.
3431 // The following bits describe usage of optional slots. They have to stay
3432 // together because of we index using them into offset arrays.
3433 enum_flag_MultipurposeSlotsMask = 0x001F,
3434 enum_flag_HasPerInstInfo = 0x0001,
3435 enum_flag_HasInterfaceMap = 0x0002,
3436 enum_flag_HasDispatchMapSlot = 0x0004,
3437 enum_flag_HasNonVirtualSlots = 0x0008,
3438 enum_flag_HasModuleOverride = 0x0010,
3443 enum_flag_HasModuleDependencies = 0x0080,
3445 enum_flag_IsIntrinsicType = 0x0100,
3449 enum_flag_HasCctor = 0x0400,
3450 enum_flag_HasVirtualStaticMethods = 0x0800,
3452 #ifdef FEATURE_64BIT_ALIGNMENT
3453 enum_flag_RequiresAlign8 = 0x1000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)
3456 enum_flag_HasBoxedRegularStatics = 0x2000, // GetNumBoxedRegularStatics() != 0
3458 enum_flag_HasSingleNonVirtualSlot = 0x4000,
3461 }; // enum WFLAGS2_ENUM
3463 __forceinline void ClearFlag(WFLAGS_LOW_ENUM flag)
3465 _ASSERTE(!IsStringOrArray());
3468 __forceinline void SetFlag(WFLAGS_LOW_ENUM flag)
3470 _ASSERTE(!IsStringOrArray());
3473 __forceinline DWORD GetFlag(WFLAGS_LOW_ENUM flag) const
3476 return (IsStringOrArray() ? (enum_flag_StringArrayValues & flag) : (m_dwFlags & flag));
3478 __forceinline BOOL TestFlagWithMask(WFLAGS_LOW_ENUM mask, WFLAGS_LOW_ENUM flag) const
3480 LIMITED_METHOD_DAC_CONTRACT;
3481 return (IsStringOrArray() ? (((DWORD)enum_flag_StringArrayValues & (DWORD)mask) == (DWORD)flag) :
3482 ((m_dwFlags & (DWORD)mask) == (DWORD)flag));
3485 __forceinline void ClearFlag(WFLAGS_HIGH_ENUM flag)
3489 __forceinline void SetFlag(WFLAGS_HIGH_ENUM flag)
3493 __forceinline DWORD GetFlag(WFLAGS_HIGH_ENUM flag) const
3495 LIMITED_METHOD_DAC_CONTRACT;
3496 return m_dwFlags & flag;
3498 __forceinline BOOL TestFlagWithMask(WFLAGS_HIGH_ENUM mask, WFLAGS_HIGH_ENUM flag) const
3500 LIMITED_METHOD_DAC_CONTRACT;
3501 return ((m_dwFlags & (DWORD)mask) == (DWORD)flag);
3504 __forceinline void ClearFlag(WFLAGS2_ENUM flag)
3508 __forceinline void SetFlag(WFLAGS2_ENUM flag)
3512 __forceinline DWORD GetFlag(WFLAGS2_ENUM flag) const
3514 LIMITED_METHOD_DAC_CONTRACT;
3515 return m_wFlags2 & flag;
3517 __forceinline BOOL TestFlagWithMask(WFLAGS2_ENUM mask, WFLAGS2_ENUM flag) const
3519 return (m_wFlags2 & (DWORD)mask) == (DWORD)flag;
3523 // Low WORD is component size for array and string types (HasComponentSize() returns true).
3524 // Used for flags otherwise.
3527 // Base size of instance of this class when allocated on the heap
3530 // See WFLAGS2_ENUM for values.
3533 // Class token if it fits into 16-bits. If this is (WORD)-1, the class token is stored in the TokenOverflow optional member.
3536 // <NICE> In the normal cases we shouldn't need a full word for each of these </NICE>
3537 WORD m_wNumVirtuals;
3538 WORD m_wNumInterfaces;
3541 LPCUTF8 debug_m_szClassName;
3544 PTR_MethodTable m_pParentMethodTable;
3546 PTR_Module m_pLoaderModule;
3548 PTR_MethodTableWriteableData m_pWriteableData;
3550 // The value of lowest two bits describe what the union contains
3552 UNION_EECLASS = 0, // 0 - pointer to EEClass. This MethodTable is the canonical method table.
3553 UNION_METHODTABLE = 1, // 1 - pointer to canonical MethodTable.
3555 static const TADDR UNION_MASK = 1;
3558 DPTR(EEClass) m_pEEClass;
3562 __forceinline static LowBits union_getLowBits(TADDR pCanonMT)
3564 LIMITED_METHOD_DAC_CONTRACT;
3565 return LowBits(pCanonMT & UNION_MASK);
3567 __forceinline static TADDR union_getPointer(TADDR pCanonMT)
3569 LIMITED_METHOD_DAC_CONTRACT;
3570 return (pCanonMT & ~UNION_MASK);
3573 // m_pPerInstInfo and m_pInterfaceMap have to be at fixed offsets because of performance sensitive
3574 // JITed code and JIT helpers. However, they are frequently not present. The space is used by other
3575 // multipurpose slots on first come first served basis if the fixed ones are not present. The other
3576 // multipurpose are DispatchMapSlot, NonVirtualSlots, ModuleOverride (see enum_flag_MultipurposeSlotsMask).
3577 // The multipurpose slots that do not fit are stored after vtable slots.
3581 PerInstInfo_t m_pPerInstInfo;
3582 TADDR m_ElementTypeHnd;
3583 TADDR m_pMultipurposeSlot1;
3588 PTR_InterfaceInfo m_pInterfaceMap;
3589 TADDR m_pMultipurposeSlot2;
3592 // VTable and Non-Virtual slots go here
3594 // Overflow multipurpose slots go here
3596 // Optional Members go here
3597 // See above for the list of optional members
3599 // Generic dictionary pointers go here
3601 // Interface map goes here
3603 // Generic instantiation+dictionary goes here
3607 // disallow direct creation
3608 void *operator new(size_t dummy);
3609 void operator delete(void *pData);
3612 // Optional members. These are used for fields in the data structure where
3613 // the fields are (a) known when MT is created and (b) there is a default
3614 // value for the field in the common case. That is, they are normally used
3615 // for data that is only relevant to a small number of method tables.
3617 // Optional members and multipurpose slots have similar purpose, but they differ in details:
3618 // - Multipurpose slots can only accommodate pointer sized structures right now. It is non-trivial
3619 // to add new ones, the access is faster.
3620 // - Optional members can accommodate structures of any size. It is trivial to add new ones,
3621 // the access is slower.
3623 // The following macro will automatically create GetXXX accessors for the optional members.
3624 #define METHODTABLE_OPTIONAL_MEMBERS() \
3625 /* NAME TYPE GETTER */ \
3626 /* Accessing this member efficiently is currently performance critical for static field accesses */ \
3627 /* in generic classes, so place it early in the list. */ \
3628 METHODTABLE_OPTIONAL_MEMBER(GenericsStaticsInfo, GenericsStaticsInfo, GetGenericsStaticsInfo ) \
3629 /* Accessed during x-domain transition only, so place it late in the list. */ \
3630 METHODTABLE_REMOTING_OPTIONAL_MEMBERS() \
3631 /* Accessed during certain generic type load operations only, so low priority */ \
3632 METHODTABLE_OPTIONAL_MEMBER(ExtraInterfaceInfo, TADDR, GetExtraInterfaceInfoPtr ) \
3633 /* TypeDef token for assemblies with more than 64k types. Never happens in real world. */ \
3634 METHODTABLE_OPTIONAL_MEMBER(TokenOverflow, TADDR, GetTokenOverflowPtr ) \
3636 #define METHODTABLE_REMOTING_OPTIONAL_MEMBERS()
3638 enum OptionalMemberId
3640 #undef METHODTABLE_OPTIONAL_MEMBER
3641 #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) OptionalMember_##NAME,
3642 METHODTABLE_OPTIONAL_MEMBERS()
3643 OptionalMember_Count,
3645 OptionalMember_First = OptionalMember_GenericsStaticsInfo,
3648 FORCEINLINE DWORD GetOffsetOfOptionalMember(OptionalMemberId id);
3653 // Public accessor helpers for the optional members of MethodTable
3656 #undef METHODTABLE_OPTIONAL_MEMBER
3657 #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \
3658 inline DPTR(TYPE) GETTER() \
3660 LIMITED_METHOD_CONTRACT; \
3661 _ASSERTE(Has##NAME()); \
3662 return dac_cast<DPTR(TYPE)>(dac_cast<TADDR>(this) + GetOffsetOfOptionalMember(OptionalMember_##NAME)); \
3665 METHODTABLE_OPTIONAL_MEMBERS()
3668 inline DWORD GetStartOffsetOfOptionalMembers()
3670 WRAPPER_NO_CONTRACT;
3671 return GetOffsetOfOptionalMember(OptionalMember_First);
3674 inline DWORD GetEndOffsetOfOptionalMembers()
3676 WRAPPER_NO_CONTRACT;
3677 return GetOffsetOfOptionalMember(OptionalMember_Count);
3680 inline static DWORD GetOptionalMembersAllocationSize(
3681 DWORD dwMultipurposeSlotsMask,
3682 BOOL needsGenericsStaticsInfo,
3683 BOOL needsTokenOverflow);
3684 inline DWORD GetOptionalMembersSize();
3686 // The PerInstInfo is a (possibly empty) array of pointers to
3687 // Instantiations/Dictionaries. This array comes after the optional members.
3688 inline DWORD GetPerInstInfoSize();
3690 // This is the size of the interface map chunk in the method table.
3691 // If the MethodTable has a dynamic interface map then the size includes the pointer
3692 // that stores the extra info for that map.
3693 // The interface map itself comes after the PerInstInfo (if any)
3694 inline DWORD GetInterfaceMapSize();
3696 // The instantiation/dictionary comes at the end of the MethodTable after
3697 // the interface map. This is the total number of bytes used by the dictionary.
3698 // The pSlotSize argument is used to return the size occupied by slots (not including
3699 // the optional back pointer used when expanding dictionaries).
3700 inline DWORD GetInstAndDictSize(DWORD *pSlotSize);
3703 // Helper template to compute the offsets at compile time
3705 struct MultipurposeSlotOffset;
3707 static const BYTE c_DispatchMapSlotOffsets[];
3708 static const BYTE c_NonVirtualSlotsOffsets[];
3709 static const BYTE c_ModuleOverrideOffsets[];
3711 static const BYTE c_OptionalMembersStartOffsets[]; // total sizes of optional slots
3713 TADDR GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const BYTE * offsets);
3715 void SetMultipurposeSlotsMask(DWORD dwMask)
3717 LIMITED_METHOD_CONTRACT;
3718 _ASSERTE((m_wFlags2 & enum_flag_MultipurposeSlotsMask) == 0);
3719 m_wFlags2 |= (WORD)dwMask;
3722 BOOL HasModuleOverride()
3724 LIMITED_METHOD_DAC_CONTRACT;
3725 return GetFlag(enum_flag_HasModuleOverride);
3728 DPTR(PTR_Module) GetModuleOverridePtr()
3730 LIMITED_METHOD_DAC_CONTRACT;
3731 return dac_cast<DPTR(PTR_Module)>(GetMultipurposeSlotPtr(enum_flag_HasModuleOverride, c_ModuleOverrideOffsets));
3734 void SetModule(Module * pModule);
3739 }; // class MethodTable
3741 #ifndef CROSSBITNESS_COMPILE
3742 static_assert_no_msg(sizeof(MethodTable) == SIZEOF__MethodTable_);
3744 #if defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
3745 WORD GetEquivalentMethodSlot(MethodTable * pOldMT, MethodTable * pNewMT, WORD wMTslot, BOOL *pfFound);
3746 #endif // defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
3748 MethodTable* CreateMinimalMethodTable(Module* pContainingModule,
3749 LoaderHeap* pCreationHeap,
3750 AllocMemTracker* pamTracker);
3752 #endif // !_METHODTABLE_H_