summaryrefslogtreecommitdiff
path: root/src/vm/typehandle.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/typehandle.h')
-rw-r--r--src/vm/typehandle.h833
1 files changed, 833 insertions, 0 deletions
diff --git a/src/vm/typehandle.h b/src/vm/typehandle.h
new file mode 100644
index 0000000000..72a5656cc3
--- /dev/null
+++ b/src/vm/typehandle.h
@@ -0,0 +1,833 @@
+// 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);
+ }
+
+ DWORD IsTransparentProxy() const;
+
+ // 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
+
+#ifdef FEATURE_HFA
+ bool IsHFA() const;
+ CorElementType GetHFAType() const;
+#endif // FEATURE_HFA
+
+#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;
+
+ BOOL IsDomainNeutral() 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;
+
+ // 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;
+
+ // Is this type part of an assembly loaded for introspection?
+ BOOL IsIntrospectionOnly() const;
+
+ // Checks this type and its components for "IsIntrospectionOnly"
+ BOOL ContainsIntrospectionOnlyTypes() 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
+
+#if defined(CHECK_APP_DOMAIN_LEAKS) || defined(_DEBUG)
+ BOOL IsAppDomainAgile() const;
+ BOOL IsCheckAppDomainAgile() const;
+
+ BOOL IsArrayOfElementsAppDomainAgile() const;
+ BOOL IsArrayOfElementsCheckAppDomainAgile() const;
+#endif
+
+#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;
+ STATIC_CONTRACT_SO_TOLERANT;
+ 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