summaryrefslogtreecommitdiff
path: root/src/vm/typehandle.h
blob: 9e373df86d911cd3fdb916ea89862eb99760a0a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//
// File: typehandle.h
//


//

//
// ============================================================================


#ifndef TYPEHANDLE_H
#define TYPEHANDLE_H

#include "check.h"
#include "classloadlevel.h"
#include "fixuppointer.h"

class TypeDesc;
class TypeHandle;
class Instantiation;
class ArrayTypeDesc;
class FnPtrTypeDesc;
class ParamTypeDesc;
class TypeVarTypeDesc;
class MethodTable;
class EEClass;
class Module;
class Assembly;
class BaseDomain;
class MethodDesc;
class TypeKey;
class TypeHandleList;
class InstantiationContext;
class DataImage;
namespace Generics { class RecursionGraph; }
struct CORINFO_CLASS_STRUCT_;

typedef DPTR(class TypeVarTypeDesc) PTR_TypeVarTypeDesc;
typedef SPTR(class FnPtrTypeDesc) PTR_FnPtrTypeDesc;
typedef DPTR(class ParamTypeDesc) PTR_ParamTypeDesc;
typedef DPTR(class ArrayTypeDesc) PTR_ArrayTypeDesc;
typedef DPTR(class TypeDesc) PTR_TypeDesc;
typedef DPTR(class TypeHandle) PTR_TypeHandle;


typedef CUnorderedArray<TypeHandle, 40> DFLPendingList;

class TypeHandlePairList;

#ifdef FEATURE_COMINTEROP
class ComCallWrapperTemplate;
#endif // FEATURE_COMINTEROP

/*************************************************************************/
// A TypeHandle is the FUNDAMENTAL concept of type identity in the CLR.
// That is two types are equal if and only if their type handles
// are equal.  A TypeHandle, is a pointer sized struture that encodes 
// everything you need to know to figure out what kind of type you are
// actually dealing with.  

// At the present time a TypeHandle can point at two possible things
//
//      1) A MethodTable    (Intrinsics, Classes, Value Types and their instantiations)
//      2) A TypeDesc       (all other cases: arrays, byrefs, pointer types, function pointers, generic type variables)  
//
// or with IL stubs, a third thing:
//
//      3) A MethodTable for a native value type.
//
// Array MTs are not valid TypeHandles: for example no allocated object will
// ever return such a type handle from Object::GetTypeHandle(), and
// these type handles should not be passed across the JIT Interface
// as CORINFO_CLASS_HANDLEs.  However some code in the EE does create 
// temporary TypeHandles out of these MTs, so we can't yet assert 
// !pMT->IsArray() in the TypeHandle constructor.
//
// Wherever possible, you should be using TypeHandles or MethodTables.
// Code that is known to work over Class/ValueClass types (including their
// instantaitions) is currently written to use MethodTables.
//
// TypeDescs in turn break down into several variants and are
// for special cases around the edges
//    - array types whose method tables get share
//    - types for function pointers for verification and reflection
//    - types for generic parameters for verification and reflection
//
// Generic type instantiations (in C# syntax: C<ty_1,...,ty_n>) are represented by
// MethodTables, i.e. a new MethodTable gets allocated for each such instantiation.
// The entries in these tables (i.e. the code) are, however, often shared.
// Clients of TypeHandle don't need to know any of this detail; just use the
// GetInstantiation and HasInstantiation methods.

class TypeHandle 
{
public:
    TypeHandle() { 
        LIMITED_METHOD_DAC_CONTRACT;

        m_asTAddr = 0; 
    }

    static TypeHandle FromPtr(PTR_VOID aPtr)
    { 
        LIMITED_METHOD_DAC_CONTRACT;

        return TypeHandle(dac_cast<TADDR>(aPtr));
    }
    // Create a TypeHandle from the target address of a MethodTable
    static TypeHandle FromTAddr(TADDR data)
    { 
        LIMITED_METHOD_DAC_CONTRACT;

        return TypeHandle(data);
    }

    // When you ask for a class in JitInterface when all you have
    // is a methodDesc of an array method...
    // Convert from a JitInterface handle to an internal EE TypeHandle
    explicit TypeHandle(struct CORINFO_CLASS_STRUCT_*aPtr)
    {
        LIMITED_METHOD_DAC_CONTRACT;

        m_asTAddr = dac_cast<TADDR>(aPtr);
        // NormalizeUnsharedArrayMT();
        INDEBUGIMPL(Verify());
    }

    TypeHandle(MethodTable const * aMT) {
        LIMITED_METHOD_DAC_CONTRACT;

        m_asTAddr = dac_cast<TADDR>(aMT); 
        // NormalizeUnsharedArrayMT();
        INDEBUGIMPL(Verify());
    }

    explicit TypeHandle(TypeDesc *aType) {
        LIMITED_METHOD_DAC_CONTRACT;
        _ASSERTE(aType);

        m_asTAddr = (dac_cast<TADDR>(aType) | 2); 
        INDEBUGIMPL(Verify());
    }

    inline BOOL IsNativeValueType() const;
    inline MethodTable *AsNativeValueType() const;

private:
    // This constructor has been made private.  You must use the explicit static functions
    // TypeHandle::FromPtr and TypeHandle::TAddr instead of these constructors.  
    // Allowing a public constructor that takes a "void *" or a "TADDR" is error-prone.
    explicit TypeHandle(TADDR aTAddr)
    { 
        LIMITED_METHOD_DAC_CONTRACT;
        m_asTAddr = aTAddr;
        // NormalizeUnsharedArrayMT();
        INDEBUGIMPL(Verify());
    }

    
public:
    FORCEINLINE int operator==(const TypeHandle& typeHnd) const {
        LIMITED_METHOD_DAC_CONTRACT;

        return(m_asTAddr == typeHnd.m_asTAddr);
    }

    FORCEINLINE int operator!=(const TypeHandle& typeHnd) const {
        LIMITED_METHOD_DAC_CONTRACT;

        return(m_asTAddr != typeHnd.m_asTAddr);
    }

        // Methods for probing exactly what kind of a type handle we have
    FORCEINLINE BOOL IsNull() const { 
        LIMITED_METHOD_DAC_CONTRACT;
#ifdef _PREFIX_
        if (m_asTAddr == 0) {
#ifndef DACCESS_COMPILE
            PREFIX_ASSUME(m_asPtr == NULL);
#endif
            return true;
        }
        else {
#ifndef DACCESS_COMPILE
            PREFIX_ASSUME(m_asPtr != NULL);
#endif
            return false;
        }            
#else
        return(m_asTAddr == 0); 
#endif
    }

    // Note that this returns denormalized BOOL to help the compiler with optimizations
    FORCEINLINE BOOL IsTypeDesc() const  {
        LIMITED_METHOD_DAC_CONTRACT;
#ifdef _PREFIX_
        if (m_asTAddr & 2) {
            PREFIX_ASSUME(m_asTAddr != NULL);
#ifndef DACCESS_COMPILE
            PREFIX_ASSUME(m_asPtr   != NULL);
#endif
            return true;
        }
        else {
            return false;
        }            
#else
        return(m_asTAddr & 2);
#endif
    }

    BOOL IsEnum() const;

    BOOL IsFnPtrType() const;
                             
    inline PTR_MethodTable AsMethodTable() const;

    inline PTR_TypeDesc AsTypeDesc() const;

    // To the extent possible, you should try to use methods like the ones
    // below that treat all types uniformly.

    // Gets the size that this type would take up embedded in another object
    // thus objects all return sizeof(void*).  
    unsigned GetSize() const;

    // Returns the type name, including the generic instantiation if possible.
    // See the TypeString class for better control over name formatting.
    void GetName(SString &result) const;

    // Returns the ELEMENT_TYPE_* that you would use in a signature
    // The only normalization that happens is that for type handles
    // for instantiated types (e.g. class List<String> or
    // value type Pair<int,int>)) this returns either ELEMENT_TYPE_CLASS
    // or ELEMENT_TYPE_VALUE, _not_ ELEMENT_TYPE_WITH.
    CorElementType GetSignatureCorElementType() const;
         
    // This helper:
    // - Will return enums underlying type
    // - Will return underlying primitive for System.Int32 etc...
    // - Will return underlying primitive as will be used in the calling convention
    //      For example
    //              struct t
    //              {
    //                  public int i;
    //              }
    //      will return ELEMENT_TYPE_I4 in x86 instead of ELEMENT_TYPE_VALUETYPE. We
    //      call this type of value type a primitive value type
    //
    // Internal representation is used among another things for the calling convention
    // (jit benefits of primitive value types) or optimizing marshalling.
    //
    // This will NOT convert E_T_ARRAY, E_T_SZARRAY etc. to E_T_CLASS (though it probably
    // should).  Use CorTypeInfo::IsObjRef for that.
    CorElementType GetInternalCorElementType() const; 

    // This helper will return the same as GetSignatureCorElementType except:
    // - Will return enums underlying type
    CorElementType GetVerifierCorElementType() const;

    //-------------------------------------------------------------------
    // CASTING
    // 
    // There are two variants of the "CanCastTo" method:
    //
    // CanCastTo
    // - restore encoded pointers on demand
    // - might throw, might trigger GC
    // - return type is boolean (FALSE = cannot cast, TRUE = can cast)
    //
    // CanCastToNoGC
    // - do not restore encoded pointers on demand
    // - does not throw, does not trigger GC
    // - return type is three-valued (CanCast, CannotCast, MaybeCast)
    // - MaybeCast indicates that the test tripped on an encoded pointer
    //   so the caller should now call CanCastTo if it cares
    //
    // Note that if the TypeHandle is a valuetype, the caller is responsible
    // for checking that the valuetype is in its boxed form before calling
    // CanCastTo. Otherwise, the caller should be using IsBoxedAndCanCastTo()
    typedef enum { CannotCast, CanCast, MaybeCast } CastResult;

    BOOL CanCastTo(TypeHandle type, TypeHandlePairList *pVisited = NULL) const;
    BOOL IsBoxedAndCanCastTo(TypeHandle type, TypeHandlePairList *pVisited) const;
    CastResult CanCastToNoGC(TypeHandle type) const;

#ifndef DACCESS_COMPILE
    // Type equivalence based on Guid and TypeIdentifier attributes
    inline BOOL IsEquivalentTo(TypeHandle type COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL)) const;
#endif

    // Get the parent, known to be decoded
    TypeHandle GetParent() const;

    // Obtain element type for an array or pointer, returning NULL otherwise
    TypeHandle GetTypeParam() const;

    // Obtain instantiation from an instantiated type
    // NULL if not instantiated
    Instantiation GetInstantiation() const;

    // Does this type satisfy its class constraints, recursively up the hierarchy
    BOOL SatisfiesClassConstraints() const;

    TypeHandle Instantiate(Instantiation inst) const;
    TypeHandle MakePointer() const;
    TypeHandle MakeByRef() const;
    TypeHandle MakeSZArray() const;
    TypeHandle MakeArray(int rank) const;
    TypeHandle MakeNativeValueType() const;

    // Obtain instantiation from an instantiated type *or* a pointer to the element type for an array 
    Instantiation GetClassOrArrayInstantiation() const;

    // Is this type instantiated?
    BOOL HasInstantiation() const;

    // Is this a generic type whose type arguments are its formal type parameters?
    BOOL IsGenericTypeDefinition() const;

    // Is this either a non-generic type (e.g. a non-genric class type or an array type or a pointer type etc.)
    // or a generic type whose type arguments are its formal type parameters?
    //Equivalent to (!HasInstantiation() || IsGenericTypeDefinition());
    inline BOOL IsTypicalTypeDefinition() const;     

    enum InteropKind
    {
        Interop_ManagedToNative, // use for RCW-related queries
        Interop_NativeToManaged, // use for CCW-related queries
    };

    inline BOOL SupportsGenericInterop(InteropKind interopKind) const;

    BOOL IsSharedByGenericInstantiations() const;

    // Recursively search the type arguments and if
    // one of the type arguments is Canon then return TRUE
    //
    // A<__Canon>    is the canonical TypeHandle (aka "representative" generic MT)
    // A<B<__Canon>> is a subtype that contains a Canonical type
    //
    BOOL IsCanonicalSubtype() const;

    // Similar to IsCanonicalSubtype, but applied to a vector.
    static BOOL IsCanonicalSubtypeInstantiation(Instantiation inst);

    // For an uninstantiated generic type, return the number of type parameters required for instantiation
    // For an instantiated type, return the number of type parameters in the instantiation
    // Otherwise return 0
    DWORD GetNumGenericArgs() const;

    BOOL IsValueType() const;
    BOOL IsInterface() const;
    BOOL IsAbstract() const;

    inline DWORD IsObjectType() const
    {
        LIMITED_METHOD_CONTRACT;
        return *this == TypeHandle(g_pObjectClass);
    }

    // Retrieve the key corresponding to this handle
    TypeKey GetTypeKey() const;

    // To what level has this type been loaded?
    ClassLoadLevel GetLoadLevel() const;

    // Equivalent to GetLoadLevel() == CLASS_LOADED
    BOOL IsFullyLoaded() const;

    void DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level, DFLPendingList *pPending, BOOL *pfBailed,
                     const InstantiationContext *pInstContext);

    inline void SetIsFullyLoaded();

 
#ifdef _DEBUG
    // Check that this type matches the key given 
    // i.e. that all aspects (element type, module/token, rank for arrays, instantiation for generic types) match up
    CHECK CheckMatchesKey(TypeKey *pKey) const;

    // Check that this type is loaded up to the level indicated
    // Also check that it is non-null
    CHECK CheckLoadLevel(ClassLoadLevel level);

    // Equivalent to CheckLoadLevel(CLASS_LOADED)
    CHECK CheckFullyLoaded();
#endif

    bool IsHFA() const;   
    CorElementType GetHFAType() const;

#ifdef FEATURE_64BIT_ALIGNMENT
    bool RequiresAlign8() const;
#endif // FEATURE_64BIT_ALIGNMENT

#ifndef DACCESS_COMPILE

    BOOL IsBlittable() const;
    BOOL HasLayout() const;
    
#ifdef FEATURE_COMINTEROP
    TypeHandle GetCoClassForInterface() const;
    DWORD IsComClassInterface() const;
    BOOL IsComObjectType() const;
    BOOL IsComEventItfType() const;
    CorIfaceAttr GetComInterfaceType() const;
    TypeHandle GetDefItfForComClassItf() const;

    BOOL IsProjectedFromWinRT() const;
    BOOL IsExportedToWinRT() const;

    ComCallWrapperTemplate *GetComCallWrapperTemplate() const;
    BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate);
#endif // FEATURE_COMINTEROP

#endif 

    // Unlike AsMethodTable, GetMethodTable will get the method table
    // of the type, regardless of whether it is an array etc. Note, however
    // this method table may be shared, and some types (like TypeByRef), have
    // no method table (and this function returns NULL for them)
    inline PTR_MethodTable GetMethodTable() const;

    // Returns the method table which should be used for visibility checking.
    // Like GetMethodTable except for TypeDescs returns the root ElementType.
    // So for Foo[] instead of returning Array returns Foo. 
    inline MethodTable* GetMethodTableOfElementType() const;

    // Returns the MethodTable for the SZARRAY or ARRAY type
    inline MethodTable * GetPossiblySharedArrayMethodTable() const;

    // As above but returns a TypeHandle (so it will return a non-null result
    // for generic type variables, for instance).
    inline TypeHandle GetElementType() const;

    // Return the canonical representative MT amongst the set of MT's that share
    // code with the MT for the given TypeHandle because of generics.
    PTR_MethodTable GetCanonicalMethodTable() const;

    // The module that defined the underlying type
    // (First strip off array/ptr qualifiers and generic type arguments)
    PTR_Module GetModule() const;

    // The ngen'ed module where this type lives
    PTR_Module GetZapModule() const;

    // Does this immediate item live in an NGEN module?
    BOOL IsZapped() const;

    // The module where this type lives for the purposes of loading and prejitting
    // Note: NGen time result might differ from runtime result for parametrized types (generics, arrays, etc.)
    // See code:ClassLoader::ComputeLoaderModule or file:clsload.hpp#LoaderModule for more information
    PTR_Module GetLoaderModule() const;

    // The assembly that defined this type (== GetModule()->GetAssembly())
    Assembly * GetAssembly() const;

    // GetDomain on an instantiated type, e.g. C<ty1,ty2> returns the SharedDomain if all the
    // constituent parts of the type are SharedDomain (i.e. domain-neutral), 
    // and returns an AppDomain if any of the parts are from an AppDomain, 
    // i.e. are domain-bound.  If any of the parts are domain-bound
    // then they will all belong to the same domain.
    PTR_BaseDomain GetDomain() const;

    PTR_LoaderAllocator GetLoaderAllocator() const;

    // Get the class token, assuming the type handle represents a named type,
    // i.e. a class, a value type, a generic instantiation etc.
    inline mdTypeDef GetCl() const;

    // Shortcuts

    // ARRAY or SZARRAY TypeDesc (arrays with a shared MethodTable)
    // If this is TRUE, it is OK to call AsArray()
    // Also see IsArrayType()
    BOOL IsArray() const;

    // See comment of IsArrayType() for the explanation of this method
#if 0
    void NormalizeUnsharedArrayMT();
#endif

    // ARRAY or SZARRAY
    // Note that this does not imply that it is OK to call AsArray(). See IsArray()
    //
    // All arrays, even those with a unique unshared MethodTable, have an ArrayTypeDesc
    // which is used for type identity. However, over time, people have started
    // wrapping the MethodTables directly in a TypeHandle. Note that such 
    // TypeHandles cannot be used for type identity. However, IsArrayType() lets
    // you check even for such cases where IsArray() returns FALSE, but the type
    // still is an array type.
    //
    // @TODO: Change all the constructors of TypeHandle which take a MethodTable 
    // to call NormalizeUnsharedArrayMT(). TypeHandle::Verify() can then enforce
    // that IsArray() is fully correct.
    BOOL IsArrayType() const;

    // VAR or MVAR
    BOOL IsGenericVariable() const;

    // BYREF
    BOOL IsByRef() const;

    // BYREFLIKE (does not return TRUE for IsByRef types)
    BOOL IsByRefLike() const;

    // PTR
    BOOL IsPointer() const;

    // True if this type *is* a formal generic type parameter or any component of it is a formal generic type parameter
    BOOL ContainsGenericVariables(BOOL methodOnly=FALSE) const;

    Module* GetDefiningModuleForOpenType() const;    

    // Is actually ParamTypeDesc (ARRAY, SZARRAY, BYREF, PTR)
    BOOL HasTypeParam() const;

    BOOL IsRestored_NoLogging() const;
    BOOL IsRestored() const;

    // Does this type have zap-encoded components (generic arguments, etc)?
    BOOL HasUnrestoredTypeKey() const;

    // True if this type handle is a zap-encoded fixup
    BOOL IsEncodedFixup() const;

    // Only used at NGEN-time
    BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited) const;

    void DoRestoreTypeKey();    

    void CheckRestore() const;
    BOOL IsExternallyVisible() const;

    // Does this type participate in type equivalence?
    inline BOOL HasTypeEquivalence() const;

    // Not clear we should have this.  
    inline PTR_ArrayTypeDesc AsArray() const;
    
    FnPtrTypeDesc* AsFnPtrType() const;
    
    TypeVarTypeDesc* AsGenericVariable() const;
    
    Instantiation GetInstantiationOfParentClass(MethodTable *pWhichParent) const;

    PTR_VOID AsPtr() const {                     // Please don't use this if you can avoid it
        LIMITED_METHOD_DAC_CONTRACT;

        return(PTR_VOID(m_asTAddr)); 
    }

    TADDR AsTAddr() const {       
        LIMITED_METHOD_DAC_CONTRACT;

        return m_asTAddr;
    }

    INDEBUGIMPL(BOOL Verify();)             // DEBUGGING Make certain this is a valid type handle 

#ifdef DACCESS_COMPILE
    void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
#endif
    
    OBJECTREF GetManagedClassObject() const;
    OBJECTREF GetManagedClassObjectFast() const;
    
    static TypeHandle MergeArrayTypeHandlesToCommonParent(
        TypeHandle ta, TypeHandle tb);

    static TypeHandle MergeTypeHandlesToCommonParent(
        TypeHandle ta, TypeHandle tb);


    BOOL NotifyDebuggerLoad(AppDomain *domain, BOOL attaching) const;
    void NotifyDebuggerUnload(AppDomain *domain) const;

    // Execute the callback functor for each MethodTable that makes up the given type handle.  This method
    // does not invoke the functor for generic variables
    template<class T>
    inline void ForEachComponentMethodTable(T &callback) const;

private:
    static TypeHandle MergeClassWithInterface(
        TypeHandle tClass, TypeHandle tInterface);

    union 
    {
        TADDR               m_asTAddr;      // we look at the low order bits
#ifndef DACCESS_COMPILE
        void *              m_asPtr;
        PTR_MethodTable     m_asMT;
        PTR_TypeDesc        m_asTypeDesc;
        PTR_ArrayTypeDesc   m_asArrayTypeDesc;
        PTR_ParamTypeDesc   m_asParamTypeDesc;
        PTR_TypeVarTypeDesc m_asTypeVarTypeDesc;
        PTR_FnPtrTypeDesc   m_asFnPtrTypeDesc;
#endif
    };
};

class TypeHandleList
{
    TypeHandle m_typeHandle;
    TypeHandleList* m_pNext;
    bool m_fBrokenCycle;
 public:
    TypeHandleList(TypeHandle t, TypeHandleList* pNext) : m_typeHandle(t),m_pNext(pNext),m_fBrokenCycle(false) { };
    static BOOL Exists(TypeHandleList* pList, TypeHandle t)
    {
        LIMITED_METHOD_CONTRACT;
        while (pList != NULL) { if (pList->m_typeHandle == t) return TRUE; pList = pList->m_pNext; }
        return FALSE;
    }

    // Supports enumeration of the list.
    static BOOL GetNext(TypeHandleList** ppList, TypeHandle* pHandle)
    {
        LIMITED_METHOD_CONTRACT;
        if (*ppList != NULL)
        {
            *pHandle = (*ppList)->m_typeHandle;
            (*ppList) = (*ppList)->m_pNext;
            return TRUE;
        }
        return FALSE;
    }

    void MarkBrokenCycle(TypeHandle th)
    {
        LIMITED_METHOD_CONTRACT;
        TypeHandleList* pList = this;
        while (pList->m_typeHandle != th) { pList->m_fBrokenCycle = true; pList = pList->m_pNext; }
    }
    bool HasBrokenCycleMark()
    {
        LIMITED_METHOD_CONTRACT;
        return m_fBrokenCycle;
    }
};

class TypeHandlePairList // TODO: Template for TypeHandleList, TypeHandlePairList, TokenPairList?
{
    TypeHandle m_typeHandle1;
    TypeHandle m_typeHandle2;
    TypeHandlePairList *m_pNext;
public:
    TypeHandlePairList(TypeHandle t1, TypeHandle t2, TypeHandlePairList *pNext) : m_typeHandle1(t1), m_typeHandle2(t2), m_pNext(pNext) { };
    static BOOL Exists(TypeHandlePairList *pList, TypeHandle t1, TypeHandle t2)
    {
        LIMITED_METHOD_CONTRACT;
        while (pList != NULL)
        {
            if (pList->m_typeHandle1 == t1 && pList->m_typeHandle2 == t2)
                return TRUE;
            if (pList->m_typeHandle1 == t2 && pList->m_typeHandle2 == t1)
                return TRUE;

            pList = pList->m_pNext;
        }
        return FALSE;
    }
};

#if CHECK_INVARIANTS
inline CHECK CheckPointer(TypeHandle th, IsNullOK ok = NULL_NOT_OK)
{
    STATIC_CONTRACT_NOTHROW;
    STATIC_CONTRACT_GC_NOTRIGGER;
    STATIC_CONTRACT_FORBID_FAULT;
    SUPPORTS_DAC;
    STATIC_CONTRACT_CANNOT_TAKE_LOCK;

    if (th.IsNull())
    {
        CHECK_MSG(ok, "Illegal null TypeHandle");
    }
    else
    {
        __if_exists(TypeHandle::Check)
        {
            CHECK(th.Check());
        }
#if 0
        CHECK(CheckInvariant(o));
#endif
    }

    CHECK_OK;
}

#endif  // CHECK_INVARIANTS

/*************************************************************************/
// dac_casts for TypeHandle makes FixupPointer<TypeHandle> work.
//
// TypeHandle is wrapper around pointer to MethodTable or TypeDesc. Even though
// it may feel counterintuitive, it is possible to treat it like a pointer and
// use the regular FixupPointer to implement TypeHandle indirection cells.
// The lowest bit of TypeHandle (when wrapped inside FixupPointer) is 
// used to mark optional indirection.
//
template<>
inline TADDR dac_cast(TypeHandle src)
{
    SUPPORTS_DAC;
    return src.AsTAddr();
}

template<>
inline TypeHandle dac_cast(TADDR src)
{
    SUPPORTS_DAC;
    return TypeHandle::FromTAddr(src);
}

/*************************************************************************/
// Instantiation is representation of generic instantiation. 
// It is simple read-only array of TypeHandles. In NGen, the type handles
// may be encoded using indirections. That's one reason why it is convenient
// to have wrapper class that performs the decoding.
class Instantiation
{
public:
    // Construct empty instantiation
    Instantiation()
        : m_pArgs(NULL), m_nArgs(0)
    {
        LIMITED_METHOD_DAC_CONTRACT;
    }

    // Copy construct
    Instantiation(const Instantiation & inst)
        : m_pArgs(inst.m_pArgs), m_nArgs(inst.m_nArgs)
    {
        LIMITED_METHOD_DAC_CONTRACT;
        _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
    }

    // Construct instantiation from array of FixupPointers
    Instantiation(FixupPointer<TypeHandle> * pArgs, DWORD nArgs)
        : m_pArgs(pArgs), m_nArgs(nArgs)
    {
        LIMITED_METHOD_DAC_CONTRACT;
        _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
    }

    // Construct instantiation from array of TypeHandles
    Instantiation(TypeHandle * pArgs, DWORD nArgs)
        : m_nArgs(nArgs)
    {
        LIMITED_METHOD_DAC_CONTRACT;

        DACCOP_IGNORE(CastOfMarshalledType, "Dual mode DAC problem, but since the size is the same, the cast is safe");
        m_pArgs = (FixupPointer<TypeHandle> *)pArgs;
        _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
    }

#ifdef DACCESS_COMPILE
    // Construct instantiation from target array of FixupPointers in DAC.
    // This method will create local copy of the instantiation arguments.
    Instantiation(DPTR(FixupPointer<TypeHandle>) pArgs, DWORD nArgs)
    {
        LIMITED_METHOD_DAC_CONTRACT;

        // Create a local copy of the instanitation under DAC
        PVOID pLocalArgs = PTR_READ(dac_cast<TADDR>(pArgs), nArgs * sizeof(TypeHandle));
        m_pArgs = (FixupPointer<TypeHandle> *)pLocalArgs;

        m_nArgs = nArgs;

        _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
    }
#endif

    // Return i-th instantiation argument
    TypeHandle operator[](DWORD iArg) const
    {
        LIMITED_METHOD_DAC_CONTRACT;
        _ASSERTE(iArg < m_nArgs);
        return m_pArgs[iArg].GetValue();
    }

    DWORD GetNumArgs() const
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return m_nArgs;
    }

    BOOL IsEmpty() const
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return m_nArgs == 0;
    }

    // Unsafe access to the instantiation. Do not use unless absolutely necessary!!!
    FixupPointer<TypeHandle> * GetRawArgs() const
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return m_pArgs;
    }

private:
    // Note that for DAC builds, m_pArgs may be host allocated buffer, not a copy of an object marshalled by DAC.
    FixupPointer<TypeHandle> * m_pArgs;
    DWORD m_nArgs;
};

#endif // TYPEHANDLE_H