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: typehandle.cpp
6//
7
8
9//
10
11//
12// ============================================================================
13
14
15#include "common.h"
16#include "class.h"
17#include "typehandle.h"
18#include "eeconfig.h"
19#include "generics.h"
20#include "typedesc.h"
21#include "typekey.h"
22#include "typestring.h"
23#include "classloadlevel.h"
24#include "array.h"
25#ifdef FEATURE_PREJIT
26#include "zapsig.h"
27#endif
28
29// This method is not being called by all the constructors of TypeHandle
30// because of the following reason. SystemDomain::LoadBaseSystemClasses()
31// loads TYPE__OBJECT_ARRAY which causes the following issues:
32//
33// If mscorlib is JIT-compiled, Module::CreateArrayMethodTable calls
34// TypeString::AppendName() with a TypeHandle that wraps the MethodTable
35// being created.
36// If mscorlib is ngenned, Module::RestoreMethodTablePointer() needs
37// a TypeHandle to call ClassLoader::EnsureLoaded().
38//
39
40#if 0
41
42void TypeHandle::NormalizeUnsharedArrayMT()
43{
44 WRAPPER_NO_CONTRACT;
45 STATIC_CONTRACT_SO_TOLERANT; // @TODO: This is probably incorrect
46
47 if (IsNull() || IsTypeDesc())
48 return;
49
50 if (!AsMethodTable()->IsArray())
51 return;
52
53 // This is an array type with a unique unshared MethodTable.
54 // We know that there must exist an ArrayTypeDesc for it, and it
55 // must have been restored.
56 // Let's look it up and use it.
57
58 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
59
60 TypeHandle elemType = AsMethodTable()->GetApproxArrayElementTypeHandle();
61 CorElementType kind = AsMethodTable()->GetInternalCorElementType();
62 unsigned rank = AsMethodTable()->GetRank();
63
64 // @todo This should be turned into a probe with a hard SO when we have one
65 CONTRACT_VIOLATION(SOToleranceViolation);
66 // == FailIfNotLoadedOrNotRestored
67 TypeHandle arrayType = ClassLoader::LoadArrayTypeThrowing( elemType,
68 kind,
69 rank,
70 ClassLoader::DontLoadTypes);
71 CONSISTENCY_CHECK(!arrayType.IsNull() && arrayType.IsArray());
72
73 //
74 // Update the current TypeHandle to use the ArrayTypeDesc
75 //
76 m_asPtr = arrayType.AsPtr();
77
78 INDEBUGIMPL(Verify());
79}
80
81#endif
82
83#ifdef _DEBUG_IMPL
84
85BOOL TypeHandle::Verify()
86{
87 STATIC_CONTRACT_NOTHROW;
88 STATIC_CONTRACT_GC_NOTRIGGER;
89 STATIC_CONTRACT_FORBID_FAULT;
90 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
91 STATIC_CONTRACT_DEBUG_ONLY;
92 STATIC_CONTRACT_SUPPORTS_DAC;
93
94 if (IsNull())
95 return(TRUE);
96
97 // If you try to do IBC logging of a type being created, the type
98 // will look inconsistent. IBC logging knows to filter out such types.
99 if (g_IBCLogger.InstrEnabled())
100 return TRUE;
101
102 if (!IsRestored_NoLogging())
103 return TRUE;
104
105 if (!IsTypeDesc())
106 {
107 _ASSERTE(AsMethodTable()->SanityCheck()); // Sane method table
108
109 // @TODO: See TypeHandle::IsArrayType() for an explanation
110 // of why this assert is commented out.
111 //
112 // _ASSERTE(!AsMethodTable()->IsArray());
113 }
114 else
115 {
116 if (IsArray())
117 AsArray()->Verify();
118 }
119 return(TRUE);
120}
121
122#endif // _DEBUG_IMPL
123
124unsigned TypeHandle::GetSize() const
125{
126 LIMITED_METHOD_DAC_CONTRACT;
127
128 CorElementType type = GetInternalCorElementType();
129
130 if (type == ELEMENT_TYPE_VALUETYPE)
131 {
132 if (IsTypeDesc())
133 return(AsNativeValueType()->GetNativeSize());
134 else
135 return(AsMethodTable()->GetNumInstanceFieldBytes());
136 }
137
138 return(GetSizeForCorElementType(type));
139}
140
141PTR_Module TypeHandle::GetModule() const {
142 LIMITED_METHOD_DAC_CONTRACT;
143
144 if (IsTypeDesc())
145 return AsTypeDesc()->GetModule();
146 return(AsMethodTable()->GetModule());
147}
148
149Assembly* TypeHandle::GetAssembly() const {
150 LIMITED_METHOD_DAC_CONTRACT;
151
152 if (IsTypeDesc())
153 return AsTypeDesc()->GetAssembly();
154 return(AsMethodTable()->GetAssembly());
155}
156
157BOOL TypeHandle::IsArray() const {
158 LIMITED_METHOD_DAC_CONTRACT;
159
160 return(IsTypeDesc() && AsTypeDesc()->IsArray());
161}
162
163BOOL TypeHandle::IsArrayType() const {
164 LIMITED_METHOD_DAC_CONTRACT;
165
166 if (IsTypeDesc())
167 {
168 return AsTypeDesc()->IsArray();
169 }
170 else
171 {
172 return AsMethodTable()->IsArray();
173 }
174}
175
176BOOL TypeHandle::IsGenericVariable() const {
177 LIMITED_METHOD_DAC_CONTRACT;
178
179 return(IsTypeDesc() && CorTypeInfo::IsGenericVariable_NoThrow(AsTypeDesc()->GetInternalCorElementType()));
180}
181
182BOOL TypeHandle::HasTypeParam() const {
183 LIMITED_METHOD_DAC_CONTRACT;
184
185 if (!IsTypeDesc()) return FALSE;
186
187 CorElementType etype = AsTypeDesc()->GetInternalCorElementType();
188 return(CorTypeInfo::IsModifier_NoThrow(etype) || etype == ELEMENT_TYPE_VALUETYPE);
189}
190
191Module *TypeHandle::GetDefiningModuleForOpenType() const
192{
193 WRAPPER_NO_CONTRACT;
194 SUPPORTS_DAC;
195
196 Module* returnValue = NULL;
197
198 INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(goto Exit;);
199
200 if (IsGenericVariable())
201 {
202 PTR_TypeVarTypeDesc pTyVar = dac_cast<PTR_TypeVarTypeDesc>(AsTypeDesc());
203 returnValue = pTyVar->GetModule();
204 goto Exit;
205 }
206
207 if (HasTypeParam())
208 {
209 returnValue = GetTypeParam().GetDefiningModuleForOpenType();
210 }
211 else if (HasInstantiation())
212 {
213 returnValue = GetMethodTable()->GetDefiningModuleForOpenType();
214 }
215Exit:
216 ;
217 END_INTERIOR_STACK_PROBE;
218
219 return returnValue;
220}
221
222BOOL TypeHandle::ContainsGenericVariables(BOOL methodOnly /*=FALSE*/) const
223{
224 STATIC_CONTRACT_SO_TOLERANT;
225 STATIC_CONTRACT_NOTHROW;
226 SUPPORTS_DAC;
227
228 if (IsTypeDesc())
229 {
230 if (IsGenericVariable())
231 {
232 if (!methodOnly)
233 return TRUE;
234
235 PTR_TypeVarTypeDesc pTyVar = dac_cast<PTR_TypeVarTypeDesc>(AsTypeDesc());
236 return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef;
237 }
238
239 if (HasTypeParam())
240 {
241 return GetTypeParam().ContainsGenericVariables(methodOnly);
242 }
243 }
244 else if (HasInstantiation())
245 {
246 if (GetMethodTable()->ContainsGenericVariables(methodOnly))
247 return TRUE;
248 }
249
250 return FALSE;
251}
252
253//@GENERICS:
254// Return the number of type parameters in the instantiation of an instantiated type
255// or the number of type parameters to a generic type
256// Return 0 otherwise.
257DWORD TypeHandle::GetNumGenericArgs() const {
258 LIMITED_METHOD_DAC_CONTRACT;
259
260 if (IsTypeDesc())
261 return 0;
262 else
263 return GetMethodTable()->GetNumGenericArgs();
264}
265
266BOOL TypeHandle::IsGenericTypeDefinition() const {
267 LIMITED_METHOD_DAC_CONTRACT;
268
269 if (!IsTypeDesc())
270 return AsMethodTable()->IsGenericTypeDefinition();
271 else
272 return FALSE;
273}
274
275PTR_MethodTable TypeHandle::GetCanonicalMethodTable() const
276{
277 LIMITED_METHOD_DAC_CONTRACT;
278
279 if (IsTypeDesc())
280 {
281 PTR_MethodTable pMT = AsTypeDesc()->GetMethodTable();
282 if (pMT != NULL)
283 pMT = pMT->GetCanonicalMethodTable();
284 return pMT;
285 }
286 else
287 {
288 return AsMethodTable()->GetCanonicalMethodTable();
289 }
290}
291
292// Obtain instantiation from an instantiated type or a pointer to the
293// element type of an array or pointer type
294Instantiation TypeHandle::GetClassOrArrayInstantiation() const
295{
296 LIMITED_METHOD_DAC_CONTRACT;
297
298 if (IsTypeDesc())
299 {
300 return AsTypeDesc()->GetClassOrArrayInstantiation();
301 }
302 else if (IsArrayType())
303 {
304 return AsMethodTable()->GetArrayInstantiation();
305 }
306 else
307 {
308 return GetInstantiation();
309 }
310}
311
312Instantiation TypeHandle::GetInstantiationOfParentClass(MethodTable *pWhichParent) const
313{
314 LIMITED_METHOD_DAC_CONTRACT;
315
316 return GetMethodTable()->GetInstantiationOfParentClass(pWhichParent);
317}
318
319// Obtain element type from an array or pointer type
320TypeHandle TypeHandle::GetTypeParam() const
321{
322 LIMITED_METHOD_DAC_CONTRACT;
323
324 if (IsTypeDesc())
325 return AsTypeDesc()->GetTypeParam();
326 else
327 return TypeHandle();
328}
329
330#ifndef DACCESS_COMPILE
331TypeHandle TypeHandle::Instantiate(Instantiation inst) const
332{
333 STATIC_CONTRACT_WRAPPER;
334 return ClassLoader::LoadGenericInstantiationThrowing(GetModule(), GetCl(), inst);
335}
336
337TypeHandle TypeHandle::MakePointer() const
338{
339 STATIC_CONTRACT_WRAPPER;
340 return ClassLoader::LoadPointerOrByrefTypeThrowing(ELEMENT_TYPE_PTR, *this);
341}
342
343TypeHandle TypeHandle::MakeByRef() const
344{
345 STATIC_CONTRACT_WRAPPER;
346 return ClassLoader::LoadPointerOrByrefTypeThrowing(ELEMENT_TYPE_BYREF, *this);
347}
348
349TypeHandle TypeHandle::MakeSZArray() const
350{
351 STATIC_CONTRACT_WRAPPER;
352 return ClassLoader::LoadArrayTypeThrowing(*this);
353}
354
355TypeHandle TypeHandle::MakeArray(int rank) const
356{
357 STATIC_CONTRACT_WRAPPER;
358 return ClassLoader::LoadArrayTypeThrowing(*this, ELEMENT_TYPE_ARRAY, rank);
359}
360
361// The returned TypeHandle is a ParamTypeDesc that acts like a facade for the original valuetype. It makes the
362// valuetype look like its unmanaged view, i.e. GetSize() returns GetNativeSize(), IsBlittable() returns TRUE,
363// and JIT interface special-cases it when reporting GC pointers to the JIT.
364TypeHandle TypeHandle::MakeNativeValueType() const
365{
366 STATIC_CONTRACT_WRAPPER;
367 return ClassLoader::LoadNativeValueTypeThrowing(*this);
368}
369
370#endif // #ifndef DACCESS_COMPILE
371
372PTR_Module TypeHandle::GetLoaderModule() const
373{
374 LIMITED_METHOD_DAC_CONTRACT;
375
376 if (IsTypeDesc())
377 return AsTypeDesc()->GetLoaderModule();
378 else
379 return AsMethodTable()->GetLoaderModule();
380}
381
382PTR_Module TypeHandle::GetZapModule() const
383{
384 LIMITED_METHOD_DAC_CONTRACT;
385
386 if (IsTypeDesc())
387 return AsTypeDesc()->GetZapModule();
388 else
389 return AsMethodTable()->GetZapModule();
390}
391
392PTR_BaseDomain TypeHandle::GetDomain() const
393{
394 LIMITED_METHOD_DAC_CONTRACT;
395
396 if (IsTypeDesc())
397 return AsTypeDesc()->GetDomain();
398 else
399 return AsMethodTable()->GetDomain();
400
401}
402
403PTR_LoaderAllocator TypeHandle::GetLoaderAllocator() const
404{
405 STATIC_CONTRACT_NOTHROW;
406 STATIC_CONTRACT_GC_NOTRIGGER;
407 STATIC_CONTRACT_FORBID_FAULT;
408 STATIC_CONTRACT_SO_INTOLERANT;
409 STATIC_CONTRACT_SUPPORTS_DAC;
410
411 if (IsTypeDesc())
412 {
413 return AsTypeDesc()->GetLoaderAllocator();
414 }
415 else
416 {
417 return AsMethodTable()->GetLoaderAllocator();
418 }
419}
420
421BOOL TypeHandle::IsSharedByGenericInstantiations() const
422{
423 LIMITED_METHOD_DAC_CONTRACT;
424
425 if (IsTypeDesc())
426 {
427 // Arrays are the only typedesc in valid generic instantiations (see code:Generics::CheckInstantiation)
428
429 if (HasTypeParam())
430 {
431 return GetTypeParam().IsCanonicalSubtype();
432 }
433 return FALSE;
434 }
435 else
436 return AsMethodTable()->IsSharedByGenericInstantiations();
437}
438
439BOOL TypeHandle::IsCanonicalSubtype() const
440{
441 LIMITED_METHOD_DAC_CONTRACT;
442
443 return (*this == TypeHandle(g_pCanonMethodTableClass)) || IsSharedByGenericInstantiations();
444}
445
446/* static */ BOOL TypeHandle::IsCanonicalSubtypeInstantiation(Instantiation inst)
447{
448 LIMITED_METHOD_DAC_CONTRACT;
449
450 for (DWORD i = 0; i < inst.GetNumArgs(); i++)
451 {
452 if (inst[i].IsCanonicalSubtype())
453 return TRUE;
454 }
455 return FALSE;
456}
457
458// Obtain instantiation from an instantiated type.
459// Return NULL if it's not one.
460Instantiation TypeHandle::GetInstantiation() const
461{
462 LIMITED_METHOD_DAC_CONTRACT;
463
464 if (!IsTypeDesc()) return AsMethodTable()->GetInstantiation();
465 else return Instantiation();
466}
467
468
469BOOL TypeHandle::IsValueType() const
470{
471 LIMITED_METHOD_DAC_CONTRACT;
472
473 if (!IsTypeDesc()) return AsMethodTable()->IsValueType();
474 else return AsTypeDesc()->IsNativeValueType();
475}
476
477BOOL TypeHandle::IsInterface() const
478{
479 LIMITED_METHOD_DAC_CONTRACT;
480
481 return !IsTypeDesc() && AsMethodTable()->IsInterface();
482}
483
484BOOL TypeHandle::IsAbstract() const
485{
486 WRAPPER_NO_CONTRACT;
487 PREFIX_ASSUME(GetMethodTable() != NULL);
488 return GetMethodTable()->IsAbstract();
489}
490
491bool TypeHandle::IsHFA() const
492{
493 WRAPPER_NO_CONTRACT;
494
495 if (!IsTypeDesc())
496 return AsMethodTable()->IsHFA();
497
498 if (AsTypeDesc()->IsNativeValueType())
499 return AsNativeValueType()->IsNativeHFA();
500
501 return false;
502}
503
504CorElementType TypeHandle::GetHFAType() const
505{
506 WRAPPER_NO_CONTRACT;
507
508 if (!IsTypeDesc())
509 return AsMethodTable()->GetHFAType();
510
511 if (AsTypeDesc()->IsNativeValueType())
512 return AsNativeValueType()->GetNativeHFAType();
513
514 return ELEMENT_TYPE_END;
515}
516
517
518#ifdef FEATURE_64BIT_ALIGNMENT
519bool TypeHandle::RequiresAlign8() const
520{
521 WRAPPER_NO_CONTRACT;
522
523 if (IsNativeValueType())
524 return AsNativeValueType()->NativeRequiresAlign8();
525
526 return GetMethodTable()->RequiresAlign8();
527}
528#endif // FEATURE_64BIT_ALIGNMENT
529
530#ifndef DACCESS_COMPILE
531
532BOOL TypeHandle::IsBlittable() const
533{
534 LIMITED_METHOD_CONTRACT;
535
536 if (!IsTypeDesc())
537 {
538 // This is a simple type (not an array, ptr or byref) so if
539 // simply check to see if the type is blittable.
540 return AsMethodTable()->IsBlittable();
541 }
542
543 if (AsTypeDesc()->IsArray())
544 {
545 // Single dimentional array's of blittable types are also blittable.
546 if (AsArray()->GetRank() == 1)
547 {
548 if (AsArray()->GetArrayElementTypeHandle().IsBlittable())
549 return TRUE;
550 }
551 }
552 else if (AsTypeDesc()->IsNativeValueType())
553 {
554 return TRUE;
555 }
556
557 return FALSE;
558}
559
560BOOL TypeHandle::HasLayout() const
561{
562 WRAPPER_NO_CONTRACT;
563 MethodTable *pMT = GetMethodTable();
564 return pMT ? pMT->HasLayout() : FALSE;
565}
566
567#ifdef FEATURE_COMINTEROP
568
569TypeHandle TypeHandle::GetCoClassForInterface() const
570{
571 WRAPPER_NO_CONTRACT;
572 PREFIX_ASSUME(GetMethodTable() != NULL);
573 return GetMethodTable()->GetCoClassForInterface();
574}
575
576DWORD TypeHandle::IsComClassInterface() const
577{
578 WRAPPER_NO_CONTRACT;
579 PREFIX_ASSUME(GetMethodTable() != NULL);
580 return GetMethodTable()->IsComClassInterface();
581}
582
583BOOL TypeHandle::IsComObjectType() const
584{
585 WRAPPER_NO_CONTRACT;
586 PREFIX_ASSUME(GetMethodTable() != NULL);
587 return GetMethodTable()->IsComObjectType();
588}
589
590BOOL TypeHandle::IsComEventItfType() const
591{
592 WRAPPER_NO_CONTRACT;
593 PREFIX_ASSUME(GetMethodTable() != NULL);
594 return GetMethodTable()->IsComEventItfType();
595}
596
597CorIfaceAttr TypeHandle::GetComInterfaceType() const
598{
599 WRAPPER_NO_CONTRACT;
600 PREFIX_ASSUME(GetMethodTable() != NULL);
601 return GetMethodTable()->GetComInterfaceType();
602}
603
604TypeHandle TypeHandle::GetDefItfForComClassItf() const
605{
606 WRAPPER_NO_CONTRACT;
607 PREFIX_ASSUME(GetMethodTable() != NULL);
608 return GetMethodTable()->GetDefItfForComClassItf();
609}
610
611BOOL TypeHandle::IsProjectedFromWinRT() const
612{
613 LIMITED_METHOD_CONTRACT;
614 PREFIX_ASSUME(GetMethodTable() != NULL);
615 return GetMethodTable()->IsProjectedFromWinRT();
616}
617
618BOOL TypeHandle::IsExportedToWinRT() const
619{
620 LIMITED_METHOD_CONTRACT;
621 PREFIX_ASSUME(GetMethodTable() != NULL);
622 return GetMethodTable()->IsExportedToWinRT();
623}
624
625ComCallWrapperTemplate *TypeHandle::GetComCallWrapperTemplate() const
626{
627 LIMITED_METHOD_CONTRACT;
628 PRECONDITION(IsArray() || !IsTypeDesc());
629
630 if (IsTypeDesc())
631 {
632 return AsArray()->GetComCallWrapperTemplate();
633 }
634 return AsMethodTable()->GetComCallWrapperTemplate();
635}
636
637BOOL TypeHandle::SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate)
638{
639 CONTRACTL
640 {
641 THROWS;
642 GC_NOTRIGGER;
643 MODE_ANY;
644 }
645 CONTRACTL_END;
646
647 PRECONDITION(IsArray() || !IsTypeDesc());
648
649 if (IsTypeDesc())
650 {
651 return AsArray()->SetComCallWrapperTemplate(pTemplate);
652 }
653 return AsMethodTable()->SetComCallWrapperTemplate(pTemplate);
654}
655
656#endif // FEATURE_COMINTEROP
657
658//--------------------------------------------------------------------------------------
659// CanCastTo is necessary but not sufficient, as it assumes that any valuetype
660// involved is in its boxed form.
661
662BOOL TypeHandle::IsBoxedAndCanCastTo(TypeHandle type, TypeHandlePairList *pPairList) const
663{
664 CONTRACTL
665 {
666 THROWS;
667 GC_TRIGGERS;
668 INJECT_FAULT(COMPlusThrowOM());
669
670 LOADS_TYPE(CLASS_DEPENDENCIES_LOADED);
671
672 // The caller should check for an exact match.
673 // That will cover the cast of a (unboxed) valuetype to itself.
674 PRECONDITION(*this != type);
675 }
676 CONTRACTL_END
677
678
679 CorElementType fromParamCorType = GetVerifierCorElementType();
680
681 if (CorTypeInfo::IsObjRef(fromParamCorType))
682 {
683 // fromParamCorType is a reference type. We can just use CanCastTo
684 return CanCastTo(type, pPairList);
685 }
686 else if (CorTypeInfo::IsGenericVariable(fromParamCorType))
687 {
688 TypeVarTypeDesc* varFromParam = AsGenericVariable();
689
690 if (!varFromParam->ConstraintsLoaded())
691 varFromParam->LoadConstraints(CLASS_DEPENDENCIES_LOADED);
692
693 // A generic type parameter cannot be compatible with another type
694 // as it could be substitued with a valuetype. However, if it is
695 // constrained to a reference type, then we can use CanCastTo.
696 if (varFromParam->ConstrainedAsObjRef())
697 return CanCastTo(type, pPairList);
698 }
699
700 return FALSE;
701}
702
703//--------------------------------------------------------------------------------------
704// CanCastTo is necessary but not sufficient, as it assumes that any valuetype
705// involved is in its boxed form. See IsBoxedAndCanCastTo() if the valuetype
706// is not guaranteed to be in its boxed form.
707
708BOOL TypeHandle::CanCastTo(TypeHandle type, TypeHandlePairList *pVisited) const
709{
710 CONTRACTL
711 {
712 THROWS;
713 GC_TRIGGERS;
714 INJECT_FAULT(COMPlusThrowOM());
715
716 LOADS_TYPE(CLASS_DEPENDENCIES_LOADED);
717 }
718 CONTRACTL_END
719
720 if (*this == type)
721 return(true);
722
723 if (IsTypeDesc())
724 return AsTypeDesc()->CanCastTo(type, pVisited);
725
726 if (type.IsTypeDesc())
727 return(false);
728
729 return AsMethodTable()->CanCastToClassOrInterface(type.AsMethodTable(), pVisited);
730}
731
732#include <optsmallperfcritical.h>
733TypeHandle::CastResult TypeHandle::CanCastToNoGC(TypeHandle type) const
734{
735 LIMITED_METHOD_CONTRACT;
736
737 if (*this == type)
738 return(CanCast);
739
740 if (IsTypeDesc())
741 return AsTypeDesc()->CanCastToNoGC(type);
742
743 if (type.IsTypeDesc())
744 return(CannotCast);
745
746 return AsMethodTable()->CanCastToClassOrInterfaceNoGC(type.AsMethodTable());
747}
748#include <optdefault.h>
749
750#endif // #ifndef DACCESS_COMPILE
751
752void TypeHandle::GetName(SString &result) const
753{
754 CONTRACTL
755 {
756 THROWS;
757 GC_NOTRIGGER;
758 SO_TOLERANT;
759 INJECT_FAULT(COMPlusThrowOM(););
760 }
761 CONTRACTL_END
762
763 INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(goto Exit;);
764 {
765
766 if (IsTypeDesc())
767 {
768 AsTypeDesc()->GetName(result);
769 goto Exit;
770 }
771
772 AsMethodTable()->_GetFullyQualifiedNameForClass(result);
773
774 // Tack the instantiation on the end
775 Instantiation inst = GetInstantiation();
776 if (!inst.IsEmpty())
777 TypeString::AppendInst(result, inst);
778 }
779Exit:
780 ;
781 END_INTERIOR_STACK_PROBE;
782}
783
784TypeHandle TypeHandle::GetParent() const
785{
786 STATIC_CONTRACT_NOTHROW;
787 STATIC_CONTRACT_GC_NOTRIGGER;
788 STATIC_CONTRACT_FORBID_FAULT;
789 STATIC_CONTRACT_SO_TOLERANT;
790
791 if (IsTypeDesc())
792 return(AsTypeDesc()->GetParent());
793 else
794 return TypeHandle(AsMethodTable()->GetParentMethodTable());
795}
796#ifndef DACCESS_COMPILE
797
798/* static */
799TypeHandle TypeHandle::MergeClassWithInterface(TypeHandle tClass, TypeHandle tInterface)
800{
801 CONTRACTL
802 {
803 THROWS;
804 GC_TRIGGERS;
805 INJECT_FAULT(COMPlusThrowOM());
806 }
807 CONTRACTL_END
808
809 MethodTable *pMTClass = tClass.AsMethodTable();
810
811 // Check if the class implements the interface
812 if (pMTClass->ImplementsEquivalentInterface(tInterface.AsMethodTable()))
813 {
814 // The class implements the interface or its equivalent, so our merged state should be the interface
815 return tInterface;
816 }
817
818 // Check if the class and the interface implement a common interface
819 MethodTable *pMTInterface = tInterface.AsMethodTable();
820 MethodTable::InterfaceMapIterator intIt = pMTInterface->IterateInterfaceMap();
821 while (intIt.Next())
822 {
823 MethodTable *pMT = intIt.GetInterface();
824 if (pMTClass->ImplementsEquivalentInterface(pMT))
825 {
826 // Found a common interface. If there are multiple common interfaces, then
827 // the problem is ambiguous so we'll just take the first one--it's the best
828 // we can do. If an ensuing code path relies on another common interface,
829 // the verifier will think the code is unverifiable, but it would require a
830 // major redesign of the verifier to fix that.
831 return TypeHandle(pMT);
832 }
833 }
834
835 // No compatible merge found - using Object
836 return TypeHandle(g_pObjectClass);
837}
838
839/* static */
840TypeHandle TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle ta, TypeHandle tb)
841{
842 CONTRACTL
843 {
844 THROWS;
845 GC_TRIGGERS;
846 INJECT_FAULT(COMPlusThrowOM());
847 }
848 CONTRACTL_END
849
850 _ASSERTE(!ta.IsNull() && !tb.IsNull());
851
852 if (ta == tb)
853 return ta;
854
855 // Handle the array case
856 if (ta.IsArray())
857 {
858 if (tb.IsArray())
859 return MergeArrayTypeHandlesToCommonParent(ta, tb);
860 else if (tb.IsInterface())
861 {
862 //Check to see if we can merge the array to a common interface (such as Derived[] and IList<Base>)
863 if (ArraySupportsBizarreInterface(ta.AsArray(), tb.AsMethodTable()))
864 return tb;
865 }
866 ta = TypeHandle(g_pArrayClass); // keep merging from here.
867 }
868 else if (tb.IsArray())
869 {
870 if (ta.IsInterface() && ArraySupportsBizarreInterface(tb.AsArray(), ta.AsMethodTable()))
871 return ta;
872
873 tb = TypeHandle(g_pArrayClass);
874 }
875
876
877 // If either is a (by assumption boxed) type variable
878 // return the supertype, if they are related, or object if they are incomparable.
879 if (ta.IsGenericVariable() || tb.IsGenericVariable())
880 {
881 if (ta.CanCastTo(tb))
882 return tb;
883 if (tb.CanCastTo(ta))
884 return ta;
885 return TypeHandle(g_pObjectClass);
886 }
887
888
889 _ASSERTE(!ta.IsTypeDesc() && !tb.IsTypeDesc());
890
891
892 MethodTable *pMTa = ta.AsMethodTable();
893 MethodTable *pMTb = tb.AsMethodTable();
894
895 if (pMTb->IsInterface())
896 {
897
898 if (pMTa->IsInterface())
899 {
900 //
901 // Both classes are interfaces. Check that if one
902 // interface extends the other.
903 //
904 // Does tb extend ta ?
905 //
906
907 if (pMTb->ImplementsEquivalentInterface(pMTa))
908 {
909 // tb extends ta, so our merged state should be ta
910 return ta;
911 }
912
913 //
914 // Does tb extend ta ?
915 //
916 if (pMTa->ImplementsEquivalentInterface(pMTb))
917 {
918 // ta extends tb, so our merged state should be tb
919 return tb;
920 }
921
922 // No compatible merge found - using Object
923 return TypeHandle(g_pObjectClass);
924 }
925 else
926 return MergeClassWithInterface(ta, tb);
927 }
928 else if (pMTa->IsInterface())
929 return MergeClassWithInterface(tb, ta);
930
931 DWORD aDepth = 0;
932 DWORD bDepth = 0;
933 TypeHandle tSearch;
934
935 // find the depth in the class hierarchy for each class
936 for (tSearch = ta; (!tSearch.IsNull()); tSearch = tSearch.GetParent())
937 aDepth++;
938
939 for (tSearch = tb; (!tSearch.IsNull()); tSearch = tSearch.GetParent())
940 bDepth++;
941
942 // for whichever class is lower down in the hierarchy, walk up the superclass chain
943 // to the same level as the other class
944 while (aDepth > bDepth)
945 {
946 ta = ta.GetParent();
947 aDepth--;
948 }
949
950 while (bDepth > aDepth)
951 {
952 tb = tb.GetParent();
953 bDepth--;
954 }
955
956 while (!ta.IsEquivalentTo(tb))
957 {
958 ta = ta.GetParent();
959 tb = tb.GetParent();
960 }
961
962 // If no compatible merge is found, we end up using Object
963
964 _ASSERTE(!ta.IsNull());
965
966 return ta;
967}
968
969/* static */
970TypeHandle TypeHandle::MergeArrayTypeHandlesToCommonParent(TypeHandle ta, TypeHandle tb)
971{
972 CONTRACTL
973 {
974 THROWS;
975 GC_TRIGGERS;
976 INJECT_FAULT(COMPlusThrowOM());
977 }
978 CONTRACTL_END
979
980 CorElementType taKind = ta.GetInternalCorElementType();
981 CorElementType tbKind = tb.GetInternalCorElementType();
982 _ASSERTE(CorTypeInfo::IsArray(taKind) && CorTypeInfo::IsArray(tbKind));
983
984 TypeHandle taElem;
985 TypeHandle tMergeElem;
986
987 // If they match we are good to go.
988 if (ta == tb)
989 return ta;
990
991 if (ta == TypeHandle(g_pArrayClass))
992 return ta;
993 else if (tb == TypeHandle(g_pArrayClass))
994 return tb;
995
996 // Get the rank and kind of the first array
997 DWORD rank = ta.AsArray()->GetRank();
998 CorElementType mergeKind = taKind;
999
1000 // if no match on the rank the common ancestor is System.Array
1001 if (rank != tb.AsArray()->GetRank())
1002 return TypeHandle(g_pArrayClass);
1003
1004 if (tbKind != taKind)
1005 {
1006 if (CorTypeInfo::IsArray(tbKind) &&
1007 CorTypeInfo::IsArray(taKind) && rank == 1)
1008 mergeKind = ELEMENT_TYPE_ARRAY;
1009 else
1010 return TypeHandle(g_pArrayClass);
1011 }
1012
1013 // If both are arrays of reference types, return an array of the common
1014 // ancestor.
1015 taElem = ta.AsArray()->GetArrayElementTypeHandle();
1016 if (taElem.IsEquivalentTo(tb.AsArray()->GetArrayElementTypeHandle()))
1017 {
1018 // The element types match/are equivalent, so we are good to go.
1019 tMergeElem = taElem;
1020 }
1021 else if (taElem.IsArray() && tb.AsArray()->GetArrayElementTypeHandle().IsArray())
1022 {
1023 // Arrays - Find the common ancestor of the element types.
1024 tMergeElem = MergeArrayTypeHandlesToCommonParent(taElem, tb.AsArray()->GetArrayElementTypeHandle());
1025 }
1026 else if (CorTypeInfo::IsObjRef(taElem.GetSignatureCorElementType()) &&
1027 CorTypeInfo::IsObjRef(tb.AsArray()->GetArrayElementTypeHandle().GetSignatureCorElementType()))
1028 {
1029 // Find the common ancestor of the element types.
1030 tMergeElem = MergeTypeHandlesToCommonParent(taElem, tb.AsArray()->GetArrayElementTypeHandle());
1031 }
1032 else
1033 {
1034 // The element types have nothing in common.
1035 return TypeHandle(g_pArrayClass);
1036 }
1037
1038
1039 {
1040 // This should just result in resolving an already loaded type.
1041 ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
1042 // == FailIfNotLoadedOrNotRestored
1043 TypeHandle result = ClassLoader::LoadArrayTypeThrowing(tMergeElem, mergeKind, rank, ClassLoader::DontLoadTypes);
1044 _ASSERTE(!result.IsNull());
1045
1046 // <TODO> should be able to assert IsRestored here </TODO>
1047 return result;
1048 }
1049}
1050
1051#endif // #ifndef DACCESS_COMPILE
1052
1053BOOL TypeHandle::IsEnum() const
1054{
1055 LIMITED_METHOD_CONTRACT;
1056
1057 return (!IsTypeDesc() && AsMethodTable()->IsEnum());
1058}
1059
1060BOOL TypeHandle::IsFnPtrType() const
1061{
1062 LIMITED_METHOD_DAC_CONTRACT;
1063
1064 return (IsTypeDesc() &&
1065 (GetSignatureCorElementType() == ELEMENT_TYPE_FNPTR));
1066}
1067
1068BOOL TypeHandle::IsRestored_NoLogging() const
1069{
1070 LIMITED_METHOD_CONTRACT;
1071
1072 if (!IsTypeDesc())
1073 {
1074 return GetMethodTable()->IsRestored_NoLogging();
1075 }
1076 else
1077 {
1078 return AsTypeDesc()->IsRestored_NoLogging();
1079 }
1080}
1081
1082BOOL TypeHandle::IsRestored() const
1083{
1084 LIMITED_METHOD_DAC_CONTRACT;
1085
1086 if (!IsTypeDesc())
1087 {
1088 return GetMethodTable()->IsRestored();
1089 }
1090 else
1091 {
1092 return AsTypeDesc()->IsRestored();
1093 }
1094}
1095
1096BOOL TypeHandle::IsEncodedFixup() const
1097{
1098 LIMITED_METHOD_DAC_CONTRACT;
1099
1100 return CORCOMPILE_IS_POINTER_TAGGED(m_asTAddr);
1101}
1102
1103BOOL TypeHandle::HasUnrestoredTypeKey() const
1104{
1105 WRAPPER_NO_CONTRACT;
1106 SUPPORTS_DAC;
1107
1108 if (IsTypeDesc())
1109 return AsTypeDesc()->HasUnrestoredTypeKey();
1110 else
1111 return AsMethodTable()->HasUnrestoredTypeKey();
1112}
1113
1114#ifdef FEATURE_PREJIT
1115void TypeHandle::DoRestoreTypeKey()
1116{
1117 CONTRACT_VOID
1118 {
1119 THROWS;
1120 GC_TRIGGERS;
1121 PRECONDITION(!IsEncodedFixup());
1122 }
1123 CONTRACT_END
1124
1125#ifndef DACCESS_COMPILE
1126 if (IsTypeDesc())
1127 {
1128 AsTypeDesc()->DoRestoreTypeKey();
1129 }
1130
1131 if (!IsTypeDesc() || IsArray())
1132 {
1133 MethodTable* pMT = GetMethodTable();
1134 PREFIX_ASSUME(pMT != NULL);
1135 pMT->DoRestoreTypeKey();
1136 }
1137#endif
1138
1139#ifdef _DEBUG
1140#ifndef DACCESS_COMPILE
1141 if (LoggingOn(LF_CLASSLOADER, LL_INFO10000))
1142 {
1143 StackSString name;
1144 TypeString::AppendTypeDebug(name, *this);
1145 LOG((LF_CLASSLOADER, LL_INFO10000, "GENERICS:RestoreTypeKey: type %S at %p\n", name.GetUnicode(), AsPtr()));
1146 }
1147#endif
1148#endif
1149
1150
1151 RETURN;
1152}
1153#endif
1154
1155void TypeHandle::CheckRestore() const
1156{
1157 CONTRACTL
1158 {
1159 if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
1160 if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
1161 PRECONDITION(!IsEncodedFixup());
1162 }
1163 CONTRACTL_END
1164
1165 if (!IsFullyLoaded())
1166 {
1167 ClassLoader::EnsureLoaded(*this);
1168 _ASSERTE(IsFullyLoaded());
1169 }
1170
1171 g_IBCLogger.LogTypeMethodTableAccess(this);
1172}
1173
1174#ifndef DACCESS_COMPILE
1175
1176#ifdef FEATURE_NATIVE_IMAGE_GENERATION
1177BOOL TypeHandle::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited) const
1178{
1179 STATIC_STANDARD_VM_CONTRACT;
1180
1181 _ASSERTE(GetAppDomain()->IsCompilationDomain());
1182
1183 if (!IsTypeDesc())
1184 return GetMethodTable()->ComputeNeedsRestore(image, pVisited);
1185 else
1186 return AsTypeDesc()->ComputeNeedsRestore(image, pVisited);
1187}
1188#endif // FEATURE_NATIVE_IMAGE_GENERATION
1189
1190BOOL
1191TypeHandle::IsExternallyVisible() const
1192{
1193 CONTRACTL
1194 {
1195 THROWS;
1196 GC_TRIGGERS;
1197 MODE_ANY;
1198 }
1199 CONTRACTL_END
1200
1201 if (!IsTypeDesc())
1202 {
1203 return AsMethodTable()->IsExternallyVisible();
1204 }
1205
1206 if (IsGenericVariable())
1207 { // VAR, MVAR
1208 return TRUE;
1209 }
1210
1211 if (IsFnPtrType())
1212 { // FNPTR
1213 // Function pointer has to check its all argument types
1214 return AsFnPtrType()->IsExternallyVisible();
1215 }
1216 // ARRAY, SZARRAY, PTR, BYREF
1217 _ASSERTE(HasTypeParam());
1218
1219 TypeHandle paramType = AsTypeDesc()->GetTypeParam();
1220 _ASSERTE(!paramType.IsNull());
1221
1222 return paramType.IsExternallyVisible();
1223} // TypeHandle::IsExternallyVisible
1224
1225#ifndef CROSSGEN_COMPILE
1226OBJECTREF TypeHandle::GetManagedClassObject() const
1227{
1228 CONTRACTL
1229 {
1230 THROWS;
1231 GC_TRIGGERS;
1232 MODE_COOPERATIVE;
1233
1234 INJECT_FAULT(COMPlusThrowOM());
1235 }
1236 CONTRACTL_END;
1237
1238#ifdef _DEBUG
1239 // Force a GC here because GetManagedClassObject could trigger GC nondeterminsticaly
1240 GCStress<cfg_any, PulseGcTriggerPolicy>::MaybeTrigger();
1241#endif // _DEBUG
1242
1243 if (!IsTypeDesc())
1244 {
1245 return AsMethodTable()->GetManagedClassObject();
1246 }
1247 else
1248 {
1249 switch(GetInternalCorElementType())
1250 {
1251 case ELEMENT_TYPE_ARRAY:
1252 case ELEMENT_TYPE_SZARRAY:
1253 case ELEMENT_TYPE_BYREF:
1254 case ELEMENT_TYPE_PTR:
1255 return ((ParamTypeDesc*)AsTypeDesc())->GetManagedClassObject();
1256
1257 case ELEMENT_TYPE_VAR:
1258 case ELEMENT_TYPE_MVAR:
1259 return ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObject();
1260
1261 // for this release a function pointer is mapped into an IntPtr. This result in a loss of information. Fix next release
1262 case ELEMENT_TYPE_FNPTR:
1263 return MscorlibBinder::GetElementType(ELEMENT_TYPE_I)->GetManagedClassObject();
1264
1265 default:
1266 _ASSERTE(!"Bad Element Type");
1267 return NULL;
1268 }
1269 }
1270}
1271
1272
1273OBJECTREF TypeHandle::GetManagedClassObjectFast() const
1274{
1275 CONTRACTL {
1276 NOTHROW;
1277 GC_NOTRIGGER;
1278 MODE_ANY;
1279 SO_TOLERANT;
1280
1281 FORBID_FAULT;
1282 }
1283 CONTRACTL_END;
1284
1285 OBJECTREF o = NULL;
1286
1287 if (!IsTypeDesc()) {
1288 o = AsMethodTable()->GetManagedClassObjectIfExists();
1289 }
1290 else
1291 {
1292 switch(GetInternalCorElementType())
1293 {
1294 case ELEMENT_TYPE_ARRAY:
1295 case ELEMENT_TYPE_SZARRAY:
1296 case ELEMENT_TYPE_BYREF:
1297 case ELEMENT_TYPE_PTR:
1298 o = ((ParamTypeDesc*)AsTypeDesc())->GetManagedClassObjectFast();
1299 break;
1300
1301 case ELEMENT_TYPE_VAR:
1302 case ELEMENT_TYPE_MVAR:
1303 o = ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObjectFast();
1304 break;
1305
1306 // for this release a function pointer is mapped into an IntPtr. This result in a loss of information. Fix next release
1307 case ELEMENT_TYPE_FNPTR:
1308 // because TheFnPtrClass() can throw we return NULL for now. That is not a major deal because it just means we will
1309 // not take advantage of this optimization, but the case is rather rare.
1310 //o = TheFnPtrClass()->GetManagedClassObjectFast();
1311 break;
1312
1313 default:
1314 _ASSERTE(!"Bad Element Type");
1315 return NULL;
1316 }
1317 }
1318 return o;
1319}
1320#endif // CROSSGEN_COMPILE
1321
1322#endif // #ifndef DACCESS_COMPILE
1323
1324BOOL TypeHandle::IsByRef() const
1325{
1326 LIMITED_METHOD_CONTRACT;
1327
1328 return(IsTypeDesc() && AsTypeDesc()->IsByRef());
1329
1330}
1331
1332BOOL TypeHandle::IsByRefLike() const
1333{
1334 LIMITED_METHOD_CONTRACT;
1335
1336 return(!IsTypeDesc() && AsMethodTable()->IsByRefLike());
1337
1338}
1339
1340BOOL TypeHandle::IsPointer() const
1341{
1342 LIMITED_METHOD_CONTRACT;
1343
1344 return(IsTypeDesc() && AsTypeDesc()->IsPointer());
1345
1346}
1347
1348//
1349// The internal type is the type that most of the runtime cares about. This type has had two normalizations
1350// applied to it
1351//
1352// * Enumerated type have been normalized to the primitive type that underlies them (typically int)
1353// * Value types that look like ints (which include RuntimeTypeHandles, etc), have been morphed to be
1354// their underlying type (much like enumeration types. See
1355// * see code:MethodTable#KindsOfElementTypes for more
1356// * This value is set by code:EEClass::ComputeInternalCorElementTypeForValueType
1357CorElementType TypeHandle::GetInternalCorElementType() const
1358{
1359 LIMITED_METHOD_DAC_CONTRACT;
1360
1361 if (IsTypeDesc())
1362 return AsTypeDesc()->GetInternalCorElementType();
1363 else
1364 return AsMethodTable()->GetInternalCorElementType();
1365}
1366
1367BOOL TypeHandle::HasInstantiation() const
1368{
1369 LIMITED_METHOD_DAC_CONTRACT;
1370
1371 if (IsTypeDesc()) return false;
1372 if (IsNull()) return false;
1373 return AsMethodTable()->HasInstantiation();
1374}
1375
1376ClassLoadLevel TypeHandle::GetLoadLevel() const
1377{
1378 LIMITED_METHOD_DAC_CONTRACT;
1379
1380 if (IsTypeDesc())
1381 {
1382 return AsTypeDesc()->GetLoadLevel();
1383 }
1384 else
1385 {
1386 return AsMethodTable()->GetLoadLevel();
1387 }
1388}
1389
1390BOOL TypeHandle::IsFullyLoaded() const
1391{
1392 LIMITED_METHOD_CONTRACT;
1393
1394 if (IsTypeDesc())
1395 {
1396 return AsTypeDesc()->IsFullyLoaded();
1397 }
1398 else
1399 {
1400 return AsMethodTable()->IsFullyLoaded();
1401 }
1402}
1403
1404void TypeHandle::DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level,
1405 DFLPendingList *pPending, BOOL *pfBailed, const InstantiationContext *pInstContext)
1406{
1407 CONTRACTL
1408 {
1409 THROWS;
1410 GC_TRIGGERS;
1411 MODE_ANY;
1412 }
1413 CONTRACTL_END;
1414
1415 _ASSERTE(level == CLASS_LOADED || level == CLASS_DEPENDENCIES_LOADED);
1416 _ASSERTE(pfBailed != NULL);
1417 _ASSERTE(!(level == CLASS_LOADED && pPending == NULL));
1418
1419
1420 if (IsTypeDesc())
1421 {
1422 return AsTypeDesc()->DoFullyLoad(pVisited, level, pPending, pfBailed, pInstContext);
1423 }
1424 else
1425 {
1426 return AsMethodTable()->DoFullyLoad(pVisited, level, pPending, pfBailed, pInstContext);
1427 }
1428}
1429
1430// As its name suggests, this returns the type as it is in the meta-data signature. No morphing to deal
1431// with verification or with value types that are treated as primitives is done.
1432// see code:MethodTable#KindsOfElementTypes for more
1433CorElementType TypeHandle::GetSignatureCorElementType() const
1434{
1435 LIMITED_METHOD_DAC_CONTRACT;
1436
1437 // This gets used by
1438 // MethodTable::DoRestoreTypeKey() -->
1439 // Module::RestoreMethodTablePointer() -->
1440 // ZapSig::DecodeType() -->
1441 // SigPointer::GetTypeHandleThrowing -->
1442 // TypeHandle::GetSignatureCorElementType
1443 // early on during the process of restoring, i.e. after the EEClass for the
1444 // MT is restored but not the parent method table. Thus we cannot
1445 // assume that the parent method table is even yet a valid pointer.
1446 // However both MethodTable::GetClass and MethodTable::IsValueType work
1447 // even if the parent method table pointer has not been restored.
1448
1449 if (IsTypeDesc())
1450 {
1451 return AsTypeDesc()->GetInternalCorElementType();
1452 }
1453 else
1454 {
1455 return AsMethodTable()->GetSignatureCorElementType();
1456 }
1457}
1458
1459// As its name suggests, this returns the type used by the IL verifier. The basic difference between this
1460// type and the type in the meta-data is that enumerations have been normalized to their underlieing
1461// primitive type. see code:MethodTable#KindsOfElementTypes for more
1462CorElementType TypeHandle::GetVerifierCorElementType() const
1463{
1464 LIMITED_METHOD_CONTRACT;
1465
1466 if (IsTypeDesc())
1467 {
1468 return AsTypeDesc()->GetInternalCorElementType();
1469 }
1470 else
1471 {
1472 return AsMethodTable()->GetVerifierCorElementType();
1473 }
1474}
1475
1476
1477#ifdef DACCESS_COMPILE
1478
1479void
1480TypeHandle::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
1481{
1482 SUPPORTS_DAC;
1483 if (!m_asTAddr)
1484 {
1485 return;
1486 }
1487
1488 CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED
1489 (
1490 if (IsArray())
1491 {
1492 AsArray()->EnumMemoryRegions(flags);
1493 }
1494 else if (IsGenericVariable())
1495 {
1496 AsGenericVariable()->EnumMemoryRegions(flags);
1497 }
1498 else if (IsFnPtrType())
1499 {
1500 AsFnPtrType()->EnumMemoryRegions(flags);
1501 }
1502 else if (IsTypeDesc())
1503 {
1504 DacEnumMemoryRegion(dac_cast<TADDR>(AsTypeDesc()), sizeof(TypeDesc));
1505 }
1506 else
1507 {
1508 GetMethodTable()->EnumMemoryRegions(flags);
1509 }
1510 );
1511}
1512
1513#endif // DACCESS_COMPILE
1514
1515
1516
1517//--------------------------------------------------------------------------------------
1518// For generic instantiations, check that it satisfies constraints.
1519//
1520// Because this is really a part of DoFullyLoad() that is broken out for readability reasons,
1521// it takes both the typehandle and its template typehandle as a parameter (DoFullyLoad
1522// already has the latter typehandle so this way, we avoid a second call to the loader.)
1523//
1524// Return value:
1525//
1526// Returns TRUE if constraints are satisfied.
1527//
1528// Returns FALSE if constraints are violated and the type is a canonical instantiation. (We
1529// have to let these load as these form the basis of every instantiation. The canonical
1530// methodtable is not available to users.
1531//
1532// THROWS if constraints are violated
1533//
1534//
1535//--------------------------------------------------------------------------------------
1536BOOL SatisfiesClassConstraints(TypeHandle instanceTypeHnd, TypeHandle typicalTypeHnd,
1537 const InstantiationContext *pInstContext)
1538{
1539 CONTRACTL
1540 {
1541 THROWS;
1542 GC_TRIGGERS;
1543 PRECONDITION(!instanceTypeHnd.IsCanonicalSubtype());
1544 }
1545 CONTRACTL_END;
1546
1547#ifndef DACCESS_COMPILE
1548
1549 Instantiation formalInst = typicalTypeHnd.GetInstantiation();
1550 Instantiation actualInst = instanceTypeHnd.GetInstantiation();
1551 _ASSERTE(formalInst.GetNumArgs() == actualInst.GetNumArgs());
1552
1553 for (DWORD i = 0; i < actualInst.GetNumArgs(); i++)
1554 {
1555 TypeHandle thActualArg = actualInst[i];
1556
1557 SigTypeContext typeContext;
1558 SigTypeContext::InitTypeContext(instanceTypeHnd, &typeContext);
1559
1560 // Log the TypeVarTypeDesc access
1561 g_IBCLogger.LogTypeMethodTableWriteableAccess(&thActualArg);
1562
1563 BOOL bSatisfiesConstraints =
1564 formalInst[i].AsGenericVariable()->SatisfiesConstraints(&typeContext, thActualArg, pInstContext);
1565
1566 if (!bSatisfiesConstraints)
1567 {
1568 SString argNum;
1569 argNum.Printf("%d", i);
1570
1571 SString typicalTypeHndName;
1572 TypeString::AppendType(typicalTypeHndName, typicalTypeHnd);
1573
1574 SString actualParamName;
1575 TypeString::AppendType(actualParamName, actualInst[i]);
1576
1577 SString formalParamName;
1578 TypeString::AppendType(formalParamName, formalInst[i]);
1579
1580 COMPlusThrow(kTypeLoadException,
1581 IDS_EE_CLASS_CONSTRAINTS_VIOLATION,
1582 argNum,
1583 actualParamName,
1584 typicalTypeHndName,
1585 formalParamName
1586 );
1587 }
1588 }
1589
1590 return TRUE;
1591
1592#else
1593 return TRUE;
1594#endif
1595}
1596
1597
1598
1599
1600#ifndef DACCESS_COMPILE
1601BOOL TypeHandle::SatisfiesClassConstraints() const
1602{
1603 CONTRACTL
1604 {
1605 THROWS;
1606 GC_TRIGGERS;
1607 MODE_ANY;
1608 SO_INTOLERANT;
1609
1610 INJECT_FAULT(COMPlusThrowOM());
1611 }
1612 CONTRACTL_END;
1613
1614 BOOL returnValue = FALSE;
1615 Instantiation classInst;
1616 TypeHandle thCanonical;
1617 Instantiation typicalInst;
1618 SigTypeContext typeContext;
1619 TypeHandle thParent;
1620
1621 INTERIOR_STACK_PROBE_CHECK_THREAD;
1622
1623 //TODO: cache (positive?) result in methodtable using, say, enum_flag2_UNUSEDxxx
1624
1625 //TODO: reconsider this check
1626 thParent = GetParent();
1627
1628 if (!thParent.IsNull() && !thParent.SatisfiesClassConstraints())
1629 {
1630 returnValue = FALSE;
1631 goto Exit;
1632 }
1633
1634 if (!HasInstantiation())
1635 {
1636 returnValue = TRUE;
1637 goto Exit;
1638 }
1639
1640 classInst = GetInstantiation();
1641 thCanonical = ClassLoader::LoadTypeDefThrowing(
1642 GetModule(),
1643 GetCl(),
1644 ClassLoader::ThrowIfNotFound,
1645 ClassLoader::PermitUninstDefOrRef);
1646 typicalInst = thCanonical.GetInstantiation();
1647
1648 SigTypeContext::InitTypeContext(*this, &typeContext);
1649
1650 for (DWORD i = 0; i < classInst.GetNumArgs(); i++)
1651 {
1652 TypeHandle thArg = classInst[i];
1653 _ASSERTE(!thArg.IsNull());
1654
1655 TypeVarTypeDesc* tyvar = typicalInst[i].AsGenericVariable();
1656 _ASSERTE(tyvar != NULL);
1657 _ASSERTE(TypeFromToken(tyvar->GetTypeOrMethodDef()) == mdtTypeDef);
1658
1659 tyvar->LoadConstraints(); //TODO: is this necessary for anything but the typical class?
1660
1661 if (!tyvar->SatisfiesConstraints(&typeContext, thArg))
1662 {
1663 returnValue = FALSE;
1664 goto Exit;
1665 }
1666
1667 }
1668 returnValue = TRUE;
1669Exit:
1670 ;
1671 END_INTERIOR_STACK_PROBE;
1672
1673 return returnValue;
1674}
1675
1676TypeKey TypeHandle::GetTypeKey() const
1677{
1678 LIMITED_METHOD_CONTRACT;
1679 STATIC_CONTRACT_SO_TOLERANT;
1680 PRECONDITION(!IsGenericVariable());
1681
1682 if (IsTypeDesc())
1683 {
1684 TypeDesc *pTD = AsTypeDesc();
1685 CorElementType etype = pTD->GetInternalCorElementType();
1686 if (CorTypeInfo::IsArray_NoThrow(etype))
1687 {
1688 TypeKey tk(etype, pTD->GetTypeParam(), FALSE, pTD->GetMethodTable()->GetRank());
1689 return tk;
1690 }
1691 else if (CorTypeInfo::IsModifier_NoThrow(etype) || etype == ELEMENT_TYPE_VALUETYPE)
1692 {
1693 TypeKey tk(etype, pTD->GetTypeParam());
1694 return tk;
1695 }
1696 else
1697 {
1698 CONSISTENCY_CHECK(etype == ELEMENT_TYPE_FNPTR);
1699 FnPtrTypeDesc* pFTD = (FnPtrTypeDesc*) pTD;
1700 TypeKey tk(pFTD->GetCallConv(), pFTD->GetNumArgs(), pFTD->GetRetAndArgTypesPointer());
1701 return tk;
1702 }
1703 }
1704 else
1705 {
1706 MethodTable *pMT = AsMethodTable();
1707 if (pMT->IsArray())
1708 {
1709 TypeKey tk(pMT->GetInternalCorElementType(), pMT->GetApproxArrayElementTypeHandle(), TRUE, pMT->GetRank());
1710 return tk;
1711 }
1712 else if (pMT->IsTypicalTypeDefinition())
1713 {
1714 TypeKey tk(pMT->GetModule(), pMT->GetCl());
1715 return tk;
1716 }
1717 else
1718 {
1719 TypeKey tk(pMT->GetModule(), pMT->GetCl(), pMT->GetInstantiation());
1720 return tk;
1721 }
1722 }
1723}
1724
1725
1726#ifdef _DEBUG
1727// Check that a type handle matches the key provided
1728CHECK TypeHandle::CheckMatchesKey(TypeKey *pKey) const
1729{
1730 WRAPPER_NO_CONTRACT;
1731 CONTRACT_VIOLATION(TakesLockViolation); // this is debug-only code
1732 CONSISTENCY_CHECK(!IsGenericVariable());
1733
1734 // Check first to avoid creating debug name
1735 if (!GetTypeKey().Equals(pKey))
1736 {
1737 StackSString typeKeyString;
1738 CONTRACT_VIOLATION(GCViolation|ThrowsViolation);
1739 TypeString::AppendTypeKeyDebug(typeKeyString, pKey);
1740 if (!IsTypeDesc() && AsMethodTable()->IsArray())
1741 {
1742 MethodTable *pMT = AsMethodTable();
1743 CHECK_MSGF(pMT->GetInternalCorElementType() == pKey->GetKind(),
1744 ("CorElementType %d of Array MethodTable does not match key %S", pMT->GetArrayElementType(), typeKeyString.GetUnicode()));
1745
1746 CHECK_MSGF(pMT->GetApproxArrayElementTypeHandle() == pKey->GetElementType(),
1747 ("Element type of Array MethodTable does not match key %S",typeKeyString.GetUnicode()));
1748
1749 CHECK_MSGF(pMT->GetRank() == pKey->GetRank(),
1750 ("Rank %d of Array MethodTable does not match key %S", pMT->GetRank(), typeKeyString.GetUnicode()));
1751 }
1752 else
1753 if (IsTypeDesc())
1754 {
1755 TypeDesc *pTD = AsTypeDesc();
1756 CHECK_MSGF(pTD->GetInternalCorElementType() == pKey->GetKind(),
1757 ("CorElementType %d of TypeDesc does not match key %S", pTD->GetInternalCorElementType(), typeKeyString.GetUnicode()));
1758
1759 if (CorTypeInfo::IsModifier(pKey->GetKind()))
1760 {
1761 CHECK_MSGF(pTD->GetTypeParam() == pKey->GetElementType(),
1762 ("Element type of TypeDesc does not match key %S",typeKeyString.GetUnicode()));
1763 }
1764 if (CorTypeInfo::IsArray(pKey->GetKind()))
1765 {
1766 CHECK_MSGF(pTD->GetMethodTable()->GetRank() == pKey->GetRank(),
1767 ("Rank %d of array TypeDesc does not match key %S", pTD->GetMethodTable()->GetRank(), typeKeyString.GetUnicode()));
1768 }
1769 }
1770 else
1771 {
1772 MethodTable *pMT = AsMethodTable();
1773 CHECK_MSGF(pMT->GetModule() == pKey->GetModule(), ("Module of MethodTable does not match key %S", typeKeyString.GetUnicode()));
1774 CHECK_MSGF(pMT->GetCl() == pKey->GetTypeToken(),
1775 ("TypeDef %x of Methodtable does not match TypeDef %x of key %S", pMT->GetCl(), pKey->GetTypeToken(),
1776 typeKeyString.GetUnicode()));
1777
1778 if (pMT->IsTypicalTypeDefinition())
1779 {
1780 CHECK_MSGF(pKey->GetNumGenericArgs() == 0 && !pKey->HasInstantiation(),
1781 ("Key %S for Typical MethodTable has non-zero number of generic arguments", typeKeyString.GetUnicode()));
1782 }
1783 else
1784 {
1785 CHECK_MSGF(pMT->GetNumGenericArgs() == pKey->GetNumGenericArgs(),
1786 ("Number of generic params %d in MethodTable does not match key %S", pMT->GetNumGenericArgs(), typeKeyString.GetUnicode()));
1787 if (pKey->HasInstantiation())
1788 {
1789 for (DWORD i = 0; i < pMT->GetNumGenericArgs(); i++)
1790 {
1791#ifdef FEATURE_PREJIT
1792 CHECK_MSGF(ZapSig::CompareTypeHandleFieldToTypeHandle(pMT->GetInstantiation().GetRawArgs()[i].GetValuePtr(), pKey->GetInstantiation()[i]),
1793 ("Generic argument %d in MethodTable does not match key %S", i, typeKeyString.GetUnicode()));
1794#else
1795 CHECK_MSGF(pMT->GetInstantiation()[i] == pKey->GetInstantiation()[i],
1796 ("Generic argument %d in MethodTable does not match key %S", i, typeKeyString.GetUnicode()));
1797#endif
1798 }
1799 }
1800 }
1801 }
1802 }
1803 CHECK_OK;
1804}
1805
1806const char * const classLoadLevelName[] =
1807{
1808 "BEGIN",
1809 "UNRESTOREDTYPEKEY",
1810 "UNRESTORED",
1811 "APPROXPARENTS",
1812 "EXACTPARENTS",
1813 "DEPENDENCIES_LOADED",
1814 "LOADED",
1815};
1816
1817// Check that this type is loaded up to the level indicated
1818// Also check that it is non-null
1819CHECK TypeHandle::CheckLoadLevel(ClassLoadLevel requiredLevel)
1820{
1821 CHECK(!IsNull());
1822 // CHECK_MSGF(!IsNull(), ("Type is null, required load level is %s", classLoadLevelName[requiredLevel]));
1823 static_assert_no_msg(NumItems(classLoadLevelName) == (1 + CLASS_LOAD_LEVEL_FINAL));
1824
1825 // Quick check to avoid creating debug string
1826 ClassLoadLevel actualLevel = GetLoadLevel();
1827 if (actualLevel < requiredLevel)
1828 {
1829 // SString debugTypeName;
1830 // TypeString::AppendTypeDebug(debugTypeName, *this);
1831 CHECK(actualLevel >= requiredLevel);
1832 // CHECK_MSGF(actualLevel >= requiredLevel,
1833 // ("Type has not been sufficiently loaded (actual level is %d, required level is %d)",
1834 // /* debugTypeName.GetUnicode(), */ actualLevel, requiredLevel /* classLoadLevelName[actualLevel], classLoadLevelName[requiredLevel] */));
1835 }
1836 CONSISTENCY_CHECK((actualLevel > CLASS_LOAD_UNRESTORED) == IsRestored());
1837 CONSISTENCY_CHECK((actualLevel == CLASS_LOAD_UNRESTOREDTYPEKEY) == HasUnrestoredTypeKey());
1838 CHECK_OK;
1839}
1840
1841// Check that this type is fully loaded (i.e. to level CLASS_LOADED)
1842CHECK TypeHandle::CheckFullyLoaded()
1843{
1844 CONTRACTL
1845 {
1846 NOTHROW;
1847 GC_NOTRIGGER;
1848 SO_TOLERANT;
1849 MODE_ANY;
1850 }
1851 CONTRACTL_END;
1852 if (IsGenericVariable())
1853 {
1854 CHECK_OK;
1855 }
1856 CheckLoadLevel(CLASS_LOADED);
1857 CHECK_OK;
1858}
1859
1860#endif //DEBUG
1861
1862#endif //DACCESS_COMPILE
1863