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
22class TypeDesc;
23class TypeHandle;
24class Instantiation;
25class ArrayTypeDesc;
26class FnPtrTypeDesc;
27class ParamTypeDesc;
28class TypeVarTypeDesc;
29class MethodTable;
30class EEClass;
31class Module;
32class Assembly;
33class BaseDomain;
34class MethodDesc;
35class TypeKey;
36class TypeHandleList;
37class InstantiationContext;
38class DataImage;
39namespace Generics { class RecursionGraph; }
40struct CORINFO_CLASS_STRUCT_;
41
42typedef DPTR(class TypeVarTypeDesc) PTR_TypeVarTypeDesc;
43typedef SPTR(class FnPtrTypeDesc) PTR_FnPtrTypeDesc;
44typedef DPTR(class ParamTypeDesc) PTR_ParamTypeDesc;
45typedef DPTR(class ArrayTypeDesc) PTR_ArrayTypeDesc;
46typedef DPTR(class TypeDesc) PTR_TypeDesc;
47typedef DPTR(class TypeHandle) PTR_TypeHandle;
48
49
50typedef CUnorderedArray<TypeHandle, 40> DFLPendingList;
51
52class TypeHandlePairList;
53
54#ifdef FEATURE_COMINTEROP
55class 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
97class TypeHandle
98{
99public:
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
151private:
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
164public:
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
589private:
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
608class 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
648class TypeHandlePairList // TODO: Template for TypeHandleList, TypeHandlePairList, TokenPairList?
649{
650 TypeHandle m_typeHandle1;
651 TypeHandle m_typeHandle2;
652 TypeHandlePairList *m_pNext;
653public:
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
672inline 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 STATIC_CONTRACT_SO_TOLERANT;
678 SUPPORTS_DAC;
679 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
680
681 if (th.IsNull())
682 {
683 CHECK_MSG(ok, "Illegal null TypeHandle");
684 }
685 else
686 {
687 __if_exists(TypeHandle::Check)
688 {
689 CHECK(th.Check());
690 }
691#if 0
692 CHECK(CheckInvariant(o));
693#endif
694 }
695
696 CHECK_OK;
697}
698
699#endif // CHECK_INVARIANTS
700
701/*************************************************************************/
702// dac_casts for TypeHandle makes FixupPointer<TypeHandle> work.
703//
704// TypeHandle is wrapper around pointer to MethodTable or TypeDesc. Even though
705// it may feel counterintuitive, it is possible to treat it like a pointer and
706// use the regular FixupPointer to implement TypeHandle indirection cells.
707// The lowest bit of TypeHandle (when wrapped inside FixupPointer) is
708// used to mark optional indirection.
709//
710template<>
711inline TADDR dac_cast(TypeHandle src)
712{
713 SUPPORTS_DAC;
714 return src.AsTAddr();
715}
716
717template<>
718inline TypeHandle dac_cast(TADDR src)
719{
720 SUPPORTS_DAC;
721 return TypeHandle::FromTAddr(src);
722}
723
724/*************************************************************************/
725// Instantiation is representation of generic instantiation.
726// It is simple read-only array of TypeHandles. In NGen, the type handles
727// may be encoded using indirections. That's one reason why it is convenient
728// to have wrapper class that performs the decoding.
729class Instantiation
730{
731public:
732 // Construct empty instantiation
733 Instantiation()
734 : m_pArgs(NULL), m_nArgs(0)
735 {
736 LIMITED_METHOD_DAC_CONTRACT;
737 }
738
739 // Copy construct
740 Instantiation(const Instantiation & inst)
741 : m_pArgs(inst.m_pArgs), m_nArgs(inst.m_nArgs)
742 {
743 LIMITED_METHOD_DAC_CONTRACT;
744 _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
745 }
746
747 // Construct instantiation from array of FixupPointers
748 Instantiation(FixupPointer<TypeHandle> * pArgs, DWORD nArgs)
749 : m_pArgs(pArgs), m_nArgs(nArgs)
750 {
751 LIMITED_METHOD_DAC_CONTRACT;
752 _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
753 }
754
755 // Construct instantiation from array of TypeHandles
756 Instantiation(TypeHandle * pArgs, DWORD nArgs)
757 : m_nArgs(nArgs)
758 {
759 LIMITED_METHOD_DAC_CONTRACT;
760
761 DACCOP_IGNORE(CastOfMarshalledType, "Dual mode DAC problem, but since the size is the same, the cast is safe");
762 m_pArgs = (FixupPointer<TypeHandle> *)pArgs;
763 _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
764 }
765
766#ifdef DACCESS_COMPILE
767 // Construct instantiation from target array of FixupPointers in DAC.
768 // This method will create local copy of the instantiation arguments.
769 Instantiation(DPTR(FixupPointer<TypeHandle>) pArgs, DWORD nArgs)
770 {
771 LIMITED_METHOD_DAC_CONTRACT;
772
773 // Create a local copy of the instanitation under DAC
774 PVOID pLocalArgs = PTR_READ(dac_cast<TADDR>(pArgs), nArgs * sizeof(TypeHandle));
775 m_pArgs = (FixupPointer<TypeHandle> *)pLocalArgs;
776
777 m_nArgs = nArgs;
778
779 _ASSERTE(m_nArgs == 0 || m_pArgs != NULL);
780 }
781#endif
782
783 // Return i-th instantiation argument
784 TypeHandle operator[](DWORD iArg) const
785 {
786 LIMITED_METHOD_DAC_CONTRACT;
787 _ASSERTE(iArg < m_nArgs);
788 return m_pArgs[iArg].GetValue();
789 }
790
791 DWORD GetNumArgs() const
792 {
793 LIMITED_METHOD_DAC_CONTRACT;
794 return m_nArgs;
795 }
796
797 BOOL IsEmpty() const
798 {
799 LIMITED_METHOD_DAC_CONTRACT;
800 return m_nArgs == 0;
801 }
802
803 // Unsafe access to the instantiation. Do not use unless absolutely necessary!!!
804 FixupPointer<TypeHandle> * GetRawArgs() const
805 {
806 LIMITED_METHOD_DAC_CONTRACT;
807 return m_pArgs;
808 }
809
810private:
811 // Note that for DAC builds, m_pArgs may be host allocated buffer, not a copy of an object marshalled by DAC.
812 FixupPointer<TypeHandle> * m_pArgs;
813 DWORD m_nArgs;
814};
815
816#endif // TYPEHANDLE_H
817