From ef1e2ab328087c61a6878c1e84f4fc5d710aebce Mon Sep 17 00:00:00 2001 From: dotnet-bot Date: Fri, 30 Jan 2015 14:14:42 -0800 Subject: Initial commit to populate CoreCLR repo [tfs-changeset: 1407945] --- src/vm/typehandle.cpp | 2086 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2086 insertions(+) create mode 100644 src/vm/typehandle.cpp (limited to 'src/vm/typehandle.cpp') diff --git a/src/vm/typehandle.cpp b/src/vm/typehandle.cpp new file mode 100644 index 0000000000..e8bcbde4b6 --- /dev/null +++ b/src/vm/typehandle.cpp @@ -0,0 +1,2086 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// +// File: typehandle.cpp +// + + +// + +// +// ============================================================================ + + +#include "common.h" +#include "class.h" +#include "typehandle.h" +#include "eeconfig.h" +#include "generics.h" +#include "typedesc.h" +#include "typekey.h" +#include "typestring.h" +#include "classloadlevel.h" +#include "array.h" +#ifdef FEATURE_PREJIT +#include "zapsig.h" +#endif + +// This method is not being called by all the constructors of TypeHandle +// because of the following reason. SystemDomain::LoadBaseSystemClasses() +// loads TYPE__OBJECT_ARRAY which causes the following issues: +// +// If mscorlib is JIT-compiled, Module::CreateArrayMethodTable calls +// TypeString::AppendName() with a TypeHandle that wraps the MethodTable +// being created. +// If mscorlib is ngenned, Module::RestoreMethodTablePointer() needs +// a TypeHandle to call ClassLoader::EnsureLoaded(). +// + +#if 0 + +void TypeHandle::NormalizeUnsharedArrayMT() +{ + WRAPPER_NO_CONTRACT; + STATIC_CONTRACT_SO_TOLERANT; // @TODO: This is probably incorrect + + if (IsNull() || IsTypeDesc()) + return; + + if (!AsMethodTable()->IsArray()) + return; + + // This is an array type with a unique unshared MethodTable. + // We know that there must exist an ArrayTypeDesc for it, and it + // must have been restored. + // Let's look it up and use it. + + ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); + + TypeHandle elemType = AsMethodTable()->GetApproxArrayElementTypeHandle(); + CorElementType kind = AsMethodTable()->GetInternalCorElementType(); + unsigned rank = AsMethodTable()->GetRank(); + + // @todo This should be turned into a probe with a hard SO when we have one + CONTRACT_VIOLATION(SOToleranceViolation); + // == FailIfNotLoadedOrNotRestored + TypeHandle arrayType = ClassLoader::LoadArrayTypeThrowing( elemType, + kind, + rank, + ClassLoader::DontLoadTypes); + CONSISTENCY_CHECK(!arrayType.IsNull() && arrayType.IsArray()); + + // + // Update the current TypeHandle to use the ArrayTypeDesc + // + m_asPtr = arrayType.AsPtr(); + + INDEBUGIMPL(Verify()); +} + +#endif + +#ifdef _DEBUG_IMPL + +BOOL TypeHandle::Verify() +{ + STATIC_CONTRACT_NOTHROW; + STATIC_CONTRACT_GC_NOTRIGGER; + STATIC_CONTRACT_FORBID_FAULT; + STATIC_CONTRACT_CANNOT_TAKE_LOCK; + STATIC_CONTRACT_DEBUG_ONLY; + STATIC_CONTRACT_SUPPORTS_DAC; + + if (IsNull()) + return(TRUE); + + // If you try to do IBC logging of a type being created, the type + // will look inconsistent. IBC logging knows to filter out such types. + if (g_IBCLogger.InstrEnabled()) + return TRUE; + + if (!IsRestored_NoLogging()) + return TRUE; + + if (!IsTypeDesc()) + { + _ASSERTE(AsMethodTable()->SanityCheck()); // Sane method table + + // @TODO: See TypeHandle::IsArrayType() for an explanation + // of why this assert is commented out. + // + // _ASSERTE(!AsMethodTable()->IsArray()); + } + else + { + if (IsArray()) + AsArray()->Verify(); + } + return(TRUE); +} + +#endif // _DEBUG_IMPL + +unsigned TypeHandle::GetSize() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + CorElementType type = GetInternalCorElementType(); + + if (type == ELEMENT_TYPE_VALUETYPE) + { + if (IsTypeDesc()) + return(AsNativeValueType()->GetNativeSize()); + else + return(AsMethodTable()->GetNumInstanceFieldBytes()); + } + + return(GetSizeForCorElementType(type)); +} + +PTR_Module TypeHandle::GetModule() const { + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return AsTypeDesc()->GetModule(); + return(AsMethodTable()->GetModule()); +} + +Assembly* TypeHandle::GetAssembly() const { + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return AsTypeDesc()->GetAssembly(); + return(AsMethodTable()->GetAssembly()); +} + +BOOL TypeHandle::IsArray() const { + LIMITED_METHOD_DAC_CONTRACT; + + return(IsTypeDesc() && AsTypeDesc()->IsArray()); +} + +BOOL TypeHandle::IsArrayType() const { + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + { + return AsTypeDesc()->IsArray(); + } + else + { + return AsMethodTable()->IsArray(); + } +} + +BOOL TypeHandle::IsGenericVariable() const { + LIMITED_METHOD_DAC_CONTRACT; + + return(IsTypeDesc() && CorTypeInfo::IsGenericVariable_NoThrow(AsTypeDesc()->GetInternalCorElementType())); +} + +BOOL TypeHandle::HasTypeParam() const { + LIMITED_METHOD_DAC_CONTRACT; + + if (!IsTypeDesc()) return FALSE; + + CorElementType etype = AsTypeDesc()->GetInternalCorElementType(); + return(CorTypeInfo::IsModifier_NoThrow(etype) || etype == ELEMENT_TYPE_VALUETYPE); +} + +Module *TypeHandle::GetDefiningModuleForOpenType() const +{ + WRAPPER_NO_CONTRACT; + SUPPORTS_DAC; + + Module* returnValue = NULL; + + INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(goto Exit;); + + if (IsGenericVariable()) + { + PTR_TypeVarTypeDesc pTyVar = dac_cast(AsTypeDesc()); + returnValue = pTyVar->GetModule(); + goto Exit; + } + + if (HasTypeParam()) + { + returnValue = GetTypeParam().GetDefiningModuleForOpenType(); + } + else if (HasInstantiation()) + { + returnValue = GetMethodTable()->GetDefiningModuleForOpenType(); + } +Exit: + ; + END_INTERIOR_STACK_PROBE; + + return returnValue; +} + +BOOL TypeHandle::ContainsGenericVariables(BOOL methodOnly /*=FALSE*/) const +{ + STATIC_CONTRACT_SO_TOLERANT; + STATIC_CONTRACT_NOTHROW; + SUPPORTS_DAC; + + if (IsTypeDesc()) + { + if (IsGenericVariable()) + { + if (!methodOnly) + return TRUE; + + PTR_TypeVarTypeDesc pTyVar = dac_cast(AsTypeDesc()); + return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef; + } + + if (HasTypeParam()) + { + return GetTypeParam().ContainsGenericVariables(methodOnly); + } + } + else if (HasInstantiation()) + { + if (GetMethodTable()->ContainsGenericVariables(methodOnly)) + return TRUE; + } + + return FALSE; +} + +//@GENERICS: +// Return the number of type parameters in the instantiation of an instantiated type +// or the number of type parameters to a generic type +// Return 0 otherwise. +DWORD TypeHandle::GetNumGenericArgs() const { + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return 0; + else + return GetMethodTable()->GetNumGenericArgs(); +} + +BOOL TypeHandle::IsGenericTypeDefinition() const { + LIMITED_METHOD_DAC_CONTRACT; + + if (!IsTypeDesc()) + return AsMethodTable()->IsGenericTypeDefinition(); + else + return FALSE; +} + +PTR_MethodTable TypeHandle::GetCanonicalMethodTable() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + { + PTR_MethodTable pMT = AsTypeDesc()->GetMethodTable(); + if (pMT != NULL) + pMT = pMT->GetCanonicalMethodTable(); + return pMT; + } + else + { + return AsMethodTable()->GetCanonicalMethodTable(); + } +} + +// Obtain instantiation from an instantiated type or a pointer to the +// element type of an array or pointer type +Instantiation TypeHandle::GetClassOrArrayInstantiation() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + { + return AsTypeDesc()->GetClassOrArrayInstantiation(); + } + else if (IsArrayType()) + { + return AsMethodTable()->GetArrayInstantiation(); + } + else + { + return GetInstantiation(); + } +} + +Instantiation TypeHandle::GetInstantiationOfParentClass(MethodTable *pWhichParent) const +{ + LIMITED_METHOD_DAC_CONTRACT; + + return GetMethodTable()->GetInstantiationOfParentClass(pWhichParent); +} + +// Obtain element type from an array or pointer type +TypeHandle TypeHandle::GetTypeParam() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return AsTypeDesc()->GetTypeParam(); + else + return TypeHandle(); +} + +#ifndef DACCESS_COMPILE +TypeHandle TypeHandle::Instantiate(Instantiation inst) const +{ + STATIC_CONTRACT_WRAPPER; + return ClassLoader::LoadGenericInstantiationThrowing(GetModule(), GetCl(), inst); +} + +TypeHandle TypeHandle::MakePointer() const +{ + STATIC_CONTRACT_WRAPPER; + return ClassLoader::LoadPointerOrByrefTypeThrowing(ELEMENT_TYPE_PTR, *this); +} + +TypeHandle TypeHandle::MakeByRef() const +{ + STATIC_CONTRACT_WRAPPER; + return ClassLoader::LoadPointerOrByrefTypeThrowing(ELEMENT_TYPE_BYREF, *this); +} + +TypeHandle TypeHandle::MakeSZArray() const +{ + STATIC_CONTRACT_WRAPPER; + return ClassLoader::LoadArrayTypeThrowing(*this); +} + +TypeHandle TypeHandle::MakeArray(int rank) const +{ + STATIC_CONTRACT_WRAPPER; + return ClassLoader::LoadArrayTypeThrowing(*this, ELEMENT_TYPE_ARRAY, rank); +} + +// The returned TypeHandle is a ParamTypeDesc that acts like a facade for the original valuetype. It makes the +// valuetype look like its unmanaged view, i.e. GetSize() returns GetNativeSize(), IsBlittable() returns TRUE, +// and JIT interface special-cases it when reporting GC pointers to the JIT. +TypeHandle TypeHandle::MakeNativeValueType() const +{ + STATIC_CONTRACT_WRAPPER; + return ClassLoader::LoadNativeValueTypeThrowing(*this); +} + +#endif // #ifndef DACCESS_COMPILE + +PTR_Module TypeHandle::GetLoaderModule() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return AsTypeDesc()->GetLoaderModule(); + else + return AsMethodTable()->GetLoaderModule(); +} + +PTR_Module TypeHandle::GetZapModule() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return AsTypeDesc()->GetZapModule(); + else + return AsMethodTable()->GetZapModule(); +} + +PTR_BaseDomain TypeHandle::GetDomain() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return AsTypeDesc()->GetDomain(); + else + return AsMethodTable()->GetDomain(); + +} + +PTR_LoaderAllocator TypeHandle::GetLoaderAllocator() const +{ + STATIC_CONTRACT_NOTHROW; + STATIC_CONTRACT_GC_NOTRIGGER; + STATIC_CONTRACT_FORBID_FAULT; + STATIC_CONTRACT_SO_INTOLERANT; + STATIC_CONTRACT_SUPPORTS_DAC; + + if (IsTypeDesc()) + { + return AsTypeDesc()->GetLoaderAllocator(); + } + else + { + return AsMethodTable()->GetLoaderAllocator(); + } +} + +BOOL TypeHandle::IsSharedByGenericInstantiations() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + { + // Arrays are the only typedesc in valid generic instantiations (see code:Generics::CheckInstantiation) + + if (HasTypeParam()) + { + return GetTypeParam().IsCanonicalSubtype(); + } + return FALSE; + } + else + return AsMethodTable()->IsSharedByGenericInstantiations(); +} + +BOOL TypeHandle::IsCanonicalSubtype() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + return (*this == TypeHandle(g_pCanonMethodTableClass)) || IsSharedByGenericInstantiations(); +} + +/* static */ BOOL TypeHandle::IsCanonicalSubtypeInstantiation(Instantiation inst) +{ + LIMITED_METHOD_DAC_CONTRACT; + + for (DWORD i = 0; i < inst.GetNumArgs(); i++) + { + if (inst[i].IsCanonicalSubtype()) + return TRUE; + } + return FALSE; +} + +// Obtain instantiation from an instantiated type. +// Return NULL if it's not one. +Instantiation TypeHandle::GetInstantiation() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (!IsTypeDesc()) return AsMethodTable()->GetInstantiation(); + else return Instantiation(); +} + + +BOOL TypeHandle::IsValueType() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (!IsTypeDesc()) return AsMethodTable()->IsValueType(); + else return AsTypeDesc()->IsNativeValueType(); +} + +BOOL TypeHandle::IsInterface() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + return !IsTypeDesc() && AsMethodTable()->IsInterface(); +} + +BOOL TypeHandle::IsAbstract() const +{ + WRAPPER_NO_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->IsAbstract(); +} + +DWORD TypeHandle::IsTransparentProxy() const +{ + WRAPPER_NO_CONTRACT; +#ifdef FEATURE_REMOTING + return !IsTypeDesc() && AsMethodTable()->IsTransparentProxy(); +#else + return FALSE; +#endif +} + +#ifdef FEATURE_HFA +bool TypeHandle::IsHFA() const +{ + WRAPPER_NO_CONTRACT; + + if (!IsTypeDesc()) + return AsMethodTable()->IsHFA(); + + if (AsTypeDesc()->IsNativeValueType()) + return AsNativeValueType()->IsNativeHFA(); + + return false; +} + +CorElementType TypeHandle::GetHFAType() const +{ + WRAPPER_NO_CONTRACT; + + if (!IsTypeDesc()) + return AsMethodTable()->GetHFAType(); + + if (AsTypeDesc()->IsNativeValueType()) + return AsNativeValueType()->GetNativeHFAType(); + + return ELEMENT_TYPE_END; +} +#endif // FEATURE_HFA + +#ifdef FEATURE_64BIT_ALIGNMENT +bool TypeHandle::RequiresAlign8() const +{ + WRAPPER_NO_CONTRACT; + + if (IsNativeValueType()) + return AsNativeValueType()->NativeRequiresAlign8(); + + return GetMethodTable()->RequiresAlign8(); +} +#endif // FEATURE_64BIT_ALIGNMENT + +#ifndef DACCESS_COMPILE + +BOOL TypeHandle::IsBlittable() const +{ + LIMITED_METHOD_CONTRACT; + + if (!IsTypeDesc()) + { + // This is a simple type (not an array, ptr or byref) so if + // simply check to see if the type is blittable. + return AsMethodTable()->IsBlittable(); + } + + if (AsTypeDesc()->IsArray()) + { + // Single dimentional array's of blittable types are also blittable. + if (AsArray()->GetRank() == 1) + { + if (AsArray()->GetArrayElementTypeHandle().IsBlittable()) + return TRUE; + } + } + else if (AsTypeDesc()->IsNativeValueType()) + { + return TRUE; + } + + return FALSE; +} + +BOOL TypeHandle::HasLayout() const +{ + WRAPPER_NO_CONTRACT; + MethodTable *pMT = GetMethodTable(); + return pMT ? pMT->HasLayout() : FALSE; +} + +#ifdef FEATURE_COMINTEROP + +TypeHandle TypeHandle::GetCoClassForInterface() const +{ + WRAPPER_NO_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->GetCoClassForInterface(); +} + +DWORD TypeHandle::IsComClassInterface() const +{ + WRAPPER_NO_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->IsComClassInterface(); +} + +BOOL TypeHandle::IsComObjectType() const +{ + WRAPPER_NO_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->IsComObjectType(); +} + +BOOL TypeHandle::IsComEventItfType() const +{ + WRAPPER_NO_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->IsComEventItfType(); +} + +CorIfaceAttr TypeHandle::GetComInterfaceType() const +{ + WRAPPER_NO_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->GetComInterfaceType(); +} + +TypeHandle TypeHandle::GetDefItfForComClassItf() const +{ + WRAPPER_NO_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->GetDefItfForComClassItf(); +} + +BOOL TypeHandle::IsProjectedFromWinRT() const +{ + LIMITED_METHOD_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->IsProjectedFromWinRT(); +} + +BOOL TypeHandle::IsExportedToWinRT() const +{ + LIMITED_METHOD_CONTRACT; + PREFIX_ASSUME(GetMethodTable() != NULL); + return GetMethodTable()->IsExportedToWinRT(); +} + +ComCallWrapperTemplate *TypeHandle::GetComCallWrapperTemplate() const +{ + LIMITED_METHOD_CONTRACT; + PRECONDITION(IsArray() || !IsTypeDesc()); + + if (IsTypeDesc()) + { + return AsArray()->GetComCallWrapperTemplate(); + } + return AsMethodTable()->GetComCallWrapperTemplate(); +} + +BOOL TypeHandle::SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate) +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + } + CONTRACTL_END; + + PRECONDITION(IsArray() || !IsTypeDesc()); + + if (IsTypeDesc()) + { + return AsArray()->SetComCallWrapperTemplate(pTemplate); + } + return AsMethodTable()->SetComCallWrapperTemplate(pTemplate); +} + +#endif // FEATURE_COMINTEROP + +//-------------------------------------------------------------------------------------- +// CanCastTo is necessary but not sufficient, as it assumes that any valuetype +// involved is in its boxed form. + +BOOL TypeHandle::IsBoxedAndCanCastTo(TypeHandle type, TypeHandlePairList *pPairList) const +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + + LOADS_TYPE(CLASS_DEPENDENCIES_LOADED); + + // The caller should check for an exact match. + // That will cover the cast of a (unboxed) valuetype to itself. + PRECONDITION(*this != type); + } + CONTRACTL_END + + + CorElementType fromParamCorType = GetVerifierCorElementType(); + + if (CorTypeInfo::IsObjRef(fromParamCorType)) + { + // fromParamCorType is a reference type. We can just use CanCastTo + return CanCastTo(type, pPairList); + } + else if (CorTypeInfo::IsGenericVariable(fromParamCorType)) + { + TypeVarTypeDesc* varFromParam = AsGenericVariable(); + + if (!varFromParam->ConstraintsLoaded()) + varFromParam->LoadConstraints(CLASS_DEPENDENCIES_LOADED); + + // A generic type parameter cannot be compatible with another type + // as it could be substitued with a valuetype. However, if it is + // constrained to a reference type, then we can use CanCastTo. + if (varFromParam->ConstrainedAsObjRef()) + return CanCastTo(type, pPairList); + } + + return FALSE; +} + +//-------------------------------------------------------------------------------------- +// CanCastTo is necessary but not sufficient, as it assumes that any valuetype +// involved is in its boxed form. See IsBoxedAndCanCastTo() if the valuetype +// is not guaranteed to be in its boxed form. + +BOOL TypeHandle::CanCastTo(TypeHandle type, TypeHandlePairList *pVisited) const +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + + LOADS_TYPE(CLASS_DEPENDENCIES_LOADED); + } + CONTRACTL_END + + if (*this == type) + return(true); + + if (IsTypeDesc()) + return AsTypeDesc()->CanCastTo(type, pVisited); + + if (type.IsTypeDesc()) + return(false); + + if (AsMethodTable()->IsTransparentProxy()) + return (false); + + return AsMethodTable()->CanCastToClassOrInterface(type.AsMethodTable(), pVisited); +} + +#include +TypeHandle::CastResult TypeHandle::CanCastToNoGC(TypeHandle type) const +{ + LIMITED_METHOD_CONTRACT; + + if (*this == type) + return(CanCast); + + if (IsTypeDesc()) + return AsTypeDesc()->CanCastToNoGC(type); + + if (type.IsTypeDesc()) + return(CannotCast); + + if (AsMethodTable()->IsTransparentProxy()) + return (CannotCast); + + return AsMethodTable()->CanCastToClassOrInterfaceNoGC(type.AsMethodTable()); +} +#include + +#endif // #ifndef DACCESS_COMPILE + +void TypeHandle::GetName(SString &result) const +{ + CONTRACTL + { + THROWS; + GC_NOTRIGGER; + SO_TOLERANT; + INJECT_FAULT(COMPlusThrowOM();); + } + CONTRACTL_END + + INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(goto Exit;); + { + + if (IsTypeDesc()) + { + AsTypeDesc()->GetName(result); + goto Exit; + } + + AsMethodTable()->_GetFullyQualifiedNameForClass(result); + + // Tack the instantiation on the end + Instantiation inst = GetInstantiation(); + if (!inst.IsEmpty()) + TypeString::AppendInst(result, inst); + } +Exit: + ; + END_INTERIOR_STACK_PROBE; +} + +TypeHandle TypeHandle::GetParent() const +{ + STATIC_CONTRACT_NOTHROW; + STATIC_CONTRACT_GC_NOTRIGGER; + STATIC_CONTRACT_FORBID_FAULT; + STATIC_CONTRACT_SO_TOLERANT; + + if (IsTypeDesc()) + return(AsTypeDesc()->GetParent()); + else + return TypeHandle(AsMethodTable()->GetParentMethodTable()); +} +#ifndef DACCESS_COMPILE + +/* static */ +TypeHandle TypeHandle::MergeClassWithInterface(TypeHandle tClass, TypeHandle tInterface) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + MethodTable *pMTClass = tClass.AsMethodTable(); + + // Check if the class implements the interface + if (pMTClass->ImplementsEquivalentInterface(tInterface.AsMethodTable())) + { + // The class implements the interface or its equivalent, so our merged state should be the interface + return tInterface; + } + + // Check if the class and the interface implement a common interface + MethodTable *pMTInterface = tInterface.AsMethodTable(); + MethodTable::InterfaceMapIterator intIt = pMTInterface->IterateInterfaceMap(); + while (intIt.Next()) + { + MethodTable *pMT = intIt.GetInterface(); + if (pMTClass->ImplementsEquivalentInterface(pMT)) + { + // Found a common interface. If there are multiple common interfaces, then + // the problem is ambiguous so we'll just take the first one--it's the best + // we can do. If an ensuing code path relies on another common interface, + // the verifier will think the code is unverifiable, but it would require a + // major redesign of the verifier to fix that. + return TypeHandle(pMT); + } + } + + // No compatible merge found - using Object + return TypeHandle(g_pObjectClass); +} + +/* static */ +TypeHandle TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle ta, TypeHandle tb) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + _ASSERTE(!ta.IsNull() && !tb.IsNull()); + + if (ta == tb) + return ta; + + // Handle the array case + if (ta.IsArray()) + { + if (tb.IsArray()) + return MergeArrayTypeHandlesToCommonParent(ta, tb); + else if (tb.IsInterface()) + { + //Check to see if we can merge the array to a common interface (such as Derived[] and IList) + if (ArraySupportsBizarreInterface(ta.AsArray(), tb.AsMethodTable())) + return tb; + } + ta = TypeHandle(g_pArrayClass); // keep merging from here. + } + else if (tb.IsArray()) + { + if (ta.IsInterface() && ArraySupportsBizarreInterface(tb.AsArray(), ta.AsMethodTable())) + return ta; + + tb = TypeHandle(g_pArrayClass); + } + + + // If either is a (by assumption boxed) type variable + // return the supertype, if they are related, or object if they are incomparable. + if (ta.IsGenericVariable() || tb.IsGenericVariable()) + { + if (ta.CanCastTo(tb)) + return tb; + if (tb.CanCastTo(ta)) + return ta; + return TypeHandle(g_pObjectClass); + } + + + _ASSERTE(!ta.IsTypeDesc() && !tb.IsTypeDesc()); + + + MethodTable *pMTa = ta.AsMethodTable(); + MethodTable *pMTb = tb.AsMethodTable(); + + if (pMTb->IsInterface()) + { + + if (pMTa->IsInterface()) + { + // + // Both classes are interfaces. Check that if one + // interface extends the other. + // + // Does tb extend ta ? + // + + if (pMTb->ImplementsEquivalentInterface(pMTa)) + { + // tb extends ta, so our merged state should be ta + return ta; + } + + // + // Does tb extend ta ? + // + if (pMTa->ImplementsEquivalentInterface(pMTb)) + { + // ta extends tb, so our merged state should be tb + return tb; + } + + // No compatible merge found - using Object + return TypeHandle(g_pObjectClass); + } + else + return MergeClassWithInterface(ta, tb); + } + else if (pMTa->IsInterface()) + return MergeClassWithInterface(tb, ta); + + DWORD aDepth = 0; + DWORD bDepth = 0; + TypeHandle tSearch; + + // find the depth in the class hierarchy for each class + for (tSearch = ta; (!tSearch.IsNull()); tSearch = tSearch.GetParent()) + aDepth++; + + for (tSearch = tb; (!tSearch.IsNull()); tSearch = tSearch.GetParent()) + bDepth++; + + // for whichever class is lower down in the hierarchy, walk up the superclass chain + // to the same level as the other class + while (aDepth > bDepth) + { + ta = ta.GetParent(); + aDepth--; + } + + while (bDepth > aDepth) + { + tb = tb.GetParent(); + bDepth--; + } + + while (!ta.IsEquivalentTo(tb)) + { + ta = ta.GetParent(); + tb = tb.GetParent(); + } + + // If no compatible merge is found, we end up using Object + + _ASSERTE(!ta.IsNull()); + + return ta; +} + +/* static */ +TypeHandle TypeHandle::MergeArrayTypeHandlesToCommonParent(TypeHandle ta, TypeHandle tb) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END + + CorElementType taKind = ta.GetInternalCorElementType(); + CorElementType tbKind = tb.GetInternalCorElementType(); + _ASSERTE(CorTypeInfo::IsArray(taKind) && CorTypeInfo::IsArray(tbKind)); + + TypeHandle taElem; + TypeHandle tMergeElem; + + // If they match we are good to go. + if (ta == tb) + return ta; + + if (ta == TypeHandle(g_pArrayClass)) + return ta; + else if (tb == TypeHandle(g_pArrayClass)) + return tb; + + // Get the rank and kind of the first array + DWORD rank = ta.AsArray()->GetRank(); + CorElementType mergeKind = taKind; + + // if no match on the rank the common ancestor is System.Array + if (rank != tb.AsArray()->GetRank()) + return TypeHandle(g_pArrayClass); + + if (tbKind != taKind) + { + if (CorTypeInfo::IsArray(tbKind) && + CorTypeInfo::IsArray(taKind) && rank == 1) + mergeKind = ELEMENT_TYPE_ARRAY; + else + return TypeHandle(g_pArrayClass); + } + + // If both are arrays of reference types, return an array of the common + // ancestor. + taElem = ta.AsArray()->GetArrayElementTypeHandle(); + if (taElem.IsEquivalentTo(tb.AsArray()->GetArrayElementTypeHandle())) + { + // The element types match/are equivalent, so we are good to go. + tMergeElem = taElem; + } + else if (taElem.IsArray() && tb.AsArray()->GetArrayElementTypeHandle().IsArray()) + { + // Arrays - Find the common ancestor of the element types. + tMergeElem = MergeArrayTypeHandlesToCommonParent(taElem, tb.AsArray()->GetArrayElementTypeHandle()); + } + else if (CorTypeInfo::IsObjRef(taElem.GetSignatureCorElementType()) && + CorTypeInfo::IsObjRef(tb.AsArray()->GetArrayElementTypeHandle().GetSignatureCorElementType())) + { + // Find the common ancestor of the element types. + tMergeElem = MergeTypeHandlesToCommonParent(taElem, tb.AsArray()->GetArrayElementTypeHandle()); + } + else + { + // The element types have nothing in common. + return TypeHandle(g_pArrayClass); + } + + + { + // This should just result in resolving an already loaded type. + ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); + // == FailIfNotLoadedOrNotRestored + TypeHandle result = ClassLoader::LoadArrayTypeThrowing(tMergeElem, mergeKind, rank, ClassLoader::DontLoadTypes); + _ASSERTE(!result.IsNull()); + + // should be able to assert IsRestored here + return result; + } +} + +#endif // #ifndef DACCESS_COMPILE + +BOOL TypeHandle::IsEnum() const +{ + LIMITED_METHOD_CONTRACT; + + return (!IsTypeDesc() && AsMethodTable()->IsEnum()); +} + +BOOL TypeHandle::IsFnPtrType() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + return (IsTypeDesc() && + (GetSignatureCorElementType() == ELEMENT_TYPE_FNPTR)); +} + +// Is this type part of an assembly loaded for introspection? +BOOL +TypeHandle::IsIntrospectionOnly() const +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END + +#ifndef DACCESS_COMPILE + if (IsFnPtrType()) + { + return AsFnPtrType()->IsIntrospectionOnly(); + } + else if (HasTypeParam()) + { + return GetTypeParam().IsIntrospectionOnly(); + } + else + { + return GetModule()->IsIntrospectionOnly(); + } +#else //DACCESS_COMPILE + return FALSE; +#endif //DACCESS_COMPILE +} // TypeHandle::IsIntrospectionOnly + +// Checks this type and its components for "IsIntrospectionOnly" +BOOL +TypeHandle::ContainsIntrospectionOnlyTypes() const +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END + +#ifndef DACCESS_COMPILE + if (IsFnPtrType()) + { + return AsFnPtrType()->ContainsIntrospectionOnlyTypes(); + } + else if (HasTypeParam()) + { + return GetTypeParam().ContainsIntrospectionOnlyTypes(); + } + else if (IsTypeDesc()) + { + return GetModule()->IsIntrospectionOnly(); + } + else + { + return AsMethodTable()->ContainsIntrospectionOnlyTypes(); + } +#else //DACCESS_COMPILE + return FALSE; +#endif //DACCESS_COMPILE +} // TypeHandle::ContainsIntrospectionOnlyTypes + +// Is this type part of an assembly loaded for introspection? +BOOL +TypeKey::IsIntrospectionOnly() +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END + +#ifndef DACCESS_COMPILE + switch (m_kind) + { + case ELEMENT_TYPE_CLASS: + return u.asClass.m_pModule->IsIntrospectionOnly(); + + case ELEMENT_TYPE_ARRAY: + case ELEMENT_TYPE_SZARRAY: + case ELEMENT_TYPE_PTR: + case ELEMENT_TYPE_BYREF: + return TypeHandle::FromTAddr(u.asParamType.m_paramType).IsIntrospectionOnly(); + + case ELEMENT_TYPE_FNPTR: + // Return TRUE if any return/arguments type was loaded for introspection only + for (DWORD i = 0; i <= u.asFnPtr.m_numArgs; i++) + { + if (u.asFnPtr.m_pRetAndArgTypes[i].IsIntrospectionOnly()) + { + return TRUE; + } + } + // None of return/arguments types was loaded for introspection only + return FALSE; + + default: + UNREACHABLE_MSG("Corrupted typekey"); + } +#else //DACCESS_COMPILE + return FALSE; +#endif //DACCESS_COMPILE +} // TypeKey::IsIntrospectionOnly + +BOOL TypeHandle::IsRestored_NoLogging() const +{ + LIMITED_METHOD_CONTRACT; + + if (!IsTypeDesc()) + { + return GetMethodTable()->IsRestored_NoLogging(); + } + else + { + return AsTypeDesc()->IsRestored_NoLogging(); + } +} + +BOOL TypeHandle::IsRestored() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (!IsTypeDesc()) + { + return GetMethodTable()->IsRestored(); + } + else + { + return AsTypeDesc()->IsRestored(); + } +} + +BOOL TypeHandle::IsEncodedFixup() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + return CORCOMPILE_IS_POINTER_TAGGED(m_asTAddr); +} + +BOOL TypeHandle::HasUnrestoredTypeKey() const +{ + WRAPPER_NO_CONTRACT; + SUPPORTS_DAC; + + if (IsTypeDesc()) + return AsTypeDesc()->HasUnrestoredTypeKey(); + else + return AsMethodTable()->HasUnrestoredTypeKey(); +} + +#ifdef FEATURE_PREJIT +void TypeHandle::DoRestoreTypeKey() +{ + CONTRACT_VOID + { + THROWS; + GC_TRIGGERS; + PRECONDITION(!IsEncodedFixup()); + } + CONTRACT_END + +#ifndef DACCESS_COMPILE + if (IsTypeDesc()) + { + AsTypeDesc()->DoRestoreTypeKey(); + } + + if (!IsTypeDesc() || IsArray()) + { + MethodTable* pMT = GetMethodTable(); + PREFIX_ASSUME(pMT != NULL); + pMT->DoRestoreTypeKey(); + } +#endif + +#ifdef _DEBUG +#ifndef DACCESS_COMPILE + if (LoggingOn(LF_CLASSLOADER, LL_INFO10000)) + { + StackSString name; + TypeString::AppendTypeDebug(name, *this); + LOG((LF_CLASSLOADER, LL_INFO10000, "GENERICS:RestoreTypeKey: type %S at %p\n", name.GetUnicode(), AsPtr())); + } +#endif +#endif + + + RETURN; +} +#endif + +void TypeHandle::CheckRestore() const +{ + CONTRACTL + { + if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; + if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; + PRECONDITION(!IsEncodedFixup()); + } + CONTRACTL_END + + if (!IsFullyLoaded()) + { + ClassLoader::EnsureLoaded(*this); + _ASSERTE(IsFullyLoaded()); + } + + g_IBCLogger.LogTypeMethodTableAccess(this); +} + +#ifndef DACCESS_COMPILE + +#ifdef FEATURE_NATIVE_IMAGE_GENERATION +BOOL TypeHandle::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited) const +{ + STATIC_STANDARD_VM_CONTRACT; + + _ASSERTE(GetAppDomain()->IsCompilationDomain()); + + if (!IsTypeDesc()) + return GetMethodTable()->ComputeNeedsRestore(image, pVisited); + else + return AsTypeDesc()->ComputeNeedsRestore(image, pVisited); +} +#endif // FEATURE_NATIVE_IMAGE_GENERATION + +BOOL +TypeHandle::IsExternallyVisible() const +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END + + if (!IsTypeDesc()) + { + return AsMethodTable()->IsExternallyVisible(); + } + + if (IsGenericVariable()) + { // VAR, MVAR + return TRUE; + } + + if (IsFnPtrType()) + { // FNPTR + // Function pointer has to check its all argument types + return AsFnPtrType()->IsExternallyVisible(); + } + // ARRAY, SZARRAY, PTR, BYREF + _ASSERTE(HasTypeParam()); + + TypeHandle paramType = AsTypeDesc()->GetTypeParam(); + _ASSERTE(!paramType.IsNull()); + + return paramType.IsExternallyVisible(); +} // TypeHandle::IsExternallyVisible + +#ifndef CROSSGEN_COMPILE +OBJECTREF TypeHandle::GetManagedClassObject() const +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_COOPERATIVE; + + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END; + +#ifdef _DEBUG + // Force a GC here because GetManagedClassObject could trigger GC nondeterminsticaly + GCStress::MaybeTrigger(); +#endif // _DEBUG + + if (!IsTypeDesc()) + { + _ASSERT(AsMethodTable()->IsTransparentProxy() == false); + return AsMethodTable()->GetManagedClassObject(); + } + else + { + switch(GetInternalCorElementType()) + { + case ELEMENT_TYPE_ARRAY: + case ELEMENT_TYPE_SZARRAY: + case ELEMENT_TYPE_BYREF: + case ELEMENT_TYPE_PTR: + return ((ParamTypeDesc*)AsTypeDesc())->GetManagedClassObject(); + + case ELEMENT_TYPE_VAR: + case ELEMENT_TYPE_MVAR: + return ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObject(); + + // for this release a function pointer is mapped into an IntPtr. This result in a loss of information. Fix next release + case ELEMENT_TYPE_FNPTR: + return MscorlibBinder::GetElementType(ELEMENT_TYPE_I)->GetManagedClassObject(); + + default: + _ASSERTE(!"Bad Element Type"); + return NULL; + } + } +} + + +OBJECTREF TypeHandle::GetManagedClassObjectFast() const +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + + FORBID_FAULT; + } + CONTRACTL_END; + + OBJECTREF o = NULL; + + if (!IsTypeDesc()) { + o = AsMethodTable()->GetManagedClassObjectIfExists(); + } + else + { + switch(GetInternalCorElementType()) + { + case ELEMENT_TYPE_ARRAY: + case ELEMENT_TYPE_SZARRAY: + case ELEMENT_TYPE_BYREF: + case ELEMENT_TYPE_PTR: + o = ((ParamTypeDesc*)AsTypeDesc())->GetManagedClassObjectFast(); + break; + + case ELEMENT_TYPE_VAR: + case ELEMENT_TYPE_MVAR: + o = ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObjectFast(); + break; + + // for this release a function pointer is mapped into an IntPtr. This result in a loss of information. Fix next release + case ELEMENT_TYPE_FNPTR: + // because TheFnPtrClass() can throw we return NULL for now. That is not a major deal because it just means we will + // not take advantage of this optimization, but the case is rather rare. + //o = TheFnPtrClass()->GetManagedClassObjectFast(); + break; + + default: + _ASSERTE(!"Bad Element Type"); + return NULL; + } + } + return o; +} +#endif // CROSSGEN_COMPILE + +#endif // #ifndef DACCESS_COMPILE + +#if defined(CHECK_APP_DOMAIN_LEAKS) || defined(_DEBUG) + +BOOL TypeHandle::IsAppDomainAgile() const +{ + LIMITED_METHOD_CONTRACT; + + if (!IsTypeDesc()) + { + MethodTable *pMT = AsMethodTable(); + return pMT->GetClass()->IsAppDomainAgile(); + } + else if (IsArray()) + { + TypeHandle th = AsArray()->GetArrayElementTypeHandle(); + return th.IsArrayOfElementsAppDomainAgile(); + } + else + { + // @todo: consider other types of type handles agile? + return FALSE; + } +} + +BOOL TypeHandle::IsCheckAppDomainAgile() const +{ + LIMITED_METHOD_CONTRACT; + + if (!IsTypeDesc()) + { + MethodTable *pMT = AsMethodTable(); + return pMT->GetClass()->IsCheckAppDomainAgile(); + } + else if (IsArray()) + { + TypeHandle th = AsArray()->GetArrayElementTypeHandle(); + return th.IsArrayOfElementsCheckAppDomainAgile(); + } + else + { + // @todo: consider other types of type handles agile? + return FALSE; + } +} + +BOOL TypeHandle::IsArrayOfElementsAppDomainAgile() const +{ + LIMITED_METHOD_CONTRACT; + + if (!IsTypeDesc()) + { + MethodTable *pMT = AsMethodTable(); + return (pMT->GetClass()->IsSealed()) && pMT->GetClass()->IsAppDomainAgile(); + } + else + if (IsArray()) + { + return AsArray()->GetArrayElementTypeHandle().IsArrayOfElementsAppDomainAgile(); + } + else + { + // I'm not sure how to prove a typedesc is sealed, so + // just bail and return FALSE here rather than recursing. + + return FALSE; + } +} + +BOOL TypeHandle::IsArrayOfElementsCheckAppDomainAgile() const +{ + LIMITED_METHOD_CONTRACT; + + if (!IsTypeDesc()) + { + MethodTable *pMT = AsMethodTable(); + return (pMT->GetClass()->IsAppDomainAgile() + && (pMT->GetClass()->IsSealed()) == 0) + || pMT->GetClass()->IsCheckAppDomainAgile(); + } + else + if (IsArray()) + { + return AsArray()->GetArrayElementTypeHandle().IsArrayOfElementsCheckAppDomainAgile(); + } + else + { + // I'm not sure how to prove a typedesc is sealed, so + // just bail and return FALSE here rather than recursing. + + return FALSE; + } +} + +#endif // defined(CHECK_APP_DOMAIN_LEAKS) || defined(_DEBUG) + + +BOOL TypeHandle::IsByRef() const +{ + LIMITED_METHOD_CONTRACT; + + return(IsTypeDesc() && AsTypeDesc()->IsByRef()); + +} + +BOOL TypeHandle::IsPointer() const +{ + LIMITED_METHOD_CONTRACT; + + return(IsTypeDesc() && AsTypeDesc()->IsPointer()); + +} + +// +// The internal type is the type that most of the runtime cares about. This type has had two normalizations +// applied to it +// +// * Enumerated type have been normalized to the primitive type that underlies them (typically int) +// * Value types that look like ints (which include RuntimeTypeHandles, etc), have been morphed to be +// their underlying type (much like enumeration types. See +// * see code:MethodTable#KindsOfElementTypes for more +// * This value is set by code:EEClass::ComputeInternalCorElementTypeForValueType +CorElementType TypeHandle::GetInternalCorElementType() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + return AsTypeDesc()->GetInternalCorElementType(); + else + return AsMethodTable()->GetInternalCorElementType(); +} + +BOOL TypeHandle::IsDomainNeutral() const +{ + LIMITED_METHOD_CONTRACT; + + if (IsTypeDesc()) + return AsTypeDesc()->IsDomainNeutral(); + else + return AsMethodTable()->IsDomainNeutral(); +} + +BOOL TypeHandle::HasInstantiation() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) return false; + if (IsNull()) return false; + return AsMethodTable()->HasInstantiation(); +} + +ClassLoadLevel TypeHandle::GetLoadLevel() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + if (IsTypeDesc()) + { + return AsTypeDesc()->GetLoadLevel(); + } + else + { + return AsMethodTable()->GetLoadLevel(); + } +} + +BOOL TypeHandle::IsFullyLoaded() const +{ + LIMITED_METHOD_CONTRACT; + + if (IsTypeDesc()) + { + return AsTypeDesc()->IsFullyLoaded(); + } + else + { + return AsMethodTable()->IsFullyLoaded(); + } +} + +void TypeHandle::DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level, + DFLPendingList *pPending, BOOL *pfBailed, const InstantiationContext *pInstContext) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + _ASSERTE(level == CLASS_LOADED || level == CLASS_DEPENDENCIES_LOADED); + _ASSERTE(pfBailed != NULL); + _ASSERTE(!(level == CLASS_LOADED && pPending == NULL)); + + + if (IsTypeDesc()) + { + return AsTypeDesc()->DoFullyLoad(pVisited, level, pPending, pfBailed, pInstContext); + } + else + { + return AsMethodTable()->DoFullyLoad(pVisited, level, pPending, pfBailed, pInstContext); + } +} + +// As its name suggests, this returns the type as it is in the meta-data signature. No morphing to deal +// with verification or with value types that are treated as primitives is done. +// see code:MethodTable#KindsOfElementTypes for more +CorElementType TypeHandle::GetSignatureCorElementType() const +{ + LIMITED_METHOD_DAC_CONTRACT; + + // This gets used by + // MethodTable::DoRestoreTypeKey() --> + // Module::RestoreMethodTablePointer() --> + // ZapSig::DecodeType() --> + // SigPointer::GetTypeHandleThrowing --> + // TypeHandle::GetSignatureCorElementType + // early on during the process of restoring, i.e. after the EEClass for the + // MT is restored but not the parent method table. Thus we cannot + // assume that the parent method table is even yet a valid pointer. + // However both MethodTable::GetClass and MethodTable::IsValueType work + // even if the parent method table pointer has not been restored. + + if (IsTypeDesc()) + { + return AsTypeDesc()->GetInternalCorElementType(); + } + else + { + return AsMethodTable()->GetSignatureCorElementType(); + } +} + +// As its name suggests, this returns the type used by the IL verifier. The basic difference between this +// type and the type in the meta-data is that enumerations have been normalized to their underlieing +// primitive type. see code:MethodTable#KindsOfElementTypes for more +CorElementType TypeHandle::GetVerifierCorElementType() const +{ + LIMITED_METHOD_CONTRACT; + + if (IsTypeDesc()) + { + return AsTypeDesc()->GetInternalCorElementType(); + } + else + { + return AsMethodTable()->GetVerifierCorElementType(); + } +} + + +#ifdef DACCESS_COMPILE + +void +TypeHandle::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) +{ + SUPPORTS_DAC; + if (!m_asTAddr) + { + return; + } + + CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED + ( + if (IsArray()) + { + AsArray()->EnumMemoryRegions(flags); + } + else if (IsGenericVariable()) + { + AsGenericVariable()->EnumMemoryRegions(flags); + } + else if (IsFnPtrType()) + { + AsFnPtrType()->EnumMemoryRegions(flags); + } + else if (IsTypeDesc()) + { + DacEnumMemoryRegion(dac_cast(AsTypeDesc()), sizeof(TypeDesc)); + } + else + { + GetMethodTable()->EnumMemoryRegions(flags); + } + ); +} + +#endif // DACCESS_COMPILE + + + +//-------------------------------------------------------------------------------------- +// For generic instantiations, check that it satisfies constraints. +// +// Because this is really a part of DoFullyLoad() that is broken out for readability reasons, +// it takes both the typehandle and its template typehandle as a parameter (DoFullyLoad +// already has the latter typehandle so this way, we avoid a second call to the loader.) +// +// Return value: +// +// Returns TRUE if constraints are satisfied. +// +// Returns FALSE if constraints are violated and the type is a canonical instantiation. (We +// have to let these load as these form the basis of every instantiation. The canonical +// methodtable is not available to users. +// +// THROWS if constraints are violated +// +// +//-------------------------------------------------------------------------------------- +BOOL SatisfiesClassConstraints(TypeHandle instanceTypeHnd, TypeHandle typicalTypeHnd, + const InstantiationContext *pInstContext) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + PRECONDITION(!instanceTypeHnd.IsCanonicalSubtype()); + } + CONTRACTL_END; + +#ifndef DACCESS_COMPILE + + Instantiation formalInst = typicalTypeHnd.GetInstantiation(); + Instantiation actualInst = instanceTypeHnd.GetInstantiation(); + _ASSERTE(formalInst.GetNumArgs() == actualInst.GetNumArgs()); + + for (DWORD i = 0; i < actualInst.GetNumArgs(); i++) + { + TypeHandle thActualArg = actualInst[i]; + + SigTypeContext typeContext; + SigTypeContext::InitTypeContext(instanceTypeHnd, &typeContext); + + // Log the TypeVarTypeDesc access + g_IBCLogger.LogTypeMethodTableWriteableAccess(&thActualArg); + + BOOL bSatisfiesConstraints = + formalInst[i].AsGenericVariable()->SatisfiesConstraints(&typeContext, thActualArg, pInstContext); + + if (!bSatisfiesConstraints) + { + SString argNum; + argNum.Printf("%d", i); + + SString typicalTypeHndName; + TypeString::AppendType(typicalTypeHndName, typicalTypeHnd); + + SString actualParamName; + TypeString::AppendType(actualParamName, actualInst[i]); + + SString formalParamName; + TypeString::AppendType(formalParamName, formalInst[i]); + + COMPlusThrow(kTypeLoadException, + IDS_EE_CLASS_CONSTRAINTS_VIOLATION, + argNum, + actualParamName, + typicalTypeHndName, + formalParamName + ); + } + } + + return TRUE; + +#else + return TRUE; +#endif +} + + + + +#ifndef DACCESS_COMPILE +BOOL TypeHandle::SatisfiesClassConstraints() const +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_INTOLERANT; + + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END; + + BOOL returnValue = FALSE; + Instantiation classInst; + TypeHandle thCanonical; + Instantiation typicalInst; + SigTypeContext typeContext; + TypeHandle thParent; + + INTERIOR_STACK_PROBE_CHECK_THREAD; + + //TODO: cache (positive?) result in methodtable using, say, enum_flag2_UNUSEDxxx + + //TODO: reconsider this check + thParent = GetParent(); + + if (!thParent.IsNull() && !thParent.SatisfiesClassConstraints()) + { + returnValue = FALSE; + goto Exit; + } + + if (!HasInstantiation()) + { + returnValue = TRUE; + goto Exit; + } + + classInst = GetInstantiation(); + thCanonical = ClassLoader::LoadTypeDefThrowing( + GetModule(), + GetCl(), + ClassLoader::ThrowIfNotFound, + ClassLoader::PermitUninstDefOrRef); + typicalInst = thCanonical.GetInstantiation(); + + SigTypeContext::InitTypeContext(*this, &typeContext); + + for (DWORD i = 0; i < classInst.GetNumArgs(); i++) + { + TypeHandle thArg = classInst[i]; + _ASSERTE(!thArg.IsNull()); + + TypeVarTypeDesc* tyvar = typicalInst[i].AsGenericVariable(); + _ASSERTE(tyvar != NULL); + _ASSERTE(TypeFromToken(tyvar->GetTypeOrMethodDef()) == mdtTypeDef); + + tyvar->LoadConstraints(); //TODO: is this necessary for anything but the typical class? + + if (!tyvar->SatisfiesConstraints(&typeContext, thArg)) + { + returnValue = FALSE; + goto Exit; + } + + } + returnValue = TRUE; +Exit: + ; + END_INTERIOR_STACK_PROBE; + + return returnValue; +} + +TypeKey TypeHandle::GetTypeKey() const +{ + LIMITED_METHOD_CONTRACT; + STATIC_CONTRACT_SO_TOLERANT; + PRECONDITION(!IsGenericVariable()); + + if (IsTypeDesc()) + { + TypeDesc *pTD = AsTypeDesc(); + CorElementType etype = pTD->GetInternalCorElementType(); + if (CorTypeInfo::IsArray_NoThrow(etype)) + { + TypeKey tk(etype, pTD->GetTypeParam(), FALSE, pTD->GetMethodTable()->GetRank()); + return tk; + } + else if (CorTypeInfo::IsModifier_NoThrow(etype) || etype == ELEMENT_TYPE_VALUETYPE) + { + TypeKey tk(etype, pTD->GetTypeParam()); + return tk; + } + else + { + CONSISTENCY_CHECK(etype == ELEMENT_TYPE_FNPTR); + FnPtrTypeDesc* pFTD = (FnPtrTypeDesc*) pTD; + TypeKey tk(pFTD->GetCallConv(), pFTD->GetNumArgs(), pFTD->GetRetAndArgTypesPointer()); + return tk; + } + } + else + { + MethodTable *pMT = AsMethodTable(); + if (pMT->IsArray()) + { + TypeKey tk(pMT->GetInternalCorElementType(), pMT->GetApproxArrayElementTypeHandle(), TRUE, pMT->GetRank()); + return tk; + } + else if (pMT->IsTypicalTypeDefinition()) + { + TypeKey tk(pMT->GetModule(), pMT->GetCl()); + return tk; + } + else + { + TypeKey tk(pMT->GetModule(), pMT->GetCl(), pMT->GetInstantiation()); + return tk; + } + } +} + + +#ifdef _DEBUG +// Check that a type handle matches the key provided +CHECK TypeHandle::CheckMatchesKey(TypeKey *pKey) const +{ + WRAPPER_NO_CONTRACT; + CONTRACT_VIOLATION(TakesLockViolation); // this is debug-only code + CONSISTENCY_CHECK(!IsGenericVariable()); + + // Check first to avoid creating debug name + if (!GetTypeKey().Equals(pKey)) + { + StackSString typeKeyString; + CONTRACT_VIOLATION(GCViolation|ThrowsViolation); + TypeString::AppendTypeKeyDebug(typeKeyString, pKey); + if (!IsTypeDesc() && AsMethodTable()->IsArray()) + { + MethodTable *pMT = AsMethodTable(); + CHECK_MSGF(pMT->GetInternalCorElementType() == pKey->GetKind(), + ("CorElementType %d of Array MethodTable does not match key %S", pMT->GetArrayElementType(), typeKeyString.GetUnicode())); + + CHECK_MSGF(pMT->GetApproxArrayElementTypeHandle() == pKey->GetElementType(), + ("Element type of Array MethodTable does not match key %S",typeKeyString.GetUnicode())); + + CHECK_MSGF(pMT->GetRank() == pKey->GetRank(), + ("Rank %d of Array MethodTable does not match key %S", pMT->GetRank(), typeKeyString.GetUnicode())); + } + else + if (IsTypeDesc()) + { + TypeDesc *pTD = AsTypeDesc(); + CHECK_MSGF(pTD->GetInternalCorElementType() == pKey->GetKind(), + ("CorElementType %d of TypeDesc does not match key %S", pTD->GetInternalCorElementType(), typeKeyString.GetUnicode())); + + if (CorTypeInfo::IsModifier(pKey->GetKind())) + { + CHECK_MSGF(pTD->GetTypeParam() == pKey->GetElementType(), + ("Element type of TypeDesc does not match key %S",typeKeyString.GetUnicode())); + } + if (CorTypeInfo::IsArray(pKey->GetKind())) + { + CHECK_MSGF(pTD->GetMethodTable()->GetRank() == pKey->GetRank(), + ("Rank %d of array TypeDesc does not match key %S", pTD->GetMethodTable()->GetRank(), typeKeyString.GetUnicode())); + } + } + else + { + MethodTable *pMT = AsMethodTable(); + CHECK_MSGF(pMT->GetModule() == pKey->GetModule(), ("Module of MethodTable does not match key %S", typeKeyString.GetUnicode())); + CHECK_MSGF(pMT->GetCl() == pKey->GetTypeToken(), + ("TypeDef %x of Methodtable does not match TypeDef %x of key %S", pMT->GetCl(), pKey->GetTypeToken(), + typeKeyString.GetUnicode())); + + if (pMT->IsTypicalTypeDefinition()) + { + CHECK_MSGF(pKey->GetNumGenericArgs() == 0 && !pKey->HasInstantiation(), + ("Key %S for Typical MethodTable has non-zero number of generic arguments", typeKeyString.GetUnicode())); + } + else + { + CHECK_MSGF(pMT->GetNumGenericArgs() == pKey->GetNumGenericArgs(), + ("Number of generic params %d in MethodTable does not match key %S", pMT->GetNumGenericArgs(), typeKeyString.GetUnicode())); + if (pKey->HasInstantiation()) + { + for (DWORD i = 0; i < pMT->GetNumGenericArgs(); i++) + { +#ifdef FEATURE_PREJIT + CHECK_MSGF(ZapSig::CompareTypeHandleFieldToTypeHandle(pMT->GetInstantiation().GetRawArgs()[i].GetValuePtr(), pKey->GetInstantiation()[i]), + ("Generic argument %d in MethodTable does not match key %S", i, typeKeyString.GetUnicode())); +#else + CHECK_MSGF(pMT->GetInstantiation()[i] == pKey->GetInstantiation()[i], + ("Generic argument %d in MethodTable does not match key %S", i, typeKeyString.GetUnicode())); +#endif + } + } + } + } + } + CHECK_OK; +} + +const char * const classLoadLevelName[] = +{ + "BEGIN", + "UNRESTOREDTYPEKEY", + "UNRESTORED", + "APPROXPARENTS", + "EXACTPARENTS", + "DEPENDENCIES_LOADED", + "LOADED", +}; + +// Check that this type is loaded up to the level indicated +// Also check that it is non-null +CHECK TypeHandle::CheckLoadLevel(ClassLoadLevel requiredLevel) +{ + CHECK(!IsNull()); + // CHECK_MSGF(!IsNull(), ("Type is null, required load level is %s", classLoadLevelName[requiredLevel])); + static_assert_no_msg(NumItems(classLoadLevelName) == (1 + CLASS_LOAD_LEVEL_FINAL)); + + // Quick check to avoid creating debug string + ClassLoadLevel actualLevel = GetLoadLevel(); + if (actualLevel < requiredLevel) + { + // SString debugTypeName; + // TypeString::AppendTypeDebug(debugTypeName, *this); + CHECK(actualLevel >= requiredLevel); + // CHECK_MSGF(actualLevel >= requiredLevel, + // ("Type has not been sufficiently loaded (actual level is %d, required level is %d)", + // /* debugTypeName.GetUnicode(), */ actualLevel, requiredLevel /* classLoadLevelName[actualLevel], classLoadLevelName[requiredLevel] */)); + } + CONSISTENCY_CHECK((actualLevel > CLASS_LOAD_UNRESTORED) == IsRestored()); + CONSISTENCY_CHECK((actualLevel == CLASS_LOAD_UNRESTOREDTYPEKEY) == HasUnrestoredTypeKey()); + CHECK_OK; +} + +// Check that this type is fully loaded (i.e. to level CLASS_LOADED) +CHECK TypeHandle::CheckFullyLoaded() +{ + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + SO_TOLERANT; + MODE_ANY; + } + CONTRACTL_END; + if (IsGenericVariable()) + { + CHECK_OK; + } + CheckLoadLevel(CLASS_LOADED); + CHECK_OK; +} + +#endif //DEBUG + +#endif //DACCESS_COMPILE -- cgit v1.2.3