Remove relocations for vtable chunks (#17147)
[platform/upstream/coreclr.git] / src / vm / methodtable.inl
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.inl
6 //
7
8
9 //
10
11 //
12 // ============================================================================
13
14 #ifndef _METHODTABLE_INL_ 
15 #define _METHODTABLE_INL_
16
17 #include "methodtable.h"
18 #include "genericdict.h"
19 #include "threadstatics.h"
20
21 //==========================================================================================
22 inline PTR_EEClass MethodTable::GetClass_NoLogging()
23 {
24     LIMITED_METHOD_DAC_CONTRACT;
25
26     TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT);
27
28 #ifdef _DEBUG 
29     LowBits lowBits = union_getLowBits(addr);
30     if (lowBits == UNION_EECLASS)
31     {
32         return PTR_EEClass(addr);
33     }
34     else if (lowBits == UNION_METHODTABLE)
35     {
36         // pointer to canonical MethodTable.
37         TADDR canonicalMethodTable = union_getPointer(addr);
38         return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT));
39     }
40 #ifdef FEATURE_PREJIT
41     else if (lowBits == UNION_INDIRECTION)
42     {
43         // pointer to indirection cell that points to canonical MethodTable
44         TADDR canonicalMethodTable = *PTR_TADDR(union_getPointer(addr));
45         return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT));
46     }
47 #endif
48 #ifdef DACCESS_COMPILE
49     // Minidumps don't guarantee that every member of every class will be able to work here.
50 #else
51     _ASSERTE(!"Malformed m_pEEClass in MethodTable");
52 #endif
53     return NULL;
54
55 #else
56
57     if ((addr & 2) == 0)
58     {
59         // pointer to EEClass
60         return PTR_EEClass(addr);
61     }
62
63 #ifdef FEATURE_PREJIT
64     if ((addr & 1) != 0)
65     {
66         // pointer to indirection cell that points to canonical MethodTable
67         TADDR canonicalMethodTable = *PTR_TADDR(addr - 3);
68         return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT));
69     }
70 #endif
71
72     // pointer to canonical MethodTable.
73     return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(addr - 2), &MethodTable::m_pCanonMT));
74 #endif
75 }
76
77 //==========================================================================================
78 inline PTR_EEClass MethodTable::GetClass()
79 {
80     LIMITED_METHOD_DAC_CONTRACT;
81
82     _ASSERTE_IMPL(!IsAsyncPinType());
83     _ASSERTE_IMPL(GetClass_NoLogging() != NULL);
84
85     g_IBCLogger.LogEEClassAndMethodTableAccess(this);
86     return GetClass_NoLogging();
87 }
88
89 //==========================================================================================
90 inline Assembly * MethodTable::GetAssembly()
91 {
92     WRAPPER_NO_CONTRACT;
93     return GetModule()->GetAssembly();
94 }
95
96 //==========================================================================================
97 // DO NOT ADD ANY ASSERTS OR ANY OTHER CODE TO THIS METHOD.
98 // DO NOT USE THIS METHOD.
99 // Yes folks, for better or worse the debugger pokes supposed object addresses
100 // to try to see if objects are valid, possibly firing an AccessViolation or
101 // worse.  Thus it is "correct" behaviour for this to AV, and incorrect
102 // behaviour for it to assert if called on an invalid pointer.
103 inline PTR_EEClass MethodTable::GetClassWithPossibleAV()
104 {
105     CANNOT_HAVE_CONTRACT;
106     SUPPORTS_DAC;
107     return GetClass_NoLogging();
108 }
109
110 //==========================================================================================
111 inline BOOL MethodTable::IsClassPointerValid()
112 {
113     WRAPPER_NO_CONTRACT;
114     SUPPORTS_DAC;
115
116     TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT);
117
118     LowBits lowBits = union_getLowBits(addr);
119     if (lowBits == UNION_EECLASS)
120     {
121         return !m_pEEClass.IsNull();
122     }
123     else if (lowBits == UNION_METHODTABLE)
124     {
125         // pointer to canonical MethodTable.
126         TADDR canonicalMethodTable = union_getPointer(addr);
127         return !PTR_MethodTable(canonicalMethodTable)->m_pEEClass.IsNull();
128     }
129 #ifdef FEATURE_PREJIT
130     else if (lowBits == UNION_INDIRECTION)
131     {
132         // pointer to indirection cell that points to canonical MethodTable
133         TADDR canonicalMethodTable = *PTR_TADDR(union_getPointer(addr));
134         if (CORCOMPILE_IS_POINTER_TAGGED(canonicalMethodTable))
135             return FALSE;
136         return !PTR_MethodTable(canonicalMethodTable)->m_pEEClass.IsNull();
137     }
138 #endif
139     _ASSERTE(!"Malformed m_pEEClass in MethodTable");
140     return FALSE;
141 }
142
143 //==========================================================================================
144 // Does this immediate item live in an NGEN module?
145 inline BOOL MethodTable::IsZapped()
146 {
147     LIMITED_METHOD_DAC_CONTRACT;
148
149 #ifdef FEATURE_PREJIT
150     return GetFlag(enum_flag_IsZapped);
151 #else
152     return FALSE;
153 #endif
154 }
155
156 //==========================================================================================
157 // For types that are part of an ngen-ed assembly this gets the
158 // Module* that contains this methodtable.
159 inline PTR_Module MethodTable::GetZapModule()
160 {
161     LIMITED_METHOD_DAC_CONTRACT;
162
163     PTR_Module zapModule = NULL;
164     if (IsZapped())
165     {
166         zapModule = ReadPointer(this, &MethodTable::m_pLoaderModule);
167     }
168
169     return zapModule;
170 }
171
172 //==========================================================================================
173 inline PTR_Module MethodTable::GetLoaderModule() 
174 {
175     LIMITED_METHOD_DAC_CONTRACT;
176     return ReadPointer(this, &MethodTable::m_pLoaderModule);
177 }
178
179 inline PTR_LoaderAllocator MethodTable::GetLoaderAllocator() 
180 {
181     LIMITED_METHOD_DAC_CONTRACT;
182     return GetLoaderModule()->GetLoaderAllocator();
183 }
184
185
186
187 #ifndef DACCESS_COMPILE 
188 //==========================================================================================
189 inline void MethodTable::SetLoaderModule(Module* pModule) 
190 {
191     WRAPPER_NO_CONTRACT;
192     m_pLoaderModule.SetValue(pModule);
193 }
194
195 inline void MethodTable::SetLoaderAllocator(LoaderAllocator* pAllocator) 
196 {
197     LIMITED_METHOD_CONTRACT;
198     _ASSERTE(pAllocator == GetLoaderAllocator());
199
200     if (pAllocator->Id()->IsCollectible())
201     {
202         SetFlag(enum_flag_Collectible);
203     }
204 }
205
206 #endif
207
208 //==========================================================================================
209 inline WORD MethodTable::GetNumNonVirtualSlots()
210 {
211     LIMITED_METHOD_DAC_CONTRACT;
212     return HasNonVirtualSlots() ? GetClass()->GetNumNonVirtualSlots() : 0;
213 }        
214
215 //==========================================================================================
216 inline WORD MethodTable::GetNumInstanceFields()
217 {
218     WRAPPER_NO_CONTRACT;
219     return (GetClass()->GetNumInstanceFields());
220 }
221
222 //==========================================================================================
223 inline WORD MethodTable::GetNumStaticFields()
224 {
225     LIMITED_METHOD_DAC_CONTRACT;
226     return (GetClass()->GetNumStaticFields());
227 }
228
229 //==========================================================================================
230 inline WORD MethodTable::GetNumThreadStaticFields()
231 {
232     LIMITED_METHOD_DAC_CONTRACT;
233     return (GetClass()->GetNumThreadStaticFields());
234 }
235
236 //==========================================================================================
237 inline DWORD MethodTable::GetNumInstanceFieldBytes()
238 {
239     LIMITED_METHOD_DAC_CONTRACT;
240     return(GetBaseSize() - GetClass()->GetBaseSizePadding());
241 }
242
243 //==========================================================================================
244 inline WORD MethodTable::GetNumIntroducedInstanceFields()
245 {
246     LIMITED_METHOD_DAC_CONTRACT;
247
248     WORD wNumFields = GetNumInstanceFields();
249
250     MethodTable * pParentMT = GetParentMethodTable();
251     if (pParentMT != NULL)
252     {
253         WORD wNumParentFields = pParentMT->GetNumInstanceFields();
254
255         // If this assert fires, then our bookkeeping is bad. Perhaps we incremented the count
256         // of fields on the base class w/o incrementing the count in the derived class. (EnC scenarios).
257         _ASSERTE(wNumFields >= wNumParentFields);
258
259         wNumFields -= wNumParentFields;
260     }
261
262     return(wNumFields);
263 }
264
265 //==========================================================================================
266 inline DWORD MethodTable::GetAlignedNumInstanceFieldBytes()
267 {
268     WRAPPER_NO_CONTRACT;
269     return((GetNumInstanceFieldBytes() + 3) & (~3));
270 }
271
272 //==========================================================================================
273 inline PTR_FieldDesc MethodTable::GetApproxFieldDescListRaw()
274 {
275     WRAPPER_NO_CONTRACT;
276     // Careful about using this method. If it's possible that fields may have been added via EnC, then
277     // must use the FieldDescIterator as any fields added via EnC won't be in the raw list
278
279     return GetClass()->GetFieldDescList();
280 }
281
282 #ifdef FEATURE_COMINTEROP
283 //==========================================================================================
284 inline DWORD MethodTable::IsComClassInterface()
285 {
286     WRAPPER_NO_CONTRACT;
287     return GetClass()->IsComClassInterface();
288 }
289
290 //==========================================================================================
291 inline DWORD MethodTable::IsComImport()
292 {
293     WRAPPER_NO_CONTRACT;
294     return GetClass()->IsComImport();
295 }
296
297 //==========================================================================================
298 // Sparse VTables.   These require a SparseVTableMap in the EEClass in
299 // order to record how the CLR's vtable slots map across to COM
300 // Interop slots.
301 //
302 inline int MethodTable::IsSparseForCOMInterop()
303 {
304     WRAPPER_NO_CONTRACT;
305     return GetClass()->IsSparseForCOMInterop();
306 }
307
308 //==========================================================================================
309 inline int MethodTable::IsComEventItfType()
310 {
311     WRAPPER_NO_CONTRACT;
312     _ASSERTE(GetClass());
313     return GetClass()->IsComEventItfType();
314 }
315
316 #endif // FEATURE_COMINTEROP
317
318 //==========================================================================================
319 inline DWORD MethodTable::GetAttrClass()
320 {
321     WRAPPER_NO_CONTRACT;
322     return GetClass()->GetAttrClass();
323 }
324
325 //==========================================================================================
326 inline BOOL MethodTable::IsSerializable()
327 {
328     WRAPPER_NO_CONTRACT;
329     return GetClass()->IsSerializable();
330 }
331
332 //==========================================================================================
333 inline BOOL MethodTable::SupportsGenericInterop(TypeHandle::InteropKind interopKind,
334                         MethodTable::Mode mode /*= modeAll*/)
335 {
336     LIMITED_METHOD_CONTRACT;
337
338 #ifdef FEATURE_COMINTEROP
339     return ((IsInterface() || IsDelegate()) &&    // interface or delegate
340             HasInstantiation() &&                 // generic
341             !IsSharedByGenericInstantiations() && // unshared
342             !ContainsGenericVariables() &&        // closed over concrete types
343             // defined in .winmd or one of the redirected mscorlib interfaces
344             ((((mode & modeProjected) != 0) && IsProjectedFromWinRT()) ||
345              (((mode & modeRedirected) != 0) && (IsWinRTRedirectedInterface(interopKind) || IsWinRTRedirectedDelegate()))));
346 #else // FEATURE_COMINTEROP
347     return FALSE;
348 #endif // FEATURE_COMINTEROP
349 }
350
351
352 //==========================================================================================
353 inline BOOL MethodTable::IsNotTightlyPacked()
354 {
355     WRAPPER_NO_CONTRACT;
356     return GetClass()->IsNotTightlyPacked();
357 }
358
359 //==========================================================================================
360 inline BOOL MethodTable::HasFieldsWhichMustBeInited()
361 {
362     WRAPPER_NO_CONTRACT;
363     return GetClass()->HasFieldsWhichMustBeInited();
364 }
365
366 //==========================================================================================
367 inline BOOL MethodTable::SupportsAutoNGen()
368 {
369     LIMITED_METHOD_CONTRACT;
370     return FALSE;
371 }
372
373 //==========================================================================================
374 inline BOOL MethodTable::RunCCTorAsIfNGenImageExists()
375 {
376     LIMITED_METHOD_CONTRACT;
377 #ifdef FEATURE_CORESYSTEM
378     return TRUE; // On our coresystem builds we will always be using triton in the customer scenario.
379 #else
380     return FALSE;
381 #endif
382 }
383
384 //==========================================================================================
385 inline BOOL MethodTable::IsAbstract()
386 {
387     WRAPPER_NO_CONTRACT;
388     return GetClass()->IsAbstract();
389 }
390
391 //==========================================================================================
392
393 #ifdef FEATURE_COMINTEROP
394 //==========================================================================================
395 inline void MethodTable::SetHasGuidInfo()
396 {
397     LIMITED_METHOD_CONTRACT;
398     _ASSERTE(IsInterface() || (HasCCWTemplate() && IsDelegate()));
399
400     // for delegates, having CCW template implies having GUID info
401     if (IsInterface())
402         SetFlag(enum_flag_IfInterfaceThenHasGuidInfo);
403 }
404
405 //==========================================================================================
406 inline BOOL MethodTable::HasGuidInfo()
407 {
408     LIMITED_METHOD_DAC_CONTRACT;
409
410     if (IsInterface())
411         return GetFlag(enum_flag_IfInterfaceThenHasGuidInfo);
412
413     // HasCCWTemplate() is intentionally checked first here to avoid hitting 
414     // g_pMulticastDelegateClass == NULL inside IsDelegate() during startup
415     return HasCCWTemplate() && IsDelegate();
416 }
417
418 //==========================================================================================
419 // True IFF the type has a GUID explicitly assigned to it (including WinRT generic interfaces
420 // where the GUID is computed).
421 inline BOOL MethodTable::HasExplicitGuid()
422 {
423     CONTRACTL {
424         THROWS;
425         GC_TRIGGERS;
426         MODE_ANY;
427         SUPPORTS_DAC;
428     } CONTRACTL_END;
429
430     GUID guid;
431     GetGuid(&guid, FALSE);
432     return (guid != GUID_NULL);
433 }
434
435 //==========================================================================================
436 inline void MethodTable::SetHasCCWTemplate()
437 {
438     LIMITED_METHOD_CONTRACT;
439     SetFlag(enum_flag_HasCCWTemplate);
440 }
441
442 //==========================================================================================
443 inline BOOL MethodTable::HasCCWTemplate()
444 {
445     LIMITED_METHOD_DAC_CONTRACT;
446     return GetFlag(enum_flag_HasCCWTemplate);
447 }
448
449 //==========================================================================================
450 inline void MethodTable::SetHasRCWPerTypeData()
451 {
452     LIMITED_METHOD_CONTRACT;
453     SetFlag(enum_flag_HasRCWPerTypeData);
454 }
455
456 //==========================================================================================
457 inline BOOL MethodTable::HasRCWPerTypeData()
458 {
459     LIMITED_METHOD_DAC_CONTRACT;
460     return GetFlag(enum_flag_HasRCWPerTypeData);
461 }
462
463 //==========================================================================================
464 // Get the GUID used for WinRT interop
465 //   * if the type is not a WinRT type or a redirected interfae return FALSE
466 inline BOOL MethodTable::GetGuidForWinRT(GUID *pGuid)
467 {
468     CONTRACTL {
469         THROWS;
470         GC_TRIGGERS;
471         MODE_ANY;
472         SUPPORTS_DAC;
473     } CONTRACTL_END;
474
475     BOOL bRes = FALSE;
476     if ((IsProjectedFromWinRT() && !HasInstantiation()) || 
477         (SupportsGenericInterop(TypeHandle::Interop_NativeToManaged) && IsLegalNonArrayWinRTType()))
478     {
479         bRes = SUCCEEDED(GetGuidNoThrow(pGuid, TRUE, FALSE));
480     }
481
482     return bRes;
483 }
484
485
486 #endif // FEATURE_COMINTEROP
487
488 //==========================================================================================
489 // The following two methods produce correct results only if this type is
490 // marked Serializable (verified by assert in checked builds) and the field
491 // in question was introduced in this type (the index is the FieldDesc
492 // index).
493 inline BOOL MethodTable::IsFieldNotSerialized(DWORD dwFieldIndex)
494 {
495     LIMITED_METHOD_CONTRACT;
496     _ASSERTE(IsSerializable());
497     return FALSE;
498 }
499
500 //==========================================================================================
501 inline BOOL MethodTable::IsFieldOptionallySerialized(DWORD dwFieldIndex)
502 {
503     LIMITED_METHOD_CONTRACT;
504     _ASSERTE(IsSerializable());
505     return FALSE;
506 }
507
508 //==========================================================================================
509 // Is pParentMT System.Enum? (Cannot be called before System.Enum is loaded.)
510 inline BOOL MethodTable::IsEnum()
511 {
512     LIMITED_METHOD_DAC_CONTRACT;
513
514     // We should not be calling this before our parent method table pointer
515     // is valid .
516     _ASSERTE_IMPL(IsParentMethodTablePointerValid());
517
518     PTR_MethodTable pParentMT = GetParentMethodTable();
519
520     // Make sure that we are not using this method during startup
521     _ASSERTE(g_pEnumClass != NULL);
522
523     return (pParentMT == g_pEnumClass);
524 }
525
526 //==========================================================================================
527 // Is pParentMT either System.ValueType or System.Enum?
528 inline BOOL MethodTable::IsValueType()
529 {
530     LIMITED_METHOD_DAC_CONTRACT;
531
532     g_IBCLogger.LogMethodTableAccess(this);
533
534     return GetFlag(enum_flag_Category_ValueType_Mask) == enum_flag_Category_ValueType;
535 }
536
537 //==========================================================================================
538 inline CorElementType MethodTable::GetArrayElementType()
539 {
540     WRAPPER_NO_CONTRACT;
541
542     _ASSERTE (IsArray());
543     return dac_cast<PTR_ArrayClass>(GetClass())->GetArrayElementType();
544 }
545
546 //==========================================================================================
547 inline DWORD MethodTable::GetRank()
548 {
549     LIMITED_METHOD_DAC_CONTRACT;
550
551     _ASSERTE (IsArray());
552     if (GetFlag(enum_flag_Category_IfArrayThenSzArray))
553         return 1;  // ELEMENT_TYPE_SZARRAY
554     else
555         return dac_cast<PTR_ArrayClass>(GetClass())->GetRank();
556 }
557
558 //==========================================================================================
559 inline BOOL MethodTable::IsTruePrimitive()
560 {
561     LIMITED_METHOD_DAC_CONTRACT;
562     return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_TruePrimitive;
563 }
564
565 //==========================================================================================
566 inline void MethodTable::SetIsTruePrimitive()
567 {
568     LIMITED_METHOD_DAC_CONTRACT;
569     SetFlag(enum_flag_Category_TruePrimitive);
570 }
571
572 //==========================================================================================
573 inline BOOL MethodTable::IsBlittable()
574 {
575     WRAPPER_NO_CONTRACT;
576 #ifndef DACCESS_COMPILE 
577     _ASSERTE(GetClass());
578     return GetClass()->IsBlittable();
579 #else // DACCESS_COMPILE
580     DacNotImpl();
581     return false;
582 #endif // DACCESS_COMPILE
583 }
584
585 //==========================================================================================
586 inline BOOL MethodTable::HasClassConstructor()
587 {
588     WRAPPER_NO_CONTRACT;
589     return GetFlag(enum_flag_HasCctor);
590 }
591
592 //==========================================================================================
593 inline void MethodTable::SetHasClassConstructor()
594 {
595     WRAPPER_NO_CONTRACT;
596     return SetFlag(enum_flag_HasCctor);
597 }
598
599 //==========================================================================================
600 inline WORD MethodTable::GetClassConstructorSlot()
601 {
602     WRAPPER_NO_CONTRACT;
603     _ASSERTE(HasClassConstructor());
604
605     // The class constructor slot is the first non-vtable slot
606     return GetNumVirtuals();
607 }
608
609 //==========================================================================================
610 inline BOOL MethodTable::HasDefaultConstructor()
611 {
612     WRAPPER_NO_CONTRACT;
613     return GetFlag(enum_flag_HasDefaultCtor);
614 }
615
616 //==========================================================================================
617 inline void MethodTable::SetHasDefaultConstructor()
618 {
619     WRAPPER_NO_CONTRACT;
620     return SetFlag(enum_flag_HasDefaultCtor);
621 }
622
623 //==========================================================================================
624 inline WORD MethodTable::GetDefaultConstructorSlot()
625 {
626     WRAPPER_NO_CONTRACT;
627     _ASSERTE(HasDefaultConstructor());
628
629     // The default ctor slot is right after cctor slot if there is one
630     return GetNumVirtuals() + (HasClassConstructor() ? 1 : 0);
631 }
632
633 //==========================================================================================
634 inline BOOL MethodTable::HasLayout()
635 {
636     WRAPPER_NO_CONTRACT;
637     _ASSERTE(GetClass());
638     return GetClass()->HasLayout();
639 }
640
641 //==========================================================================================
642 inline MethodDesc* MethodTable::GetMethodDescForSlot(DWORD slot)
643 {
644     CONTRACTL
645     {
646         NOTHROW;
647         GC_NOTRIGGER;
648         SO_TOLERANT;
649         MODE_ANY;
650     }
651     CONTRACTL_END;
652
653     PCODE pCode = GetRestoredSlot(slot);
654
655     // This is an optimization that we can take advantage of if we're trying to get the MethodDesc 
656     // for an interface virtual, since their slots usually point to stub.
657     if (IsInterface() && slot < GetNumVirtuals())
658     {
659         return MethodDesc::GetMethodDescFromStubAddr(pCode);
660     }
661
662     return MethodTable::GetMethodDescForSlotAddress(pCode);
663 }
664
665 #ifndef DACCESS_COMPILE 
666
667 //==========================================================================================
668 inline INT32 MethodTable::MethodIterator::GetNumMethods() const
669 {
670     LIMITED_METHOD_CONTRACT;
671     //  assert that number of methods hasn't changed during the iteration
672     CONSISTENCY_CHECK( m_pMethodData->GetNumMethods() == static_cast< UINT32 >( m_iMethods ) );
673     return m_iMethods;
674 }
675
676 //==========================================================================================
677 // Returns TRUE if it's valid to request data from the current position
678 inline BOOL MethodTable::MethodIterator::IsValid() const
679 {
680     LIMITED_METHOD_CONTRACT;
681     return m_iCur >= 0 && m_iCur < GetNumMethods();
682 }
683
684 //==========================================================================================
685 inline BOOL MethodTable::MethodIterator::MoveTo(UINT32 idx)
686 {
687     LIMITED_METHOD_CONTRACT;
688     m_iCur = (INT32)idx;
689     return IsValid();
690 }
691
692 //==========================================================================================
693 inline BOOL MethodTable::MethodIterator::Prev()
694 {
695     WRAPPER_NO_CONTRACT;
696     if (IsValid())
697         --m_iCur;
698     return (IsValid());
699 }
700
701 //==========================================================================================
702 inline BOOL MethodTable::MethodIterator::Next()
703 {
704     WRAPPER_NO_CONTRACT;
705     if (IsValid())
706         ++m_iCur;
707     return (IsValid());
708 }
709
710 //==========================================================================================
711 inline void MethodTable::MethodIterator::MoveToBegin()
712 {
713     WRAPPER_NO_CONTRACT;
714     m_iCur = 0;
715 }
716
717 //==========================================================================================
718 inline void MethodTable::MethodIterator::MoveToEnd()
719 {
720     WRAPPER_NO_CONTRACT;
721     m_iCur = GetNumMethods() - 1;
722 }
723
724 //==========================================================================================
725 inline UINT32 MethodTable::MethodIterator::GetSlotNumber() const {
726     LIMITED_METHOD_CONTRACT;
727     CONSISTENCY_CHECK(IsValid());
728     return (UINT32)m_iCur;
729 }
730
731 //==========================================================================================
732 inline UINT32 MethodTable::MethodIterator::GetImplSlotNumber() const {
733     WRAPPER_NO_CONTRACT;
734     CONSISTENCY_CHECK(IsValid());
735     return (UINT32)m_pMethodData->GetImplSlotNumber(m_iCur);
736 }
737
738 //==========================================================================================
739 inline BOOL MethodTable::MethodIterator::IsVirtual() const {
740     LIMITED_METHOD_CONTRACT;
741     CONSISTENCY_CHECK(IsValid());
742     return m_iCur < (INT32)(GetNumVirtuals());
743 }
744
745 //==========================================================================================
746 inline UINT32 MethodTable::MethodIterator::GetNumVirtuals() const {
747     LIMITED_METHOD_CONTRACT;
748     return m_pMethodData->GetNumVirtuals();;
749 }
750
751 //==========================================================================================
752 inline DispatchSlot MethodTable::MethodIterator::GetTarget() const {
753     LIMITED_METHOD_CONTRACT;
754     CONSISTENCY_CHECK(IsValid());
755     return m_pMethodData->GetImplSlot(m_iCur);
756 }
757
758 //==========================================================================================
759 inline MethodDesc *MethodTable::MethodIterator::GetMethodDesc() const {
760     LIMITED_METHOD_CONTRACT;
761     CONSISTENCY_CHECK(IsValid());
762     MethodDesc *pMD = m_pMethodData->GetImplMethodDesc(m_iCur);
763     CONSISTENCY_CHECK(CheckPointer(pMD));
764     return pMD;
765 }
766
767 //==========================================================================================
768 inline MethodDesc *MethodTable::MethodIterator::GetDeclMethodDesc() const {
769     LIMITED_METHOD_CONTRACT;
770     CONSISTENCY_CHECK(IsValid());
771     MethodDesc *pMD = m_pMethodData->GetDeclMethodDesc(m_iCur);
772     CONSISTENCY_CHECK(CheckPointer(pMD));
773     CONSISTENCY_CHECK(pMD->GetSlot() == GetSlotNumber());
774     return pMD;
775 }
776
777 #endif // DACCESS_COMPILE 
778
779 //==========================================================================================
780 // Non-canonical types share the method bodies with the canonical type. So the canonical
781 // type can be said to own the method bodies. Hence, by default, IntroducedMethodIterator
782 // only lets you iterate methods of the canonical type. You have to pass in
783 // restrictToCanonicalTypes=FALSE to iterate methods through a non-canonical type.
784
785 inline MethodTable::IntroducedMethodIterator::IntroducedMethodIterator(
786         MethodTable *pMT, 
787         BOOL restrictToCanonicalTypes /* = TRUE */ )
788 {
789     WRAPPER_NO_CONTRACT;
790     CONSISTENCY_CHECK(pMT->IsCanonicalMethodTable() || !restrictToCanonicalTypes);
791
792     SetChunk(pMT->GetClass()->GetChunks());
793 }
794
795 //==========================================================================================
796 FORCEINLINE BOOL MethodTable::IntroducedMethodIterator::Next()
797 {
798     WRAPPER_NO_CONTRACT;
799     CONSISTENCY_CHECK(IsValid());
800
801     // Check whether the next MethodDesc is still within the bounds of the current chunk
802     TADDR pNext = dac_cast<TADDR>(m_pMethodDesc) + m_pMethodDesc->SizeOf();
803
804     if (pNext < m_pChunkEnd)
805     {
806         // Just skip to the next method in the same chunk
807         m_pMethodDesc = PTR_MethodDesc(pNext);
808     }
809     else
810     {
811         _ASSERTE(pNext == m_pChunkEnd);
812
813         // We have walked all the methods in the current chunk. Move on
814         // to the next chunk.
815         SetChunk(m_pChunk->GetNextChunk());
816     }
817
818     return IsValid();
819 }
820
821 //==========================================================================================
822 inline BOOL MethodTable::IntroducedMethodIterator::IsValid() const
823 {
824     LIMITED_METHOD_CONTRACT;
825     return m_pMethodDesc != NULL;
826 }
827
828 //==========================================================================================
829 inline MethodDesc * MethodTable::IntroducedMethodIterator::GetMethodDesc() const
830 {
831     WRAPPER_NO_CONTRACT;
832     CONSISTENCY_CHECK(IsValid());
833     return m_pMethodDesc;
834 }
835
836 //==========================================================================================
837 inline DWORD MethodTable::GetIndexOfVtableIndirection(DWORD slotNum)
838 {
839     LIMITED_METHOD_DAC_CONTRACT;
840     _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK);
841
842     return slotNum >> VTABLE_SLOTS_PER_CHUNK_LOG2;
843 }
844
845 //==========================================================================================
846 inline DWORD MethodTable::GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals)
847 {
848     LIMITED_METHOD_DAC_CONTRACT;
849     _ASSERTE(indirectionIndex < GetNumVtableIndirections(wNumVirtuals));
850
851     return indirectionIndex * VTABLE_SLOTS_PER_CHUNK;
852 }
853
854 //==========================================================================================
855 inline DWORD MethodTable::GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals)
856 {
857     LIMITED_METHOD_DAC_CONTRACT;
858     _ASSERTE(indirectionIndex < GetNumVtableIndirections(wNumVirtuals));
859
860     DWORD end = (indirectionIndex + 1) * VTABLE_SLOTS_PER_CHUNK;
861
862     if (end > wNumVirtuals)
863     {
864         end = wNumVirtuals;
865     }
866
867     return end;
868 }
869
870 //==========================================================================================
871 inline UINT32 MethodTable::GetIndexAfterVtableIndirection(UINT32 slotNum)
872 {
873     LIMITED_METHOD_DAC_CONTRACT;
874     _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK);
875
876     return (slotNum & (VTABLE_SLOTS_PER_CHUNK - 1));
877 }
878
879 //==========================================================================================
880 inline DWORD MethodTable::GetNumVtableIndirections(DWORD wNumVirtuals)
881 {
882     LIMITED_METHOD_DAC_CONTRACT;
883     _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK);
884
885     return (wNumVirtuals + (VTABLE_SLOTS_PER_CHUNK - 1)) >> VTABLE_SLOTS_PER_CHUNK_LOG2;
886 }
887
888 //==========================================================================================
889 inline DPTR(MethodTable::VTableIndir_t) MethodTable::GetVtableIndirections()
890 {
891     LIMITED_METHOD_DAC_CONTRACT;
892     return dac_cast<DPTR(VTableIndir_t)>(dac_cast<TADDR>(this) + sizeof(MethodTable));
893 }
894
895 //==========================================================================================
896 inline DWORD MethodTable::GetNumVtableIndirections()
897 {
898     WRAPPER_NO_CONTRACT;
899
900     return GetNumVtableIndirections(GetNumVirtuals_NoLogging());
901 }
902
903 //==========================================================================================
904 inline MethodTable::VtableIndirectionSlotIterator::VtableIndirectionSlotIterator(MethodTable *pMT)
905   : m_pSlot(pMT->GetVtableIndirections()),
906     m_i((DWORD) -1),
907     m_count(pMT->GetNumVtableIndirections()),
908     m_pMT(pMT)
909 {
910     WRAPPER_NO_CONTRACT;
911 }
912
913 //==========================================================================================
914 inline MethodTable::VtableIndirectionSlotIterator::VtableIndirectionSlotIterator(MethodTable *pMT, DWORD index)
915   : m_pSlot(pMT->GetVtableIndirections() + index),
916     m_i(index),
917     m_count(pMT->GetNumVtableIndirections()),
918     m_pMT(pMT)
919 {
920     WRAPPER_NO_CONTRACT;
921     PRECONDITION(index != (DWORD) -1 && index < m_count);
922 }
923
924 //==========================================================================================
925 inline BOOL MethodTable::VtableIndirectionSlotIterator::Next()
926 {
927     LIMITED_METHOD_DAC_CONTRACT;
928     PRECONDITION(!Finished());
929     if (m_i != (DWORD) -1)
930         m_pSlot++;
931     return (++m_i < m_count);
932 }
933
934 //==========================================================================================
935 inline BOOL MethodTable::VtableIndirectionSlotIterator::Finished()
936 {
937     LIMITED_METHOD_DAC_CONTRACT;
938     return (m_i == m_count);
939 }
940
941 //==========================================================================================
942 inline DWORD MethodTable::VtableIndirectionSlotIterator::GetIndex()
943 {
944     LIMITED_METHOD_DAC_CONTRACT;
945     return m_i;
946 }
947
948 //==========================================================================================
949 inline DWORD MethodTable::VtableIndirectionSlotIterator::GetOffsetFromMethodTable()
950 {
951     WRAPPER_NO_CONTRACT;
952     PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
953     
954     return GetVtableOffset() + sizeof(VTableIndir_t) * m_i;
955 }
956
957 //==========================================================================================
958 inline DPTR(MethodTable::VTableIndir2_t) MethodTable::VtableIndirectionSlotIterator::GetIndirectionSlot()
959 {
960     LIMITED_METHOD_DAC_CONTRACT;
961     PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
962
963     return m_pSlot->GetValueMaybeNull(dac_cast<TADDR>(m_pSlot));
964 }
965
966 //==========================================================================================
967 #ifndef DACCESS_COMPILE
968 inline void MethodTable::VtableIndirectionSlotIterator::SetIndirectionSlot(DPTR(MethodTable::VTableIndir2_t) pChunk)
969 {
970     LIMITED_METHOD_CONTRACT;
971     m_pSlot->SetValueMaybeNull(pChunk);
972 }
973 #endif
974
975 //==========================================================================================
976 inline DWORD MethodTable::VtableIndirectionSlotIterator::GetStartSlot()
977 {
978     WRAPPER_NO_CONTRACT;
979     PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
980
981     return GetStartSlotForVtableIndirection(m_i, m_pMT->GetNumVirtuals());
982 }
983
984 //==========================================================================================
985 inline DWORD MethodTable::VtableIndirectionSlotIterator::GetEndSlot()
986 {
987     WRAPPER_NO_CONTRACT;
988     PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
989
990     return GetEndSlotForVtableIndirection(m_i, m_pMT->GetNumVirtuals());
991 }
992
993 //==========================================================================================
994 inline DWORD MethodTable::VtableIndirectionSlotIterator::GetNumSlots()
995 {
996     WRAPPER_NO_CONTRACT;
997
998     return GetEndSlot() - GetStartSlot();
999 }
1000
1001 //==========================================================================================
1002 inline DWORD MethodTable::VtableIndirectionSlotIterator::GetSize()
1003 {
1004     WRAPPER_NO_CONTRACT;
1005
1006     return GetNumSlots() * sizeof(PCODE);
1007 }
1008
1009 //==========================================================================================
1010 // Create a new iterator over the vtable indirection slots
1011 // The iterator starts just before the first item
1012 inline MethodTable::VtableIndirectionSlotIterator MethodTable::IterateVtableIndirectionSlots()
1013 {
1014     WRAPPER_NO_CONTRACT;
1015     return VtableIndirectionSlotIterator(this);
1016 }
1017
1018 //==========================================================================================
1019 // Create a new iterator over the vtable indirection slots, starting at the index specified
1020 inline MethodTable::VtableIndirectionSlotIterator MethodTable::IterateVtableIndirectionSlotsFrom(DWORD index)
1021 {
1022     WRAPPER_NO_CONTRACT;
1023     return VtableIndirectionSlotIterator(this, index);
1024 }
1025
1026 #ifndef DACCESS_COMPILE
1027 #ifdef FEATURE_COMINTEROP
1028
1029 //==========================================================================================
1030 inline ComCallWrapperTemplate *MethodTable::GetComCallWrapperTemplate()
1031 {
1032     LIMITED_METHOD_CONTRACT;
1033     if (HasCCWTemplate())
1034     {
1035         return *GetCCWTemplatePtr();
1036     }
1037     return GetClass()->GetComCallWrapperTemplate();
1038 }
1039
1040 //==========================================================================================
1041 inline BOOL MethodTable::SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate)
1042 {
1043     CONTRACTL
1044     {
1045         THROWS;
1046         GC_NOTRIGGER;
1047         MODE_ANY;
1048     }
1049     CONTRACTL_END;
1050
1051     if (HasCCWTemplate())
1052     {
1053         TypeHandle th(this);
1054         g_IBCLogger.LogTypeMethodTableWriteableAccess(&th);
1055         return (InterlockedCompareExchangeT(EnsureWritablePages(GetCCWTemplatePtr()), pTemplate, NULL) == NULL);
1056     }
1057     g_IBCLogger.LogEEClassCOWTableAccess(this);
1058     return GetClass_NoLogging()->SetComCallWrapperTemplate(pTemplate);
1059 }
1060
1061 #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
1062 //==========================================================================================
1063 inline ClassFactoryBase *MethodTable::GetComClassFactory()
1064 {
1065     LIMITED_METHOD_CONTRACT;
1066     return GetClass()->GetComClassFactory();
1067 }
1068
1069 //==========================================================================================
1070 inline BOOL MethodTable::SetComClassFactory(ClassFactoryBase *pFactory)
1071 {
1072     CONTRACTL
1073     {
1074         THROWS;
1075         GC_NOTRIGGER;
1076         MODE_ANY;
1077     }
1078     CONTRACTL_END;
1079
1080     g_IBCLogger.LogEEClassCOWTableAccess(this);
1081     return GetClass_NoLogging()->SetComClassFactory(pFactory);
1082 }
1083 #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION
1084 #endif // FEATURE_COMINTEROP
1085 #endif // DACCESS_COMPILE
1086
1087 #ifdef FEATURE_COMINTEROP
1088 //==========================================================================================
1089 inline BOOL MethodTable::IsProjectedFromWinRT()
1090 {
1091     LIMITED_METHOD_DAC_CONTRACT;
1092     _ASSERTE(GetClass());
1093     return GetClass()->IsProjectedFromWinRT();
1094 }
1095
1096 //==========================================================================================
1097 inline BOOL MethodTable::IsExportedToWinRT()
1098 {
1099     LIMITED_METHOD_DAC_CONTRACT;
1100     _ASSERTE(GetClass());
1101     return GetClass()->IsExportedToWinRT();
1102 }
1103
1104 //==========================================================================================
1105 inline BOOL MethodTable::IsWinRTDelegate()
1106 {
1107     LIMITED_METHOD_DAC_CONTRACT;
1108     return (IsProjectedFromWinRT() && IsDelegate()) || IsWinRTRedirectedDelegate();
1109 }
1110
1111 #else // FEATURE_COMINTEROP
1112
1113 //==========================================================================================
1114 inline BOOL MethodTable::IsProjectedFromWinRT()
1115 {
1116     LIMITED_METHOD_DAC_CONTRACT;
1117     return FALSE;
1118 }
1119
1120 //==========================================================================================
1121 inline BOOL MethodTable::IsExportedToWinRT()
1122 {
1123     LIMITED_METHOD_DAC_CONTRACT;
1124     return FALSE;
1125 }
1126
1127 //==========================================================================================
1128 inline BOOL MethodTable::IsWinRTDelegate()
1129 {
1130     LIMITED_METHOD_DAC_CONTRACT;
1131     return FALSE;
1132 }
1133
1134 #endif // FEATURE_COMINTEROP
1135
1136 //==========================================================================================
1137 inline UINT32 MethodTable::GetNativeSize()
1138 {
1139     LIMITED_METHOD_CONTRACT;
1140     _ASSERTE(GetClass());
1141     return GetClass()->GetNativeSize();
1142 }
1143
1144 //==========================================================================================
1145 inline PTR_MethodTable MethodTable::GetCanonicalMethodTable()
1146 {
1147     LIMITED_METHOD_DAC_CONTRACT;
1148
1149     TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT);
1150
1151 #ifdef _DEBUG
1152     LowBits lowBits = union_getLowBits(addr);
1153     if (lowBits == UNION_EECLASS)
1154     {
1155         return dac_cast<PTR_MethodTable>(this);
1156     }
1157     else if (lowBits == UNION_METHODTABLE)
1158     {
1159         // pointer to canonical MethodTable.
1160         return PTR_MethodTable(union_getPointer(addr));
1161     }
1162 #ifdef FEATURE_PREJIT
1163     else if (lowBits == UNION_INDIRECTION)
1164     {
1165         return PTR_MethodTable(*PTR_TADDR(union_getPointer(addr)));
1166     }
1167 #endif
1168     _ASSERTE(!"Malformed m_pCanonMT in MethodTable");
1169     return NULL;
1170 #else
1171
1172     if ((addr & 2) == 0)
1173         return dac_cast<PTR_MethodTable>(this);
1174
1175 #ifdef FEATURE_PREJIT
1176     if ((addr & 1) != 0)
1177         return PTR_MethodTable(*PTR_TADDR(addr - 3));
1178 #endif
1179
1180     return PTR_MethodTable(addr - 2);
1181 #endif
1182 }
1183
1184 //==========================================================================================
1185 inline TADDR MethodTable::GetCanonicalMethodTableFixup()
1186 {
1187     LIMITED_METHOD_DAC_CONTRACT;
1188
1189 #ifdef FEATURE_PREJIT
1190     TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT);
1191     LowBits lowBits = union_getLowBits(addr);
1192     if (lowBits == UNION_INDIRECTION)
1193     {
1194         // pointer to canonical MethodTable.
1195         return *PTR_TADDR(union_getPointer(addr));
1196     }
1197     else
1198 #endif
1199     {
1200         return NULL;
1201     }
1202 }
1203
1204 //==========================================================================================
1205 #ifndef DACCESS_COMPILE
1206 FORCEINLINE BOOL MethodTable::IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited /*= NULL*/))
1207 {
1208     WRAPPER_NO_CONTRACT;
1209
1210     if (this == pOtherMT)
1211         return TRUE;
1212
1213 #ifdef FEATURE_TYPEEQUIVALENCE
1214     // bail early for normal types
1215     if (!HasTypeEquivalence() || !pOtherMT->HasTypeEquivalence())
1216         return FALSE;
1217
1218     if (IsEquivalentTo_Worker(pOtherMT COMMA_INDEBUG(pVisited)))
1219         return TRUE;
1220 #endif // FEATURE_TYPEEQUIVALENCE
1221
1222     return FALSE;
1223 }
1224 #endif
1225
1226 //==========================================================================================
1227 inline IMDInternalImport* MethodTable::GetMDImport()
1228 {
1229     LIMITED_METHOD_CONTRACT;
1230     return GetModule()->GetMDImport();
1231 }
1232
1233 //==========================================================================================
1234 inline BOOL MethodTable::IsSealed()
1235 {
1236     LIMITED_METHOD_CONTRACT;
1237     return GetClass()->IsSealed();
1238 }
1239
1240 //==========================================================================================
1241 inline BOOL MethodTable::IsManagedSequential()
1242 {
1243     LIMITED_METHOD_CONTRACT;
1244     return GetClass()->IsManagedSequential();
1245 }
1246
1247 //==========================================================================================
1248 inline BOOL MethodTable::HasExplicitSize()
1249 {
1250     LIMITED_METHOD_CONTRACT;
1251     return GetClass()->HasExplicitSize();
1252 }
1253
1254 //==========================================================================================
1255 inline DWORD MethodTable::GetPerInstInfoSize()
1256 {
1257     LIMITED_METHOD_DAC_CONTRACT;
1258     return GetNumDicts() * sizeof(PerInstInfoElem_t);
1259 }
1260
1261 //==========================================================================================
1262 inline EEClassLayoutInfo *MethodTable::GetLayoutInfo()
1263 {
1264     LIMITED_METHOD_CONTRACT;
1265     PRECONDITION(HasLayout());
1266     return GetClass()->GetLayoutInfo();
1267 }
1268
1269 //==========================================================================================
1270 // These come after the pointers to the generic dictionaries (if any)
1271 inline DWORD MethodTable::GetInterfaceMapSize()
1272 {
1273     LIMITED_METHOD_DAC_CONTRACT;
1274
1275     DWORD cbIMap = GetNumInterfaces() * sizeof(InterfaceInfo_t);
1276 #ifdef FEATURE_COMINTEROP 
1277     cbIMap += (HasDynamicInterfaceMap() ? sizeof(DWORD_PTR) : 0);
1278 #endif
1279     return cbIMap;
1280 }
1281
1282 //==========================================================================================
1283 // These are the generic dictionaries themselves and are come after
1284 //  the interface map.  In principle they need not be inline in the method table.
1285 inline DWORD MethodTable::GetInstAndDictSize()
1286 {
1287     LIMITED_METHOD_DAC_CONTRACT;
1288
1289     if (!HasInstantiation())
1290         return 0;
1291     else
1292         return DictionaryLayout::GetFirstDictionaryBucketSize(GetNumGenericArgs(), GetClass()->GetDictionaryLayout());
1293 }
1294
1295 //==========================================================================================
1296 inline BOOL MethodTable::IsSharedByGenericInstantiations()
1297 {
1298     LIMITED_METHOD_DAC_CONTRACT;
1299
1300     g_IBCLogger.LogMethodTableAccess(this);
1301
1302     return TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_SharedInst);
1303 }
1304
1305 //==========================================================================================
1306 inline BOOL MethodTable::IsCanonicalMethodTable()
1307 {
1308     LIMITED_METHOD_DAC_CONTRACT;
1309
1310     return (union_getLowBits(ReadPointer(this, &MethodTable::m_pCanonMT)) == UNION_EECLASS);
1311 }
1312
1313 //==========================================================================================
1314 FORCEINLINE BOOL MethodTable::HasInstantiation()
1315 {
1316     LIMITED_METHOD_DAC_CONTRACT;
1317
1318     // Generics flags cannot be expressed in terms of GetFlag()
1319     return !TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_NonGeneric);
1320 }
1321
1322 //==========================================================================================
1323 inline void MethodTable::SetHasInstantiation(BOOL fTypicalInstantiation, BOOL fSharedByGenericInstantiations)
1324 {
1325     LIMITED_METHOD_CONTRACT;
1326     _ASSERTE(!IsStringOrArray());
1327     SetFlag(fTypicalInstantiation ? enum_flag_GenericsMask_TypicalInst :
1328         (fSharedByGenericInstantiations ? enum_flag_GenericsMask_SharedInst : enum_flag_GenericsMask_GenericInst));
1329 }
1330 //==========================================================================================
1331 inline BOOL MethodTable::IsGenericTypeDefinition()
1332 {
1333     LIMITED_METHOD_DAC_CONTRACT;
1334
1335     // Generics flags cannot be expressed in terms of GetFlag()
1336     return TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_TypicalInst);
1337 }
1338
1339 //==========================================================================================
1340 inline PTR_InterfaceInfo MethodTable::GetInterfaceMap()
1341 {
1342     LIMITED_METHOD_DAC_CONTRACT;
1343
1344     return ReadPointer(this, &MethodTable::m_pInterfaceMap);
1345 }
1346
1347 //==========================================================================================
1348 FORCEINLINE TADDR MethodTable::GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const BYTE * offsets)
1349 {
1350     LIMITED_METHOD_DAC_CONTRACT;
1351
1352     _ASSERTE(GetFlag(flag));
1353
1354     DWORD offset = offsets[GetFlag((WFLAGS2_ENUM)(flag - 1))];
1355
1356     if (offset >= sizeof(MethodTable)) {
1357         offset += GetNumVtableIndirections() * sizeof(VTableIndir_t);
1358     }
1359
1360     return dac_cast<TADDR>(this) + offset;
1361 }
1362
1363 //==========================================================================================
1364 // This method is dependent on the declared order of optional members
1365 // If you add or remove an optional member or reorder them please change this method
1366 FORCEINLINE DWORD MethodTable::GetOffsetOfOptionalMember(OptionalMemberId id)
1367 {
1368     LIMITED_METHOD_CONTRACT;
1369
1370     DWORD offset = c_OptionalMembersStartOffsets[GetFlag(enum_flag_MultipurposeSlotsMask)];
1371
1372     offset += GetNumVtableIndirections() * sizeof(VTableIndir_t);
1373
1374 #undef METHODTABLE_OPTIONAL_MEMBER
1375 #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \
1376     if (id == OptionalMember_##NAME) { \
1377         return offset; \
1378     } \
1379     C_ASSERT(sizeof(TYPE) % sizeof(UINT_PTR) == 0); /* To insure proper alignment */ \
1380     if (Has##NAME()) { \
1381         offset += sizeof(TYPE); \
1382     }
1383
1384     METHODTABLE_OPTIONAL_MEMBERS()
1385
1386     _ASSERTE(!"Wrong optional member" || id == OptionalMember_Count);
1387     return offset;
1388 }
1389
1390 //==========================================================================================
1391 // this is not the pretties function however I got bitten pretty hard by the computation 
1392 // of the allocation size of a MethodTable done "by hand" in few places.
1393 // Essentially the idea is that this is going to centralize computation of size for optional
1394 // members so the next morons that need to add an optional member will look at this function
1395 // and hopefully be less exposed to code doing size computation behind their back
1396 inline DWORD MethodTable::GetOptionalMembersAllocationSize(DWORD dwMultipurposeSlotsMask,
1397                                                            BOOL needsRemotableMethodInfo,
1398                                                            BOOL needsGenericsStaticsInfo,
1399                                                            BOOL needsGuidInfo,
1400                                                            BOOL needsCCWTemplate,
1401                                                            BOOL needsRCWPerTypeData,
1402                                                            BOOL needsRemotingVtsInfo,
1403                                                            BOOL needsContextStatic,
1404                                                            BOOL needsTokenOverflow)
1405 {
1406     LIMITED_METHOD_CONTRACT;
1407
1408     DWORD size = c_OptionalMembersStartOffsets[dwMultipurposeSlotsMask] - sizeof(MethodTable);
1409
1410     if (needsRemotableMethodInfo)
1411         size += sizeof(UINT_PTR);
1412     if (needsGenericsStaticsInfo)
1413         size += sizeof(GenericsStaticsInfo);
1414     if (needsGuidInfo)
1415         size += sizeof(UINT_PTR);
1416     if (needsCCWTemplate)
1417         size += sizeof(UINT_PTR);
1418     if (needsRCWPerTypeData)
1419         size += sizeof(UINT_PTR);
1420     if (needsRemotingVtsInfo)
1421         size += sizeof(UINT_PTR);
1422     if (needsContextStatic)
1423         size += sizeof(UINT_PTR);
1424     if (dwMultipurposeSlotsMask & enum_flag_HasInterfaceMap)
1425         size += sizeof(UINT_PTR);
1426     if (needsTokenOverflow)
1427         size += sizeof(UINT_PTR);
1428
1429     return size;
1430 }
1431
1432 inline DWORD MethodTable::GetOptionalMembersSize()
1433 {
1434     WRAPPER_NO_CONTRACT;
1435
1436     return GetEndOffsetOfOptionalMembers() - GetStartOffsetOfOptionalMembers();
1437 }
1438
1439 #ifndef DACCESS_COMPILE
1440
1441 //==========================================================================================
1442 inline PTR_BYTE MethodTable::GetNonGCStaticsBasePointer()
1443 {
1444     WRAPPER_NO_CONTRACT;
1445     return GetDomainLocalModule()->GetNonGCStaticsBasePointer(this);
1446 }
1447
1448 //==========================================================================================
1449 inline PTR_BYTE MethodTable::GetGCStaticsBasePointer()
1450 {
1451     WRAPPER_NO_CONTRACT;
1452     return GetDomainLocalModule()->GetGCStaticsBasePointer(this);
1453 }
1454
1455 //==========================================================================================
1456 inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer()
1457 {
1458     CONTRACTL
1459     {
1460         NOTHROW;
1461         GC_NOTRIGGER;
1462         MODE_ANY;
1463     }
1464     CONTRACTL_END;
1465
1466     // Get the current thread
1467     PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread());
1468
1469     // Get the current module's ModuleIndex
1470     ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
1471     
1472     PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLBIfExists(pThread, NULL);
1473     if (pTLB == NULL)
1474         return NULL;
1475
1476     PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
1477     if (pTLM == NULL)
1478         return NULL;
1479
1480     return pTLM->GetNonGCStaticsBasePointer(this);
1481 }
1482
1483 //==========================================================================================
1484 inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer()
1485 {
1486     CONTRACTL
1487     {
1488         NOTHROW;
1489         GC_NOTRIGGER;
1490         MODE_COOPERATIVE;
1491     }
1492     CONTRACTL_END;
1493
1494     // Get the current thread
1495     PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread());
1496
1497     // Get the current module's ModuleIndex
1498     ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
1499     
1500     PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLBIfExists(pThread, NULL);
1501     if (pTLB == NULL)
1502         return NULL;
1503
1504     PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
1505     if (pTLM == NULL)
1506         return NULL;
1507
1508     return pTLM->GetGCStaticsBasePointer(this);
1509 }
1510
1511 #endif //!DACCESS_COMPILE
1512
1513 //==========================================================================================
1514 inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain)
1515 {
1516     LIMITED_METHOD_DAC_CONTRACT;
1517
1518     // Get the current module's ModuleIndex
1519     ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
1520     
1521     PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLBIfExists(pThread, pDomain);
1522     if (pTLB == NULL)
1523         return NULL;
1524
1525     PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
1526     if (pTLM == NULL)
1527         return NULL;
1528
1529     return pTLM->GetNonGCStaticsBasePointer(this);
1530 }
1531
1532 //==========================================================================================
1533 inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain)
1534 {
1535     LIMITED_METHOD_DAC_CONTRACT;
1536
1537     // Get the current module's ModuleIndex
1538     ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
1539     
1540     PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLBIfExists(pThread, pDomain);
1541     if (pTLB == NULL)
1542         return NULL;
1543
1544     PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
1545     if (pTLM == NULL)
1546         return NULL;
1547
1548     return pTLM->GetGCStaticsBasePointer(this);
1549 }
1550
1551 //==========================================================================================
1552 inline PTR_DomainLocalModule MethodTable::GetDomainLocalModule(AppDomain * pAppDomain)
1553 {
1554     WRAPPER_NO_CONTRACT;
1555     return GetModuleForStatics()->GetDomainLocalModule(pAppDomain);
1556 }
1557
1558 #ifndef DACCESS_COMPILE
1559 //==========================================================================================
1560 inline PTR_DomainLocalModule MethodTable::GetDomainLocalModule()
1561 {
1562     WRAPPER_NO_CONTRACT;
1563     return GetModuleForStatics()->GetDomainLocalModule();
1564 }
1565 #endif //!DACCESS_COMPILE
1566
1567 //==========================================================================================
1568 inline OBJECTREF MethodTable::AllocateNoChecks()
1569 {
1570     CONTRACTL
1571     {
1572         MODE_COOPERATIVE;
1573         GC_TRIGGERS;
1574         THROWS;
1575     }
1576     CONTRACTL_END;
1577
1578     // we know an instance of this class already exists in the same appdomain
1579     // therefore, some checks become redundant.
1580     // this currently only happens for Delegate.Combine
1581     CONSISTENCY_CHECK(IsRestored_NoLogging());
1582
1583     CONSISTENCY_CHECK(CheckInstanceActivated());
1584
1585     return AllocateObject(this);
1586 }
1587
1588
1589 //==========================================================================================
1590 inline DWORD MethodTable::GetClassIndex()
1591 {
1592     WRAPPER_NO_CONTRACT;
1593     return GetClassIndexFromToken(GetCl());
1594 }
1595
1596 #ifndef DACCESS_COMPILE
1597 //==========================================================================================
1598 // unbox src into dest, making sure src is of the correct type.
1599
1600 inline BOOL MethodTable::UnBoxInto(void *dest, OBJECTREF src) 
1601 {
1602     CONTRACTL
1603     {
1604         NOTHROW;
1605         GC_NOTRIGGER;
1606         SO_TOLERANT;
1607         MODE_COOPERATIVE;
1608     }
1609     CONTRACTL_END;
1610
1611     if (Nullable::IsNullableType(TypeHandle(this)))
1612         return Nullable::UnBoxNoGC(dest, src, this);
1613     else  
1614     {
1615         if (src == NULL || src->GetMethodTable() != this)
1616             return FALSE;
1617
1618         CopyValueClass(dest, src->UnBox(), this, src->GetAppDomain());
1619     }
1620     return TRUE;
1621 }
1622
1623 //==========================================================================================
1624 // unbox src into argument, making sure src is of the correct type.
1625
1626 inline BOOL MethodTable::UnBoxIntoArg(ArgDestination *argDest, OBJECTREF src)
1627 {
1628     CONTRACTL
1629     {
1630         NOTHROW;
1631         GC_NOTRIGGER;
1632         SO_TOLERANT;
1633         MODE_COOPERATIVE;
1634     }
1635     CONTRACTL_END;
1636
1637     if (Nullable::IsNullableType(TypeHandle(this)))
1638         return Nullable::UnBoxIntoArgNoGC(argDest, src, this);
1639     else  
1640     {
1641         if (src == NULL || src->GetMethodTable() != this)
1642             return FALSE;
1643
1644         CopyValueClassArg(argDest, src->UnBox(), this, src->GetAppDomain(), 0);
1645     }
1646     return TRUE;
1647 }
1648
1649 //==========================================================================================
1650 // unbox src into dest, No checks are done
1651
1652 inline void MethodTable::UnBoxIntoUnchecked(void *dest, OBJECTREF src) 
1653 {
1654     CONTRACTL
1655     {
1656         NOTHROW;
1657         GC_NOTRIGGER;
1658         SO_TOLERANT;
1659         MODE_COOPERATIVE;
1660     }
1661     CONTRACTL_END;
1662
1663     if (Nullable::IsNullableType(TypeHandle(this))) {
1664         BOOL ret;
1665         ret = Nullable::UnBoxNoGC(dest, src, this);
1666         _ASSERTE(ret);
1667     }
1668     else  
1669     {
1670         _ASSERTE(src->GetMethodTable()->GetNumInstanceFieldBytes() == GetNumInstanceFieldBytes());
1671
1672         CopyValueClass(dest, src->UnBox(), this, src->GetAppDomain());
1673     }
1674 }
1675 #endif
1676 //==========================================================================================
1677 __forceinline TypeHandle::CastResult MethodTable::CanCastToClassOrInterfaceNoGC(MethodTable *pTargetMT)
1678 {
1679     CONTRACTL
1680     {
1681         NOTHROW;
1682         GC_NOTRIGGER;
1683         MODE_ANY;
1684         INSTANCE_CHECK;
1685         SO_TOLERANT;
1686         PRECONDITION(CheckPointer(pTargetMT));
1687         PRECONDITION(!pTargetMT->IsArray());
1688     }
1689     CONTRACTL_END
1690
1691     if (pTargetMT->IsInterface())
1692         return CanCastToInterfaceNoGC(pTargetMT);
1693     else
1694         return CanCastToClassNoGC(pTargetMT);
1695 }
1696
1697 //==========================================================================================
1698 inline BOOL MethodTable::CanCastToClassOrInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited)
1699 {
1700     CONTRACTL
1701     {
1702         THROWS;
1703         GC_TRIGGERS;
1704         MODE_ANY;
1705         INSTANCE_CHECK;
1706         PRECONDITION(CheckPointer(pTargetMT));
1707         PRECONDITION(!pTargetMT->IsArray());
1708         PRECONDITION(IsRestored_NoLogging());
1709     }
1710     CONTRACTL_END
1711
1712     if (pTargetMT->IsInterface())
1713         return CanCastToInterface(pTargetMT, pVisited);
1714     else
1715         return CanCastToClass(pTargetMT, pVisited);
1716 }
1717
1718 //==========================================================================================
1719 FORCEINLINE PTR_Module MethodTable::GetGenericsStaticsModuleAndID(DWORD * pID)
1720 {
1721     CONTRACTL
1722     {
1723         NOTHROW;
1724         GC_NOTRIGGER;
1725         MODE_ANY;
1726         SO_TOLERANT;
1727         SUPPORTS_DAC;
1728     }
1729     CONTRACTL_END
1730
1731     _ASSERTE(HasGenericsStaticsInfo());
1732
1733 #ifdef FEATURE_PREJIT
1734     // This is performance sensitive codepath inlined into JIT helpers. Test the flag directly without
1735     // checking IsStringOrArray() first. IsStringOrArray() will always be false here.
1736     _ASSERTE(!IsStringOrArray());
1737     if (m_dwFlags & enum_flag_StaticsMask_IfGenericsThenCrossModule)
1738     {
1739         CrossModuleGenericsStaticsInfo *pInfo = ReadPointer(this, &MethodTable::m_pWriteableData)->GetCrossModuleGenericsStaticsInfo();
1740         _ASSERTE(FitsIn<DWORD>(pInfo->m_DynamicTypeID) || pInfo->m_DynamicTypeID == (SIZE_T)-1);
1741         *pID = static_cast<DWORD>(pInfo->m_DynamicTypeID);
1742         return pInfo->m_pModuleForStatics;
1743     }
1744 #endif // FEATURE_PREJIT
1745
1746     _ASSERTE(FitsIn<DWORD>(GetGenericsStaticsInfo()->m_DynamicTypeID) || GetGenericsStaticsInfo()->m_DynamicTypeID == (SIZE_T)-1);
1747     *pID = static_cast<DWORD>(GetGenericsStaticsInfo()->m_DynamicTypeID);
1748     return GetLoaderModule();
1749 }
1750
1751 //==========================================================================================
1752 inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle()
1753 {
1754     LIMITED_METHOD_CONTRACT;
1755     return GetLoaderAllocator()->GetLoaderAllocatorObjectHandle();
1756 }
1757
1758 //==========================================================================================
1759 FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() 
1760 {
1761     LIMITED_METHOD_CONTRACT;
1762
1763     // Logging will be done by the slow path
1764     LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle();
1765
1766     OBJECTREF retVal;
1767
1768     // GET_LOADERHANDLE_VALUE_FAST macro is inlined here to let us give hint to the compiler
1769     // when the return value is not null.
1770     if (!LoaderAllocator::GetHandleValueFast(handle, &retVal) &&
1771         !GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal))
1772     {
1773         return NULL;
1774     }
1775
1776     COMPILER_ASSUME(retVal != NULL);
1777     return retVal;
1778 }
1779
1780 //==========================================================================================
1781 inline void MethodTable::SetIsArray(CorElementType arrayType, CorElementType elementType)
1782 {
1783     STANDARD_VM_CONTRACT;
1784
1785     DWORD category = enum_flag_Category_Array;
1786     if (arrayType == ELEMENT_TYPE_SZARRAY)
1787         category |= enum_flag_Category_IfArrayThenSzArray;
1788
1789     _ASSERTE((m_dwFlags & enum_flag_Category_Mask) == 0);
1790     m_dwFlags |= category;
1791
1792     _ASSERTE(GetInternalCorElementType() == arrayType);
1793 }
1794
1795 //==========================================================================================
1796 FORCEINLINE BOOL MethodTable::ImplementsInterfaceInline(MethodTable *pInterface)
1797 {
1798     CONTRACTL
1799     {
1800         NOTHROW;
1801         GC_NOTRIGGER;
1802         SO_TOLERANT;
1803         PRECONDITION(pInterface->IsInterface()); // class we are looking up should be an interface
1804     }
1805     CONTRACTL_END;
1806
1807     //
1808     // Inline InterfaceMapIterator here for performance reasons
1809     //
1810
1811     DWORD numInterfaces = GetNumInterfaces();
1812     if (numInterfaces == 0)
1813         return FALSE;
1814
1815     InterfaceInfo_t *pInfo = GetInterfaceMap();
1816
1817     do
1818     {
1819         if (pInfo->GetMethodTable() == pInterface)
1820         {
1821             // Extensible RCW's need to be handled specially because they can have interfaces
1822             // in their map that are added at runtime. These interfaces will have a start offset
1823             // of -1 to indicate this. We cannot take for granted that every instance of this
1824             // COM object has this interface so FindInterface on these interfaces is made to fail.
1825             //
1826             // However, we are only considering the statically available slots here
1827             // (m_wNumInterface doesn't contain the dynamic slots), so we can safely
1828             // ignore this detail.
1829             return TRUE;
1830         }
1831         pInfo++;
1832     }
1833     while (--numInterfaces);
1834
1835     return FALSE;
1836 }
1837
1838 #endif // !_METHODTABLE_INL_