diff options
Diffstat (limited to 'src/vm/typehandle.h')
-rw-r--r-- | src/vm/typehandle.h | 833 |
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 |