1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
10 // This file contains definitions for methods in the code:TypeDesc class and its
12 // code:ParamTypeDesc,
13 // code:ArrayTypeDesc,
14 // code:TyVarTypeDesc,
19 // ============================================================================
23 #include "typestring.h"
24 #if defined(FEATURE_PREJIT)
29 #ifndef DACCESS_COMPILE
32 BOOL ParamTypeDesc::Verify() {
34 STATIC_CONTRACT_NOTHROW;
35 STATIC_CONTRACT_GC_NOTRIGGER;
36 STATIC_CONTRACT_FORBID_FAULT;
37 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
38 STATIC_CONTRACT_DEBUG_ONLY;
39 STATIC_CONTRACT_SUPPORTS_DAC;
41 _ASSERTE(m_TemplateMT.IsNull() || GetTemplateMethodTableInternal()->SanityCheck());
42 _ASSERTE(!GetTypeParam().IsNull());
43 BAD_FORMAT_NOTHROW_ASSERT(GetTypeParam().IsTypeDesc() || !GetTypeParam().AsMethodTable()->IsArray());
44 BAD_FORMAT_NOTHROW_ASSERT(CorTypeInfo::IsModifier_NoThrow(GetInternalCorElementType()) ||
45 GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE);
46 GetTypeParam().Verify();
50 BOOL ArrayTypeDesc::Verify() {
52 STATIC_CONTRACT_NOTHROW;
53 STATIC_CONTRACT_GC_NOTRIGGER;
54 STATIC_CONTRACT_FORBID_FAULT;
55 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
56 STATIC_CONTRACT_DEBUG_ONLY;
57 STATIC_CONTRACT_SUPPORTS_DAC;
59 // m_TemplateMT == 0 may be null when building types involving TypeVarTypeDesc's
60 BAD_FORMAT_NOTHROW_ASSERT(m_TemplateMT.IsNull() || GetTemplateMethodTable()->IsArray());
61 BAD_FORMAT_NOTHROW_ASSERT(CorTypeInfo::IsArray_NoThrow(GetInternalCorElementType()));
62 ParamTypeDesc::Verify();
68 #endif // #ifndef DACCESS_COMPILE
70 TypeHandle TypeDesc::GetBaseTypeParam()
72 LIMITED_METHOD_DAC_CONTRACT;
74 _ASSERTE(HasTypeParam());
76 TypeHandle th = dac_cast<PTR_ParamTypeDesc>(this)->GetTypeParam();
77 while (th.HasTypeParam())
79 th = dac_cast<PTR_ParamTypeDesc>(th.AsTypeDesc())->GetTypeParam();
81 _ASSERTE(!th.IsNull());
86 PTR_Module TypeDesc::GetLoaderModule()
88 STATIC_CONTRACT_NOTHROW;
89 STATIC_CONTRACT_GC_NOTRIGGER;
90 STATIC_CONTRACT_FORBID_FAULT;
95 return GetBaseTypeParam().GetLoaderModule();
97 else if (IsGenericVariable())
99 return dac_cast<PTR_TypeVarTypeDesc>(this)->GetModule();
103 PTR_Module retVal = NULL;
106 _ASSERTE(GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
107 PTR_FnPtrTypeDesc asFnPtr = dac_cast<PTR_FnPtrTypeDesc>(this);
110 retVal = ClassLoader::ComputeLoaderModuleForFunctionPointer(asFnPtr->GetRetAndArgTypesPointer(), asFnPtr->GetNumArgs()+1);
117 PTR_Module TypeDesc::GetZapModule()
121 return ExecutionManager::FindZapModule(dac_cast<TADDR>(this));
124 PTR_BaseDomain TypeDesc::GetDomain()
135 return dac_cast<PTR_BaseDomain>(AppDomain::GetCurrentDomain());
138 PTR_Module TypeDesc::GetModule() {
145 // Function pointer types belong to no module
146 //PRECONDITION(GetInternalCorElementType() != ELEMENT_TYPE_FNPTR);
150 // Note here we are making the assumption that a typeDesc lives in
151 // the classloader of its element type.
155 return GetBaseTypeParam().GetModule();
158 if (IsGenericVariable())
160 PTR_TypeVarTypeDesc asVar = dac_cast<PTR_TypeVarTypeDesc>(this);
161 return asVar->GetModule();
164 _ASSERTE(GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
166 return GetLoaderModule();
169 BOOL ParamTypeDesc::OwnsTemplateMethodTable()
178 CorElementType kind = GetInternalCorElementType();
180 // The m_TemplateMT for pointer types is UIntPtr
181 if (!CorTypeInfo::IsArray_NoThrow(kind))
186 CorElementType elemType = m_Arg.GetSignatureCorElementType();
188 // This check matches precisely one in Module::CreateArrayMethodTable
190 // They indicate if an array TypeDesc is non-canonical (in much the same a a generic
191 // method table being non-canonical), i.e. it is not the primary
192 // owner of the m_TemplateMT (the primary owner is the TypeDesc for object[])
194 if (CorTypeInfo::IsGenericVariable_NoThrow(elemType))
202 Assembly* TypeDesc::GetAssembly() {
203 STATIC_CONTRACT_NOTHROW;
204 STATIC_CONTRACT_GC_NOTRIGGER;
205 STATIC_CONTRACT_FORBID_FAULT;
207 Module *pModule = GetModule();
208 PREFIX_ASSUME(pModule!=NULL);
209 return pModule->GetAssembly();
212 void TypeDesc::GetName(SString &ssBuf)
218 INJECT_FAULT(COMPlusThrowOM(););
222 CorElementType kind = GetInternalCorElementType();
226 if (CorTypeInfo::IsModifier(kind))
229 th = TypeHandle(this);
231 if (kind == ELEMENT_TYPE_ARRAY)
232 rank = dac_cast<PTR_ArrayTypeDesc>(this)->GetRank();
233 else if (CorTypeInfo::IsGenericVariable(kind))
234 rank = dac_cast<PTR_TypeVarTypeDesc>(this)->GetIndex();
238 ConstructName(kind, th, rank, ssBuf);
241 void TypeDesc::ConstructName(CorElementType kind,
250 INJECT_FAULT(COMPlusThrowOM()); // SString operations can allocate.
254 if (CorTypeInfo::IsModifier(kind))
256 param.GetName(ssBuff);
261 case ELEMENT_TYPE_BYREF:
262 ssBuff.Append(W('&'));
265 case ELEMENT_TYPE_PTR:
266 ssBuff.Append(W('*'));
269 case ELEMENT_TYPE_SZARRAY:
270 ssBuff.Append(W("[]"));
273 case ELEMENT_TYPE_ARRAY:
274 ssBuff.Append(W('['));
278 ssBuff.Append(W('*'));
284 ssBuff.Append(W(','));
288 ssBuff.Append(W(']'));
291 case ELEMENT_TYPE_VAR:
292 case ELEMENT_TYPE_MVAR:
293 if (kind == ELEMENT_TYPE_VAR)
295 ssBuff.Printf(W("!%d"), rank);
299 ssBuff.Printf(W("!!%d"), rank);
303 case ELEMENT_TYPE_FNPTR:
304 ssBuff.Printf(W("FNPTR"));
308 LPCUTF8 namesp = CorTypeInfo::GetNamespace(kind);
309 if(namesp && *namesp) {
310 ssBuff.AppendUTF8(namesp);
311 ssBuff.Append(W('.'));
314 LPCUTF8 name = CorTypeInfo::GetName(kind);
315 BAD_FORMAT_NOTHROW_ASSERT(name);
317 ssBuff.AppendUTF8(name);
322 BOOL TypeDesc::IsArray()
324 LIMITED_METHOD_DAC_CONTRACT;
325 return CorTypeInfo::IsArray_NoThrow(GetInternalCorElementType());
328 BOOL TypeDesc::IsGenericVariable()
330 LIMITED_METHOD_DAC_CONTRACT;
331 return CorTypeInfo::IsGenericVariable_NoThrow(GetInternalCorElementType());
334 BOOL TypeDesc::IsFnPtr()
336 LIMITED_METHOD_DAC_CONTRACT;
337 return (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
340 BOOL TypeDesc::IsNativeValueType()
343 return (GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE);
346 BOOL TypeDesc::HasTypeParam()
350 return CorTypeInfo::IsModifier_NoThrow(GetInternalCorElementType()) ||
351 GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE;
354 #ifndef DACCESS_COMPILE
356 BOOL TypeDesc::CanCastTo(TypeHandle toType, TypeHandlePairList *pVisited)
362 INJECT_FAULT(COMPlusThrowOM());
366 if (TypeHandle(this) == toType)
369 //A boxed variable type can be cast to any of its constraints, or object, if none are specified
370 if (IsGenericVariable())
372 TypeVarTypeDesc *tyvar = (TypeVarTypeDesc*) this;
374 DWORD numConstraints;
375 TypeHandle *constraints = tyvar->GetConstraints(&numConstraints, CLASS_DEPENDENCIES_LOADED);
377 if (toType == g_pObjectClass)
380 if (toType == g_pValueTypeClass)
382 mdGenericParam genericParamToken = tyvar->GetToken();
384 if (FAILED(tyvar->GetModule()->GetMDImport()->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
388 DWORD specialConstraints = flags & gpSpecialConstraintMask;
389 if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
393 if (constraints == NULL)
396 for (DWORD i = 0; i < numConstraints; i++)
398 if (constraints[i].CanCastTo(toType, pVisited))
404 // If we're not casting to a TypeDesc (i.e. not to a reference array type, variable type etc.)
405 // then we must be trying to cast to a class or interface type.
406 if (!toType.IsTypeDesc())
410 // I am a variable type, pointer type, function pointer type
411 // etc. I am not an object or value type. Therefore
412 // I can't be cast to an object or value type.
416 MethodTable *pMT = GetMethodTable();
419 // This does the right thing if 'type' == System.Array or System.Object, System.Clonable ...
420 if (pMT->CanCastToClassOrInterface(toType.AsMethodTable(), pVisited) != 0)
425 if (IsArray() && toType.AsMethodTable()->IsInterface())
427 if (ArraySupportsBizarreInterface((ArrayTypeDesc*)this, toType.AsMethodTable()))
437 TypeDesc* toTypeDesc = toType.AsTypeDesc();
439 CorElementType toKind = toTypeDesc->GetInternalCorElementType();
440 CorElementType fromKind = GetInternalCorElementType();
442 // The element kinds must match, only exception is that SZARRAY matches a one dimension ARRAY
443 if (!(toKind == fromKind || (toKind == ELEMENT_TYPE_ARRAY && fromKind == ELEMENT_TYPE_SZARRAY)))
448 case ELEMENT_TYPE_ARRAY:
449 if (dac_cast<PTR_ArrayTypeDesc>(this)->GetRank() != dac_cast<PTR_ArrayTypeDesc>(toTypeDesc)->GetRank())
452 case ELEMENT_TYPE_SZARRAY:
453 case ELEMENT_TYPE_BYREF:
454 case ELEMENT_TYPE_PTR:
455 return TypeDesc::CanCastParam(dac_cast<PTR_ParamTypeDesc>(this)->GetTypeParam(), dac_cast<PTR_ParamTypeDesc>(toTypeDesc)->GetTypeParam(), pVisited);
457 case ELEMENT_TYPE_VAR:
458 case ELEMENT_TYPE_MVAR:
459 case ELEMENT_TYPE_FNPTR:
463 BAD_FORMAT_NOTHROW_ASSERT(toKind == ELEMENT_TYPE_TYPEDBYREF || CorTypeInfo::IsPrimitiveType(toKind));
468 BOOL TypeDesc::CanCastParam(TypeHandle fromParam, TypeHandle toParam, TypeHandlePairList *pVisited)
474 INJECT_FAULT(COMPlusThrowOM());
478 // While boxed value classes inherit from object their
479 // unboxed versions do not. Parameterized types have the
480 // unboxed version, thus, if the from type parameter is value
481 // class then only an exact match/equivalence works.
482 if (fromParam.IsEquivalentTo(toParam))
485 // Object parameters dont need an exact match but only inheritance, check for that
486 CorElementType fromParamCorType = fromParam.GetVerifierCorElementType();
487 if (CorTypeInfo::IsObjRef(fromParamCorType))
489 return fromParam.CanCastTo(toParam, pVisited);
491 else if (CorTypeInfo::IsGenericVariable(fromParamCorType))
493 TypeVarTypeDesc* varFromParam = fromParam.AsGenericVariable();
495 if (!varFromParam->ConstraintsLoaded())
496 varFromParam->LoadConstraints(CLASS_DEPENDENCIES_LOADED);
498 if (!varFromParam->ConstrainedAsObjRef())
501 return fromParam.CanCastTo(toParam, pVisited);
503 else if(CorTypeInfo::IsPrimitiveType(fromParamCorType))
505 CorElementType toParamCorType = toParam.GetVerifierCorElementType();
506 if(CorTypeInfo::IsPrimitiveType(toParamCorType))
508 if (GetNormalizedIntegralArrayElementType(toParamCorType) == GetNormalizedIntegralArrayElementType(fromParamCorType))
510 } // end if(CorTypeInfo::IsPrimitiveType(toParamCorType))
511 } // end if(CorTypeInfo::IsPrimitiveType(fromParamCorType))
513 // Anything else is not a match.
517 TypeHandle::CastResult TypeDesc::CanCastToNoGC(TypeHandle toType)
527 if (TypeHandle(this) == toType)
528 return TypeHandle::CanCast;
530 //A boxed variable type can be cast to any of its constraints, or object, if none are specified
531 if (IsGenericVariable())
533 TypeVarTypeDesc *tyvar = (TypeVarTypeDesc*) this;
535 if (!tyvar->ConstraintsLoaded())
536 return TypeHandle::MaybeCast;
538 DWORD numConstraints;
539 TypeHandle *constraints = tyvar->GetCachedConstraints(&numConstraints);
541 if (toType == g_pObjectClass)
542 return TypeHandle::CanCast;
544 if (toType == g_pValueTypeClass)
545 return TypeHandle::MaybeCast;
547 if (constraints == NULL)
548 return TypeHandle::CannotCast;
550 for (DWORD i = 0; i < numConstraints; i++)
552 if (constraints[i].CanCastToNoGC(toType) == TypeHandle::CanCast)
553 return TypeHandle::CanCast;
555 return TypeHandle::MaybeCast;
558 // If we're not casting to a TypeDesc (i.e. not to a reference array type, variable type etc.)
559 // then we must be trying to cast to a class or interface type.
560 if (!toType.IsTypeDesc())
564 // I am a variable type, pointer type, function pointer type
565 // etc. I am not an object or value type. Therefore
566 // I can't be cast to an object or value type.
567 return TypeHandle::CannotCast;
570 MethodTable *pMT = GetMethodTable();
573 // This does the right thing if 'type' == System.Array or System.Object, System.Clonable ...
574 return pMT->CanCastToClassOrInterfaceNoGC(toType.AsMethodTable());
577 TypeDesc* toTypeDesc = toType.AsTypeDesc();
579 CorElementType toKind = toTypeDesc->GetInternalCorElementType();
580 CorElementType fromKind = GetInternalCorElementType();
582 // The element kinds must match, only exception is that SZARRAY matches a one dimension ARRAY
583 if (!(toKind == fromKind || (toKind == ELEMENT_TYPE_ARRAY && fromKind == ELEMENT_TYPE_SZARRAY)))
584 return TypeHandle::CannotCast;
588 case ELEMENT_TYPE_ARRAY:
589 if (dac_cast<PTR_ArrayTypeDesc>(this)->GetRank() != dac_cast<PTR_ArrayTypeDesc>(toTypeDesc)->GetRank())
590 return TypeHandle::CannotCast;
592 case ELEMENT_TYPE_SZARRAY:
593 case ELEMENT_TYPE_BYREF:
594 case ELEMENT_TYPE_PTR:
595 return TypeDesc::CanCastParamNoGC(dac_cast<PTR_ParamTypeDesc>(this)->GetTypeParam(), dac_cast<PTR_ParamTypeDesc>(toTypeDesc)->GetTypeParam());
597 case ELEMENT_TYPE_VAR:
598 case ELEMENT_TYPE_MVAR:
599 case ELEMENT_TYPE_FNPTR:
600 return TypeHandle::CannotCast;
603 BAD_FORMAT_NOTHROW_ASSERT(toKind == ELEMENT_TYPE_TYPEDBYREF || CorTypeInfo::IsPrimitiveType_NoThrow(toKind));
604 return TypeHandle::CanCast;
608 TypeHandle::CastResult TypeDesc::CanCastParamNoGC(TypeHandle fromParam, TypeHandle toParam)
618 // While boxed value classes inherit from object their
619 // unboxed versions do not. Parameterized types have the
620 // unboxed version, thus, if the from type parameter is value
621 // class then only an exact match works.
622 if (fromParam == toParam)
623 return TypeHandle::CanCast;
625 // Object parameters dont need an exact match but only inheritance, check for that
626 CorElementType fromParamCorType = fromParam.GetVerifierCorElementType();
627 if (CorTypeInfo::IsObjRef_NoThrow(fromParamCorType))
629 return fromParam.CanCastToNoGC(toParam);
631 else if (CorTypeInfo::IsGenericVariable_NoThrow(fromParamCorType))
633 TypeVarTypeDesc* varFromParam = fromParam.AsGenericVariable();
635 if (!varFromParam->ConstraintsLoaded())
636 return TypeHandle::MaybeCast;
638 if (!varFromParam->ConstrainedAsObjRef())
639 return TypeHandle::CannotCast;
641 return fromParam.CanCastToNoGC(toParam);
643 else if (CorTypeInfo::IsPrimitiveType_NoThrow(fromParamCorType))
645 CorElementType toParamCorType = toParam.GetVerifierCorElementType();
646 if(CorTypeInfo::IsPrimitiveType_NoThrow(toParamCorType))
648 if (toParamCorType == fromParamCorType)
649 return TypeHandle::CanCast;
651 // Primitive types such as E_T_I4 and E_T_U4 are interchangeable
652 // Enums with interchangeable underlying types are interchangable
653 // BOOL is NOT interchangeable with I1/U1, neither CHAR -- with I2/U2
654 if((toParamCorType != ELEMENT_TYPE_BOOLEAN)
655 &&(fromParamCorType != ELEMENT_TYPE_BOOLEAN)
656 &&(toParamCorType != ELEMENT_TYPE_CHAR)
657 &&(fromParamCorType != ELEMENT_TYPE_CHAR))
659 if ((CorTypeInfo::Size_NoThrow(toParamCorType) == CorTypeInfo::Size_NoThrow(fromParamCorType))
660 && (CorTypeInfo::IsFloat_NoThrow(toParamCorType) == CorTypeInfo::IsFloat_NoThrow(fromParamCorType)))
662 return TypeHandle::CanCast;
665 } // end if(CorTypeInfo::IsPrimitiveType(toParamCorType))
666 } // end if(CorTypeInfo::IsPrimitiveType(fromParamCorType))
669 // Types with equivalence need the slow path
670 MethodTable * pFromMT = fromParam.GetMethodTable();
671 if (pFromMT != NULL && pFromMT->HasTypeEquivalence())
672 return TypeHandle::MaybeCast;
673 MethodTable * pToMT = toParam.GetMethodTable();
674 if (pToMT != NULL && pToMT->HasTypeEquivalence())
675 return TypeHandle::MaybeCast;
678 // Anything else is not a match.
679 return TypeHandle::CannotCast;
682 BOOL TypeDesc::IsEquivalentTo(TypeHandle type COMMA_INDEBUG(TypeHandlePairList *pVisited))
692 if (TypeHandle(this) == type)
695 if (!type.IsTypeDesc())
698 TypeDesc *pOther = type.AsTypeDesc();
700 // bail early for normal types
701 if (!HasTypeEquivalence() || !pOther->HasTypeEquivalence())
704 // if the TypeDesc types are different, then they are not equivalent
705 if (GetInternalCorElementType() != pOther->GetInternalCorElementType())
710 // pointer, byref, array
712 // Arrays must have the same rank.
715 ArrayTypeDesc *pThisArray = (ArrayTypeDesc *)this;
716 ArrayTypeDesc *pOtherArray = (ArrayTypeDesc *)pOther;
717 if (pThisArray->GetRank() != pOtherArray->GetRank())
721 return GetTypeParam().IsEquivalentTo(pOther->GetTypeParam() COMMA_INDEBUG(pVisited));
727 #endif // #ifndef DACCESS_COMPILE
731 TypeHandle TypeDesc::GetParent() {
733 STATIC_CONTRACT_NOTHROW;
734 STATIC_CONTRACT_GC_NOTRIGGER;
735 STATIC_CONTRACT_FORBID_FAULT;
737 CorElementType kind = GetInternalCorElementType();
738 if (CorTypeInfo::IsArray_NoThrow(kind)) {
740 BAD_FORMAT_NOTHROW_ASSERT(kind == ELEMENT_TYPE_SZARRAY || kind == ELEMENT_TYPE_ARRAY);
741 return ((ArrayTypeDesc*)this)->GetParent();
743 if (CorTypeInfo::IsPrimitiveType_NoThrow(kind))
744 return (MethodTable*)g_pObjectClass;
748 #ifndef DACCESS_COMPILE
750 #ifndef CROSSGEN_COMPILE
751 OBJECTREF ParamTypeDesc::GetManagedClassObject()
758 INJECT_FAULT(COMPlusThrowOM());
760 PRECONDITION(GetInternalCorElementType() == ELEMENT_TYPE_ARRAY ||
761 GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY ||
762 GetInternalCorElementType() == ELEMENT_TYPE_BYREF ||
763 GetInternalCorElementType() == ELEMENT_TYPE_PTR);
767 if (m_hExposedClassObject == NULL) {
768 REFLECTCLASSBASEREF refClass = NULL;
769 GCPROTECT_BEGIN(refClass);
770 refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass);
772 LoaderAllocator *pLoaderAllocator = GetLoaderAllocator();
773 TypeHandle th = TypeHandle(this);
774 ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th);
775 ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject());
777 // Let all threads fight over who wins using InterlockedCompareExchange.
778 // Only the winner can set m_hExposedClassObject from NULL.
779 LOADERHANDLE hExposedClassObject = pLoaderAllocator->AllocateHandle(refClass);
781 EnsureWritablePages(this);
782 if (FastInterlockCompareExchangePointer(&m_hExposedClassObject, hExposedClassObject, static_cast<LOADERHANDLE>(NULL)))
784 pLoaderAllocator->FreeHandle(hExposedClassObject);
787 if (OwnsTemplateMethodTable())
789 // Set the handle on template methodtable as well to make Object.GetType for arrays take the fast path
790 EnsureWritablePages(GetTemplateMethodTableInternal()->GetWriteableDataForWrite())->m_hExposedClassObject = m_hExposedClassObject;
793 // Log the TypeVarTypeDesc access
794 g_IBCLogger.LogTypeMethodTableWriteableAccess(&th);
798 return GetManagedClassObjectIfExists();
800 #endif // CROSSGEN_COMPILE
802 #endif // #ifndef DACCESS_COMPILE
804 BOOL TypeDesc::IsRestored()
806 STATIC_CONTRACT_NOTHROW;
807 STATIC_CONTRACT_GC_NOTRIGGER;
808 STATIC_CONTRACT_FORBID_FAULT;
809 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
812 TypeHandle th = TypeHandle(this);
813 g_IBCLogger.LogTypeMethodTableAccess(&th);
814 return IsRestored_NoLogging();
817 BOOL TypeDesc::IsRestored_NoLogging()
819 STATIC_CONTRACT_NOTHROW;
820 STATIC_CONTRACT_GC_NOTRIGGER;
821 STATIC_CONTRACT_FORBID_FAULT;
822 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
825 return (m_typeAndFlags & TypeDesc::enum_flag_Unrestored) == 0;
828 ClassLoadLevel TypeDesc::GetLoadLevel()
830 STATIC_CONTRACT_NOTHROW;
831 STATIC_CONTRACT_GC_NOTRIGGER;
832 STATIC_CONTRACT_FORBID_FAULT;
835 if (m_typeAndFlags & TypeDesc::enum_flag_UnrestoredTypeKey)
837 return CLASS_LOAD_UNRESTOREDTYPEKEY;
839 else if (m_typeAndFlags & TypeDesc::enum_flag_Unrestored)
841 return CLASS_LOAD_UNRESTORED;
843 else if (m_typeAndFlags & TypeDesc::enum_flag_IsNotFullyLoaded)
845 if (m_typeAndFlags & TypeDesc::enum_flag_DependenciesLoaded)
847 return CLASS_DEPENDENCIES_LOADED;
851 return CLASS_LOAD_EXACTPARENTS;
859 // Recursive worker that pumps the transitive closure of a type's dependencies to the specified target level.
860 // Dependencies include:
864 // - canonical type, for non-canonical instantiations
865 // - typical type, for non-typical instantiations
869 // pVisited - used to prevent endless recursion in the case of cyclic dependencies
871 // level - target level to pump to - must be CLASS_DEPENDENCIES_LOADED or CLASS_LOADED
873 // if CLASS_DEPENDENCIES_LOADED, all transitive dependencies are resolved to their
876 // if CLASS_LOADED, all type-safety checks are done on the type and all its transitive
877 // dependencies. Note that for the CLASS_LOADED case, some types may be left
878 // on the pending list rather that pushed to CLASS_LOADED in the case of cyclic
879 // dependencies - the root caller must handle this.
882 // pfBailed - if we or one of our depedencies bails early due to cyclic dependencies, we
883 // must set *pfBailed to TRUE. Otherwise, we must *leave it unchanged* (thus, the
884 // boolean acts as a cumulative OR.)
886 // pPending - if one of our dependencies bailed, the type cannot yet be promoted to CLASS_LOADED
887 // as the dependencies will be checked later and may fail a security check then.
888 // Instead, DoFullyLoad() will add the type to the pending list - the root caller
889 // is responsible for promoting the type after the full transitive closure has been
890 // walked. Note that it would be just as correct to always defer to the pending list -
891 // however, that is a little less performant.
893 // pInstContext - instantiation context created in code:SigPointer.GetTypeHandleThrowing and ultimately
894 // passed down to code:TypeVarTypeDesc.SatisfiesConstraints.
896 void TypeDesc::DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level,
897 DFLPendingList *pPending, BOOL *pfBailed, const InstantiationContext *pInstContext)
906 _ASSERTE(level == CLASS_LOADED || level == CLASS_DEPENDENCIES_LOADED);
907 _ASSERTE(pfBailed != NULL);
908 _ASSERTE(!(level == CLASS_LOADED && pPending == NULL));
911 #ifndef DACCESS_COMPILE
913 if (Generics::RecursionGraph::HasSeenType(pVisited, TypeHandle(this)))
919 if (GetLoadLevel() >= level)
924 if (level == CLASS_LOADED)
926 UINT numTH = pPending->Count();
927 TypeHandle *pTypeHndPending = pPending->Table();
928 for (UINT idxPending = 0; idxPending < numTH; idxPending++)
930 if (pTypeHndPending[idxPending].IsTypeDesc() && pTypeHndPending[idxPending].AsTypeDesc() == this)
940 BOOL fBailed = FALSE;
942 // First ensure that we're loaded to just below CLASS_LOADED
943 ClassLoader::EnsureLoaded(TypeHandle(this), (ClassLoadLevel) (level-1));
945 Generics::RecursionGraph newVisited(pVisited, TypeHandle(this));
949 // Fully load the type parameter
950 GetTypeParam().DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext);
952 ParamTypeDesc* pPTD = (ParamTypeDesc*) this;
954 // Fully load the template method table
955 if (!pPTD->m_TemplateMT.IsNull())
957 pPTD->GetTemplateMethodTableInternal()->DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext);
963 case CLASS_DEPENDENCIES_LOADED:
964 FastInterlockOr(&m_typeAndFlags, TypeDesc::enum_flag_DependenciesLoaded);
970 // We couldn't complete security checks on some dependency because he is already being processed by one of our callers.
971 // Do not mark this class fully loaded yet. Put him on the pending list and he will be marked fully loaded when
972 // everything unwinds.
976 TypeHandle* pthPending = pPending->AppendThrowing();
977 *pthPending = TypeHandle(this);
981 // Finally, mark this method table as fully loaded
987 _ASSERTE(!"Can't get here.");
994 #ifdef FEATURE_PREJIT
995 void TypeDesc::DoRestoreTypeKey()
1004 #ifndef DACCESS_COMPILE
1007 ParamTypeDesc* pPTD = (ParamTypeDesc*) this;
1008 EnsureWritablePages(pPTD);
1010 // Must have the same loader module, so not encoded
1011 CONSISTENCY_CHECK(!pPTD->m_Arg.IsEncodedFixup());
1012 ClassLoader::EnsureLoaded(pPTD->m_Arg, CLASS_LOAD_UNRESTORED);
1014 // Might live somewhere else e.g. Object[] is shared across all ref array types
1015 Module::RestoreMethodTablePointer(&(pPTD->m_TemplateMT), NULL, CLASS_LOAD_UNRESTORED);
1019 EnsureWritablePages(this);
1022 FastInterlockAnd(&m_typeAndFlags, ~TypeDesc::enum_flag_UnrestoredTypeKey);
1026 #ifndef DACCESS_COMPILE
1028 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
1029 // This just performs a shallow save
1030 void TypeDesc::Save(DataImage *image)
1032 STANDARD_VM_CONTRACT;
1034 ClassLoader::EnsureLoaded(TypeHandle(this));
1036 if (LoggingOn(LF_ZAP, LL_INFO10000))
1039 TypeString::AppendType(name, TypeHandle(this));
1040 LOG((LF_ZAP, LL_INFO10000, "TypeDesc::Save %S\n", name.GetUnicode()));
1043 if (IsGenericVariable())
1045 ((TypeVarTypeDesc*)this)->Save(image);
1047 else if (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR)
1049 ((FnPtrTypeDesc *)this)->Save(image);
1053 _ASSERTE(HasTypeParam());
1054 ((ParamTypeDesc*)this)->Save(image);
1059 void TypeDesc::Fixup(DataImage *image)
1061 STANDARD_VM_CONTRACT;
1063 if (IsGenericVariable())
1065 TypeVarTypeDesc* tyvar = (TypeVarTypeDesc*) this;
1066 tyvar->Fixup(image);
1068 else if (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR)
1070 ((FnPtrTypeDesc*)this)->Fixup(image);
1074 // Works for array and PTR/BYREF types, but not function pointers
1075 _ASSERTE(HasTypeParam());
1079 ((ArrayTypeDesc*) this)->Fixup(image);
1083 ((ParamTypeDesc*) this)->Fixup(image);
1087 if (NeedsRestore(image))
1089 TypeDesc *pTD = (TypeDesc*) image->GetImagePointer(this);
1090 _ASSERTE(pTD != NULL);
1091 pTD->m_typeAndFlags |= TypeDesc::enum_flag_Unrestored | TypeDesc::enum_flag_UnrestoredTypeKey | TypeDesc::enum_flag_IsNotFullyLoaded;
1096 BOOL TypeDesc::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited)
1098 STATIC_STANDARD_VM_CONTRACT;
1100 _ASSERTE(GetAppDomain()->IsCompilationDomain());
1104 return dac_cast<PTR_ParamTypeDesc>(this)->ComputeNeedsRestore(image, pVisited);
1112 void ParamTypeDesc::Save(DataImage *image)
1114 STANDARD_VM_CONTRACT;
1118 image->StoreStructure(this, sizeof(ArrayTypeDesc), DataImage::ITEM_ARRAY_TYPEDESC);
1122 image->StoreStructure(this, sizeof(ParamTypeDesc), DataImage::ITEM_PARAM_TYPEDESC);
1125 // This set of checks matches precisely those in Module::CreateArrayMethodTable
1126 // and ParamTypeDesc::ComputeNeedsRestore
1128 // They indicate if an array TypeDesc is non-canonical (in much the same a a generic
1129 // method table being non-canonical), i.e. it is not the primary
1130 // owner of the m_TemplateMT (the primary owner is the TypeDesc for object[])
1132 if (OwnsTemplateMethodTable())
1134 // This TypeDesc should be the only one saving this MT
1135 _ASSERTE(!image->IsStored(GetTemplateMethodTableInternal()));
1136 Module::SaveMethodTable(image, GetTemplateMethodTableInternal(), 0);
1142 void ParamTypeDesc::Fixup(DataImage *image)
1144 STANDARD_VM_CONTRACT;
1146 _ASSERTE(image->GetModule()->GetAssembly() ==
1147 GetAppDomain()->ToCompilationDomain()->GetTargetAssembly());
1149 if (LoggingOn(LF_ZAP, LL_INFO10000))
1152 TypeString::AppendType(name, TypeHandle(this));
1153 LOG((LF_ZAP, LL_INFO10000, "ParamTypeDesc::Fixup %S\n", name.GetUnicode()));
1156 if (!m_TemplateMT.IsNull())
1158 if (OwnsTemplateMethodTable())
1160 // In all other cases the type desc "owns" the m_TemplateMT
1161 // and it is always stored in the same module as the TypeDesc (i.e. the
1162 // TypeDesc and the MT are "tightly-knit") In other words if one is present in
1163 // an NGEN image then then other will be, and if one is "used" at runtime then
1164 // the other will be too.
1165 image->FixupMethodTablePointer(this, &m_TemplateMT);
1166 GetTemplateMethodTableInternal()->Fixup(image);
1170 // Fixup the pointer to the possibly-shared m_TemplateMT. This might be in a different module.
1171 image->FixupMethodTablePointer(this, &m_TemplateMT);
1175 // Fixup the pointer to the element type.
1176 image->HardBindTypeHandlePointer(this, offsetof(ParamTypeDesc, m_Arg));
1178 // The managed object will get regenerated on demand
1179 image->ZeroField(this, offsetof(ParamTypeDesc, m_hExposedClassObject), sizeof(m_hExposedClassObject));
1182 void ArrayTypeDesc::Fixup(DataImage *image)
1184 STANDARD_VM_CONTRACT;
1186 ParamTypeDesc::Fixup(image);
1188 #ifdef FEATURE_COMINTEROP
1189 // We don't save CCW templates into ngen images
1190 image->ZeroField(this, offsetof(ArrayTypeDesc, m_pCCWTemplate), sizeof(m_pCCWTemplate));
1191 #endif // FEATURE_COMINTEROP
1194 BOOL ParamTypeDesc::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited)
1196 STATIC_STANDARD_VM_CONTRACT;
1198 _ASSERTE(GetAppDomain()->IsCompilationDomain());
1200 if (m_typeAndFlags & TypeDesc::enum_flag_NeedsRestore)
1204 if (m_typeAndFlags & TypeDesc::enum_flag_PreRestored)
1210 if (!image->CanPrerestoreEagerBindToTypeHandle(m_Arg, pVisited))
1215 // This set of checks matches precisely those in Module::CreateArrayMethodTable and ParamTypeDesc::Fixup
1217 if (!m_TemplateMT.IsNull())
1219 if (OwnsTemplateMethodTable())
1221 if (GetTemplateMethodTableInternal()->ComputeNeedsRestore(image, pVisited))
1228 if (!image->CanPrerestoreEagerBindToMethodTable(GetTemplateMethodTableInternal(), pVisited))
1235 // Cache the results of running the algorithm.
1236 // We can only cache the result if we have not speculatively assumed
1237 // that any types are not NeedsRestore, i.e. the visited list is empty
1238 if (pVisited == NULL)
1240 if (LoggingOn(LF_ZAP, LL_INFO10000))
1243 TypeString::AppendType(name, TypeHandle(this));
1244 LOG((LF_ZAP, LL_INFO10000, "ParamTypeDesc::ComputeNeedsRestore=%d for %S\n", res, name.GetUnicode()));
1246 m_typeAndFlags |= (res ? TypeDesc::enum_flag_NeedsRestore : TypeDesc::enum_flag_PreRestored);
1250 #endif // FEATURE_NATIVE_IMAGE_GENERATION
1252 void TypeDesc::SetIsRestored()
1254 STATIC_CONTRACT_THROWS;
1255 STATIC_CONTRACT_GC_NOTRIGGER;
1256 STATIC_CONTRACT_FORBID_FAULT;
1257 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
1259 TypeHandle th = TypeHandle(this);
1260 FastInterlockAnd(EnsureWritablePages(&m_typeAndFlags), ~TypeDesc::enum_flag_Unrestored);
1263 #endif // #ifndef DACCESS_COMPILE
1265 void TypeDesc::Restore()
1271 INJECT_FAULT(COMPlusThrowOM(););
1272 CONSISTENCY_CHECK(!HasUnrestoredTypeKey());
1276 #ifndef DACCESS_COMPILE
1279 ParamTypeDesc *pPTD = dac_cast<PTR_ParamTypeDesc>(this);
1281 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_EXACTPARENTS);
1283 // Must have the same loader module
1284 ClassLoader::EnsureLoaded(pPTD->m_Arg, CLASS_LOAD_EXACTPARENTS);
1286 // Method-table pointer must have been restored by DoRestoreTypeKey
1287 Module::RestoreMethodTablePointer(&pPTD->m_TemplateMT, NULL, CLASS_LOAD_EXACTPARENTS);
1293 #endif // #ifndef DACCESS_COMPILE
1296 #endif // FEATURE_PREJIT
1299 #ifndef DACCESS_COMPILE
1301 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
1302 void TypeVarTypeDesc::Save(DataImage *image)
1304 STANDARD_VM_CONTRACT;
1306 // We don't persist the constraints: instead, load them back on demand
1307 m_numConstraints = (DWORD) -1;
1309 LOG((LF_ZAP, LL_INFO10000, " TypeVarTypeDesc::Save %x (%p)\n", GetToken(), this));
1310 image->StoreStructure(this, sizeof(TypeVarTypeDesc),
1311 DataImage::ITEM_TYVAR_TYPEDESC);
1314 void TypeVarTypeDesc::Fixup(DataImage *image)
1316 STANDARD_VM_CONTRACT;
1318 LOG((LF_ZAP, LL_INFO10000, " TypeVarTypeDesc::Fixup %x (%p)\n", GetToken(), this));
1319 image->FixupRelativePointerField(this, offsetof(TypeVarTypeDesc, m_pModule));
1320 image->ZeroField(this, offsetof(TypeVarTypeDesc, m_hExposedClassObject), sizeof(m_hExposedClassObject));
1322 // We don't persist the constraints: instead, load them back on demand
1323 image->ZeroPointerField(this, offsetof(TypeVarTypeDesc, m_constraints));
1326 #endif // FEATURE_NATIVE_IMAGE_GENERATION
1328 MethodDesc * TypeVarTypeDesc::LoadOwnerMethod()
1336 PRECONDITION(TypeFromToken(m_typeOrMethodDef) == mdtMethodDef);
1340 MethodDesc *pMD = GetModule()->LookupMethodDef(m_typeOrMethodDef);
1343 pMD = MemberLoader::GetMethodDescFromMethodDef(GetModule(), m_typeOrMethodDef, FALSE);
1348 TypeHandle TypeVarTypeDesc::LoadOwnerType()
1356 PRECONDITION(TypeFromToken(m_typeOrMethodDef) == mdtTypeDef);
1360 TypeHandle genericType = GetModule()->LookupTypeDef(m_typeOrMethodDef);
1361 if (genericType.IsNull())
1363 genericType = ClassLoader::LoadTypeDefThrowing(GetModule(), m_typeOrMethodDef,
1364 ClassLoader::ThrowIfNotFound,
1365 ClassLoader::PermitUninstDefOrRef);
1370 TypeHandle* TypeVarTypeDesc::GetCachedConstraints(DWORD *pNumConstraints)
1372 LIMITED_METHOD_CONTRACT;
1373 PRECONDITION(CheckPointer(pNumConstraints));
1374 PRECONDITION(m_numConstraints != (DWORD) -1);
1376 *pNumConstraints = m_numConstraints;
1377 return m_constraints;
1383 TypeHandle* TypeVarTypeDesc::GetConstraints(DWORD *pNumConstraints, ClassLoadLevel level /* = CLASS_LOADED */)
1385 WRAPPER_NO_CONTRACT;
1386 PRECONDITION(CheckPointer(pNumConstraints));
1387 PRECONDITION(level == CLASS_DEPENDENCIES_LOADED || level == CLASS_LOADED);
1389 if (m_numConstraints == (DWORD) -1)
1390 LoadConstraints(level);
1392 *pNumConstraints = m_numConstraints;
1393 return m_constraints;
1397 void TypeVarTypeDesc::LoadConstraints(ClassLoadLevel level /* = CLASS_LOADED */)
1405 INJECT_FAULT(COMPlusThrowOM());
1407 PRECONDITION(level == CLASS_DEPENDENCIES_LOADED || level == CLASS_LOADED);
1411 _ASSERTE(((INT_PTR)&m_constraints) % sizeof(m_constraints) == 0);
1412 _ASSERTE(((INT_PTR)&m_numConstraints) % sizeof(m_numConstraints) == 0);
1414 DWORD numConstraints = m_numConstraints;
1416 if (numConstraints == (DWORD) -1)
1418 EnsureWritablePages(this);
1420 IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1422 HENUMInternalHolder hEnum(pInternalImport);
1423 mdGenericParamConstraint tkConstraint;
1425 SigTypeContext typeContext;
1426 mdToken defToken = GetTypeOrMethodDef();
1428 MethodTable *pMT = NULL;
1429 if (TypeFromToken(defToken) == mdtMethodDef)
1431 MethodDesc *pMD = LoadOwnerMethod();
1432 _ASSERTE(pMD->IsGenericMethodDefinition());
1434 SigTypeContext::InitTypeContext(pMD,&typeContext);
1436 _ASSERTE(!typeContext.m_methodInst.IsEmpty());
1437 pMT = pMD->GetMethodTable();
1441 _ASSERTE(TypeFromToken(defToken) == mdtTypeDef);
1442 TypeHandle genericType = LoadOwnerType();
1443 _ASSERTE(genericType.IsGenericTypeDefinition());
1445 SigTypeContext::InitTypeContext(genericType,&typeContext);
1448 hEnum.EnumInit(mdtGenericParamConstraint, GetToken());
1449 numConstraints = pInternalImport->EnumGetCount(&hEnum);
1450 if (numConstraints != 0)
1452 LoaderAllocator* pAllocator = GetModule()->GetLoaderAllocator();
1453 // If there is a single class constraint we put in in element 0 of the array
1454 AllocMemHolder<TypeHandle> constraints
1455 (pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(numConstraints) * S_SIZE_T(sizeof(TypeHandle))));
1458 while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
1460 _ASSERTE(i <= numConstraints);
1461 mdToken tkConstraintType, tkParam;
1462 if (FAILED(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType)))
1464 GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
1466 _ASSERTE(tkParam == GetToken());
1467 TypeHandle thConstraint = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(GetModule(), tkConstraintType,
1469 ClassLoader::ThrowIfNotFound,
1470 ClassLoader::FailIfUninstDefOrRef,
1471 ClassLoader::LoadTypes,
1474 constraints[i++] = thConstraint;
1476 // Method type constraints behave contravariantly
1477 // (cf Bounded polymorphism e.g. see
1478 // Cardelli & Wegner, On understanding types, data abstraction and polymorphism, Computing Surveys 17(4), Dec 1985)
1479 if (pMT != NULL && pMT->HasVariance() && TypeFromToken(tkConstraintType) == mdtTypeSpec)
1482 PCCOR_SIGNATURE pSig;
1483 if (FAILED(pInternalImport->GetTypeSpecFromToken(tkConstraintType, &pSig, &cSig)))
1485 GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
1487 if (!EEClass::CheckVarianceInSig(pMT->GetNumGenericArgs(),
1488 pMT->GetClass()->GetVarianceInfo(),
1490 SigPointer(pSig, cSig),
1493 GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_VARIANCE_IN_CONSTRAINT);
1498 if (InterlockedCompareExchangeT(&m_constraints, constraints.operator->(), NULL) == NULL)
1500 constraints.SuppressRelease();
1504 m_numConstraints = numConstraints;
1507 for (DWORD i = 0; i < numConstraints; i++)
1509 ClassLoader::EnsureLoaded(m_constraints[i], level);
1513 BOOL TypeVarTypeDesc::ConstrainedAsObjRef()
1520 PRECONDITION(ConstraintsLoaded());
1524 IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1525 mdGenericParam genericParamToken = GetToken();
1527 if (FAILED(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
1531 DWORD specialConstraints = flags & gpSpecialConstraintMask;
1533 if ((specialConstraints & gpReferenceTypeConstraint) != 0)
1536 return ConstrainedAsObjRefHelper();
1539 // A recursive helper that helps determine whether this variable is constrained as ObjRef.
1540 // Please note that we do not check the gpReferenceTypeConstraint special constraint here
1541 // because this property does not propagate up the constraining hierarchy.
1542 // (e.g. "class A<S, T> where S : T, where T : class" does not guarantee that S is ObjRef)
1543 BOOL TypeVarTypeDesc::ConstrainedAsObjRefHelper()
1553 DWORD dwNumConstraints = 0;
1554 TypeHandle* constraints = GetCachedConstraints(&dwNumConstraints);
1556 for (DWORD i = 0; i < dwNumConstraints; i++)
1558 TypeHandle constraint = constraints[i];
1560 if (constraint.IsGenericVariable() && constraint.AsGenericVariable()->ConstrainedAsObjRefHelper())
1563 if (!constraint.IsInterface() && CorTypeInfo::IsObjRef_NoThrow(constraint.GetInternalCorElementType()))
1565 // Object, ValueType, and Enum are ObjRefs but they do not constrain the var to ObjRef!
1566 MethodTable *mt = constraint.GetMethodTable();
1568 if (mt != g_pObjectClass &&
1569 mt != g_pValueTypeClass &&
1580 BOOL TypeVarTypeDesc::ConstrainedAsValueType()
1587 PRECONDITION(ConstraintsLoaded());
1591 IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1592 mdGenericParam genericParamToken = GetToken();
1594 if (FAILED(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
1598 DWORD specialConstraints = flags & gpSpecialConstraintMask;
1600 if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
1603 DWORD dwNumConstraints = 0;
1604 TypeHandle* constraints = GetCachedConstraints(&dwNumConstraints);
1606 for (DWORD i = 0; i < dwNumConstraints; i++)
1608 TypeHandle constraint = constraints[i];
1610 if (constraint.IsGenericVariable())
1612 if (constraint.AsGenericVariable()->ConstrainedAsValueType())
1617 // the following condition will also disqualify interfaces
1618 if (!CorTypeInfo::IsObjRef_NoThrow(constraint.GetInternalCorElementType()))
1626 //---------------------------------------------------------------------------------------------------------------------
1627 // Loads the type of a constraint given the constraint token and instantiation context. If pInstContext is
1628 // not NULL and the constraint's type is a typespec, pInstContext will be used to instantiate the typespec.
1629 // Otherwise typical instantiation is returned if the constraint type is generic.
1630 //---------------------------------------------------------------------------------------------------------------------
1632 TypeHandle LoadTypeVarConstraint(TypeVarTypeDesc *pTypeVar, mdGenericParamConstraint tkConstraint,
1633 const InstantiationContext *pInstContext)
1639 INJECT_FAULT(COMPlusThrowOM());
1641 PRECONDITION(CheckPointer(pTypeVar));
1645 Module *pTyModule = pTypeVar->GetModule();
1646 IMDInternalImport* pInternalImport = pTyModule->GetMDImport();
1648 mdToken tkConstraintType, tkParam;
1649 IfFailThrow(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType));
1650 _ASSERTE(tkParam == pTypeVar->GetToken());
1651 mdToken tkOwnerToken = pTypeVar->GetTypeOrMethodDef();
1653 if (TypeFromToken(tkConstraintType) == mdtTypeSpec && pInstContext != NULL)
1655 if(pInstContext->m_pSubstChain == NULL)
1657 // The substitution chain will be null in situations
1658 // where we are instantiating types that are open, and therefore
1659 // we should be using the fully open TypeVar constraint instantiation code
1660 // below. However, in the case of a open method on a closed generic class
1661 // we will also have a null substitution chain. In this case, if we can ensure
1662 // that the instantiation type parameters are non type-var types, it is valid
1663 // to use the passed in instantiation when instantiating the type var constraint.
1664 BOOL fContextContainsValidGenericTypeParams = FALSE;
1666 if (TypeFromToken(tkOwnerToken) == mdtMethodDef)
1668 SigTypeContext sigTypeContext;
1670 MethodDesc *pMD = pTypeVar->LoadOwnerMethod();
1672 SigTypeContext::InitTypeContext(pMD, &sigTypeContext);
1673 fContextContainsValidGenericTypeParams = SigTypeContext::IsValidTypeOnlyInstantiationOf(&sigTypeContext, pInstContext->m_pArgContext);
1676 if (!fContextContainsValidGenericTypeParams)
1677 goto LoadConstraintOnOpenType;
1680 // obtain the constraint type's signature if it's a typespec
1682 PCCOR_SIGNATURE ptr;
1684 IfFailThrow(pInternalImport->GetSigFromToken(tkConstraintType, &cbSig, &ptr));
1686 SigPointer pSig(ptr, cbSig);
1688 // instantiate the signature using the current InstantiationContext
1689 return pSig.GetTypeHandleThrowing(pTyModule,
1690 pInstContext->m_pArgContext,
1691 ClassLoader::LoadTypes, CLASS_DEPENDENCIES_LOADED, FALSE,
1692 pInstContext->m_pSubstChain);
1696 LoadConstraintOnOpenType:
1698 SigTypeContext sigTypeContext;
1700 switch (TypeFromToken(tkOwnerToken))
1704 // the type variable is declared by a type - load the handle of the type
1705 TypeHandle thOwner = pTyModule->GetClassLoader()->LoadTypeDefThrowing(pTyModule,
1707 ClassLoader::ThrowIfNotFound,
1708 ClassLoader::PermitUninstDefOrRef,
1710 CLASS_LOAD_APPROXPARENTS
1713 SigTypeContext::InitTypeContext(thOwner, &sigTypeContext);
1719 // the type variable is declared by a method - load its method desc
1720 MethodDesc *pMD = pTyModule->LookupMethodDef(tkOwnerToken);
1722 SigTypeContext::InitTypeContext(pMD, &sigTypeContext);
1728 COMPlusThrow(kBadImageFormatException);
1732 // load the (typical instantiation of) constraint type
1733 return ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pTyModule,
1736 ClassLoader::ThrowIfNotFound,
1737 ClassLoader::FailIfUninstDefOrRef,
1738 ClassLoader::LoadTypes,
1739 CLASS_DEPENDENCIES_LOADED);
1743 //---------------------------------------------------------------------------------------------------------------------
1744 // We come here only if a type parameter with a special constraint is instantiated by an argument that is itself
1745 // a type parameter. In this case, we'll need to examine *its* constraints to see if the range of types that would satisfy its
1746 // constraints is a subset of the range of types that would satisfy the special constraint.
1748 // This routine will return TRUE if it can prove that argument "pTyArg" has a constraint that will satisfy the special constraint.
1750 // (NOTE: It does not check against anything other than one specific specialConstraint (it doesn't even know what they are.) This is
1751 // just one step in the checking of constraints.)
1752 //---------------------------------------------------------------------------------------------------------------------
1754 BOOL SatisfiesSpecialConstraintRecursive(TypeVarTypeDesc *pTyArg, DWORD specialConstraint, TypeHandleList *pVisitedVars = NULL)
1760 INJECT_FAULT(COMPlusThrowOM());
1762 PRECONDITION(CheckPointer(pTyArg));
1766 // The caller must invoke for all special constraints that apply - this fcn can only reliably test against one
1767 // constraint at a time.
1768 _ASSERTE(specialConstraint == gpNotNullableValueTypeConstraint
1769 || specialConstraint == gpReferenceTypeConstraint
1770 || specialConstraint == gpDefaultConstructorConstraint);
1772 IMDInternalImport* pInternalImport = pTyArg->GetModule()->GetMDImport();
1774 // Get the argument type's own special constraints
1776 IfFailThrow(pTyArg->GetModule()->GetMDImport()->GetGenericParamProps(pTyArg->GetToken(), NULL, &argFlags, NULL, NULL, NULL));
1778 DWORD argSpecialConstraints = argFlags & gpSpecialConstraintMask;
1780 // First, if the argument's own special constraints match the parameter's special constraints,
1781 // we can safely conclude the constraint is satisfied.
1782 switch (specialConstraint)
1784 case gpNotNullableValueTypeConstraint:
1786 if ((argSpecialConstraints & gpNotNullableValueTypeConstraint) != 0)
1793 case gpReferenceTypeConstraint:
1795 // gpReferenceTypeConstraint is not "inherited" so ignore it if pTyArg is a variable
1796 // constraining the argument rather than the argument itself.
1798 if (pVisitedVars == NULL && (argSpecialConstraints & gpReferenceTypeConstraint) != 0)
1805 case gpDefaultConstructorConstraint:
1807 // gpDefaultConstructorConstraint is not "inherited" so ignore it if pTyArg is a variable
1808 // constraining the argument rather than the argument itself.
1810 if ((pVisitedVars == NULL && (argSpecialConstraints & gpDefaultConstructorConstraint) != 0) ||
1811 (argSpecialConstraints & gpNotNullableValueTypeConstraint) != 0)
1819 // The special constraints did not match. However, we may find a primary type constraint
1820 // that would always satisfy the special constraint.
1821 HENUMInternalHolder hEnum(pInternalImport);
1822 hEnum.EnumInit(mdtGenericParamConstraint, pTyArg->GetToken());
1824 mdGenericParamConstraint tkConstraint;
1825 while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
1827 // We pass NULL instantiation context here because when checking for special constraints, it makes
1828 // no difference whether we load a typical (e.g. A<T>) or concrete (e.g. A<string>) instantiation.
1829 TypeHandle thConstraint = LoadTypeVarConstraint(pTyArg, tkConstraint, NULL);
1831 if (thConstraint.IsGenericVariable())
1833 // The variable is constrained by another variable, which we need to check recursively. An
1834 // example of why this is necessary follows:
1836 // class A<T> where T : class
1838 // class B<S, R> : A<S> where S : R where R : EventArgs
1841 if (!TypeHandleList::Exists(pVisitedVars, thConstraint))
1843 TypeHandleList newVisitedVars(thConstraint, pVisitedVars);
1844 if (SatisfiesSpecialConstraintRecursive(thConstraint.AsGenericVariable(),
1852 else if (thConstraint.IsInterface())
1854 // This is a secondary constraint - this tells us nothing about the eventual instantiation that
1859 // This is a type constraint. Remember that the eventual instantiation is only guaranteed to be
1860 // something *derived* from this type, not the actual type itself. To emphasize, we rename the local.
1862 TypeHandle thAncestorOfType = thConstraint;
1864 if (specialConstraint == gpNotNullableValueTypeConstraint)
1866 if (thAncestorOfType.IsValueType() && !(thAncestorOfType.AsMethodTable()->IsNullable()))
1872 if (specialConstraint == gpReferenceTypeConstraint)
1875 if (!thAncestorOfType.IsTypeDesc())
1877 MethodTable *pAncestorMT = thAncestorOfType.AsMethodTable();
1879 if ((!(pAncestorMT->IsValueType())) && pAncestorMT != g_pObjectClass && pAncestorMT != g_pValueTypeClass)
1881 // ValueTypes are sealed except when they aren't (cough, cough, System.Enum...). Sigh.
1882 // Don't put all our trust in IsValueType() here - check the ancestry chain as well.
1883 BOOL fIsValueTypeAnAncestor = FALSE;
1884 MethodTable *pParentMT = pAncestorMT->GetParentMethodTable();
1887 if (pParentMT == g_pValueTypeClass)
1889 fIsValueTypeAnAncestor = TRUE;
1892 pParentMT = pParentMT->GetParentMethodTable();
1895 if (!fIsValueTypeAnAncestor)
1903 if (specialConstraint == gpDefaultConstructorConstraint)
1905 // If a valuetype, just check to ensure that doesn't have a private default ctor.
1906 // If not a valuetype, not much we can conclude knowing just an ancestor class.
1907 if (thAncestorOfType.IsValueType() && thAncestorOfType.GetMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor())
1916 // If we got here, we found no evidence that the argument's constraints are strict enough to satisfy the parameter's constraints.
1920 //---------------------------------------------------------------------------------------------------------------------
1921 // Walks the "constraining chain" of a type variable and appends all concrete constraints as well as type vars
1922 // to the provided ArrayList. Upon leaving the function, the list contains all types that the type variable is
1923 // known to be assignable to.
1926 // class A<S, T> where S : T, IComparable where T : EventArgs
1928 // void f<U>(U u) where U : S, IDisposable { }
1930 // This would put 5 types to the U's list: S, T, IDisposable, IComparable, and EventArgs.
1931 //---------------------------------------------------------------------------------------------------------------------
1933 void GatherConstraintsRecursive(TypeVarTypeDesc *pTyArg, ArrayList *pArgList, const InstantiationContext *pInstContext,
1934 TypeHandleList *pVisitedVars = NULL)
1940 INJECT_FAULT(COMPlusThrowOM());
1942 PRECONDITION(CheckPointer(pTyArg));
1943 PRECONDITION(CheckPointer(pArgList));
1947 IMDInternalImport* pInternalImport = pTyArg->GetModule()->GetMDImport();
1949 // enumerate constraints of the pTyArg
1950 HENUMInternalHolder hEnum(pInternalImport);
1951 hEnum.EnumInit(mdtGenericParamConstraint, pTyArg->GetToken());
1953 mdGenericParamConstraint tkConstraint;
1954 while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
1956 TypeHandle thConstraint = LoadTypeVarConstraint(pTyArg, tkConstraint, pInstContext);
1958 if (thConstraint.IsGenericVariable())
1960 // see if it's safe to recursively call ourselves
1961 if (!TypeHandleList::Exists(pVisitedVars, thConstraint))
1963 pArgList->Append(thConstraint.AsPtr());
1965 TypeHandleList newVisitedVars(thConstraint, pVisitedVars);
1966 GatherConstraintsRecursive(thConstraint.AsGenericVariable(), pArgList, pInstContext, &newVisitedVars);
1969 // Note: circular type parameter constraints will be detected and reported later in
1970 // MethodTable::DoFullyLoad, we just have to avoid SO here.
1974 pArgList->Append(thConstraint.AsPtr());
1979 // pTypeContextOfConstraintDeclarer = type context of the generic type that declares the constraint
1980 // This is needed to load the "X" type when the constraint is the frm
1982 // Caution: Do NOT use it to load types or constraints attached to "thArg".
1984 // thArg = typehandle of the type being substituted for the type parameter.
1986 // pInstContext = the instantiation context (type context + substitution chain) to be
1987 // used when loading constraints attached to "thArg".
1989 BOOL TypeVarTypeDesc::SatisfiesConstraints(SigTypeContext *pTypeContextOfConstraintDeclarer, TypeHandle thArg,
1990 const InstantiationContext *pInstContext/*=NULL*/)
1998 PRECONDITION(!thArg.IsNull());
1999 INJECT_FAULT(COMPlusThrowOM());
2003 IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
2004 mdGenericParamConstraint tkConstraint;
2006 INDEBUG(mdToken defToken = GetTypeOrMethodDef());
2007 _ASSERTE(TypeFromToken(defToken) == mdtMethodDef || TypeFromToken(defToken) == mdtTypeDef);
2009 // prepare for the enumeration of this variable's general constraints
2010 mdGenericParam genericParamToken = GetToken();
2012 HENUMInternalHolder hEnum(pInternalImport);
2013 hEnum.EnumInit(mdtGenericParamConstraint, genericParamToken);
2017 // First check special constraints (must-be-reference-type, must-be-value-type, and must-have-default-constructor)
2019 IfFailThrow(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL));
2021 DWORD specialConstraints = flags & gpSpecialConstraintMask;
2023 if (thArg.IsGenericVariable())
2025 TypeVarTypeDesc *pTyVar = thArg.AsGenericVariable();
2027 if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
2029 if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpNotNullableValueTypeConstraint))
2035 if ((specialConstraints & gpReferenceTypeConstraint) != 0)
2037 if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpReferenceTypeConstraint))
2043 if ((specialConstraints & gpDefaultConstructorConstraint) != 0)
2045 if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpDefaultConstructorConstraint))
2051 if (hEnum.EnumGetCount() == 0)
2053 // return immediately if there are no general constraints to satisfy (fast path)
2057 // Now walk the "constraining chain" of type variables and gather all constraint types.
2059 // This work should not be left to code:TypeHandle.CanCastTo because we need typespec constraints
2060 // to be instantiated in pInstContext. If we just do thArg.CanCastTo(thConstraint), it would load
2061 // typical instantiations of the constraints and the can-cast-to check may fail. In addition,
2062 // code:TypeHandle.CanCastTo will SO if the constraints are circular.
2068 // void f<U>(B<U, T> b) where U : A<T> { }
2070 // class B<S, R> where S : A<R> { }
2072 // If we load the signature of, say, A<int>.f<U> (concrete class but typical method), and end up
2073 // here verifying that S : A<R> is satisfied by U : A<T>, we must instantiate the constraint type
2074 // A<T> using pInstContext so that it becomes A<int>. Otherwise the constraint check fails.
2076 GatherConstraintsRecursive(pTyVar, &argList, pInstContext);
2080 if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
2082 if (!thArg.IsValueType())
2086 // the type argument is a value type, however if it is any kind of Nullable we want to fail
2087 // as the constraint accepts any value type except Nullable types (Nullable itself is a value type)
2088 if (thArg.AsMethodTable()->IsNullable())
2093 if ((specialConstraints & gpReferenceTypeConstraint) != 0)
2095 if (thArg.IsValueType())
2099 if ((specialConstraints & gpDefaultConstructorConstraint) != 0)
2101 if (thArg.IsTypeDesc() || (!thArg.AsMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor()))
2106 // Complete the list by adding thArg itself. If thArg is not a generic variable this will be the only
2107 // item in the list. If it is a generic variable, we need it in the list as well in addition to all the
2108 // constraints gathered by GatherConstraintsRecursive, because e.g. class A<S, T> : where S : T
2109 // can be instantiated using A<U, U>.
2110 argList.Append(thArg.AsPtr());
2112 // At this point argList contains all types that thArg is known to be assignable to. The list may
2113 // contain duplicates and it consists of zero or more type variables, zero or more possibly generic
2114 // interfaces, and at most one possibly generic class.
2116 // Now check general subtype constraints
2117 while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
2119 mdToken tkConstraintType, tkParam;
2120 IfFailThrow(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType));
2122 _ASSERTE(tkParam == GetToken());
2123 TypeHandle thConstraint = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(GetModule(),
2125 pTypeContextOfConstraintDeclarer,
2126 ClassLoader::ThrowIfNotFound,
2127 ClassLoader::FailIfUninstDefOrRef,
2128 ClassLoader::LoadTypes,
2129 CLASS_DEPENDENCIES_LOADED);
2131 // System.Object constraint will be always satisfied - even if argList is empty
2132 if (!thConstraint.IsObjectType())
2134 BOOL fCanCast = FALSE;
2136 // loop over all types that we know the arg will be assignable to
2137 ArrayList::Iterator iter = argList.Iterate();
2140 TypeHandle thElem = TypeHandle::FromPtr(iter.GetElement());
2142 if (thElem.IsGenericVariable())
2144 // if a generic variable equals to the constraint, then this constraint will be satisfied
2145 if (thElem == thConstraint)
2151 // and any variable with the gpNotNullableValueTypeConstraint special constraint
2152 // satisfies the "derived from System.ValueType" general subtype constraint
2153 if (thConstraint == g_pValueTypeClass)
2155 TypeVarTypeDesc *pTyElem = thElem.AsGenericVariable();
2156 IfFailThrow(pTyElem->GetModule()->GetMDImport()->GetGenericParamProps(
2157 pTyElem->GetToken(),
2164 if ((flags & gpNotNullableValueTypeConstraint) != 0)
2173 // if a concrete type can be cast to the constraint, then this constraint will be satisifed
2174 if (thElem.CanCastTo(thConstraint))
2190 #ifndef CROSSGEN_COMPILE
2191 OBJECTREF TypeVarTypeDesc::GetManagedClassObject()
2198 INJECT_FAULT(COMPlusThrowOM());
2200 PRECONDITION(IsGenericVariable());
2204 if (m_hExposedClassObject == NULL) {
2205 REFLECTCLASSBASEREF refClass = NULL;
2206 GCPROTECT_BEGIN(refClass);
2207 refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass);
2209 LoaderAllocator *pLoaderAllocator = GetLoaderAllocator();
2210 TypeHandle th = TypeHandle(this);
2211 ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th);
2212 ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject());
2214 // Let all threads fight over who wins using InterlockedCompareExchange.
2215 // Only the winner can set m_hExposedClassObject from NULL.
2216 LOADERHANDLE hExposedClassObject = pLoaderAllocator->AllocateHandle(refClass);
2218 if (FastInterlockCompareExchangePointer(EnsureWritablePages(&m_hExposedClassObject), hExposedClassObject, static_cast<LOADERHANDLE>(NULL)))
2220 pLoaderAllocator->FreeHandle(hExposedClassObject);
2225 return GetManagedClassObjectIfExists();
2227 #endif // CROSSGEN_COMPILE
2229 #endif //!DACCESS_COMPILE
2232 FnPtrTypeDesc::GetRetAndArgTypes()
2242 // Decode encoded type handles on demand
2243 #if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
2244 for (DWORD i = 0; i <= m_NumArgs; i++)
2246 Module::RestoreTypeHandlePointerRaw(&m_RetAndArgTypes[i]);
2248 #endif //defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
2250 return m_RetAndArgTypes;
2251 } // FnPtrTypeDesc::GetRetAndArgTypes
2253 #ifndef DACCESS_COMPILE
2255 // Returns TRUE if all return and argument types are externally visible.
2257 FnPtrTypeDesc::IsExternallyVisible() const
2267 const TypeHandle * rgRetAndArgTypes = GetRetAndArgTypes();
2268 for (DWORD i = 0; i <= m_NumArgs; i++)
2270 if (!rgRetAndArgTypes[i].IsExternallyVisible())
2275 // All return/arguments types are externally visible
2277 } // FnPtrTypeDesc::IsExternallyVisible
2279 #endif //DACCESS_COMPILE
2281 #if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
2283 void FnPtrTypeDesc::Save(DataImage * image)
2285 STANDARD_VM_CONTRACT;
2287 image->StoreStructure(
2289 sizeof(FnPtrTypeDesc) + (m_NumArgs * sizeof(TypeHandle)),
2290 DataImage::ITEM_FPTR_TYPEDESC);
2293 void FnPtrTypeDesc::Fixup(DataImage * image)
2295 STANDARD_VM_CONTRACT;
2297 for (DWORD i = 0; i <= m_NumArgs; i++)
2299 image->FixupTypeHandlePointerInPlace(
2301 (BYTE *)&m_RetAndArgTypes[i] - (BYTE *)this);
2305 #endif //defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
2307 #ifdef DACCESS_COMPILE
2310 ParamTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2315 PTR_MethodTable pTemplateMT = GetTemplateMethodTableInternal();
2316 if (pTemplateMT.IsValid())
2318 pTemplateMT->EnumMemoryRegions(flags);
2321 m_Arg.EnumMemoryRegions(flags);
2325 TypeVarTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2330 PTR_TypeVarTypeDesc ptrThis(this);
2332 if (GetModule().IsValid())
2334 GetModule()->EnumMemoryRegions(flags, true);
2337 if (m_numConstraints != (DWORD)-1)
2339 PTR_TypeHandle constraint = m_constraints;
2340 for (DWORD i = 0; i < m_numConstraints; i++)
2342 if (constraint.IsValid())
2344 constraint->EnumMemoryRegions(flags);
2349 } // TypeVarTypeDesc::EnumMemoryRegions
2352 FnPtrTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2357 for (DWORD i = 0; i < m_NumArgs; i++)
2359 m_RetAndArgTypes[i].EnumMemoryRegions(flags);
2363 #endif //DACCESS_COMPILE