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.
4//
5// File: methodtable.h
6//
7
8#ifndef _METHODTABLE_H_
9#define _METHODTABLE_H_
10
11/*
12 * Include Files
13 */
14#include "vars.hpp"
15#include "cor.h"
16#include "hash.h"
17#include "crst.h"
18#include "cgensys.h"
19#include "declsec.h"
20#ifdef FEATURE_COMINTEROP
21#include "stdinterfaces.h"
22#endif
23#include "slist.h"
24#include "spinlock.h"
25#include "typehandle.h"
26#include "eehash.h"
27#include "contractimpl.h"
28#include "generics.h"
29#include "fixuppointer.h"
30#include "gcinfotypes.h"
31
32/*
33 * Forward Declarations
34 */
35class AppDomain;
36class ArrayClass;
37class ArrayMethodDesc;
38struct ClassCtorInfoEntry;
39class ClassLoader;
40class DomainLocalBlock;
41class FCallMethodDesc;
42class EEClass;
43class EnCFieldDesc;
44class FieldDesc;
45class JIT_TrialAlloc;
46struct LayoutRawFieldInfo;
47class MetaSig;
48class MethodDesc;
49class MethodDescChunk;
50class MethodTable;
51class Module;
52class Object;
53class Stub;
54class Substitution;
55class TypeHandle;
56class Dictionary;
57class AllocMemTracker;
58class SimpleRWLock;
59class MethodDataCache;
60class EEClassLayoutInfo;
61#ifdef FEATURE_COMINTEROP
62class ComCallWrapperTemplate;
63#endif
64#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
65class ClassFactoryBase;
66#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
67class ArgDestination;
68
69//============================================================================
70// This is the in-memory structure of a class and it will evolve.
71//============================================================================
72
73// <TODO>
74// Add a sync block
75// Also this class currently has everything public - this may changes
76// Might also need to hold onto the meta data loader fot this class</TODO>
77
78//
79// A MethodTable contains an array of these structures, which describes each interface implemented
80// by this class (directly declared or indirectly declared).
81//
82// Generic type instantiations (in C# syntax: C<ty_1,...,ty_n>) are represented by
83// MethodTables, i.e. a new MethodTable gets allocated for each such instantiation.
84// The entries in these tables (i.e. the code) are, however, often shared.
85//
86// In particular, a MethodTable's vtable contents (and hence method descriptors) may be
87// shared between compatible instantiations (e.g. List<string> and List<object> have
88// the same vtable *contents*). Likewise the EEClass will be shared between
89// compatible instantiations whenever the vtable contents are.
90//
91// !!! Thus that it is _not_ generally the case that GetClass.GetMethodTable() == t. !!!
92//
93// Instantiated interfaces have their own method tables unique to the instantiation e.g. I<string> is
94// distinct from I<int> and I<object>
95//
96// For generic types the interface map lists generic interfaces
97// For instantiated types the interface map lists instantiated interfaces
98// e.g. for C<T> : I<T>, J<string>
99// the interface map for C would list I and J
100// the interface map for C<int> would list I<int> and J<string>
101//
102struct InterfaceInfo_t
103{
104#ifdef DACCESS_COMPILE
105 friend class NativeImageDumper;
106#endif
107
108 // Method table of the interface
109#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
110 RelativeFixupPointer<PTR_MethodTable> m_pMethodTable;
111#else
112 FixupPointer<PTR_MethodTable> m_pMethodTable;
113#endif
114
115public:
116 FORCEINLINE PTR_MethodTable GetMethodTable()
117 {
118 LIMITED_METHOD_CONTRACT;
119 return ReadPointerMaybeNull(this, &InterfaceInfo_t::m_pMethodTable);
120 }
121
122#ifndef DACCESS_COMPILE
123 void SetMethodTable(MethodTable * pMT)
124 {
125 LIMITED_METHOD_CONTRACT;
126 m_pMethodTable.SetValueMaybeNull(pMT);
127 }
128
129 // Get approximate method table. This is used by the type loader before the type is fully loaded.
130 PTR_MethodTable GetApproxMethodTable(Module * pContainingModule);
131#endif // !DACCESS_COMPILE
132
133#ifndef DACCESS_COMPILE
134 InterfaceInfo_t(InterfaceInfo_t &right)
135 {
136 m_pMethodTable.SetValueMaybeNull(right.m_pMethodTable.GetValueMaybeNull());
137 }
138#else // !DACCESS_COMPILE
139private:
140 InterfaceInfo_t(InterfaceInfo_t &right);
141#endif // !DACCESS_COMPILE
142}; // struct InterfaceInfo_t
143
144typedef DPTR(InterfaceInfo_t) PTR_InterfaceInfo;
145
146namespace ClassCompat
147{
148 struct InterfaceInfo_t;
149};
150
151// Data needed when simulating old VTable layout for COM Interop
152// This is necessary as the data is saved in MethodDescs and we need
153// to simulate different values without copying or changing the existing
154// MethodDescs
155//
156// This will be created in a parallel array to ppMethodDescList and
157// ppUnboxMethodDescList in the bmtMethAndFieldDescs structure below
158struct InteropMethodTableSlotData
159{
160 enum
161 {
162 e_DUPLICATE = 0x0001 // The entry is duplicate
163 };
164
165 MethodDesc *pMD; // The MethodDesc for this slot
166 WORD wSlot; // The simulated slot value for the MethodDesc
167 WORD wFlags; // The simulated duplicate value
168 MethodDesc *pDeclMD; // To keep track of MethodImpl's
169
170 void SetDuplicate()
171 {
172 wFlags |= e_DUPLICATE;
173 }
174
175 BOOL IsDuplicate() {
176 return ((BOOL)(wFlags & e_DUPLICATE));
177 }
178
179 WORD GetSlot() {
180 return wSlot;
181 }
182
183 void SetSlot(WORD wSlot) {
184 this->wSlot = wSlot;
185 }
186}; // struct InteropMethodTableSlotData
187
188#ifdef FEATURE_COMINTEROP
189struct InteropMethodTableData
190{
191 WORD cVTable; // Count of vtable slots
192 InteropMethodTableSlotData *pVTable; // Data for each slot
193
194 WORD cNonVTable; // Count of non-vtable slots
195 InteropMethodTableSlotData *pNonVTable; // Data for each slot
196
197 WORD cInterfaceMap; // Count of interfaces
198 ClassCompat::InterfaceInfo_t *
199 pInterfaceMap; // The interface map
200
201 // Utility methods
202 static WORD GetRealMethodDesc(MethodTable *pMT, MethodDesc *pMD);
203 static WORD GetSlotForMethodDesc(MethodTable *pMT, MethodDesc *pMD);
204 ClassCompat::InterfaceInfo_t* FindInterface(MethodTable *pInterface);
205 WORD GetStartSlotForInterface(MethodTable* pInterface);
206};
207
208class InteropMethodTableSlotDataMap
209{
210protected:
211 InteropMethodTableSlotData *m_pSlotData;
212 DWORD m_cSlotData;
213 DWORD m_iCurSlot;
214
215public:
216 InteropMethodTableSlotDataMap(InteropMethodTableSlotData *pSlotData, DWORD cSlotData);
217 InteropMethodTableSlotData *GetData(MethodDesc *pMD);
218 BOOL Exists(MethodDesc *pMD);
219
220protected:
221 InteropMethodTableSlotData *Exists_Helper(MethodDesc *pMD);
222 InteropMethodTableSlotData *GetNewEntry();
223}; // class InteropMethodTableSlotDataMap
224#endif // FEATURE_COMINTEROP
225
226//
227// This struct contains cached information on the GUID associated with a type.
228//
229
230struct GuidInfo
231{
232 GUID m_Guid; // The actual guid of the type.
233 BOOL m_bGeneratedFromName; // A boolean indicating if it was generated from the
234 // name of the type.
235};
236
237typedef DPTR(GuidInfo) PTR_GuidInfo;
238
239
240// GenericsDictInfo is stored at negative offset of the dictionary
241struct GenericsDictInfo
242{
243#ifdef _WIN64
244 DWORD m_dwPadding; // Just to keep the size a multiple of 8
245#endif
246
247 // Total number of instantiation dictionaries including inherited ones
248 // i.e. how many instantiated classes (including this one) are there in the hierarchy?
249 // See comments about PerInstInfo
250 WORD m_wNumDicts;
251
252 // Number of type parameters (NOT including those of superclasses).
253 WORD m_wNumTyPars;
254}; // struct GenericsDictInfo
255typedef DPTR(GenericsDictInfo) PTR_GenericsDictInfo;
256
257struct GenericsStaticsInfo
258{
259 // Pointer to field descs for statics
260 RelativePointer<PTR_FieldDesc> m_pFieldDescs;
261
262 // Method table ID for statics
263 SIZE_T m_DynamicTypeID;
264
265}; // struct GenericsStaticsInfo
266typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo;
267
268
269// CrossModuleGenericsStaticsInfo is used in NGen images for statics of cross-module
270// generic instantiations. CrossModuleGenericsStaticsInfo is optional member of
271// MethodTableWriteableData.
272struct CrossModuleGenericsStaticsInfo
273{
274 // Module this method table statics are attached to.
275 //
276 // The statics has to be attached to module referenced from the generic instantiation
277 // in domain-neutral code. We need to guarantee that the module for the statics
278 // has a valid local represenation in an appdomain.
279 //
280 PTR_Module m_pModuleForStatics;
281
282 // Method table ID for statics
283 SIZE_T m_DynamicTypeID;
284}; // struct CrossModuleGenericsStaticsInfo
285typedef DPTR(CrossModuleGenericsStaticsInfo) PTR_CrossModuleGenericsStaticsInfo;
286
287#ifdef FEATURE_COMINTEROP
288struct RCWPerTypeData;
289#endif // FEATURE_COMINTEROP
290
291//
292// This struct consolidates the writeable parts of the MethodTable
293// so that we can layout a read-only MethodTable with a pointer
294// to the writeable parts of the MethodTable in an ngen image
295//
296struct MethodTableWriteableData
297{
298 friend class MethodTable;
299#if defined(DACCESS_COMPILE)
300 friend class NativeImageDumper;
301#endif
302
303 enum
304 {
305 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
306 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
307 // CARRY THE CORRECT INITIAL FLAGS.
308
309 enum_flag_Unrestored = 0x00000004,
310 enum_flag_HasApproxParent = 0x00000010,
311 enum_flag_UnrestoredTypeKey = 0x00000020,
312 enum_flag_IsNotFullyLoaded = 0x00000040,
313 enum_flag_DependenciesLoaded = 0x00000080, // class and all depedencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED
314
315 enum_flag_SkipWinRTOverride = 0x00000100, // No WinRT override is needed
316
317 enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x00000200, // Is any field type or sub field type overrode Equals or GetHashCode
318 enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x00000400, // Whether we have checked the overridden Equals or GetHashCode
319
320#ifdef FEATURE_PREJIT
321 // These flags are used only at ngen time. We store them here since
322 // we are running out of available flags in MethodTable. They may eventually
323 // go into ngen speficic state.
324 enum_flag_NGEN_IsFixedUp = 0x00010000, // This MT has been fixed up during NGEN
325 enum_flag_NGEN_IsNeedsRestoreCached = 0x00020000, // Set if we have cached the results of needs restore computation
326 enum_flag_NGEN_CachedNeedsRestore = 0x00040000, // The result of the needs restore computation
327 enum_flag_NGEN_OverridingInterface = 0x00080000, // Overriding interface that we should generate WinRT CCW stubs for.
328
329#ifdef FEATURE_READYTORUN_COMPILER
330 enum_flag_NGEN_IsLayoutFixedComputed = 0x0010000, // Set if we have cached the result of IsLayoutFixed computation
331 enum_flag_NGEN_IsLayoutFixed = 0x0020000, // The result of the IsLayoutFixed computation
332#endif
333
334#endif // FEATURE_PREJIT
335
336#ifdef _DEBUG
337 enum_flag_ParentMethodTablePointerValid = 0x40000000,
338 enum_flag_HasInjectedInterfaceDuplicates = 0x80000000,
339#endif
340 };
341 DWORD m_dwFlags; // Lot of empty bits here.
342
343 /*
344 * m_hExposedClassObject is LoaderAllocator slot index to
345 * a RuntimeType instance for this class.
346 */
347 LOADERHANDLE m_hExposedClassObject;
348
349#ifdef _DEBUG
350 // to avoid verify same method table too many times when it's not changing, we cache the GC count
351 // on which the method table is verified. When fast GC STRESS is turned on, we only verify the MT if
352 // current GC count is bigger than the number. Note most thing which will invalidate a MT will require a
353 // GC (like AD unload)
354 Volatile<DWORD> m_dwLastVerifedGCCnt;
355
356#ifdef _WIN64
357 DWORD m_dwPadding; // Just to keep the size a multiple of 8
358#endif
359
360#endif
361
362 // Optional CrossModuleGenericsStaticsInfo may be here.
363
364public:
365#ifdef _DEBUG
366 inline BOOL IsParentMethodTablePointerValid() const
367 {
368 LIMITED_METHOD_DAC_CONTRACT;
369
370 return (m_dwFlags & enum_flag_ParentMethodTablePointerValid);
371 }
372 inline void SetParentMethodTablePointerValid()
373 {
374 LIMITED_METHOD_CONTRACT;
375
376 m_dwFlags |= enum_flag_ParentMethodTablePointerValid;
377 }
378#endif
379
380#ifdef FEATURE_PREJIT
381
382 void Save(DataImage *image, MethodTable *pMT, DWORD profilingFlags) const;
383 void Fixup(DataImage *image, MethodTable *pMT, BOOL needsRestore);
384
385 inline BOOL IsFixedUp() const
386 {
387 LIMITED_METHOD_CONTRACT;
388
389 return (m_dwFlags & enum_flag_NGEN_IsFixedUp);
390 }
391 inline void SetFixedUp()
392 {
393 LIMITED_METHOD_CONTRACT;
394
395 m_dwFlags |= enum_flag_NGEN_IsFixedUp;
396 }
397
398 inline BOOL IsNeedsRestoreCached() const
399 {
400 LIMITED_METHOD_CONTRACT;
401
402 return (m_dwFlags & enum_flag_NGEN_IsNeedsRestoreCached);
403 }
404
405 inline BOOL GetCachedNeedsRestore() const
406 {
407 LIMITED_METHOD_CONTRACT;
408
409 _ASSERTE(IsNeedsRestoreCached());
410 return (m_dwFlags & enum_flag_NGEN_CachedNeedsRestore);
411 }
412
413 inline void SetCachedNeedsRestore(BOOL fNeedsRestore)
414 {
415 LIMITED_METHOD_CONTRACT;
416
417 _ASSERTE(!IsNeedsRestoreCached());
418 m_dwFlags |= enum_flag_NGEN_IsNeedsRestoreCached;
419 if (fNeedsRestore) m_dwFlags |= enum_flag_NGEN_CachedNeedsRestore;
420 }
421
422 inline void SetIsOverridingInterface()
423 {
424 CONTRACTL
425 {
426 THROWS;
427 GC_NOTRIGGER;
428 MODE_ANY;
429 }
430 CONTRACTL_END;
431
432 if ((m_dwFlags & enum_flag_NGEN_OverridingInterface) != 0) return;
433 FastInterlockOr(EnsureWritablePages((ULONG *) &m_dwFlags), enum_flag_NGEN_OverridingInterface);
434 }
435
436 inline BOOL IsOverridingInterface() const
437 {
438 LIMITED_METHOD_CONTRACT;
439 return (m_dwFlags & enum_flag_NGEN_OverridingInterface);
440 }
441#endif // FEATURE_PREJIT
442
443
444 inline LOADERHANDLE GetExposedClassObjectHandle() const
445 {
446 LIMITED_METHOD_CONTRACT;
447 return m_hExposedClassObject;
448 }
449
450 void SetIsNotFullyLoadedForBuildMethodTable()
451 {
452 LIMITED_METHOD_CONTRACT;
453
454 // Used only during method table initialization - no need for logging or Interlocked Exchange.
455 m_dwFlags |= (MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
456 MethodTableWriteableData::enum_flag_Unrestored |
457 MethodTableWriteableData::enum_flag_IsNotFullyLoaded |
458 MethodTableWriteableData::enum_flag_HasApproxParent);
459 }
460
461 void SetIsRestoredForBuildMethodTable()
462 {
463 LIMITED_METHOD_CONTRACT;
464
465 // Used only during method table initialization - no need for logging or Interlocked Exchange.
466 m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
467 MethodTableWriteableData::enum_flag_Unrestored);
468 }
469
470 void SetIsFullyLoadedForBuildMethodTable()
471 {
472 LIMITED_METHOD_CONTRACT;
473
474 // Used only during method table initialization - no need for logging or Interlocked Exchange.
475 m_dwFlags &= ~(MethodTableWriteableData::enum_flag_UnrestoredTypeKey |
476 MethodTableWriteableData::enum_flag_Unrestored |
477 MethodTableWriteableData::enum_flag_IsNotFullyLoaded |
478 MethodTableWriteableData::enum_flag_HasApproxParent);
479 }
480
481 inline CrossModuleGenericsStaticsInfo * GetCrossModuleGenericsStaticsInfo()
482 {
483 LIMITED_METHOD_DAC_CONTRACT;
484
485 SIZE_T size = sizeof(MethodTableWriteableData);
486 return PTR_CrossModuleGenericsStaticsInfo(dac_cast<TADDR>(this) + size);
487 }
488
489}; // struct MethodTableWriteableData
490
491typedef DPTR(MethodTableWriteableData) PTR_MethodTableWriteableData;
492typedef DPTR(MethodTableWriteableData const) PTR_Const_MethodTableWriteableData;
493
494#ifdef UNIX_AMD64_ABI_ITF
495inline
496SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeType)
497{
498 static const SystemVClassificationType toSystemVAmd64ClassificationTypeMap[] = {
499 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_END
500 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VOID
501 SystemVClassificationTypeInteger, // ELEMENT_TYPE_BOOLEAN
502 SystemVClassificationTypeInteger, // ELEMENT_TYPE_CHAR
503 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I1
504 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U1
505 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I2
506 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U2
507 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I4
508 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U4
509 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I8
510 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U8
511 SystemVClassificationTypeSSE, // ELEMENT_TYPE_R4
512 SystemVClassificationTypeSSE, // ELEMENT_TYPE_R8
513 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_STRING
514 SystemVClassificationTypeInteger, // ELEMENT_TYPE_PTR
515 SystemVClassificationTypeIntegerByRef, // ELEMENT_TYPE_BYREF
516 SystemVClassificationTypeStruct, // ELEMENT_TYPE_VALUETYPE
517 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_CLASS
518 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_VAR (type variable)
519 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_ARRAY
520 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_GENERICINST
521 SystemVClassificationTypeTypedReference, // ELEMENT_TYPE_TYPEDBYREF
522 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_VALUEARRAY_UNSUPPORTED
523 SystemVClassificationTypeInteger, // ELEMENT_TYPE_I
524 SystemVClassificationTypeInteger, // ELEMENT_TYPE_U
525 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_R_UNSUPPORTED
526
527 // put the correct type when we know our implementation
528 SystemVClassificationTypeInteger, // ELEMENT_TYPE_FNPTR
529 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_OBJECT
530 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_SZARRAY
531 SystemVClassificationTypeIntegerReference, // ELEMENT_TYPE_MVAR
532
533 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_REQD
534 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_OPT
535 SystemVClassificationTypeUnknown, // ELEMENT_TYPE_INTERNAL
536 };
537
538 _ASSERTE(sizeof(toSystemVAmd64ClassificationTypeMap) == ELEMENT_TYPE_MAX);
539 _ASSERTE(eeType < (CorElementType) sizeof(toSystemVAmd64ClassificationTypeMap));
540 // spot check of the map
541 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_I4] == SystemVClassificationTypeInteger);
542 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_PTR] == SystemVClassificationTypeInteger);
543 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_VALUETYPE] == SystemVClassificationTypeStruct);
544 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_TYPEDBYREF] == SystemVClassificationTypeTypedReference);
545 _ASSERTE((SystemVClassificationType)toSystemVAmd64ClassificationTypeMap[ELEMENT_TYPE_BYREF] == SystemVClassificationTypeIntegerByRef);
546
547 return (((unsigned)eeType) < ELEMENT_TYPE_MAX) ? (toSystemVAmd64ClassificationTypeMap[(unsigned)eeType]) : SystemVClassificationTypeUnknown;
548};
549
550#define SYSTEMV_EIGHT_BYTE_SIZE_IN_BYTES 8 // Size of an eightbyte in bytes.
551#define SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT 16 // Maximum number of fields in struct passed in registers
552
553struct SystemVStructRegisterPassingHelper
554{
555 SystemVStructRegisterPassingHelper(unsigned int totalStructSize) :
556 structSize(totalStructSize),
557 eightByteCount(0),
558 inEmbeddedStruct(false),
559 currentUniqueOffsetField(0),
560 largestFieldOffset(-1)
561 {
562 for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++)
563 {
564 eightByteClassifications[i] = SystemVClassificationTypeNoClass;
565 eightByteSizes[i] = 0;
566 eightByteOffsets[i] = 0;
567 }
568
569 // Initialize the work arrays
570 for (int i = 0; i < SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT; i++)
571 {
572 fieldClassifications[i] = SystemVClassificationTypeNoClass;
573 fieldSizes[i] = 0;
574 fieldOffsets[i] = 0;
575 }
576 }
577
578 // Input state.
579 unsigned int structSize;
580
581 // These fields are the output; these are what is computed by the classification algorithm.
582 unsigned int eightByteCount;
583 SystemVClassificationType eightByteClassifications[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
584 unsigned int eightByteSizes[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
585 unsigned int eightByteOffsets[CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS];
586
587 // Helper members to track state.
588 bool inEmbeddedStruct;
589 unsigned int currentUniqueOffsetField; // A virtual field that could encompass many overlapping fields.
590 int largestFieldOffset;
591 SystemVClassificationType fieldClassifications[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
592 unsigned int fieldSizes[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
593 unsigned int fieldOffsets[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT];
594};
595
596typedef DPTR(SystemVStructRegisterPassingHelper) SystemVStructRegisterPassingHelperPtr;
597
598#endif // UNIX_AMD64_ABI_ITF
599
600//===============================================================================================
601//
602// GC data appears before the beginning of the MethodTable
603//
604//@GENERICS:
605// Each generic type has a corresponding "generic" method table that serves the following
606// purposes:
607// * The method table pointer is used as a representative for the generic type e.g. in reflection
608// * MethodDescs for methods in the vtable are used for reflection; they should never be invoked.
609// Some other information (e.g. BaseSize) makes no sense "generically" but unfortunately gets put in anyway.
610//
611// Each distinct instantiation of a generic type has its own MethodTable structure.
612// However, the EEClass structure can be shared between compatible instantiations e.g. List<string> and List<object>.
613// In that case, MethodDescs are also shared between compatible instantiations (but see below about generic methods).
614// Hence the vtable entries for MethodTables belonging to such an EEClass are the same.
615//
616// The non-vtable section of such MethodTables are only present for one of the instantiations (the first one
617// requested) as non-vtable entries are never accessed through the vtable pointer of an object so it's always possible
618// to ensure that they are accessed through the representative MethodTable that contains them.
619
620// A MethodTable is the fundamental representation of type in the runtime. It is this structure that
621// objects point at (see code:Object). It holds the size and GC layout of the type, as well as the dispatch table
622// for virtual dispach (but not interface dispatch). There is a distinct method table for every instance of
623// a generic type. From here you can get to
624//
625// * code:EEClass
626//
627// Important fields
628// * code:MethodTable.m_pEEClass - pointer to the cold part of the type.
629// * code:MethodTable.m_pParentMethodTable - the method table of the parent type.
630//
631class MethodTableBuilder;
632class MethodTable
633{
634 /************************************
635 * FRIEND FUNCTIONS
636 ************************************/
637 // DO NOT ADD FRIENDS UNLESS ABSOLUTELY NECESSARY
638 // USE ACCESSORS TO READ/WRITE private field members
639
640 // Special access for setting up String object method table correctly
641 friend class ClassLoader;
642 friend class JIT_TrialAlloc;
643 friend class Module;
644 friend class EEClass;
645 friend class MethodTableBuilder;
646 friend class CheckAsmOffsets;
647#if defined(DACCESS_COMPILE)
648 friend class NativeImageDumper;
649#endif
650
651public:
652 // Do some sanity checking to make sure it's a method table
653 // and not pointing to some random memory. In particular
654 // check that (apart from the special case of instantiated generic types) we have
655 // GetCanonicalMethodTable() == this;
656 BOOL SanityCheck();
657
658 static void CallFinalizer(Object *obj);
659
660public:
661 PTR_Module GetModule();
662 PTR_Module GetModule_NoLogging();
663 Assembly *GetAssembly();
664
665 PTR_Module GetModuleIfLoaded();
666
667 // GetDomain on an instantiated type, e.g. C<ty1,ty2> returns the SharedDomain if all the
668 // constituent parts of the type are SharedDomain (i.e. domain-neutral),
669 // and returns an AppDomain if any of the parts are from an AppDomain,
670 // i.e. are domain-bound. Note that if any of the parts are domain-bound
671 // then they will all belong to the same domain.
672 PTR_BaseDomain GetDomain();
673
674 // Does this immediate item live in an NGEN module?
675 BOOL IsZapped();
676
677 // For types that are part of an ngen-ed assembly this gets the
678 // Module* that contains this methodtable.
679 PTR_Module GetZapModule();
680
681 // For regular, non-constructed types, GetLoaderModule() == GetModule()
682 // For constructed types (e.g. int[], Dict<int[], C>) the hash table through which a type
683 // is accessed lives in a "loader module". The rule for determining the loader module must ensure
684 // that a type never outlives its loader module with respect to app-domain unloading
685 //
686 // GetModuleForStatics() is the third kind of module. GetModuleForStatics() is module that
687 // statics are attached to.
688 PTR_Module GetLoaderModule();
689 PTR_LoaderAllocator GetLoaderAllocator();
690
691 void SetLoaderModule(Module* pModule);
692 void SetLoaderAllocator(LoaderAllocator* pAllocator);
693
694 // Get the domain local module - useful for static init checks
695 PTR_DomainLocalModule GetDomainLocalModule(AppDomain * pAppDomain);
696
697#ifndef DACCESS_COMPILE
698 // Version of GetDomainLocalModule which relies on the current AppDomain
699 PTR_DomainLocalModule GetDomainLocalModule();
700#endif
701
702 MethodTable *LoadEnclosingMethodTable(ClassLoadLevel targetLevel = CLASS_DEPENDENCIES_LOADED);
703
704 LPCWSTR GetPathForErrorMessages();
705
706 //-------------------------------------------------------------------
707 // COM INTEROP
708 //
709 BOOL IsProjectedFromWinRT();
710 BOOL IsExportedToWinRT();
711 BOOL IsWinRTDelegate();
712 BOOL IsWinRTRedirectedInterface(TypeHandle::InteropKind interopKind);
713 BOOL IsWinRTRedirectedDelegate();
714
715#ifdef FEATURE_COMINTEROP
716 TypeHandle GetCoClassForInterface();
717
718private:
719 TypeHandle SetupCoClassForInterface();
720
721public:
722 DWORD IsComClassInterface();
723
724 // Retrieves the COM interface type.
725 CorIfaceAttr GetComInterfaceType();
726 void SetComInterfaceType(CorIfaceAttr ItfType);
727
728 // Determines whether this is a WinRT-legal type
729 BOOL IsLegalWinRTType(OBJECTREF *poref);
730
731 // Determines whether this is a WinRT-legal type - don't use it with array
732 BOOL IsLegalNonArrayWinRTType();
733
734 MethodTable *GetDefaultWinRTInterface();
735
736 OBJECTHANDLE GetOHDelegate();
737 void SetOHDelegate (OBJECTHANDLE _ohDelegate);
738
739 CorClassIfaceAttr GetComClassInterfaceType();
740 TypeHandle GetDefItfForComClassItf();
741
742 void GetEventInterfaceInfo(MethodTable **ppSrcItfType, MethodTable **ppEvProvType);
743
744 BOOL IsExtensibleRCW();
745
746 // Helper to get parent class skipping over COM class in
747 // the hierarchy
748 MethodTable* GetComPlusParentMethodTable();
749
750 // class is a WinRT object class (is itself or derives from a ProjectedFromWinRT class)
751 BOOL IsWinRTObjectType();
752
753 DWORD IsComImport();
754
755 // class is a special COM event interface
756 int IsComEventItfType();
757
758 //-------------------------------------------------------------------
759 // Sparse VTables. These require a SparseVTableMap in the EEClass in
760 // order to record how the CLR's vtable slots map across to COM
761 // Interop slots.
762 //
763 int IsSparseForCOMInterop();
764
765 // COM interop helpers
766 // accessors for m_pComData
767 ComCallWrapperTemplate *GetComCallWrapperTemplate();
768 BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate);
769#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
770 ClassFactoryBase *GetComClassFactory();
771 BOOL SetComClassFactory(ClassFactoryBase *pFactory);
772#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
773
774 OBJECTREF GetObjCreateDelegate();
775 void SetObjCreateDelegate(OBJECTREF orDelegate);
776
777private:
778 // This is for COM Interop backwards compatibility
779 BOOL InsertComInteropData(InteropMethodTableData *pData);
780 InteropMethodTableData *CreateComInteropData(AllocMemTracker *pamTracker);
781
782public:
783 InteropMethodTableData *LookupComInteropData();
784 // This is the preferable entrypoint, as it will make sure that all
785 // parent MT's have their interop data created, and will create and
786 // add this MT's data if not available. The caller should make sure that
787 // an appropriate lock is taken to prevent duplicates.
788 // NOTE: The current caller of this is ComInterop, and it makes calls
789 // under its own lock to ensure not duplicates.
790 InteropMethodTableData *GetComInteropData();
791
792#else // !FEATURE_COMINTEROP
793 BOOL IsWinRTObjectType()
794 {
795 LIMITED_METHOD_CONTRACT;
796 return FALSE;
797 }
798#endif // !FEATURE_COMINTEROP
799
800 // class is a com object class
801 BOOL IsComObjectType()
802 {
803 LIMITED_METHOD_DAC_CONTRACT;
804 return GetFlag(enum_flag_ComObject);
805 }
806
807 // mark the class type as COM object class
808 void SetComObjectType();
809
810#ifdef FEATURE_ICASTABLE
811 void SetICastable();
812#endif
813
814 BOOL IsICastable(); // This type implements ICastable interface
815
816#ifdef FEATURE_TYPEEQUIVALENCE
817 // mark the type as opted into type equivalence
818 void SetHasTypeEquivalence()
819 {
820 LIMITED_METHOD_CONTRACT;
821 SetFlag(enum_flag_HasTypeEquivalence);
822 }
823#endif // FEATURE_TYPEEQUIVALENCE
824
825 // type has opted into type equivalence or is instantiated by/derived from a type that is
826 BOOL HasTypeEquivalence()
827 {
828 LIMITED_METHOD_CONTRACT;
829#ifdef FEATURE_TYPEEQUIVALENCE
830 return GetFlag(enum_flag_HasTypeEquivalence);
831#else
832 return FALSE;
833#endif // FEATURE_TYPEEQUIVALENCE
834 }
835
836 //-------------------------------------------------------------------
837 // DYNAMIC ADDITION OF INTERFACES FOR COM INTEROP
838 //
839 // Support for dynamically added interfaces on extensible RCW's.
840
841#ifdef FEATURE_COMINTEROP
842 PTR_InterfaceInfo GetDynamicallyAddedInterfaceMap();
843 unsigned GetNumDynamicallyAddedInterfaces();
844 BOOL FindDynamicallyAddedInterface(MethodTable *pInterface);
845 void AddDynamicInterface(MethodTable *pItfMT);
846
847 BOOL HasDynamicInterfaceMap()
848 {
849 LIMITED_METHOD_DAC_CONTRACT;
850
851 // currently all ComObjects except
852 // for __ComObject have dynamic Interface maps
853 return GetNumInterfaces() > 0 && IsComObjectType() && !ParentEquals(g_pObjectClass);
854 }
855#endif // FEATURE_COMINTEROP
856
857#ifndef DACCESS_COMPILE
858 VOID EnsureActive();
859 VOID EnsureInstanceActive();
860#endif
861
862 CHECK CheckActivated();
863 CHECK CheckInstanceActivated();
864
865 //-------------------------------------------------------------------
866 // THE DEFAULT CONSTRUCTOR
867 //
868
869public:
870 BOOL HasDefaultConstructor();
871 void SetHasDefaultConstructor();
872 WORD GetDefaultConstructorSlot();
873 MethodDesc *GetDefaultConstructor();
874
875 BOOL HasExplicitOrImplicitPublicDefaultConstructor();
876
877 //-------------------------------------------------------------------
878 // THE CLASS INITIALIZATION CONDITION
879 // (and related DomainLocalBlock/DomainLocalModule storage)
880 //
881 // - populate the DomainLocalModule if needed
882 // - run the cctor
883 //
884
885public:
886
887 // checks whether the class initialiser should be run on this class, and runs it if necessary
888 void CheckRunClassInitThrowing();
889
890 // checks whether or not the non-beforefieldinit class initializers have been run for all types in this type's
891 // inheritance hierarchy, and runs them if necessary. This simulates the behavior of running class constructors
892 // during object construction.
893 void CheckRunClassInitAsIfConstructingThrowing();
894
895#if defined(UNIX_AMD64_ABI_ITF)
896 // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
897 bool ClassifyEightBytes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
898#endif // defined(UNIX_AMD64_ABI_ITF)
899
900 // Copy m_dwFlags from another method table
901 void CopyFlags(MethodTable * pOldMT)
902 {
903 LIMITED_METHOD_CONTRACT;
904 m_dwFlags = pOldMT->m_dwFlags;
905 m_wFlags2 = pOldMT->m_wFlags2;
906 }
907
908 // Init the m_dwFlags field for an array
909 void SetIsArray(CorElementType arrayType, CorElementType elementType);
910
911 BOOL IsClassPreInited();
912
913 // mark the class as having its cctor run.
914#ifndef DACCESS_COMPILE
915 void SetClassInited();
916 BOOL IsClassInited(AppDomain* pAppDomain = NULL);
917
918 BOOL IsInitError();
919 void SetClassInitError();
920#endif
921
922 inline BOOL IsGlobalClass()
923 {
924 WRAPPER_NO_CONTRACT;
925 return (GetTypeDefRid() == RidFromToken(COR_GLOBAL_PARENT_TOKEN));
926 }
927
928 // uniquely identifes this type in the Domain table
929 DWORD GetClassIndex();
930
931private:
932
933#if defined(UNIX_AMD64_ABI_ITF)
934 void AssignClassifiedEightByteTypes(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel) const;
935 // Builds the internal data structures and classifies struct eightbytes for Amd System V calling convention.
936 bool ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
937 bool ClassifyEightBytesWithNativeLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct);
938#endif // defined(UNIX_AMD64_ABI_ITF)
939
940 DWORD GetClassIndexFromToken(mdTypeDef typeToken)
941 {
942 LIMITED_METHOD_CONTRACT;
943 return RidFromToken(typeToken) - 1;
944 }
945
946 // called from CheckRunClassInitThrowing(). The type wasn't marked as
947 // inited while we were there, so let's attempt to do the work.
948 void DoRunClassInitThrowing();
949
950 BOOL RunClassInitEx(OBJECTREF *pThrowable);
951
952public:
953 //-------------------------------------------------------------------
954 // THE CLASS CONSTRUCTOR
955 //
956
957 MethodDesc * GetClassConstructor();
958
959 BOOL HasClassConstructor();
960 void SetHasClassConstructor();
961 WORD GetClassConstructorSlot();
962 void SetClassConstructorSlot (WORD wCCtorSlot);
963
964 ClassCtorInfoEntry* GetClassCtorInfoIfExists();
965
966
967 void GetSavedExtent(TADDR *ppStart, TADDR *ppEnd);
968
969 //-------------------------------------------------------------------
970 // Save/Fixup/Restore/NeedsRestore
971 //
972 // Restore this method table if it's not already restored
973 // This is done by forcing a class load which in turn calls the Restore method
974 // The pending list is required for restoring types that reference themselves through
975 // instantiations of the superclass or interfaces e.g. System.Int32 : IComparable<System.Int32>
976
977
978#ifdef FEATURE_PREJIT
979
980 void Save(DataImage *image, DWORD profilingFlags);
981 void Fixup(DataImage *image);
982
983 // This is different from !IsRestored() in that it checks if restoring
984 // will ever be needed for this ngened data-structure.
985 // This is to be used at ngen time of a dependent module to determine
986 // if it can be accessed directly, or if the restoring mechanism needs
987 // to be hooked in.
988 BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited);
989
990 BOOL NeedsRestore(DataImage *image)
991 {
992 WRAPPER_NO_CONTRACT;
993 return ComputeNeedsRestore(image, NULL);
994 }
995
996private:
997 BOOL ComputeNeedsRestoreWorker(DataImage *image, TypeHandleList *pVisited);
998
999public:
1000 // This returns true at NGen time if we can eager bind to all dictionaries along the inheritance chain
1001 BOOL CanEagerBindToParentDictionaries(DataImage *image, TypeHandleList *pVisited);
1002
1003 // This returns true at NGen time if we may need to attach statics to
1004 // other module than current loader module at runtime
1005 BOOL NeedsCrossModuleGenericsStaticsInfo();
1006
1007 // Returns true at NGen time if we may need to write into the MethodTable at runtime
1008 BOOL IsWriteable();
1009
1010#endif // FEATURE_PREJIT
1011
1012 void AllocateRegularStaticBoxes();
1013 static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, OBJECTHANDLE* pHandle = 0);
1014
1015 void CheckRestore();
1016
1017 // Perform restore actions on type key components of method table (EEClass pointer + Module, generic args)
1018 void DoRestoreTypeKey();
1019
1020 inline BOOL HasUnrestoredTypeKey() const
1021 {
1022 LIMITED_METHOD_DAC_CONTRACT;
1023
1024 return !IsPreRestored() &&
1025 (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey) != 0;
1026 }
1027
1028 // Actually do the restore actions on the method table
1029 void Restore();
1030
1031 void SetIsRestored();
1032
1033 inline BOOL IsRestored_NoLogging()
1034 {
1035 LIMITED_METHOD_DAC_CONTRACT;
1036
1037 // If we are prerestored then we are considered a restored methodtable.
1038 // Note that IsPreRestored is always false for jitted code.
1039 if (IsPreRestored())
1040 return TRUE;
1041
1042 return !(GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
1043 }
1044 inline BOOL IsRestored()
1045 {
1046 LIMITED_METHOD_DAC_CONTRACT;
1047
1048 g_IBCLogger.LogMethodTableAccess(this);
1049
1050 // If we are prerestored then we are considered a restored methodtable.
1051 // Note that IsPreRestored is always false for jitted code.
1052 if (IsPreRestored())
1053 return TRUE;
1054
1055 return !(GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_Unrestored);
1056 }
1057
1058 //-------------------------------------------------------------------
1059 // LOAD LEVEL
1060 //
1061 // The load level of a method table is derived from various flag bits
1062 // See classloadlevel.h for details of each level
1063 //
1064 // Level CLASS_LOADED (fully loaded) is special: a type only
1065 // reaches this level once all of its dependent types are also at
1066 // this level (generic arguments, parent, interfaces, etc).
1067 // Fully loading a type to this level is done outside locks, hence the need for
1068 // a single atomic action that sets the level.
1069 //
1070 inline void SetIsFullyLoaded()
1071 {
1072 CONTRACTL
1073 {
1074 THROWS;
1075 GC_NOTRIGGER;
1076 MODE_ANY;
1077 }
1078 CONTRACTL_END;
1079
1080 PRECONDITION(!HasApproxParent());
1081 PRECONDITION(IsRestored_NoLogging());
1082
1083 FastInterlockAnd(EnsureWritablePages(&GetWriteableDataForWrite()->m_dwFlags), ~MethodTableWriteableData::enum_flag_IsNotFullyLoaded);
1084 }
1085
1086 // Equivalent to GetLoadLevel() == CLASS_LOADED
1087 inline BOOL IsFullyLoaded()
1088 {
1089 WRAPPER_NO_CONTRACT;
1090
1091 return (IsPreRestored())
1092 || (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded) == 0;
1093 }
1094
1095 inline BOOL IsSkipWinRTOverride()
1096 {
1097 LIMITED_METHOD_CONTRACT;
1098 return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_SkipWinRTOverride);
1099 }
1100
1101 inline void SetSkipWinRTOverride()
1102 {
1103 WRAPPER_NO_CONTRACT;
1104 FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite_NoLogging()->m_dwFlags), MethodTableWriteableData::enum_flag_SkipWinRTOverride);
1105 }
1106
1107 inline BOOL CanCompareBitsOrUseFastGetHashCode()
1108 {
1109 LIMITED_METHOD_CONTRACT;
1110 return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode);
1111 }
1112
1113 // If canCompare is true, this method ensure an atomic operation for setting
1114 // enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode and enum_flag_CanCompareBitsOrUseFastGetHashCode flags.
1115 inline void SetCanCompareBitsOrUseFastGetHashCode(BOOL canCompare)
1116 {
1117 WRAPPER_NO_CONTRACT
1118 if (canCompare)
1119 {
1120 // Set checked and canCompare flags in one interlocked operation.
1121 FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite_NoLogging()->m_dwFlags),
1122 MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode | MethodTableWriteableData::enum_flag_CanCompareBitsOrUseFastGetHashCode);
1123 }
1124 else
1125 {
1126 SetHasCheckedCanCompareBitsOrUseFastGetHashCode();
1127 }
1128 }
1129
1130 inline BOOL HasCheckedCanCompareBitsOrUseFastGetHashCode()
1131 {
1132 LIMITED_METHOD_CONTRACT;
1133 return (GetWriteableData_NoLogging()->m_dwFlags & MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode);
1134 }
1135
1136 inline void SetHasCheckedCanCompareBitsOrUseFastGetHashCode()
1137 {
1138 WRAPPER_NO_CONTRACT;
1139 FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite_NoLogging()->m_dwFlags), MethodTableWriteableData::enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode);
1140 }
1141
1142 inline void SetIsDependenciesLoaded()
1143 {
1144 CONTRACTL
1145 {
1146 THROWS;
1147 GC_NOTRIGGER;
1148 MODE_ANY;
1149 }
1150 CONTRACTL_END;
1151
1152 PRECONDITION(!HasApproxParent());
1153 PRECONDITION(IsRestored_NoLogging());
1154
1155 FastInterlockOr(EnsureWritablePages(&GetWriteableDataForWrite()->m_dwFlags), MethodTableWriteableData::enum_flag_DependenciesLoaded);
1156 }
1157
1158 inline ClassLoadLevel GetLoadLevel()
1159 {
1160 LIMITED_METHOD_DAC_CONTRACT;
1161
1162 g_IBCLogger.LogMethodTableAccess(this);
1163
1164 // Fast path for zapped images
1165 if (IsPreRestored())
1166 return CLASS_LOADED;
1167
1168 DWORD dwFlags = GetWriteableData()->m_dwFlags;
1169
1170 if (dwFlags & MethodTableWriteableData::enum_flag_IsNotFullyLoaded)
1171 {
1172 if (dwFlags & MethodTableWriteableData::enum_flag_UnrestoredTypeKey)
1173 return CLASS_LOAD_UNRESTOREDTYPEKEY;
1174
1175 if (dwFlags & MethodTableWriteableData::enum_flag_Unrestored)
1176 return CLASS_LOAD_UNRESTORED;
1177
1178 if (dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent)
1179 return CLASS_LOAD_APPROXPARENTS;
1180
1181 if (!(dwFlags & MethodTableWriteableData::enum_flag_DependenciesLoaded))
1182 return CLASS_LOAD_EXACTPARENTS;
1183
1184 return CLASS_DEPENDENCIES_LOADED;
1185 }
1186
1187 return CLASS_LOADED;
1188 }
1189
1190#ifdef _DEBUG
1191 CHECK CheckLoadLevel(ClassLoadLevel level)
1192 {
1193 LIMITED_METHOD_CONTRACT;
1194 return TypeHandle(this).CheckLoadLevel(level);
1195 }
1196#endif
1197
1198
1199 void DoFullyLoad(Generics::RecursionGraph * const pVisited, const ClassLoadLevel level, DFLPendingList * const pPending, BOOL * const pfBailed,
1200 const InstantiationContext * const pInstContext);
1201
1202 //-------------------------------------------------------------------
1203 // METHOD TABLES AS TYPE DESCRIPTORS
1204 //
1205 // A MethodTable can represeent a type such as "String" or an
1206 // instantiated type such as "List<String>".
1207 //
1208
1209 inline BOOL IsInterface()
1210 {
1211 LIMITED_METHOD_DAC_CONTRACT;
1212 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Interface;
1213 }
1214
1215 void SetIsInterface()
1216 {
1217 LIMITED_METHOD_CONTRACT;
1218
1219 _ASSERTE(GetFlag(enum_flag_Category_Mask) == 0);
1220 SetFlag(enum_flag_Category_Interface);
1221 }
1222
1223 inline BOOL IsSealed();
1224
1225 inline BOOL IsAbstract();
1226
1227 BOOL IsExternallyVisible();
1228
1229 // Get the instantiation for this instantiated type e.g. for Dict<string,int>
1230 // this would be an array {string,int}
1231 // If not instantiated, return NULL
1232 Instantiation GetInstantiation();
1233
1234 // Get the instantiation for an instantiated type or a pointer to the
1235 // element type for an array
1236 Instantiation GetClassOrArrayInstantiation();
1237 Instantiation GetArrayInstantiation();
1238
1239 // Does this method table require that additional modules be loaded?
1240 inline BOOL HasModuleDependencies()
1241 {
1242 LIMITED_METHOD_CONTRACT;
1243 return GetFlag(enum_flag_HasModuleDependencies);
1244 }
1245
1246 inline void SetHasModuleDependencies()
1247 {
1248 SetFlag(enum_flag_HasModuleDependencies);
1249 }
1250
1251 inline BOOL IsIntrinsicType()
1252 {
1253 LIMITED_METHOD_DAC_CONTRACT;;
1254 return GetFlag(enum_flag_IsIntrinsicType);
1255 }
1256
1257 inline void SetIsIntrinsicType()
1258 {
1259 LIMITED_METHOD_DAC_CONTRACT;;
1260 SetFlag(enum_flag_IsIntrinsicType);
1261 }
1262
1263 // See the comment in code:MethodTable.DoFullyLoad for detailed description.
1264 inline BOOL DependsOnEquivalentOrForwardedStructs()
1265 {
1266 LIMITED_METHOD_CONTRACT;
1267 return GetFlag(enum_flag_DependsOnEquivalentOrForwardedStructs);
1268 }
1269
1270 inline void SetDependsOnEquivalentOrForwardedStructs()
1271 {
1272 SetFlag(enum_flag_DependsOnEquivalentOrForwardedStructs);
1273 }
1274
1275 // Is this a method table for a generic type instantiation, e.g. List<string>?
1276 inline BOOL HasInstantiation();
1277
1278 // Returns true for any class which is either itself a generic
1279 // instantiation or is derived from a generic
1280 // instantiation anywhere in it's class hierarchy,
1281 //
1282 // e.g. class D : C<int>
1283 // or class E : D, class D : C<int>
1284 //
1285 // Does not return true just because the class supports
1286 // an instantiated interface type.
1287 BOOL HasGenericClassInstantiationInHierarchy()
1288 {
1289 WRAPPER_NO_CONTRACT;
1290 return GetNumDicts() != 0;
1291 }
1292
1293 // Is this an instantiation of a generic class at its formal
1294 // type parameters ie. List<T> ?
1295 inline BOOL IsGenericTypeDefinition();
1296
1297 BOOL ContainsGenericMethodVariables();
1298
1299 static BOOL ComputeContainsGenericVariables(Instantiation inst);
1300
1301 inline void SetContainsGenericVariables()
1302 {
1303 LIMITED_METHOD_CONTRACT;
1304 SetFlag(enum_flag_ContainsGenericVariables);
1305 }
1306
1307 inline void SetHasVariance()
1308 {
1309 LIMITED_METHOD_CONTRACT;
1310 SetFlag(enum_flag_HasVariance);
1311 }
1312
1313 inline BOOL HasVariance()
1314 {
1315 LIMITED_METHOD_CONTRACT;
1316 return GetFlag(enum_flag_HasVariance);
1317 }
1318
1319 // Is this something like List<T> or List<Stack<T>>?
1320 // List<Blah<T>> only exists for reflection and verification.
1321 inline DWORD ContainsGenericVariables(BOOL methodVarsOnly = FALSE)
1322 {
1323 WRAPPER_NO_CONTRACT;
1324 SUPPORTS_DAC;
1325 if (methodVarsOnly)
1326 return ContainsGenericMethodVariables();
1327 else
1328 return GetFlag(enum_flag_ContainsGenericVariables);
1329 }
1330
1331 BOOL IsByRefLike()
1332 {
1333 LIMITED_METHOD_DAC_CONTRACT;;
1334 return GetFlag(enum_flag_IsByRefLike);
1335 }
1336
1337 void SetIsByRefLike()
1338 {
1339 LIMITED_METHOD_CONTRACT;
1340 SetFlag(enum_flag_IsByRefLike);
1341 }
1342
1343 // class is a com object class
1344 Module* GetDefiningModuleForOpenType();
1345
1346 inline BOOL IsTypicalTypeDefinition()
1347 {
1348 LIMITED_METHOD_CONTRACT;
1349 return !HasInstantiation() || IsGenericTypeDefinition();
1350 }
1351
1352 typedef enum
1353 {
1354 modeProjected = 0x1,
1355 modeRedirected = 0x2,
1356 modeAll = modeProjected|modeRedirected
1357 } Mode;
1358
1359 // Is this a generic interface/delegate that can be used for COM interop?
1360 inline BOOL SupportsGenericInterop(TypeHandle::InteropKind interopKind, Mode = modeAll);
1361
1362 BOOL HasSameTypeDefAs(MethodTable *pMT);
1363 BOOL HasSameTypeDefAs_NoLogging(MethodTable *pMT);
1364
1365 //-------------------------------------------------------------------
1366 // GENERICS & CODE SHARING
1367 //
1368
1369 BOOL IsSharedByGenericInstantiations();
1370
1371 // If this is a "representative" generic MT or a non-generic (regular) MT return true
1372 inline BOOL IsCanonicalMethodTable();
1373
1374 // Return the canonical representative MT amongst the set of MT's that share
1375 // code with the given MT because of generics.
1376 PTR_MethodTable GetCanonicalMethodTable();
1377
1378 // Returns fixup if canonical method table needs fixing up, NULL otherwise
1379 TADDR GetCanonicalMethodTableFixup();
1380
1381 //-------------------------------------------------------------------
1382 // Accessing methods by slot number
1383 //
1384 // Some of these functions are also currently used to get non-virtual
1385 // methods, relying on the assumption that they are contiguous. This
1386 // is not true for non-virtual methods in generic instantiations, which
1387 // only live on the canonical method table.
1388
1389 enum
1390 {
1391 NO_SLOT = 0xffff // a unique slot number used to indicate "empty" for fields that record slot numbers
1392 };
1393
1394 PCODE GetSlot(UINT32 slotNumber)
1395 {
1396 WRAPPER_NO_CONTRACT;
1397 STATIC_CONTRACT_SO_TOLERANT;
1398 CONSISTENCY_CHECK(slotNumber < GetNumVtableSlots());
1399
1400 TADDR pSlot = GetSlotPtrRaw(slotNumber);
1401 if (slotNumber < GetNumVirtuals())
1402 {
1403 return VTableIndir2_t::GetValueMaybeNullAtPtr(pSlot);
1404 }
1405 else if (IsZapped() && slotNumber >= GetNumVirtuals())
1406 {
1407 // Non-virtual slots in NGened images are relative pointers
1408 return RelativePointer<PCODE>::GetValueAtPtr(pSlot);
1409 }
1410 return *dac_cast<PTR_PCODE>(pSlot);
1411 }
1412
1413 // Special-case for when we know that the slot number corresponds
1414 // to a virtual method.
1415 inline PCODE GetSlotForVirtual(UINT32 slotNum)
1416 {
1417 LIMITED_METHOD_CONTRACT;
1418
1419 CONSISTENCY_CHECK(slotNum < GetNumVirtuals());
1420 // Virtual slots live in chunks pointed to by vtable indirections
1421
1422 DWORD index = GetIndexOfVtableIndirection(slotNum);
1423 TADDR base = dac_cast<TADDR>(&(GetVtableIndirections()[index]));
1424 DPTR(VTableIndir2_t) baseAfterInd = VTableIndir_t::GetValueMaybeNullAtPtr(base) + GetIndexAfterVtableIndirection(slotNum);
1425 return VTableIndir2_t::GetValueMaybeNullAtPtr(dac_cast<TADDR>(baseAfterInd));
1426 }
1427
1428 TADDR GetSlotPtrRaw(UINT32 slotNum)
1429 {
1430 WRAPPER_NO_CONTRACT;
1431 STATIC_CONTRACT_SO_TOLERANT;
1432 CONSISTENCY_CHECK(slotNum < GetNumVtableSlots());
1433
1434 if (slotNum < GetNumVirtuals())
1435 {
1436 // Virtual slots live in chunks pointed to by vtable indirections
1437 DWORD index = GetIndexOfVtableIndirection(slotNum);
1438 TADDR base = dac_cast<TADDR>(&(GetVtableIndirections()[index]));
1439 DPTR(VTableIndir2_t) baseAfterInd = VTableIndir_t::GetValueMaybeNullAtPtr(base) + GetIndexAfterVtableIndirection(slotNum);
1440 return dac_cast<TADDR>(baseAfterInd);
1441 }
1442 else if (HasSingleNonVirtualSlot())
1443 {
1444 // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member,
1445 // except when there is only one in which case it lives in the optional member itself
1446 _ASSERTE(slotNum == GetNumVirtuals());
1447 return GetNonVirtualSlotsPtr();
1448 }
1449 else
1450 {
1451 // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member
1452 _ASSERTE(HasNonVirtualSlotsArray());
1453 g_IBCLogger.LogMethodTableNonVirtualSlotsAccess(this);
1454 return dac_cast<TADDR>(GetNonVirtualSlotsArray() + (slotNum - GetNumVirtuals()));
1455 }
1456 }
1457
1458 TADDR GetSlotPtr(UINT32 slotNum)
1459 {
1460 WRAPPER_NO_CONTRACT;
1461 STATIC_CONTRACT_SO_TOLERANT;
1462
1463 // Slots in NGened images are relative pointers
1464 CONSISTENCY_CHECK(!IsZapped());
1465
1466 return GetSlotPtrRaw(slotNum);
1467 }
1468
1469 void SetSlot(UINT32 slotNum, PCODE slotVal);
1470
1471 //-------------------------------------------------------------------
1472 // The VTABLE
1473 //
1474 // Rather than the traditional array of code pointers (or "slots") we use a two-level vtable in
1475 // which slots for virtual methods live in chunks. Doing so allows the chunks to be shared among
1476 // method tables (the most common example being between parent and child classes where the child
1477 // does not override any method in the chunk). This yields substantial space savings at the fixed
1478 // cost of one additional indirection for a virtual call.
1479 //
1480 // Note that none of this should be visible outside the implementation of MethodTable; all other
1481 // code continues to refer to a virtual method via the traditional slot number. This is similar to
1482 // how we refer to non-virtual methods as having a slot number despite having long ago moved their
1483 // code pointers out of the vtable.
1484 //
1485 // Consider a class where GetNumVirtuals is 5 and (for the sake of the example) assume we break
1486 // the vtable into chunks of size 3. The layout would be as follows:
1487 //
1488 // pMT chunk 1 chunk 2
1489 // ------------------ ------------------ ------------------
1490 // | | | M1() | | M4() |
1491 // | fixed-size | ------------------ ------------------
1492 // | portion of | | M2() | | M5() |
1493 // | MethodTable | ------------------ ------------------
1494 // | | | M3() |
1495 // ------------------ ------------------
1496 // | ptr to chunk 1 |
1497 // ------------------
1498 // | ptr to chunk 2 |
1499 // ------------------
1500 //
1501 // We refer to "ptr to chunk 1" and "ptr to chunk 2" as "indirection slots."
1502 //
1503 // The current chunking strategy is independent of class properties; all are of size 8. Several
1504 // other strategies were tried, and the only one that has performed better empirically is to begin
1505 // with a single chunk of size 4 (matching the number of virtuals in System.Object) and then
1506 // continue with chunks of size 8. However it was a small improvement and required the run-time
1507 // helpers listed below to be measurably slower.
1508 //
1509 // If you want to change this, you should only need to modify the first four functions below
1510 // along with any assembly helper that has taken a dependency on the layout. Currently,
1511 // those consist of:
1512 // JIT_IsInstanceOfInterface
1513 // JIT_ChkCastInterface
1514 // Transparent proxy stub
1515 //
1516 // This layout only applies to the virtual methods in a class (those with slot number below GetNumVirtuals).
1517 // Non-virtual methods that are in the vtable (those with slot numbers between GetNumVirtuals and
1518 // GetNumVtableSlots) are laid out in a single chunk pointed to by an optional member.
1519 // See GetSlotPtrRaw for more details.
1520
1521 #define VTABLE_SLOTS_PER_CHUNK 8
1522 #define VTABLE_SLOTS_PER_CHUNK_LOG2 3
1523
1524#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
1525 typedef RelativePointer<PCODE> VTableIndir2_t;
1526 typedef RelativePointer<DPTR(VTableIndir2_t)> VTableIndir_t;
1527#else
1528 typedef PlainPointer<PCODE> VTableIndir2_t;
1529 typedef PlainPointer<DPTR(VTableIndir2_t)> VTableIndir_t;
1530#endif
1531
1532 static DWORD GetIndexOfVtableIndirection(DWORD slotNum);
1533 static DWORD GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
1534 static DWORD GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals);
1535 static UINT32 GetIndexAfterVtableIndirection(UINT32 slotNum);
1536 static DWORD GetNumVtableIndirections(DWORD wNumVirtuals);
1537 DPTR(VTableIndir_t) GetVtableIndirections();
1538 DWORD GetNumVtableIndirections();
1539
1540 class VtableIndirectionSlotIterator
1541 {
1542 friend class MethodTable;
1543
1544 private:
1545 DPTR(VTableIndir_t) m_pSlot;
1546 DWORD m_i;
1547 DWORD m_count;
1548 PTR_MethodTable m_pMT;
1549
1550 VtableIndirectionSlotIterator(MethodTable *pMT);
1551 VtableIndirectionSlotIterator(MethodTable *pMT, DWORD index);
1552
1553 public:
1554 BOOL Next();
1555 BOOL Finished();
1556 DWORD GetIndex();
1557 DWORD GetOffsetFromMethodTable();
1558 DPTR(VTableIndir2_t) GetIndirectionSlot();
1559
1560#ifndef DACCESS_COMPILE
1561 void SetIndirectionSlot(DPTR(VTableIndir2_t) pChunk);
1562#endif
1563
1564 DWORD GetStartSlot();
1565 DWORD GetEndSlot();
1566 DWORD GetNumSlots();
1567 DWORD GetSize();
1568 }; // class VtableIndirectionSlotIterator
1569
1570 VtableIndirectionSlotIterator IterateVtableIndirectionSlots();
1571 VtableIndirectionSlotIterator IterateVtableIndirectionSlotsFrom(DWORD index);
1572
1573#ifdef FEATURE_PREJIT
1574 static BOOL CanShareVtableChunksFrom(MethodTable *pTargetMT, Module *pCurrentLoaderModule, Module *pCurrentPreferredZapModule);
1575 BOOL CanInternVtableChunk(DataImage *image, VtableIndirectionSlotIterator it);
1576#else
1577 static BOOL CanShareVtableChunksFrom(MethodTable *pTargetMT, Module *pCurrentLoaderModule);
1578#endif
1579
1580 inline BOOL HasNonVirtualSlots()
1581 {
1582 LIMITED_METHOD_DAC_CONTRACT;
1583 return GetFlag(enum_flag_HasNonVirtualSlots);
1584 }
1585
1586 inline BOOL HasSingleNonVirtualSlot()
1587 {
1588 LIMITED_METHOD_DAC_CONTRACT;
1589 return GetFlag(enum_flag_HasSingleNonVirtualSlot);
1590 }
1591
1592 inline BOOL HasNonVirtualSlotsArray()
1593 {
1594 LIMITED_METHOD_DAC_CONTRACT;
1595 return HasNonVirtualSlots() && !HasSingleNonVirtualSlot();
1596 }
1597
1598 TADDR GetNonVirtualSlotsPtr();
1599
1600 inline PTR_PCODE GetNonVirtualSlotsArray()
1601 {
1602 LIMITED_METHOD_DAC_CONTRACT;
1603 _ASSERTE(HasNonVirtualSlotsArray());
1604 return RelativePointer<PTR_PCODE>::GetValueAtPtr(GetNonVirtualSlotsPtr());
1605 }
1606
1607#ifndef DACCESS_COMPILE
1608 inline void SetNonVirtualSlotsArray(PCODE *slots)
1609 {
1610 LIMITED_METHOD_CONTRACT;
1611 _ASSERTE(HasNonVirtualSlotsArray());
1612
1613 RelativePointer<PCODE *> *pRelPtr = (RelativePointer<PCODE *> *)GetNonVirtualSlotsPtr();
1614 pRelPtr->SetValue(slots);
1615 }
1616
1617 inline void SetHasSingleNonVirtualSlot()
1618 {
1619 LIMITED_METHOD_CONTRACT;
1620 SetFlag(enum_flag_HasSingleNonVirtualSlot);
1621 }
1622#endif
1623
1624 inline unsigned GetNonVirtualSlotsArraySize()
1625 {
1626 LIMITED_METHOD_DAC_CONTRACT;
1627 return GetNumNonVirtualSlots() * sizeof(PCODE);
1628 }
1629
1630 inline WORD GetNumNonVirtualSlots();
1631
1632 inline WORD GetNumVirtuals()
1633 {
1634 LIMITED_METHOD_DAC_CONTRACT;
1635
1636 g_IBCLogger.LogMethodTableAccess(this);
1637 return GetNumVirtuals_NoLogging();
1638 }
1639
1640 inline WORD GetNumVirtuals_NoLogging()
1641 {
1642 LIMITED_METHOD_DAC_CONTRACT;
1643
1644 return m_wNumVirtuals;
1645 }
1646
1647 inline void SetNumVirtuals (WORD wNumVtableSlots)
1648 {
1649 LIMITED_METHOD_CONTRACT;
1650 m_wNumVirtuals = wNumVtableSlots;
1651 }
1652
1653 unsigned GetNumParentVirtuals()
1654 {
1655 LIMITED_METHOD_CONTRACT;
1656 if (IsInterface()) {
1657 return 0;
1658 }
1659 MethodTable *pMTParent = GetParentMethodTable();
1660 g_IBCLogger.LogMethodTableAccess(this);
1661 return pMTParent == NULL ? 0 : pMTParent->GetNumVirtuals();
1662 }
1663
1664 #define SIZEOF__MethodTable_ (0x10 + (6 INDEBUG(+1)) * TARGET_POINTER_SIZE)
1665
1666 static inline DWORD GetVtableOffset()
1667 {
1668 LIMITED_METHOD_DAC_CONTRACT;
1669
1670 return SIZEOF__MethodTable_;
1671 }
1672
1673 // Return total methods: virtual, static, and instance method slots.
1674 WORD GetNumMethods();
1675
1676 // Return number of slots in this methodtable. This is just an information about the layout of the methodtable, it should not be used
1677 // for functionality checks. Do not confuse with GetNumVirtuals()!
1678 WORD GetNumVtableSlots()
1679 {
1680 LIMITED_METHOD_DAC_CONTRACT;
1681 return GetNumVirtuals() + GetNumNonVirtualSlots();
1682 }
1683
1684 //-------------------------------------------------------------------
1685 // Slots <-> the MethodDesc associated with the slot.
1686 //
1687
1688 MethodDesc* GetMethodDescForSlot(DWORD slot);
1689
1690 static MethodDesc* GetMethodDescForSlotAddress(PCODE addr, BOOL fSpeculative = FALSE);
1691
1692 PCODE GetRestoredSlot(DWORD slot);
1693
1694 // Returns MethodTable that GetRestoredSlot get its values from
1695 MethodTable * GetRestoredSlotMT(DWORD slot);
1696
1697 // Used to map methods on the same slot between instantiations.
1698 MethodDesc * GetParallelMethodDesc(MethodDesc * pDefMD);
1699
1700 //-------------------------------------------------------------------
1701 // BoxedEntryPoint MethodDescs.
1702 //
1703 // Virtual methods on structs have BoxedEntryPoint method descs in their vtable.
1704 // See also notes for MethodDesc::FindOrCreateAssociatedMethodDesc. You should
1705 // probably be using that function if you need to map between unboxing
1706 // stubs and non-unboxing stubs.
1707
1708 MethodDesc* GetBoxedEntryPointMD(MethodDesc *pMD);
1709
1710 MethodDesc* GetUnboxedEntryPointMD(MethodDesc *pMD);
1711 MethodDesc* GetExistingUnboxedEntryPointMD(MethodDesc *pMD);
1712
1713 //-------------------------------------------------------------------
1714 // FIELD LAYOUT, OBJECT SIZE ETC.
1715 //
1716
1717 inline BOOL HasLayout();
1718
1719 inline EEClassLayoutInfo *GetLayoutInfo();
1720
1721 inline BOOL IsBlittable();
1722
1723 inline BOOL IsManagedSequential();
1724
1725 inline BOOL HasExplicitSize();
1726
1727 UINT32 GetNativeSize();
1728
1729 DWORD GetBaseSize()
1730 {
1731 LIMITED_METHOD_DAC_CONTRACT;
1732 return(m_BaseSize);
1733 }
1734
1735 void SetBaseSize(DWORD baseSize)
1736 {
1737 LIMITED_METHOD_CONTRACT;
1738 m_BaseSize = baseSize;
1739 }
1740
1741 BOOL IsStringOrArray() const
1742 {
1743 LIMITED_METHOD_DAC_CONTRACT;
1744 return HasComponentSize();
1745 }
1746
1747 BOOL IsString()
1748 {
1749 LIMITED_METHOD_DAC_CONTRACT;
1750 return HasComponentSize() && !IsArray();
1751 }
1752
1753 BOOL HasComponentSize() const
1754 {
1755 LIMITED_METHOD_DAC_CONTRACT;
1756 return GetFlag(enum_flag_HasComponentSize);
1757 }
1758
1759 // returns random combination of flags if this doesn't have a component size
1760 WORD RawGetComponentSize()
1761 {
1762 LIMITED_METHOD_DAC_CONTRACT;
1763#if BIGENDIAN
1764 return *((WORD*)&m_dwFlags + 1);
1765#else // !BIGENDIAN
1766 return *(WORD*)&m_dwFlags;
1767#endif // !BIGENDIAN
1768 }
1769
1770 // returns 0 if this doesn't have a component size
1771
1772 // The component size is actually 16-bit WORD, but this method is returning SIZE_T to ensure
1773 // that SIZE_T is used everywhere for object size computation. It is necessary to support
1774 // objects bigger than 2GB.
1775 SIZE_T GetComponentSize()
1776 {
1777 LIMITED_METHOD_DAC_CONTRACT;
1778 return HasComponentSize() ? RawGetComponentSize() : 0;
1779 }
1780
1781 void SetComponentSize(WORD wComponentSize)
1782 {
1783 LIMITED_METHOD_CONTRACT;
1784 // it would be nice to assert here that this is either a string
1785 // or an array, but how do we know.
1786 //
1787 // it would also be nice to assert that the component size is > 0,
1788 // but it turns out that for array's of System.Void we cannot do
1789 // that b/c the component size is 0 (?)
1790 SetFlag(enum_flag_HasComponentSize);
1791 m_dwFlags = (m_dwFlags & ~0xFFFF) | wComponentSize;
1792 }
1793
1794 inline WORD GetNumInstanceFields();
1795
1796 inline WORD GetNumStaticFields();
1797
1798 inline WORD GetNumThreadStaticFields();
1799
1800 // Note that for value types GetBaseSize returns the size of instance fields for
1801 // a boxed value, and GetNumInstanceFieldsBytes for an unboxed value.
1802 // We place methods like these on MethodTable primarily so we can choose to cache
1803 // the information within MethodTable, and so less code manipulates EEClass
1804 // objects directly, because doing so can lead to bugs related to generics.
1805 //
1806 // <TODO> Use m_wBaseSize whenever this is identical to GetNumInstanceFieldBytes.
1807 // We would need to reserve a flag for this. </TODO>
1808 //
1809 inline DWORD GetNumInstanceFieldBytes();
1810
1811 inline WORD GetNumIntroducedInstanceFields();
1812
1813 // <TODO> Does this always return the same (or related) size as GetBaseSize()? </TODO>
1814 inline DWORD GetAlignedNumInstanceFieldBytes();
1815
1816
1817 // Note: This flag MUST be available even from an unrestored MethodTable - see GcScanRoots in siginfo.cpp.
1818 DWORD ContainsPointers()
1819 {
1820 LIMITED_METHOD_CONTRACT;
1821 return GetFlag(enum_flag_ContainsPointers);
1822 }
1823 BOOL Collectible()
1824 {
1825 LIMITED_METHOD_CONTRACT;
1826#ifdef FEATURE_COLLECTIBLE_TYPES
1827 return GetFlag(enum_flag_Collectible);
1828#else
1829 return FALSE;
1830#endif
1831 }
1832 BOOL ContainsPointersOrCollectible()
1833 {
1834 LIMITED_METHOD_CONTRACT;
1835 return GetFlag(enum_flag_ContainsPointers) || GetFlag(enum_flag_Collectible);
1836 }
1837
1838 OBJECTHANDLE GetLoaderAllocatorObjectHandle();
1839 NOINLINE BYTE *GetLoaderAllocatorObjectForGC();
1840
1841 BOOL IsNotTightlyPacked();
1842
1843 void SetContainsPointers()
1844 {
1845 LIMITED_METHOD_CONTRACT;
1846 SetFlag(enum_flag_ContainsPointers);
1847 }
1848
1849#ifdef FEATURE_64BIT_ALIGNMENT
1850 inline bool RequiresAlign8()
1851 {
1852 LIMITED_METHOD_DAC_CONTRACT;
1853 return !!GetFlag(enum_flag_RequiresAlign8);
1854 }
1855
1856 inline void SetRequiresAlign8()
1857 {
1858 LIMITED_METHOD_CONTRACT;
1859 SetFlag(enum_flag_RequiresAlign8);
1860 }
1861#endif // FEATURE_64BIT_ALIGNMENT
1862
1863 //-------------------------------------------------------------------
1864 // FIELD DESCRIPTORS
1865 //
1866 // Most of this API still lives on EEClass.
1867 //
1868 // ************************************ WARNING *************
1869 // ** !!!!INSTANCE FIELDDESCS ARE REPRESENTATIVES!!!!! **
1870 // ** THEY ARE SHARED BY COMPATIBLE GENERIC INSTANTIATIONS **
1871 // ************************************ WARNING *************
1872
1873 // This goes straight to the EEClass
1874 // Careful about using this method. If it's possible that fields may have been added via EnC, then
1875 // must use the FieldDescIterator as any fields added via EnC won't be in the raw list
1876 PTR_FieldDesc GetApproxFieldDescListRaw();
1877
1878 // This returns a type-exact FieldDesc for a static field, but may still return a representative
1879 // for a non-static field.
1880 PTR_FieldDesc GetFieldDescByIndex(DWORD fieldIndex);
1881
1882 DWORD GetIndexForFieldDesc(FieldDesc *pField);
1883
1884 BOOL IsMarshaledByRef()
1885 {
1886 return FALSE;
1887 }
1888
1889 BOOL IsContextful()
1890 {
1891 return FALSE;
1892 }
1893
1894 inline bool RequiresFatDispatchTokens()
1895 {
1896 LIMITED_METHOD_CONTRACT;
1897 return !!GetFlag(enum_flag_RequiresDispatchTokenFat);
1898 }
1899
1900 inline void SetRequiresFatDispatchTokens()
1901 {
1902 LIMITED_METHOD_CONTRACT;
1903 SetFlag(enum_flag_RequiresDispatchTokenFat);
1904 }
1905
1906 inline bool HasPreciseInitCctors()
1907 {
1908 LIMITED_METHOD_CONTRACT;
1909 return !!GetFlag(enum_flag_HasPreciseInitCctors);
1910 }
1911
1912 inline void SetHasPreciseInitCctors()
1913 {
1914 LIMITED_METHOD_CONTRACT;
1915 SetFlag(enum_flag_HasPreciseInitCctors);
1916 }
1917
1918#if defined(FEATURE_HFA)
1919 inline bool IsHFA()
1920 {
1921 LIMITED_METHOD_CONTRACT;
1922 return !!GetFlag(enum_flag_IsHFA);
1923 }
1924
1925 inline void SetIsHFA()
1926 {
1927 LIMITED_METHOD_CONTRACT;
1928 SetFlag(enum_flag_IsHFA);
1929 }
1930#else // !FEATURE_HFA
1931 bool IsHFA();
1932#endif // FEATURE_HFA
1933
1934 // Get the HFA type. This is supported both with FEATURE_HFA, in which case it
1935 // depends on the cached bit on the class, or without, in which case it is recomputed
1936 // for each invocation.
1937 CorElementType GetHFAType();
1938 // The managed and unmanaged HFA type can differ for types with layout. The following two methods return the unmanaged HFA type.
1939 bool IsNativeHFA();
1940 CorElementType GetNativeHFAType();
1941
1942#ifdef UNIX_AMD64_ABI
1943 inline bool IsRegPassedStruct()
1944 {
1945 LIMITED_METHOD_CONTRACT;
1946 return !!GetFlag(enum_flag_IsRegStructPassed);
1947 }
1948
1949 inline void SetRegPassedStruct()
1950 {
1951 LIMITED_METHOD_CONTRACT;
1952 SetFlag(enum_flag_IsRegStructPassed);
1953 }
1954#else
1955 inline bool IsRegPassedStruct()
1956 {
1957 return false;
1958 }
1959#endif
1960
1961#ifdef FEATURE_64BIT_ALIGNMENT
1962 // Returns true iff the native view of this type requires 64-bit aligment.
1963 bool NativeRequiresAlign8();
1964#endif // FEATURE_64BIT_ALIGNMENT
1965
1966 // True if interface casts for an object having this type require more
1967 // than a simple scan of the interface map
1968 // See JIT_IsInstanceOfInterface
1969 inline BOOL InstanceRequiresNonTrivialInterfaceCast()
1970 {
1971 STATIC_CONTRACT_SO_TOLERANT;
1972 LIMITED_METHOD_CONTRACT;
1973
1974 return GetFlag(enum_flag_NonTrivialInterfaceCast);
1975 }
1976
1977
1978 //-------------------------------------------------------------------
1979 // PARENT INTERFACES
1980 //
1981 unsigned GetNumInterfaces()
1982 {
1983 LIMITED_METHOD_DAC_CONTRACT;
1984 return m_wNumInterfaces;
1985 }
1986
1987 //-------------------------------------------------------------------
1988 // CASTING
1989 //
1990 // There are two variants of each of these methods:
1991 //
1992 // CanCastToX
1993 // - restore encoded pointers on demand
1994 // - might throw, might trigger GC
1995 // - return type is boolean (FALSE = cannot cast, TRUE = can cast)
1996 //
1997 // CanCastToXNoGC
1998 // - do not restore encoded pointers on demand
1999 // - does not throw, does not trigger GC
2000 // - return type is three-valued (CanCast, CannotCast, MaybeCast)
2001 // - MaybeCast indicates that the test tripped on an encoded pointer
2002 // so the caller should now call CanCastToXRestoring if it cares
2003 //
2004 BOOL CanCastToInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
2005 BOOL CanCastToClass(MethodTable *pTargetMT, TypeHandlePairList *pVisited = NULL);
2006 BOOL CanCastToClassOrInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited);
2007 BOOL CanCastByVarianceToInterfaceOrDelegate(MethodTable *pTargetMT, TypeHandlePairList *pVisited);
2008
2009 BOOL CanCastToNonVariantInterface(MethodTable *pTargetMT);
2010
2011 TypeHandle::CastResult CanCastToInterfaceNoGC(MethodTable *pTargetMT);
2012 TypeHandle::CastResult CanCastToClassNoGC(MethodTable *pTargetMT);
2013 TypeHandle::CastResult CanCastToClassOrInterfaceNoGC(MethodTable *pTargetMT);
2014
2015 // The inline part of equivalence check.
2016#ifndef DACCESS_COMPILE
2017 FORCEINLINE BOOL IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL));
2018
2019#ifdef FEATURE_TYPEEQUIVALENCE
2020 // This method is public so that TypeHandle has direct access to it
2021 BOOL IsEquivalentTo_Worker(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO tolerant
2022private:
2023 BOOL IsEquivalentTo_WorkerInner(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited)); // out-of-line part, SO intolerant
2024#endif // FEATURE_TYPEEQUIVALENCE
2025#endif
2026
2027public:
2028 //-------------------------------------------------------------------
2029 // THE METHOD TABLE PARENT (SUPERCLASS/BASE CLASS)
2030 //
2031
2032#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
2033#define PARENT_MT_FIXUP_OFFSET (-FIXUP_POINTER_INDIRECTION)
2034 typedef RelativeFixupPointer<PTR_MethodTable> ParentMT_t;
2035#else
2036#define PARENT_MT_FIXUP_OFFSET ((SSIZE_T)offsetof(MethodTable, m_pParentMethodTable))
2037 typedef IndirectPointer<PTR_MethodTable> ParentMT_t;
2038#endif
2039
2040 BOOL HasApproxParent()
2041 {
2042 LIMITED_METHOD_DAC_CONTRACT;
2043 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasApproxParent) != 0;
2044 }
2045 inline void SetHasExactParent()
2046 {
2047 WRAPPER_NO_CONTRACT;
2048 FastInterlockAnd(&(GetWriteableDataForWrite()->m_dwFlags), ~MethodTableWriteableData::enum_flag_HasApproxParent);
2049 }
2050
2051
2052 // Caller must know that the parent method table is not an encoded fixup
2053 inline PTR_MethodTable GetParentMethodTable()
2054 {
2055 LIMITED_METHOD_DAC_CONTRACT;
2056
2057 PRECONDITION(IsParentMethodTablePointerValid());
2058 return ReadPointerMaybeNull(this, &MethodTable::m_pParentMethodTable, GetFlagHasIndirectParent());
2059 }
2060
2061 inline static PTR_VOID GetParentMethodTableOrIndirection(PTR_VOID pMT)
2062 {
2063 WRAPPER_NO_CONTRACT;
2064#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
2065 PTR_MethodTable pMethodTable = dac_cast<PTR_MethodTable>(pMT);
2066 PTR_MethodTable pParentMT = ReadPointerMaybeNull((MethodTable*) pMethodTable, &MethodTable::m_pParentMethodTable);
2067 return dac_cast<PTR_VOID>(pParentMT);
2068#else
2069 return PTR_VOID(*PTR_TADDR(dac_cast<TADDR>(pMT) + offsetof(MethodTable, m_pParentMethodTable)));
2070#endif
2071 }
2072
2073 inline static BOOL IsParentMethodTableTagged(PTR_MethodTable pMT)
2074 {
2075 LIMITED_METHOD_CONTRACT;
2076 TADDR base = dac_cast<TADDR>(pMT) + offsetof(MethodTable, m_pParentMethodTable);
2077 return pMT->m_pParentMethodTable.IsTaggedIndirect(base, pMT->GetFlagHasIndirectParent(), PARENT_MT_FIXUP_OFFSET);
2078 }
2079
2080 bool GetFlagHasIndirectParent()
2081 {
2082#ifdef FEATURE_PREJIT
2083 return !!GetFlag(enum_flag_HasIndirectParent);
2084#else
2085 return false;
2086#endif
2087 }
2088
2089#ifndef DACCESS_COMPILE
2090 inline ParentMT_t * GetParentMethodTablePointerPtr()
2091 {
2092 LIMITED_METHOD_CONTRACT;
2093 return &m_pParentMethodTable;
2094 }
2095
2096 inline bool IsParentMethodTableIndirectPointerMaybeNull()
2097 {
2098 LIMITED_METHOD_CONTRACT;
2099 return m_pParentMethodTable.IsIndirectPtrMaybeNullIndirect(GetFlagHasIndirectParent(), PARENT_MT_FIXUP_OFFSET);
2100 }
2101
2102 inline bool IsParentMethodTableIndirectPointer()
2103 {
2104 LIMITED_METHOD_CONTRACT;
2105 return m_pParentMethodTable.IsIndirectPtrIndirect(GetFlagHasIndirectParent(), PARENT_MT_FIXUP_OFFSET);
2106 }
2107
2108 inline MethodTable ** GetParentMethodTableValuePtr()
2109 {
2110 LIMITED_METHOD_CONTRACT;
2111 return m_pParentMethodTable.GetValuePtrIndirect(GetFlagHasIndirectParent(), PARENT_MT_FIXUP_OFFSET);
2112 }
2113#endif // !DACCESS_COMPILE
2114
2115 // Is the parent method table pointer equal to the given argument?
2116 BOOL ParentEquals(PTR_MethodTable pMT)
2117 {
2118 LIMITED_METHOD_DAC_CONTRACT;
2119 PRECONDITION(IsParentMethodTablePointerValid());
2120 g_IBCLogger.LogMethodTableAccess(this);
2121 return GetParentMethodTable() == pMT;
2122 }
2123
2124#ifdef _DEBUG
2125 BOOL IsParentMethodTablePointerValid();
2126#endif
2127
2128#ifndef DACCESS_COMPILE
2129 void SetParentMethodTable (MethodTable *pParentMethodTable)
2130 {
2131 LIMITED_METHOD_CONTRACT;
2132 PRECONDITION(!IsParentMethodTableIndirectPointerMaybeNull());
2133 m_pParentMethodTable.SetValueMaybeNull(pParentMethodTable);
2134#ifdef _DEBUG
2135 GetWriteableDataForWrite_NoLogging()->SetParentMethodTablePointerValid();
2136#endif
2137 }
2138#endif // !DACCESS_COMPILE
2139 MethodTable * GetMethodTableMatchingParentClass(MethodTable * pWhichParent);
2140 Instantiation GetInstantiationOfParentClass(MethodTable *pWhichParent);
2141
2142 //-------------------------------------------------------------------
2143 // THE EEClass (Possibly shared between instantiations!).
2144 //
2145 // Note that it is not generally the case that GetClass.GetMethodTable() == t.
2146
2147 PTR_EEClass GetClass();
2148
2149 inline PTR_EEClass GetClass_NoLogging();
2150
2151 PTR_EEClass GetClassWithPossibleAV();
2152
2153 BOOL ValidateWithPossibleAV();
2154
2155 BOOL IsClassPointerValid();
2156
2157 static UINT32 GetOffsetOfFlags()
2158 {
2159 LIMITED_METHOD_CONTRACT;
2160 return offsetof(MethodTable, m_dwFlags);
2161 }
2162
2163 static UINT32 GetIfArrayThenSzArrayFlag()
2164 {
2165 LIMITED_METHOD_CONTRACT;
2166 return enum_flag_Category_IfArrayThenSzArray;
2167 }
2168
2169 //-------------------------------------------------------------------
2170 // CONSTRUCTION
2171 //
2172 // Do not call the following at any time except when creating a method table.
2173 // One day we will have proper constructors for method tables and all these
2174 // will disappear.
2175#ifndef DACCESS_COMPILE
2176 inline void SetClass(EEClass *pClass)
2177 {
2178 LIMITED_METHOD_CONTRACT;
2179 m_pEEClass.SetValue(pClass);
2180 }
2181
2182 inline void SetCanonicalMethodTable(MethodTable * pMT)
2183 {
2184 m_pCanonMT.SetValue((TADDR)pMT | MethodTable::UNION_METHODTABLE);
2185 }
2186#endif
2187
2188 inline void SetHasInstantiation(BOOL fTypicalInstantiation, BOOL fSharedByGenericInstantiations);
2189
2190 //-------------------------------------------------------------------
2191 // INTERFACE IMPLEMENTATION
2192 //
2193 public:
2194 // Faster force-inlined version of ImplementsInterface
2195 BOOL ImplementsInterfaceInline(MethodTable *pInterface);
2196
2197 BOOL ImplementsInterface(MethodTable *pInterface);
2198 BOOL ImplementsEquivalentInterface(MethodTable *pInterface);
2199
2200 MethodDesc *GetMethodDescForInterfaceMethod(TypeHandle ownerType, MethodDesc *pInterfaceMD, BOOL throwOnConflict);
2201 MethodDesc *GetMethodDescForInterfaceMethod(MethodDesc *pInterfaceMD, BOOL throwOnConflict); // You can only use this one for non-generic interfaces
2202
2203 //-------------------------------------------------------------------
2204 // INTERFACE MAP.
2205 //
2206
2207 inline PTR_InterfaceInfo GetInterfaceMap();
2208
2209#ifndef DACCESS_COMPILE
2210 void SetInterfaceMap(WORD wNumInterfaces, InterfaceInfo_t* iMap);
2211#endif
2212
2213 inline int HasInterfaceMap()
2214 {
2215 LIMITED_METHOD_DAC_CONTRACT;
2216 return (m_wNumInterfaces != 0);
2217 }
2218
2219 // Where possible, use this iterator over the interface map instead of accessing the map directly
2220 // That way we can easily change the implementation of the map
2221 class InterfaceMapIterator
2222 {
2223 friend class MethodTable;
2224
2225 private:
2226 PTR_InterfaceInfo m_pMap;
2227 DWORD m_i;
2228 DWORD m_count;
2229
2230 InterfaceMapIterator(MethodTable *pMT)
2231 : m_pMap(pMT->GetInterfaceMap()),
2232 m_i((DWORD) -1),
2233 m_count(pMT->GetNumInterfaces())
2234 {
2235 WRAPPER_NO_CONTRACT;
2236 }
2237
2238 InterfaceMapIterator(MethodTable *pMT, DWORD index)
2239 : m_pMap(pMT->GetInterfaceMap() + index),
2240 m_i(index),
2241 m_count(pMT->GetNumInterfaces())
2242 {
2243 WRAPPER_NO_CONTRACT;
2244 CONSISTENCY_CHECK(index >= 0 && index < m_count);
2245 }
2246
2247 public:
2248 InterfaceInfo_t* GetInterfaceInfo()
2249 {
2250 LIMITED_METHOD_CONTRACT;
2251 return m_pMap;
2252 }
2253
2254 // Move to the next item in the map, returning TRUE if an item
2255 // exists or FALSE if we've run off the end
2256 inline BOOL Next()
2257 {
2258 LIMITED_METHOD_CONTRACT;
2259 PRECONDITION(!Finished());
2260 if (m_i != (DWORD) -1)
2261 m_pMap++;
2262 return (++m_i < m_count);
2263 }
2264
2265 // Have we iterated over all of the items?
2266 BOOL Finished()
2267 {
2268 return (m_i == m_count);
2269 }
2270
2271 // Get the interface at the current position
2272 inline PTR_MethodTable GetInterface()
2273 {
2274 CONTRACT(PTR_MethodTable)
2275 {
2276 GC_NOTRIGGER;
2277 NOTHROW;
2278 SUPPORTS_DAC;
2279 PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
2280 POSTCONDITION(CheckPointer(RETVAL));
2281 }
2282 CONTRACT_END;
2283
2284 RETURN (m_pMap->GetMethodTable());
2285 }
2286
2287#ifndef DACCESS_COMPILE
2288 void SetInterface(MethodTable *pMT)
2289 {
2290 WRAPPER_NO_CONTRACT;
2291 m_pMap->SetMethodTable(pMT);
2292 }
2293#endif
2294
2295 DWORD GetIndex()
2296 {
2297 LIMITED_METHOD_CONTRACT;
2298 return m_i;
2299 }
2300 }; // class InterfaceMapIterator
2301
2302 // Create a new iterator over the interface map
2303 // The iterator starts just before the first item in the map
2304 InterfaceMapIterator IterateInterfaceMap()
2305 {
2306 WRAPPER_NO_CONTRACT;
2307 return InterfaceMapIterator(this);
2308 }
2309
2310 // Create a new iterator over the interface map, starting at the index specified
2311 InterfaceMapIterator IterateInterfaceMapFrom(DWORD index)
2312 {
2313 WRAPPER_NO_CONTRACT;
2314 return InterfaceMapIterator(this, index);
2315 }
2316
2317 //-------------------------------------------------------------------
2318 // ADDITIONAL INTERFACE MAP DATA
2319 //
2320
2321 // We store extra info (flag bits) for interfaces implemented on this MethodTable in a separate optional
2322 // location for better data density (if we put them in the interface map directly data alignment could
2323 // have us using 32 or even 64 bits to represent a single boolean value). Currently the only flag we
2324 // persist is IsDeclaredOnClass (was the interface explicitly declared by this class).
2325
2326 // Currently we always store extra info whenever we have an interface map (in the future you could imagine
2327 // this being limited to those scenarios in which at least one of the interfaces has a non-default value
2328 // for a flag).
2329 inline BOOL HasExtraInterfaceInfo()
2330 {
2331 SUPPORTS_DAC;
2332 return HasInterfaceMap();
2333 }
2334
2335 // Count of interfaces that can have their extra info stored inline in the optional data structure itself
2336 // (once the interface count exceeds this limit the optional data slot will instead point to a buffer with
2337 // the information).
2338 enum { kInlinedInterfaceInfoThreshhold = sizeof(TADDR) * 8 };
2339
2340 // Calculate how many bytes of storage will be required to track additional information for interfaces.
2341 // This will be zero if there are no interfaces, but can also be zero for small numbers of interfaces as
2342 // well, and callers should be ready to handle this.
2343 static SIZE_T GetExtraInterfaceInfoSize(DWORD cInterfaces);
2344
2345 // Called after GetExtraInterfaceInfoSize above to setup a new MethodTable with the additional memory to
2346 // track extra interface info. If there are a non-zero number of interfaces implemented on this class but
2347 // GetExtraInterfaceInfoSize() returned zero, this call must still be made (with a NULL argument).
2348 void InitializeExtraInterfaceInfo(PVOID pInfo);
2349
2350#ifdef FEATURE_PREJIT
2351 // Ngen support.
2352 void SaveExtraInterfaceInfo(DataImage *pImage);
2353 void FixupExtraInterfaceInfo(DataImage *pImage);
2354#endif // FEATURE_PREJIT
2355
2356#ifdef DACCESS_COMPILE
2357 void EnumMemoryRegionsForExtraInterfaceInfo();
2358#endif // DACCESS_COMPILE
2359
2360 // For the given interface in the map (specified via map index) mark the interface as declared explicitly
2361 // on this class. This is not legal for dynamically added interfaces (as used by RCWs).
2362 void SetInterfaceDeclaredOnClass(DWORD index);
2363
2364 // For the given interface in the map (specified via map index) return true if the interface was declared
2365 // explicitly on this class.
2366 bool IsInterfaceDeclaredOnClass(DWORD index);
2367
2368 //-------------------------------------------------------------------
2369 // VIRTUAL/INTERFACE CALL RESOLUTION
2370 //
2371 // These should probably go in method.hpp since they don't have
2372 // much to do with method tables per se.
2373 //
2374
2375 // get the method desc given the interface method desc
2376 static MethodDesc *GetMethodDescForInterfaceMethodAndServer(TypeHandle ownerType, MethodDesc *pItfMD, OBJECTREF *pServer);
2377
2378#ifdef FEATURE_COMINTEROP
2379 // 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)
2380 MethodDesc *GetMethodDescForComInterfaceMethod(MethodDesc *pItfMD, bool fNullOk);
2381#endif // FEATURE_COMINTEROP
2382
2383
2384 // Try a partial resolve of the constraint call, up to generic code sharing.
2385 //
2386 // Note that this will not necessarily resolve the call exactly, since we might be compiling
2387 // shared generic code - it may just resolve it to a candidate suitable for
2388 // JIT compilation, and require a runtime lookup for the actual code pointer
2389 // to call.
2390 //
2391 // Return NULL if the call could not be resolved, e.g. because it is invoked
2392 // on a type that inherits the implementation of the method from System.Object
2393 // or System.ValueType.
2394 //
2395 // Always returns an unboxed entry point with a uniform calling convention.
2396 MethodDesc * TryResolveConstraintMethodApprox(
2397 TypeHandle ownerType,
2398 MethodDesc * pMD,
2399 BOOL * pfForceUseRuntimeLookup = NULL);
2400
2401 //-------------------------------------------------------------------
2402 // CONTRACT IMPLEMENTATIONS
2403 //
2404
2405 inline BOOL HasDispatchMap()
2406 {
2407 WRAPPER_NO_CONTRACT;
2408 return GetDispatchMap() != NULL;
2409 }
2410
2411 PTR_DispatchMap GetDispatchMap();
2412
2413 inline BOOL HasDispatchMapSlot()
2414 {
2415 LIMITED_METHOD_DAC_CONTRACT;
2416 return GetFlag(enum_flag_HasDispatchMapSlot);
2417 }
2418
2419#ifndef DACCESS_COMPILE
2420 void SetDispatchMap(DispatchMap *pDispatchMap)
2421 {
2422 LIMITED_METHOD_CONTRACT;
2423 _ASSERTE(HasDispatchMapSlot());
2424
2425 TADDR pSlot = GetMultipurposeSlotPtr(enum_flag_HasDispatchMapSlot, c_DispatchMapSlotOffsets);
2426
2427 RelativePointer<DispatchMap *> *pRelPtr = (RelativePointer<DispatchMap *> *)pSlot;
2428 pRelPtr->SetValue(pDispatchMap);
2429 }
2430#endif // !DACCESS_COMPILE
2431
2432protected:
2433 BOOL FindEncodedMapDispatchEntry(UINT32 typeID,
2434 UINT32 slotNumber,
2435 DispatchMapEntry *pEntry);
2436
2437 BOOL FindIntroducedImplementationTableDispatchEntry(UINT32 slotNumber,
2438 DispatchMapEntry *pEntry,
2439 BOOL fVirtualMethodsOnly);
2440
2441 BOOL FindDispatchEntryForCurrentType(UINT32 typeID,
2442 UINT32 slotNumber,
2443 DispatchMapEntry *pEntry);
2444
2445 BOOL FindDispatchEntry(UINT32 typeID,
2446 UINT32 slotNumber,
2447 DispatchMapEntry *pEntry);
2448
2449public:
2450 BOOL FindDispatchImpl(
2451 UINT32 typeID,
2452 UINT32 slotNumber,
2453 DispatchSlot * pImplSlot,
2454 BOOL throwOnConflict);
2455
2456
2457#ifndef DACCESS_COMPILE
2458 BOOL FindDefaultInterfaceImplementation(
2459 MethodDesc *pInterfaceMD,
2460 MethodTable *pObjectMT,
2461 MethodDesc **ppDefaultMethod,
2462 BOOL allowVariance,
2463 BOOL throwOnConflict);
2464#endif // DACCESS_COMPILE
2465
2466 DispatchSlot FindDispatchSlot(UINT32 typeID, UINT32 slotNumber, BOOL throwOnConflict);
2467
2468 DispatchSlot FindDispatchSlot(DispatchToken tok, BOOL throwOnConflict);
2469
2470 // You must use the second of these two if there is any chance the pMD is a method
2471 // on a generic interface such as IComparable<T> (which it normally can be). The
2472 // ownerType is used to provide an exact qualification in the case the pMD is
2473 // a shared method descriptor.
2474 DispatchSlot FindDispatchSlotForInterfaceMD(MethodDesc *pMD, BOOL throwOnConflict);
2475 DispatchSlot FindDispatchSlotForInterfaceMD(TypeHandle ownerType, MethodDesc *pMD, BOOL throwOnConflict);
2476
2477 MethodDesc *ReverseInterfaceMDLookup(UINT32 slotNumber);
2478
2479 // Lookup, does not assign if not already done.
2480 UINT32 LookupTypeID();
2481 // Lookup, will assign ID if not already done.
2482 UINT32 GetTypeID();
2483
2484
2485 MethodTable *LookupDispatchMapType(DispatchMapTypeID typeID);
2486
2487 MethodDesc *GetIntroducingMethodDesc(DWORD slotNumber);
2488
2489 // Determines whether all methods in the given interface have their final implementing
2490 // slot in a parent class. I.e. if this returns TRUE, it is trivial (no VSD lookup) to
2491 // dispatch pItfMT methods on this class if one knows how to dispatch them on pParentMT.
2492 BOOL ImplementsInterfaceWithSameSlotsAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
2493
2494 // Determines whether all methods in the given interface have their final implementation
2495 // in a parent class. I.e. if this returns TRUE, this class behaves the same as pParentMT
2496 // when it comes to dispatching pItfMT methods.
2497 BOOL HasSameInterfaceImplementationAsParent(MethodTable *pItfMT, MethodTable *pParentMT);
2498
2499public:
2500 static MethodDesc *MapMethodDeclToMethodImpl(MethodDesc *pMDDecl);
2501
2502 //-------------------------------------------------------------------
2503 // FINALIZATION SEMANTICS
2504 //
2505
2506 DWORD CannotUseSuperFastHelper()
2507 {
2508 WRAPPER_NO_CONTRACT;
2509 return HasFinalizer();
2510 }
2511
2512 void SetHasFinalizer()
2513 {
2514 LIMITED_METHOD_CONTRACT;
2515 SetFlag(enum_flag_HasFinalizer);
2516 }
2517
2518 void SetHasCriticalFinalizer()
2519 {
2520 LIMITED_METHOD_CONTRACT;
2521 SetFlag(enum_flag_HasCriticalFinalizer);
2522 }
2523 // Does this class have non-trivial finalization requirements?
2524 DWORD HasFinalizer()
2525 {
2526 LIMITED_METHOD_DAC_CONTRACT;
2527 return GetFlag(enum_flag_HasFinalizer);
2528 }
2529 // Must this class be finalized during a rude appdomain unload, and
2530 // must it's finalizer run in a different order from normal finalizers?
2531 DWORD HasCriticalFinalizer() const
2532 {
2533 LIMITED_METHOD_CONTRACT;
2534 return GetFlag(enum_flag_HasCriticalFinalizer);
2535 }
2536
2537 //-------------------------------------------------------------------
2538 // STATIC FIELDS
2539 //
2540
2541 DWORD GetOffsetOfFirstStaticHandle();
2542 DWORD GetOffsetOfFirstStaticMT();
2543
2544#ifndef DACCESS_COMPILE
2545 inline PTR_BYTE GetNonGCStaticsBasePointer();
2546 inline PTR_BYTE GetGCStaticsBasePointer();
2547 inline PTR_BYTE GetNonGCThreadStaticsBasePointer();
2548 inline PTR_BYTE GetGCThreadStaticsBasePointer();
2549#endif //!DACCESS_COMPILE
2550
2551 inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread);
2552 inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread);
2553
2554 inline DWORD IsDynamicStatics()
2555 {
2556 LIMITED_METHOD_DAC_CONTRACT;
2557 return !TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_NonDynamic);
2558 }
2559
2560 inline void SetDynamicStatics(BOOL fGeneric)
2561 {
2562 LIMITED_METHOD_CONTRACT;
2563 SetFlag(fGeneric ? enum_flag_StaticsMask_Generics : enum_flag_StaticsMask_Dynamic);
2564 }
2565
2566 inline void SetHasBoxedRegularStatics()
2567 {
2568 LIMITED_METHOD_CONTRACT;
2569 SetFlag(enum_flag_HasBoxedRegularStatics);
2570 }
2571
2572 inline DWORD HasBoxedRegularStatics()
2573 {
2574 LIMITED_METHOD_CONTRACT;
2575 return GetFlag(enum_flag_HasBoxedRegularStatics);
2576 }
2577
2578 DWORD HasFixedAddressVTStatics();
2579
2580 //-------------------------------------------------------------------
2581 // PER-INSTANTIATION STATICS INFO
2582 //
2583
2584
2585 void SetupGenericsStaticsInfo(FieldDesc* pStaticFieldDescs);
2586
2587 BOOL HasGenericsStaticsInfo()
2588 {
2589 LIMITED_METHOD_DAC_CONTRACT;
2590 return GetFlag(enum_flag_StaticsMask_Generics);
2591 }
2592
2593 PTR_FieldDesc GetGenericsStaticFieldDescs()
2594 {
2595 WRAPPER_NO_CONTRACT;
2596 _ASSERTE(HasGenericsStaticsInfo());
2597 return ReadPointerMaybeNull((GenericsStaticsInfo *)GetGenericsStaticsInfo(), &GenericsStaticsInfo::m_pFieldDescs);
2598 }
2599
2600 BOOL HasCrossModuleGenericStaticsInfo()
2601 {
2602 LIMITED_METHOD_DAC_CONTRACT;
2603 return TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_CrossModuleGenerics);
2604 }
2605
2606 PTR_Module GetGenericsStaticsModuleAndID(DWORD * pID);
2607
2608 WORD GetNumHandleRegularStatics();
2609
2610 WORD GetNumBoxedRegularStatics ();
2611 WORD GetNumBoxedThreadStatics ();
2612
2613 //-------------------------------------------------------------------
2614 // DYNAMIC ID
2615 //
2616
2617 // Used for generics and reflection emit in memory
2618 DWORD GetModuleDynamicEntryID();
2619 Module* GetModuleForStatics();
2620
2621 //-------------------------------------------------------------------
2622 // GENERICS DICT INFO
2623 //
2624
2625 // Number of generic arguments, whether this is a method table for
2626 // a generic type instantiation, e.g. List<string> or the "generic" MethodTable
2627 // e.g. for List.
2628 inline DWORD GetNumGenericArgs()
2629 {
2630 LIMITED_METHOD_DAC_CONTRACT;
2631 if (HasInstantiation())
2632 return (DWORD) (GetGenericsDictInfo()->m_wNumTyPars);
2633 else
2634 return 0;
2635 }
2636
2637 inline DWORD GetNumDicts()
2638 {
2639 LIMITED_METHOD_DAC_CONTRACT;
2640 if (HasPerInstInfo())
2641 {
2642 PTR_GenericsDictInfo pDictInfo = GetGenericsDictInfo();
2643 return (DWORD) (pDictInfo->m_wNumDicts);
2644 }
2645 else
2646 return 0;
2647 }
2648
2649 //-------------------------------------------------------------------
2650 // OBJECTS
2651 //
2652
2653 OBJECTREF Allocate();
2654
2655 // This flavor of Allocate is more efficient, but can only be used
2656 // if IsRestored(), CheckInstanceActivated(), IsClassInited() are known to be true.
2657 // A sufficient condition is that another instance of the exact same type already
2658 // exists in the same appdomain. It's currently called only from Delegate.Combine
2659 // via COMDelegate::InternalAllocLike.
2660 OBJECTREF AllocateNoChecks();
2661
2662 OBJECTREF Box(void* data);
2663 OBJECTREF FastBox(void** data);
2664#ifndef DACCESS_COMPILE
2665 BOOL UnBoxInto(void *dest, OBJECTREF src);
2666 BOOL UnBoxIntoArg(ArgDestination *argDest, OBJECTREF src);
2667 void UnBoxIntoUnchecked(void *dest, OBJECTREF src);
2668#endif
2669
2670#ifdef _DEBUG
2671 // Used for debugging class layout. Dumps to the debug console
2672 // when debug is true.
2673 void DebugDumpVtable(LPCUTF8 szClassName, BOOL fDebug);
2674 void Debug_DumpInterfaceMap(LPCSTR szInterfaceMapPrefix);
2675 void Debug_DumpDispatchMap();
2676 void DebugDumpFieldLayout(LPCUTF8 pszClassName, BOOL debug);
2677 void DebugRecursivelyDumpInstanceFields(LPCUTF8 pszClassName, BOOL debug);
2678 void DebugDumpGCDesc(LPCUTF8 pszClassName, BOOL debug);
2679#endif //_DEBUG
2680
2681 inline BOOL IsAgileAndFinalizable()
2682 {
2683 LIMITED_METHOD_CONTRACT;
2684 // Right now, System.Thread is the only cases of this.
2685 // Things should stay this way - please don't change without talking to EE team.
2686 return this == g_pThreadClass;
2687 }
2688
2689
2690 //-------------------------------------------------------------------
2691 // ENUMS, DELEGATES, VALUE TYPES, ARRAYS
2692 //
2693 // #KindsOfElementTypes
2694 // GetInternalCorElementType() retrieves the internal representation of the type. It's not always
2695 // appropiate to use this. For example, we treat enums as their underlying type or some structs are
2696 // optimized to be ints. To get the signature type or the verifier type (same as signature except for
2697 // enums are normalized to the primtive type that underlies them), use the APIs in Typehandle.h
2698 //
2699 // * code:TypeHandle.GetSignatureCorElementType()
2700 // * code:TypeHandle.GetVerifierCorElementType()
2701 // * code:TypeHandle.GetInternalCorElementType()
2702 CorElementType GetInternalCorElementType();
2703 void SetInternalCorElementType(CorElementType _NormType);
2704
2705 // See code:TypeHandle::GetVerifierCorElementType for description
2706 CorElementType GetVerifierCorElementType();
2707
2708 // See code:TypeHandle::GetSignatureCorElementType for description
2709 CorElementType GetSignatureCorElementType();
2710
2711 // A true primitive is one who's GetVerifierCorElementType() ==
2712 // ELEMENT_TYPE_I,
2713 // ELEMENT_TYPE_I4,
2714 // ELEMENT_TYPE_TYPEDBYREF etc.
2715 // Note that GetIntenalCorElementType might return these same values for some additional
2716 // types such as Enums and some structs.
2717 BOOL IsTruePrimitive();
2718 void SetIsTruePrimitive();
2719
2720 // Is this delegate? Returns false for System.Delegate and System.MulticastDelegate.
2721 inline BOOL IsDelegate()
2722 {
2723 LIMITED_METHOD_DAC_CONTRACT;
2724 // We do not allow single cast delegates anymore, just check for multicast delegate
2725 _ASSERTE(g_pMulticastDelegateClass);
2726 return ParentEquals(g_pMulticastDelegateClass);
2727 }
2728
2729 // Is this System.Object?
2730 inline BOOL IsObjectClass()
2731 {
2732 LIMITED_METHOD_CONTRACT;
2733 _ASSERTE(g_pObjectClass);
2734 return (this == g_pObjectClass);
2735 }
2736
2737 // Is this System.ValueType?
2738 inline DWORD IsValueTypeClass()
2739 {
2740 LIMITED_METHOD_CONTRACT;
2741 _ASSERTE(g_pValueTypeClass);
2742 return (this == g_pValueTypeClass);
2743 }
2744
2745 // Is this value type? Returns false for System.ValueType and System.Enum.
2746 inline BOOL IsValueType();
2747
2748 // Returns "TRUE" iff "this" is a struct type such that return buffers used for returning a value
2749 // of this type must be stack-allocated. This will generally be true only if the struct
2750 // contains GC pointers, and does not exceed some size limit. Maintaining this as an invariant allows
2751 // an optimization: the JIT may assume that return buffer pointers for return types for which this predicate
2752 // returns TRUE are always stack allocated, and thus, that stores to the GC-pointer fields of such return
2753 // buffers do not require GC write barriers.
2754 BOOL IsStructRequiringStackAllocRetBuf();
2755
2756 // Is this enum? Returns false for System.Enum.
2757 inline BOOL IsEnum();
2758
2759 // Is this array? Returns false for System.Array.
2760 inline BOOL IsArray()
2761 {
2762 LIMITED_METHOD_DAC_CONTRACT;
2763 return GetFlag(enum_flag_Category_Array_Mask) == enum_flag_Category_Array;
2764 }
2765 inline BOOL IsMultiDimArray()
2766 {
2767 LIMITED_METHOD_DAC_CONTRACT;
2768 PRECONDITION(IsArray());
2769 return !GetFlag(enum_flag_Category_IfArrayThenSzArray);
2770 }
2771
2772 // Returns true if this type is Nullable<T> for some T.
2773 inline BOOL IsNullable()
2774 {
2775 LIMITED_METHOD_DAC_CONTRACT;
2776 return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_Nullable;
2777 }
2778
2779 inline void SetIsNullable()
2780 {
2781 LIMITED_METHOD_CONTRACT;
2782 _ASSERTE(GetFlag(enum_flag_Category_Mask) == enum_flag_Category_ValueType);
2783 SetFlag(enum_flag_Category_Nullable);
2784 }
2785
2786 inline BOOL IsStructMarshalable()
2787 {
2788 LIMITED_METHOD_CONTRACT;
2789 PRECONDITION(!IsInterface());
2790 return GetFlag(enum_flag_IfNotInterfaceThenMarshalable);
2791 }
2792
2793 inline void SetStructMarshalable()
2794 {
2795 LIMITED_METHOD_CONTRACT;
2796 PRECONDITION(!IsInterface());
2797 SetFlag(enum_flag_IfNotInterfaceThenMarshalable);
2798 }
2799
2800 // The following methods are only valid for the
2801 // method tables for array types. These MTs may
2802 // be shared between array types and thus GetArrayElementTypeHandle
2803 // may only be approximate. If you need the exact element type handle then
2804 // you should probably be calling GetArrayElementTypeHandle on a TypeHandle,
2805 // or an ArrayTypeDesc, or on an object reference that is known to be an array,
2806 // e.g. a BASEARRAYREF.
2807 //
2808 // At the moment only the object[] MethodTable is shared between array types.
2809 // In the future the amount of sharing of method tables is likely to be increased.
2810 CorElementType GetArrayElementType();
2811 DWORD GetRank();
2812
2813 TypeHandle GetApproxArrayElementTypeHandle()
2814 {
2815 LIMITED_METHOD_DAC_CONTRACT;
2816 _ASSERTE (IsArray());
2817 return TypeHandle::FromTAddr(m_ElementTypeHnd);
2818 }
2819
2820 void SetApproxArrayElementTypeHandle(TypeHandle th)
2821 {
2822 LIMITED_METHOD_DAC_CONTRACT;
2823 m_ElementTypeHnd = th.AsTAddr();
2824 }
2825
2826 TypeHandle * GetApproxArrayElementTypeHandlePtr()
2827 {
2828 LIMITED_METHOD_CONTRACT;
2829 return (TypeHandle *)&m_ElementTypeHnd;
2830 }
2831
2832 static inline DWORD GetOffsetOfArrayElementTypeHandle()
2833 {
2834 LIMITED_METHOD_CONTRACT;
2835 return offsetof(MethodTable, m_ElementTypeHnd);
2836 }
2837
2838 //-------------------------------------------------------------------
2839 // UNDERLYING METADATA
2840 //
2841
2842
2843 // Get the RID/token for the metadata for the corresponding type declaration
2844 unsigned GetTypeDefRid();
2845 unsigned GetTypeDefRid_NoLogging();
2846
2847 inline mdTypeDef GetCl()
2848 {
2849 LIMITED_METHOD_CONTRACT;
2850 return TokenFromRid(GetTypeDefRid(), mdtTypeDef);
2851 }
2852
2853 inline mdTypeDef GetCl_NoLogging()
2854 {
2855 LIMITED_METHOD_CONTRACT;
2856 return TokenFromRid(GetTypeDefRid_NoLogging(), mdtTypeDef);
2857 }
2858
2859 void SetCl(mdTypeDef token);
2860
2861#ifdef _DEBUG
2862// Make this smaller in debug builds to exercise the overflow codepath
2863#define METHODTABLE_TOKEN_OVERFLOW 0xFFF
2864#else
2865#define METHODTABLE_TOKEN_OVERFLOW 0xFFFF
2866#endif
2867
2868 BOOL HasTokenOverflow()
2869 {
2870 LIMITED_METHOD_CONTRACT;
2871 return m_wToken == METHODTABLE_TOKEN_OVERFLOW;
2872 }
2873
2874 // Get the MD Import for the metadata for the corresponding type declaration
2875 IMDInternalImport* GetMDImport();
2876
2877 mdTypeDef GetEnclosingCl();
2878
2879#ifdef DACCESS_COMPILE
2880 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
2881#endif
2882
2883 //-------------------------------------------------------------------
2884 // REMOTEABLE METHOD INFO
2885 //
2886
2887#ifdef FEATURE_COMINTEROP
2888 void SetHasGuidInfo();
2889 BOOL HasGuidInfo();
2890 void SetHasCCWTemplate();
2891 BOOL HasCCWTemplate();
2892 void SetHasRCWPerTypeData();
2893 BOOL HasRCWPerTypeData();
2894#endif // FEATURE_COMINTEROP
2895
2896 //-------------------------------------------------------------------
2897 // DICTIONARIES FOR GENERIC INSTANTIATIONS
2898 //
2899 // The PerInstInfo pointer is a pointer to per-instantiation pointer table,
2900 // each entry of which points to an instantiation "dictionary"
2901 // for an instantiated type; the last pointer points to a
2902 // dictionary which is specific to this method table, previous
2903 // entries point to dictionaries in superclasses. Instantiated interfaces and structs
2904 // have just single dictionary (no inheritance).
2905 //
2906 // GetNumDicts() gives the number of dictionaries.
2907 //
2908 //@nice GENERICS: instead of a separate table of pointers, put the pointers
2909 // in the vtable itself. Advantages:
2910 // * Time: we save an indirection as we don't need to go through PerInstInfo first.
2911 // * Space: no need for PerInstInfo (1 word)
2912 // Problem is that lots of code assumes that the vtable is filled
2913 // uniformly with pointers to MethodDesc stubs.
2914 //
2915 // The dictionary for the method table is just an array of handles for
2916 // type parameters in the following cases:
2917 // * instantiated interfaces (no code)
2918 // * instantiated types whose code is not shared
2919 // Otherwise, it starts with the type parameters and then has a fixed
2920 // number of slots for handles (types & methods)
2921 // that are filled in lazily at run-time. Finally there is a "spill-bucket"
2922 // pointer used when the dictionary gets filled.
2923 // In summary:
2924 // typar_1 type handle for first type parameter
2925 // ...
2926 // typar_n type handle for last type parameter
2927 // slot_1 slot for first run-time handle (initially null)
2928 // ...
2929 // slot_m slot for last run-time handle (initially null)
2930 // next_bucket pointer to spill bucket (possibly null)
2931 // The spill bucket contains just run-time handle slots.
2932 // (Alternative: continue chaining buckets.
2933 // Advantage: no need to deallocate when growing dictionaries.
2934 // Disadvantage: more indirections required at run-time.)
2935 //
2936 // The layout of dictionaries is determined by GetClass()->GetDictionaryLayout()
2937 // Thus the layout can vary between incompatible instantiations. This is sometimes useful because individual type
2938 // parameters may or may not be shared. For example, consider a two parameter class Dict<K,D>. In instantiations shared with
2939 // Dict<double,string> any reference to K is known at JIT-compile-time (it's double) but any token containing D
2940 // must have a dictionary entry. On the other hand, for instantiations shared with Dict<string,double> the opposite holds.
2941 //
2942
2943#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
2944 typedef RelativePointer<PTR_Dictionary> PerInstInfoElem_t;
2945 typedef RelativePointer<DPTR(PerInstInfoElem_t)> PerInstInfo_t;
2946#else
2947 typedef PlainPointer<PTR_Dictionary> PerInstInfoElem_t;
2948 typedef PlainPointer<DPTR(PerInstInfoElem_t)> PerInstInfo_t;
2949#endif
2950
2951 // Return a pointer to the per-instantiation information. See field itself for comments.
2952 DPTR(PerInstInfoElem_t) GetPerInstInfo()
2953 {
2954 LIMITED_METHOD_DAC_CONTRACT;
2955 _ASSERTE(HasPerInstInfo());
2956 return ReadPointer(this, &MethodTable::m_pPerInstInfo);
2957 }
2958 BOOL HasPerInstInfo()
2959 {
2960 LIMITED_METHOD_DAC_CONTRACT;
2961 return GetFlag(enum_flag_HasPerInstInfo) && !IsArray();
2962 }
2963#ifndef DACCESS_COMPILE
2964 static inline bool IsPerInstInfoRelative()
2965 {
2966 LIMITED_METHOD_CONTRACT;
2967 return decltype(m_pPerInstInfo)::isRelative;
2968 }
2969 static inline DWORD GetOffsetOfPerInstInfo()
2970 {
2971 LIMITED_METHOD_CONTRACT;
2972 return offsetof(MethodTable, m_pPerInstInfo);
2973 }
2974 void SetPerInstInfo(PerInstInfoElem_t *pPerInstInfo)
2975 {
2976 LIMITED_METHOD_CONTRACT;
2977 m_pPerInstInfo.SetValue(pPerInstInfo);
2978 }
2979 void SetDictInfo(WORD numDicts, WORD numTyPars)
2980 {
2981 WRAPPER_NO_CONTRACT;
2982 GenericsDictInfo* pInfo = GetGenericsDictInfo();
2983 pInfo->m_wNumDicts = numDicts;
2984 pInfo->m_wNumTyPars = numTyPars;
2985 }
2986#endif // !DACCESS_COMPILE
2987 PTR_GenericsDictInfo GetGenericsDictInfo()
2988 {
2989 LIMITED_METHOD_DAC_CONTRACT;
2990 // GenericsDictInfo is stored at negative offset of the dictionary
2991 return dac_cast<PTR_GenericsDictInfo>(GetPerInstInfo()) - 1;
2992 }
2993
2994 // Get a pointer to the dictionary for this instantiated type
2995 // (The instantiation is stored in the initial slots of the dictionary)
2996 // If not instantiated, return NULL
2997 PTR_Dictionary GetDictionary();
2998
2999#ifdef FEATURE_PREJIT
3000 //
3001 // After the zapper compiles all code in a module it may attempt
3002 // to populate entries in all dictionaries
3003 // associated with generic types. This is an optional step - nothing will
3004 // go wrong at runtime except we may get more one-off calls to JIT_GenericHandle.
3005 // Although these are one-off we prefer to avoid them since they touch metadata
3006 // pages.
3007 //
3008 // Fully populating a dictionary may in theory load more types. However
3009 // for the moment only those entries that refer to types that
3010 // are already loaded will be filled in.
3011 void PrepopulateDictionary(DataImage * image, BOOL nonExpansive);
3012#endif // FEATURE_PREJIT
3013
3014 // Return a substitution suitbale for interpreting
3015 // the metadata in parent class, assuming we already have a subst.
3016 // suitable for interpreting the current class.
3017 //
3018 // If, for example, the definition for the current class is
3019 // D<T> : C<List<T>, T[] >
3020 // then this (for C<!0,!1>) will be
3021 // 0 --> List<T>
3022 // 1 --> T[]
3023 // added to the chain of substitutions.
3024 //
3025 // Subsequently, if the definition for C is
3026 // C<T, U> : B< Dictionary<T, U> >
3027 // then the next subst (for B<!0>) will be
3028 // 0 --> Dictionary< List<T>, T[] >
3029
3030 Substitution GetSubstitutionForParent(const Substitution *pSubst);
3031
3032 inline DWORD GetAttrClass();
3033
3034 inline BOOL HasFieldsWhichMustBeInited();
3035
3036 inline BOOL IsPreRestored() const
3037 {
3038 LIMITED_METHOD_DAC_CONTRACT;
3039
3040 return GetFlag(enum_flag_IsPreRestored);
3041 }
3042
3043 //-------------------------------------------------------------------
3044 // THE EXPOSED CLASS OBJECT
3045 //
3046 /*
3047 * m_ExposedClassObject is a RuntimeType instance for this class. But
3048 * do NOT use it for Arrays or remoted objects! All arrays of objects
3049 * share the same MethodTable/EEClass.
3050 * @GENERICS: this is per-instantiation data
3051 */
3052 // There are two version of GetManagedClassObject. The GetManagedClassObject()
3053 // method will get the class object. If it doesn't exist it will be created.
3054 // GetManagedClassObjectIfExists() will return null if the Type object doesn't exist.
3055 OBJECTREF GetManagedClassObject();
3056 OBJECTREF GetManagedClassObjectIfExists();
3057
3058
3059 // ------------------------------------------------------------------
3060 // Private part of MethodTable
3061 // ------------------------------------------------------------------
3062
3063#ifndef DACCESS_COMPILE
3064 inline void SetWriteableData(PTR_MethodTableWriteableData pMTWriteableData)
3065 {
3066 LIMITED_METHOD_CONTRACT;
3067 _ASSERTE(pMTWriteableData);
3068 m_pWriteableData.SetValue(pMTWriteableData);
3069 }
3070#endif
3071
3072 inline PTR_Const_MethodTableWriteableData GetWriteableData() const
3073 {
3074 LIMITED_METHOD_DAC_CONTRACT;
3075 g_IBCLogger.LogMethodTableWriteableDataAccess(this);
3076 return GetWriteableData_NoLogging();
3077 }
3078
3079 inline PTR_Const_MethodTableWriteableData GetWriteableData_NoLogging() const
3080 {
3081 LIMITED_METHOD_DAC_CONTRACT;
3082 return ReadPointer(this, &MethodTable::m_pWriteableData);
3083 }
3084
3085 inline PTR_MethodTableWriteableData GetWriteableDataForWrite()
3086 {
3087 LIMITED_METHOD_DAC_CONTRACT;
3088 g_IBCLogger.LogMethodTableWriteableDataWriteAccess(this);
3089 return GetWriteableDataForWrite_NoLogging();
3090 }
3091
3092 inline PTR_MethodTableWriteableData GetWriteableDataForWrite_NoLogging()
3093 {
3094 LIMITED_METHOD_DAC_CONTRACT;
3095 return ReadPointer(this, &MethodTable::m_pWriteableData);
3096 }
3097
3098 //-------------------------------------------------------------------
3099 // The GUID Info
3100 // Used by COM interop to get GUIDs (IIDs and CLSIDs)
3101
3102 // Get/store cached GUID information
3103 PTR_GuidInfo GetGuidInfo();
3104 void SetGuidInfo(GuidInfo* pGuidInfo);
3105
3106 // Get and cache the GUID for this interface/class
3107 HRESULT GetGuidNoThrow(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
3108
3109 // Get and cache the GUID for this interface/class
3110 void GetGuid(GUID *pGuid, BOOL bGenerateIfNotFound, BOOL bClassic = TRUE);
3111
3112#ifdef FEATURE_COMINTEROP
3113 // Get the GUID used for WinRT interop
3114 // * for projection generic interfaces returns the equivalent WinRT type's GUID
3115 // * for everything else returns the GetGuid(, TRUE)
3116 BOOL GetGuidForWinRT(GUID *pGuid);
3117
3118private:
3119 // Create RCW data associated with this type.
3120 RCWPerTypeData *CreateRCWPerTypeData(bool bThrowOnOOM);
3121
3122public:
3123 // Get the RCW data associated with this type or NULL if the type does not need such data or allocation
3124 // failed (only if bThrowOnOOM is false).
3125 RCWPerTypeData *GetRCWPerTypeData(bool bThrowOnOOM = true);
3126#endif // FEATURE_COMINTEROP
3127
3128 // Convenience method - determine if the interface/class has a guid specified (even if not yet cached)
3129 BOOL HasExplicitGuid();
3130
3131public :
3132 // Helper routines for the GetFullyQualifiedNameForClass macros defined at the top of class.h.
3133 // You probably should not use these functions directly.
3134 SString &_GetFullyQualifiedNameForClassNestedAware(SString &ssBuf);
3135 SString &_GetFullyQualifiedNameForClass(SString &ssBuf);
3136 LPCUTF8 GetFullyQualifiedNameInfo(LPCUTF8 *ppszNamespace);
3137
3138private:
3139 template<typename RedirectFunctor> SString &_GetFullyQualifiedNameForClassNestedAwareInternal(SString &ssBuf);
3140
3141public :
3142 //-------------------------------------------------------------------
3143 // Debug Info
3144 //
3145
3146
3147#ifdef _DEBUG
3148 inline LPCUTF8 GetDebugClassName()
3149 {
3150 LIMITED_METHOD_CONTRACT;
3151 return debug_m_szClassName;
3152 }
3153 inline void SetDebugClassName(LPCUTF8 name)
3154 {
3155 LIMITED_METHOD_CONTRACT;
3156 debug_m_szClassName = name;
3157 }
3158
3159 // Was the type created with injected duplicates?
3160 // TRUE means that we tried to inject duplicates (not that we found one to inject).
3161 inline BOOL Debug_HasInjectedInterfaceDuplicates() const
3162 {
3163 LIMITED_METHOD_CONTRACT;
3164 return (GetWriteableData()->m_dwFlags & MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates) != 0;
3165 }
3166 inline void Debug_SetHasInjectedInterfaceDuplicates()
3167 {
3168 LIMITED_METHOD_CONTRACT;
3169 GetWriteableDataForWrite()->m_dwFlags |= MethodTableWriteableData::enum_flag_HasInjectedInterfaceDuplicates;
3170 }
3171#endif // _DEBUG
3172
3173
3174#ifndef DACCESS_COMPILE
3175public:
3176 //--------------------------------------------------------------------------------------
3177 class MethodData
3178 {
3179 public:
3180 inline ULONG AddRef()
3181 { LIMITED_METHOD_CONTRACT; return (ULONG) InterlockedIncrement((LONG*)&m_cRef); }
3182
3183 ULONG Release();
3184
3185 // Since all methods that return a MethodData already AddRef'd, we do NOT
3186 // want to AddRef when putting a holder around it. We only want to release it.
3187 static void HolderAcquire(MethodData *pEntry)
3188 { LIMITED_METHOD_CONTRACT; return; }
3189 static void HolderRelease(MethodData *pEntry)
3190 { WRAPPER_NO_CONTRACT; if (pEntry != NULL) pEntry->Release(); }
3191
3192 protected:
3193 ULONG m_cRef;
3194
3195 public:
3196 MethodData() : m_cRef(1) { LIMITED_METHOD_CONTRACT; }
3197 virtual ~MethodData() { LIMITED_METHOD_CONTRACT; }
3198
3199 virtual MethodData *GetDeclMethodData() = 0;
3200 virtual MethodTable *GetDeclMethodTable() = 0;
3201 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber) = 0;
3202
3203 virtual MethodData *GetImplMethodData() = 0;
3204 virtual MethodTable *GetImplMethodTable() = 0;
3205 virtual DispatchSlot GetImplSlot(UINT32 slotNumber) = 0;
3206 // Returns INVALID_SLOT_NUMBER if no implementation exists.
3207 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber) = 0;
3208 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber) = 0;
3209 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber) = 0;
3210
3211 virtual UINT32 GetNumVirtuals() = 0;
3212 virtual UINT32 GetNumMethods() = 0;
3213
3214 protected:
3215 static const UINT32 INVALID_SLOT_NUMBER = UINT32_MAX;
3216
3217 // This is used when building the data
3218 struct MethodDataEntry
3219 {
3220 private:
3221 static const UINT32 INVALID_CHAIN_AND_INDEX = (UINT32)(-1);
3222 static const UINT16 INVALID_IMPL_SLOT_NUM = (UINT16)(-1);
3223
3224 // This contains both the chain delta and the table index. The
3225 // reason that they are combined is that we need atomic update
3226 // of both, and it is convenient that both are on UINT16 in size.
3227 UINT32 m_chainDeltaAndTableIndex;
3228 UINT16 m_implSlotNum; // For virtually remapped slots
3229 DispatchSlot m_slot; // The entry in the DispatchImplTable
3230 MethodDesc *m_pMD; // The MethodDesc for this slot
3231
3232 public:
3233 inline MethodDataEntry() : m_slot(NULL)
3234 { WRAPPER_NO_CONTRACT; Init(); }
3235
3236 inline void Init()
3237 {
3238 LIMITED_METHOD_CONTRACT;
3239 m_chainDeltaAndTableIndex = INVALID_CHAIN_AND_INDEX;
3240 m_implSlotNum = INVALID_IMPL_SLOT_NUM;
3241 m_slot = NULL;
3242 m_pMD = NULL;
3243 }
3244
3245 inline BOOL IsDeclInit()
3246 { LIMITED_METHOD_CONTRACT; return m_chainDeltaAndTableIndex != INVALID_CHAIN_AND_INDEX; }
3247 inline BOOL IsImplInit()
3248 { LIMITED_METHOD_CONTRACT; return m_implSlotNum != INVALID_IMPL_SLOT_NUM; }
3249
3250 inline void SetDeclData(UINT32 chainDelta, UINT32 tableIndex)
3251 { LIMITED_METHOD_CONTRACT; m_chainDeltaAndTableIndex = ((((UINT16) chainDelta) << 16) | ((UINT16) tableIndex)); }
3252 inline UINT32 GetChainDelta()
3253 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return m_chainDeltaAndTableIndex >> 16; }
3254 inline UINT32 GetTableIndex()
3255 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsDeclInit()); return (m_chainDeltaAndTableIndex & (UINT32)UINT16_MAX); }
3256
3257 inline void SetImplData(UINT32 implSlotNum)
3258 { LIMITED_METHOD_CONTRACT; m_implSlotNum = (UINT16) implSlotNum; }
3259 inline UINT32 GetImplSlotNum()
3260 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsImplInit()); return m_implSlotNum; }
3261
3262 inline void SetSlot(DispatchSlot slot)
3263 { LIMITED_METHOD_CONTRACT; m_slot = slot; }
3264 inline DispatchSlot GetSlot()
3265 { LIMITED_METHOD_CONTRACT; return m_slot; }
3266
3267 inline void SetMethodDesc(MethodDesc *pMD)
3268 { LIMITED_METHOD_CONTRACT; m_pMD = pMD; }
3269 inline MethodDesc *GetMethodDesc()
3270 { LIMITED_METHOD_CONTRACT; return m_pMD; }
3271
3272 };
3273
3274 static void ProcessMap(
3275 const DispatchMapTypeID * rgTypeIDs,
3276 UINT32 cTypeIDs,
3277 MethodTable * pMT,
3278 UINT32 cCurrentChainDepth,
3279 MethodDataEntry * rgWorkingData);
3280 }; // class MethodData
3281
3282 typedef ::Holder < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataHolder;
3283 typedef ::Wrapper < MethodData *, MethodData::HolderAcquire, MethodData::HolderRelease > MethodDataWrapper;
3284
3285protected:
3286 //--------------------------------------------------------------------------------------
3287 class MethodDataObject : public MethodData
3288 {
3289 public:
3290 // Static method that returns the amount of memory to allocate for a particular type.
3291 static UINT32 GetObjectSize(MethodTable *pMT);
3292
3293 // Constructor. Make sure you have allocated enough memory using GetObjectSize.
3294 inline MethodDataObject(MethodTable *pMT)
3295 { WRAPPER_NO_CONTRACT; Init(pMT, NULL); }
3296
3297 inline MethodDataObject(MethodTable *pMT, MethodData *pParentData)
3298 { WRAPPER_NO_CONTRACT; Init(pMT, pParentData); }
3299
3300 virtual ~MethodDataObject() { LIMITED_METHOD_CONTRACT; }
3301
3302 virtual MethodData *GetDeclMethodData()
3303 { LIMITED_METHOD_CONTRACT; return this; }
3304 virtual MethodTable *GetDeclMethodTable()
3305 { LIMITED_METHOD_CONTRACT; return m_pMT; }
3306 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
3307
3308 virtual MethodData *GetImplMethodData()
3309 { LIMITED_METHOD_CONTRACT; return this; }
3310 virtual MethodTable *GetImplMethodTable()
3311 { LIMITED_METHOD_CONTRACT; return m_pMT; }
3312 virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
3313 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
3314 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3315 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3316
3317 virtual UINT32 GetNumVirtuals()
3318 { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumVirtuals(); }
3319 virtual UINT32 GetNumMethods()
3320 { LIMITED_METHOD_CONTRACT; return m_pMT->GetCanonicalMethodTable()->GetNumMethods(); }
3321
3322 protected:
3323 void Init(MethodTable *pMT, MethodData *pParentData);
3324
3325 BOOL PopulateNextLevel();
3326
3327 // This is the method table for the actual type we're gathering the data for
3328 MethodTable *m_pMT;
3329
3330 // This is used in staged map decoding - it indicates which type we will next decode.
3331 UINT32 m_iNextChainDepth;
3332 static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
3333
3334 BOOL m_containsMethodImpl;
3335
3336 // NOTE: Use of these APIs are unlocked and may appear to be erroneous. However, since calls
3337 // to ProcessMap will result in identical values being placed in the MethodDataObjectEntry
3338 // array, it it is not a problem if there is a race, since one thread may just end up
3339 // doing some duplicate work.
3340
3341 inline UINT32 GetNextChainDepth()
3342 { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
3343
3344 inline void SetNextChainDepth(UINT32 iDepth)
3345 {
3346 LIMITED_METHOD_CONTRACT;
3347 if (GetNextChainDepth() < iDepth) {
3348 VolatileStore(&m_iNextChainDepth, iDepth);
3349 }
3350 }
3351
3352 // This is used when building the data
3353 struct MethodDataObjectEntry
3354 {
3355 private:
3356 MethodDesc *m_pMDDecl;
3357 MethodDesc *m_pMDImpl;
3358
3359 public:
3360 inline MethodDataObjectEntry() : m_pMDDecl(NULL), m_pMDImpl(NULL) {}
3361
3362 inline void SetDeclMethodDesc(MethodDesc *pMD)
3363 { LIMITED_METHOD_CONTRACT; m_pMDDecl = pMD; }
3364 inline MethodDesc *GetDeclMethodDesc()
3365 { LIMITED_METHOD_CONTRACT; return m_pMDDecl; }
3366 inline void SetImplMethodDesc(MethodDesc *pMD)
3367 { LIMITED_METHOD_CONTRACT; m_pMDImpl = pMD; }
3368 inline MethodDesc *GetImplMethodDesc()
3369 { LIMITED_METHOD_CONTRACT; return m_pMDImpl; }
3370 };
3371
3372 //
3373 // At the end of this object is an array, so you cannot derive from this class.
3374 //
3375
3376 inline MethodDataObjectEntry *GetEntryData()
3377 { LIMITED_METHOD_CONTRACT; return (MethodDataObjectEntry *)(this + 1); }
3378
3379 inline MethodDataObjectEntry *GetEntry(UINT32 i)
3380 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
3381
3382 void FillEntryDataForAncestor(MethodTable *pMT);
3383
3384 // MethodDataObjectEntry m_rgEntries[...];
3385 }; // class MethodDataObject
3386
3387 //--------------------------------------------------------------------------------------
3388 class MethodDataInterface : public MethodData
3389 {
3390 public:
3391 // Static method that returns the amount of memory to allocate for a particular type.
3392 static UINT32 GetObjectSize(MethodTable *pMT)
3393 { LIMITED_METHOD_CONTRACT; return sizeof(MethodDataInterface); }
3394
3395 // Constructor. Make sure you have allocated enough memory using GetObjectSize.
3396 MethodDataInterface(MethodTable *pMT)
3397 {
3398 LIMITED_METHOD_CONTRACT;
3399 CONSISTENCY_CHECK(CheckPointer(pMT));
3400 CONSISTENCY_CHECK(pMT->IsInterface());
3401 m_pMT = pMT;
3402 }
3403 virtual ~MethodDataInterface()
3404 { LIMITED_METHOD_CONTRACT; }
3405
3406 //
3407 // Decl data
3408 //
3409 virtual MethodData *GetDeclMethodData()
3410 { LIMITED_METHOD_CONTRACT; return this; }
3411 virtual MethodTable *GetDeclMethodTable()
3412 { LIMITED_METHOD_CONTRACT; return m_pMT; }
3413 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber);
3414
3415 //
3416 // Impl data
3417 //
3418 virtual MethodData *GetImplMethodData()
3419 { LIMITED_METHOD_CONTRACT; return this; }
3420 virtual MethodTable *GetImplMethodTable()
3421 { LIMITED_METHOD_CONTRACT; return m_pMT; }
3422 virtual DispatchSlot GetImplSlot(UINT32 slotNumber)
3423 { WRAPPER_NO_CONTRACT; return DispatchSlot(m_pMT->GetRestoredSlot(slotNumber)); }
3424 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber)
3425 { LIMITED_METHOD_CONTRACT; return slotNumber; }
3426 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3427 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3428
3429 //
3430 // Slot count data
3431 //
3432 virtual UINT32 GetNumVirtuals()
3433 { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumVirtuals(); }
3434 virtual UINT32 GetNumMethods()
3435 { LIMITED_METHOD_CONTRACT; return m_pMT->GetNumMethods(); }
3436
3437 protected:
3438 // This is the method table for the actual type we're gathering the data for
3439 MethodTable *m_pMT;
3440 }; // class MethodDataInterface
3441
3442 //--------------------------------------------------------------------------------------
3443 class MethodDataInterfaceImpl : public MethodData
3444 {
3445 public:
3446 // Object construction-related methods
3447 static UINT32 GetObjectSize(MethodTable *pMTDecl);
3448
3449 MethodDataInterfaceImpl(
3450 const DispatchMapTypeID * rgDeclTypeIDs,
3451 UINT32 cDeclTypeIDs,
3452 MethodData * pDecl,
3453 MethodData * pImpl);
3454 virtual ~MethodDataInterfaceImpl();
3455
3456 // Decl-related methods
3457 virtual MethodData *GetDeclMethodData()
3458 { LIMITED_METHOD_CONTRACT; return m_pDecl; }
3459 virtual MethodTable *GetDeclMethodTable()
3460 { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodTable(); }
3461 virtual MethodDesc *GetDeclMethodDesc(UINT32 slotNumber)
3462 { WRAPPER_NO_CONTRACT; return m_pDecl->GetDeclMethodDesc(slotNumber); }
3463
3464 // Impl-related methods
3465 virtual MethodData *GetImplMethodData()
3466 { LIMITED_METHOD_CONTRACT; return m_pImpl; }
3467 virtual MethodTable *GetImplMethodTable()
3468 { WRAPPER_NO_CONTRACT; return m_pImpl->GetImplMethodTable(); }
3469 virtual DispatchSlot GetImplSlot(UINT32 slotNumber);
3470 virtual UINT32 GetImplSlotNumber(UINT32 slotNumber);
3471 virtual MethodDesc *GetImplMethodDesc(UINT32 slotNumber);
3472 virtual void InvalidateCachedVirtualSlot(UINT32 slotNumber);
3473
3474 virtual UINT32 GetNumVirtuals()
3475 { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
3476 virtual UINT32 GetNumMethods()
3477 { WRAPPER_NO_CONTRACT; return m_pDecl->GetNumVirtuals(); }
3478
3479 protected:
3480 UINT32 MapToImplSlotNumber(UINT32 slotNumber);
3481
3482 BOOL PopulateNextLevel();
3483 void Init(
3484 const DispatchMapTypeID * rgDeclTypeIDs,
3485 UINT32 cDeclTypeIDs,
3486 MethodData * pDecl,
3487 MethodData * pImpl);
3488
3489 MethodData *m_pDecl;
3490 MethodData *m_pImpl;
3491
3492 // This is used in staged map decoding - it indicates which type(s) we will find.
3493 const DispatchMapTypeID * m_rgDeclTypeIDs;
3494 UINT32 m_cDeclTypeIDs;
3495 UINT32 m_iNextChainDepth;
3496 static const UINT32 MAX_CHAIN_DEPTH = UINT32_MAX;
3497
3498 inline UINT32 GetNextChainDepth()
3499 { LIMITED_METHOD_CONTRACT; return VolatileLoad(&m_iNextChainDepth); }
3500
3501 inline void SetNextChainDepth(UINT32 iDepth)
3502 {
3503 LIMITED_METHOD_CONTRACT;
3504 if (GetNextChainDepth() < iDepth) {
3505 VolatileStore(&m_iNextChainDepth, iDepth);
3506 }
3507 }
3508
3509 //
3510 // At the end of this object is an array, so you cannot derive from this class.
3511 //
3512
3513 inline MethodDataEntry *GetEntryData()
3514 { LIMITED_METHOD_CONTRACT; return (MethodDataEntry *)(this + 1); }
3515
3516 inline MethodDataEntry *GetEntry(UINT32 i)
3517 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(i < GetNumMethods()); return GetEntryData() + i; }
3518
3519 // MethodDataEntry m_rgEntries[...];
3520 }; // class MethodDataInterfaceImpl
3521
3522 //--------------------------------------------------------------------------------------
3523 static MethodDataCache *s_pMethodDataCache;
3524 static BOOL s_fUseParentMethodData;
3525 static BOOL s_fUseMethodDataCache;
3526
3527public:
3528 static void AllowMethodDataCaching()
3529 { WRAPPER_NO_CONTRACT; CheckInitMethodDataCache(); s_fUseMethodDataCache = TRUE; }
3530 static void ClearMethodDataCache();
3531 static void AllowParentMethodDataCopy()
3532 { LIMITED_METHOD_CONTRACT; s_fUseParentMethodData = TRUE; }
3533 // NOTE: The fCanCache argument determines if the resulting MethodData object can
3534 // be added to the global MethodDataCache. This is used when requesting a
3535 // MethodData object for a type currently being built.
3536 static MethodData *GetMethodData(MethodTable *pMT, BOOL fCanCache = TRUE);
3537 static MethodData *GetMethodData(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache = TRUE);
3538 // This method is used by BuildMethodTable because the exact interface has not yet been loaded.
3539 // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
3540 static MethodData * GetMethodData(
3541 const DispatchMapTypeID * rgDeclTypeIDs,
3542 UINT32 cDeclTypeIDs,
3543 MethodTable * pMTDecl,
3544 MethodTable * pMTImpl);
3545
3546protected:
3547 static void CheckInitMethodDataCache();
3548 static MethodData *FindParentMethodDataHelper(MethodTable *pMT);
3549 static MethodData *FindMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl);
3550 static MethodData *GetMethodDataHelper(MethodTable *pMTDecl, MethodTable *pMTImpl, BOOL fCanCache);
3551 // NOTE: This method does not cache the resulting MethodData object in the global MethodDataCache.
3552 static MethodData * GetMethodDataHelper(
3553 const DispatchMapTypeID * rgDeclTypeIDs,
3554 UINT32 cDeclTypeIDs,
3555 MethodTable * pMTDecl,
3556 MethodTable * pMTImpl);
3557
3558public:
3559 //--------------------------------------------------------------------------------------
3560 class MethodIterator
3561 {
3562 public:
3563 MethodIterator(MethodTable *pMT);
3564 MethodIterator(MethodTable *pMTDecl, MethodTable *pMTImpl);
3565 MethodIterator(MethodData *pMethodData);
3566 MethodIterator(const MethodIterator &it);
3567 inline ~MethodIterator() { WRAPPER_NO_CONTRACT; m_pMethodData->Release(); }
3568 INT32 GetNumMethods() const;
3569 inline BOOL IsValid() const;
3570 inline BOOL MoveTo(UINT32 idx);
3571 inline BOOL Prev();
3572 inline BOOL Next();
3573 inline void MoveToBegin();
3574 inline void MoveToEnd();
3575 inline UINT32 GetSlotNumber() const;
3576 inline UINT32 GetImplSlotNumber() const;
3577 inline BOOL IsVirtual() const;
3578 inline UINT32 GetNumVirtuals() const;
3579 inline DispatchSlot GetTarget() const;
3580
3581 // Can be called only if IsValid()=TRUE
3582 inline MethodDesc *GetMethodDesc() const;
3583 inline MethodDesc *GetDeclMethodDesc() const;
3584
3585 protected:
3586 void Init(MethodTable *pMTDecl, MethodTable *pMTImpl);
3587
3588 MethodData *m_pMethodData;
3589 INT32 m_iCur; // Current logical slot index
3590 INT32 m_iMethods;
3591 }; // class MethodIterator
3592#endif // !DACCESS_COMPILE
3593
3594 //--------------------------------------------------------------------------------------
3595 // This iterator lets you walk over all the method bodies introduced by this type.
3596 // This includes new static methods, new non-virtual methods, and any overrides
3597 // of the parent's virtual methods. It does not include virtual method implementations
3598 // provided by the parent
3599
3600 class IntroducedMethodIterator
3601 {
3602 public:
3603 IntroducedMethodIterator(MethodTable *pMT, BOOL restrictToCanonicalTypes = TRUE);
3604 inline BOOL IsValid() const;
3605 BOOL Next();
3606
3607 // Can be called only if IsValid()=TRUE
3608 inline MethodDesc *GetMethodDesc() const;
3609
3610 // Static worker methods of the iterator. These are meant to be used
3611 // by RuntimeTypeHandle::GetFirstIntroducedMethod and RuntimeTypeHandle::GetNextIntroducedMethod
3612 // only to expose this iterator to managed code.
3613 static MethodDesc * GetFirst(MethodTable * pMT);
3614 static MethodDesc * GetNext(MethodDesc * pMD);
3615
3616 protected:
3617 MethodDesc *m_pMethodDesc; // Current method desc
3618
3619 // Cached info about current method desc
3620 MethodDescChunk *m_pChunk;
3621 TADDR m_pChunkEnd;
3622
3623 void SetChunk(MethodDescChunk * pChunk);
3624 }; // class IntroducedMethodIterator
3625
3626 //-------------------------------------------------------------------
3627 // INSTANCE MEMBER VARIABLES
3628 //
3629
3630#ifdef DACCESS_COMPILE
3631public:
3632#else
3633private:
3634#endif
3635 enum WFLAGS_LOW_ENUM
3636 {
3637 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
3638 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
3639 // CARRY THE CORECT FLAGS.
3640 //
3641
3642 // We are overloading the low 2 bytes of m_dwFlags to be a component size for Strings
3643 // and Arrays and some set of flags which we can be assured are of a specified state
3644 // for Strings / Arrays, currently these will be a bunch of generics flags which don't
3645 // apply to Strings / Arrays.
3646
3647 enum_flag_UNUSED_ComponentSize_1 = 0x00000001,
3648
3649 enum_flag_StaticsMask = 0x00000006,
3650 enum_flag_StaticsMask_NonDynamic = 0x00000000,
3651 enum_flag_StaticsMask_Dynamic = 0x00000002, // dynamic statics (EnC, reflection.emit)
3652 enum_flag_StaticsMask_Generics = 0x00000004, // generics statics
3653 enum_flag_StaticsMask_CrossModuleGenerics = 0x00000006, // cross module generics statics (NGen)
3654 enum_flag_StaticsMask_IfGenericsThenCrossModule = 0x00000002, // helper constant to get rid of unnecessary check
3655
3656 enum_flag_NotInPZM = 0x00000008, // True if this type is not in its PreferredZapModule
3657
3658 enum_flag_GenericsMask = 0x00000030,
3659 enum_flag_GenericsMask_NonGeneric = 0x00000000, // no instantiation
3660 enum_flag_GenericsMask_GenericInst = 0x00000010, // regular instantiation, e.g. List<String>
3661 enum_flag_GenericsMask_SharedInst = 0x00000020, // shared instantiation, e.g. List<__Canon> or List<MyValueType<__Canon>>
3662 enum_flag_GenericsMask_TypicalInst = 0x00000030, // the type instantiated at its formal parameters, e.g. List<T>
3663
3664 enum_flag_HasVariance = 0x00000100, // This is an instantiated type some of whose type parameters are co- or contra-variant
3665
3666 enum_flag_HasDefaultCtor = 0x00000200,
3667 enum_flag_HasPreciseInitCctors = 0x00000400, // Do we need to run class constructors at allocation time? (Not perf important, could be moved to EEClass
3668
3669#if defined(FEATURE_HFA)
3670#if defined(UNIX_AMD64_ABI)
3671#error Can't define both FEATURE_HFA and UNIX_AMD64_ABI
3672#endif
3673 enum_flag_IsHFA = 0x00000800, // This type is an HFA (Homogenous Floating-point Aggregate)
3674#endif // FEATURE_HFA
3675
3676#if defined(UNIX_AMD64_ABI)
3677#if defined(FEATURE_HFA)
3678#error Can't define both FEATURE_HFA and UNIX_AMD64_ABI
3679#endif
3680 enum_flag_IsRegStructPassed = 0x00000800, // This type is a System V register passed struct.
3681#endif // UNIX_AMD64_ABI
3682
3683 enum_flag_IsByRefLike = 0x00001000,
3684
3685 // In a perfect world we would fill these flags using other flags that we already have
3686 // which have a constant value for something which has a component size.
3687 enum_flag_UNUSED_ComponentSize_5 = 0x00002000,
3688 enum_flag_UNUSED_ComponentSize_6 = 0x00004000,
3689 enum_flag_UNUSED_ComponentSize_7 = 0x00008000,
3690
3691#define SET_FALSE(flag) (flag & 0)
3692#define SET_TRUE(flag) (flag & 0xffff)
3693
3694 // IMPORTANT! IMPORTANT! IMPORTANT!
3695 //
3696 // As you change the flags in WFLAGS_LOW_ENUM you also need to change this
3697 // to be up to date to reflect the default values of those flags for the
3698 // case where this MethodTable is for a String or Array
3699 enum_flag_StringArrayValues = SET_TRUE(enum_flag_StaticsMask_NonDynamic) |
3700 SET_FALSE(enum_flag_NotInPZM) |
3701 SET_TRUE(enum_flag_GenericsMask_NonGeneric) |
3702 SET_FALSE(enum_flag_HasVariance) |
3703 SET_FALSE(enum_flag_HasDefaultCtor) |
3704 SET_FALSE(enum_flag_HasPreciseInitCctors),
3705
3706 }; // enum WFLAGS_LOW_ENUM
3707
3708 enum WFLAGS_HIGH_ENUM
3709 {
3710 // DO NOT use flags that have bits set in the low 2 bytes.
3711 // These flags are DWORD sized so that our atomic masking
3712 // operations can operate on the entire 4-byte aligned DWORD
3713 // instead of the logical non-aligned WORD of flags. The
3714 // low WORD of flags is reserved for the component size.
3715
3716 // The following bits describe mutually exclusive locations of the type
3717 // in the type hiearchy.
3718 enum_flag_Category_Mask = 0x000F0000,
3719
3720 enum_flag_Category_Class = 0x00000000,
3721 enum_flag_Category_Unused_1 = 0x00010000,
3722 enum_flag_Category_Unused_2 = 0x00020000,
3723 enum_flag_Category_Unused_3 = 0x00030000,
3724
3725 enum_flag_Category_ValueType = 0x00040000,
3726 enum_flag_Category_ValueType_Mask = 0x000C0000,
3727 enum_flag_Category_Nullable = 0x00050000, // sub-category of ValueType
3728 enum_flag_Category_PrimitiveValueType=0x00060000, // sub-category of ValueType, Enum or primitive value type
3729 enum_flag_Category_TruePrimitive = 0x00070000, // sub-category of ValueType, Primitive (ELEMENT_TYPE_I, etc.)
3730
3731 enum_flag_Category_Array = 0x00080000,
3732 enum_flag_Category_Array_Mask = 0x000C0000,
3733 // enum_flag_Category_IfArrayThenUnused = 0x00010000, // sub-category of Array
3734 enum_flag_Category_IfArrayThenSzArray = 0x00020000, // sub-category of Array
3735
3736 enum_flag_Category_Interface = 0x000C0000,
3737 enum_flag_Category_Unused_4 = 0x000D0000,
3738 enum_flag_Category_Unused_5 = 0x000E0000,
3739 enum_flag_Category_Unused_6 = 0x000F0000,
3740
3741 enum_flag_Category_ElementTypeMask = 0x000E0000, // bits that matter for element type mask
3742
3743
3744 enum_flag_HasFinalizer = 0x00100000, // instances require finalization
3745
3746 enum_flag_IfNotInterfaceThenMarshalable = 0x00200000, // Is this type marshalable by the pinvoke marshalling layer
3747#ifdef FEATURE_COMINTEROP
3748 enum_flag_IfInterfaceThenHasGuidInfo = 0x00200000, // Does the type has optional GuidInfo
3749#endif // FEATURE_COMINTEROP
3750
3751 enum_flag_ICastable = 0x00400000, // class implements ICastable interface
3752
3753 enum_flag_HasIndirectParent = 0x00800000, // m_pParentMethodTable has double indirection
3754
3755 enum_flag_ContainsPointers = 0x01000000,
3756
3757 enum_flag_HasTypeEquivalence = 0x02000000, // can be equivalent to another type
3758
3759#ifdef FEATURE_COMINTEROP
3760 enum_flag_HasRCWPerTypeData = 0x04000000, // has optional pointer to RCWPerTypeData
3761#endif // FEATURE_COMINTEROP
3762
3763 enum_flag_HasCriticalFinalizer = 0x08000000, // finalizer must be run on Appdomain Unload
3764 enum_flag_Collectible = 0x10000000,
3765 enum_flag_ContainsGenericVariables = 0x20000000, // we cache this flag to help detect these efficiently and
3766 // to detect this condition when restoring
3767
3768 enum_flag_ComObject = 0x40000000, // class is a com object
3769
3770 enum_flag_HasComponentSize = 0x80000000, // This is set if component size is used for flags.
3771
3772 // Types that require non-trivial interface cast have this bit set in the category
3773 enum_flag_NonTrivialInterfaceCast = enum_flag_Category_Array
3774 | enum_flag_ComObject
3775 | enum_flag_ICastable
3776
3777 }; // enum WFLAGS_HIGH_ENUM
3778
3779// NIDump needs to be able to see these flags
3780// TODO: figure out how to make these private
3781#if defined(DACCESS_COMPILE)
3782public:
3783#else
3784private:
3785#endif
3786 enum WFLAGS2_ENUM
3787 {
3788 // AS YOU ADD NEW FLAGS PLEASE CONSIDER WHETHER Generics::NewInstantiation NEEDS
3789 // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS
3790 // CARRY THE CORECT FLAGS.
3791
3792 // The following bits describe usage of optional slots. They have to stay
3793 // together because of we index using them into offset arrays.
3794 enum_flag_MultipurposeSlotsMask = 0x001F,
3795 enum_flag_HasPerInstInfo = 0x0001,
3796 enum_flag_HasInterfaceMap = 0x0002,
3797 enum_flag_HasDispatchMapSlot = 0x0004,
3798 enum_flag_HasNonVirtualSlots = 0x0008,
3799 enum_flag_HasModuleOverride = 0x0010,
3800
3801 enum_flag_IsZapped = 0x0020, // This could be fetched from m_pLoaderModule if we run out of flags
3802
3803 enum_flag_IsPreRestored = 0x0040, // Class does not need restore
3804 // This flag is set only for NGENed classes (IsZapped is true)
3805
3806 enum_flag_HasModuleDependencies = 0x0080,
3807
3808 enum_flag_IsIntrinsicType = 0x0100,
3809
3810 enum_flag_RequiresDispatchTokenFat = 0x0200,
3811
3812 enum_flag_HasCctor = 0x0400,
3813 enum_flag_HasCCWTemplate = 0x0800, // Has an extra field pointing to a CCW template
3814
3815#ifdef FEATURE_64BIT_ALIGNMENT
3816 enum_flag_RequiresAlign8 = 0x1000, // Type requires 8-byte alignment (only set on platforms that require this and don't get it implicitly)
3817#endif
3818
3819 enum_flag_HasBoxedRegularStatics = 0x2000, // GetNumBoxedRegularStatics() != 0
3820
3821 enum_flag_HasSingleNonVirtualSlot = 0x4000,
3822
3823 enum_flag_DependsOnEquivalentOrForwardedStructs= 0x8000, // Declares methods that have type equivalent or type forwarded structures in their signature
3824
3825 }; // enum WFLAGS2_ENUM
3826
3827 __forceinline void ClearFlag(WFLAGS_LOW_ENUM flag)
3828 {
3829 _ASSERTE(!IsStringOrArray());
3830 m_dwFlags &= ~flag;
3831 }
3832 __forceinline void SetFlag(WFLAGS_LOW_ENUM flag)
3833 {
3834 _ASSERTE(!IsStringOrArray());
3835 m_dwFlags |= flag;
3836 }
3837 __forceinline DWORD GetFlag(WFLAGS_LOW_ENUM flag) const
3838 {
3839 SUPPORTS_DAC;
3840 return (IsStringOrArray() ? (enum_flag_StringArrayValues & flag) : (m_dwFlags & flag));
3841 }
3842 __forceinline BOOL TestFlagWithMask(WFLAGS_LOW_ENUM mask, WFLAGS_LOW_ENUM flag) const
3843 {
3844 LIMITED_METHOD_DAC_CONTRACT;
3845 return (IsStringOrArray() ? (((DWORD)enum_flag_StringArrayValues & (DWORD)mask) == (DWORD)flag) :
3846 ((m_dwFlags & (DWORD)mask) == (DWORD)flag));
3847 }
3848
3849 __forceinline void ClearFlag(WFLAGS_HIGH_ENUM flag)
3850 {
3851 m_dwFlags &= ~flag;
3852 }
3853 __forceinline void SetFlag(WFLAGS_HIGH_ENUM flag)
3854 {
3855 m_dwFlags |= flag;
3856 }
3857 __forceinline DWORD GetFlag(WFLAGS_HIGH_ENUM flag) const
3858 {
3859 LIMITED_METHOD_DAC_CONTRACT;
3860 return m_dwFlags & flag;
3861 }
3862 __forceinline BOOL TestFlagWithMask(WFLAGS_HIGH_ENUM mask, WFLAGS_HIGH_ENUM flag) const
3863 {
3864 LIMITED_METHOD_DAC_CONTRACT;
3865 return ((m_dwFlags & (DWORD)mask) == (DWORD)flag);
3866 }
3867
3868 __forceinline void ClearFlag(WFLAGS2_ENUM flag)
3869 {
3870 m_wFlags2 &= ~flag;
3871 }
3872 __forceinline void SetFlag(WFLAGS2_ENUM flag)
3873 {
3874 m_wFlags2 |= flag;
3875 }
3876 __forceinline DWORD GetFlag(WFLAGS2_ENUM flag) const
3877 {
3878 LIMITED_METHOD_DAC_CONTRACT;
3879 return m_wFlags2 & flag;
3880 }
3881 __forceinline BOOL TestFlagWithMask(WFLAGS2_ENUM mask, WFLAGS2_ENUM flag) const
3882 {
3883 return (m_wFlags2 & (DWORD)mask) == (DWORD)flag;
3884 }
3885
3886 // Just exposing a couple of these for x86 asm versions of JIT_IsInstanceOfClass and JIT_IsInstanceOfInterface
3887public:
3888 enum
3889 {
3890 public_enum_flag_HasTypeEquivalence = enum_flag_HasTypeEquivalence,
3891 public_enum_flag_NonTrivialInterfaceCast = enum_flag_NonTrivialInterfaceCast,
3892 };
3893
3894private:
3895 /*
3896 * This stuff must be first in the struct and should fit on a cache line - don't move it. Used by the GC.
3897 */
3898 // struct
3899 // {
3900
3901 // Low WORD is component size for array and string types (HasComponentSize() returns true).
3902 // Used for flags otherwise.
3903 DWORD m_dwFlags;
3904
3905 // Base size of instance of this class when allocated on the heap
3906 DWORD m_BaseSize;
3907 // }
3908
3909 WORD m_wFlags2;
3910
3911 // Class token if it fits into 16-bits. If this is (WORD)-1, the class token is stored in the TokenOverflow optional member.
3912 WORD m_wToken;
3913
3914 // <NICE> In the normal cases we shouldn't need a full word for each of these </NICE>
3915 WORD m_wNumVirtuals;
3916 WORD m_wNumInterfaces;
3917
3918#ifdef _DEBUG
3919 LPCUTF8 debug_m_szClassName;
3920#endif //_DEBUG
3921
3922 // On Linux ARM is a RelativeFixupPointer. Otherwise,
3923 // Parent PTR_MethodTable if enum_flag_HasIndirectParent is not set. Pointer to indirection cell
3924 // if enum_flag_enum_flag_HasIndirectParent is set. The indirection is offset by offsetof(MethodTable, m_pParentMethodTable).
3925 // It allows casting helpers to go through parent chain natually. Casting helper do not need need the explicit check
3926 // for enum_flag_HasIndirectParentMethodTable.
3927 ParentMT_t m_pParentMethodTable;
3928
3929 RelativePointer<PTR_Module> m_pLoaderModule; // LoaderModule. It is equal to the ZapModule in ngened images
3930
3931#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
3932 RelativePointer<PTR_MethodTableWriteableData> m_pWriteableData;
3933#else
3934 PlainPointer<PTR_MethodTableWriteableData> m_pWriteableData;
3935#endif
3936
3937 // The value of lowest two bits describe what the union contains
3938 enum LowBits {
3939 UNION_EECLASS = 0, // 0 - pointer to EEClass. This MethodTable is the canonical method table.
3940 UNION_INVALID = 1, // 1 - not used
3941 UNION_METHODTABLE = 2, // 2 - pointer to canonical MethodTable.
3942 UNION_INDIRECTION = 3 // 3 - pointer to indirection cell that points to canonical MethodTable.
3943 }; // (used only if FEATURE_PREJIT is defined)
3944 static const TADDR UNION_MASK = 3;
3945
3946 union {
3947#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
3948 RelativePointer<DPTR(EEClass)> m_pEEClass;
3949 RelativePointer<TADDR> m_pCanonMT;
3950#else
3951 PlainPointer<DPTR(EEClass)> m_pEEClass;
3952 PlainPointer<TADDR> m_pCanonMT;
3953#endif
3954 };
3955
3956 __forceinline static LowBits union_getLowBits(TADDR pCanonMT)
3957 {
3958 LIMITED_METHOD_DAC_CONTRACT;
3959 return LowBits(pCanonMT & UNION_MASK);
3960 }
3961 __forceinline static TADDR union_getPointer(TADDR pCanonMT)
3962 {
3963 LIMITED_METHOD_DAC_CONTRACT;
3964 return (pCanonMT & ~UNION_MASK);
3965 }
3966
3967 // m_pPerInstInfo and m_pInterfaceMap have to be at fixed offsets because of performance sensitive
3968 // JITed code and JIT helpers. However, they are frequently not present. The space is used by other
3969 // multipurpose slots on first come first served basis if the fixed ones are not present. The other
3970 // multipurpose are DispatchMapSlot, NonVirtualSlots, ModuleOverride (see enum_flag_MultipurposeSlotsMask).
3971 // The multipurpose slots that do not fit are stored after vtable slots.
3972
3973 union
3974 {
3975 PerInstInfo_t m_pPerInstInfo;
3976 TADDR m_ElementTypeHnd;
3977 TADDR m_pMultipurposeSlot1;
3978 };
3979 public:
3980 union
3981 {
3982#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
3983 RelativePointer<PTR_InterfaceInfo> m_pInterfaceMap;
3984#else
3985 PlainPointer<PTR_InterfaceInfo> m_pInterfaceMap;
3986#endif
3987 TADDR m_pMultipurposeSlot2;
3988 };
3989
3990 // VTable and Non-Virtual slots go here
3991
3992 // Overflow multipurpose slots go here
3993
3994 // Optional Members go here
3995 // See above for the list of optional members
3996
3997 // Generic dictionary pointers go here
3998
3999 // Interface map goes here
4000
4001 // Generic instantiation+dictionary goes here
4002
4003private:
4004
4005 // disallow direct creation
4006 void *operator new(size_t dummy);
4007 void operator delete(void *pData);
4008 MethodTable();
4009
4010 // Optional members. These are used for fields in the data structure where
4011 // the fields are (a) known when MT is created and (b) there is a default
4012 // value for the field in the common case. That is, they are normally used
4013 // for data that is only relevant to a small number of method tables.
4014
4015 // Optional members and multipurpose slots have similar purpose, but they differ in details:
4016 // - Multipurpose slots can only accomodate pointer sized structures right now. It is non-trivial
4017 // to add new ones, the access is faster.
4018 // - Optional members can accomodate structures of any size. It is trivial to add new ones,
4019 // the access is slower.
4020
4021 // The following macro will automatically create GetXXX accessors for the optional members.
4022#define METHODTABLE_OPTIONAL_MEMBERS() \
4023 /* NAME TYPE GETTER */ \
4024 /* Accessing this member efficiently is currently performance critical for static field accesses */ \
4025 /* in generic classes, so place it early in the list. */ \
4026 METHODTABLE_OPTIONAL_MEMBER(GenericsStaticsInfo, GenericsStaticsInfo, GetGenericsStaticsInfo ) \
4027 /* Accessed by interop, fairly frequently. */ \
4028 METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS() \
4029 /* Accessed during x-domain transition only, so place it late in the list. */ \
4030 METHODTABLE_REMOTING_OPTIONAL_MEMBERS() \
4031 /* Accessed during certain generic type load operations only, so low priority */ \
4032 METHODTABLE_OPTIONAL_MEMBER(ExtraInterfaceInfo, TADDR, GetExtraInterfaceInfoPtr ) \
4033 /* TypeDef token for assemblies with more than 64k types. Never happens in real world. */ \
4034 METHODTABLE_OPTIONAL_MEMBER(TokenOverflow, TADDR, GetTokenOverflowPtr ) \
4035
4036#ifdef FEATURE_COMINTEROP
4037#define METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS() \
4038 METHODTABLE_OPTIONAL_MEMBER(GuidInfo, PTR_GuidInfo, GetGuidInfoPtr ) \
4039 METHODTABLE_OPTIONAL_MEMBER(RCWPerTypeData, RCWPerTypeData *, GetRCWPerTypeDataPtr ) \
4040 METHODTABLE_OPTIONAL_MEMBER(CCWTemplate, ComCallWrapperTemplate *, GetCCWTemplatePtr )
4041#else
4042#define METHODTABLE_COMINTEROP_OPTIONAL_MEMBERS()
4043#endif
4044
4045#define METHODTABLE_REMOTING_OPTIONAL_MEMBERS()
4046
4047 enum OptionalMemberId
4048 {
4049#undef METHODTABLE_OPTIONAL_MEMBER
4050#define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) OptionalMember_##NAME,
4051 METHODTABLE_OPTIONAL_MEMBERS()
4052 OptionalMember_Count,
4053
4054 OptionalMember_First = OptionalMember_GenericsStaticsInfo,
4055 };
4056
4057 FORCEINLINE DWORD GetOffsetOfOptionalMember(OptionalMemberId id);
4058
4059public:
4060
4061 //
4062 // Public accessor helpers for the optional members of MethodTable
4063 //
4064
4065#undef METHODTABLE_OPTIONAL_MEMBER
4066#define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \
4067 inline DPTR(TYPE) GETTER() \
4068 { \
4069 LIMITED_METHOD_CONTRACT; \
4070 STATIC_CONTRACT_SO_TOLERANT; \
4071 _ASSERTE(Has##NAME()); \
4072 return dac_cast<DPTR(TYPE)>(dac_cast<TADDR>(this) + GetOffsetOfOptionalMember(OptionalMember_##NAME)); \
4073 }
4074
4075 METHODTABLE_OPTIONAL_MEMBERS()
4076
4077private:
4078 inline DWORD GetStartOffsetOfOptionalMembers()
4079 {
4080 WRAPPER_NO_CONTRACT;
4081 return GetOffsetOfOptionalMember(OptionalMember_First);
4082 }
4083
4084 inline DWORD GetEndOffsetOfOptionalMembers()
4085 {
4086 WRAPPER_NO_CONTRACT;
4087 return GetOffsetOfOptionalMember(OptionalMember_Count);
4088 }
4089
4090 inline static DWORD GetOptionalMembersAllocationSize(
4091 DWORD dwMultipurposeSlotsMask,
4092 BOOL needsGenericsStaticsInfo,
4093 BOOL needsGuidInfo,
4094 BOOL needsCCWTemplate,
4095 BOOL needsRCWPerTypeData,
4096 BOOL needsTokenOverflow);
4097 inline DWORD GetOptionalMembersSize();
4098
4099 // The PerInstInfo is a (possibly empty) array of pointers to
4100 // Instantiations/Dictionaries. This array comes after the optional members.
4101 inline DWORD GetPerInstInfoSize();
4102
4103 // This is the size of the interface map chunk in the method table.
4104 // If the MethodTable has a dynamic interface map then the size includes the pointer
4105 // that stores the extra info for that map.
4106 // The interface map itself comes after the PerInstInfo (if any)
4107 inline DWORD GetInterfaceMapSize();
4108
4109 // The instantiation/dictionary comes at the end of the MethodTable after
4110 // the interface map.
4111 inline DWORD GetInstAndDictSize();
4112
4113private:
4114 // Helper template to compute the offsets at compile time
4115 template<int mask>
4116 struct MultipurposeSlotOffset;
4117
4118 static const BYTE c_DispatchMapSlotOffsets[];
4119 static const BYTE c_NonVirtualSlotsOffsets[];
4120 static const BYTE c_ModuleOverrideOffsets[];
4121
4122 static const BYTE c_OptionalMembersStartOffsets[]; // total sizes of optional slots
4123
4124 TADDR GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const BYTE * offsets);
4125
4126 void SetMultipurposeSlotsMask(DWORD dwMask)
4127 {
4128 LIMITED_METHOD_CONTRACT;
4129 _ASSERTE((m_wFlags2 & enum_flag_MultipurposeSlotsMask) == 0);
4130 m_wFlags2 |= (WORD)dwMask;
4131 }
4132
4133 BOOL HasModuleOverride()
4134 {
4135 LIMITED_METHOD_DAC_CONTRACT;
4136 return GetFlag(enum_flag_HasModuleOverride);
4137 }
4138
4139 DPTR(RelativeFixupPointer<PTR_Module>) GetModuleOverridePtr()
4140 {
4141 LIMITED_METHOD_DAC_CONTRACT;
4142 return dac_cast<DPTR(RelativeFixupPointer<PTR_Module>)>(GetMultipurposeSlotPtr(enum_flag_HasModuleOverride, c_ModuleOverrideOffsets));
4143 }
4144
4145 void SetModule(Module * pModule);
4146
4147public:
4148
4149 BOOL Validate ();
4150
4151#ifdef FEATURE_READYTORUN_COMPILER
4152 //
4153 // Is field layout in this type fixed within the current version bubble?
4154 // This check does not take the inheritance chain into account.
4155 //
4156 BOOL IsLayoutFixedInCurrentVersionBubble();
4157
4158 //
4159 // Is field layout of the inheritance chain fixed within the current version bubble?
4160 //
4161 BOOL IsInheritanceChainLayoutFixedInCurrentVersionBubble();
4162
4163 //
4164 // Is the inheritance chain fixed within the current version bubble?
4165 //
4166 BOOL IsInheritanceChainFixedInCurrentVersionBubble();
4167#endif
4168
4169}; // class MethodTable
4170
4171#ifndef CROSSBITNESS_COMPILE
4172static_assert_no_msg(sizeof(MethodTable) == SIZEOF__MethodTable_);
4173#endif
4174#if defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
4175WORD GetEquivalentMethodSlot(MethodTable * pOldMT, MethodTable * pNewMT, WORD wMTslot, BOOL *pfFound);
4176#endif // defined(FEATURE_TYPEEQUIVALENCE) && !defined(DACCESS_COMPILE)
4177
4178MethodTable* CreateMinimalMethodTable(Module* pContainingModule,
4179 LoaderHeap* pCreationHeap,
4180 AllocMemTracker* pamTracker);
4181
4182#endif // !_METHODTABLE_H_
4183