[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / typehandle.h
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.h
6 //
7
8
9 //
10
11 //
12 // ============================================================================
13
14
15 #ifndef TYPEHANDLE_H
16 #define TYPEHANDLE_H
17
18 #include "check.h"
19 #include "classloadlevel.h"
20 #include "fixuppointer.h"
21
22 class TypeDesc;
23 class TypeHandle;
24 class Instantiation;
25 class ArrayTypeDesc;
26 class FnPtrTypeDesc;
27 class ParamTypeDesc;
28 class TypeVarTypeDesc;
29 class MethodTable;
30 class EEClass;
31 class Module;
32 class Assembly;
33 class BaseDomain;
34 class MethodDesc;
35 class TypeKey;
36 class TypeHandleList;
37 class InstantiationContext;
38 class DataImage;
39 namespace Generics { class RecursionGraph; }
40 struct CORINFO_CLASS_STRUCT_;
41
42 typedef DPTR(class TypeVarTypeDesc) PTR_TypeVarTypeDesc;
43 typedef SPTR(class FnPtrTypeDesc) PTR_FnPtrTypeDesc;
44 typedef DPTR(class ParamTypeDesc) PTR_ParamTypeDesc;
45 typedef DPTR(class ArrayTypeDesc) PTR_ArrayTypeDesc;
46 typedef DPTR(class TypeDesc) PTR_TypeDesc;
47 typedef DPTR(class TypeHandle) PTR_TypeHandle;
48
49
50 typedef CUnorderedArray<TypeHandle, 40> DFLPendingList;
51
52 class TypeHandlePairList;
53
54 #ifdef FEATURE_COMINTEROP
55 class ComCallWrapperTemplate;
56 #endif // FEATURE_COMINTEROP
57
58 /*************************************************************************/
59 // A TypeHandle is the FUNDAMENTAL concept of type identity in the CLR.
60 // That is two types are equal if and only if their type handles
61 // are equal.  A TypeHandle, is a pointer sized struture that encodes 
62 // everything you need to know to figure out what kind of type you are
63 // actually dealing with.  
64
65 // At the present time a TypeHandle can point at two possible things
66 //
67 //      1) A MethodTable    (Intrinsics, Classes, Value Types and their instantiations)
68 //      2) A TypeDesc       (all other cases: arrays, byrefs, pointer types, function pointers, generic type variables)  
69 //
70 // or with IL stubs, a third thing:
71 //
72 //      3) A MethodTable for a native value type.
73 //
74 // Array MTs are not valid TypeHandles: for example no allocated object will
75 // ever return such a type handle from Object::GetTypeHandle(), and
76 // these type handles should not be passed across the JIT Interface
77 // as CORINFO_CLASS_HANDLEs.  However some code in the EE does create 
78 // temporary TypeHandles out of these MTs, so we can't yet assert 
79 // !pMT->IsArray() in the TypeHandle constructor.
80 //
81 // Wherever possible, you should be using TypeHandles or MethodTables.
82 // Code that is known to work over Class/ValueClass types (including their
83 // instantaitions) is currently written to use MethodTables.
84 //
85 // TypeDescs in turn break down into several variants and are
86 // for special cases around the edges
87 //    - array types whose method tables get share
88 //    - types for function pointers for verification and reflection
89 //    - types for generic parameters for verification and reflection
90 //
91 // Generic type instantiations (in C# syntax: C<ty_1,...,ty_n>) are represented by
92 // MethodTables, i.e. a new MethodTable gets allocated for each such instantiation.
93 // The entries in these tables (i.e. the code) are, however, often shared.
94 // Clients of TypeHandle don't need to know any of this detail; just use the
95 // GetInstantiation and HasInstantiation methods.
96
97 class TypeHandle 
98 {
99 public:
100     TypeHandle() { 
101         LIMITED_METHOD_DAC_CONTRACT;
102
103         m_asTAddr = 0; 
104     }
105
106     static TypeHandle FromPtr(PTR_VOID aPtr)
107     { 
108         LIMITED_METHOD_DAC_CONTRACT;
109
110         return TypeHandle(dac_cast<TADDR>(aPtr));
111     }
112     // Create a TypeHandle from the target address of a MethodTable
113     static TypeHandle FromTAddr(TADDR data)
114     { 
115         LIMITED_METHOD_DAC_CONTRACT;
116
117         return TypeHandle(data);
118     }
119
120     // When you ask for a class in JitInterface when all you have
121     // is a methodDesc of an array method...
122     // Convert from a JitInterface handle to an internal EE TypeHandle
123     explicit TypeHandle(struct CORINFO_CLASS_STRUCT_*aPtr)
124     {
125         LIMITED_METHOD_DAC_CONTRACT;
126
127         m_asTAddr = dac_cast<TADDR>(aPtr);
128         // NormalizeUnsharedArrayMT();
129         INDEBUGIMPL(Verify());
130     }
131
132     TypeHandle(MethodTable const * aMT) {
133         LIMITED_METHOD_DAC_CONTRACT;
134
135         m_asTAddr = dac_cast<TADDR>(aMT); 
136         // NormalizeUnsharedArrayMT();
137         INDEBUGIMPL(Verify());
138     }
139
140     explicit TypeHandle(TypeDesc *aType) {
141         LIMITED_METHOD_DAC_CONTRACT;
142         _ASSERTE(aType);
143
144         m_asTAddr = (dac_cast<TADDR>(aType) | 2); 
145         INDEBUGIMPL(Verify());
146     }
147
148     inline BOOL IsNativeValueType() const;
149     inline MethodTable *AsNativeValueType() const;
150
151 private:
152     // This constructor has been made private.  You must use the explicit static functions
153     // TypeHandle::FromPtr and TypeHandle::TAddr instead of these constructors.  
154     // Allowing a public constructor that takes a "void *" or a "TADDR" is error-prone.
155     explicit TypeHandle(TADDR aTAddr)
156     { 
157         LIMITED_METHOD_DAC_CONTRACT;
158         m_asTAddr = aTAddr;
159         // NormalizeUnsharedArrayMT();
160         INDEBUGIMPL(Verify());
161     }
162
163     
164 public:
165     FORCEINLINE int operator==(const TypeHandle& typeHnd) const {
166         LIMITED_METHOD_DAC_CONTRACT;
167
168         return(m_asTAddr == typeHnd.m_asTAddr);
169     }
170
171     FORCEINLINE int operator!=(const TypeHandle& typeHnd) const {
172         LIMITED_METHOD_DAC_CONTRACT;
173
174         return(m_asTAddr != typeHnd.m_asTAddr);
175     }
176
177         // Methods for probing exactly what kind of a type handle we have
178     FORCEINLINE BOOL IsNull() const { 
179         LIMITED_METHOD_DAC_CONTRACT;
180 #ifdef _PREFIX_
181         if (m_asTAddr == 0) {
182 #ifndef DACCESS_COMPILE
183             PREFIX_ASSUME(m_asPtr == NULL);
184 #endif
185             return true;
186         }
187         else {
188 #ifndef DACCESS_COMPILE
189             PREFIX_ASSUME(m_asPtr != NULL);
190 #endif
191             return false;
192         }            
193 #else
194         return(m_asTAddr == 0); 
195 #endif
196     }
197
198     // Note that this returns denormalized BOOL to help the compiler with optimizations
199     FORCEINLINE BOOL IsTypeDesc() const  {
200         LIMITED_METHOD_DAC_CONTRACT;
201 #ifdef _PREFIX_
202         if (m_asTAddr & 2) {
203             PREFIX_ASSUME(m_asTAddr != NULL);
204 #ifndef DACCESS_COMPILE
205             PREFIX_ASSUME(m_asPtr   != NULL);
206 #endif
207             return true;
208         }
209         else {
210             return false;
211         }            
212 #else
213         return(m_asTAddr & 2);
214 #endif
215     }
216
217     BOOL IsEnum() const;
218
219     BOOL IsFnPtrType() const;
220                              
221     inline PTR_MethodTable AsMethodTable() const;
222
223     inline PTR_TypeDesc AsTypeDesc() const;
224
225     // To the extent possible, you should try to use methods like the ones
226     // below that treat all types uniformly.
227
228     // Gets the size that this type would take up embedded in another object
229     // thus objects all return sizeof(void*).  
230     unsigned GetSize() const;
231
232     // Returns the type name, including the generic instantiation if possible.
233     // See the TypeString class for better control over name formatting.
234     void GetName(SString &result) const;
235
236     // Returns the ELEMENT_TYPE_* that you would use in a signature
237     // The only normalization that happens is that for type handles
238     // for instantiated types (e.g. class List<String> or
239     // value type Pair<int,int>)) this returns either ELEMENT_TYPE_CLASS
240     // or ELEMENT_TYPE_VALUE, _not_ ELEMENT_TYPE_WITH.
241     CorElementType GetSignatureCorElementType() const;
242          
243     // This helper:
244     // - Will return enums underlying type
245     // - Will return underlying primitive for System.Int32 etc...
246     // - Will return underlying primitive as will be used in the calling convention
247     //      For example
248     //              struct t
249     //              {
250     //                  public int i;
251     //              }
252     //      will return ELEMENT_TYPE_I4 in x86 instead of ELEMENT_TYPE_VALUETYPE. We
253     //      call this type of value type a primitive value type
254     //
255     // Internal representation is used among another things for the calling convention
256     // (jit benefits of primitive value types) or optimizing marshalling.
257     //
258     // This will NOT convert E_T_ARRAY, E_T_SZARRAY etc. to E_T_CLASS (though it probably
259     // should).  Use CorTypeInfo::IsObjRef for that.
260     CorElementType GetInternalCorElementType() const; 
261
262     // This helper will return the same as GetSignatureCorElementType except:
263     // - Will return enums underlying type
264     CorElementType GetVerifierCorElementType() const;
265
266     //-------------------------------------------------------------------
267     // CASTING
268     // 
269     // There are two variants of the "CanCastTo" method:
270     //
271     // CanCastTo
272     // - restore encoded pointers on demand
273     // - might throw, might trigger GC
274     // - return type is boolean (FALSE = cannot cast, TRUE = can cast)
275     //
276     // CanCastToNoGC
277     // - do not restore encoded pointers on demand
278     // - does not throw, does not trigger GC
279     // - return type is three-valued (CanCast, CannotCast, MaybeCast)
280     // - MaybeCast indicates that the test tripped on an encoded pointer
281     //   so the caller should now call CanCastTo if it cares
282     //
283     // Note that if the TypeHandle is a valuetype, the caller is responsible
284     // for checking that the valuetype is in its boxed form before calling
285     // CanCastTo. Otherwise, the caller should be using IsBoxedAndCanCastTo()
286     typedef enum { CannotCast, CanCast, MaybeCast } CastResult;
287
288     BOOL CanCastTo(TypeHandle type, TypeHandlePairList *pVisited = NULL) const;
289     BOOL IsBoxedAndCanCastTo(TypeHandle type, TypeHandlePairList *pVisited) const;
290     CastResult CanCastToNoGC(TypeHandle type) const;
291
292 #ifndef DACCESS_COMPILE
293     // Type equivalence based on Guid and TypeIdentifier attributes
294     inline BOOL IsEquivalentTo(TypeHandle type COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL)) const;
295 #endif
296
297     // Get the parent, known to be decoded
298     TypeHandle GetParent() const;
299
300     // Obtain element type for an array or pointer, returning NULL otherwise
301     TypeHandle GetTypeParam() const;
302
303     // Obtain instantiation from an instantiated type
304     // NULL if not instantiated
305     Instantiation GetInstantiation() const;
306
307     // Does this type satisfy its class constraints, recursively up the hierarchy
308     BOOL SatisfiesClassConstraints() const;
309
310     TypeHandle Instantiate(Instantiation inst) const;
311     TypeHandle MakePointer() const;
312     TypeHandle MakeByRef() const;
313     TypeHandle MakeSZArray() const;
314     TypeHandle MakeArray(int rank) const;
315     TypeHandle MakeNativeValueType() const;
316
317     // Obtain instantiation from an instantiated type *or* a pointer to the element type for an array 
318     Instantiation GetClassOrArrayInstantiation() const;
319
320     // Is this type instantiated?
321     BOOL HasInstantiation() const;
322
323     // Is this a generic type whose type arguments are its formal type parameters?
324     BOOL IsGenericTypeDefinition() const;
325
326     // Is this either a non-generic type (e.g. a non-genric class type or an array type or a pointer type etc.)
327     // or a generic type whose type arguments are its formal type parameters?
328     //Equivalent to (!HasInstantiation() || IsGenericTypeDefinition());
329     inline BOOL IsTypicalTypeDefinition() const;     
330
331     enum InteropKind
332     {
333         Interop_ManagedToNative, // use for RCW-related queries
334         Interop_NativeToManaged, // use for CCW-related queries
335     };
336
337     inline BOOL SupportsGenericInterop(InteropKind interopKind) const;
338
339     BOOL IsSharedByGenericInstantiations() const;
340
341     // Recursively search the type arguments and if
342     // one of the type arguments is Canon then return TRUE
343     //
344     // A<__Canon>    is the canonical TypeHandle (aka "representative" generic MT)
345     // A<B<__Canon>> is a subtype that contains a Canonical type
346     //
347     BOOL IsCanonicalSubtype() const;
348
349     // Similar to IsCanonicalSubtype, but applied to a vector.
350     static BOOL IsCanonicalSubtypeInstantiation(Instantiation inst);
351
352     // For an uninstantiated generic type, return the number of type parameters required for instantiation
353     // For an instantiated type, return the number of type parameters in the instantiation
354     // Otherwise return 0
355     DWORD GetNumGenericArgs() const;
356
357     BOOL IsValueType() const;
358     BOOL IsInterface() const;
359     BOOL IsAbstract() const;
360
361     inline DWORD IsObjectType() const
362     {
363         LIMITED_METHOD_CONTRACT;
364         return *this == TypeHandle(g_pObjectClass);
365     }
366
367     // Retrieve the key corresponding to this handle
368     TypeKey GetTypeKey() const;
369
370     // To what level has this type been loaded?
371     ClassLoadLevel GetLoadLevel() const;
372
373     // Equivalent to GetLoadLevel() == CLASS_LOADED
374     BOOL IsFullyLoaded() const;
375
376     void DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level, DFLPendingList *pPending, BOOL *pfBailed,
377                      const InstantiationContext *pInstContext);
378
379     inline void SetIsFullyLoaded();
380
381  
382 #ifdef _DEBUG
383     // Check that this type matches the key given 
384     // i.e. that all aspects (element type, module/token, rank for arrays, instantiation for generic types) match up
385     CHECK CheckMatchesKey(TypeKey *pKey) const;
386
387     // Check that this type is loaded up to the level indicated
388     // Also check that it is non-null
389     CHECK CheckLoadLevel(ClassLoadLevel level);
390
391     // Equivalent to CheckLoadLevel(CLASS_LOADED)
392     CHECK CheckFullyLoaded();
393 #endif
394
395     bool IsHFA() const;   
396     CorElementType GetHFAType() const;
397
398 #ifdef FEATURE_64BIT_ALIGNMENT
399     bool RequiresAlign8() const;
400 #endif // FEATURE_64BIT_ALIGNMENT
401
402 #ifndef DACCESS_COMPILE
403
404     BOOL IsBlittable() const;
405     BOOL HasLayout() const;
406     
407 #ifdef FEATURE_COMINTEROP
408     TypeHandle GetCoClassForInterface() const;
409     DWORD IsComClassInterface() const;
410     BOOL IsComObjectType() const;
411     BOOL IsComEventItfType() const;
412     CorIfaceAttr GetComInterfaceType() const;
413     TypeHandle GetDefItfForComClassItf() const;
414
415     BOOL IsProjectedFromWinRT() const;
416     BOOL IsExportedToWinRT() const;
417
418     ComCallWrapperTemplate *GetComCallWrapperTemplate() const;
419     BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate);
420 #endif // FEATURE_COMINTEROP
421
422 #endif 
423
424     // Unlike AsMethodTable, GetMethodTable will get the method table
425     // of the type, regardless of whether it is an array etc. Note, however
426     // this method table may be shared, and some types (like TypeByRef), have
427     // no method table (and this function returns NULL for them)
428     inline PTR_MethodTable GetMethodTable() const;
429
430     // Returns the method table which should be used for visibility checking.
431     // Like GetMethodTable except for TypeDescs returns the root ElementType.
432     // So for Foo[] instead of returning Array returns Foo. 
433     inline MethodTable* GetMethodTableOfElementType() const;
434
435     // Returns the MethodTable for the SZARRAY or ARRAY type
436     inline MethodTable * GetPossiblySharedArrayMethodTable() const;
437
438     // As above but returns a TypeHandle (so it will return a non-null result
439     // for generic type variables, for instance).
440     inline TypeHandle GetElementType() const;
441
442     // Return the canonical representative MT amongst the set of MT's that share
443     // code with the MT for the given TypeHandle because of generics.
444     PTR_MethodTable GetCanonicalMethodTable() const;
445
446     // The module that defined the underlying type
447     // (First strip off array/ptr qualifiers and generic type arguments)
448     PTR_Module GetModule() const;
449
450     // The ngen'ed module where this type lives
451     PTR_Module GetZapModule() const;
452
453     // Does this immediate item live in an NGEN module?
454     BOOL IsZapped() const;
455
456     // The module where this type lives for the purposes of loading and prejitting
457     // Note: NGen time result might differ from runtime result for parametrized types (generics, arrays, etc.)
458     // See code:ClassLoader::ComputeLoaderModule or file:clsload.hpp#LoaderModule for more information
459     PTR_Module GetLoaderModule() const;
460
461     // The assembly that defined this type (== GetModule()->GetAssembly())
462     Assembly * GetAssembly() const;
463
464     // GetDomain on an instantiated type, e.g. C<ty1,ty2> returns the SharedDomain if all the
465     // constituent parts of the type are SharedDomain (i.e. domain-neutral), 
466     // and returns an AppDomain if any of the parts are from an AppDomain, 
467     // i.e. are domain-bound.  If any of the parts are domain-bound
468     // then they will all belong to the same domain.
469     PTR_BaseDomain GetDomain() const;
470
471     PTR_LoaderAllocator GetLoaderAllocator() const;
472
473     // Get the class token, assuming the type handle represents a named type,
474     // i.e. a class, a value type, a generic instantiation etc.
475     inline mdTypeDef GetCl() const;
476
477     // Shortcuts
478
479     // ARRAY or SZARRAY TypeDesc (arrays with a shared MethodTable)
480     // If this is TRUE, it is OK to call AsArray()
481     // Also see IsArrayType()
482     BOOL IsArray() const;
483
484     // See comment of IsArrayType() for the explanation of this method
485 #if 0
486     void NormalizeUnsharedArrayMT();
487 #endif
488
489     // ARRAY or SZARRAY
490     // Note that this does not imply that it is OK to call AsArray(). See IsArray()
491     //
492     // All arrays, even those with a unique unshared MethodTable, have an ArrayTypeDesc
493     // which is used for type identity. However, over time, people have started
494     // wrapping the MethodTables directly in a TypeHandle. Note that such 
495     // TypeHandles cannot be used for type identity. However, IsArrayType() lets
496     // you check even for such cases where IsArray() returns FALSE, but the type
497     // still is an array type.
498     //
499     // @TODO: Change all the constructors of TypeHandle which take a MethodTable 
500     // to call NormalizeUnsharedArrayMT(). TypeHandle::Verify() can then enforce
501     // that IsArray() is fully correct.
502     BOOL IsArrayType() const;
503
504     // VAR or MVAR
505     BOOL IsGenericVariable() const;
506
507     // BYREF
508     BOOL IsByRef() const;
509
510     // BYREFLIKE (does not return TRUE for IsByRef types)
511     BOOL IsByRefLike() const;
512
513     // PTR
514     BOOL IsPointer() const;
515
516     // True if this type *is* a formal generic type parameter or any component of it is a formal generic type parameter
517     BOOL ContainsGenericVariables(BOOL methodOnly=FALSE) const;
518
519     Module* GetDefiningModuleForOpenType() const;    
520
521     // Is actually ParamTypeDesc (ARRAY, SZARRAY, BYREF, PTR)
522     BOOL HasTypeParam() const;
523
524     BOOL IsRestored_NoLogging() const;
525     BOOL IsRestored() const;
526
527     // Does this type have zap-encoded components (generic arguments, etc)?
528     BOOL HasUnrestoredTypeKey() const;
529
530     // True if this type handle is a zap-encoded fixup
531     BOOL IsEncodedFixup() const;
532
533     // Only used at NGEN-time
534     BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited) const;
535
536     void DoRestoreTypeKey();    
537
538     void CheckRestore() const;
539     BOOL IsExternallyVisible() const;
540
541     // Does this type participate in type equivalence?
542     inline BOOL HasTypeEquivalence() const;
543
544     // Not clear we should have this.  
545     inline PTR_ArrayTypeDesc AsArray() const;
546     
547     FnPtrTypeDesc* AsFnPtrType() const;
548     
549     TypeVarTypeDesc* AsGenericVariable() const;
550     
551     Instantiation GetInstantiationOfParentClass(MethodTable *pWhichParent) const;
552
553     PTR_VOID AsPtr() const {                     // Please don't use this if you can avoid it
554         LIMITED_METHOD_DAC_CONTRACT;
555
556         return(PTR_VOID(m_asTAddr)); 
557     }
558
559     TADDR AsTAddr() const {       
560         LIMITED_METHOD_DAC_CONTRACT;
561
562         return m_asTAddr;
563     }
564
565     INDEBUGIMPL(BOOL Verify();)             // DEBUGGING Make certain this is a valid type handle 
566
567 #ifdef DACCESS_COMPILE
568     void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
569 #endif
570     
571     OBJECTREF GetManagedClassObject() const;
572     OBJECTREF GetManagedClassObjectFast() const;
573     
574     static TypeHandle MergeArrayTypeHandlesToCommonParent(
575         TypeHandle ta, TypeHandle tb);
576
577     static TypeHandle MergeTypeHandlesToCommonParent(
578         TypeHandle ta, TypeHandle tb);
579
580
581     BOOL NotifyDebuggerLoad(AppDomain *domain, BOOL attaching) const;
582     void NotifyDebuggerUnload(AppDomain *domain) const;
583
584     // Execute the callback functor for each MethodTable that makes up the given type handle.  This method
585     // does not invoke the functor for generic variables
586     template<class T>
587     inline void ForEachComponentMethodTable(T &callback) const;
588
589 private:
590     static TypeHandle MergeClassWithInterface(
591         TypeHandle tClass, TypeHandle tInterface);
592
593     union 
594     {
595         TADDR               m_asTAddr;      // we look at the low order bits
596 #ifndef DACCESS_COMPILE
597         void *              m_asPtr;
598         PTR_MethodTable     m_asMT;
599         PTR_TypeDesc        m_asTypeDesc;
600         PTR_ArrayTypeDesc   m_asArrayTypeDesc;
601         PTR_ParamTypeDesc   m_asParamTypeDesc;
602         PTR_TypeVarTypeDesc m_asTypeVarTypeDesc;
603         PTR_FnPtrTypeDesc   m_asFnPtrTypeDesc;
604 #endif
605     };
606 };
607
608 class TypeHandleList
609 {
610     TypeHandle m_typeHandle;
611     TypeHandleList* m_pNext;
612     bool m_fBrokenCycle;
613  public:
614     TypeHandleList(TypeHandle t, TypeHandleList* pNext) : m_typeHandle(t),m_pNext(pNext),m_fBrokenCycle(false) { };
615     static BOOL Exists(TypeHandleList* pList, TypeHandle t)
616     {
617         LIMITED_METHOD_CONTRACT;
618         while (pList != NULL) { if (pList->m_typeHandle == t) return TRUE; pList = pList->m_pNext; }
619         return FALSE;
620     }
621
622     // Supports enumeration of the list.
623     static BOOL GetNext(TypeHandleList** ppList, TypeHandle* pHandle)
624     {
625         LIMITED_METHOD_CONTRACT;
626         if (*ppList != NULL)
627         {
628             *pHandle = (*ppList)->m_typeHandle;
629             (*ppList) = (*ppList)->m_pNext;
630             return TRUE;
631         }
632         return FALSE;
633     }
634
635     void MarkBrokenCycle(TypeHandle th)
636     {
637         LIMITED_METHOD_CONTRACT;
638         TypeHandleList* pList = this;
639         while (pList->m_typeHandle != th) { pList->m_fBrokenCycle = true; pList = pList->m_pNext; }
640     }
641     bool HasBrokenCycleMark()
642     {
643         LIMITED_METHOD_CONTRACT;
644         return m_fBrokenCycle;
645     }
646 };
647
648 class TypeHandlePairList // TODO: Template for TypeHandleList, TypeHandlePairList, TokenPairList?
649 {
650     TypeHandle m_typeHandle1;
651     TypeHandle m_typeHandle2;
652     TypeHandlePairList *m_pNext;
653 public:
654     TypeHandlePairList(TypeHandle t1, TypeHandle t2, TypeHandlePairList *pNext) : m_typeHandle1(t1), m_typeHandle2(t2), m_pNext(pNext) { };
655     static BOOL Exists(TypeHandlePairList *pList, TypeHandle t1, TypeHandle t2)
656     {
657         LIMITED_METHOD_CONTRACT;
658         while (pList != NULL)
659         {
660             if (pList->m_typeHandle1 == t1 && pList->m_typeHandle2 == t2)
661                 return TRUE;
662             if (pList->m_typeHandle1 == t2 && pList->m_typeHandle2 == t1)
663                 return TRUE;
664
665             pList = pList->m_pNext;
666         }
667         return FALSE;
668     }
669 };
670
671 #if CHECK_INVARIANTS
672 inline CHECK CheckPointer(TypeHandle th, IsNullOK ok = NULL_NOT_OK)
673 {
674     STATIC_CONTRACT_NOTHROW;
675     STATIC_CONTRACT_GC_NOTRIGGER;
676     STATIC_CONTRACT_FORBID_FAULT;
677     SUPPORTS_DAC;
678     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
679
680     if (th.IsNull())
681     {
682         CHECK_MSG(ok, "Illegal null TypeHandle");
683     }
684     else
685     {
686         __if_exists(TypeHandle::Check)
687         {
688             CHECK(th.Check());
689         }
690 #if 0
691         CHECK(CheckInvariant(o));
692 #endif
693     }
694
695     CHECK_OK;
696 }
697
698 #endif  // CHECK_INVARIANTS
699
700 /*************************************************************************/
701 // dac_casts for TypeHandle makes FixupPointer<TypeHandle> work.
702 //
703 // TypeHandle is wrapper around pointer to MethodTable or TypeDesc. Even though
704 // it may feel counterintuitive, it is possible to treat it like a pointer and
705 // use the regular FixupPointer to implement TypeHandle indirection cells.
706 // The lowest bit of TypeHandle (when wrapped inside FixupPointer) is 
707 // used to mark optional indirection.
708 //
709 template<>
710 inline TADDR dac_cast(TypeHandle src)
711 {
712     SUPPORTS_DAC;
713     return src.AsTAddr();
714 }
715
716 template<>
717 inline TypeHandle dac_cast(TADDR src)
718 {
719     SUPPORTS_DAC;
720     return TypeHandle::FromTAddr(src);
721 }
722
723 /*************************************************************************/
724 // Instantiation is representation of generic instantiation. 
725 // It is simple read-only array of TypeHandles. In NGen, the type handles
726 // may be encoded using indirections. That's one reason why it is convenient
727 // to have wrapper class that performs the decoding.
728 class Instantiation
729 {
730 public:
731     // Construct empty instantiation
732     Instantiation()
733         : m_pArgs(NULL), m_nArgs(0)
734     {
735         LIMITED_METHOD_DAC_CONTRACT;
736     }
737
738     // Copy construct
739     Instantiation(const Instantiation & inst)
740         : m_pArgs(inst.m_pArgs), m_nArgs(inst.m_nArgs)
741     {
742         LIMITED_METHOD_DAC_CONTRACT;
743         _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
744     }
745
746     // Construct instantiation from array of FixupPointers
747     Instantiation(FixupPointer<TypeHandle> * pArgs, DWORD nArgs)
748         : m_pArgs(pArgs), m_nArgs(nArgs)
749     {
750         LIMITED_METHOD_DAC_CONTRACT;
751         _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
752     }
753
754     // Construct instantiation from array of TypeHandles
755     Instantiation(TypeHandle * pArgs, DWORD nArgs)
756         : m_nArgs(nArgs)
757     {
758         LIMITED_METHOD_DAC_CONTRACT;
759
760         DACCOP_IGNORE(CastOfMarshalledType, "Dual mode DAC problem, but since the size is the same, the cast is safe");
761         m_pArgs = (FixupPointer<TypeHandle> *)pArgs;
762         _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
763     }
764
765 #ifdef DACCESS_COMPILE
766     // Construct instantiation from target array of FixupPointers in DAC.
767     // This method will create local copy of the instantiation arguments.
768     Instantiation(DPTR(FixupPointer<TypeHandle>) pArgs, DWORD nArgs)
769     {
770         LIMITED_METHOD_DAC_CONTRACT;
771
772         // Create a local copy of the instanitation under DAC
773         PVOID pLocalArgs = PTR_READ(dac_cast<TADDR>(pArgs), nArgs * sizeof(TypeHandle));
774         m_pArgs = (FixupPointer<TypeHandle> *)pLocalArgs;
775
776         m_nArgs = nArgs;
777
778         _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
779     }
780 #endif
781
782     // Return i-th instantiation argument
783     TypeHandle operator[](DWORD iArg) const
784     {
785         LIMITED_METHOD_DAC_CONTRACT;
786         _ASSERTE(iArg < m_nArgs);
787         return m_pArgs[iArg].GetValue();
788     }
789
790     DWORD GetNumArgs() const
791     {
792         LIMITED_METHOD_DAC_CONTRACT;
793         return m_nArgs;
794     }
795
796     BOOL IsEmpty() const
797     {
798         LIMITED_METHOD_DAC_CONTRACT;
799         return m_nArgs == 0;
800     }
801
802     // Unsafe access to the instantiation. Do not use unless absolutely necessary!!!
803     FixupPointer<TypeHandle> * GetRawArgs() const
804     {
805         LIMITED_METHOD_DAC_CONTRACT;
806         return m_pArgs;
807     }
808
809 private:
810     // Note that for DAC builds, m_pArgs may be host allocated buffer, not a copy of an object marshalled by DAC.
811     FixupPointer<TypeHandle> * m_pArgs;
812     DWORD m_nArgs;
813 };
814
815 #endif // TYPEHANDLE_H