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)
28 #include "stackprobe.h"
31 #ifndef DACCESS_COMPILE
34 BOOL ParamTypeDesc::Verify() {
36 STATIC_CONTRACT_NOTHROW;
37 STATIC_CONTRACT_GC_NOTRIGGER;
38 STATIC_CONTRACT_FORBID_FAULT;
39 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
40 STATIC_CONTRACT_DEBUG_ONLY;
41 STATIC_CONTRACT_SUPPORTS_DAC;
43 _ASSERTE(m_TemplateMT.IsNull() || GetTemplateMethodTableInternal()->SanityCheck());
44 _ASSERTE(!GetTypeParam().IsNull());
45 BAD_FORMAT_NOTHROW_ASSERT(GetTypeParam().IsTypeDesc() || !GetTypeParam().AsMethodTable()->IsArray());
46 BAD_FORMAT_NOTHROW_ASSERT(CorTypeInfo::IsModifier_NoThrow(GetInternalCorElementType()) ||
47 GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE);
48 GetTypeParam().Verify();
52 BOOL ArrayTypeDesc::Verify() {
54 STATIC_CONTRACT_NOTHROW;
55 STATIC_CONTRACT_GC_NOTRIGGER;
56 STATIC_CONTRACT_FORBID_FAULT;
57 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
58 STATIC_CONTRACT_DEBUG_ONLY;
59 STATIC_CONTRACT_SUPPORTS_DAC;
61 // m_TemplateMT == 0 may be null when building types involving TypeVarTypeDesc's
62 BAD_FORMAT_NOTHROW_ASSERT(m_TemplateMT.IsNull() || GetTemplateMethodTable()->IsArray());
63 BAD_FORMAT_NOTHROW_ASSERT(CorTypeInfo::IsArray_NoThrow(GetInternalCorElementType()));
64 ParamTypeDesc::Verify();
70 #endif // #ifndef DACCESS_COMPILE
72 TypeHandle TypeDesc::GetBaseTypeParam()
74 LIMITED_METHOD_DAC_CONTRACT;
76 _ASSERTE(HasTypeParam());
78 TypeHandle th = dac_cast<PTR_ParamTypeDesc>(this)->GetTypeParam();
79 while (th.HasTypeParam())
81 th = dac_cast<PTR_ParamTypeDesc>(th.AsTypeDesc())->GetTypeParam();
83 _ASSERTE(!th.IsNull());
88 PTR_Module TypeDesc::GetLoaderModule()
90 STATIC_CONTRACT_NOTHROW;
91 STATIC_CONTRACT_GC_NOTRIGGER;
92 STATIC_CONTRACT_FORBID_FAULT;
97 return GetBaseTypeParam().GetLoaderModule();
99 else if (IsGenericVariable())
101 return dac_cast<PTR_TypeVarTypeDesc>(this)->GetModule();
105 PTR_Module retVal = NULL;
108 _ASSERTE(GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
109 PTR_FnPtrTypeDesc asFnPtr = dac_cast<PTR_FnPtrTypeDesc>(this);
110 BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), fFail = TRUE );
113 retVal = ClassLoader::ComputeLoaderModuleForFunctionPointer(asFnPtr->GetRetAndArgTypesPointer(), asFnPtr->GetNumArgs()+1);
115 END_SO_INTOLERANT_CODE;
121 PTR_Module TypeDesc::GetZapModule()
125 return ExecutionManager::FindZapModule(dac_cast<TADDR>(this));
128 PTR_BaseDomain TypeDesc::GetDomain()
139 Module *pZapModule = GetZapModule();
140 if (pZapModule != NULL)
142 return pZapModule->GetDomain();
147 return GetBaseTypeParam().GetDomain();
149 if (IsGenericVariable())
151 PTR_TypeVarTypeDesc asVar = dac_cast<PTR_TypeVarTypeDesc>(this);
152 return asVar->GetModule()->GetDomain();
154 _ASSERTE(GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
155 PTR_FnPtrTypeDesc asFnPtr = dac_cast<PTR_FnPtrTypeDesc>(this);
156 return BaseDomain::ComputeBaseDomain(asFnPtr->GetRetAndArgTypesPointer()[0].GetDomain(),
157 Instantiation(asFnPtr->GetRetAndArgTypesPointer(), asFnPtr->GetNumArgs()+1));
160 PTR_Module TypeDesc::GetModule() {
168 // Function pointer types belong to no module
169 //PRECONDITION(GetInternalCorElementType() != ELEMENT_TYPE_FNPTR);
173 // Note here we are making the assumption that a typeDesc lives in
174 // the classloader of its element type.
178 return GetBaseTypeParam().GetModule();
181 if (IsGenericVariable())
183 PTR_TypeVarTypeDesc asVar = dac_cast<PTR_TypeVarTypeDesc>(this);
184 return asVar->GetModule();
187 _ASSERTE(GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
189 return GetLoaderModule();
192 BOOL TypeDesc::IsDomainNeutral()
202 return GetDomain()->IsSharedDomain();
205 BOOL ParamTypeDesc::OwnsTemplateMethodTable()
214 CorElementType kind = GetInternalCorElementType();
216 // The m_TemplateMT for pointer types is UIntPtr
217 if (!CorTypeInfo::IsArray_NoThrow(kind))
222 CorElementType elemType = m_Arg.GetSignatureCorElementType();
224 // This check matches precisely one in Module::CreateArrayMethodTable
226 // They indicate if an array TypeDesc is non-canonical (in much the same a a generic
227 // method table being non-canonical), i.e. it is not the primary
228 // owner of the m_TemplateMT (the primary owner is the TypeDesc for object[])
230 if (CorTypeInfo::IsGenericVariable_NoThrow(elemType))
238 Assembly* TypeDesc::GetAssembly() {
239 STATIC_CONTRACT_NOTHROW;
240 STATIC_CONTRACT_GC_NOTRIGGER;
241 STATIC_CONTRACT_FORBID_FAULT;
243 Module *pModule = GetModule();
244 PREFIX_ASSUME(pModule!=NULL);
245 return pModule->GetAssembly();
248 void TypeDesc::GetName(SString &ssBuf)
254 INJECT_FAULT(COMPlusThrowOM(););
258 CorElementType kind = GetInternalCorElementType();
262 if (CorTypeInfo::IsModifier(kind))
265 th = TypeHandle(this);
267 if (kind == ELEMENT_TYPE_ARRAY)
268 rank = ((ArrayTypeDesc*) this)->GetRank();
269 else if (CorTypeInfo::IsGenericVariable(kind))
270 rank = ((TypeVarTypeDesc*) this)->GetIndex();
274 ConstructName(kind, th, rank, ssBuf);
277 void TypeDesc::ConstructName(CorElementType kind,
286 INJECT_FAULT(COMPlusThrowOM()); // SString operations can allocate.
290 if (CorTypeInfo::IsModifier(kind))
292 param.GetName(ssBuff);
297 case ELEMENT_TYPE_BYREF:
298 ssBuff.Append(W('&'));
301 case ELEMENT_TYPE_PTR:
302 ssBuff.Append(W('*'));
305 case ELEMENT_TYPE_SZARRAY:
306 ssBuff.Append(W("[]"));
309 case ELEMENT_TYPE_ARRAY:
310 ssBuff.Append(W('['));
314 ssBuff.Append(W('*'));
320 ssBuff.Append(W(','));
324 ssBuff.Append(W(']'));
327 case ELEMENT_TYPE_VAR:
328 case ELEMENT_TYPE_MVAR:
329 if (kind == ELEMENT_TYPE_VAR)
331 ssBuff.Printf(W("!%d"), rank);
335 ssBuff.Printf(W("!!%d"), rank);
339 case ELEMENT_TYPE_FNPTR:
340 ssBuff.Printf(W("FNPTR"));
344 LPCUTF8 namesp = CorTypeInfo::GetNamespace(kind);
345 if(namesp && *namesp) {
346 ssBuff.AppendUTF8(namesp);
347 ssBuff.Append(W('.'));
350 LPCUTF8 name = CorTypeInfo::GetName(kind);
351 BAD_FORMAT_NOTHROW_ASSERT(name);
353 ssBuff.AppendUTF8(name);
358 BOOL TypeDesc::IsArray()
360 LIMITED_METHOD_DAC_CONTRACT;
361 return CorTypeInfo::IsArray_NoThrow(GetInternalCorElementType());
364 BOOL TypeDesc::IsGenericVariable()
366 LIMITED_METHOD_DAC_CONTRACT;
367 return CorTypeInfo::IsGenericVariable_NoThrow(GetInternalCorElementType());
370 BOOL TypeDesc::IsFnPtr()
372 LIMITED_METHOD_DAC_CONTRACT;
373 return (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
376 BOOL TypeDesc::IsNativeValueType()
379 return (GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE);
382 BOOL TypeDesc::HasTypeParam()
386 return CorTypeInfo::IsModifier_NoThrow(GetInternalCorElementType()) ||
387 GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE;
390 #ifndef DACCESS_COMPILE
392 BOOL TypeDesc::CanCastTo(TypeHandle toType, TypeHandlePairList *pVisited)
398 INJECT_FAULT(COMPlusThrowOM());
402 if (TypeHandle(this) == toType)
405 //A boxed variable type can be cast to any of its constraints, or object, if none are specified
406 if (IsGenericVariable())
408 TypeVarTypeDesc *tyvar = (TypeVarTypeDesc*) this;
410 DWORD numConstraints;
411 TypeHandle *constraints = tyvar->GetConstraints(&numConstraints, CLASS_DEPENDENCIES_LOADED);
413 if (toType == g_pObjectClass)
416 if (toType == g_pValueTypeClass)
418 mdGenericParam genericParamToken = tyvar->GetToken();
420 if (FAILED(tyvar->GetModule()->GetMDImport()->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
424 DWORD specialConstraints = flags & gpSpecialConstraintMask;
425 if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
429 if (constraints == NULL)
432 for (DWORD i = 0; i < numConstraints; i++)
434 if (constraints[i].CanCastTo(toType, pVisited))
440 // If we're not casting to a TypeDesc (i.e. not to a reference array type, variable type etc.)
441 // then we must be trying to cast to a class or interface type.
442 if (!toType.IsTypeDesc())
446 // I am a variable type, pointer type, function pointer type
447 // etc. I am not an object or value type. Therefore
448 // I can't be cast to an object or value type.
452 MethodTable *pMT = GetMethodTable();
455 // This does the right thing if 'type' == System.Array or System.Object, System.Clonable ...
456 if (pMT->CanCastToClassOrInterface(toType.AsMethodTable(), pVisited) != 0)
461 if (IsArray() && toType.AsMethodTable()->IsInterface())
463 if (ArraySupportsBizarreInterface((ArrayTypeDesc*)this, toType.AsMethodTable()))
473 TypeDesc* toTypeDesc = toType.AsTypeDesc();
475 CorElementType toKind = toTypeDesc->GetInternalCorElementType();
476 CorElementType fromKind = GetInternalCorElementType();
478 // The element kinds must match, only exception is that SZARRAY matches a one dimension ARRAY
479 if (!(toKind == fromKind || (toKind == ELEMENT_TYPE_ARRAY && fromKind == ELEMENT_TYPE_SZARRAY)))
484 case ELEMENT_TYPE_ARRAY:
485 if (dac_cast<PTR_ArrayTypeDesc>(this)->GetRank() != dac_cast<PTR_ArrayTypeDesc>(toTypeDesc)->GetRank())
488 case ELEMENT_TYPE_SZARRAY:
489 case ELEMENT_TYPE_BYREF:
490 case ELEMENT_TYPE_PTR:
491 return TypeDesc::CanCastParam(dac_cast<PTR_ParamTypeDesc>(this)->GetTypeParam(), dac_cast<PTR_ParamTypeDesc>(toTypeDesc)->GetTypeParam(), pVisited);
493 case ELEMENT_TYPE_VAR:
494 case ELEMENT_TYPE_MVAR:
495 case ELEMENT_TYPE_FNPTR:
499 BAD_FORMAT_NOTHROW_ASSERT(toKind == ELEMENT_TYPE_TYPEDBYREF || CorTypeInfo::IsPrimitiveType(toKind));
504 BOOL TypeDesc::CanCastParam(TypeHandle fromParam, TypeHandle toParam, TypeHandlePairList *pVisited)
510 INJECT_FAULT(COMPlusThrowOM());
514 // While boxed value classes inherit from object their
515 // unboxed versions do not. Parameterized types have the
516 // unboxed version, thus, if the from type parameter is value
517 // class then only an exact match/equivalence works.
518 if (fromParam.IsEquivalentTo(toParam))
521 // Object parameters dont need an exact match but only inheritance, check for that
522 CorElementType fromParamCorType = fromParam.GetVerifierCorElementType();
523 if (CorTypeInfo::IsObjRef(fromParamCorType))
525 return fromParam.CanCastTo(toParam, pVisited);
527 else if (CorTypeInfo::IsGenericVariable(fromParamCorType))
529 TypeVarTypeDesc* varFromParam = fromParam.AsGenericVariable();
531 if (!varFromParam->ConstraintsLoaded())
532 varFromParam->LoadConstraints(CLASS_DEPENDENCIES_LOADED);
534 if (!varFromParam->ConstrainedAsObjRef())
537 return fromParam.CanCastTo(toParam, pVisited);
539 else if(CorTypeInfo::IsPrimitiveType(fromParamCorType))
541 CorElementType toParamCorType = toParam.GetVerifierCorElementType();
542 if(CorTypeInfo::IsPrimitiveType(toParamCorType))
544 if (toParamCorType == fromParamCorType)
547 // Primitive types such as E_T_I4 and E_T_U4 are interchangeable
548 // Enums with interchangeable underlying types are interchangable
549 // BOOL is NOT interchangeable with I1/U1, neither CHAR -- with I2/U2
550 if((toParamCorType != ELEMENT_TYPE_BOOLEAN)
551 &&(fromParamCorType != ELEMENT_TYPE_BOOLEAN)
552 &&(toParamCorType != ELEMENT_TYPE_CHAR)
553 &&(fromParamCorType != ELEMENT_TYPE_CHAR))
555 if ((CorTypeInfo::Size(toParamCorType) == CorTypeInfo::Size(fromParamCorType))
556 && (CorTypeInfo::IsFloat(toParamCorType) == CorTypeInfo::IsFloat(fromParamCorType)))
561 } // end if(CorTypeInfo::IsPrimitiveType(toParamCorType))
562 } // end if(CorTypeInfo::IsPrimitiveType(fromParamCorType))
564 // Anything else is not a match.
568 TypeHandle::CastResult TypeDesc::CanCastToNoGC(TypeHandle toType)
579 if (TypeHandle(this) == toType)
580 return TypeHandle::CanCast;
582 //A boxed variable type can be cast to any of its constraints, or object, if none are specified
583 if (IsGenericVariable())
585 TypeVarTypeDesc *tyvar = (TypeVarTypeDesc*) this;
587 if (!tyvar->ConstraintsLoaded())
588 return TypeHandle::MaybeCast;
590 DWORD numConstraints;
591 TypeHandle *constraints = tyvar->GetCachedConstraints(&numConstraints);
593 if (toType == g_pObjectClass)
594 return TypeHandle::CanCast;
596 if (toType == g_pValueTypeClass)
597 return TypeHandle::MaybeCast;
599 if (constraints == NULL)
600 return TypeHandle::CannotCast;
602 for (DWORD i = 0; i < numConstraints; i++)
604 if (constraints[i].CanCastToNoGC(toType) == TypeHandle::CanCast)
605 return TypeHandle::CanCast;
607 return TypeHandle::MaybeCast;
610 // If we're not casting to a TypeDesc (i.e. not to a reference array type, variable type etc.)
611 // then we must be trying to cast to a class or interface type.
612 if (!toType.IsTypeDesc())
616 // I am a variable type, pointer type, function pointer type
617 // etc. I am not an object or value type. Therefore
618 // I can't be cast to an object or value type.
619 return TypeHandle::CannotCast;
622 MethodTable *pMT = GetMethodTable();
625 // This does the right thing if 'type' == System.Array or System.Object, System.Clonable ...
626 return pMT->CanCastToClassOrInterfaceNoGC(toType.AsMethodTable());
629 TypeDesc* toTypeDesc = toType.AsTypeDesc();
631 CorElementType toKind = toTypeDesc->GetInternalCorElementType();
632 CorElementType fromKind = GetInternalCorElementType();
634 // The element kinds must match, only exception is that SZARRAY matches a one dimension ARRAY
635 if (!(toKind == fromKind || (toKind == ELEMENT_TYPE_ARRAY && fromKind == ELEMENT_TYPE_SZARRAY)))
636 return TypeHandle::CannotCast;
640 case ELEMENT_TYPE_ARRAY:
641 if (dac_cast<PTR_ArrayTypeDesc>(this)->GetRank() != dac_cast<PTR_ArrayTypeDesc>(toTypeDesc)->GetRank())
642 return TypeHandle::CannotCast;
644 case ELEMENT_TYPE_SZARRAY:
645 case ELEMENT_TYPE_BYREF:
646 case ELEMENT_TYPE_PTR:
647 return TypeDesc::CanCastParamNoGC(dac_cast<PTR_ParamTypeDesc>(this)->GetTypeParam(), dac_cast<PTR_ParamTypeDesc>(toTypeDesc)->GetTypeParam());
649 case ELEMENT_TYPE_VAR:
650 case ELEMENT_TYPE_MVAR:
651 case ELEMENT_TYPE_FNPTR:
652 return TypeHandle::CannotCast;
655 BAD_FORMAT_NOTHROW_ASSERT(toKind == ELEMENT_TYPE_TYPEDBYREF || CorTypeInfo::IsPrimitiveType_NoThrow(toKind));
656 return TypeHandle::CanCast;
660 TypeHandle::CastResult TypeDesc::CanCastParamNoGC(TypeHandle fromParam, TypeHandle toParam)
671 // While boxed value classes inherit from object their
672 // unboxed versions do not. Parameterized types have the
673 // unboxed version, thus, if the from type parameter is value
674 // class then only an exact match works.
675 if (fromParam == toParam)
676 return TypeHandle::CanCast;
678 // Object parameters dont need an exact match but only inheritance, check for that
679 CorElementType fromParamCorType = fromParam.GetVerifierCorElementType();
680 if (CorTypeInfo::IsObjRef_NoThrow(fromParamCorType))
682 return fromParam.CanCastToNoGC(toParam);
684 else if (CorTypeInfo::IsGenericVariable_NoThrow(fromParamCorType))
686 TypeVarTypeDesc* varFromParam = fromParam.AsGenericVariable();
688 if (!varFromParam->ConstraintsLoaded())
689 return TypeHandle::MaybeCast;
691 if (!varFromParam->ConstrainedAsObjRef())
692 return TypeHandle::CannotCast;
694 return fromParam.CanCastToNoGC(toParam);
696 else if (CorTypeInfo::IsPrimitiveType_NoThrow(fromParamCorType))
698 CorElementType toParamCorType = toParam.GetVerifierCorElementType();
699 if(CorTypeInfo::IsPrimitiveType_NoThrow(toParamCorType))
701 if (toParamCorType == fromParamCorType)
702 return TypeHandle::CanCast;
704 // Primitive types such as E_T_I4 and E_T_U4 are interchangeable
705 // Enums with interchangeable underlying types are interchangable
706 // BOOL is NOT interchangeable with I1/U1, neither CHAR -- with I2/U2
707 if((toParamCorType != ELEMENT_TYPE_BOOLEAN)
708 &&(fromParamCorType != ELEMENT_TYPE_BOOLEAN)
709 &&(toParamCorType != ELEMENT_TYPE_CHAR)
710 &&(fromParamCorType != ELEMENT_TYPE_CHAR))
712 if ((CorTypeInfo::Size_NoThrow(toParamCorType) == CorTypeInfo::Size_NoThrow(fromParamCorType))
713 && (CorTypeInfo::IsFloat_NoThrow(toParamCorType) == CorTypeInfo::IsFloat_NoThrow(fromParamCorType)))
715 return TypeHandle::CanCast;
718 } // end if(CorTypeInfo::IsPrimitiveType(toParamCorType))
719 } // end if(CorTypeInfo::IsPrimitiveType(fromParamCorType))
722 // Types with equivalence need the slow path
723 MethodTable * pFromMT = fromParam.GetMethodTable();
724 if (pFromMT != NULL && pFromMT->HasTypeEquivalence())
725 return TypeHandle::MaybeCast;
726 MethodTable * pToMT = toParam.GetMethodTable();
727 if (pToMT != NULL && pToMT->HasTypeEquivalence())
728 return TypeHandle::MaybeCast;
731 // Anything else is not a match.
732 return TypeHandle::CannotCast;
735 BOOL TypeDesc::IsEquivalentTo(TypeHandle type COMMA_INDEBUG(TypeHandlePairList *pVisited))
746 if (TypeHandle(this) == type)
749 if (!type.IsTypeDesc())
752 TypeDesc *pOther = type.AsTypeDesc();
754 // bail early for normal types
755 if (!HasTypeEquivalence() || !pOther->HasTypeEquivalence())
758 // if the TypeDesc types are different, then they are not equivalent
759 if (GetInternalCorElementType() != pOther->GetInternalCorElementType())
764 // pointer, byref, array
766 // Arrays must have the same rank.
769 ArrayTypeDesc *pThisArray = (ArrayTypeDesc *)this;
770 ArrayTypeDesc *pOtherArray = (ArrayTypeDesc *)pOther;
771 if (pThisArray->GetRank() != pOtherArray->GetRank())
775 return GetTypeParam().IsEquivalentTo(pOther->GetTypeParam() COMMA_INDEBUG(pVisited));
781 #endif // #ifndef DACCESS_COMPILE
785 TypeHandle TypeDesc::GetParent() {
787 STATIC_CONTRACT_NOTHROW;
788 STATIC_CONTRACT_GC_NOTRIGGER;
789 STATIC_CONTRACT_FORBID_FAULT;
791 CorElementType kind = GetInternalCorElementType();
792 if (CorTypeInfo::IsArray_NoThrow(kind)) {
794 BAD_FORMAT_NOTHROW_ASSERT(kind == ELEMENT_TYPE_SZARRAY || kind == ELEMENT_TYPE_ARRAY);
795 return ((ArrayTypeDesc*)this)->GetParent();
797 if (CorTypeInfo::IsPrimitiveType_NoThrow(kind))
798 return (MethodTable*)g_pObjectClass;
802 #ifndef DACCESS_COMPILE
804 #ifndef CROSSGEN_COMPILE
805 OBJECTREF ParamTypeDesc::GetManagedClassObject()
812 INJECT_FAULT(COMPlusThrowOM());
814 PRECONDITION(GetInternalCorElementType() == ELEMENT_TYPE_ARRAY ||
815 GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY ||
816 GetInternalCorElementType() == ELEMENT_TYPE_BYREF ||
817 GetInternalCorElementType() == ELEMENT_TYPE_PTR);
821 if (m_hExposedClassObject == NULL) {
822 REFLECTCLASSBASEREF refClass = NULL;
823 GCPROTECT_BEGIN(refClass);
824 if (GetAssembly()->IsIntrospectionOnly())
825 refClass = (REFLECTCLASSBASEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__CLASS_INTROSPECTION_ONLY));
827 refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass);
829 LoaderAllocator *pLoaderAllocator = GetLoaderAllocator();
830 TypeHandle th = TypeHandle(this);
831 ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th);
832 ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject());
834 // Let all threads fight over who wins using InterlockedCompareExchange.
835 // Only the winner can set m_hExposedClassObject from NULL.
836 LOADERHANDLE hExposedClassObject = pLoaderAllocator->AllocateHandle(refClass);
838 EnsureWritablePages(this);
839 if (FastInterlockCompareExchangePointer(&m_hExposedClassObject, hExposedClassObject, static_cast<LOADERHANDLE>(NULL)))
841 pLoaderAllocator->ClearHandle(hExposedClassObject);
844 if (OwnsTemplateMethodTable())
846 // Set the handle on template methodtable as well to make Object.GetType for arrays take the fast path
847 EnsureWritablePages(GetTemplateMethodTableInternal()->GetWriteableDataForWrite())->m_hExposedClassObject = m_hExposedClassObject;
850 // Log the TypeVarTypeDesc access
851 g_IBCLogger.LogTypeMethodTableWriteableAccess(&th);
855 return GetManagedClassObjectIfExists();
857 #endif // CROSSGEN_COMPILE
859 #endif // #ifndef DACCESS_COMPILE
861 BOOL TypeDesc::IsRestored()
863 STATIC_CONTRACT_NOTHROW;
864 STATIC_CONTRACT_GC_NOTRIGGER;
865 STATIC_CONTRACT_FORBID_FAULT;
866 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
869 TypeHandle th = TypeHandle(this);
870 g_IBCLogger.LogTypeMethodTableAccess(&th);
871 return IsRestored_NoLogging();
874 BOOL TypeDesc::IsRestored_NoLogging()
876 STATIC_CONTRACT_NOTHROW;
877 STATIC_CONTRACT_GC_NOTRIGGER;
878 STATIC_CONTRACT_FORBID_FAULT;
879 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
882 return (m_typeAndFlags & TypeDesc::enum_flag_Unrestored) == 0;
885 ClassLoadLevel TypeDesc::GetLoadLevel()
887 STATIC_CONTRACT_NOTHROW;
888 STATIC_CONTRACT_GC_NOTRIGGER;
889 STATIC_CONTRACT_FORBID_FAULT;
892 if (m_typeAndFlags & TypeDesc::enum_flag_UnrestoredTypeKey)
894 return CLASS_LOAD_UNRESTOREDTYPEKEY;
896 else if (m_typeAndFlags & TypeDesc::enum_flag_Unrestored)
898 return CLASS_LOAD_UNRESTORED;
900 else if (m_typeAndFlags & TypeDesc::enum_flag_IsNotFullyLoaded)
902 if (m_typeAndFlags & TypeDesc::enum_flag_DependenciesLoaded)
904 return CLASS_DEPENDENCIES_LOADED;
908 return CLASS_LOAD_EXACTPARENTS;
916 // Recursive worker that pumps the transitive closure of a type's dependencies to the specified target level.
917 // Dependencies include:
921 // - canonical type, for non-canonical instantiations
922 // - typical type, for non-typical instantiations
926 // pVisited - used to prevent endless recursion in the case of cyclic dependencies
928 // level - target level to pump to - must be CLASS_DEPENDENCIES_LOADED or CLASS_LOADED
930 // if CLASS_DEPENDENCIES_LOADED, all transitive dependencies are resolved to their
933 // if CLASS_LOADED, all type-safety checks are done on the type and all its transitive
934 // dependencies. Note that for the CLASS_LOADED case, some types may be left
935 // on the pending list rather that pushed to CLASS_LOADED in the case of cyclic
936 // dependencies - the root caller must handle this.
939 // pfBailed - if we or one of our depedencies bails early due to cyclic dependencies, we
940 // must set *pfBailed to TRUE. Otherwise, we must *leave it unchanged* (thus, the
941 // boolean acts as a cumulative OR.)
943 // pPending - if one of our dependencies bailed, the type cannot yet be promoted to CLASS_LOADED
944 // as the dependencies will be checked later and may fail a security check then.
945 // Instead, DoFullyLoad() will add the type to the pending list - the root caller
946 // is responsible for promoting the type after the full transitive closure has been
947 // walked. Note that it would be just as correct to always defer to the pending list -
948 // however, that is a little less performant.
950 // pInstContext - instantiation context created in code:SigPointer.GetTypeHandleThrowing and ultimately
951 // passed down to code:TypeVarTypeDesc.SatisfiesConstraints.
953 void TypeDesc::DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level,
954 DFLPendingList *pPending, BOOL *pfBailed, const InstantiationContext *pInstContext)
963 _ASSERTE(level == CLASS_LOADED || level == CLASS_DEPENDENCIES_LOADED);
964 _ASSERTE(pfBailed != NULL);
965 _ASSERTE(!(level == CLASS_LOADED && pPending == NULL));
968 #ifndef DACCESS_COMPILE
970 if (Generics::RecursionGraph::HasSeenType(pVisited, TypeHandle(this)))
976 if (GetLoadLevel() >= level)
981 if (level == CLASS_LOADED)
983 UINT numTH = pPending->Count();
984 TypeHandle *pTypeHndPending = pPending->Table();
985 for (UINT idxPending = 0; idxPending < numTH; idxPending++)
987 if (pTypeHndPending[idxPending].IsTypeDesc() && pTypeHndPending[idxPending].AsTypeDesc() == this)
997 BOOL fBailed = FALSE;
999 // First ensure that we're loaded to just below CLASS_LOADED
1000 ClassLoader::EnsureLoaded(TypeHandle(this), (ClassLoadLevel) (level-1));
1002 Generics::RecursionGraph newVisited(pVisited, TypeHandle(this));
1006 // Fully load the type parameter
1007 GetTypeParam().DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext);
1009 ParamTypeDesc* pPTD = (ParamTypeDesc*) this;
1011 // Fully load the template method table
1012 if (!pPTD->m_TemplateMT.IsNull())
1014 pPTD->GetTemplateMethodTableInternal()->DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext);
1020 case CLASS_DEPENDENCIES_LOADED:
1021 FastInterlockOr(&m_typeAndFlags, TypeDesc::enum_flag_DependenciesLoaded);
1027 // We couldn't complete security checks on some dependency because he is already being processed by one of our callers.
1028 // Do not mark this class fully loaded yet. Put him on the pending list and he will be marked fully loaded when
1029 // everything unwinds.
1033 TypeHandle* pthPending = pPending->AppendThrowing();
1034 *pthPending = TypeHandle(this);
1038 // Finally, mark this method table as fully loaded
1044 _ASSERTE(!"Can't get here.");
1051 #ifdef FEATURE_PREJIT
1052 void TypeDesc::DoRestoreTypeKey()
1061 #ifndef DACCESS_COMPILE
1064 ParamTypeDesc* pPTD = (ParamTypeDesc*) this;
1065 EnsureWritablePages(pPTD);
1067 // Must have the same loader module, so not encoded
1068 CONSISTENCY_CHECK(!pPTD->m_Arg.IsEncodedFixup());
1069 ClassLoader::EnsureLoaded(pPTD->m_Arg, CLASS_LOAD_UNRESTORED);
1071 // Might live somewhere else e.g. Object[] is shared across all ref array types
1072 Module::RestoreMethodTablePointer(&(pPTD->m_TemplateMT), NULL, CLASS_LOAD_UNRESTORED);
1076 EnsureWritablePages(this);
1079 FastInterlockAnd(&m_typeAndFlags, ~TypeDesc::enum_flag_UnrestoredTypeKey);
1083 #ifndef DACCESS_COMPILE
1085 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
1086 // This just performs a shallow save
1087 void TypeDesc::Save(DataImage *image)
1089 STANDARD_VM_CONTRACT;
1091 ClassLoader::EnsureLoaded(TypeHandle(this));
1093 if (LoggingOn(LF_ZAP, LL_INFO10000))
1096 TypeString::AppendType(name, TypeHandle(this));
1097 LOG((LF_ZAP, LL_INFO10000, "TypeDesc::Save %S\n", name.GetUnicode()));
1100 if (IsGenericVariable())
1102 ((TypeVarTypeDesc*)this)->Save(image);
1104 else if (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR)
1106 ((FnPtrTypeDesc *)this)->Save(image);
1110 _ASSERTE(HasTypeParam());
1111 ((ParamTypeDesc*)this)->Save(image);
1116 void TypeDesc::Fixup(DataImage *image)
1118 STANDARD_VM_CONTRACT;
1120 if (IsGenericVariable())
1122 TypeVarTypeDesc* tyvar = (TypeVarTypeDesc*) this;
1123 tyvar->Fixup(image);
1125 else if (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR)
1127 ((FnPtrTypeDesc*)this)->Fixup(image);
1131 // Works for array and PTR/BYREF types, but not function pointers
1132 _ASSERTE(HasTypeParam());
1136 ((ArrayTypeDesc*) this)->Fixup(image);
1140 ((ParamTypeDesc*) this)->Fixup(image);
1144 if (NeedsRestore(image))
1146 TypeDesc *pTD = (TypeDesc*) image->GetImagePointer(this);
1147 _ASSERTE(pTD != NULL);
1148 pTD->m_typeAndFlags |= TypeDesc::enum_flag_Unrestored | TypeDesc::enum_flag_UnrestoredTypeKey | TypeDesc::enum_flag_IsNotFullyLoaded;
1153 BOOL TypeDesc::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited)
1155 STATIC_STANDARD_VM_CONTRACT;
1157 _ASSERTE(GetAppDomain()->IsCompilationDomain());
1161 return dac_cast<PTR_ParamTypeDesc>(this)->ComputeNeedsRestore(image, pVisited);
1169 void ParamTypeDesc::Save(DataImage *image)
1171 STANDARD_VM_CONTRACT;
1175 image->StoreStructure(this, sizeof(ArrayTypeDesc), DataImage::ITEM_ARRAY_TYPEDESC);
1179 image->StoreStructure(this, sizeof(ParamTypeDesc), DataImage::ITEM_PARAM_TYPEDESC);
1182 // This set of checks matches precisely those in Module::CreateArrayMethodTable
1183 // and ParamTypeDesc::ComputeNeedsRestore
1185 // They indicate if an array TypeDesc is non-canonical (in much the same a a generic
1186 // method table being non-canonical), i.e. it is not the primary
1187 // owner of the m_TemplateMT (the primary owner is the TypeDesc for object[])
1189 if (OwnsTemplateMethodTable())
1191 // This TypeDesc should be the only one saving this MT
1192 _ASSERTE(!image->IsStored(GetTemplateMethodTableInternal()));
1193 Module::SaveMethodTable(image, GetTemplateMethodTableInternal(), 0);
1199 void ParamTypeDesc::Fixup(DataImage *image)
1201 STANDARD_VM_CONTRACT;
1203 _ASSERTE(image->GetModule()->GetAssembly() ==
1204 GetAppDomain()->ToCompilationDomain()->GetTargetAssembly());
1206 if (LoggingOn(LF_ZAP, LL_INFO10000))
1209 TypeString::AppendType(name, TypeHandle(this));
1210 LOG((LF_ZAP, LL_INFO10000, "ParamTypeDesc::Fixup %S\n", name.GetUnicode()));
1213 if (!m_TemplateMT.IsNull())
1215 if (OwnsTemplateMethodTable())
1217 // In all other cases the type desc "owns" the m_TemplateMT
1218 // and it is always stored in the same module as the TypeDesc (i.e. the
1219 // TypeDesc and the MT are "tightly-knit") In other words if one is present in
1220 // an NGEN image then then other will be, and if one is "used" at runtime then
1221 // the other will be too.
1222 image->FixupMethodTablePointer(this, &m_TemplateMT);
1223 GetTemplateMethodTableInternal()->Fixup(image);
1227 // Fixup the pointer to the possibly-shared m_TemplateMT. This might be in a different module.
1228 image->FixupMethodTablePointer(this, &m_TemplateMT);
1232 // Fixup the pointer to the element type.
1233 image->HardBindTypeHandlePointer(this, offsetof(ParamTypeDesc, m_Arg));
1235 // The managed object will get regenerated on demand
1236 image->ZeroField(this, offsetof(ParamTypeDesc, m_hExposedClassObject), sizeof(m_hExposedClassObject));
1239 void ArrayTypeDesc::Fixup(DataImage *image)
1241 STANDARD_VM_CONTRACT;
1243 ParamTypeDesc::Fixup(image);
1245 #ifdef FEATURE_COMINTEROP
1246 // We don't save CCW templates into ngen images
1247 image->ZeroField(this, offsetof(ArrayTypeDesc, m_pCCWTemplate), sizeof(m_pCCWTemplate));
1248 #endif // FEATURE_COMINTEROP
1251 BOOL ParamTypeDesc::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited)
1253 STATIC_STANDARD_VM_CONTRACT;
1255 _ASSERTE(GetAppDomain()->IsCompilationDomain());
1257 if (m_typeAndFlags & TypeDesc::enum_flag_NeedsRestore)
1261 if (m_typeAndFlags & TypeDesc::enum_flag_PreRestored)
1267 if (!image->CanPrerestoreEagerBindToTypeHandle(m_Arg, pVisited))
1272 // This set of checks matches precisely those in Module::CreateArrayMethodTable and ParamTypeDesc::Fixup
1274 if (!m_TemplateMT.IsNull())
1276 if (OwnsTemplateMethodTable())
1278 if (GetTemplateMethodTableInternal()->ComputeNeedsRestore(image, pVisited))
1285 if (!image->CanPrerestoreEagerBindToMethodTable(GetTemplateMethodTableInternal(), pVisited))
1292 // Cache the results of running the algorithm.
1293 // We can only cache the result if we have not speculatively assumed
1294 // that any types are not NeedsRestore, i.e. the visited list is empty
1295 if (pVisited == NULL)
1297 if (LoggingOn(LF_ZAP, LL_INFO10000))
1300 TypeString::AppendType(name, TypeHandle(this));
1301 LOG((LF_ZAP, LL_INFO10000, "ParamTypeDesc::ComputeNeedsRestore=%d for %S\n", res, name.GetUnicode()));
1303 m_typeAndFlags |= (res ? TypeDesc::enum_flag_NeedsRestore : TypeDesc::enum_flag_PreRestored);
1307 #endif // FEATURE_NATIVE_IMAGE_GENERATION
1309 void TypeDesc::SetIsRestored()
1311 STATIC_CONTRACT_THROWS;
1312 STATIC_CONTRACT_GC_NOTRIGGER;
1313 STATIC_CONTRACT_FORBID_FAULT;
1314 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
1316 TypeHandle th = TypeHandle(this);
1317 FastInterlockAnd(EnsureWritablePages(&m_typeAndFlags), ~TypeDesc::enum_flag_Unrestored);
1320 #endif // #ifndef DACCESS_COMPILE
1322 void TypeDesc::Restore()
1328 INJECT_FAULT(COMPlusThrowOM(););
1329 CONSISTENCY_CHECK(!HasUnrestoredTypeKey());
1333 #ifndef DACCESS_COMPILE
1336 ParamTypeDesc *pPTD = dac_cast<PTR_ParamTypeDesc>(this);
1338 OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_EXACTPARENTS);
1340 // Must have the same loader module
1341 ClassLoader::EnsureLoaded(pPTD->m_Arg, CLASS_LOAD_EXACTPARENTS);
1343 // Method-table pointer must have been restored by DoRestoreTypeKey
1344 Module::RestoreMethodTablePointer(&pPTD->m_TemplateMT, NULL, CLASS_LOAD_EXACTPARENTS);
1350 #endif // #ifndef DACCESS_COMPILE
1353 #endif // FEATURE_PREJIT
1356 #ifndef DACCESS_COMPILE
1358 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
1359 void TypeVarTypeDesc::Save(DataImage *image)
1361 STANDARD_VM_CONTRACT;
1363 // We don't persist the constraints: instead, load them back on demand
1364 m_numConstraints = (DWORD) -1;
1366 LOG((LF_ZAP, LL_INFO10000, " TypeVarTypeDesc::Save %x (%p)\n", GetToken(), this));
1367 image->StoreStructure(this, sizeof(TypeVarTypeDesc),
1368 DataImage::ITEM_TYVAR_TYPEDESC);
1371 void TypeVarTypeDesc::Fixup(DataImage *image)
1373 STANDARD_VM_CONTRACT;
1375 LOG((LF_ZAP, LL_INFO10000, " TypeVarTypeDesc::Fixup %x (%p)\n", GetToken(), this));
1376 image->FixupRelativePointerField(this, offsetof(TypeVarTypeDesc, m_pModule));
1377 image->ZeroField(this, offsetof(TypeVarTypeDesc, m_hExposedClassObject), sizeof(m_hExposedClassObject));
1379 // We don't persist the constraints: instead, load them back on demand
1380 image->ZeroPointerField(this, offsetof(TypeVarTypeDesc, m_constraints));
1383 #endif // FEATURE_NATIVE_IMAGE_GENERATION
1385 MethodDesc * TypeVarTypeDesc::LoadOwnerMethod()
1393 PRECONDITION(TypeFromToken(m_typeOrMethodDef) == mdtMethodDef);
1397 MethodDesc *pMD = GetModule()->LookupMethodDef(m_typeOrMethodDef);
1400 pMD = MemberLoader::GetMethodDescFromMethodDef(GetModule(), m_typeOrMethodDef, FALSE);
1405 TypeHandle TypeVarTypeDesc::LoadOwnerType()
1413 PRECONDITION(TypeFromToken(m_typeOrMethodDef) == mdtTypeDef);
1417 TypeHandle genericType = GetModule()->LookupTypeDef(m_typeOrMethodDef);
1418 if (genericType.IsNull())
1420 genericType = ClassLoader::LoadTypeDefThrowing(GetModule(), m_typeOrMethodDef,
1421 ClassLoader::ThrowIfNotFound,
1422 ClassLoader::PermitUninstDefOrRef);
1427 TypeHandle* TypeVarTypeDesc::GetCachedConstraints(DWORD *pNumConstraints)
1429 LIMITED_METHOD_CONTRACT;
1430 PRECONDITION(CheckPointer(pNumConstraints));
1431 PRECONDITION(m_numConstraints != (DWORD) -1);
1433 *pNumConstraints = m_numConstraints;
1434 return m_constraints;
1440 TypeHandle* TypeVarTypeDesc::GetConstraints(DWORD *pNumConstraints, ClassLoadLevel level /* = CLASS_LOADED */)
1442 WRAPPER_NO_CONTRACT;
1443 PRECONDITION(CheckPointer(pNumConstraints));
1444 PRECONDITION(level == CLASS_DEPENDENCIES_LOADED || level == CLASS_LOADED);
1446 if (m_numConstraints == (DWORD) -1)
1447 LoadConstraints(level);
1449 *pNumConstraints = m_numConstraints;
1450 return m_constraints;
1454 void TypeVarTypeDesc::LoadConstraints(ClassLoadLevel level /* = CLASS_LOADED */)
1462 INJECT_FAULT(COMPlusThrowOM());
1464 PRECONDITION(level == CLASS_DEPENDENCIES_LOADED || level == CLASS_LOADED);
1468 _ASSERTE(((INT_PTR)&m_constraints) % sizeof(m_constraints) == 0);
1469 _ASSERTE(((INT_PTR)&m_numConstraints) % sizeof(m_numConstraints) == 0);
1471 DWORD numConstraints = m_numConstraints;
1473 if (numConstraints == (DWORD) -1)
1475 EnsureWritablePages(this);
1477 IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1479 HENUMInternalHolder hEnum(pInternalImport);
1480 mdGenericParamConstraint tkConstraint;
1482 SigTypeContext typeContext;
1483 mdToken defToken = GetTypeOrMethodDef();
1485 MethodTable *pMT = NULL;
1486 if (TypeFromToken(defToken) == mdtMethodDef)
1488 MethodDesc *pMD = LoadOwnerMethod();
1489 _ASSERTE(pMD->IsGenericMethodDefinition());
1491 SigTypeContext::InitTypeContext(pMD,&typeContext);
1493 _ASSERTE(!typeContext.m_methodInst.IsEmpty());
1494 pMT = pMD->GetMethodTable();
1498 _ASSERTE(TypeFromToken(defToken) == mdtTypeDef);
1499 TypeHandle genericType = LoadOwnerType();
1500 _ASSERTE(genericType.IsGenericTypeDefinition());
1502 SigTypeContext::InitTypeContext(genericType,&typeContext);
1505 hEnum.EnumInit(mdtGenericParamConstraint, GetToken());
1506 numConstraints = pInternalImport->EnumGetCount(&hEnum);
1507 if (numConstraints != 0)
1509 LoaderAllocator* pAllocator = GetModule()->GetLoaderAllocator();
1510 // If there is a single class constraint we put in in element 0 of the array
1511 AllocMemHolder<TypeHandle> constraints
1512 (pAllocator->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(numConstraints) * S_SIZE_T(sizeof(TypeHandle))));
1515 while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
1517 _ASSERTE(i <= numConstraints);
1518 mdToken tkConstraintType, tkParam;
1519 if (FAILED(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType)))
1521 GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
1523 _ASSERTE(tkParam == GetToken());
1524 TypeHandle thConstraint = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(GetModule(), tkConstraintType,
1526 ClassLoader::ThrowIfNotFound,
1527 ClassLoader::FailIfUninstDefOrRef,
1528 ClassLoader::LoadTypes,
1531 constraints[i++] = thConstraint;
1533 // Method type constraints behave contravariantly
1534 // (cf Bounded polymorphism e.g. see
1535 // Cardelli & Wegner, On understanding types, data abstraction and polymorphism, Computing Surveys 17(4), Dec 1985)
1536 if (pMT != NULL && pMT->HasVariance() && TypeFromToken(tkConstraintType) == mdtTypeSpec)
1539 PCCOR_SIGNATURE pSig;
1540 if (FAILED(pInternalImport->GetTypeSpecFromToken(tkConstraintType, &pSig, &cSig)))
1542 GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
1544 if (!EEClass::CheckVarianceInSig(pMT->GetNumGenericArgs(),
1545 pMT->GetClass()->GetVarianceInfo(),
1547 SigPointer(pSig, cSig),
1550 GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_VARIANCE_IN_CONSTRAINT);
1555 if (InterlockedCompareExchangeT(&m_constraints, constraints.operator->(), NULL) == NULL)
1557 constraints.SuppressRelease();
1561 m_numConstraints = numConstraints;
1564 for (DWORD i = 0; i < numConstraints; i++)
1566 ClassLoader::EnsureLoaded(m_constraints[i], level);
1570 BOOL TypeVarTypeDesc::ConstrainedAsObjRef()
1577 PRECONDITION(ConstraintsLoaded());
1581 IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1582 mdGenericParam genericParamToken = GetToken();
1584 if (FAILED(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
1588 DWORD specialConstraints = flags & gpSpecialConstraintMask;
1590 if ((specialConstraints & gpReferenceTypeConstraint) != 0)
1593 return ConstrainedAsObjRefHelper();
1596 // A recursive helper that helps determine whether this variable is constrained as ObjRef.
1597 // Please note that we do not check the gpReferenceTypeConstraint special constraint here
1598 // because this property does not propagate up the constraining hierarchy.
1599 // (e.g. "class A<S, T> where S : T, where T : class" does not guarantee that S is ObjRef)
1600 BOOL TypeVarTypeDesc::ConstrainedAsObjRefHelper()
1610 DWORD dwNumConstraints = 0;
1611 TypeHandle* constraints = GetCachedConstraints(&dwNumConstraints);
1613 for (DWORD i = 0; i < dwNumConstraints; i++)
1615 TypeHandle constraint = constraints[i];
1617 if (constraint.IsGenericVariable() && constraint.AsGenericVariable()->ConstrainedAsObjRefHelper())
1620 if (!constraint.IsInterface() && CorTypeInfo::IsObjRef_NoThrow(constraint.GetInternalCorElementType()))
1622 // Object, ValueType, and Enum are ObjRefs but they do not constrain the var to ObjRef!
1623 MethodTable *mt = constraint.GetMethodTable();
1625 if (mt != g_pObjectClass &&
1626 mt != g_pValueTypeClass &&
1637 BOOL TypeVarTypeDesc::ConstrainedAsValueType()
1644 PRECONDITION(ConstraintsLoaded());
1648 IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1649 mdGenericParam genericParamToken = GetToken();
1651 if (FAILED(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
1655 DWORD specialConstraints = flags & gpSpecialConstraintMask;
1657 if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
1660 DWORD dwNumConstraints = 0;
1661 TypeHandle* constraints = GetCachedConstraints(&dwNumConstraints);
1663 for (DWORD i = 0; i < dwNumConstraints; i++)
1665 TypeHandle constraint = constraints[i];
1667 if (constraint.IsGenericVariable())
1669 if (constraint.AsGenericVariable()->ConstrainedAsValueType())
1674 // the following condition will also disqualify interfaces
1675 if (!CorTypeInfo::IsObjRef_NoThrow(constraint.GetInternalCorElementType()))
1683 //---------------------------------------------------------------------------------------------------------------------
1684 // Loads the type of a constraint given the constraint token and instantiation context. If pInstContext is
1685 // not NULL and the constraint's type is a typespec, pInstContext will be used to instantiate the typespec.
1686 // Otherwise typical instantiation is returned if the constraint type is generic.
1687 //---------------------------------------------------------------------------------------------------------------------
1689 TypeHandle LoadTypeVarConstraint(TypeVarTypeDesc *pTypeVar, mdGenericParamConstraint tkConstraint,
1690 const InstantiationContext *pInstContext)
1696 INJECT_FAULT(COMPlusThrowOM());
1698 PRECONDITION(CheckPointer(pTypeVar));
1702 Module *pTyModule = pTypeVar->GetModule();
1703 IMDInternalImport* pInternalImport = pTyModule->GetMDImport();
1705 mdToken tkConstraintType, tkParam;
1706 IfFailThrow(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType));
1707 _ASSERTE(tkParam == pTypeVar->GetToken());
1708 mdToken tkOwnerToken = pTypeVar->GetTypeOrMethodDef();
1710 if (TypeFromToken(tkConstraintType) == mdtTypeSpec && pInstContext != NULL)
1712 if(pInstContext->m_pSubstChain == NULL)
1714 // The substitution chain will be null in situations
1715 // where we are instantiating types that are open, and therefore
1716 // we should be using the fully open TypeVar constraint instantiation code
1717 // below. However, in the case of a open method on a closed generic class
1718 // we will also have a null substitution chain. In this case, if we can ensure
1719 // that the instantiation type parameters are non type-var types, it is valid
1720 // to use the passed in instantiation when instantiating the type var constraint.
1721 BOOL fContextContainsValidGenericTypeParams = FALSE;
1723 if (TypeFromToken(tkOwnerToken) == mdtMethodDef)
1725 SigTypeContext sigTypeContext;
1727 MethodDesc *pMD = pTypeVar->LoadOwnerMethod();
1729 SigTypeContext::InitTypeContext(pMD, &sigTypeContext);
1730 fContextContainsValidGenericTypeParams = SigTypeContext::IsValidTypeOnlyInstantiationOf(&sigTypeContext, pInstContext->m_pArgContext);
1733 if (!fContextContainsValidGenericTypeParams)
1734 goto LoadConstraintOnOpenType;
1737 // obtain the constraint type's signature if it's a typespec
1739 PCCOR_SIGNATURE ptr;
1741 IfFailThrow(pInternalImport->GetSigFromToken(tkConstraintType, &cbSig, &ptr));
1743 SigPointer pSig(ptr, cbSig);
1745 // instantiate the signature using the current InstantiationContext
1746 return pSig.GetTypeHandleThrowing(pTyModule,
1747 pInstContext->m_pArgContext,
1748 ClassLoader::LoadTypes, CLASS_DEPENDENCIES_LOADED, FALSE,
1749 pInstContext->m_pSubstChain);
1753 LoadConstraintOnOpenType:
1755 SigTypeContext sigTypeContext;
1757 switch (TypeFromToken(tkOwnerToken))
1761 // the type variable is declared by a type - load the handle of the type
1762 TypeHandle thOwner = pTyModule->GetClassLoader()->LoadTypeDefThrowing(pTyModule,
1764 ClassLoader::ThrowIfNotFound,
1765 ClassLoader::PermitUninstDefOrRef,
1767 CLASS_LOAD_APPROXPARENTS
1770 SigTypeContext::InitTypeContext(thOwner, &sigTypeContext);
1776 // the type variable is declared by a method - load its method desc
1777 MethodDesc *pMD = pTyModule->LookupMethodDef(tkOwnerToken);
1779 SigTypeContext::InitTypeContext(pMD, &sigTypeContext);
1785 COMPlusThrow(kBadImageFormatException);
1789 // load the (typical instantiation of) constraint type
1790 return ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pTyModule,
1793 ClassLoader::ThrowIfNotFound,
1794 ClassLoader::FailIfUninstDefOrRef,
1795 ClassLoader::LoadTypes,
1796 CLASS_DEPENDENCIES_LOADED);
1800 //---------------------------------------------------------------------------------------------------------------------
1801 // We come here only if a type parameter with a special constraint is instantiated by an argument that is itself
1802 // a type parameter. In this case, we'll need to examine *its* constraints to see if the range of types that would satisfy its
1803 // constraints is a subset of the range of types that would satisfy the special constraint.
1805 // This routine will return TRUE if it can prove that argument "pTyArg" has a constraint that will satisfy the special constraint.
1807 // (NOTE: It does not check against anything other than one specific specialConstraint (it doesn't even know what they are.) This is
1808 // just one step in the checking of constraints.)
1809 //---------------------------------------------------------------------------------------------------------------------
1811 BOOL SatisfiesSpecialConstraintRecursive(TypeVarTypeDesc *pTyArg, DWORD specialConstraint, TypeHandleList *pVisitedVars = NULL)
1817 INJECT_FAULT(COMPlusThrowOM());
1819 PRECONDITION(CheckPointer(pTyArg));
1823 // The caller must invoke for all special constraints that apply - this fcn can only reliably test against one
1824 // constraint at a time.
1825 _ASSERTE(specialConstraint == gpNotNullableValueTypeConstraint
1826 || specialConstraint == gpReferenceTypeConstraint
1827 || specialConstraint == gpDefaultConstructorConstraint);
1829 IMDInternalImport* pInternalImport = pTyArg->GetModule()->GetMDImport();
1831 // Get the argument type's own special constraints
1833 IfFailThrow(pTyArg->GetModule()->GetMDImport()->GetGenericParamProps(pTyArg->GetToken(), NULL, &argFlags, NULL, NULL, NULL));
1835 DWORD argSpecialConstraints = argFlags & gpSpecialConstraintMask;
1837 // First, if the argument's own special constraints match the parameter's special constraints,
1838 // we can safely conclude the constraint is satisfied.
1839 switch (specialConstraint)
1841 case gpNotNullableValueTypeConstraint:
1843 if ((argSpecialConstraints & gpNotNullableValueTypeConstraint) != 0)
1850 case gpReferenceTypeConstraint:
1852 // gpReferenceTypeConstraint is not "inherited" so ignore it if pTyArg is a variable
1853 // constraining the argument rather than the argument itself.
1855 if (pVisitedVars == NULL && (argSpecialConstraints & gpReferenceTypeConstraint) != 0)
1862 case gpDefaultConstructorConstraint:
1864 // gpDefaultConstructorConstraint is not "inherited" so ignore it if pTyArg is a variable
1865 // constraining the argument rather than the argument itself.
1867 if ((pVisitedVars == NULL && (argSpecialConstraints & gpDefaultConstructorConstraint) != 0) ||
1868 (argSpecialConstraints & gpNotNullableValueTypeConstraint) != 0)
1876 // The special constraints did not match. However, we may find a primary type constraint
1877 // that would always satisfy the special constraint.
1878 HENUMInternalHolder hEnum(pInternalImport);
1879 hEnum.EnumInit(mdtGenericParamConstraint, pTyArg->GetToken());
1881 mdGenericParamConstraint tkConstraint;
1882 while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
1884 // We pass NULL instantiation context here because when checking for special constraints, it makes
1885 // no difference whether we load a typical (e.g. A<T>) or concrete (e.g. A<string>) instantiation.
1886 TypeHandle thConstraint = LoadTypeVarConstraint(pTyArg, tkConstraint, NULL);
1888 if (thConstraint.IsGenericVariable())
1890 // The variable is constrained by another variable, which we need to check recursively. An
1891 // example of why this is necessary follows:
1893 // class A<T> where T : class
1895 // class B<S, R> : A<S> where S : R where R : EventArgs
1898 if (!TypeHandleList::Exists(pVisitedVars, thConstraint))
1900 TypeHandleList newVisitedVars(thConstraint, pVisitedVars);
1901 if (SatisfiesSpecialConstraintRecursive(thConstraint.AsGenericVariable(),
1909 else if (thConstraint.IsInterface())
1911 // This is a secondary constraint - this tells us nothing about the eventual instantiation that
1916 // This is a type constraint. Remember that the eventual instantiation is only guaranteed to be
1917 // something *derived* from this type, not the actual type itself. To emphasize, we rename the local.
1919 TypeHandle thAncestorOfType = thConstraint;
1921 if (specialConstraint == gpNotNullableValueTypeConstraint)
1923 if (thAncestorOfType.IsValueType() && !(thAncestorOfType.AsMethodTable()->IsNullable()))
1929 if (specialConstraint == gpReferenceTypeConstraint)
1932 if (!thAncestorOfType.IsTypeDesc())
1934 MethodTable *pAncestorMT = thAncestorOfType.AsMethodTable();
1936 if ((!(pAncestorMT->IsValueType())) && pAncestorMT != g_pObjectClass && pAncestorMT != g_pValueTypeClass)
1938 // ValueTypes are sealed except when they aren't (cough, cough, System.Enum...). Sigh.
1939 // Don't put all our trust in IsValueType() here - check the ancestry chain as well.
1940 BOOL fIsValueTypeAnAncestor = FALSE;
1941 MethodTable *pParentMT = pAncestorMT->GetParentMethodTable();
1944 if (pParentMT == g_pValueTypeClass)
1946 fIsValueTypeAnAncestor = TRUE;
1949 pParentMT = pParentMT->GetParentMethodTable();
1952 if (!fIsValueTypeAnAncestor)
1960 if (specialConstraint == gpDefaultConstructorConstraint)
1962 // If a valuetype, just check to ensure that doesn't have a private default ctor.
1963 // If not a valuetype, not much we can conclude knowing just an ancestor class.
1964 if (thAncestorOfType.IsValueType() && thAncestorOfType.GetMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor())
1973 // If we got here, we found no evidence that the argument's constraints are strict enough to satisfy the parameter's constraints.
1977 //---------------------------------------------------------------------------------------------------------------------
1978 // Walks the "constraining chain" of a type variable and appends all concrete constraints as well as type vars
1979 // to the provided ArrayList. Upon leaving the function, the list contains all types that the type variable is
1980 // known to be assignable to.
1983 // class A<S, T> where S : T, IComparable where T : EventArgs
1985 // void f<U>(U u) where U : S, IDisposable { }
1987 // This would put 5 types to the U's list: S, T, IDisposable, IComparable, and EventArgs.
1988 //---------------------------------------------------------------------------------------------------------------------
1990 void GatherConstraintsRecursive(TypeVarTypeDesc *pTyArg, ArrayList *pArgList, const InstantiationContext *pInstContext,
1991 TypeHandleList *pVisitedVars = NULL)
1997 INJECT_FAULT(COMPlusThrowOM());
1999 PRECONDITION(CheckPointer(pTyArg));
2000 PRECONDITION(CheckPointer(pArgList));
2004 IMDInternalImport* pInternalImport = pTyArg->GetModule()->GetMDImport();
2006 // enumerate constraints of the pTyArg
2007 HENUMInternalHolder hEnum(pInternalImport);
2008 hEnum.EnumInit(mdtGenericParamConstraint, pTyArg->GetToken());
2010 mdGenericParamConstraint tkConstraint;
2011 while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
2013 TypeHandle thConstraint = LoadTypeVarConstraint(pTyArg, tkConstraint, pInstContext);
2015 if (thConstraint.IsGenericVariable())
2017 // see if it's safe to recursively call ourselves
2018 if (!TypeHandleList::Exists(pVisitedVars, thConstraint))
2020 pArgList->Append(thConstraint.AsPtr());
2022 TypeHandleList newVisitedVars(thConstraint, pVisitedVars);
2023 GatherConstraintsRecursive(thConstraint.AsGenericVariable(), pArgList, pInstContext, &newVisitedVars);
2026 // Note: circular type parameter constraints will be detected and reported later in
2027 // MethodTable::DoFullyLoad, we just have to avoid SO here.
2031 pArgList->Append(thConstraint.AsPtr());
2036 // pTypeContextOfConstraintDeclarer = type context of the generic type that declares the constraint
2037 // This is needed to load the "X" type when the constraint is the frm
2039 // Caution: Do NOT use it to load types or constraints attached to "thArg".
2041 // thArg = typehandle of the type being substituted for the type parameter.
2043 // pInstContext = the instantiation context (type context + substitution chain) to be
2044 // used when loading constraints attached to "thArg".
2046 BOOL TypeVarTypeDesc::SatisfiesConstraints(SigTypeContext *pTypeContextOfConstraintDeclarer, TypeHandle thArg,
2047 const InstantiationContext *pInstContext/*=NULL*/)
2055 PRECONDITION(!thArg.IsNull());
2056 INJECT_FAULT(COMPlusThrowOM());
2060 IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
2061 mdGenericParamConstraint tkConstraint;
2063 INDEBUG(mdToken defToken = GetTypeOrMethodDef());
2064 _ASSERTE(TypeFromToken(defToken) == mdtMethodDef || TypeFromToken(defToken) == mdtTypeDef);
2066 // prepare for the enumeration of this variable's general constraints
2067 mdGenericParam genericParamToken = GetToken();
2069 HENUMInternalHolder hEnum(pInternalImport);
2070 hEnum.EnumInit(mdtGenericParamConstraint, genericParamToken);
2074 // First check special constraints (must-be-reference-type, must-be-value-type, and must-have-default-constructor)
2076 IfFailThrow(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL));
2078 DWORD specialConstraints = flags & gpSpecialConstraintMask;
2080 if (thArg.IsGenericVariable())
2082 TypeVarTypeDesc *pTyVar = thArg.AsGenericVariable();
2084 if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
2086 if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpNotNullableValueTypeConstraint))
2092 if ((specialConstraints & gpReferenceTypeConstraint) != 0)
2094 if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpReferenceTypeConstraint))
2100 if ((specialConstraints & gpDefaultConstructorConstraint) != 0)
2102 if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpDefaultConstructorConstraint))
2108 if (hEnum.EnumGetCount() == 0)
2110 // return immediately if there are no general constraints to satisfy (fast path)
2114 // Now walk the "constraining chain" of type variables and gather all constraint types.
2116 // This work should not be left to code:TypeHandle.CanCastTo because we need typespec constraints
2117 // to be instantiated in pInstContext. If we just do thArg.CanCastTo(thConstraint), it would load
2118 // typical instantiations of the constraints and the can-cast-to check may fail. In addition,
2119 // code:TypeHandle.CanCastTo will SO if the constraints are circular.
2125 // void f<U>(B<U, T> b) where U : A<T> { }
2127 // class B<S, R> where S : A<R> { }
2129 // If we load the signature of, say, A<int>.f<U> (concrete class but typical method), and end up
2130 // here verifying that S : A<R> is satisfied by U : A<T>, we must instantiate the constraint type
2131 // A<T> using pInstContext so that it becomes A<int>. Otherwise the constraint check fails.
2133 GatherConstraintsRecursive(pTyVar, &argList, pInstContext);
2137 if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
2139 if (!thArg.IsValueType())
2143 // the type argument is a value type, however if it is any kind of Nullable we want to fail
2144 // as the constraint accepts any value type except Nullable types (Nullable itself is a value type)
2145 if (thArg.AsMethodTable()->IsNullable())
2150 if ((specialConstraints & gpReferenceTypeConstraint) != 0)
2152 if (thArg.IsValueType())
2156 if ((specialConstraints & gpDefaultConstructorConstraint) != 0)
2158 if (thArg.IsTypeDesc() || (!thArg.AsMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor()))
2163 // Complete the list by adding thArg itself. If thArg is not a generic variable this will be the only
2164 // item in the list. If it is a generic variable, we need it in the list as well in addition to all the
2165 // constraints gathered by GatherConstraintsRecursive, because e.g. class A<S, T> : where S : T
2166 // can be instantiated using A<U, U>.
2167 argList.Append(thArg.AsPtr());
2169 // At this point argList contains all types that thArg is known to be assignable to. The list may
2170 // contain duplicates and it consists of zero or more type variables, zero or more possibly generic
2171 // interfaces, and at most one possibly generic class.
2173 // Now check general subtype constraints
2174 while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
2176 mdToken tkConstraintType, tkParam;
2177 IfFailThrow(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType));
2179 _ASSERTE(tkParam == GetToken());
2180 TypeHandle thConstraint = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(GetModule(),
2182 pTypeContextOfConstraintDeclarer,
2183 ClassLoader::ThrowIfNotFound,
2184 ClassLoader::FailIfUninstDefOrRef,
2185 ClassLoader::LoadTypes,
2186 CLASS_DEPENDENCIES_LOADED);
2188 // System.Object constraint will be always satisfied - even if argList is empty
2189 if (!thConstraint.IsObjectType())
2191 BOOL fCanCast = FALSE;
2193 // loop over all types that we know the arg will be assignable to
2194 ArrayList::Iterator iter = argList.Iterate();
2197 TypeHandle thElem = TypeHandle::FromPtr(iter.GetElement());
2199 if (thElem.IsGenericVariable())
2201 // if a generic variable equals to the constraint, then this constraint will be satisfied
2202 if (thElem == thConstraint)
2208 // and any variable with the gpNotNullableValueTypeConstraint special constraint
2209 // satisfies the "derived from System.ValueType" general subtype constraint
2210 if (thConstraint == g_pValueTypeClass)
2212 TypeVarTypeDesc *pTyElem = thElem.AsGenericVariable();
2213 IfFailThrow(pTyElem->GetModule()->GetMDImport()->GetGenericParamProps(
2214 pTyElem->GetToken(),
2221 if ((flags & gpNotNullableValueTypeConstraint) != 0)
2230 // if a concrete type can be cast to the constraint, then this constraint will be satisifed
2231 if (thElem.CanCastTo(thConstraint))
2247 #ifndef CROSSGEN_COMPILE
2248 OBJECTREF TypeVarTypeDesc::GetManagedClassObject()
2255 INJECT_FAULT(COMPlusThrowOM());
2257 PRECONDITION(IsGenericVariable());
2261 if (m_hExposedClassObject == NULL) {
2262 REFLECTCLASSBASEREF refClass = NULL;
2263 GCPROTECT_BEGIN(refClass);
2264 if (GetAssembly()->IsIntrospectionOnly())
2265 refClass = (REFLECTCLASSBASEREF) AllocateObject(MscorlibBinder::GetClass(CLASS__CLASS_INTROSPECTION_ONLY));
2267 refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass);
2269 LoaderAllocator *pLoaderAllocator = GetLoaderAllocator();
2270 TypeHandle th = TypeHandle(this);
2271 ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th);
2272 ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject());
2274 // Let all threads fight over who wins using InterlockedCompareExchange.
2275 // Only the winner can set m_hExposedClassObject from NULL.
2276 LOADERHANDLE hExposedClassObject = pLoaderAllocator->AllocateHandle(refClass);
2278 if (FastInterlockCompareExchangePointer(EnsureWritablePages(&m_hExposedClassObject), hExposedClassObject, static_cast<LOADERHANDLE>(NULL)))
2280 pLoaderAllocator->ClearHandle(hExposedClassObject);
2285 return GetManagedClassObjectIfExists();
2287 #endif // CROSSGEN_COMPILE
2289 #endif //!DACCESS_COMPILE
2292 FnPtrTypeDesc::GetRetAndArgTypes()
2302 // Decode encoded type handles on demand
2303 #if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
2304 for (DWORD i = 0; i <= m_NumArgs; i++)
2306 Module::RestoreTypeHandlePointerRaw(&m_RetAndArgTypes[i]);
2308 #endif //defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
2310 return m_RetAndArgTypes;
2311 } // FnPtrTypeDesc::GetRetAndArgTypes
2313 #ifndef DACCESS_COMPILE
2315 // Returns TRUE if all return and argument types are externally visible.
2317 FnPtrTypeDesc::IsExternallyVisible() const
2327 const TypeHandle * rgRetAndArgTypes = GetRetAndArgTypes();
2328 for (DWORD i = 0; i <= m_NumArgs; i++)
2330 if (!rgRetAndArgTypes[i].IsExternallyVisible())
2335 // All return/arguments types are externally visible
2337 } // FnPtrTypeDesc::IsExternallyVisible
2339 // Returns TRUE if any of return or argument types is part of an assembly loaded for introspection.
2341 FnPtrTypeDesc::IsIntrospectionOnly() const
2350 const TypeHandle * rgRetAndArgTypes = GetRetAndArgTypes();
2351 for (DWORD i = 0; i <= m_NumArgs; i++)
2353 if (rgRetAndArgTypes[i].IsIntrospectionOnly())
2358 // None of the return/arguments type was loaded for introspection
2360 } // FnPtrTypeDesc::IsIntrospectionOnly
2362 // Returns TRUE if any of return or argument types is part of an assembly loaded for introspection.
2363 // Instantiations of generic types are also recursively checked.
2365 FnPtrTypeDesc::ContainsIntrospectionOnlyTypes() const
2374 const TypeHandle * rgRetAndArgTypes = GetRetAndArgTypes();
2375 for (DWORD i = 0; i <= m_NumArgs; i++)
2377 if (rgRetAndArgTypes[i].ContainsIntrospectionOnlyTypes())
2382 // None of the return/arguments type contains types loaded for introspection
2384 } // FnPtrTypeDesc::ContainsIntrospectionOnlyTypes
2386 #endif //DACCESS_COMPILE
2388 #if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
2390 void FnPtrTypeDesc::Save(DataImage * image)
2392 STANDARD_VM_CONTRACT;
2394 image->StoreStructure(
2396 sizeof(FnPtrTypeDesc) + (m_NumArgs * sizeof(TypeHandle)),
2397 DataImage::ITEM_FPTR_TYPEDESC);
2400 void FnPtrTypeDesc::Fixup(DataImage * image)
2402 STANDARD_VM_CONTRACT;
2404 for (DWORD i = 0; i <= m_NumArgs; i++)
2406 image->FixupTypeHandlePointerInPlace(
2408 (BYTE *)&m_RetAndArgTypes[i] - (BYTE *)this);
2412 #endif //defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
2414 #ifdef DACCESS_COMPILE
2417 ParamTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2422 PTR_MethodTable pTemplateMT = GetTemplateMethodTableInternal();
2423 if (pTemplateMT.IsValid())
2425 pTemplateMT->EnumMemoryRegions(flags);
2428 m_Arg.EnumMemoryRegions(flags);
2432 TypeVarTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2437 PTR_TypeVarTypeDesc ptrThis(this);
2439 if (GetModule().IsValid())
2441 GetModule()->EnumMemoryRegions(flags, true);
2444 if (m_numConstraints != (DWORD)-1)
2446 PTR_TypeHandle constraint = m_constraints;
2447 for (DWORD i = 0; i < m_numConstraints; i++)
2449 if (constraint.IsValid())
2451 constraint->EnumMemoryRegions(flags);
2456 } // TypeVarTypeDesc::EnumMemoryRegions
2459 FnPtrTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2464 for (DWORD i = 0; i < m_NumArgs; i++)
2466 m_RetAndArgTypes[i].EnumMemoryRegions(flags);
2470 #endif //DACCESS_COMPILE