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