1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
12 // ============================================================================
14 #ifndef _METHODTABLE_H_
15 #define _METHODTABLE_H_
26 #ifdef FEATURE_COMINTEROP
27 #include "stdinterfaces.h"
31 #include "typehandle.h"
33 #include "contractimpl.h"
35 #include "fixuppointer.h"
38 * Forward Declarations
42 class ArrayMethodDesc;
43 struct ClassCtorInfoEntry;
45 class DomainLocalBlock;
46 class FCallMethodDesc;
51 struct LayoutRawFieldInfo;
54 class MethodDescChunk;
62 class AllocMemTracker;
64 class MethodDataCache;
65 class EEClassLayoutInfo;
66 #ifdef FEATURE_COMINTEROP
67 class ComCallWrapperTemplate;
69 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
70 class ClassFactoryBase;
71 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
74 //============================================================================
75 // This is the in-memory structure of a class and it will evolve.
76 //============================================================================
80 // Also this class currently has everything public - this may changes
81 // Might also need to hold onto the meta data loader fot this class</TODO>
84 // A MethodTable contains an array of these structures, which describes each interface implemented
85 // by this class (directly declared or indirectly declared).
87 // Generic type instantiations (in C# syntax: C<ty_1,...,ty_n>) are represented by
88 // MethodTables, i.e. a new MethodTable gets allocated for each such instantiation.
89 // The entries in these tables (i.e. the code) are, however, often shared.
91 // In particular, a MethodTable's vtable contents (and hence method descriptors) may be
92 // shared between compatible instantiations (e.g. List<string> and List<object> have
93 // the same vtable *contents*). Likewise the EEClass will be shared between
94 // compatible instantiations whenever the vtable contents are.
96 // !!! Thus that it is _not_ generally the case that GetClass.GetMethodTable() == t. !!!
98 // Instantiated interfaces have their own method tables unique to the instantiation e.g. I<string> is
99 // distinct from I<int> and I<object>
101 // For generic types the interface map lists generic interfaces
102 // For instantiated types the interface map lists instantiated interfaces
103 // e.g. for C<T> : I<T>, J<string>
104 // the interface map for C would list I and J
105 // the interface map for C<int> would list I<int> and J<string>
107 struct InterfaceInfo_t
109 #ifdef DACCESS_COMPILE
110 friend class NativeImageDumper;
113 // Method table of the interface
114 #if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
115 RelativeFixupPointer<PTR_MethodTable> m_pMethodTable;
117 FixupPointer<PTR_MethodTable> m_pMethodTable;
121 FORCEINLINE PTR_MethodTable GetMethodTable()
123 LIMITED_METHOD_CONTRACT;
124 return ReadPointerMaybeNull(this, &InterfaceInfo_t::m_pMethodTable);
127 #ifndef DACCESS_COMPILE
128 void SetMethodTable(MethodTable * pMT)
130 LIMITED_METHOD_CONTRACT;
131 m_pMethodTable.SetValueMaybeNull(pMT);
134 // Get approximate method table. This is used by the type loader before the type is fully loaded.
135 PTR_MethodTable GetApproxMethodTable(Module * pContainingModule);
136 #endif // !DACCESS_COMPILE
138 #ifndef DACCESS_COMPILE
139 InterfaceInfo_t(InterfaceInfo_t &right)
141 m_pMethodTable.SetValueMaybeNull(right.m_pMethodTable.GetValueMaybeNull());
143 #else // !DACCESS_COMPILE
145 InterfaceInfo_t(InterfaceInfo_t &right);
146 #endif // !DACCESS_COMPILE
147 }; // struct InterfaceInfo_t
149 typedef DPTR(InterfaceInfo_t) PTR_InterfaceInfo;
151 namespace ClassCompat
153 struct InterfaceInfo_t;
156 // Data needed when simulating old VTable layout for COM Interop
157 // This is necessary as the data is saved in MethodDescs and we need
158 // to simulate different values without copying or changing the existing
161 // This will be created in a parallel array to ppMethodDescList and
162 // ppUnboxMethodDescList in the bmtMethAndFieldDescs structure below
163 struct InteropMethodTableSlotData
167 e_DUPLICATE = 0x0001 // The entry is duplicate
170 MethodDesc *pMD; // The MethodDesc for this slot
171 WORD wSlot; // The simulated slot value for the MethodDesc
172 WORD wFlags; // The simulated duplicate value
173 MethodDesc *pDeclMD; // To keep track of MethodImpl's
177 wFlags |= e_DUPLICATE;
181 return ((BOOL)(wFlags & e_DUPLICATE));
188 void SetSlot(WORD wSlot) {
191 }; // struct InteropMethodTableSlotData
193 #ifdef FEATURE_COMINTEROP
194 struct InteropMethodTableData
196 WORD cVTable; // Count of vtable slots
197 InteropMethodTableSlotData *pVTable; // Data for each slot
199 WORD cNonVTable; // Count of non-vtable slots
200 InteropMethodTableSlotData *pNonVTable; // Data for each slot
202 WORD cInterfaceMap; // Count of interfaces
203 ClassCompat::InterfaceInfo_t *
204 pInterfaceMap; // The interface map
207 static WORD GetRealMethodDesc(MethodTable *pMT, MethodDesc *pMD);
208 static WORD GetSlotForMethodDesc(MethodTable *pMT, MethodDesc *pMD);
209 ClassCompat::InterfaceInfo_t* FindInterface(MethodTable *pInterface);
210 WORD GetStartSlotForInterface(MethodTable* pInterface);
213 class InteropMethodTableSlotDataMap
216 InteropMethodTableSlotData *m_pSlotData;
221 InteropMethodTableSlotDataMap(InteropMethodTableSlotData *pSlotData, DWORD cSlotData);
222 InteropMethodTableSlotData *GetData(MethodDesc *pMD);
223 BOOL Exists(MethodDesc *pMD);
226 InteropMethodTableSlotData *Exists_Helper(MethodDesc *pMD);
227 InteropMethodTableSlotData *GetNewEntry();
228 }; // class InteropMethodTableSlotDataMap
229 #endif // FEATURE_COMINTEROP
232 // This struct contains cached information on the GUID associated with a type.
237 GUID m_Guid; // The actual guid of the type.
238 BOOL m_bGeneratedFromName; // A boolean indicating if it was generated from the
242 typedef DPTR(GuidInfo) PTR_GuidInfo;
245 // GenericsDictInfo is stored at negative offset of the dictionary
246 struct GenericsDictInfo
249 DWORD m_dwPadding; // Just to keep the size a multiple of 8
252 // Total number of instantiation dictionaries including inherited ones
253 // i.e. how many instantiated classes (including this one) are there in the hierarchy?
254 // See comments about PerInstInfo
257 // Number of type parameters (NOT including those of superclasses).
259 }; // struct GenericsDictInfo
260 typedef DPTR(GenericsDictInfo) PTR_GenericsDictInfo;
262 struct GenericsStaticsInfo
264 // Pointer to field descs for statics
265 RelativePointer<PTR_FieldDesc> m_pFieldDescs;
267 // Method table ID for statics
268 SIZE_T m_DynamicTypeID;
270 }; // struct GenericsStaticsInfo
271 typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo;
274 // CrossModuleGenericsStaticsInfo is used in NGen images for statics of cross-module
275 // generic instantiations. CrossModuleGenericsStaticsInfo is optional member of
276 // MethodTableWriteableData.
277 struct CrossModuleGenericsStaticsInfo
279 // Module this method table statics are attached to.
281 // The statics has to be attached to module referenced from the generic instantiation
282 // in domain-neutral code. We need to guarantee that the module for the statics
283 // has a valid local represenation in an appdomain.
285 PTR_Module m_pModuleForStatics;
287 // Method table ID for statics
288 SIZE_T m_DynamicTypeID;
289 }; // struct CrossModuleGenericsStaticsInfo
290 typedef DPTR(CrossModuleGenericsStaticsInfo) PTR_CrossModuleGenericsStaticsInfo;
292 // This structure records methods and fields which are interesting for VTS
293 // (Version Tolerant Serialization). A pointer to it is optionally appended to
294 // MethodTables with VTS event methods or NotSerialized or OptionallySerialized
295 // fields. The structure is variable length to incorporate a packed array of
296 // data describing the disposition of fields in the type.
297 struct RemotingVtsInfo
301 VTS_CALLBACK_ON_SERIALIZING = 0,
302 VTS_CALLBACK_ON_SERIALIZED,
303 VTS_CALLBACK_ON_DESERIALIZING,
304 VTS_CALLBACK_ON_DESERIALIZED,
305 VTS_NUM_CALLBACK_TYPES
308 FixupPointer<PTR_MethodDesc> m_pCallbacks[VTS_NUM_CALLBACK_TYPES];
312 DWORD m_rFieldTypes[1];
314 static DWORD GetSize(DWORD dwNumFields)
316 LIMITED_METHOD_CONTRACT;
317 // Encode each field in two bits. Round up allocation to the nearest DWORD.
318 DWORD dwBitsRequired = dwNumFields * 2;
319 DWORD dwBytesRequired = (dwBitsRequired + 7) / 8;
320 return (DWORD)(offsetof(RemotingVtsInfo, m_rFieldTypes[0]) + ALIGN_UP(dwBytesRequired, sizeof(DWORD)));
323 void SetIsNotSerialized(DWORD dwFieldIndex)
325 LIMITED_METHOD_CONTRACT;
326 _ASSERTE(dwFieldIndex < m_dwNumFields);
327 DWORD dwRecordIndex = dwFieldIndex * 2;
328 DWORD dwOffset = dwRecordIndex / (sizeof(DWORD) * 8);
329 DWORD dwMask = 1 << (dwRecordIndex % (sizeof(DWORD) * 8));
330 m_rFieldTypes[dwOffset] |= dwMask;
333 BOOL IsNotSerialized(DWORD dwFieldIndex)
335 LIMITED_METHOD_CONTRACT;
336 _ASSERTE(dwFieldIndex < m_dwNumFields);
337 DWORD dwRecordIndex = dwFieldIndex * 2;
338 DWORD dwOffset = dwRecordIndex / (sizeof(DWORD) * 8);
339 DWORD dwMask = 1 << (dwRecordIndex % (sizeof(DWORD) * 8));
340 return m_rFieldTypes[dwOffset] & dwMask;
343 void SetIsOptionallySerialized(DWORD dwFieldIndex)
345 LIMITED_METHOD_CONTRACT;
346 _ASSERTE(dwFieldIndex < m_dwNumFields);
347 DWORD dwRecordIndex = dwFieldIndex * 2;
348 DWORD dwOffset = dwRecordIndex / (sizeof(DWORD) * 8);
349 DWORD dwMask = 2 << (dwRecordIndex % (sizeof(DWORD) * 8));
350 m_rFieldTypes[dwOffset] |= dwMask;
353 BOOL IsOptionallySerialized(DWORD dwFieldIndex)
355 LIMITED_METHOD_CONTRACT;
356 _ASSERTE(dwFieldIndex < m_dwNumFields);
357 DWORD dwRecordIndex = dwFieldIndex * 2;
358 DWORD dwOffset = dwRecordIndex / (sizeof(DWORD) * 8);
359 DWORD dwMask = 2 << (dwRecordIndex % (sizeof(DWORD) * 8));
360 return m_rFieldTypes[dwOffset] & dwMask;
362 }; // struct RemotingVtsInfo
363 typedef DPTR(RemotingVtsInfo) PTR_RemotingVtsInfo;
366 struct ContextStaticsBucket
368 // Offset which points to the CLS storage. Allocated lazily - -1 means no offset allocated yet.
369 DWORD m_dwContextStaticsOffset;
370 // Size of CLS fields
371 WORD m_wContextStaticsSize;
373 typedef DPTR(ContextStaticsBucket) PTR_ContextStaticsBucket;
375 #ifdef FEATURE_COMINTEROP
376 struct RCWPerTypeData;
377 #endif // FEATURE_COMINTEROP
380 // This struct consolidates the writeable parts of the MethodTable
381 // so that we can layout a read-only MethodTable with a pointer
382 // to the writeable parts of the MethodTable in an ngen image
384 struct MethodTableWriteableData
386 friend class MethodTable;
387 #if defined(DACCESS_COMPILE)
388 friend class NativeImageDumper;
393 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
394 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
395 // CARRY THE CORRECT INITIAL FLAGS.
397 enum_flag_RemotingConfigChecked = 0x00000001,
398 enum_flag_RequiresManagedActivation = 0x00000002,
399 enum_flag_Unrestored = 0x00000004,
400 enum_flag_CriticalTypePrepared = 0x00000008, // CriticalFinalizerObject derived type has had backout routines prepared
401 enum_flag_HasApproxParent = 0x00000010,
402 enum_flag_UnrestoredTypeKey = 0x00000020,
403 enum_flag_IsNotFullyLoaded = 0x00000040,
404 enum_flag_DependenciesLoaded = 0x00000080, // class and all depedencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED
406 enum_flag_SkipWinRTOverride = 0x00000100, // No WinRT override is needed
408 #ifdef FEATURE_PREJIT
409 // These flags are used only at ngen time. We store them here since
410 // we are running out of available flags in MethodTable. They may eventually
411 // go into ngen speficic state.
412 enum_flag_NGEN_IsFixedUp = 0x00010000, // This MT has been fixed up during NGEN
413 enum_flag_NGEN_IsNeedsRestoreCached = 0x00020000, // Set if we have cached the results of needs restore computation
414 enum_flag_NGEN_CachedNeedsRestore = 0x00040000, // The result of the needs restore computation
415 enum_flag_NGEN_OverridingInterface = 0x00080000, // Overriding interface that we should generate WinRT CCW stubs for.
417 #ifdef FEATURE_READYTORUN_COMPILER
418 enum_flag_NGEN_IsLayoutFixedComputed = 0x0010000, // Set if we have cached the result of IsLayoutFixed computation
419 enum_flag_NGEN_IsLayoutFixed = 0x0020000, // The result of the IsLayoutFixed computation
422 #endif // FEATURE_PREJIT
425 enum_flag_ParentMethodTablePointerValid = 0x40000000,
426 enum_flag_HasInjectedInterfaceDuplicates = 0x80000000,
429 DWORD m_dwFlags; // Lot of empty bits here.
432 * m_hExposedClassObject is LoaderAllocator slot index to
433 * a RuntimeType instance for this class.
435 LOADERHANDLE m_hExposedClassObject;
438 // to avoid verify same method table too many times when it's not changing, we cache the GC count
439 // on which the method table is verified. When fast GC STRESS is turned on, we only verify the MT if
440 // current GC count is bigger than the number. Note most thing which will invalidate a MT will require a
441 // GC (like AD unload)
442 Volatile<DWORD> m_dwLastVerifedGCCnt;
445 DWORD m_dwPadding; // Just to keep the size a multiple of 8
450 // Optional CrossModuleGenericsStaticsInfo may be here.
454 inline BOOL IsParentMethodTablePointerValid() const
456 LIMITED_METHOD_DAC_CONTRACT;
458 return (m_dwFlags & enum_flag_ParentMethodTablePointerValid);
460 inline void SetParentMethodTablePointerValid()
462 LIMITED_METHOD_CONTRACT;
464 m_dwFlags |= enum_flag_ParentMethodTablePointerValid;
468 #ifdef FEATURE_PREJIT
470 void Save(DataImage *image, MethodTable *pMT, DWORD profilingFlags) const;
471 void Fixup(DataImage *image, MethodTable *pMT, BOOL needsRestore);
473 inline BOOL IsFixedUp() const
475 LIMITED_METHOD_CONTRACT;
477 return (m_dwFlags & enum_flag_NGEN_IsFixedUp);
479 inline void SetFixedUp()
481 LIMITED_METHOD_CONTRACT;
483 m_dwFlags |= enum_flag_NGEN_IsFixedUp;
486 inline BOOL IsNeedsRestoreCached() const
488 LIMITED_METHOD_CONTRACT;
490 return (m_dwFlags & enum_flag_NGEN_IsNeedsRestoreCached);
493 inline BOOL GetCachedNeedsRestore() const
495 LIMITED_METHOD_CONTRACT;
497 _ASSERTE(IsNeedsRestoreCached());
498 return (m_dwFlags & enum_flag_NGEN_CachedNeedsRestore);
501 inline void SetCachedNeedsRestore(BOOL fNeedsRestore)
503 LIMITED_METHOD_CONTRACT;
505 _ASSERTE(!IsNeedsRestoreCached());
506 m_dwFlags |= enum_flag_NGEN_IsNeedsRestoreCached;
507 if (fNeedsRestore) m_dwFlags |= enum_flag_NGEN_CachedNeedsRestore;
510 inline void SetIsOverridingInterface()
520 if ((m_dwFlags & enum_flag_NGEN_OverridingInterface) != 0) return;
521 FastInterlockOr(EnsureWritablePages((ULONG *) &m_dwFlags), enum_flag_NGEN_OverridingInterface);
524 inline BOOL IsOverridingInterface() const
526 LIMITED_METHOD_CONTRACT;
527 return (m_dwFlags & enum_flag_NGEN_OverridingInterface);
529 #endif // FEATURE_PREJIT
531 inline BOOL IsRemotingConfigChecked() const
533 LIMITED_METHOD_CONTRACT;
534 return m_dwFlags & enum_flag_RemotingConfigChecked;
536 inline void SetRemotingConfigChecked()
539 // remembers that we went through the rigorous
540 // checks to decide whether this class should be
541 // activated locally or remote
542 FastInterlockOr(EnsureWritablePages((ULONG *)&m_dwFlags), enum_flag_RemotingConfigChecked);
544 inline void TrySetRemotingConfigChecked()
547 // remembers that we went through the rigorous
548 // checks to decide whether this class should be
549 // activated locally or remote
550 if (EnsureWritablePagesNoThrow(&m_dwFlags, sizeof(m_dwFlags)))
551 FastInterlockOr((ULONG *)&m_dwFlags, enum_flag_RemotingConfigChecked);
553 inline BOOL RequiresManagedActivation() const
555 LIMITED_METHOD_CONTRACT;
556 return m_dwFlags & enum_flag_RequiresManagedActivation;
558 inline void SetRequiresManagedActivation()
561 FastInterlockOr(EnsureWritablePages((ULONG *) &m_dwFlags), enum_flag_RequiresManagedActivation|enum_flag_RemotingConfigChecked);
564 inline LOADERHANDLE GetExposedClassObjectHandle() const
566 LIMITED_METHOD_CONTRACT;
567 return m_hExposedClassObject;
570 void SetIsNotFullyLoadedForBuildMethodTable()
572 LIMITED_METHOD_CONTRACT;
574 // Used only during method table initialization - no need for logging or Interlocked Exchange.
575 m_dwFlags |= (MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
576 MethodTableWriteableData::enum_flag_Unrestored |
577 MethodTableWriteableData::enum_flag_IsNotFullyLoaded |
578 MethodTableWriteableData::enum_flag_HasApproxParent);
581 void SetIsRestoredForBuildMethodTable()
583 LIMITED_METHOD_CONTRACT;
585 // Used only during method table initialization - no need for logging or Interlocked Exchange.
586 m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
587 MethodTableWriteableData::enum_flag_Unrestored);
590 void SetIsFullyLoadedForBuildMethodTable()
592 LIMITED_METHOD_CONTRACT;
594 // Used only during method table initialization - no need for logging or Interlocked Exchange.
595 m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
596 MethodTableWriteableData::enum_flag_Unrestored |
597 MethodTableWriteableData::enum_flag_IsNotFullyLoaded |
598 MethodTableWriteableData::enum_flag_HasApproxParent);
601 // Have the backout methods (Finalizer, Dispose, ReleaseHandle etc.) been prepared for this type? This currently only happens
602 // for types derived from CriticalFinalizerObject.
603 inline BOOL CriticalTypeHasBeenPrepared() const
605 LIMITED_METHOD_CONTRACT;
606 return m_dwFlags & enum_flag_CriticalTypePrepared;
608 inline void SetCriticalTypeHasBeenPrepared()
611 FastInterlockOr(EnsureWritablePages((ULONG*)&m_dwFlags), enum_flag_CriticalTypePrepared);
614 inline CrossModuleGenericsStaticsInfo * GetCrossModuleGenericsStaticsInfo()
616 LIMITED_METHOD_DAC_CONTRACT;
618 SIZE_T size = sizeof(MethodTableWriteableData);
619 return PTR_CrossModuleGenericsStaticsInfo(dac_cast<TADDR>(this) + size);
622 }; // struct MethodTableWriteableData
624 typedef DPTR(MethodTableWriteableData) PTR_MethodTableWriteableData;
625 typedef DPTR(MethodTableWriteableData const) PTR_Const_MethodTableWriteableData;
627 #ifdef FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF
629 SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeType)
631 static const SystemVClassificationType toSystemVAmd64ClassificationTypeMap[] = {
632 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_END
633 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VOID
634 SystemVClassificationTypeInteger, // ELEMENT_TYPE_BOOLEAN
635 SystemVClassificationTypeInteger, // ELEMENT_TYPE_CHAR
636 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I1
637 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U1
638 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I2
639 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U2
640 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I4
641 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U4
642 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I8
643 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U8
644 SystemVClassificationTypeSSE, // ELEMENT_TYPE_R4
645 SystemVClassificationTypeSSE, // ELEMENT_TYPE_R8
646 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_STRING
647 SystemVClassificationTypeInteger, // ELEMENT_TYPE_PTR
648 SystemVClassificationTypeIntegerByRef, // ELEMENT_TYPE_BYREF
649 SystemVClassificationTypeStruct, // ELEMENT_TYPE_VALUETYPE
650 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_CLASS
651 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_VAR (type variable)
652 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_ARRAY
653 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_GENERICINST
654 SystemVClassificationTypeTypedReference, // ELEMENT_TYPE_TYPEDBYREF
655 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED
656 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I
657 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U
658 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_R_UNSUPPORTED
660 // put the correct type when we know our implementation
661 SystemVClassificationTypeInteger, // ELEMENT_TYPE_FNPTR
662 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_OBJECT
663 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_SZARRAY
664 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_MVAR
666 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_REQD
667 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_OPT
668 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_INTERNAL
671 _ASSERTE(sizeof(toSystemVAmd64ClassificationTypeMap) == ELEMENT_TYPE_MAX);
672 _ASSERTE(eeType < (CorElementType) sizeof(toSystemVAmd64ClassificationTypeMap));
673 // spot check of the map
674 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_I4] == SystemVClassificationTypeInteger);
675 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_PTR] == SystemVClassificationTypeInteger);
676 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_VALUETYPE] == SystemVClassificationTypeStruct);
677 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_TYPEDBYREF] == SystemVClassificationTypeTypedReference);
678 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_BYREF] == SystemVClassificationTypeIntegerByRef);
680 return (((unsigned)eeType) < ELEMENT_TYPE_MAX) ? (toSystemVAmd64ClassificationTypeMap[(unsigned)eeType]) : SystemVClassificationTypeUnknown;
683 #define SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES 8 // Size of an eightbyte in bytes.
684 #define SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT 16 // Maximum number of fields in struct passed in registers
686 struct SystemVStructRegisterPassingHelper
688 SystemVStructRegisterPassingHelper(unsigned int totalStructSize) :
689 structSize(totalStructSize),
691 inEmbeddedStruct(false),
692 currentUniqueOffsetField(0),
693 largestFieldOffset(-1)
695 for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
697 eightByteClassifications[i] = SystemVClassificationTypeNoClass;
698 eightByteSizes[i] = 0;
699 eightByteOffsets[i] = 0;
702 // Initialize the work arrays
703 for (int i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++)
705 fieldClassifications[i] = SystemVClassificationTypeNoClass;
712 unsigned int structSize;
714 // These fields are the output; these are what is computed by the classification algorithm.
715 unsigned int eightByteCount;
716 SystemVClassificationType eightByteClassifications[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
717 unsigned int eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
718 unsigned int eightByteOffsets[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
720 // Helper members to track state.
721 bool inEmbeddedStruct;
722 unsigned int currentUniqueOffsetField; // A virtual field that could encompass many overlapping fields.
723 int largestFieldOffset;
724 SystemVClassificationType fieldClassifications[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
725 unsigned int fieldSizes[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
726 unsigned int fieldOffsets[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
729 typedef DPTR(SystemVStructRegisterPassingHelper) SystemVStructRegisterPassingHelperPtr;
731 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF
733 //===============================================================================================
735 // GC data appears before the beginning of the MethodTable
738 // Each generic type has a corresponding "generic" method table that serves the following
740 // * The method table pointer is used as a representative for the generic type e.g. in reflection
741 // * MethodDescs for methods in the vtable are used for reflection; they should never be invoked.
742 // Some other information (e.g. BaseSize) makes no sense "generically" but unfortunately gets put in anyway.
744 // Each distinct instantiation of a generic type has its own MethodTable structure.
745 // However, the EEClass structure can be shared between compatible instantiations e.g. List<string> and List<object>.
746 // In that case, MethodDescs are also shared between compatible instantiations (but see below about generic methods).
747 // Hence the vtable entries for MethodTables belonging to such an EEClass are the same.
749 // The non-vtable section of such MethodTables are only present for one of the instantiations (the first one
750 // requested) as non-vtable entries are never accessed through the vtable pointer of an object so it's always possible
751 // to ensure that they are accessed through the representative MethodTable that contains them.
753 // A MethodTable is the fundamental representation of type in the runtime. It is this structure that
754 // objects point at (see code:Object). It holds the size and GC layout of the type, as well as the dispatch table
755 // for virtual dispach (but not interface dispatch). There is a distinct method table for every instance of
756 // a generic type. From here you can get to
761 // * code:MethodTable.m_pEEClass - pointer to the cold part of the type.
762 // * code:MethodTable.m_pParentMethodTable - the method table of the parent type.
764 class MethodTableBuilder;
767 /************************************
769 ************************************/
770 // DO NOT ADD FRIENDS UNLESS ABSOLUTELY NECESSARY
771 // USE ACCESSORS TO READ/WRITE private field members
773 // Special access for setting up String object method table correctly
774 friend class ClassLoader;
775 friend class JIT_TrialAlloc;
777 friend class EEClass;
778 friend class MethodTableBuilder;
779 friend class CheckAsmOffsets;
780 #if defined(DACCESS_COMPILE)
781 friend class NativeImageDumper;
785 // Do some sanity checking to make sure it's a method table
786 // and not pointing to some random memory. In particular
787 // check that (apart from the special case of instantiated generic types) we have
788 // GetCanonicalMethodTable() == this;
791 static void CallFinalizer(Object *obj);
794 PTR_Module GetModule();
795 PTR_Module GetModule_NoLogging();
796 Assembly *GetAssembly();
798 PTR_Module GetModuleIfLoaded();
800 // GetDomain on an instantiated type, e.g. C<ty1,ty2> returns the SharedDomain if all the
801 // constituent parts of the type are SharedDomain (i.e. domain-neutral),
802 // and returns an AppDomain if any of the parts are from an AppDomain,
803 // i.e. are domain-bound. Note that if any of the parts are domain-bound
804 // then they will all belong to the same domain.
805 PTR_BaseDomain GetDomain();
807 // Does this immediate item live in an NGEN module?
810 // For types that are part of an ngen-ed assembly this gets the
811 // Module* that contains this methodtable.
812 PTR_Module GetZapModule();
814 // For regular, non-constructed types, GetLoaderModule() == GetModule()
815 // For constructed types (e.g. int[], Dict<int[], C>) the hash table through which a type
816 // is accessed lives in a "loader module". The rule for determining the loader module must ensure
817 // that a type never outlives its loader module with respect to app-domain unloading
819 // GetModuleForStatics() is the third kind of module. GetModuleForStatics() is module that
820 // statics are attached to.
821 PTR_Module GetLoaderModule();
822 PTR_LoaderAllocator GetLoaderAllocator();
824 void SetLoaderModule(Module* pModule);
825 void SetLoaderAllocator(LoaderAllocator* pAllocator);
827 // Get the domain local module - useful for static init checks
828 PTR_DomainLocalModule GetDomainLocalModule(AppDomain * pAppDomain);
830 #ifndef DACCESS_COMPILE
831 // Version of GetDomainLocalModule which relies on the current AppDomain
832 PTR_DomainLocalModule GetDomainLocalModule();
835 // Return whether the type lives in the shared domain.
836 BOOL IsDomainNeutral();
838 MethodTable *LoadEnclosingMethodTable(ClassLoadLevel targetLevel = CLASS_DEPENDENCIES_LOADED);
840 LPCWSTR GetPathForErrorMessages();
842 //-------------------------------------------------------------------
845 BOOL IsProjectedFromWinRT();
846 BOOL IsExportedToWinRT();
847 BOOL IsWinRTDelegate();
848 BOOL IsWinRTRedirectedInterface(TypeHandle::InteropKind interopKind);
849 BOOL IsWinRTRedirectedDelegate();
851 #ifdef FEATURE_COMINTEROP
852 TypeHandle GetCoClassForInterface();
855 TypeHandle SetupCoClassForInterface();
858 DWORD IsComClassInterface();
860 // Retrieves the COM interface type.
861 CorIfaceAttr GetComInterfaceType();
862 void SetComInterfaceType(CorIfaceAttr ItfType);
864 // Determines whether this is a WinRT-legal type
865 BOOL IsLegalWinRTType(OBJECTREF *poref);
867 // Determines whether this is a WinRT-legal type - don't use it with array
868 BOOL IsLegalNonArrayWinRTType();
870 MethodTable *GetDefaultWinRTInterface();
872 OBJECTHANDLE GetOHDelegate();
873 void SetOHDelegate (OBJECTHANDLE _ohDelegate);
875 CorClassIfaceAttr GetComClassInterfaceType();
876 TypeHandle GetDefItfForComClassItf();
878 void GetEventInterfaceInfo(MethodTable **ppSrcItfType, MethodTable **ppEvProvType);
880 BOOL IsExtensibleRCW();
882 // mark the class type as COM object class
883 void SetComObjectType();
885 #if defined(FEATURE_TYPEEQUIVALENCE)
886 // mark the type as opted into type equivalence
887 void SetHasTypeEquivalence();
890 // Helper to get parent class skipping over COM class in
892 MethodTable* GetComPlusParentMethodTable();
894 // class is a com object class
895 BOOL IsComObjectType()
897 LIMITED_METHOD_DAC_CONTRACT;
898 return GetFlag(enum_flag_ComObject);
900 // class is a WinRT object class (is itself or derives from a ProjectedFromWinRT class)
901 BOOL IsWinRTObjectType();
905 // class is a special COM event interface
906 int IsComEventItfType();
908 //-------------------------------------------------------------------
909 // Sparse VTables. These require a SparseVTableMap in the EEClass in
910 // order to record how the CLR's vtable slots map across to COM
913 int IsSparseForCOMInterop();
915 // COM interop helpers
916 // accessors for m_pComData
917 ComCallWrapperTemplate *GetComCallWrapperTemplate();
918 BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate);
919 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
920 ClassFactoryBase *GetComClassFactory();
921 BOOL SetComClassFactory(ClassFactoryBase *pFactory);
922 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
924 OBJECTREF GetObjCreateDelegate();
925 void SetObjCreateDelegate(OBJECTREF orDelegate);
928 // This is for COM Interop backwards compatibility
929 BOOL InsertComInteropData(InteropMethodTableData *pData);
930 InteropMethodTableData *CreateComInteropData(AllocMemTracker *pamTracker);
933 InteropMethodTableData *LookupComInteropData();
934 // This is the preferable entrypoint, as it will make sure that all
935 // parent MT's have their interop data created, and will create and
936 // add this MT's data if not available. The caller should make sure that
937 // an appropriate lock is taken to prevent duplicates.
938 // NOTE: The current caller of this is ComInterop, and it makes calls
939 // under its own lock to ensure not duplicates.
940 InteropMethodTableData *GetComInteropData();
942 #else // !FEATURE_COMINTEROP
943 BOOL IsComObjectType()
948 BOOL IsWinRTObjectType()
950 LIMITED_METHOD_CONTRACT;
953 #endif // !FEATURE_COMINTEROP
955 #ifdef FEATURE_ICASTABLE
959 BOOL IsICastable(); // This type implements ICastable interface
961 #ifdef FEATURE_TYPEEQUIVALENCE
962 // type has opted into type equivalence or is instantiated by/derived from a type that is
963 BOOL HasTypeEquivalence()
965 LIMITED_METHOD_CONTRACT;
966 return GetFlag(enum_flag_HasTypeEquivalence);
969 BOOL HasTypeEquivalence()
971 LIMITED_METHOD_CONTRACT;
976 //-------------------------------------------------------------------
977 // DYNAMIC ADDITION OF INTERFACES FOR COM INTEROP
979 // Support for dynamically added interfaces on extensible RCW's.
981 #ifdef FEATURE_COMINTEROP
982 PTR_InterfaceInfo GetDynamicallyAddedInterfaceMap();
983 unsigned GetNumDynamicallyAddedInterfaces();
984 BOOL FindDynamicallyAddedInterface(MethodTable *pInterface);
985 void AddDynamicInterface(MethodTable *pItfMT);
987 BOOL HasDynamicInterfaceMap()
989 LIMITED_METHOD_DAC_CONTRACT;
991 // currently all ComObjects except
992 // for __ComObject have dynamic Interface maps
993 return GetNumInterfaces() > 0 && IsComObjectType() && !ParentEquals(g_pObjectClass);
995 #endif // FEATURE_COMINTEROP
997 BOOL IsIntrospectionOnly();
999 // Checks this type and its instantiation for "IsIntrospectionOnly"
1000 BOOL ContainsIntrospectionOnlyTypes();
1002 #ifndef DACCESS_COMPILE
1003 VOID EnsureActive();
1004 VOID EnsureInstanceActive();
1007 CHECK CheckActivated();
1008 CHECK CheckInstanceActivated();
1010 //-------------------------------------------------------------------
1011 // THE DEFAULT CONSTRUCTOR
1015 BOOL HasDefaultConstructor();
1016 void SetHasDefaultConstructor();
1017 WORD GetDefaultConstructorSlot();
1018 MethodDesc *GetDefaultConstructor();
1020 BOOL HasExplicitOrImplicitPublicDefaultConstructor();
1022 //-------------------------------------------------------------------
1023 // THE CLASS INITIALIZATION CONDITION
1024 // (and related DomainLocalBlock/DomainLocalModule storage)
1026 // - populate the DomainLocalModule if needed
1032 // checks whether the class initialiser should be run on this class, and runs it if necessary
1033 void CheckRunClassInitThrowing();
1035 // checks whether or not the non-beforefieldinit class initializers have been run for all types in this type's
1036 // inheritance hierarchy, and runs them if necessary. This simulates the behavior of running class constructors
1037 // during object construction.
1038 void CheckRunClassInitAsIfConstructingThrowing();
1040 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
1041 // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
1042 bool ClassifyEightBytes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
1043 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
1045 // Copy m_dwFlags from another method table
1046 void CopyFlags(MethodTable * pOldMT)
1048 LIMITED_METHOD_CONTRACT;
1049 m_dwFlags = pOldMT->m_dwFlags;
1050 m_wFlags2 = pOldMT->m_wFlags2;
1053 // Init the m_dwFlags field for an array
1054 void SetIsArray(CorElementType arrayType, CorElementType elementType);
1056 BOOL IsClassPreInited();
1058 // mark the class as having its cctor run.
1059 #ifndef DACCESS_COMPILE
1060 void SetClassInited();
1061 BOOL IsClassInited(AppDomain* pAppDomain = NULL);
1064 void SetClassInitError();
1067 inline BOOL IsGlobalClass()
1069 WRAPPER_NO_CONTRACT;
1070 return (GetTypeDefRid() == RidFromToken(COR_GLOBAL_PARENT_TOKEN));
1073 // uniquely identifes this type in the Domain table
1074 DWORD GetClassIndex();
1076 bool ClassRequiresUnmanagedCodeCheck();
1080 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
1081 void AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel) const;
1082 // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
1083 bool ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
1084 bool ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
1085 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING_ITF)
1087 DWORD GetClassIndexFromToken(mdTypeDef typeToken)
1089 LIMITED_METHOD_CONTRACT;
1090 return RidFromToken(typeToken) - 1;
1093 // called from CheckRunClassInitThrowing(). The type wasn't marked as
1094 // inited while we were there, so let's attempt to do the work.
1095 void DoRunClassInitThrowing();
1097 BOOL RunClassInitEx(OBJECTREF *pThrowable);
1100 //-------------------------------------------------------------------
1101 // THE CLASS CONSTRUCTOR
1104 MethodDesc * GetClassConstructor();
1106 BOOL HasClassConstructor();
1107 void SetHasClassConstructor();
1108 WORD GetClassConstructorSlot();
1109 void SetClassConstructorSlot (WORD wCCtorSlot);
1111 ClassCtorInfoEntry* GetClassCtorInfoIfExists();
1114 void GetSavedExtent(TADDR *ppStart, TADDR *ppEnd);
1116 //-------------------------------------------------------------------
1117 // Save/Fixup/Restore/NeedsRestore
1119 // Restore this method table if it's not already restored
1120 // This is done by forcing a class load which in turn calls the Restore method
1121 // The pending list is required for restoring types that reference themselves through
1122 // instantiations of the superclass or interfaces e.g. System.Int32 : IComparable<System.Int32>
1125 #ifdef FEATURE_PREJIT
1127 void Save(DataImage *image, DWORD profilingFlags);
1128 void Fixup(DataImage *image);
1130 // This is different from !IsRestored() in that it checks if restoring
1131 // will ever be needed for this ngened data-structure.
1132 // This is to be used at ngen time of a dependent module to determine
1133 // if it can be accessed directly, or if the restoring mechanism needs
1135 BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited);
1137 BOOL NeedsRestore(DataImage *image)
1139 WRAPPER_NO_CONTRACT;
1140 return ComputeNeedsRestore(image, NULL);
1144 BOOL ComputeNeedsRestoreWorker(DataImage *image, TypeHandleList *pVisited);
1147 // This returns true at NGen time if we can eager bind to all dictionaries along the inheritance chain
1148 BOOL CanEagerBindToParentDictionaries(DataImage *image, TypeHandleList *pVisited);
1150 // This returns true at NGen time if we may need to attach statics to
1151 // other module than current loader module at runtime
1152 BOOL NeedsCrossModuleGenericsStaticsInfo();
1154 // Returns true at NGen time if we may need to write into the MethodTable at runtime
1157 #endif // FEATURE_PREJIT
1159 void AllocateRegularStaticBoxes();
1160 static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0);
1162 void CheckRestore();
1164 // Perform restore actions on type key components of method table (EEClass pointer + Module, generic args)
1165 void DoRestoreTypeKey();
1167 inline BOOL HasUnrestoredTypeKey() const
1169 LIMITED_METHOD_DAC_CONTRACT;
1171 return !IsPreRestored() &&
1172 (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey) != 0;
1175 // Actually do the restore actions on the method table
1178 void SetIsRestored();
1180 inline BOOL IsRestored_NoLogging()
1182 LIMITED_METHOD_DAC_CONTRACT;
1184 // If we are prerestored then we are considered a restored methodtable.
1185 // Note that IsPreRestored is always false for jitted code.
1186 if (IsPreRestored())
1189 return !(GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
1191 inline BOOL IsRestored()
1193 LIMITED_METHOD_DAC_CONTRACT;
1195 g_IBCLogger.LogMethodTableAccess(this);
1197 // If we are prerestored then we are considered a restored methodtable.
1198 // Note that IsPreRestored is always false for jitted code.
1199 if (IsPreRestored())
1202 return !(GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
1205 //-------------------------------------------------------------------
1208 // The load level of a method table is derived from various flag bits
1209 // See classloadlevel.h for details of each level
1211 // Level CLASS_LOADED (fully loaded) is special: a type only
1212 // reaches this level once all of its dependent types are also at
1213 // this level (generic arguments, parent, interfaces, etc).
1214 // Fully loading a type to this level is done outside locks, hence the need for
1215 // a single atomic action that sets the level.
1217 inline void SetIsFullyLoaded()
1227 PRECONDITION(!HasApproxParent());
1228 PRECONDITION(IsRestored_NoLogging());
1230 FastInterlockAnd(EnsureWritablePages(&GetWriteableDataForWrite()->m_dwFlags), ~MethodTableWriteableData::enum_flag_IsNotFullyLoaded);
1233 // Equivalent to GetLoadLevel() == CLASS_LOADED
1234 inline BOOL IsFullyLoaded()
1236 WRAPPER_NO_CONTRACT;
1238 return (IsPreRestored())
1239 || (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded) == 0;
1242 inline BOOL IsSkipWinRTOverride()
1244 LIMITED_METHOD_CONTRACT;
1245 return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_SkipWinRTOverride);
1248 inline void SetSkipWinRTOverride()
1250 WRAPPER_NO_CONTRACT;
1251 FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite_NoLogging()->m_dwFlags), MethodTableWriteableData::enum_flag_SkipWinRTOverride);
1254 inline void SetIsDependenciesLoaded()
1264 PRECONDITION(!HasApproxParent());
1265 PRECONDITION(IsRestored_NoLogging());
1267 FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite()->m_dwFlags), MethodTableWriteableData::enum_flag_DependenciesLoaded);
1270 inline ClassLoadLevel GetLoadLevel()
1272 LIMITED_METHOD_DAC_CONTRACT;
1274 g_IBCLogger.LogMethodTableAccess(this);
1276 // Fast path for zapped images
1277 if (IsPreRestored())
1278 return CLASS_LOADED;
1280 DWORD dwFlags = GetWriteableData()->m_dwFlags;
1282 if (dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded)
1284 if (dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey)
1285 return CLASS_LOAD_UNRESTOREDTYPEKEY;
1287 if (dwFlags & MethodTableWriteableData::enum_flag_Unrestored)
1288 return CLASS_LOAD_UNRESTORED;
1290 if (dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent)
1291 return CLASS_LOAD_APPROXPARENTS;
1293 if (!(dwFlags & MethodTableWriteableData::enum_flag_DependenciesLoaded))
1294 return CLASS_LOAD_EXACTPARENTS;
1296 return CLASS_DEPENDENCIES_LOADED;
1299 return CLASS_LOADED;
1303 CHECK CheckLoadLevel(ClassLoadLevel level)
1305 LIMITED_METHOD_CONTRACT;
1306 return TypeHandle(this).CheckLoadLevel(level);
1311 void DoFullyLoad(Generics::RecursionGraph * const pVisited, const ClassLoadLevel level, DFLPendingList * const pPending, BOOL * const pfBailed,
1312 const InstantiationContext * const pInstContext);
1314 //-------------------------------------------------------------------
1315 // METHOD TABLES AS TYPE DESCRIPTORS
1317 // A MethodTable can represeent a type such as "String" or an
1318 // instantiated type such as "List<String>".
1321 inline BOOL IsInterface()
1323 LIMITED_METHOD_DAC_CONTRACT;
1324 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Interface;
1327 void SetIsInterface()
1329 LIMITED_METHOD_CONTRACT;
1331 _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
1332 SetFlag(enum_flag_Category_Interface);
1335 inline BOOL IsSealed();
1337 inline BOOL IsAbstract();
1339 BOOL IsExternallyVisible();
1341 // Get the instantiation for this instantiated type e.g. for Dict<string,int>
1342 // this would be an array {string,int}
1343 // If not instantiated, return NULL
1344 Instantiation GetInstantiation();
1346 // Get the instantiation for an instantiated type or a pointer to the
1347 // element type for an array
1348 Instantiation GetClassOrArrayInstantiation();
1349 Instantiation GetArrayInstantiation();
1351 // Does this method table require that additional modules be loaded?
1352 inline BOOL HasModuleDependencies()
1354 LIMITED_METHOD_CONTRACT;
1355 return GetFlag(enum_flag_HasModuleDependencies);
1358 inline void SetHasModuleDependencies()
1360 SetFlag(enum_flag_HasModuleDependencies);
1363 // See the comment in code:MethodTable.DoFullyLoad for detailed description.
1364 inline BOOL DependsOnEquivalentOrForwardedStructs()
1366 LIMITED_METHOD_CONTRACT;
1367 return GetFlag(enum_flag_DependsOnEquivalentOrForwardedStructs);
1370 inline void SetDependsOnEquivalentOrForwardedStructs()
1372 SetFlag(enum_flag_DependsOnEquivalentOrForwardedStructs);
1375 // Is this a method table for a generic type instantiation, e.g. List<string>?
1376 inline BOOL HasInstantiation();
1378 // Returns true for any class which is either itself a generic
1379 // instantiation or is derived from a generic
1380 // instantiation anywhere in it's class hierarchy,
1382 // e.g. class D : C<int>
1383 // or class E : D, class D : C<int>
1385 // Does not return true just because the class supports
1386 // an instantiated interface type.
1387 BOOL HasGenericClassInstantiationInHierarchy()
1389 WRAPPER_NO_CONTRACT;
1390 return GetNumDicts() != 0;
1393 // Is this an instantiation of a generic class at its formal
1394 // type parameters ie. List<T> ?
1395 inline BOOL IsGenericTypeDefinition();
1397 BOOL ContainsGenericMethodVariables();
1399 static BOOL ComputeContainsGenericVariables(Instantiation inst);
1401 inline void SetContainsGenericVariables()
1403 LIMITED_METHOD_CONTRACT;
1404 SetFlag(enum_flag_ContainsGenericVariables);
1407 inline void SetHasVariance()
1409 LIMITED_METHOD_CONTRACT;
1410 SetFlag(enum_flag_HasVariance);
1413 inline BOOL HasVariance()
1415 LIMITED_METHOD_CONTRACT;
1416 return GetFlag(enum_flag_HasVariance);
1419 // Is this something like List<T> or List<Stack<T>>?
1420 // List<Blah<T>> only exists for reflection and verification.
1421 inline DWORD ContainsGenericVariables(BOOL methodVarsOnly = FALSE)
1423 WRAPPER_NO_CONTRACT;
1426 return ContainsGenericMethodVariables();
1428 return GetFlag(enum_flag_ContainsGenericVariables);
1433 LIMITED_METHOD_DAC_CONTRACT;;
1434 return GetFlag(enum_flag_IsByRefLike);
1437 void SetIsByRefLike()
1439 LIMITED_METHOD_CONTRACT;
1440 SetFlag(enum_flag_IsByRefLike);
1443 // class is a com object class
1444 Module* GetDefiningModuleForOpenType();
1446 inline BOOL IsTypicalTypeDefinition()
1448 LIMITED_METHOD_CONTRACT;
1449 return !HasInstantiation() || IsGenericTypeDefinition();
1454 modeProjected = 0x1,
1455 modeRedirected = 0x2,
1456 modeAll = modeProjected|modeRedirected
1459 // Is this a generic interface/delegate that can be used for COM interop?
1460 inline BOOL SupportsGenericInterop(TypeHandle::InteropKind interopKind, Mode = modeAll);
1462 BOOL HasSameTypeDefAs(MethodTable *pMT);
1463 BOOL HasSameTypeDefAs_NoLogging(MethodTable *pMT);
1465 //-------------------------------------------------------------------
1466 // GENERICS & CODE SHARING
1469 BOOL IsSharedByGenericInstantiations();
1471 // If this is a "representative" generic MT or a non-generic (regular) MT return true
1472 inline BOOL IsCanonicalMethodTable();
1474 // Return the canonical representative MT amongst the set of MT's that share
1475 // code with the given MT because of generics.
1476 PTR_MethodTable GetCanonicalMethodTable();
1478 // Returns fixup if canonical method table needs fixing up, NULL otherwise
1479 TADDR GetCanonicalMethodTableFixup();
1481 //-------------------------------------------------------------------
1482 // Accessing methods by slot number
1484 // Some of these functions are also currently used to get non-virtual
1485 // methods, relying on the assumption that they are contiguous. This
1486 // is not true for non-virtual methods in generic instantiations, which
1487 // only live on the canonical method table.
1491 NO_SLOT = 0xffff // a unique slot number used to indicate "empty" for fields that record slot numbers
1494 PCODE GetSlot(UINT32 slotNumber)
1496 WRAPPER_NO_CONTRACT;
1497 STATIC_CONTRACT_SO_TOLERANT;
1498 CONSISTENCY_CHECK(slotNumber < GetNumVtableSlots());
1499 PTR_PCODE pSlot = GetSlotPtrRaw(slotNumber);
1500 if (IsZapped() && slotNumber >= GetNumVirtuals())
1502 // Non-virtual slots in NGened images are relative pointers
1503 return RelativePointer<PCODE>::GetValueAtPtr(dac_cast<TADDR>(pSlot));
1508 // Special-case for when we know that the slot number corresponds
1509 // to a virtual method.
1510 inline PCODE GetSlotForVirtual(UINT32 slotNum)
1512 LIMITED_METHOD_CONTRACT;
1514 CONSISTENCY_CHECK(slotNum < GetNumVirtuals());
1515 // Virtual slots live in chunks pointed to by vtable indirections
1516 return *(GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum));
1519 PTR_PCODE GetSlotPtrRaw(UINT32 slotNum)
1521 WRAPPER_NO_CONTRACT;
1522 STATIC_CONTRACT_SO_TOLERANT;
1523 CONSISTENCY_CHECK(slotNum < GetNumVtableSlots());
1525 if (slotNum < GetNumVirtuals())
1527 // Virtual slots live in chunks pointed to by vtable indirections
1528 return GetVtableIndirections()[GetIndexOfVtableIndirection(slotNum)] + GetIndexAfterVtableIndirection(slotNum);
1530 else if (HasSingleNonVirtualSlot())
1532 // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member,
1533 // except when there is only one in which case it lives in the optional member itself
1534 _ASSERTE(slotNum == GetNumVirtuals());
1535 return dac_cast<PTR_PCODE>(GetNonVirtualSlotsPtr());
1539 // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member
1540 _ASSERTE(HasNonVirtualSlotsArray());
1541 g_IBCLogger.LogMethodTableNonVirtualSlotsAccess(this);
1542 return GetNonVirtualSlotsArray() + (slotNum - GetNumVirtuals());
1546 PTR_PCODE GetSlotPtr(UINT32 slotNum)
1548 WRAPPER_NO_CONTRACT;
1549 STATIC_CONTRACT_SO_TOLERANT;
1551 // Slots in NGened images are relative pointers
1552 CONSISTENCY_CHECK(!IsZapped());
1554 return GetSlotPtrRaw(slotNum);
1557 void SetSlot(UINT32 slotNum, PCODE slotVal);
1559 //-------------------------------------------------------------------
1562 // Rather than the traditional array of code pointers (or "slots") we use a two-level vtable in
1563 // which slots for virtual methods live in chunks. Doing so allows the chunks to be shared among
1564 // method tables (the most common example being between parent and child classes where the child
1565 // does not override any method in the chunk). This yields substantial space savings at the fixed
1566 // cost of one additional indirection for a virtual call.
1568 // Note that none of this should be visible outside the implementation of MethodTable; all other
1569 // code continues to refer to a virtual method via the traditional slot number. This is similar to
1570 // how we refer to non-virtual methods as having a slot number despite having long ago moved their
1571 // code pointers out of the vtable.
1573 // Consider a class where GetNumVirtuals is 5 and (for the sake of the example) assume we break
1574 // the vtable into chunks of size 3. The layout would be as follows:
1576 // pMT chunk 1 chunk 2
1577 // ------------------ ------------------ ------------------
1578 // | | | M1() | | M4() |
1579 // | fixed-size | ------------------ ------------------
1580 // | portion of | | M2() | | M5() |
1581 // | MethodTable | ------------------ ------------------
1583 // ------------------ ------------------
1584 // | ptr to chunk 1 |
1585 // ------------------
1586 // | ptr to chunk 2 |
1587 // ------------------
1589 // We refer to "ptr to chunk 1" and "ptr to chunk 2" as "indirection slots."
1591 // The current chunking strategy is independent of class properties; all are of size 8. Several
1592 // other strategies were tried, and the only one that has performed better empirically is to begin
1593 // with a single chunk of size 4 (matching the number of virtuals in System.Object) and then
1594 // continue with chunks of size 8. However it was a small improvement and required the run-time
1595 // helpers listed below to be measurably slower.
1597 // If you want to change this, you should only need to modify the first four functions below
1598 // along with any assembly helper that has taken a dependency on the layout. Currently,
1599 // those consist of:
1600 // JIT_IsInstanceOfInterface
1601 // JIT_ChkCastInterface
1602 // Transparent proxy stub
1604 // This layout only applies to the virtual methods in a class (those with slot number below GetNumVirtuals).
1605 // Non-virtual methods that are in the vtable (those with slot numbers between GetNumVirtuals and
1606 // GetNumVtableSlots) are laid out in a single chunk pointed to by an optional member.
1607 // See GetSlotPtrRaw for more details.
1609 #define VTABLE_SLOTS_PER_CHUNK 8
1610 #define VTABLE_SLOTS_PER_CHUNK_LOG2 3
1612 static DWORD GetIndexOfVtableIndirection(DWORD slotNum);
1613 static DWORD GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
1614 static DWORD GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
1615 static UINT32 GetIndexAfterVtableIndirection(UINT32 slotNum);
1616 static DWORD GetNumVtableIndirections(DWORD wNumVirtuals);
1617 PTR_PTR_PCODE GetVtableIndirections();
1618 DWORD GetNumVtableIndirections();
1620 class VtableIndirectionSlotIterator
1622 friend class MethodTable;
1625 PTR_PTR_PCODE m_pSlot;
1628 PTR_MethodTable m_pMT;
1630 VtableIndirectionSlotIterator(MethodTable *pMT);
1631 VtableIndirectionSlotIterator(MethodTable *pMT, DWORD index);
1637 DWORD GetOffsetFromMethodTable();
1638 PTR_PCODE GetIndirectionSlot();
1640 #ifndef DACCESS_COMPILE
1641 void SetIndirectionSlot(PTR_PCODE pChunk);
1644 DWORD GetStartSlot();
1646 DWORD GetNumSlots();
1648 }; // class VtableIndirectionSlotIterator
1650 VtableIndirectionSlotIterator IterateVtableIndirectionSlots();
1651 VtableIndirectionSlotIterator IterateVtableIndirectionSlotsFrom(DWORD index);
1653 #ifdef FEATURE_PREJIT
1654 static BOOL CanShareVtableChunksFrom(MethodTable *pTargetMT, Module *pCurrentLoaderModule, Module *pCurrentPreferredZapModule);
1655 BOOL CanInternVtableChunk(DataImage *image, VtableIndirectionSlotIterator it);
1657 static BOOL CanShareVtableChunksFrom(MethodTable *pTargetMT, Module *pCurrentLoaderModule);
1660 inline BOOL HasNonVirtualSlots()
1662 LIMITED_METHOD_DAC_CONTRACT;
1663 return GetFlag(enum_flag_HasNonVirtualSlots);
1666 inline BOOL HasSingleNonVirtualSlot()
1668 LIMITED_METHOD_DAC_CONTRACT;
1669 return GetFlag(enum_flag_HasSingleNonVirtualSlot);
1672 inline BOOL HasNonVirtualSlotsArray()
1674 LIMITED_METHOD_DAC_CONTRACT;
1675 return HasNonVirtualSlots() && !HasSingleNonVirtualSlot();
1678 TADDR GetNonVirtualSlotsPtr();
1680 inline PTR_PCODE GetNonVirtualSlotsArray()
1682 LIMITED_METHOD_DAC_CONTRACT;
1683 _ASSERTE(HasNonVirtualSlotsArray());
1684 return RelativePointer<PTR_PCODE>::GetValueAtPtr(GetNonVirtualSlotsPtr());
1687 #ifndef DACCESS_COMPILE
1688 inline void SetNonVirtualSlotsArray(PCODE *slots)
1690 LIMITED_METHOD_CONTRACT;
1691 _ASSERTE(HasNonVirtualSlotsArray());
1693 RelativePointer<PCODE *> *pRelPtr = (RelativePointer<PCODE *> *)GetNonVirtualSlotsPtr();
1694 pRelPtr->SetValue(slots);
1697 inline void SetHasSingleNonVirtualSlot()
1699 LIMITED_METHOD_CONTRACT;
1700 SetFlag(enum_flag_HasSingleNonVirtualSlot);
1704 inline unsigned GetNonVirtualSlotsArraySize()
1706 LIMITED_METHOD_DAC_CONTRACT;
1707 return GetNumNonVirtualSlots() * sizeof(PCODE);
1710 inline WORD GetNumNonVirtualSlots();
1712 inline WORD GetNumVirtuals()
1714 LIMITED_METHOD_DAC_CONTRACT;
1716 g_IBCLogger.LogMethodTableAccess(this);
1717 return GetNumVirtuals_NoLogging();
1720 inline WORD GetNumVirtuals_NoLogging()
1722 LIMITED_METHOD_DAC_CONTRACT;
1724 return m_wNumVirtuals;
1727 inline void SetNumVirtuals (WORD wNumVtableSlots)
1729 LIMITED_METHOD_CONTRACT;
1730 m_wNumVirtuals = wNumVtableSlots;
1733 unsigned GetNumParentVirtuals()
1735 LIMITED_METHOD_CONTRACT;
1736 if (IsInterface() || IsTransparentProxy()) {
1739 MethodTable *pMTParent = GetParentMethodTable();
1740 g_IBCLogger.LogMethodTableAccess(this);
1741 return pMTParent == NULL ? 0 : pMTParent->GetNumVirtuals();
1744 static inline DWORD GetVtableOffset()
1746 LIMITED_METHOD_DAC_CONTRACT;
1748 return (sizeof(MethodTable));
1751 // Return total methods: virtual, static, and instance method slots.
1752 WORD GetNumMethods();
1754 // Return number of slots in this methodtable. This is just an information about the layout of the methodtable, it should not be used
1755 // for functionality checks. Do not confuse with GetNumVirtuals()!
1756 WORD GetNumVtableSlots()
1758 LIMITED_METHOD_DAC_CONTRACT;
1759 return GetNumVirtuals() + GetNumNonVirtualSlots();
1762 //-------------------------------------------------------------------
1763 // Slots <-> the MethodDesc associated with the slot.
1766 MethodDesc* GetMethodDescForSlot(DWORD slot);
1768 static MethodDesc* GetMethodDescForSlotAddress(PCODE addr, BOOL fSpeculative = FALSE);
1770 PCODE GetRestoredSlot(DWORD slot);
1772 // Returns MethodTable that GetRestoredSlot get its values from
1773 MethodTable * GetRestoredSlotMT(DWORD slot);
1775 // Used to map methods on the same slot between instantiations.
1776 MethodDesc * GetParallelMethodDesc(MethodDesc * pDefMD);
1778 //-------------------------------------------------------------------
1779 // BoxedEntryPoint MethodDescs.
1781 // Virtual methods on structs have BoxedEntryPoint method descs in their vtable.
1782 // See also notes for MethodDesc::FindOrCreateAssociatedMethodDesc. You should
1783 // probably be using that function if you need to map between unboxing
1784 // stubs and non-unboxing stubs.
1786 MethodDesc* GetBoxedEntryPointMD(MethodDesc *pMD);
1788 MethodDesc* GetUnboxedEntryPointMD(MethodDesc *pMD);
1789 MethodDesc* GetExistingUnboxedEntryPointMD(MethodDesc *pMD);
1791 //-------------------------------------------------------------------
1792 // FIELD LAYOUT, OBJECT SIZE ETC.
1795 inline BOOL HasLayout();
1797 inline EEClassLayoutInfo *GetLayoutInfo();
1799 inline BOOL IsBlittable();
1801 inline BOOL IsManagedSequential();
1803 inline BOOL HasExplicitSize();
1805 UINT32 GetNativeSize();
1809 LIMITED_METHOD_DAC_CONTRACT;
1813 void SetBaseSize(DWORD baseSize)
1815 LIMITED_METHOD_CONTRACT;
1816 m_BaseSize = baseSize;
1819 BOOL IsStringOrArray() const
1821 LIMITED_METHOD_DAC_CONTRACT;
1822 return HasComponentSize();
1827 LIMITED_METHOD_DAC_CONTRACT;
1828 return HasComponentSize() && !IsArray();
1831 BOOL HasComponentSize() const
1833 LIMITED_METHOD_DAC_CONTRACT;
1834 return GetFlag(enum_flag_HasComponentSize);
1837 // returns random combination of flags if this doesn't have a component size
1838 WORD RawGetComponentSize()
1840 LIMITED_METHOD_DAC_CONTRACT;
1842 return *((WORD*)&m_dwFlags + 1);
1844 return *(WORD*)&m_dwFlags;
1845 #endif // !BIGENDIAN
1848 // returns 0 if this doesn't have a component size
1850 // The component size is actually 16-bit WORD, but this method is returning SIZE_T to ensure
1851 // that SIZE_T is used everywhere for object size computation. It is necessary to support
1852 // objects bigger than 2GB.
1853 SIZE_T GetComponentSize()
1855 LIMITED_METHOD_DAC_CONTRACT;
1856 return HasComponentSize() ? RawGetComponentSize() : 0;
1859 void SetComponentSize(WORD wComponentSize)
1861 LIMITED_METHOD_CONTRACT;
1862 // it would be nice to assert here that this is either a string
1863 // or an array, but how do we know.
1865 // it would also be nice to assert that the component size is > 0,
1866 // but it turns out that for array's of System.Void we cannot do
1867 // that b/c the component size is 0 (?)
1868 SetFlag(enum_flag_HasComponentSize);
1869 m_dwFlags = (m_dwFlags & ~0xFFFF) | wComponentSize;
1872 inline WORD GetNumInstanceFields();
1874 inline WORD GetNumStaticFields();
1876 inline WORD GetNumThreadStaticFields();
1878 // Note that for value types GetBaseSize returns the size of instance fields for
1879 // a boxed value, and GetNumInstanceFieldsBytes for an unboxed value.
1880 // We place methods like these on MethodTable primarily so we can choose to cache
1881 // the information within MethodTable, and so less code manipulates EEClass
1882 // objects directly, because doing so can lead to bugs related to generics.
1884 // <TODO> Use m_wBaseSize whenever this is identical to GetNumInstanceFieldBytes.
1885 // We would need to reserve a flag for this. </TODO>
1887 inline DWORD GetNumInstanceFieldBytes();
1889 inline WORD GetNumIntroducedInstanceFields();
1891 // <TODO> Does this always return the same (or related) size as GetBaseSize()? </TODO>
1892 inline DWORD GetAlignedNumInstanceFieldBytes();
1895 // Note: This flag MUST be available even from an unrestored MethodTable - see GcScanRoots in siginfo.cpp.
1896 DWORD ContainsPointers()
1898 LIMITED_METHOD_CONTRACT;
1899 return GetFlag(enum_flag_ContainsPointers);
1903 LIMITED_METHOD_CONTRACT;
1904 #ifdef FEATURE_COLLECTIBLE_TYPES
1905 return GetFlag(enum_flag_Collectible);
1910 BOOL ContainsPointersOrCollectible()
1912 LIMITED_METHOD_CONTRACT;
1913 return GetFlag(enum_flag_ContainsPointers) || GetFlag(enum_flag_Collectible);
1916 OBJECTHANDLE GetLoaderAllocatorObjectHandle();
1917 NOINLINE BYTE *GetLoaderAllocatorObjectForGC();
1919 BOOL IsNotTightlyPacked();
1921 void SetContainsPointers()
1923 LIMITED_METHOD_CONTRACT;
1924 SetFlag(enum_flag_ContainsPointers);
1927 #ifdef FEATURE_64BIT_ALIGNMENT
1928 inline bool RequiresAlign8()
1930 LIMITED_METHOD_DAC_CONTRACT;
1931 return !!GetFlag(enum_flag_RequiresAlign8);
1934 inline void SetRequiresAlign8()
1936 LIMITED_METHOD_CONTRACT;
1937 SetFlag(enum_flag_RequiresAlign8);
1939 #endif // FEATURE_64BIT_ALIGNMENT
1941 //-------------------------------------------------------------------
1942 // FIELD DESCRIPTORS
1944 // Most of this API still lives on EEClass.
1946 // ************************************ WARNING *************
1947 // ** !!!!INSTANCE FIELDDESCS ARE REPRESENTATIVES!!!!! **
1948 // ** THEY ARE SHARED BY COMPATIBLE GENERIC INSTANTIATIONS **
1949 // ************************************ WARNING *************
1951 // This goes straight to the EEClass
1952 // Careful about using this method. If it's possible that fields may have been added via EnC, then
1953 // must use the FieldDescIterator as any fields added via EnC won't be in the raw list
1954 PTR_FieldDesc GetApproxFieldDescListRaw();
1956 // This returns a type-exact FieldDesc for a static field, but may still return a representative
1957 // for a non-static field.
1958 PTR_FieldDesc GetFieldDescByIndex(DWORD fieldIndex);
1960 DWORD GetIndexForFieldDesc(FieldDesc *pField);
1962 //-------------------------------------------------------------------
1963 // REMOTING and THUNKING.
1965 // We find a lot of information from the VTable. But sometimes the VTable is a
1966 // thunking layer rather than the true type's VTable. For instance, context
1967 // proxies use a single VTable for proxies to all the types we've loaded.
1968 // The following service adjusts a MethodTable based on the supplied instance. As
1969 // we add new thunking layers, we just need to teach this service how to navigate
1971 inline BOOL IsTransparentProxy()
1976 BOOL IsMarshaledByRef()
1986 inline bool RequiresFatDispatchTokens()
1988 LIMITED_METHOD_CONTRACT;
1989 return !!GetFlag(enum_flag_RequiresDispatchTokenFat);
1992 inline void SetRequiresFatDispatchTokens()
1994 LIMITED_METHOD_CONTRACT;
1995 SetFlag(enum_flag_RequiresDispatchTokenFat);
1998 inline bool HasPreciseInitCctors()
2000 LIMITED_METHOD_CONTRACT;
2001 return !!GetFlag(enum_flag_HasPreciseInitCctors);
2004 inline void SetHasPreciseInitCctors()
2006 LIMITED_METHOD_CONTRACT;
2007 SetFlag(enum_flag_HasPreciseInitCctors);
2010 #if defined(FEATURE_HFA)
2013 LIMITED_METHOD_CONTRACT;
2014 return !!GetFlag(enum_flag_IsHFA);
2017 inline void SetIsHFA()
2019 LIMITED_METHOD_CONTRACT;
2020 SetFlag(enum_flag_IsHFA);
2022 #endif // FEATURE_HFA
2024 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2025 inline bool IsRegPassedStruct()
2027 LIMITED_METHOD_CONTRACT;
2028 return !!GetFlag(enum_flag_IsRegStructPassed);
2031 inline void SetRegPassedStruct()
2033 LIMITED_METHOD_CONTRACT;
2034 SetFlag(enum_flag_IsRegStructPassed);
2036 #endif // defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
2040 CorElementType GetHFAType();
2042 // The managed and unmanaged HFA type can differ for types with layout. The following two methods return the unmanaged HFA type.
2044 CorElementType GetNativeHFAType();
2045 #endif // FEATURE_HFA
2047 #ifdef FEATURE_64BIT_ALIGNMENT
2048 // Returns true iff the native view of this type requires 64-bit aligment.
2049 bool NativeRequiresAlign8();
2050 #endif // FEATURE_64BIT_ALIGNMENT
2052 // True if interface casts for an object having this type require more
2053 // than a simple scan of the interface map
2054 // See JIT_IsInstanceOfInterface
2055 inline BOOL InstanceRequiresNonTrivialInterfaceCast()
2057 STATIC_CONTRACT_SO_TOLERANT;
2058 LIMITED_METHOD_CONTRACT;
2060 return GetFlag(enum_flag_NonTrivialInterfaceCast);
2064 //-------------------------------------------------------------------
2065 // PARENT INTERFACES
2067 unsigned GetNumInterfaces()
2069 LIMITED_METHOD_DAC_CONTRACT;
2070 return m_wNumInterfaces;
2073 //-------------------------------------------------------------------
2076 // There are two variants of each of these methods:
2079 // - restore encoded pointers on demand
2080 // - might throw, might trigger GC
2081 // - return type is boolean (FALSE = cannot cast, TRUE = can cast)
2084 // - do not restore encoded pointers on demand
2085 // - does not throw, does not trigger GC
2086 // - return type is three-valued (CanCast, CannotCast, MaybeCast)
2087 // - MaybeCast indicates that the test tripped on an encoded pointer
2088 // so the caller should now call CanCastToXRestoring if it cares
2090 BOOL CanCastToInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
2091 BOOL CanCastToClass(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
2092 BOOL CanCastToClassOrInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited);
2093 BOOL CanCastByVarianceToInterfaceOrDelegate(MethodTable *pTargetMT, TypeHandlePairList *pVisited);
2095 BOOL CanCastToNonVariantInterface(MethodTable *pTargetMT);
2097 TypeHandle::CastResult CanCastToInterfaceNoGC(MethodTable *pTargetMT);
2098 TypeHandle::CastResult CanCastToClassNoGC(MethodTable *pTargetMT);
2099 TypeHandle::CastResult CanCastToClassOrInterfaceNoGC(MethodTable *pTargetMT);
2101 // The inline part of equivalence check.
2102 #ifndef DACCESS_COMPILE
2103 FORCEINLINE BOOL IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL));
2105 #ifdef FEATURE_COMINTEROP
2106 // This method is public so that TypeHandle has direct access to it
2107 BOOL IsEquivalentTo_Worker(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO tolerant
2109 BOOL IsEquivalentTo_WorkerInner(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO intolerant
2110 #endif // FEATURE_COMINTEROP
2114 //-------------------------------------------------------------------
2115 // THE METHOD TABLE PARENT (SUPERCLASS/BASE CLASS)
2118 #if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
2119 typedef RelativeFixupPointer<PTR_MethodTable> ParentMT_t;
2121 typedef PlainPointer<PTR_MethodTable> ParentMT_t;
2124 BOOL HasApproxParent()
2126 LIMITED_METHOD_DAC_CONTRACT;
2127 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent) != 0;
2129 inline void SetHasExactParent()
2131 WRAPPER_NO_CONTRACT;
2132 FastInterlockAnd(&(GetWriteableDataForWrite()->m_dwFlags), ~MethodTableWriteableData::enum_flag_HasApproxParent);
2136 // Caller must know that the parent method table is not an encoded fixup
2137 inline PTR_MethodTable GetParentMethodTable()
2139 LIMITED_METHOD_DAC_CONTRACT;
2141 PRECONDITION(IsParentMethodTablePointerValid());
2142 return ReadPointerMaybeNull(this, &MethodTable::m_pParentMethodTable);
2145 inline static PTR_VOID GetParentMethodTable(PTR_VOID pMT)
2147 LIMITED_METHOD_DAC_CONTRACT;
2149 PTR_MethodTable pMethodTable = dac_cast<PTR_MethodTable>(pMT);
2150 return pMethodTable->GetParentMethodTable();
2153 #ifndef DACCESS_COMPILE
2154 inline ParentMT_t * GetParentMethodTablePlainOrRelativePointerPtr()
2156 LIMITED_METHOD_CONTRACT;
2157 return &m_pParentMethodTable;
2159 #endif // !DACCESS_COMPILE
2161 // Is the parent method table pointer equal to the given argument?
2162 BOOL ParentEquals(PTR_MethodTable pMT)
2164 LIMITED_METHOD_DAC_CONTRACT;
2165 PRECONDITION(IsParentMethodTablePointerValid());
2166 g_IBCLogger.LogMethodTableAccess(this);
2167 return GetParentMethodTable() == pMT;
2171 BOOL IsParentMethodTablePointerValid();
2174 #ifndef DACCESS_COMPILE
2175 void SetParentMethodTable (MethodTable *pParentMethodTable)
2177 LIMITED_METHOD_CONTRACT;
2178 PRECONDITION(!m_pParentMethodTable.IsIndirectPtrMaybeNull());
2179 m_pParentMethodTable.SetValueMaybeNull(pParentMethodTable);
2181 GetWriteableDataForWrite_NoLogging()->SetParentMethodTablePointerValid();
2184 #endif // !DACCESS_COMPILE
2185 MethodTable * GetMethodTableMatchingParentClass(MethodTable * pWhichParent);
2186 Instantiation GetInstantiationOfParentClass(MethodTable *pWhichParent);
2188 //-------------------------------------------------------------------
2189 // THE EEClass (Possibly shared between instantiations!).
2191 // Note that it is not generally the case that GetClass.GetMethodTable() == t.
2193 PTR_EEClass GetClass();
2195 inline PTR_EEClass GetClass_NoLogging();
2197 PTR_EEClass GetClassWithPossibleAV();
2199 BOOL ValidateWithPossibleAV();
2201 BOOL IsClassPointerValid();
2203 static UINT32 GetOffsetOfFlags()
2205 LIMITED_METHOD_CONTRACT;
2206 return offsetof(MethodTable, m_dwFlags);
2209 static UINT32 GetIfArrayThenSzArrayFlag()
2211 LIMITED_METHOD_CONTRACT;
2212 return enum_flag_Category_IfArrayThenSzArray;
2215 //-------------------------------------------------------------------
2218 // Do not call the following at any time except when creating a method table.
2219 // One day we will have proper constructors for method tables and all these
2221 #ifndef DACCESS_COMPILE
2222 inline void SetClass(EEClass *pClass)
2224 LIMITED_METHOD_CONTRACT;
2225 m_pEEClass.SetValue(pClass);
2228 inline void SetCanonicalMethodTable(MethodTable * pMT)
2230 m_pCanonMT.SetValue((TADDR)pMT | MethodTable::UNION_METHODTABLE);
2234 inline void SetHasInstantiation(BOOL fTypicalInstantiation, BOOL fSharedByGenericInstantiations);
2236 //-------------------------------------------------------------------
2237 // INTERFACE IMPLEMENTATION
2240 // Faster force-inlined version of ImplementsInterface
2241 BOOL ImplementsInterfaceInline(MethodTable *pInterface);
2243 BOOL ImplementsInterface(MethodTable *pInterface);
2244 BOOL ImplementsEquivalentInterface(MethodTable *pInterface);
2246 MethodDesc *GetMethodDescForInterfaceMethod(TypeHandle ownerType, MethodDesc *pInterfaceMD);
2247 MethodDesc *GetMethodDescForInterfaceMethod(MethodDesc *pInterfaceMD); // You can only use this one for non-generic interfaces
2249 //-------------------------------------------------------------------
2253 inline PTR_InterfaceInfo GetInterfaceMap();
2255 #ifndef DACCESS_COMPILE
2256 void SetInterfaceMap(WORD wNumInterfaces, InterfaceInfo_t* iMap);
2259 inline int HasInterfaceMap()
2261 LIMITED_METHOD_DAC_CONTRACT;
2262 return (m_wNumInterfaces != 0);
2265 // Where possible, use this iterator over the interface map instead of accessing the map directly
2266 // That way we can easily change the implementation of the map
2267 class InterfaceMapIterator
2269 friend class MethodTable;
2272 PTR_InterfaceInfo m_pMap;
2276 InterfaceMapIterator(MethodTable *pMT)
2277 : m_pMap(pMT->GetInterfaceMap()),
2279 m_count(pMT->GetNumInterfaces())
2281 WRAPPER_NO_CONTRACT;
2284 InterfaceMapIterator(MethodTable *pMT, DWORD index)
2285 : m_pMap(pMT->GetInterfaceMap() + index),
2287 m_count(pMT->GetNumInterfaces())
2289 WRAPPER_NO_CONTRACT;
2290 CONSISTENCY_CHECK(index >= 0 && index < m_count);
2294 InterfaceInfo_t* GetInterfaceInfo()
2296 LIMITED_METHOD_CONTRACT;
2300 // Move to the next item in the map, returning TRUE if an item
2301 // exists or FALSE if we've run off the end
2304 LIMITED_METHOD_CONTRACT;
2305 PRECONDITION(!Finished());
2306 if (m_i != (DWORD) -1)
2308 return (++m_i < m_count);
2311 // Have we iterated over all of the items?
2314 return (m_i == m_count);
2317 // Get the interface at the current position
2318 inline PTR_MethodTable GetInterface()
2320 CONTRACT(PTR_MethodTable)
2325 PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
2326 POSTCONDITION(CheckPointer(RETVAL));
2330 RETURN (m_pMap->GetMethodTable());
2333 #ifndef DACCESS_COMPILE
2334 void SetInterface(MethodTable *pMT)
2336 WRAPPER_NO_CONTRACT;
2337 m_pMap->SetMethodTable(pMT);
2343 LIMITED_METHOD_CONTRACT;
2346 }; // class InterfaceMapIterator
2348 // Create a new iterator over the interface map
2349 // The iterator starts just before the first item in the map
2350 InterfaceMapIterator IterateInterfaceMap()
2352 WRAPPER_NO_CONTRACT;
2353 return InterfaceMapIterator(this);
2356 // Create a new iterator over the interface map, starting at the index specified
2357 InterfaceMapIterator IterateInterfaceMapFrom(DWORD index)
2359 WRAPPER_NO_CONTRACT;
2360 return InterfaceMapIterator(this, index);
2363 //-------------------------------------------------------------------
2364 // ADDITIONAL INTERFACE MAP DATA
2367 // We store extra info (flag bits) for interfaces implemented on this MethodTable in a separate optional
2368 // location for better data density (if we put them in the interface map directly data alignment could
2369 // have us using 32 or even 64 bits to represent a single boolean value). Currently the only flag we
2370 // persist is IsDeclaredOnClass (was the interface explicitly declared by this class).
2372 // Currently we always store extra info whenever we have an interface map (in the future you could imagine
2373 // this being limited to those scenarios in which at least one of the interfaces has a non-default value
2375 inline BOOL HasExtraInterfaceInfo()
2378 return HasInterfaceMap();
2381 // Count of interfaces that can have their extra info stored inline in the optional data structure itself
2382 // (once the interface count exceeds this limit the optional data slot will instead point to a buffer with
2383 // the information).
2384 enum { kInlinedInterfaceInfoThreshhold = sizeof(TADDR) * 8 };
2386 // Calculate how many bytes of storage will be required to track additional information for interfaces.
2387 // This will be zero if there are no interfaces, but can also be zero for small numbers of interfaces as
2388 // well, and callers should be ready to handle this.
2389 static SIZE_T GetExtraInterfaceInfoSize(DWORD cInterfaces);
2391 // Called after GetExtraInterfaceInfoSize above to setup a new MethodTable with the additional memory to
2392 // track extra interface info. If there are a non-zero number of interfaces implemented on this class but
2393 // GetExtraInterfaceInfoSize() returned zero, this call must still be made (with a NULL argument).
2394 void InitializeExtraInterfaceInfo(PVOID pInfo);
2396 #ifdef FEATURE_PREJIT
2398 void SaveExtraInterfaceInfo(DataImage *pImage);
2399 void FixupExtraInterfaceInfo(DataImage *pImage);
2400 #endif // FEATURE_PREJIT
2402 #ifdef DACCESS_COMPILE
2403 void EnumMemoryRegionsForExtraInterfaceInfo();
2404 #endif // DACCESS_COMPILE
2406 // For the given interface in the map (specified via map index) mark the interface as declared explicitly
2407 // on this class. This is not legal for dynamically added interfaces (as used by RCWs).
2408 void SetInterfaceDeclaredOnClass(DWORD index);
2410 // For the given interface in the map (specified via map index) return true if the interface was declared
2411 // explicitly on this class.
2412 bool IsInterfaceDeclaredOnClass(DWORD index);
2414 //-------------------------------------------------------------------
2415 // VIRTUAL/INTERFACE CALL RESOLUTION
2417 // These should probably go in method.hpp since they don't have
2418 // much to do with method tables per se.
2421 // get the method desc given the interface method desc
2422 static MethodDesc *GetMethodDescForInterfaceMethodAndServer(TypeHandle ownerType, MethodDesc *pItfMD, OBJECTREF *pServer);
2424 #ifdef FEATURE_COMINTEROP
2425 // 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)
2426 MethodDesc *GetMethodDescForComInterfaceMethod(MethodDesc *pItfMD, bool fNullOk);
2427 #endif // FEATURE_COMINTEROP
2430 // Try a partial resolve of the constraint call, up to generic code sharing.
2432 // Note that this will not necessarily resolve the call exactly, since we might be compiling
2433 // shared generic code - it may just resolve it to a candidate suitable for
2434 // JIT compilation, and require a runtime lookup for the actual code pointer
2437 // Return NULL if the call could not be resolved, e.g. because it is invoked
2438 // on a type that inherits the implementation of the method from System.Object
2439 // or System.ValueType.
2441 // Always returns an unboxed entry point with a uniform calling convention.
2442 MethodDesc * TryResolveConstraintMethodApprox(
2443 TypeHandle ownerType,
2445 BOOL * pfForceUseRuntimeLookup = NULL);
2447 //-------------------------------------------------------------------
2448 // CONTRACT IMPLEMENTATIONS
2451 inline BOOL HasDispatchMap()
2453 WRAPPER_NO_CONTRACT;
2454 return GetDispatchMap() != NULL;
2457 PTR_DispatchMap GetDispatchMap();
2459 inline BOOL HasDispatchMapSlot()
2461 LIMITED_METHOD_DAC_CONTRACT;
2462 return GetFlag(enum_flag_HasDispatchMapSlot);
2465 #ifndef DACCESS_COMPILE
2466 void SetDispatchMap(DispatchMap *pDispatchMap)
2468 LIMITED_METHOD_CONTRACT;
2469 _ASSERTE(HasDispatchMapSlot());
2471 TADDR pSlot = GetMultipurposeSlotPtr(enum_flag_HasDispatchMapSlot, c_DispatchMapSlotOffsets);
2473 RelativePointer<DispatchMap *> *pRelPtr = (RelativePointer<DispatchMap *> *)pSlot;
2474 pRelPtr->SetValue(pDispatchMap);
2476 #endif // !DACCESS_COMPILE
2479 BOOL FindEncodedMapDispatchEntry(UINT32 typeID,
2481 DispatchMapEntry *pEntry);
2483 BOOL FindIntroducedImplementationTableDispatchEntry(UINT32 slotNumber,
2484 DispatchMapEntry *pEntry,
2485 BOOL fVirtualMethodsOnly);
2487 BOOL FindDispatchEntryForCurrentType(UINT32 typeID,
2489 DispatchMapEntry *pEntry);
2491 BOOL FindDispatchEntry(UINT32 typeID,
2493 DispatchMapEntry *pEntry);
2496 BOOL FindDispatchImpl(
2499 DispatchSlot * pImplSlot);
2501 DispatchSlot FindDispatchSlot(UINT32 typeID, UINT32 slotNumber);
2503 DispatchSlot FindDispatchSlot(DispatchToken tok);
2505 // You must use the second of these two if there is any chance the pMD is a method
2506 // on a generic interface such as IComparable<T> (which it normally can be). The
2507 // ownerType is used to provide an exact qualification in the case the pMD is
2508 // a shared method descriptor.
2509 DispatchSlot FindDispatchSlotForInterfaceMD(MethodDesc *pMD);
2510 DispatchSlot FindDispatchSlotForInterfaceMD(TypeHandle ownerType, MethodDesc *pMD);
2512 MethodDesc *ReverseInterfaceMDLookup(UINT32 slotNumber);
2514 // Lookup, does not assign if not already done.
2515 UINT32 LookupTypeID();
2516 // Lookup, will assign ID if not already done.
2520 MethodTable *LookupDispatchMapType(DispatchMapTypeID typeID);
2522 MethodDesc *GetIntroducingMethodDesc(DWORD slotNumber);
2524 // Determines whether all methods in the given interface have their final implementing
2525 // slot in a parent class. I.e. if this returns TRUE, it is trivial (no VSD lookup) to
2526 // dispatch pItfMT methods on this class if one knows how to dispatch them on pParentMT.
2527 BOOL ImplementsInterfaceWithSameSlotsAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
2529 // Determines whether all methods in the given interface have their final implementation
2530 // in a parent class. I.e. if this returns TRUE, this class behaves the same as pParentMT
2531 // when it comes to dispatching pItfMT methods.
2532 BOOL HasSameInterfaceImplementationAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
2535 static MethodDesc *MapMethodDeclToMethodImpl(MethodDesc *pMDDecl);
2537 //-------------------------------------------------------------------
2538 // FINALIZATION SEMANTICS
2541 DWORD CannotUseSuperFastHelper()
2543 WRAPPER_NO_CONTRACT;
2544 return HasFinalizer();
2547 void SetHasFinalizer()
2549 LIMITED_METHOD_CONTRACT;
2550 SetFlag(enum_flag_HasFinalizer);
2553 void SetHasCriticalFinalizer()
2555 LIMITED_METHOD_CONTRACT;
2556 SetFlag(enum_flag_HasCriticalFinalizer);
2558 // Does this class have non-trivial finalization requirements?
2559 DWORD HasFinalizer()
2561 LIMITED_METHOD_DAC_CONTRACT;
2562 return GetFlag(enum_flag_HasFinalizer);
2564 // Must this class be finalized during a rude appdomain unload, and
2565 // must it's finalizer run in a different order from normal finalizers?
2566 DWORD HasCriticalFinalizer() const
2568 LIMITED_METHOD_CONTRACT;
2569 return GetFlag(enum_flag_HasCriticalFinalizer);
2572 // Have the backout methods (Finalizer, Dispose, ReleaseHandle etc.) been prepared for this type? This currently only happens
2573 // for types derived from CriticalFinalizerObject.
2574 BOOL CriticalTypeHasBeenPrepared()
2576 LIMITED_METHOD_CONTRACT;
2577 _ASSERTE(HasCriticalFinalizer());
2578 return GetWriteableData()->CriticalTypeHasBeenPrepared();
2581 void SetCriticalTypeHasBeenPrepared()
2591 _ASSERTE(HasCriticalFinalizer());
2592 GetWriteableDataForWrite()->SetCriticalTypeHasBeenPrepared();
2595 //-------------------------------------------------------------------
2599 DWORD GetOffsetOfFirstStaticHandle();
2600 DWORD GetOffsetOfFirstStaticMT();
2602 #ifndef DACCESS_COMPILE
2603 inline PTR_BYTE GetNonGCStaticsBasePointer();
2604 inline PTR_BYTE GetGCStaticsBasePointer();
2605 inline PTR_BYTE GetNonGCThreadStaticsBasePointer();
2606 inline PTR_BYTE GetGCThreadStaticsBasePointer();
2607 #endif //!DACCESS_COMPILE
2609 inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain);
2610 inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain);
2612 inline DWORD IsDynamicStatics()
2614 LIMITED_METHOD_DAC_CONTRACT;
2615 return !TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_NonDynamic);
2618 inline void SetDynamicStatics(BOOL fGeneric)
2620 LIMITED_METHOD_CONTRACT;
2621 SetFlag(fGeneric ? enum_flag_StaticsMask_Generics : enum_flag_StaticsMask_Dynamic);
2624 inline void SetHasBoxedRegularStatics()
2626 LIMITED_METHOD_CONTRACT;
2627 SetFlag(enum_flag_HasBoxedRegularStatics);
2630 inline DWORD HasBoxedRegularStatics()
2632 LIMITED_METHOD_CONTRACT;
2633 return GetFlag(enum_flag_HasBoxedRegularStatics);
2636 DWORD HasFixedAddressVTStatics();
2638 //-------------------------------------------------------------------
2639 // PER-INSTANTIATION STATICS INFO
2643 void SetupGenericsStaticsInfo(FieldDesc* pStaticFieldDescs);
2645 BOOL HasGenericsStaticsInfo()
2647 LIMITED_METHOD_DAC_CONTRACT;
2648 return GetFlag(enum_flag_StaticsMask_Generics);
2651 PTR_FieldDesc GetGenericsStaticFieldDescs()
2653 WRAPPER_NO_CONTRACT;
2654 _ASSERTE(HasGenericsStaticsInfo());
2655 return ReadPointerMaybeNull((GenericsStaticsInfo *)GetGenericsStaticsInfo(), &GenericsStaticsInfo::m_pFieldDescs);
2658 BOOL HasCrossModuleGenericStaticsInfo()
2660 LIMITED_METHOD_DAC_CONTRACT;
2661 return TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_CrossModuleGenerics);
2664 PTR_Module GetGenericsStaticsModuleAndID(DWORD * pID);
2666 WORD GetNumHandleRegularStatics();
2668 WORD GetNumBoxedRegularStatics ();
2669 WORD GetNumBoxedThreadStatics ();
2671 //-------------------------------------------------------------------
2675 // Used for generics and reflection emit in memory
2676 DWORD GetModuleDynamicEntryID();
2677 Module* GetModuleForStatics();
2679 //-------------------------------------------------------------------
2680 // GENERICS DICT INFO
2683 // Number of generic arguments, whether this is a method table for
2684 // a generic type instantiation, e.g. List<string> or the "generic" MethodTable
2686 inline DWORD GetNumGenericArgs()
2688 LIMITED_METHOD_DAC_CONTRACT;
2689 if (HasInstantiation())
2690 return (DWORD) (GetGenericsDictInfo()->m_wNumTyPars);
2695 inline DWORD GetNumDicts()
2697 LIMITED_METHOD_DAC_CONTRACT;
2698 if (HasPerInstInfo())
2700 PTR_GenericsDictInfo pDictInfo = GetGenericsDictInfo();
2701 return (DWORD) (pDictInfo->m_wNumDicts);
2707 //-------------------------------------------------------------------
2711 OBJECTREF Allocate();
2713 // This flavor of Allocate is more efficient, but can only be used
2714 // if IsRestored(), CheckInstanceActivated(), IsClassInited() are known to be true.
2715 // A sufficient condition is that another instance of the exact same type already
2716 // exists in the same appdomain. It's currently called only from Delegate.Combine
2717 // via COMDelegate::InternalAllocLike.
2718 OBJECTREF AllocateNoChecks();
2720 OBJECTREF Box(void* data);
2721 OBJECTREF FastBox(void** data);
2722 #ifndef DACCESS_COMPILE
2723 BOOL UnBoxInto(void *dest, OBJECTREF src);
2724 BOOL UnBoxIntoArg(ArgDestination *argDest, OBJECTREF src);
2725 void UnBoxIntoUnchecked(void *dest, OBJECTREF src);
2729 // Used for debugging class layout. Dumps to the debug console
2730 // when debug is true.
2731 void DebugDumpVtable(LPCUTF8 szClassName, BOOL fDebug);
2732 void Debug_DumpInterfaceMap(LPCSTR szInterfaceMapPrefix);
2733 void Debug_DumpDispatchMap();
2734 void DebugDumpFieldLayout(LPCUTF8 pszClassName, BOOL debug);
2735 void DebugRecursivelyDumpInstanceFields(LPCUTF8 pszClassName, BOOL debug);
2736 void DebugDumpGCDesc(LPCUTF8 pszClassName, BOOL debug);
2739 inline BOOL IsAgileAndFinalizable()
2741 LIMITED_METHOD_CONTRACT;
2742 // Right now, System.Thread is the only cases of this.
2743 // Things should stay this way - please don't change without talking to EE team.
2744 return this == g_pThreadClass;
2748 //-------------------------------------------------------------------
2749 // ENUMS, DELEGATES, VALUE TYPES, ARRAYS
2751 // #KindsOfElementTypes
2752 // GetInternalCorElementType() retrieves the internal representation of the type. It's not always
2753 // appropiate to use this. For example, we treat enums as their underlying type or some structs are
2754 // optimized to be ints. To get the signature type or the verifier type (same as signature except for
2755 // enums are normalized to the primtive type that underlies them), use the APIs in Typehandle.h
2757 // * code:TypeHandle.GetSignatureCorElementType()
2758 // * code:TypeHandle.GetVerifierCorElementType()
2759 // * code:TypeHandle.GetInternalCorElementType()
2760 CorElementType GetInternalCorElementType();
2761 void SetInternalCorElementType(CorElementType _NormType);
2763 // See code:TypeHandle::GetVerifierCorElementType for description
2764 CorElementType GetVerifierCorElementType();
2766 // See code:TypeHandle::GetSignatureCorElementType for description
2767 CorElementType GetSignatureCorElementType();
2769 // A true primitive is one who's GetVerifierCorElementType() ==
2772 // ELEMENT_TYPE_TYPEDBYREF etc.
2773 // Note that GetIntenalCorElementType might return these same values for some additional
2774 // types such as Enums and some structs.
2775 BOOL IsTruePrimitive();
2776 void SetIsTruePrimitive();
2778 // Is this delegate? Returns false for System.Delegate and System.MulticastDelegate.
2779 inline BOOL IsDelegate()
2781 LIMITED_METHOD_DAC_CONTRACT;
2782 // We do not allow single cast delegates anymore, just check for multicast delegate
2783 _ASSERTE(g_pMulticastDelegateClass);
2784 return ParentEquals(g_pMulticastDelegateClass);
2787 // Is this System.Object?
2788 inline BOOL IsObjectClass()
2790 LIMITED_METHOD_CONTRACT;
2791 _ASSERTE(g_pObjectClass);
2792 return (this == g_pObjectClass);
2795 // Is this System.ValueType?
2796 inline DWORD IsValueTypeClass()
2798 LIMITED_METHOD_CONTRACT;
2799 _ASSERTE(g_pValueTypeClass);
2800 return (this == g_pValueTypeClass);
2803 // Is this value type? Returns false for System.ValueType and System.Enum.
2804 inline BOOL IsValueType();
2806 // Returns "TRUE" iff "this" is a struct type such that return buffers used for returning a value
2807 // of this type must be stack-allocated. This will generally be true only if the struct
2808 // contains GC pointers, and does not exceed some size limit. Maintaining this as an invariant allows
2809 // an optimization: the JIT may assume that return buffer pointers for return types for which this predicate
2810 // returns TRUE are always stack allocated, and thus, that stores to the GC-pointer fields of such return
2811 // buffers do not require GC write barriers.
2812 BOOL IsStructRequiringStackAllocRetBuf();
2814 // Is this enum? Returns false for System.Enum.
2815 inline BOOL IsEnum();
2817 // Is this array? Returns false for System.Array.
2818 inline BOOL IsArray()
2820 LIMITED_METHOD_DAC_CONTRACT;
2821 return GetFlag(enum_flag_Category_Array_Mask) == enum_flag_Category_Array;
2823 inline BOOL IsMultiDimArray()
2825 LIMITED_METHOD_DAC_CONTRACT;
2826 PRECONDITION(IsArray());
2827 return !GetFlag(enum_flag_Category_IfArrayThenSzArray);
2830 // Returns true if this type is Nullable<T> for some T.
2831 inline BOOL IsNullable()
2833 LIMITED_METHOD_DAC_CONTRACT;
2834 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Nullable;
2837 inline void SetIsNullable()
2839 LIMITED_METHOD_CONTRACT;
2840 _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType);
2841 SetFlag(enum_flag_Category_Nullable);
2844 inline BOOL IsStructMarshalable()
2846 LIMITED_METHOD_CONTRACT;
2847 PRECONDITION(!IsInterface());
2848 return GetFlag(enum_flag_IfNotInterfaceThenMarshalable);
2851 inline void SetStructMarshalable()
2853 LIMITED_METHOD_CONTRACT;
2854 PRECONDITION(!IsInterface());
2855 SetFlag(enum_flag_IfNotInterfaceThenMarshalable);
2858 // The following methods are only valid for the
2859 // method tables for array types. These MTs may
2860 // be shared between array types and thus GetArrayElementTypeHandle
2861 // may only be approximate. If you need the exact element type handle then
2862 // you should probably be calling GetArrayElementTypeHandle on a TypeHandle,
2863 // or an ArrayTypeDesc, or on an object reference that is known to be an array,
2864 // e.g. a BASEARRAYREF.
2866 // At the moment only the object[] MethodTable is shared between array types.
2867 // In the future the amount of sharing of method tables is likely to be increased.
2868 CorElementType GetArrayElementType();
2871 TypeHandle GetApproxArrayElementTypeHandle()
2873 LIMITED_METHOD_DAC_CONTRACT;
2874 _ASSERTE (IsArray());
2875 return TypeHandle::FromTAddr(m_ElementTypeHnd);
2878 void SetApproxArrayElementTypeHandle(TypeHandle th)
2880 LIMITED_METHOD_DAC_CONTRACT;
2881 m_ElementTypeHnd = th.AsTAddr();
2884 TypeHandle * GetApproxArrayElementTypeHandlePtr()
2886 LIMITED_METHOD_CONTRACT;
2887 return (TypeHandle *)&m_ElementTypeHnd;
2890 static inline DWORD GetOffsetOfArrayElementTypeHandle()
2892 LIMITED_METHOD_CONTRACT;
2893 return offsetof(MethodTable, m_ElementTypeHnd);
2896 //-------------------------------------------------------------------
2897 // UNDERLYING METADATA
2901 // Get the RID/token for the metadata for the corresponding type declaration
2902 unsigned GetTypeDefRid();
2903 unsigned GetTypeDefRid_NoLogging();
2905 inline mdTypeDef GetCl()
2907 LIMITED_METHOD_CONTRACT;
2908 return TokenFromRid(GetTypeDefRid(), mdtTypeDef);
2911 inline mdTypeDef GetCl_NoLogging()
2913 LIMITED_METHOD_CONTRACT;
2914 return TokenFromRid(GetTypeDefRid_NoLogging(), mdtTypeDef);
2917 void SetCl(mdTypeDef token);
2920 // Make this smaller in debug builds to exercise the overflow codepath
2921 #define METHODTABLE_TOKEN_OVERFLOW 0xFFF
2923 #define METHODTABLE_TOKEN_OVERFLOW 0xFFFF
2926 BOOL HasTokenOverflow()
2928 LIMITED_METHOD_CONTRACT;
2929 return m_wToken == METHODTABLE_TOKEN_OVERFLOW;
2932 // Get the MD Import for the metadata for the corresponding type declaration
2933 IMDInternalImport* GetMDImport();
2935 mdTypeDef GetEnclosingCl();
2937 #ifdef DACCESS_COMPILE
2938 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2941 //-------------------------------------------------------------------
2942 // REMOTEABLE METHOD INFO
2945 #ifdef FEATURE_COMINTEROP
2946 void SetHasGuidInfo();
2948 void SetHasCCWTemplate();
2949 BOOL HasCCWTemplate();
2950 void SetHasRCWPerTypeData();
2951 BOOL HasRCWPerTypeData();
2952 #endif // FEATURE_COMINTEROP
2954 // The following two methods produce correct results only if this type is
2955 // marked Serializable (verified by assert in checked builds) and the field
2956 // in question was introduced in this type (the index is the FieldDesc
2958 BOOL IsFieldNotSerialized(DWORD dwFieldIndex);
2959 BOOL IsFieldOptionallySerialized(DWORD dwFieldIndex);
2961 //-------------------------------------------------------------------
2962 // DICTIONARIES FOR GENERIC INSTANTIATIONS
2964 // The PerInstInfo pointer is a pointer to per-instantiation pointer table,
2965 // each entry of which points to an instantiation "dictionary"
2966 // for an instantiated type; the last pointer points to a
2967 // dictionary which is specific to this method table, previous
2968 // entries point to dictionaries in superclasses. Instantiated interfaces and structs
2969 // have just single dictionary (no inheritance).
2971 // GetNumDicts() gives the number of dictionaries.
2973 //@nice GENERICS: instead of a separate table of pointers, put the pointers
2974 // in the vtable itself. Advantages:
2975 // * Time: we save an indirection as we don't need to go through PerInstInfo first.
2976 // * Space: no need for PerInstInfo (1 word)
2977 // Problem is that lots of code assumes that the vtable is filled
2978 // uniformly with pointers to MethodDesc stubs.
2980 // The dictionary for the method table is just an array of handles for
2981 // type parameters in the following cases:
2982 // * instantiated interfaces (no code)
2983 // * instantiated types whose code is not shared
2984 // Otherwise, it starts with the type parameters and then has a fixed
2985 // number of slots for handles (types & methods)
2986 // that are filled in lazily at run-time. Finally there is a "spill-bucket"
2987 // pointer used when the dictionary gets filled.
2989 // typar_1 type handle for first type parameter
2991 // typar_n type handle for last type parameter
2992 // slot_1 slot for first run-time handle (initially null)
2994 // slot_m slot for last run-time handle (initially null)
2995 // next_bucket pointer to spill bucket (possibly null)
2996 // The spill bucket contains just run-time handle slots.
2997 // (Alternative: continue chaining buckets.
2998 // Advantage: no need to deallocate when growing dictionaries.
2999 // Disadvantage: more indirections required at run-time.)
3001 // The layout of dictionaries is determined by GetClass()->GetDictionaryLayout()
3002 // Thus the layout can vary between incompatible instantiations. This is sometimes useful because individual type
3003 // parameters may or may not be shared. For example, consider a two parameter class Dict<K,D>. In instantiations shared with
3004 // Dict<double,string> any reference to K is known at JIT-compile-time (it's double) but any token containing D
3005 // must have a dictionary entry. On the other hand, for instantiations shared with Dict<string,double> the opposite holds.
3008 #if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
3009 typedef RelativePointer<PTR_Dictionary> PerInstInfoElem_t;
3010 typedef RelativePointer<DPTR(PerInstInfoElem_t)> PerInstInfo_t;
3012 typedef PlainPointer<PTR_Dictionary> PerInstInfoElem_t;
3013 typedef PlainPointer<DPTR(PerInstInfoElem_t)> PerInstInfo_t;
3016 // Return a pointer to the per-instantiation information. See field itself for comments.
3017 DPTR(PerInstInfoElem_t) GetPerInstInfo()
3019 LIMITED_METHOD_DAC_CONTRACT;
3020 _ASSERTE(HasPerInstInfo());
3021 return ReadPointer(this, &MethodTable::m_pPerInstInfo);
3023 BOOL HasPerInstInfo()
3025 LIMITED_METHOD_DAC_CONTRACT;
3026 return GetFlag(enum_flag_HasPerInstInfo) && !IsArray();
3028 #ifndef DACCESS_COMPILE
3029 static inline bool IsPerInstInfoRelative()
3031 LIMITED_METHOD_CONTRACT;
3032 return decltype(m_pPerInstInfo)::isRelative;
3034 static inline DWORD GetOffsetOfPerInstInfo()
3036 LIMITED_METHOD_CONTRACT;
3037 return offsetof(MethodTable, m_pPerInstInfo);
3039 void SetPerInstInfo(PerInstInfoElem_t *pPerInstInfo)
3041 LIMITED_METHOD_CONTRACT;
3042 m_pPerInstInfo.SetValue(pPerInstInfo);
3044 void SetDictInfo(WORD numDicts, WORD numTyPars)
3046 WRAPPER_NO_CONTRACT;
3047 GenericsDictInfo* pInfo = GetGenericsDictInfo();
3048 pInfo->m_wNumDicts = numDicts;
3049 pInfo->m_wNumTyPars = numTyPars;
3051 #endif // !DACCESS_COMPILE
3052 PTR_GenericsDictInfo GetGenericsDictInfo()
3054 LIMITED_METHOD_DAC_CONTRACT;
3055 // GenericsDictInfo is stored at negative offset of the dictionary
3056 return dac_cast<PTR_GenericsDictInfo>(GetPerInstInfo()) - 1;
3059 // Get a pointer to the dictionary for this instantiated type
3060 // (The instantiation is stored in the initial slots of the dictionary)
3061 // If not instantiated, return NULL
3062 PTR_Dictionary GetDictionary();
3064 #ifdef FEATURE_PREJIT
3066 // After the zapper compiles all code in a module it may attempt
3067 // to populate entries in all dictionaries
3068 // associated with generic types. This is an optional step - nothing will
3069 // go wrong at runtime except we may get more one-off calls to JIT_GenericHandle.
3070 // Although these are one-off we prefer to avoid them since they touch metadata
3073 // Fully populating a dictionary may in theory load more types. However
3074 // for the moment only those entries that refer to types that
3075 // are already loaded will be filled in.
3076 void PrepopulateDictionary(DataImage * image, BOOL nonExpansive);
3077 #endif // FEATURE_PREJIT
3079 // Return a substitution suitbale for interpreting
3080 // the metadata in parent class, assuming we already have a subst.
3081 // suitable for interpreting the current class.
3083 // If, for example, the definition for the current class is
3084 // D<T> : C<List<T>, T[] >
3085 // then this (for C<!0,!1>) will be
3088 // added to the chain of substitutions.
3090 // Subsequently, if the definition for C is
3091 // C<T, U> : B< Dictionary<T, U> >
3092 // then the next subst (for B<!0>) will be
3093 // 0 --> Dictionary< List<T>, T[] >
3095 Substitution GetSubstitutionForParent(const Substitution *pSubst);
3097 inline DWORD GetAttrClass();
3099 inline BOOL IsSerializable();
3100 inline BOOL HasFieldsWhichMustBeInited();
3101 inline BOOL SupportsAutoNGen();
3102 inline BOOL RunCCTorAsIfNGenImageExists();
3104 //-------------------------------------------------------------------
3105 // SECURITY SEMANTICS
3108 void SetIsAsyncPinType()
3110 LIMITED_METHOD_CONTRACT;
3111 _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
3112 SetFlag(enum_flag_Category_AsyncPin);
3115 BOOL IsAsyncPinType()
3117 LIMITED_METHOD_DAC_CONTRACT;
3118 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_AsyncPin;
3121 inline BOOL IsPreRestored() const
3123 LIMITED_METHOD_DAC_CONTRACT;
3125 return GetFlag(enum_flag_IsPreRestored);
3128 //-------------------------------------------------------------------
3129 // THE EXPOSED CLASS OBJECT
3132 * m_ExposedClassObject is a RuntimeType instance for this class. But
3133 * do NOT use it for Arrays or remoted objects! All arrays of objects
3134 * share the same MethodTable/EEClass.
3135 * @GENERICS: this is per-instantiation data
3137 // There are two version of GetManagedClassObject. The GetManagedClassObject()
3138 // method will get the class object. If it doesn't exist it will be created.
3139 // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist.
3140 OBJECTREF GetManagedClassObject();
3141 OBJECTREF GetManagedClassObjectIfExists();
3144 // ------------------------------------------------------------------
3145 // Private part of MethodTable
3146 // ------------------------------------------------------------------
3148 #ifndef DACCESS_COMPILE
3149 inline void SetWriteableData(PTR_MethodTableWriteableData pMTWriteableData)
3151 LIMITED_METHOD_CONTRACT;
3152 _ASSERTE(pMTWriteableData);
3153 m_pWriteableData.SetValue(pMTWriteableData);
3157 inline PTR_Const_MethodTableWriteableData GetWriteableData() const
3159 LIMITED_METHOD_DAC_CONTRACT;
3160 g_IBCLogger.LogMethodTableWriteableDataAccess(this);
3161 return GetWriteableData_NoLogging();
3164 inline PTR_Const_MethodTableWriteableData GetWriteableData_NoLogging() const
3166 LIMITED_METHOD_DAC_CONTRACT;
3167 return ReadPointer(this, &MethodTable::m_pWriteableData);
3170 inline PTR_MethodTableWriteableData GetWriteableDataForWrite()
3172 LIMITED_METHOD_DAC_CONTRACT;
3173 g_IBCLogger.LogMethodTableWriteableDataWriteAccess(this);
3174 return GetWriteableDataForWrite_NoLogging();
3177 inline PTR_MethodTableWriteableData GetWriteableDataForWrite_NoLogging()
3179 LIMITED_METHOD_DAC_CONTRACT;
3180 return ReadPointer(this, &MethodTable::m_pWriteableData);
3183 //-------------------------------------------------------------------
3186 inline BOOL IsRemotingConfigChecked()
3188 WRAPPER_NO_CONTRACT;
3189 return GetWriteableData()->IsRemotingConfigChecked();
3191 inline void SetRemotingConfigChecked()
3201 GetWriteableDataForWrite()->SetRemotingConfigChecked();
3203 inline void TrySetRemotingConfigChecked()
3214 GetWriteableDataForWrite()->TrySetRemotingConfigChecked();
3216 inline BOOL RequiresManagedActivation()
3218 WRAPPER_NO_CONTRACT;
3219 return GetWriteableData()->RequiresManagedActivation();
3221 inline void SetRequiresManagedActivation()
3231 GetWriteableDataForWrite()->SetRequiresManagedActivation();
3234 // Determines whether the type may require managed activation. The actual answer is known later
3235 // once the remoting config is checked.
3236 inline BOOL MayRequireManagedActivation()
3238 LIMITED_METHOD_CONTRACT;
3239 return IsMarshaledByRef();
3242 //-------------------------------------------------------------------
3244 // Used by COM interop to get GUIDs (IIDs and CLSIDs)
3246 // Get/store cached GUID information
3247 PTR_GuidInfo GetGuidInfo();
3248 void SetGuidInfo(GuidInfo* pGuidInfo);
3250 // Get and cache the GUID for this interface/class
3251 HRESULT GetGuidNoThrow(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
3253 // Get and cache the GUID for this interface/class
3254 void GetGuid(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
3256 #ifdef FEATURE_COMINTEROP
3257 // Get the GUID used for WinRT interop
3258 // * for projection generic interfaces returns the equivalent WinRT type's GUID
3259 // * for everything else returns the GetGuid(, TRUE)
3260 BOOL GetGuidForWinRT(GUID *pGuid);
3263 // Create RCW data associated with this type.
3264 RCWPerTypeData *CreateRCWPerTypeData(bool bThrowOnOOM);
3267 // Get the RCW data associated with this type or NULL if the type does not need such data or allocation
3268 // failed (only if bThrowOnOOM is false).
3269 RCWPerTypeData *GetRCWPerTypeData(bool bThrowOnOOM = true);
3270 #endif // FEATURE_COMINTEROP
3272 // Convenience method - determine if the interface/class has a guid specified (even if not yet cached)
3273 BOOL HasExplicitGuid();
3276 // Helper routines for the GetFullyQualifiedNameForClass macros defined at the top of class.h.
3277 // You probably should not use these functions directly.
3278 SString &_GetFullyQualifiedNameForClassNestedAware(SString &ssBuf);
3279 SString &_GetFullyQualifiedNameForClass(SString &ssBuf);
3280 LPCUTF8 GetFullyQualifiedNameInfo(LPCUTF8 *ppszNamespace);
3283 template<typename RedirectFunctor> SString &_GetFullyQualifiedNameForClassNestedAwareInternal(SString &ssBuf);
3286 //-------------------------------------------------------------------
3292 inline LPCUTF8 GetDebugClassName()
3294 LIMITED_METHOD_CONTRACT;
3295 return debug_m_szClassName;
3297 inline void SetDebugClassName(LPCUTF8 name)
3299 LIMITED_METHOD_CONTRACT;
3300 debug_m_szClassName = name;
3303 // Was the type created with injected duplicates?
3304 // TRUE means that we tried to inject duplicates (not that we found one to inject).
3305 inline BOOL Debug_HasInjectedInterfaceDuplicates() const
3307 LIMITED_METHOD_CONTRACT;
3308 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates) != 0;
3310 inline void Debug_SetHasInjectedInterfaceDuplicates()
3312 LIMITED_METHOD_CONTRACT;
3313 GetWriteableDataForWrite()->m_dwFlags |= MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates;
3318 #ifndef DACCESS_COMPILE
3320 //--------------------------------------------------------------------------------------
3324 inline ULONG AddRef()
3325 { LIMITED_METHOD_CONTRACT; return (ULONG) InterlockedIncrement((LONG*)&m_cRef); }
3329 // Since all methods that return a MethodData already AddRef'd, we do NOT
3330 // want to AddRef when putting a holder around it. We only want to release it.
3331 static void HolderAcquire(MethodData *pEntry)
3332 { LIMITED_METHOD_CONTRACT; return; }
3333 static void HolderRelease(MethodData *pEntry)
3334 { WRAPPER_NO_CONTRACT; if (pEntry != NULL) pEntry->Release(); }
3340 MethodData() : m_cRef(1) { LIMITED_METHOD_CONTRACT; }
3341 virtual ~MethodData() { LIMITED_METHOD_CONTRACT; }
3343 virtual MethodData *GetDeclMethodData() = 0;
3344 virtual MethodTable *GetDeclMethodTable() = 0;
3345 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber) = 0;
3347 virtual MethodData *GetImplMethodData() = 0;
3348 virtual MethodTable *GetImplMethodTable() = 0;
3349 virtual DispatchSlot GetImplSlot(UINT32 slotNumber) = 0;
3350 // Returns INVALID_SLOT_NUMBER if no implementation exists.
3351 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber) = 0;
3352 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber) = 0;
3353 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber) = 0;
3355 virtual UINT32 GetNumVirtuals() = 0;
3356 virtual UINT32 GetNumMethods() = 0;
3359 static const UINT32 INVALID_SLOT_NUMBER = UINT32_MAX;
3361 // This is used when building the data
3362 struct MethodDataEntry
3365 static const UINT32 INVALID_CHAIN_AND_INDEX = (UINT32)(-1);
3366 static const UINT16 INVALID_IMPL_SLOT_NUM = (UINT16)(-1);
3368 // This contains both the chain delta and the table index. The
3369 // reason that they are combined is that we need atomic update
3370 // of both, and it is convenient that both are on UINT16 in size.
3371 UINT32 m_chainDeltaAndTableIndex;
3372 UINT16 m_implSlotNum; // For virtually remapped slots
3373 DispatchSlot m_slot; // The entry in the DispatchImplTable
3374 MethodDesc *m_pMD; // The MethodDesc for this slot
3377 inline MethodDataEntry() : m_slot(NULL)
3378 { WRAPPER_NO_CONTRACT; Init(); }
3382 LIMITED_METHOD_CONTRACT;
3383 m_chainDeltaAndTableIndex = INVALID_CHAIN_AND_INDEX;
3384 m_implSlotNum = INVALID_IMPL_SLOT_NUM;
3389 inline BOOL IsDeclInit()
3390 { LIMITED_METHOD_CONTRACT; return m_chainDeltaAndTableIndex != INVALID_CHAIN_AND_INDEX; }
3391 inline BOOL IsImplInit()
3392 { LIMITED_METHOD_CONTRACT; return m_implSlotNum != INVALID_IMPL_SLOT_NUM; }
3394 inline void SetDeclData(UINT32 chainDelta, UINT32 tableIndex)
3395 { LIMITED_METHOD_CONTRACT; m_chainDeltaAndTableIndex = ((((UINT16) chainDelta) << 16) | ((UINT16) tableIndex)); }
3396 inline UINT32 GetChainDelta()
3397 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return m_chainDeltaAndTableIndex >> 16; }
3398 inline UINT32 GetTableIndex()
3399 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return (m_chainDeltaAndTableIndex & (UINT32)UINT16_MAX); }
3401 inline void SetImplData(UINT32 implSlotNum)
3402 { LIMITED_METHOD_CONTRACT; m_implSlotNum = (UINT16) implSlotNum; }
3403 inline UINT32 GetImplSlotNum()
3404 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsImplInit()); return m_implSlotNum; }
3406 inline void SetSlot(DispatchSlot slot)
3407 { LIMITED_METHOD_CONTRACT; m_slot = slot; }
3408 inline DispatchSlot GetSlot()
3409 { LIMITED_METHOD_CONTRACT; return m_slot; }
3411 inline void SetMethodDesc(MethodDesc *pMD)
3412 { LIMITED_METHOD_CONTRACT; m_pMD = pMD; }
3413 inline MethodDesc *GetMethodDesc()
3414 { LIMITED_METHOD_CONTRACT; return m_pMD; }
3418 static void ProcessMap(
3419 const DispatchMapTypeID * rgTypeIDs,
3422 UINT32 cCurrentChainDepth,
3423 MethodDataEntry * rgWorkingData);
3424 }; // class MethodData
3426 typedef ::Holder < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataHolder;
3427 typedef ::Wrapper < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataWrapper;
3430 //--------------------------------------------------------------------------------------
3431 class MethodDataObject : public MethodData
3434 // Static method that returns the amount of memory to allocate for a particular type.
3435 static UINT32 GetObjectSize(MethodTable *pMT);
3437 // Constructor. Make sure you have allocated enough memory using GetObjectSize.
3438 inline MethodDataObject(MethodTable *pMT)
3439 { WRAPPER_NO_CONTRACT; Init(pMT, NULL); }
3441 inline MethodDataObject(MethodTable *pMT, MethodData *pParentData)
3442 { WRAPPER_NO_CONTRACT; Init(pMT, pParentData); }
3444 virtual ~MethodDataObject() { LIMITED_METHOD_CONTRACT; }
3446 virtual MethodData *GetDeclMethodData()
3447 { LIMITED_METHOD_CONTRACT; return this; }
3448 virtual MethodTable *GetDeclMethodTable()
3449 { LIMITED_METHOD_CONTRACT; return m_pMT; }
3450 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
3452 virtual MethodData *GetImplMethodData()
3453 { LIMITED_METHOD_CONTRACT; return this; }
3454 virtual MethodTable *GetImplMethodTable()
3455 { LIMITED_METHOD_CONTRACT; return m_pMT; }
3456 virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
3457 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
3458 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3459 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3461 virtual UINT32 GetNumVirtuals()
3462 { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumVirtuals(); }
3463 virtual UINT32 GetNumMethods()
3464 { LIMITED_METHOD_CONTRACT; return m_pMT->GetCanonicalMethodTable()->GetNumMethods(); }
3467 void Init(MethodTable *pMT, MethodData *pParentData);
3469 BOOL PopulateNextLevel();
3471 // This is the method table for the actual type we're gathering the data for
3474 // This is used in staged map decoding - it indicates which type we will next decode.
3475 UINT32 m_iNextChainDepth;
3476 static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
3478 BOOL m_containsMethodImpl;
3480 // NOTE: Use of these APIs are unlocked and may appear to be erroneous. However, since calls
3481 // to ProcessMap will result in identical values being placed in the MethodDataObjectEntry
3482 // array, it it is not a problem if there is a race, since one thread may just end up
3483 // doing some duplicate work.
3485 inline UINT32 GetNextChainDepth()
3486 { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
3488 inline void SetNextChainDepth(UINT32 iDepth)
3490 LIMITED_METHOD_CONTRACT;
3491 if (GetNextChainDepth() < iDepth) {
3492 VolatileStore(&m_iNextChainDepth, iDepth);
3496 // This is used when building the data
3497 struct MethodDataObjectEntry
3500 MethodDesc *m_pMDDecl;
3501 MethodDesc *m_pMDImpl;
3504 inline MethodDataObjectEntry() : m_pMDDecl(NULL), m_pMDImpl(NULL) {}
3506 inline void SetDeclMethodDesc(MethodDesc *pMD)
3507 { LIMITED_METHOD_CONTRACT; m_pMDDecl = pMD; }
3508 inline MethodDesc *GetDeclMethodDesc()
3509 { LIMITED_METHOD_CONTRACT; return m_pMDDecl; }
3510 inline void SetImplMethodDesc(MethodDesc *pMD)
3511 { LIMITED_METHOD_CONTRACT; m_pMDImpl = pMD; }
3512 inline MethodDesc *GetImplMethodDesc()
3513 { LIMITED_METHOD_CONTRACT; return m_pMDImpl; }
3517 // At the end of this object is an array, so you cannot derive from this class.
3520 inline MethodDataObjectEntry *GetEntryData()
3521 { LIMITED_METHOD_CONTRACT; return (MethodDataObjectEntry *)(this + 1); }
3523 inline MethodDataObjectEntry *GetEntry(UINT32 i)
3524 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
3526 void FillEntryDataForAncestor(MethodTable *pMT);
3528 // MethodDataObjectEntry m_rgEntries[...];
3529 }; // class MethodDataObject
3531 //--------------------------------------------------------------------------------------
3532 class MethodDataInterface : public MethodData
3535 // Static method that returns the amount of memory to allocate for a particular type.
3536 static UINT32 GetObjectSize(MethodTable *pMT)
3537 { LIMITED_METHOD_CONTRACT; return sizeof(MethodDataInterface); }
3539 // Constructor. Make sure you have allocated enough memory using GetObjectSize.
3540 MethodDataInterface(MethodTable *pMT)
3542 LIMITED_METHOD_CONTRACT;
3543 CONSISTENCY_CHECK(CheckPointer(pMT));
3544 CONSISTENCY_CHECK(pMT->IsInterface());
3547 virtual ~MethodDataInterface()
3548 { LIMITED_METHOD_CONTRACT; }
3553 virtual MethodData *GetDeclMethodData()
3554 { LIMITED_METHOD_CONTRACT; return this; }
3555 virtual MethodTable *GetDeclMethodTable()
3556 { LIMITED_METHOD_CONTRACT; return m_pMT; }
3557 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
3562 virtual MethodData *GetImplMethodData()
3563 { LIMITED_METHOD_CONTRACT; return this; }
3564 virtual MethodTable *GetImplMethodTable()
3565 { LIMITED_METHOD_CONTRACT; return m_pMT; }
3566 virtual DispatchSlot GetImplSlot(UINT32 slotNumber)
3567 { WRAPPER_NO_CONTRACT; return DispatchSlot(m_pMT->GetRestoredSlot(slotNumber)); }
3568 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber)
3569 { LIMITED_METHOD_CONTRACT; return slotNumber; }
3570 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3571 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3576 virtual UINT32 GetNumVirtuals()
3577 { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumVirtuals(); }
3578 virtual UINT32 GetNumMethods()
3579 { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumMethods(); }
3582 // This is the method table for the actual type we're gathering the data for
3584 }; // class MethodDataInterface
3586 //--------------------------------------------------------------------------------------
3587 class MethodDataInterfaceImpl : public MethodData
3590 // Object construction-related methods
3591 static UINT32 GetObjectSize(MethodTable *pMTDecl);
3593 MethodDataInterfaceImpl(
3594 const DispatchMapTypeID * rgDeclTypeIDs,
3595 UINT32 cDeclTypeIDs,
3597 MethodData * pImpl);
3598 virtual ~MethodDataInterfaceImpl();
3600 // Decl-related methods
3601 virtual MethodData *GetDeclMethodData()
3602 { LIMITED_METHOD_CONTRACT; return m_pDecl; }
3603 virtual MethodTable *GetDeclMethodTable()
3604 { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodTable(); }
3605 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber)
3606 { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodDesc(slotNumber); }
3608 // Impl-related methods
3609 virtual MethodData *GetImplMethodData()
3610 { LIMITED_METHOD_CONTRACT; return m_pImpl; }
3611 virtual MethodTable *GetImplMethodTable()
3612 { WRAPPER_NO_CONTRACT; return m_pImpl->GetImplMethodTable(); }
3613 virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
3614 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
3615 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3616 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3618 virtual UINT32 GetNumVirtuals()
3619 { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
3620 virtual UINT32 GetNumMethods()
3621 { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
3624 UINT32 MapToImplSlotNumber(UINT32 slotNumber);
3626 BOOL PopulateNextLevel();
3628 const DispatchMapTypeID * rgDeclTypeIDs,
3629 UINT32 cDeclTypeIDs,
3631 MethodData * pImpl);
3633 MethodData *m_pDecl;
3634 MethodData *m_pImpl;
3636 // This is used in staged map decoding - it indicates which type(s) we will find.
3637 const DispatchMapTypeID * m_rgDeclTypeIDs;
3638 UINT32 m_cDeclTypeIDs;
3639 UINT32 m_iNextChainDepth;
3640 static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
3642 inline UINT32 GetNextChainDepth()
3643 { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
3645 inline void SetNextChainDepth(UINT32 iDepth)
3647 LIMITED_METHOD_CONTRACT;
3648 if (GetNextChainDepth() < iDepth) {
3649 VolatileStore(&m_iNextChainDepth, iDepth);
3654 // At the end of this object is an array, so you cannot derive from this class.
3657 inline MethodDataEntry *GetEntryData()
3658 { LIMITED_METHOD_CONTRACT; return (MethodDataEntry *)(this + 1); }
3660 inline MethodDataEntry *GetEntry(UINT32 i)
3661 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
3663 // MethodDataEntry m_rgEntries[...];
3664 }; // class MethodDataInterfaceImpl
3666 //--------------------------------------------------------------------------------------
3667 static MethodDataCache *s_pMethodDataCache;
3668 static BOOL s_fUseParentMethodData;
3669 static BOOL s_fUseMethodDataCache;
3672 static void AllowMethodDataCaching()
3673 { WRAPPER_NO_CONTRACT; CheckInitMethodDataCache(); s_fUseMethodDataCache = TRUE; }
3674 static void ClearMethodDataCache();
3675 static void AllowParentMethodDataCopy()
3676 { LIMITED_METHOD_CONTRACT; s_fUseParentMethodData = TRUE; }
3677 // NOTE: The fCanCache argument determines if the resulting MethodData object can
3678 // be added to the global MethodDataCache. This is used when requesting a
3679 // MethodData object for a type currently being built.
3680 static MethodData *GetMethodData(MethodTable *pMT, BOOL fCanCache = TRUE);
3681 static MethodData *GetMethodData(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache = TRUE);
3682 // This method is used by BuildMethodTable because the exact interface has not yet been loaded.
3683 // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
3684 static MethodData * GetMethodData(
3685 const DispatchMapTypeID * rgDeclTypeIDs,
3686 UINT32 cDeclTypeIDs,
3687 MethodTable * pMTDecl,
3688 MethodTable * pMTImpl);
3691 static void CheckInitMethodDataCache();
3692 static MethodData *FindParentMethodDataHelper(MethodTable *pMT);
3693 static MethodData *FindMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl);
3694 static MethodData *GetMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache);
3695 // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
3696 static MethodData * GetMethodDataHelper(
3697 const DispatchMapTypeID * rgDeclTypeIDs,
3698 UINT32 cDeclTypeIDs,
3699 MethodTable * pMTDecl,
3700 MethodTable * pMTImpl);
3703 //--------------------------------------------------------------------------------------
3704 class MethodIterator
3707 MethodIterator(MethodTable *pMT);
3708 MethodIterator(MethodTable *pMTDecl, MethodTable *pMTImpl);
3709 MethodIterator(MethodData *pMethodData);
3710 MethodIterator(const MethodIterator &it);
3711 inline ~MethodIterator() { WRAPPER_NO_CONTRACT; m_pMethodData->Release(); }
3712 INT32 GetNumMethods() const;
3713 inline BOOL IsValid() const;
3714 inline BOOL MoveTo(UINT32 idx);
3717 inline void MoveToBegin();
3718 inline void MoveToEnd();
3719 inline UINT32 GetSlotNumber() const;
3720 inline UINT32 GetImplSlotNumber() const;
3721 inline BOOL IsVirtual() const;
3722 inline UINT32 GetNumVirtuals() const;
3723 inline DispatchSlot GetTarget() const;
3725 // Can be called only if IsValid()=TRUE
3726 inline MethodDesc *GetMethodDesc() const;
3727 inline MethodDesc *GetDeclMethodDesc() const;
3730 void Init(MethodTable *pMTDecl, MethodTable *pMTImpl);
3732 MethodData *m_pMethodData;
3733 INT32 m_iCur; // Current logical slot index
3735 }; // class MethodIterator
3736 #endif // !DACCESS_COMPILE
3738 //--------------------------------------------------------------------------------------
3739 // This iterator lets you walk over all the method bodies introduced by this type.
3740 // This includes new static methods, new non-virtual methods, and any overrides
3741 // of the parent's virtual methods. It does not include virtual method implementations
3742 // provided by the parent
3744 class IntroducedMethodIterator
3747 IntroducedMethodIterator(MethodTable *pMT, BOOL restrictToCanonicalTypes = TRUE);
3748 inline BOOL IsValid() const;
3751 // Can be called only if IsValid()=TRUE
3752 inline MethodDesc *GetMethodDesc() const;
3754 // Static worker methods of the iterator. These are meant to be used
3755 // by RuntimeTypeHandle::GetFirstIntroducedMethod and RuntimeTypeHandle::GetNextIntroducedMethod
3756 // only to expose this iterator to managed code.
3757 static MethodDesc * GetFirst(MethodTable * pMT);
3758 static MethodDesc * GetNext(MethodDesc * pMD);
3761 MethodDesc *m_pMethodDesc; // Current method desc
3763 // Cached info about current method desc
3764 MethodDescChunk *m_pChunk;
3767 void SetChunk(MethodDescChunk * pChunk);
3768 }; // class IntroducedMethodIterator
3770 //-------------------------------------------------------------------
3771 // INSTANCE MEMBER VARIABLES
3774 #ifdef DACCESS_COMPILE
3779 enum WFLAGS_LOW_ENUM
3781 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
3782 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
3783 // CARRY THE CORECT FLAGS.
3786 // We are overloading the low 2 bytes of m_dwFlags to be a component size for Strings
3787 // and Arrays and some set of flags which we can be assured are of a specified state
3788 // for Strings / Arrays, currently these will be a bunch of generics flags which don't
3789 // apply to Strings / Arrays.
3791 enum_flag_UNUSED_ComponentSize_1 = 0x00000001,
3793 enum_flag_StaticsMask = 0x00000006,
3794 enum_flag_StaticsMask_NonDynamic = 0x00000000,
3795 enum_flag_StaticsMask_Dynamic = 0x00000002, // dynamic statics (EnC, reflection.emit)
3796 enum_flag_StaticsMask_Generics = 0x00000004, // generics statics
3797 enum_flag_StaticsMask_CrossModuleGenerics = 0x00000006, // cross module generics statics (NGen)
3798 enum_flag_StaticsMask_IfGenericsThenCrossModule = 0x00000002, // helper constant to get rid of unnecessary check
3800 enum_flag_NotInPZM = 0x00000008, // True if this type is not in its PreferredZapModule
3802 enum_flag_GenericsMask = 0x00000030,
3803 enum_flag_GenericsMask_NonGeneric = 0x00000000, // no instantiation
3804 enum_flag_GenericsMask_GenericInst = 0x00000010, // regular instantiation, e.g. List<String>
3805 enum_flag_GenericsMask_SharedInst = 0x00000020, // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
3806 enum_flag_GenericsMask_TypicalInst = 0x00000030, // the type instantiated at its formal parameters, e.g. List<T>
3808 enum_flag_HasRemotingVtsInfo = 0x00000080, // Optional data present indicating VTS methods and optional fields
3810 enum_flag_HasVariance = 0x00000100, // This is an instantiated type some of whose type parameters are co or contra-variant
3812 enum_flag_HasDefaultCtor = 0x00000200,
3813 enum_flag_HasPreciseInitCctors = 0x00000400, // Do we need to run class constructors at allocation time? (Not perf important, could be moved to EEClass
3815 #if defined(FEATURE_HFA)
3816 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3817 #error Can't define both FEATURE_HFA and FEATURE_UNIX_AMD64_STRUCT_PASSING
3819 enum_flag_IsHFA = 0x00000800, // This type is an HFA (Homogenous Floating-point Aggregate)
3820 #endif // FEATURE_HFA
3822 #if defined(FEATURE_UNIX_AMD64_STRUCT_PASSING)
3823 #if defined(FEATURE_HFA)
3824 #error Can't define both FEATURE_HFA and FEATURE_UNIX_AMD64_STRUCT_PASSING
3826 enum_flag_IsRegStructPassed = 0x00000800, // This type is a System V register passed struct.
3827 #endif // FEATURE_UNIX_AMD64_STRUCT_PASSING
3829 enum_flag_IsByRefLike = 0x00001000,
3831 // In a perfect world we would fill these flags using other flags that we already have
3832 // which have a constant value for something which has a component size.
3833 enum_flag_UNUSED_ComponentSize_5 = 0x00002000,
3834 enum_flag_UNUSED_ComponentSize_6 = 0x00004000,
3835 enum_flag_UNUSED_ComponentSize_7 = 0x00008000,
3837 #define SET_FALSE(flag) (flag & 0)
3838 #define SET_TRUE(flag) (flag & 0xffff)
3840 // IMPORTANT! IMPORTANT! IMPORTANT!
3842 // As you change the flags in WFLAGS_LOW_ENUM you also need to change this
3843 // to be up to date to reflect the default values of those flags for the
3844 // case where this MethodTable is for a String or Array
3845 enum_flag_StringArrayValues = SET_TRUE(enum_flag_StaticsMask_NonDynamic) |
3846 SET_FALSE(enum_flag_NotInPZM) |
3847 SET_TRUE(enum_flag_GenericsMask_NonGeneric) |
3848 SET_FALSE(enum_flag_HasVariance) |
3849 SET_FALSE(enum_flag_HasDefaultCtor) |
3850 SET_FALSE(enum_flag_HasPreciseInitCctors),
3852 }; // enum WFLAGS_LOW_ENUM
3854 enum WFLAGS_HIGH_ENUM
3856 // DO NOT use flags that have bits set in the low 2 bytes.
3857 // These flags are DWORD sized so that our atomic masking
3858 // operations can operate on the entire 4-byte aligned DWORD
3859 // instead of the logical non-aligned WORD of flags. The
3860 // low WORD of flags is reserved for the component size.
3862 // The following bits describe mutually exclusive locations of the type
3863 // in the type hiearchy.
3864 enum_flag_Category_Mask = 0x000F0000,
3866 enum_flag_Category_Class = 0x00000000,
3867 enum_flag_Category_Unused_1 = 0x00010000,
3869 enum_flag_Category_MarshalByRef_Mask= 0x000E0000,
3870 enum_flag_Category_MarshalByRef = 0x00020000,
3871 enum_flag_Category_Contextful = 0x00030000, // sub-category of MarshalByRef
3873 enum_flag_Category_ValueType = 0x00040000,
3874 enum_flag_Category_ValueType_Mask = 0x000C0000,
3875 enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType
3876 enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or primitive value type
3877 enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.)
3879 enum_flag_Category_Array = 0x00080000,
3880 enum_flag_Category_Array_Mask = 0x000C0000,
3881 // enum_flag_Category_IfArrayThenUnused = 0x00010000, // sub-category of Array
3882 enum_flag_Category_IfArrayThenSzArray = 0x00020000, // sub-category of Array
3884 enum_flag_Category_Interface = 0x000C0000,
3885 enum_flag_Category_Unused_2 = 0x000D0000,
3886 enum_flag_Category_TransparentProxy = 0x000E0000,
3887 enum_flag_Category_AsyncPin = 0x000F0000,
3889 enum_flag_Category_ElementTypeMask = 0x000E0000, // bits that matter for element type mask
3892 enum_flag_HasFinalizer = 0x00100000, // instances require finalization
3894 enum_flag_IfNotInterfaceThenMarshalable = 0x00200000, // Is this type marshalable by the pinvoke marshalling layer
3895 #ifdef FEATURE_COMINTEROP
3896 enum_flag_IfInterfaceThenHasGuidInfo = 0x00200000, // Does the type has optional GuidInfo
3897 #endif // FEATURE_COMINTEROP
3899 enum_flag_ICastable = 0x00400000, // class implements ICastable interface
3901 enum_flag_HasIndirectParent = 0x00800000, // m_pParentMethodTable has double indirection
3903 enum_flag_ContainsPointers = 0x01000000,
3905 enum_flag_HasTypeEquivalence = 0x02000000, // can be equivalent to another type
3907 #ifdef FEATURE_COMINTEROP
3908 enum_flag_HasRCWPerTypeData = 0x04000000, // has optional pointer to RCWPerTypeData
3909 #endif // FEATURE_COMINTEROP
3911 enum_flag_HasCriticalFinalizer = 0x08000000, // finalizer must be run on Appdomain Unload
3912 enum_flag_Collectible = 0x10000000,
3913 enum_flag_ContainsGenericVariables = 0x20000000, // we cache this flag to help detect these efficiently and
3914 // to detect this condition when restoring
3916 enum_flag_ComObject = 0x40000000, // class is a com object
3918 enum_flag_HasComponentSize = 0x80000000, // This is set if component size is used for flags.
3920 // Types that require non-trivial interface cast have this bit set in the category
3921 enum_flag_NonTrivialInterfaceCast = enum_flag_Category_Array
3922 | enum_flag_ComObject
3923 | enum_flag_ICastable
3925 }; // enum WFLAGS_HIGH_ENUM
3927 // NIDump needs to be able to see these flags
3928 // TODO: figure out how to make these private
3929 #if defined(DACCESS_COMPILE)
3936 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
3937 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
3938 // CARRY THE CORECT FLAGS.
3940 // The following bits describe usage of optional slots. They have to stay
3941 // together because of we index using them into offset arrays.
3942 enum_flag_MultipurposeSlotsMask = 0x001F,
3943 enum_flag_HasPerInstInfo = 0x0001,
3944 enum_flag_HasInterfaceMap = 0x0002,
3945 enum_flag_HasDispatchMapSlot = 0x0004,
3946 enum_flag_HasNonVirtualSlots = 0x0008,
3947 enum_flag_HasModuleOverride = 0x0010,
3949 enum_flag_IsZapped = 0x0020, // This could be fetched from m_pLoaderModule if we run out of flags
3951 enum_flag_IsPreRestored = 0x0040, // Class does not need restore
3952 // This flag is set only for NGENed classes (IsZapped is true)
3954 enum_flag_HasModuleDependencies = 0x0080,
3956 // enum_Unused = 0x0100,
3958 enum_flag_RequiresDispatchTokenFat = 0x0200,
3960 enum_flag_HasCctor = 0x0400,
3961 enum_flag_HasCCWTemplate = 0x0800, // Has an extra field pointing to a CCW template
3963 #ifdef FEATURE_64BIT_ALIGNMENT
3964 enum_flag_RequiresAlign8 = 0x1000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)
3967 enum_flag_HasBoxedRegularStatics = 0x2000, // GetNumBoxedRegularStatics() != 0
3969 enum_flag_HasSingleNonVirtualSlot = 0x4000,
3971 enum_flag_DependsOnEquivalentOrForwardedStructs= 0x8000, // Declares methods that have type equivalent or type forwarded structures in their signature
3973 }; // enum WFLAGS2_ENUM
3975 __forceinline void ClearFlag(WFLAGS_LOW_ENUM flag)
3977 _ASSERTE(!IsStringOrArray());
3980 __forceinline void SetFlag(WFLAGS_LOW_ENUM flag)
3982 _ASSERTE(!IsStringOrArray());
3985 __forceinline DWORD GetFlag(WFLAGS_LOW_ENUM flag) const
3988 return (IsStringOrArray() ? (enum_flag_StringArrayValues & flag) : (m_dwFlags & flag));
3990 __forceinline BOOL TestFlagWithMask(WFLAGS_LOW_ENUM mask, WFLAGS_LOW_ENUM flag) const
3992 LIMITED_METHOD_DAC_CONTRACT;
3993 return (IsStringOrArray() ? (((DWORD)enum_flag_StringArrayValues & (DWORD)mask) == (DWORD)flag) :
3994 ((m_dwFlags & (DWORD)mask) == (DWORD)flag));
3997 __forceinline void ClearFlag(WFLAGS_HIGH_ENUM flag)
4001 __forceinline void SetFlag(WFLAGS_HIGH_ENUM flag)
4005 __forceinline DWORD GetFlag(WFLAGS_HIGH_ENUM flag) const
4007 LIMITED_METHOD_DAC_CONTRACT;
4008 return m_dwFlags & flag;
4010 __forceinline BOOL TestFlagWithMask(WFLAGS_HIGH_ENUM mask, WFLAGS_HIGH_ENUM flag) const
4012 LIMITED_METHOD_DAC_CONTRACT;
4013 return ((m_dwFlags & (DWORD)mask) == (DWORD)flag);
4016 __forceinline void ClearFlag(WFLAGS2_ENUM flag)
4020 __forceinline void SetFlag(WFLAGS2_ENUM flag)
4024 __forceinline DWORD GetFlag(WFLAGS2_ENUM flag) const
4026 LIMITED_METHOD_DAC_CONTRACT;
4027 return m_wFlags2 & flag;
4029 __forceinline BOOL TestFlagWithMask(WFLAGS2_ENUM mask, WFLAGS2_ENUM flag) const
4031 return (m_wFlags2 & (DWORD)mask) == (DWORD)flag;
4034 // Just exposing a couple of these for x86 asm versions of JIT_IsInstanceOfClass and JIT_IsInstanceOfInterface
4038 public_enum_flag_HasTypeEquivalence = enum_flag_HasTypeEquivalence,
4039 public_enum_flag_NonTrivialInterfaceCast = enum_flag_NonTrivialInterfaceCast,
4044 * This stuff must be first in the struct and should fit on a cache line - don't move it. Used by the GC.
4049 // Low WORD is component size for array and string types (HasComponentSize() returns true).
4050 // Used for flags otherwise.
4053 // Base size of instance of this class when allocated on the heap
4059 // Class token if it fits into 16-bits. If this is (WORD)-1, the class token is stored in the TokenOverflow optional member.
4062 // <NICE> In the normal cases we shouldn't need a full word for each of these </NICE>
4063 WORD m_wNumVirtuals;
4064 WORD m_wNumInterfaces;
4067 LPCUTF8 debug_m_szClassName;
4070 // Parent PTR_MethodTable if enum_flag_HasIndirectParent is not set. Pointer to indirection cell
4071 // if enum_flag_enum_flag_HasIndirectParent is set. The indirection is offset by offsetof(MethodTable, m_pParentMethodTable).
4072 // It allows casting helpers to go through parent chain natually. Casting helper do not need need the explicit check
4073 // for enum_flag_HasIndirectParentMethodTable.
4074 ParentMT_t m_pParentMethodTable;
4076 RelativePointer<PTR_Module> m_pLoaderModule; // LoaderModule. It is equal to the ZapModule in ngened images
4078 #if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
4079 RelativePointer<PTR_MethodTableWriteableData> m_pWriteableData;
4081 PlainPointer<PTR_MethodTableWriteableData> m_pWriteableData;
4084 // The value of lowest two bits describe what the union contains
4086 UNION_EECLASS = 0, // 0 - pointer to EEClass. This MethodTable is the canonical method table.
4087 UNION_INVALID = 1, // 1 - not used
4088 UNION_METHODTABLE = 2, // 2 - pointer to canonical MethodTable.
4089 UNION_INDIRECTION = 3 // 3 - pointer to indirection cell that points to canonical MethodTable.
4090 }; // (used only if FEATURE_PREJIT is defined)
4091 static const TADDR UNION_MASK = 3;
4094 #if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
4095 RelativePointer<DPTR(EEClass)> m_pEEClass;
4096 RelativePointer<TADDR> m_pCanonMT;
4098 PlainPointer<DPTR(EEClass)> m_pEEClass;
4099 PlainPointer<TADDR> m_pCanonMT;
4103 __forceinline static LowBits union_getLowBits(TADDR pCanonMT)
4105 LIMITED_METHOD_DAC_CONTRACT;
4106 return LowBits(pCanonMT & UNION_MASK);
4108 __forceinline static TADDR union_getPointer(TADDR pCanonMT)
4110 LIMITED_METHOD_DAC_CONTRACT;
4111 return (pCanonMT & ~UNION_MASK);
4114 // m_pPerInstInfo and m_pInterfaceMap have to be at fixed offsets because of performance sensitive
4115 // JITed code and JIT helpers. However, they are frequently not present. The space is used by other
4116 // multipurpose slots on first come first served basis if the fixed ones are not present. The other
4117 // multipurpose are DispatchMapSlot, NonVirtualSlots, ModuleOverride (see enum_flag_MultipurposeSlotsMask).
4118 // The multipurpose slots that do not fit are stored after vtable slots.
4122 PerInstInfo_t m_pPerInstInfo;
4123 TADDR m_ElementTypeHnd;
4124 TADDR m_pMultipurposeSlot1;
4129 #if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
4130 RelativePointer<PTR_InterfaceInfo> m_pInterfaceMap;
4132 PlainPointer<PTR_InterfaceInfo> m_pInterfaceMap;
4134 TADDR m_pMultipurposeSlot2;
4137 // VTable and Non-Virtual slots go here
4139 // Overflow multipurpose slots go here
4141 // Optional Members go here
4142 // See above for the list of optional members
4144 // Generic dictionary pointers go here
4146 // Interface map goes here
4148 // Generic instantiation+dictionary goes here
4152 // disallow direct creation
4153 void *operator new(size_t dummy);
4154 void operator delete(void *pData);
4157 // Optional members. These are used for fields in the data structure where
4158 // the fields are (a) known when MT is created and (b) there is a default
4159 // value for the field in the common case. That is, they are normally used
4160 // for data that is only relevant to a small number of method tables.
4162 // Optional members and multipurpose slots have similar purpose, but they differ in details:
4163 // - Multipurpose slots can only accomodate pointer sized structures right now. It is non-trivial
4164 // to add new ones, the access is faster.
4165 // - Optional members can accomodate structures of any size. It is trivial to add new ones,
4166 // the access is slower.
4168 // The following macro will automatically create GetXXX accessors for the optional members.
4169 #define METHODTABLE_OPTIONAL_MEMBERS() \
4170 /* NAME TYPE GETTER */ \
4171 /* Accessing this member efficiently is currently performance critical for static field accesses */ \
4172 /* in generic classes, so place it early in the list. */ \
4173 METHODTABLE_OPTIONAL_MEMBER(GenericsStaticsInfo, GenericsStaticsInfo, GetGenericsStaticsInfo ) \
4174 /* Accessed by interop, fairly frequently. */ \
4175 METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS() \
4176 /* Accessed during x-domain transition only, so place it late in the list. */ \
4177 METHODTABLE_REMOTING_OPTIONAL_MEMBERS() \
4178 /* Accessed during certain generic type load operations only, so low priority */ \
4179 METHODTABLE_OPTIONAL_MEMBER(ExtraInterfaceInfo, TADDR, GetExtraInterfaceInfoPtr ) \
4180 /* TypeDef token for assemblies with more than 64k types. Never happens in real world. */ \
4181 METHODTABLE_OPTIONAL_MEMBER(TokenOverflow, TADDR, GetTokenOverflowPtr ) \
4183 #ifdef FEATURE_COMINTEROP
4184 #define METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS() \
4185 METHODTABLE_OPTIONAL_MEMBER(GuidInfo, PTR_GuidInfo, GetGuidInfoPtr ) \
4186 METHODTABLE_OPTIONAL_MEMBER(RCWPerTypeData, RCWPerTypeData *, GetRCWPerTypeDataPtr ) \
4187 METHODTABLE_OPTIONAL_MEMBER(CCWTemplate, ComCallWrapperTemplate *, GetCCWTemplatePtr )
4189 #define METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS()
4192 #define METHODTABLE_REMOTING_OPTIONAL_MEMBERS()
4194 enum OptionalMemberId
4196 #undef METHODTABLE_OPTIONAL_MEMBER
4197 #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) OptionalMember_##NAME,
4198 METHODTABLE_OPTIONAL_MEMBERS()
4199 OptionalMember_Count,
4201 OptionalMember_First = OptionalMember_GenericsStaticsInfo,
4204 FORCEINLINE DWORD GetOffsetOfOptionalMember(OptionalMemberId id);
4209 // Public accessor helpers for the optional members of MethodTable
4212 #undef METHODTABLE_OPTIONAL_MEMBER
4213 #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \
4214 inline DPTR(TYPE) GETTER() \
4216 LIMITED_METHOD_CONTRACT; \
4217 STATIC_CONTRACT_SO_TOLERANT; \
4218 _ASSERTE(Has##NAME()); \
4219 return dac_cast<DPTR(TYPE)>(dac_cast<TADDR>(this) + GetOffsetOfOptionalMember(OptionalMember_##NAME)); \
4222 METHODTABLE_OPTIONAL_MEMBERS()
4225 inline DWORD GetStartOffsetOfOptionalMembers()
4227 WRAPPER_NO_CONTRACT;
4228 return GetOffsetOfOptionalMember(OptionalMember_First);
4231 inline DWORD GetEndOffsetOfOptionalMembers()
4233 WRAPPER_NO_CONTRACT;
4234 return GetOffsetOfOptionalMember(OptionalMember_Count);
4237 inline static DWORD GetOptionalMembersAllocationSize(
4238 DWORD dwMultipurposeSlotsMask,
4239 BOOL needsRemotableMethodInfo,
4240 BOOL needsGenericsStaticsInfo,
4242 BOOL needsCCWTemplate,
4243 BOOL needsRCWPerTypeData,
4244 BOOL needsRemotingVtsInfo,
4245 BOOL needsContextStatic,
4246 BOOL needsTokenOverflow);
4247 inline DWORD GetOptionalMembersSize();
4249 // The PerInstInfo is a (possibly empty) array of pointers to
4250 // Instantiations/Dictionaries. This array comes after the optional members.
4251 inline DWORD GetPerInstInfoSize();
4253 // This is the size of the interface map chunk in the method table.
4254 // If the MethodTable has a dynamic interface map then the size includes the pointer
4255 // that stores the extra info for that map.
4256 // The interface map itself comes after the PerInstInfo (if any)
4257 inline DWORD GetInterfaceMapSize();
4259 // The instantiation/dictionary comes at the end of the MethodTable after
4260 // the interface map.
4261 inline DWORD GetInstAndDictSize();
4264 // Helper template to compute the offsets at compile time
4266 struct MultipurposeSlotOffset;
4268 static const BYTE c_DispatchMapSlotOffsets[];
4269 static const BYTE c_NonVirtualSlotsOffsets[];
4270 static const BYTE c_ModuleOverrideOffsets[];
4272 static const BYTE c_OptionalMembersStartOffsets[]; // total sizes of optional slots
4274 TADDR GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const BYTE * offsets);
4276 void SetMultipurposeSlotsMask(DWORD dwMask)
4278 LIMITED_METHOD_CONTRACT;
4279 _ASSERTE((m_wFlags2 & enum_flag_MultipurposeSlotsMask) == 0);
4280 m_wFlags2 |= (WORD)dwMask;
4283 BOOL HasModuleOverride()
4285 LIMITED_METHOD_DAC_CONTRACT;
4286 return GetFlag(enum_flag_HasModuleOverride);
4289 DPTR(RelativeFixupPointer<PTR_Module>) GetModuleOverridePtr()
4291 LIMITED_METHOD_DAC_CONTRACT;
4292 return dac_cast<DPTR(RelativeFixupPointer<PTR_Module>)>(GetMultipurposeSlotPtr(enum_flag_HasModuleOverride, c_ModuleOverrideOffsets));
4295 void SetModule(Module * pModule);
4297 /************************************
4301 ************************************/
4307 #ifdef FEATURE_READYTORUN_COMPILER
4309 // Is field layout in this type fixed within the current version bubble?
4310 // This check does not take the inheritance chain into account.
4312 BOOL IsLayoutFixedInCurrentVersionBubble();
4315 // Is field layout of the inheritance chain fixed within the current version bubble?
4317 BOOL IsInheritanceChainLayoutFixedInCurrentVersionBubble();
4320 }; // class MethodTable
4322 #if defined(FEATURE_COMINTEROP) && !defined(DACCESS_COMPILE)
4323 WORD GetEquivalentMethodSlot(MethodTable * pOldMT, MethodTable * pNewMT, WORD wMTslot, BOOL *pfFound);
4324 #endif // defined(FEATURE_COMINTEROP) && !defined(DACCESS_COMPILE)
4326 MethodTable* CreateMinimalMethodTable(Module* pContainingModule,
4327 LoaderHeap* pCreationHeap,
4328 AllocMemTracker* pamTracker);
4330 #endif // !_METHODTABLE_H_