[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / typedesc.cpp
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.
4 // 
5 // File: typedesc.cpp
6 // 
7
8
9 // 
10 // This file contains definitions for methods in the code:TypeDesc class and its 
11 // subclasses 
12 //     code:ParamTypeDesc, 
13 //     code:ArrayTypeDesc, 
14 //     code:TyVarTypeDesc, 
15 //     code:FnPtrTypeDesc
16 // 
17
18 // 
19 // ============================================================================
20
21 #include "common.h"
22 #include "typedesc.h"
23 #include "typestring.h"
24 #if defined(FEATURE_PREJIT)
25 #include "compile.h"
26 #endif
27 #include "array.h"
28
29 #ifndef DACCESS_COMPILE
30 #ifdef _DEBUG
31
32 BOOL ParamTypeDesc::Verify() {
33
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;
40
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();
47     return(true);
48 }
49
50 BOOL ArrayTypeDesc::Verify() {
51
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;
58
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();
63     return(true);
64 }
65
66 #endif
67
68 #endif // #ifndef DACCESS_COMPILE
69
70 TypeHandle TypeDesc::GetBaseTypeParam()
71 {
72     LIMITED_METHOD_DAC_CONTRACT;
73
74     _ASSERTE(HasTypeParam());
75
76     TypeHandle th = dac_cast<PTR_ParamTypeDesc>(this)->GetTypeParam();
77     while (th.HasTypeParam())
78     {
79         th = dac_cast<PTR_ParamTypeDesc>(th.AsTypeDesc())->GetTypeParam();
80     }
81     _ASSERTE(!th.IsNull());
82
83     return th;
84 }
85
86 PTR_Module TypeDesc::GetLoaderModule()
87 {
88     STATIC_CONTRACT_NOTHROW;
89     STATIC_CONTRACT_GC_NOTRIGGER;
90     STATIC_CONTRACT_FORBID_FAULT;
91     SUPPORTS_DAC;
92
93     if (HasTypeParam())
94     {
95         return GetBaseTypeParam().GetLoaderModule();
96     }
97     else if (IsGenericVariable())
98     {
99         return dac_cast<PTR_TypeVarTypeDesc>(this)->GetModule();
100     }
101     else
102     {
103         PTR_Module retVal = NULL;
104         BOOL fFail = FALSE;
105
106         _ASSERTE(GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
107         PTR_FnPtrTypeDesc asFnPtr = dac_cast<PTR_FnPtrTypeDesc>(this);
108         if (!fFail)
109         {
110             retVal = ClassLoader::ComputeLoaderModuleForFunctionPointer(asFnPtr->GetRetAndArgTypesPointer(), asFnPtr->GetNumArgs()+1);
111         }                                              
112         return retVal;
113     }
114 }
115
116
117 PTR_Module TypeDesc::GetZapModule()
118 {
119     WRAPPER_NO_CONTRACT;
120     SUPPORTS_DAC;
121     return ExecutionManager::FindZapModule(dac_cast<TADDR>(this));
122 }
123
124 PTR_BaseDomain TypeDesc::GetDomain()
125 {
126     CONTRACTL
127     {
128         NOTHROW;
129         GC_NOTRIGGER;
130         FORBID_FAULT;
131         SUPPORTS_DAC;
132     }
133     CONTRACTL_END
134
135     return dac_cast<PTR_BaseDomain>(AppDomain::GetCurrentDomain());
136 }
137
138 PTR_Module TypeDesc::GetModule() {
139     CONTRACTL
140     {
141         NOTHROW;
142         GC_NOTRIGGER;
143         FORBID_FAULT;
144         SUPPORTS_DAC;
145         // Function pointer types belong to no module
146         //PRECONDITION(GetInternalCorElementType() != ELEMENT_TYPE_FNPTR);
147     }
148     CONTRACTL_END
149
150     // Note here we are making the assumption that a typeDesc lives in
151     // the classloader of its element type.
152
153     if (HasTypeParam())
154     {
155         return GetBaseTypeParam().GetModule();
156     }
157
158     if (IsGenericVariable())
159     {
160         PTR_TypeVarTypeDesc asVar = dac_cast<PTR_TypeVarTypeDesc>(this);
161         return asVar->GetModule();
162     }
163
164     _ASSERTE(GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
165
166     return GetLoaderModule();
167 }
168
169 BOOL ParamTypeDesc::OwnsTemplateMethodTable()
170 {
171     CONTRACTL
172     {
173         NOTHROW;
174         GC_NOTRIGGER;
175     }
176     CONTRACTL_END;
177
178     CorElementType kind = GetInternalCorElementType();
179
180     // The m_TemplateMT for pointer types is UIntPtr
181     if (!CorTypeInfo::IsArray_NoThrow(kind))
182     {
183         return FALSE;
184     }
185
186     CorElementType elemType = m_Arg.GetSignatureCorElementType();
187
188     // This check matches precisely one in Module::CreateArrayMethodTable
189     //
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[])
193
194     if (CorTypeInfo::IsGenericVariable_NoThrow(elemType))
195     {
196         return FALSE;
197     }
198
199     return TRUE;
200 }
201
202 Assembly* TypeDesc::GetAssembly() {
203     STATIC_CONTRACT_NOTHROW;
204     STATIC_CONTRACT_GC_NOTRIGGER;
205     STATIC_CONTRACT_FORBID_FAULT;
206
207     Module *pModule = GetModule();
208     PREFIX_ASSUME(pModule!=NULL);
209     return pModule->GetAssembly();
210 }
211
212 void TypeDesc::GetName(SString &ssBuf)
213 {
214     CONTRACTL
215     {
216         THROWS;
217         GC_NOTRIGGER;
218         INJECT_FAULT(COMPlusThrowOM(););
219     }
220     CONTRACTL_END
221
222     CorElementType kind = GetInternalCorElementType();
223     TypeHandle th;
224     int rank;
225
226     if (CorTypeInfo::IsModifier(kind))
227         th = GetTypeParam();
228     else
229         th = TypeHandle(this);
230
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();
235     else
236         rank = 0;
237
238     ConstructName(kind, th, rank, ssBuf);
239 }
240
241 void TypeDesc::ConstructName(CorElementType kind,
242                              TypeHandle param,
243                              int rank,
244                              SString &ssBuff)
245 {
246     CONTRACTL
247     {
248         THROWS;
249         GC_NOTRIGGER;
250         INJECT_FAULT(COMPlusThrowOM()); // SString operations can allocate.
251     }
252     CONTRACTL_END
253
254     if (CorTypeInfo::IsModifier(kind))
255     {
256         param.GetName(ssBuff);
257     }
258
259     switch(kind)
260     {
261     case ELEMENT_TYPE_BYREF:
262         ssBuff.Append(W('&'));
263         break;
264
265     case ELEMENT_TYPE_PTR:
266         ssBuff.Append(W('*'));
267         break;
268
269     case ELEMENT_TYPE_SZARRAY:
270         ssBuff.Append(W("[]"));
271         break;
272
273     case ELEMENT_TYPE_ARRAY:
274         ssBuff.Append(W('['));
275
276         if (rank == 1)
277         {
278             ssBuff.Append(W('*'));
279         }
280         else
281         {
282             while(--rank > 0)
283             {
284                 ssBuff.Append(W(','));
285             }
286         }
287
288         ssBuff.Append(W(']'));
289         break;
290
291     case ELEMENT_TYPE_VAR:
292     case ELEMENT_TYPE_MVAR:
293         if (kind == ELEMENT_TYPE_VAR)
294         {
295             ssBuff.Printf(W("!%d"), rank);
296         }
297         else
298         {
299             ssBuff.Printf(W("!!%d"), rank);
300         }
301         break;
302
303     case ELEMENT_TYPE_FNPTR:
304         ssBuff.Printf(W("FNPTR"));
305         break;
306
307     default:
308         LPCUTF8 namesp = CorTypeInfo::GetNamespace(kind);
309         if(namesp && *namesp) {
310             ssBuff.AppendUTF8(namesp);
311             ssBuff.Append(W('.'));
312         }
313
314         LPCUTF8 name = CorTypeInfo::GetName(kind);
315         BAD_FORMAT_NOTHROW_ASSERT(name);
316         if (name && *name) {
317             ssBuff.AppendUTF8(name);
318         }
319     }
320 }
321
322 BOOL TypeDesc::IsArray()
323 {
324     LIMITED_METHOD_DAC_CONTRACT;
325     return CorTypeInfo::IsArray_NoThrow(GetInternalCorElementType());
326 }
327
328 BOOL TypeDesc::IsGenericVariable()
329 {
330     LIMITED_METHOD_DAC_CONTRACT;
331     return CorTypeInfo::IsGenericVariable_NoThrow(GetInternalCorElementType());
332 }
333
334 BOOL TypeDesc::IsFnPtr()
335 {
336     LIMITED_METHOD_DAC_CONTRACT;
337     return (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR);
338 }
339
340 BOOL TypeDesc::IsNativeValueType()
341 {
342     WRAPPER_NO_CONTRACT;
343     return (GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE);
344 }
345
346 BOOL TypeDesc::HasTypeParam()
347 {
348     WRAPPER_NO_CONTRACT;
349     SUPPORTS_DAC;
350     return CorTypeInfo::IsModifier_NoThrow(GetInternalCorElementType()) ||
351            GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE;
352 }
353
354 #ifndef DACCESS_COMPILE
355
356 BOOL TypeDesc::CanCastTo(TypeHandle toType, TypeHandlePairList *pVisited)
357 {
358     CONTRACTL
359     {
360         THROWS;
361         GC_TRIGGERS;
362         INJECT_FAULT(COMPlusThrowOM());
363     }
364     CONTRACTL_END
365
366     if (TypeHandle(this) == toType)
367         return TRUE;
368
369     //A boxed variable type can be cast to any of its constraints, or object, if none are specified
370     if (IsGenericVariable())
371     {
372         TypeVarTypeDesc *tyvar = (TypeVarTypeDesc*) this;
373
374         DWORD numConstraints;
375         TypeHandle *constraints = tyvar->GetConstraints(&numConstraints, CLASS_DEPENDENCIES_LOADED);
376
377         if (toType == g_pObjectClass)
378             return TRUE;
379
380         if (toType == g_pValueTypeClass) 
381         {
382             mdGenericParam genericParamToken = tyvar->GetToken();
383             DWORD flags;
384             if (FAILED(tyvar->GetModule()->GetMDImport()->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
385             {
386                 return FALSE;
387             }
388             DWORD specialConstraints = flags & gpSpecialConstraintMask;
389             if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0) 
390                 return TRUE;
391         }
392
393         if (constraints == NULL)
394             return FALSE;
395
396         for (DWORD i = 0; i < numConstraints; i++)
397         {
398             if (constraints[i].CanCastTo(toType, pVisited))
399                 return TRUE;
400         }
401         return FALSE;
402     }
403
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())
407     {
408         if (!IsArray())
409         {
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.
413             return FALSE;
414         }
415
416         MethodTable *pMT = GetMethodTable();
417         _ASSERTE(pMT != 0);
418
419         // This does the right thing if 'type' == System.Array or System.Object, System.Clonable ...
420         if (pMT->CanCastToClassOrInterface(toType.AsMethodTable(), pVisited) != 0)
421         {
422             return TRUE;
423         }
424
425         if (IsArray() && toType.AsMethodTable()->IsInterface())
426         {
427             if (ArraySupportsBizarreInterface((ArrayTypeDesc*)this, toType.AsMethodTable()))
428             {
429                 return TRUE;
430             }
431
432         }
433
434         return FALSE;
435     }
436
437     TypeDesc* toTypeDesc = toType.AsTypeDesc();
438
439     CorElementType toKind = toTypeDesc->GetInternalCorElementType();
440     CorElementType fromKind = GetInternalCorElementType();
441
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)))
444         return FALSE;
445
446     switch (toKind)
447     {
448     case ELEMENT_TYPE_ARRAY:
449         if (dac_cast<PTR_ArrayTypeDesc>(this)->GetRank() != dac_cast<PTR_ArrayTypeDesc>(toTypeDesc)->GetRank())
450             return FALSE;
451         // fall through
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);
456
457     case ELEMENT_TYPE_VAR:
458     case ELEMENT_TYPE_MVAR:
459     case ELEMENT_TYPE_FNPTR:
460         return FALSE;
461
462     default:
463         BAD_FORMAT_NOTHROW_ASSERT(toKind == ELEMENT_TYPE_TYPEDBYREF || CorTypeInfo::IsPrimitiveType(toKind));
464         return TRUE;
465     }
466 }
467
468 BOOL TypeDesc::CanCastParam(TypeHandle fromParam, TypeHandle toParam, TypeHandlePairList *pVisited)
469 {
470     CONTRACTL
471     {
472         THROWS;
473         GC_TRIGGERS;
474         INJECT_FAULT(COMPlusThrowOM());
475     }
476     CONTRACTL_END
477
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))
483         return TRUE;
484
485         // Object parameters dont need an exact match but only inheritance, check for that
486     CorElementType fromParamCorType = fromParam.GetVerifierCorElementType();
487     if (CorTypeInfo::IsObjRef(fromParamCorType))
488     {
489         return fromParam.CanCastTo(toParam, pVisited);
490     }
491     else if (CorTypeInfo::IsGenericVariable(fromParamCorType))
492     {
493         TypeVarTypeDesc* varFromParam = fromParam.AsGenericVariable();
494             
495         if (!varFromParam->ConstraintsLoaded())
496             varFromParam->LoadConstraints(CLASS_DEPENDENCIES_LOADED);
497
498         if (!varFromParam->ConstrainedAsObjRef())
499             return FALSE;
500             
501         return fromParam.CanCastTo(toParam, pVisited);
502     }
503     else if(CorTypeInfo::IsPrimitiveType(fromParamCorType))
504     {
505         CorElementType toParamCorType = toParam.GetVerifierCorElementType();
506         if(CorTypeInfo::IsPrimitiveType(toParamCorType))
507         {
508             if (GetNormalizedIntegralArrayElementType(toParamCorType) == GetNormalizedIntegralArrayElementType(fromParamCorType))
509                 return TRUE;
510         } // end if(CorTypeInfo::IsPrimitiveType(toParamCorType))
511     } // end if(CorTypeInfo::IsPrimitiveType(fromParamCorType)) 
512
513         // Anything else is not a match.
514     return FALSE;
515 }
516
517 TypeHandle::CastResult TypeDesc::CanCastToNoGC(TypeHandle toType)
518 {
519     CONTRACTL
520     {
521         NOTHROW;
522         GC_NOTRIGGER;
523         FORBID_FAULT;
524     }
525     CONTRACTL_END
526
527     if (TypeHandle(this) == toType)
528         return TypeHandle::CanCast;
529
530     //A boxed variable type can be cast to any of its constraints, or object, if none are specified
531     if (IsGenericVariable())
532     {
533         TypeVarTypeDesc *tyvar = (TypeVarTypeDesc*) this;
534
535         if (!tyvar->ConstraintsLoaded())
536             return TypeHandle::MaybeCast;
537
538         DWORD numConstraints;
539         TypeHandle *constraints = tyvar->GetCachedConstraints(&numConstraints);
540
541         if (toType == g_pObjectClass)
542             return TypeHandle::CanCast;
543
544         if (toType == g_pValueTypeClass)
545             return TypeHandle::MaybeCast;
546
547         if (constraints == NULL)
548             return TypeHandle::CannotCast;
549
550         for (DWORD i = 0; i < numConstraints; i++)
551         {
552             if (constraints[i].CanCastToNoGC(toType) == TypeHandle::CanCast)
553                 return TypeHandle::CanCast;
554         }
555         return TypeHandle::MaybeCast;
556     }
557
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())
561     {
562         if (!IsArray())
563         {
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;
568         }
569
570         MethodTable *pMT = GetMethodTable();
571         _ASSERTE(pMT != 0);
572
573         // This does the right thing if 'type' == System.Array or System.Object, System.Clonable ...
574         return pMT->CanCastToClassOrInterfaceNoGC(toType.AsMethodTable());
575     }
576
577     TypeDesc* toTypeDesc = toType.AsTypeDesc();
578
579     CorElementType toKind = toTypeDesc->GetInternalCorElementType();
580     CorElementType fromKind = GetInternalCorElementType();
581
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;
585
586     switch (toKind)
587     {
588     case ELEMENT_TYPE_ARRAY:
589         if (dac_cast<PTR_ArrayTypeDesc>(this)->GetRank() != dac_cast<PTR_ArrayTypeDesc>(toTypeDesc)->GetRank())
590             return TypeHandle::CannotCast;
591         // fall through
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());
596
597     case ELEMENT_TYPE_VAR:
598     case ELEMENT_TYPE_MVAR:
599     case ELEMENT_TYPE_FNPTR:
600         return TypeHandle::CannotCast;
601
602     default:
603         BAD_FORMAT_NOTHROW_ASSERT(toKind == ELEMENT_TYPE_TYPEDBYREF || CorTypeInfo::IsPrimitiveType_NoThrow(toKind));
604         return TypeHandle::CanCast;
605     }
606 }
607
608 TypeHandle::CastResult TypeDesc::CanCastParamNoGC(TypeHandle fromParam, TypeHandle toParam)
609 {
610     CONTRACTL
611     {
612         NOTHROW;
613         GC_NOTRIGGER;
614         FORBID_FAULT;
615     }
616     CONTRACTL_END
617
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;
624
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))
628     {
629         return fromParam.CanCastToNoGC(toParam);
630     }
631     else if (CorTypeInfo::IsGenericVariable_NoThrow(fromParamCorType))
632     {
633         TypeVarTypeDesc* varFromParam = fromParam.AsGenericVariable();
634             
635         if (!varFromParam->ConstraintsLoaded())
636             return TypeHandle::MaybeCast;
637
638         if (!varFromParam->ConstrainedAsObjRef())
639             return TypeHandle::CannotCast;
640             
641         return fromParam.CanCastToNoGC(toParam);
642     }
643     else if (CorTypeInfo::IsPrimitiveType_NoThrow(fromParamCorType))
644     {
645         CorElementType toParamCorType = toParam.GetVerifierCorElementType();
646         if(CorTypeInfo::IsPrimitiveType_NoThrow(toParamCorType))
647         {
648             if (toParamCorType == fromParamCorType)
649                 return TypeHandle::CanCast;
650
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))
658             {
659                 if ((CorTypeInfo::Size_NoThrow(toParamCorType) == CorTypeInfo::Size_NoThrow(fromParamCorType))
660                     && (CorTypeInfo::IsFloat_NoThrow(toParamCorType) == CorTypeInfo::IsFloat_NoThrow(fromParamCorType)))
661                 {
662                     return TypeHandle::CanCast;
663                 }
664             }
665         } // end if(CorTypeInfo::IsPrimitiveType(toParamCorType))
666     } // end if(CorTypeInfo::IsPrimitiveType(fromParamCorType)) 
667     else
668     {
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;
676     }
677
678     // Anything else is not a match.
679     return TypeHandle::CannotCast;
680 }
681
682 BOOL TypeDesc::IsEquivalentTo(TypeHandle type COMMA_INDEBUG(TypeHandlePairList *pVisited))
683 {
684     CONTRACTL
685     {
686         THROWS;
687         GC_TRIGGERS;
688         MODE_ANY;
689     }
690     CONTRACTL_END;
691
692     if (TypeHandle(this) == type)
693         return TRUE;
694
695     if (!type.IsTypeDesc())
696         return FALSE;
697
698     TypeDesc *pOther = type.AsTypeDesc();
699
700     // bail early for normal types
701     if (!HasTypeEquivalence() || !pOther->HasTypeEquivalence())
702         return FALSE;
703
704     // if the TypeDesc types are different, then they are not equivalent
705     if (GetInternalCorElementType() != pOther->GetInternalCorElementType())
706         return FALSE;
707         
708     if (HasTypeParam())
709     {
710         // pointer, byref, array
711
712         // Arrays must have the same rank.
713         if (IsArray())
714         {
715             ArrayTypeDesc *pThisArray = (ArrayTypeDesc *)this;
716             ArrayTypeDesc *pOtherArray = (ArrayTypeDesc *)pOther;
717             if (pThisArray->GetRank() != pOtherArray->GetRank())
718                 return FALSE;
719         }
720
721         return GetTypeParam().IsEquivalentTo(pOther->GetTypeParam() COMMA_INDEBUG(pVisited));
722     }
723
724     // var, mvar, fnptr
725     return FALSE;
726 }
727 #endif // #ifndef DACCESS_COMPILE
728
729
730
731 TypeHandle TypeDesc::GetParent() {
732
733     STATIC_CONTRACT_NOTHROW;
734     STATIC_CONTRACT_GC_NOTRIGGER;
735     STATIC_CONTRACT_FORBID_FAULT;
736
737     CorElementType kind = GetInternalCorElementType();
738     if (CorTypeInfo::IsArray_NoThrow(kind)) {
739         _ASSERTE(IsArray());
740         BAD_FORMAT_NOTHROW_ASSERT(kind == ELEMENT_TYPE_SZARRAY || kind == ELEMENT_TYPE_ARRAY);
741         return ((ArrayTypeDesc*)this)->GetParent();
742     }
743     if (CorTypeInfo::IsPrimitiveType_NoThrow(kind))
744         return (MethodTable*)g_pObjectClass;
745     return TypeHandle();
746 }
747
748 #ifndef DACCESS_COMPILE
749
750 #ifndef CROSSGEN_COMPILE
751 OBJECTREF ParamTypeDesc::GetManagedClassObject()
752 {
753     CONTRACTL {
754         THROWS;
755         GC_TRIGGERS;
756         MODE_COOPERATIVE;
757
758         INJECT_FAULT(COMPlusThrowOM());
759
760         PRECONDITION(GetInternalCorElementType() == ELEMENT_TYPE_ARRAY ||
761                      GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY ||
762                      GetInternalCorElementType() == ELEMENT_TYPE_BYREF ||
763                      GetInternalCorElementType() == ELEMENT_TYPE_PTR);
764     }
765     CONTRACTL_END;
766
767     if (m_hExposedClassObject == NULL) {
768         REFLECTCLASSBASEREF  refClass = NULL;
769         GCPROTECT_BEGIN(refClass);
770         refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass);
771
772         LoaderAllocator *pLoaderAllocator = GetLoaderAllocator();
773         TypeHandle th = TypeHandle(this);
774         ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th);
775         ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject());
776
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);
780
781         EnsureWritablePages(this);
782         if (FastInterlockCompareExchangePointer(&m_hExposedClassObject, hExposedClassObject, static_cast<LOADERHANDLE>(NULL)))
783         {
784             pLoaderAllocator->FreeHandle(hExposedClassObject);
785         }
786
787         if (OwnsTemplateMethodTable())
788         {
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;
791         }
792
793         // Log the TypeVarTypeDesc access
794         g_IBCLogger.LogTypeMethodTableWriteableAccess(&th);
795
796         GCPROTECT_END();
797     }
798     return GetManagedClassObjectIfExists();
799 }
800 #endif // CROSSGEN_COMPILE
801
802 #endif // #ifndef DACCESS_COMPILE
803
804 BOOL TypeDesc::IsRestored()
805 {
806     STATIC_CONTRACT_NOTHROW;
807     STATIC_CONTRACT_GC_NOTRIGGER;
808     STATIC_CONTRACT_FORBID_FAULT;
809     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
810     SUPPORTS_DAC;
811
812     TypeHandle th = TypeHandle(this);
813     g_IBCLogger.LogTypeMethodTableAccess(&th);
814     return IsRestored_NoLogging();
815 }
816
817 BOOL TypeDesc::IsRestored_NoLogging()
818 {
819     STATIC_CONTRACT_NOTHROW;
820     STATIC_CONTRACT_GC_NOTRIGGER;
821     STATIC_CONTRACT_FORBID_FAULT;
822     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
823     SUPPORTS_DAC;
824
825     return (m_typeAndFlags & TypeDesc::enum_flag_Unrestored) == 0;
826 }
827
828 ClassLoadLevel TypeDesc::GetLoadLevel()
829 {
830     STATIC_CONTRACT_NOTHROW;
831     STATIC_CONTRACT_GC_NOTRIGGER;
832     STATIC_CONTRACT_FORBID_FAULT;
833     SUPPORTS_DAC;
834
835     if (m_typeAndFlags & TypeDesc::enum_flag_UnrestoredTypeKey)
836     {
837         return CLASS_LOAD_UNRESTOREDTYPEKEY;
838     }
839     else if (m_typeAndFlags & TypeDesc::enum_flag_Unrestored)
840     {
841         return CLASS_LOAD_UNRESTORED;
842     }
843     else if (m_typeAndFlags & TypeDesc::enum_flag_IsNotFullyLoaded)
844     {
845         if (m_typeAndFlags & TypeDesc::enum_flag_DependenciesLoaded)
846         {
847             return CLASS_DEPENDENCIES_LOADED;
848         }
849         else
850         {
851             return CLASS_LOAD_EXACTPARENTS;
852         }
853     }
854
855     return CLASS_LOADED;
856 }
857
858
859 // Recursive worker that pumps the transitive closure of a type's dependencies to the specified target level.
860 // Dependencies include:
861 //
862 //   - parent
863 //   - interfaces
864 //   - canonical type, for non-canonical instantiations
865 //   - typical type, for non-typical instantiations
866 //
867 // Parameters:
868 //
869 //   pVisited - used to prevent endless recursion in the case of cyclic dependencies
870 //
871 //   level    - target level to pump to - must be CLASS_DEPENDENCIES_LOADED or CLASS_LOADED
872 //
873 //              if CLASS_DEPENDENCIES_LOADED, all transitive dependencies are resolved to their
874 //                 exact types.
875 //
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.
880 //
881 //
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.)
885 //
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.
892 //              
893 //  pInstContext - instantiation context created in code:SigPointer.GetTypeHandleThrowing and ultimately
894 //                 passed down to code:TypeVarTypeDesc.SatisfiesConstraints.
895 //
896 void TypeDesc::DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level,
897                            DFLPendingList *pPending, BOOL *pfBailed, const InstantiationContext *pInstContext)
898 {
899     CONTRACTL
900     {
901         THROWS;
902         GC_TRIGGERS;
903     }
904     CONTRACTL_END
905
906     _ASSERTE(level == CLASS_LOADED || level == CLASS_DEPENDENCIES_LOADED);
907     _ASSERTE(pfBailed != NULL);
908     _ASSERTE(!(level == CLASS_LOADED && pPending == NULL));
909
910
911 #ifndef DACCESS_COMPILE
912
913     if (Generics::RecursionGraph::HasSeenType(pVisited, TypeHandle(this)))
914     {
915         *pfBailed = TRUE;
916         return;
917     }
918
919     if (GetLoadLevel() >= level)
920     {
921         return;
922     }
923
924     if (level == CLASS_LOADED)
925     {
926         UINT numTH = pPending->Count();
927         TypeHandle *pTypeHndPending = pPending->Table();
928         for (UINT idxPending = 0; idxPending < numTH; idxPending++)
929         {
930             if (pTypeHndPending[idxPending].IsTypeDesc() && pTypeHndPending[idxPending].AsTypeDesc() == this)
931             {
932                 *pfBailed = TRUE;
933                 return;
934             }
935         }
936
937     }
938
939
940     BOOL fBailed = FALSE;
941
942     // First ensure that we're loaded to just below CLASS_LOADED
943     ClassLoader::EnsureLoaded(TypeHandle(this), (ClassLoadLevel) (level-1));
944     
945     Generics::RecursionGraph newVisited(pVisited, TypeHandle(this));
946
947     if (HasTypeParam())
948     {
949         // Fully load the type parameter
950         GetTypeParam().DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext);
951
952         ParamTypeDesc* pPTD = (ParamTypeDesc*) this;
953
954         // Fully load the template method table
955         if (!pPTD->m_TemplateMT.IsNull())
956         {
957             pPTD->GetTemplateMethodTableInternal()->DoFullyLoad(&newVisited, level, pPending, &fBailed, pInstContext);
958         }
959     }
960
961     switch (level)
962     {
963         case CLASS_DEPENDENCIES_LOADED:
964             FastInterlockOr(&m_typeAndFlags, TypeDesc::enum_flag_DependenciesLoaded);
965             break;
966
967         case CLASS_LOADED:
968             if (fBailed)
969             {
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.
973
974                 *pfBailed = TRUE;
975
976                 TypeHandle* pthPending = pPending->AppendThrowing();
977                 *pthPending = TypeHandle(this);
978             }
979             else
980             {
981                 // Finally, mark this method table as fully loaded
982                 SetIsFullyLoaded();
983             }
984             break;
985
986         default:
987             _ASSERTE(!"Can't get here.");
988             break;
989     }
990 #endif
991 }
992
993
994 #ifdef FEATURE_PREJIT
995 void TypeDesc::DoRestoreTypeKey()
996 {
997     CONTRACTL
998     {
999         THROWS;
1000         GC_TRIGGERS;
1001     }
1002     CONTRACTL_END
1003
1004 #ifndef DACCESS_COMPILE
1005     if (HasTypeParam())
1006     {
1007         ParamTypeDesc* pPTD = (ParamTypeDesc*) this;
1008         EnsureWritablePages(pPTD);
1009
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);
1013
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);
1016     }
1017     else
1018     {
1019         EnsureWritablePages(this);
1020     }
1021
1022     FastInterlockAnd(&m_typeAndFlags, ~TypeDesc::enum_flag_UnrestoredTypeKey);
1023 #endif
1024 }
1025
1026 #ifndef DACCESS_COMPILE
1027
1028 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
1029 // This just performs a shallow save
1030 void TypeDesc::Save(DataImage *image)
1031 {
1032     STANDARD_VM_CONTRACT;
1033
1034     ClassLoader::EnsureLoaded(TypeHandle(this));
1035
1036     if (LoggingOn(LF_ZAP, LL_INFO10000))
1037     {
1038         StackSString name;
1039         TypeString::AppendType(name, TypeHandle(this));
1040         LOG((LF_ZAP, LL_INFO10000, "TypeDesc::Save %S\n", name.GetUnicode()));
1041     }
1042
1043     if (IsGenericVariable())
1044     {
1045         ((TypeVarTypeDesc*)this)->Save(image);
1046     }
1047     else if (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR)
1048     {
1049         ((FnPtrTypeDesc *)this)->Save(image);
1050     }
1051     else
1052     {
1053         _ASSERTE(HasTypeParam());
1054         ((ParamTypeDesc*)this)->Save(image);
1055     }
1056
1057 }
1058
1059 void TypeDesc::Fixup(DataImage *image)
1060 {
1061     STANDARD_VM_CONTRACT;
1062
1063     if (IsGenericVariable())
1064     {
1065         TypeVarTypeDesc* tyvar = (TypeVarTypeDesc*) this;
1066         tyvar->Fixup(image);
1067     }
1068     else if (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR)
1069     {
1070         ((FnPtrTypeDesc*)this)->Fixup(image);
1071     }
1072     else
1073     {
1074         // Works for array and PTR/BYREF types, but not function pointers
1075         _ASSERTE(HasTypeParam());
1076         
1077         if (IsArray())
1078         {
1079             ((ArrayTypeDesc*) this)->Fixup(image);
1080         }
1081         else
1082         {
1083             ((ParamTypeDesc*) this)->Fixup(image);
1084         }
1085     }
1086
1087     if (NeedsRestore(image))
1088     {
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;
1092     }
1093
1094 }
1095
1096 BOOL TypeDesc::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited)
1097 {
1098     STATIC_STANDARD_VM_CONTRACT;
1099
1100     _ASSERTE(GetAppDomain()->IsCompilationDomain());
1101
1102     if (HasTypeParam())
1103     {
1104         return dac_cast<PTR_ParamTypeDesc>(this)->ComputeNeedsRestore(image, pVisited);
1105     }
1106     else
1107         return FALSE;
1108 }
1109
1110
1111
1112 void ParamTypeDesc::Save(DataImage *image)
1113 {
1114     STANDARD_VM_CONTRACT;
1115
1116     if (IsArray())
1117     {
1118         image->StoreStructure(this, sizeof(ArrayTypeDesc), DataImage::ITEM_ARRAY_TYPEDESC);
1119     }
1120     else
1121     {
1122         image->StoreStructure(this, sizeof(ParamTypeDesc), DataImage::ITEM_PARAM_TYPEDESC);
1123     }
1124
1125     // This set of checks matches precisely those in Module::CreateArrayMethodTable
1126     // and ParamTypeDesc::ComputeNeedsRestore
1127     //
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[])
1131     //
1132     if (OwnsTemplateMethodTable())
1133     {
1134         // This TypeDesc should be the only one saving this MT
1135         _ASSERTE(!image->IsStored(GetTemplateMethodTableInternal()));
1136         Module::SaveMethodTable(image, GetTemplateMethodTableInternal(), 0);
1137     }
1138
1139 }
1140
1141
1142 void ParamTypeDesc::Fixup(DataImage *image)
1143 {
1144     STANDARD_VM_CONTRACT;
1145
1146     _ASSERTE(image->GetModule()->GetAssembly() ==
1147              GetAppDomain()->ToCompilationDomain()->GetTargetAssembly());
1148
1149     if (LoggingOn(LF_ZAP, LL_INFO10000))
1150     {
1151         StackSString name;
1152         TypeString::AppendType(name, TypeHandle(this));
1153         LOG((LF_ZAP, LL_INFO10000, "ParamTypeDesc::Fixup %S\n", name.GetUnicode()));
1154     }
1155
1156     if (!m_TemplateMT.IsNull())
1157     {
1158         if (OwnsTemplateMethodTable())
1159         {
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);
1167         }
1168         else
1169         {
1170             // Fixup the pointer to the possibly-shared m_TemplateMT. This might be in a different module.
1171             image->FixupMethodTablePointer(this, &m_TemplateMT);
1172         }
1173     }
1174
1175     // Fixup the pointer to the element type.
1176     image->HardBindTypeHandlePointer(this, offsetof(ParamTypeDesc, m_Arg));
1177
1178     // The managed object will get regenerated on demand
1179     image->ZeroField(this, offsetof(ParamTypeDesc, m_hExposedClassObject), sizeof(m_hExposedClassObject));
1180 }
1181
1182 void ArrayTypeDesc::Fixup(DataImage *image)
1183 {
1184     STANDARD_VM_CONTRACT;
1185
1186     ParamTypeDesc::Fixup(image);
1187
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
1192 }
1193
1194 BOOL ParamTypeDesc::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited)
1195 {
1196     STATIC_STANDARD_VM_CONTRACT;
1197
1198     _ASSERTE(GetAppDomain()->IsCompilationDomain());
1199
1200     if (m_typeAndFlags & TypeDesc::enum_flag_NeedsRestore)
1201     {
1202         return TRUE;
1203     }
1204     if (m_typeAndFlags & TypeDesc::enum_flag_PreRestored)
1205     {
1206         return FALSE;
1207     }
1208
1209     BOOL res = FALSE;
1210     if (!image->CanPrerestoreEagerBindToTypeHandle(m_Arg, pVisited))
1211     {
1212         res = TRUE;
1213     }
1214
1215     // This set of checks matches precisely those in Module::CreateArrayMethodTable and ParamTypeDesc::Fixup
1216     //
1217     if (!m_TemplateMT.IsNull())
1218     { 
1219         if (OwnsTemplateMethodTable())
1220         {
1221             if (GetTemplateMethodTableInternal()->ComputeNeedsRestore(image, pVisited))
1222             {
1223                 res = TRUE;
1224             }
1225         }
1226         else
1227         {
1228             if (!image->CanPrerestoreEagerBindToMethodTable(GetTemplateMethodTableInternal(), pVisited))
1229             {
1230                 res = TRUE;
1231             }
1232         }
1233     }
1234
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)
1239     {
1240         if (LoggingOn(LF_ZAP, LL_INFO10000))
1241         {
1242             StackSString name;
1243             TypeString::AppendType(name, TypeHandle(this));
1244             LOG((LF_ZAP, LL_INFO10000, "ParamTypeDesc::ComputeNeedsRestore=%d for %S\n", res, name.GetUnicode()));
1245         }
1246         m_typeAndFlags |= (res ? TypeDesc::enum_flag_NeedsRestore : TypeDesc::enum_flag_PreRestored);
1247     }
1248     return res;
1249 }
1250 #endif // FEATURE_NATIVE_IMAGE_GENERATION
1251
1252 void TypeDesc::SetIsRestored()
1253 {
1254     STATIC_CONTRACT_THROWS;
1255     STATIC_CONTRACT_GC_NOTRIGGER;
1256     STATIC_CONTRACT_FORBID_FAULT;
1257     STATIC_CONTRACT_CANNOT_TAKE_LOCK;
1258
1259     TypeHandle th = TypeHandle(this);
1260     FastInterlockAnd(EnsureWritablePages(&m_typeAndFlags), ~TypeDesc::enum_flag_Unrestored);
1261 }
1262
1263 #endif // #ifndef DACCESS_COMPILE
1264
1265 void TypeDesc::Restore()
1266 {
1267     CONTRACTL
1268     {
1269         THROWS;
1270         GC_TRIGGERS;
1271         INJECT_FAULT(COMPlusThrowOM(););
1272         CONSISTENCY_CHECK(!HasUnrestoredTypeKey());
1273     }
1274     CONTRACTL_END;
1275
1276 #ifndef DACCESS_COMPILE
1277     if (HasTypeParam())
1278     {
1279         ParamTypeDesc *pPTD = dac_cast<PTR_ParamTypeDesc>(this);
1280
1281         OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOAD_EXACTPARENTS);
1282
1283         // Must have the same loader module
1284         ClassLoader::EnsureLoaded(pPTD->m_Arg, CLASS_LOAD_EXACTPARENTS);
1285
1286         // Method-table pointer must have been restored by DoRestoreTypeKey
1287         Module::RestoreMethodTablePointer(&pPTD->m_TemplateMT, NULL, CLASS_LOAD_EXACTPARENTS);
1288     }
1289
1290     SetIsRestored();
1291 #else
1292     DacNotImpl();
1293 #endif // #ifndef DACCESS_COMPILE
1294 }
1295
1296 #endif // FEATURE_PREJIT
1297
1298
1299 #ifndef DACCESS_COMPILE
1300
1301 #ifdef FEATURE_NATIVE_IMAGE_GENERATION
1302 void TypeVarTypeDesc::Save(DataImage *image)
1303 {
1304     STANDARD_VM_CONTRACT;
1305
1306     // We don't persist the constraints: instead, load them back on demand
1307     m_numConstraints = (DWORD) -1;
1308
1309     LOG((LF_ZAP, LL_INFO10000, "  TypeVarTypeDesc::Save %x (%p)\n", GetToken(), this));
1310     image->StoreStructure(this, sizeof(TypeVarTypeDesc),
1311                                     DataImage::ITEM_TYVAR_TYPEDESC);
1312 }
1313
1314 void TypeVarTypeDesc::Fixup(DataImage *image)
1315 {
1316     STANDARD_VM_CONTRACT;
1317
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));
1321
1322     // We don't persist the constraints: instead, load them back on demand
1323     image->ZeroPointerField(this, offsetof(TypeVarTypeDesc, m_constraints));
1324
1325 }
1326 #endif // FEATURE_NATIVE_IMAGE_GENERATION
1327
1328 MethodDesc * TypeVarTypeDesc::LoadOwnerMethod()
1329 {
1330     CONTRACTL
1331     {
1332         THROWS;
1333         GC_TRIGGERS;
1334         MODE_ANY;
1335
1336         PRECONDITION(TypeFromToken(m_typeOrMethodDef) == mdtMethodDef);
1337     }
1338     CONTRACTL_END;
1339
1340     MethodDesc *pMD = GetModule()->LookupMethodDef(m_typeOrMethodDef);
1341     if (pMD == NULL)
1342     {
1343         pMD = MemberLoader::GetMethodDescFromMethodDef(GetModule(), m_typeOrMethodDef, FALSE);
1344     }
1345     return pMD;
1346 }
1347
1348 TypeHandle TypeVarTypeDesc::LoadOwnerType()
1349 {
1350     CONTRACTL
1351     {
1352         THROWS;
1353         GC_TRIGGERS;
1354         MODE_ANY;
1355
1356         PRECONDITION(TypeFromToken(m_typeOrMethodDef) == mdtTypeDef);
1357     }
1358     CONTRACTL_END;
1359
1360     TypeHandle genericType = GetModule()->LookupTypeDef(m_typeOrMethodDef);
1361     if (genericType.IsNull())
1362     {
1363         genericType = ClassLoader::LoadTypeDefThrowing(GetModule(), m_typeOrMethodDef,
1364             ClassLoader::ThrowIfNotFound,
1365             ClassLoader::PermitUninstDefOrRef);
1366     }
1367     return genericType;
1368 }
1369
1370 TypeHandle* TypeVarTypeDesc::GetCachedConstraints(DWORD *pNumConstraints)
1371 {
1372     LIMITED_METHOD_CONTRACT;
1373     PRECONDITION(CheckPointer(pNumConstraints));
1374     PRECONDITION(m_numConstraints != (DWORD) -1);
1375
1376     *pNumConstraints = m_numConstraints;
1377     return m_constraints;
1378 }
1379
1380
1381
1382
1383 TypeHandle* TypeVarTypeDesc::GetConstraints(DWORD *pNumConstraints, ClassLoadLevel level /* = CLASS_LOADED */)
1384 {
1385     WRAPPER_NO_CONTRACT;
1386     PRECONDITION(CheckPointer(pNumConstraints));
1387     PRECONDITION(level == CLASS_DEPENDENCIES_LOADED || level == CLASS_LOADED);
1388
1389     if (m_numConstraints == (DWORD) -1)
1390         LoadConstraints(level);
1391
1392     *pNumConstraints = m_numConstraints;
1393     return m_constraints;
1394 }
1395
1396
1397 void TypeVarTypeDesc::LoadConstraints(ClassLoadLevel level /* = CLASS_LOADED */)
1398 {
1399     CONTRACTL
1400     {
1401         THROWS;
1402         GC_TRIGGERS;
1403         MODE_ANY;
1404
1405         INJECT_FAULT(COMPlusThrowOM());
1406
1407         PRECONDITION(level == CLASS_DEPENDENCIES_LOADED || level == CLASS_LOADED);
1408     }
1409     CONTRACTL_END;
1410
1411     _ASSERTE(((INT_PTR)&m_constraints) % sizeof(m_constraints) == 0);
1412     _ASSERTE(((INT_PTR)&m_numConstraints) % sizeof(m_numConstraints) == 0);
1413
1414     DWORD numConstraints = m_numConstraints;
1415
1416     if (numConstraints == (DWORD) -1)
1417     {
1418         EnsureWritablePages(this);
1419
1420         IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1421
1422         HENUMInternalHolder hEnum(pInternalImport);
1423         mdGenericParamConstraint tkConstraint;
1424
1425         SigTypeContext typeContext;
1426         mdToken defToken = GetTypeOrMethodDef();
1427
1428         MethodTable *pMT = NULL;
1429         if (TypeFromToken(defToken) == mdtMethodDef)
1430         {
1431             MethodDesc *pMD = LoadOwnerMethod();
1432             _ASSERTE(pMD->IsGenericMethodDefinition());
1433             
1434             SigTypeContext::InitTypeContext(pMD,&typeContext);
1435             
1436             _ASSERTE(!typeContext.m_methodInst.IsEmpty());
1437             pMT = pMD->GetMethodTable();
1438         }
1439         else
1440         {
1441             _ASSERTE(TypeFromToken(defToken) == mdtTypeDef);
1442             TypeHandle genericType = LoadOwnerType();
1443             _ASSERTE(genericType.IsGenericTypeDefinition());
1444
1445             SigTypeContext::InitTypeContext(genericType,&typeContext);
1446         }
1447         
1448         hEnum.EnumInit(mdtGenericParamConstraint, GetToken());
1449         numConstraints = pInternalImport->EnumGetCount(&hEnum);
1450         if (numConstraints != 0)
1451         {
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))));
1456
1457             DWORD i = 0;
1458             while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
1459             {
1460                 _ASSERTE(i <= numConstraints);
1461                 mdToken tkConstraintType, tkParam;
1462                 if (FAILED(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType)))
1463                 {
1464                     GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
1465                 }
1466                 _ASSERTE(tkParam == GetToken());
1467                 TypeHandle thConstraint = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(GetModule(), tkConstraintType, 
1468                                                                                       &typeContext, 
1469                                                                                       ClassLoader::ThrowIfNotFound, 
1470                                                                                       ClassLoader::FailIfUninstDefOrRef,
1471                                                                                       ClassLoader::LoadTypes,
1472                                                                                       level);
1473
1474                 constraints[i++] = thConstraint;
1475
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)
1480                 {
1481                     ULONG cSig;
1482                     PCCOR_SIGNATURE pSig;
1483                     if (FAILED(pInternalImport->GetTypeSpecFromToken(tkConstraintType, &pSig, &cSig)))
1484                     {
1485                         GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_BADFORMAT);
1486                     }
1487                     if (!EEClass::CheckVarianceInSig(pMT->GetNumGenericArgs(),
1488                                                      pMT->GetClass()->GetVarianceInfo(), 
1489                                                      pMT->GetModule(),
1490                                                      SigPointer(pSig, cSig),
1491                                                      gpContravariant))
1492                     {
1493                         GetModule()->GetAssembly()->ThrowTypeLoadException(pInternalImport, pMT->GetCl(), IDS_CLASSLOAD_VARIANCE_IN_CONSTRAINT);
1494                     }
1495                 }
1496             }
1497
1498             if (InterlockedCompareExchangeT(&m_constraints, constraints.operator->(), NULL) == NULL)
1499             {
1500                 constraints.SuppressRelease();
1501             }
1502         }
1503         
1504         m_numConstraints = numConstraints;
1505     }
1506
1507     for (DWORD i = 0; i < numConstraints; i++)
1508     {
1509         ClassLoader::EnsureLoaded(m_constraints[i], level);
1510     }
1511 }
1512
1513 BOOL TypeVarTypeDesc::ConstrainedAsObjRef()
1514 {
1515     CONTRACTL
1516     {
1517         NOTHROW;
1518         GC_NOTRIGGER;
1519         MODE_ANY;
1520         PRECONDITION(ConstraintsLoaded());
1521     }
1522     CONTRACTL_END;
1523     
1524     IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1525     mdGenericParam genericParamToken = GetToken();
1526     DWORD flags;
1527     if (FAILED(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
1528     {
1529         return FALSE;
1530     }
1531     DWORD specialConstraints = flags & gpSpecialConstraintMask;
1532     
1533     if ((specialConstraints & gpReferenceTypeConstraint) != 0)
1534         return TRUE;
1535     
1536     return ConstrainedAsObjRefHelper();
1537 }
1538
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()
1544 {
1545     CONTRACTL
1546     {
1547         NOTHROW;
1548         GC_NOTRIGGER;
1549         MODE_ANY;
1550     }
1551     CONTRACTL_END;
1552
1553     DWORD dwNumConstraints = 0;
1554     TypeHandle* constraints = GetCachedConstraints(&dwNumConstraints);
1555
1556     for (DWORD i = 0; i < dwNumConstraints; i++)
1557     {
1558         TypeHandle constraint = constraints[i];
1559
1560         if (constraint.IsGenericVariable() && constraint.AsGenericVariable()->ConstrainedAsObjRefHelper())
1561             return TRUE;
1562         
1563         if (!constraint.IsInterface() && CorTypeInfo::IsObjRef_NoThrow(constraint.GetInternalCorElementType()))
1564         {
1565             // Object, ValueType, and Enum are ObjRefs but they do not constrain the var to ObjRef!
1566             MethodTable *mt = constraint.GetMethodTable();
1567
1568             if (mt != g_pObjectClass &&
1569                 mt != g_pValueTypeClass &&
1570                 mt != g_pEnumClass)
1571             {
1572                 return TRUE;
1573             }
1574         }
1575     }
1576
1577     return FALSE;
1578 }
1579
1580 BOOL TypeVarTypeDesc::ConstrainedAsValueType()
1581 {
1582     CONTRACTL
1583     {
1584         NOTHROW;
1585         GC_NOTRIGGER;
1586         MODE_ANY;
1587         PRECONDITION(ConstraintsLoaded());
1588     }
1589     CONTRACTL_END;
1590     
1591     IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
1592     mdGenericParam genericParamToken = GetToken();
1593     DWORD flags;
1594     if (FAILED(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL)))
1595     {
1596         return FALSE;
1597     }
1598     DWORD specialConstraints = flags & gpSpecialConstraintMask;
1599
1600     if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
1601         return TRUE;
1602
1603     DWORD dwNumConstraints = 0;
1604     TypeHandle* constraints = GetCachedConstraints(&dwNumConstraints);
1605
1606     for (DWORD i = 0; i < dwNumConstraints; i++)
1607     {
1608         TypeHandle constraint = constraints[i];
1609
1610         if (constraint.IsGenericVariable())
1611         {
1612             if (constraint.AsGenericVariable()->ConstrainedAsValueType())
1613                 return TRUE;
1614         }
1615         else
1616         {
1617             // the following condition will also disqualify interfaces
1618             if (!CorTypeInfo::IsObjRef_NoThrow(constraint.GetInternalCorElementType()))
1619                 return TRUE;
1620         }
1621     }
1622
1623     return FALSE;
1624 }
1625
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 //---------------------------------------------------------------------------------------------------------------------
1631 static
1632 TypeHandle LoadTypeVarConstraint(TypeVarTypeDesc *pTypeVar, mdGenericParamConstraint tkConstraint,
1633                                  const InstantiationContext *pInstContext)
1634 {
1635     CONTRACTL
1636     {
1637         THROWS;
1638         GC_TRIGGERS;
1639         INJECT_FAULT(COMPlusThrowOM());
1640         MODE_ANY;
1641         PRECONDITION(CheckPointer(pTypeVar));
1642     }
1643     CONTRACTL_END;
1644
1645     Module *pTyModule = pTypeVar->GetModule();
1646     IMDInternalImport* pInternalImport = pTyModule->GetMDImport();
1647
1648     mdToken tkConstraintType, tkParam;
1649     IfFailThrow(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType));
1650     _ASSERTE(tkParam == pTypeVar->GetToken());
1651     mdToken tkOwnerToken = pTypeVar->GetTypeOrMethodDef();
1652     
1653     if (TypeFromToken(tkConstraintType) == mdtTypeSpec && pInstContext != NULL)
1654     {
1655         if(pInstContext->m_pSubstChain == NULL)
1656         {
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;
1665
1666             if (TypeFromToken(tkOwnerToken) == mdtMethodDef)
1667             {
1668                 SigTypeContext sigTypeContext;
1669
1670                 MethodDesc *pMD = pTypeVar->LoadOwnerMethod();
1671
1672                 SigTypeContext::InitTypeContext(pMD, &sigTypeContext);
1673                 fContextContainsValidGenericTypeParams = SigTypeContext::IsValidTypeOnlyInstantiationOf(&sigTypeContext, pInstContext->m_pArgContext);
1674             }
1675
1676             if (!fContextContainsValidGenericTypeParams)
1677                 goto LoadConstraintOnOpenType;
1678         }
1679
1680         // obtain the constraint type's signature if it's a typespec
1681         ULONG cbSig;
1682         PCCOR_SIGNATURE ptr;
1683         
1684         IfFailThrow(pInternalImport->GetSigFromToken(tkConstraintType, &cbSig, &ptr));
1685         
1686         SigPointer pSig(ptr, cbSig);
1687         
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);
1693     }
1694     else
1695     {
1696 LoadConstraintOnOpenType:
1697
1698         SigTypeContext sigTypeContext;
1699         
1700         switch (TypeFromToken(tkOwnerToken))
1701         {
1702             case mdtTypeDef:
1703             {
1704                 // the type variable is declared by a type - load the handle of the type
1705                 TypeHandle thOwner = pTyModule->GetClassLoader()->LoadTypeDefThrowing(pTyModule,
1706                                                                                       tkOwnerToken,
1707                                                                                       ClassLoader::ThrowIfNotFound,
1708                                                                                       ClassLoader::PermitUninstDefOrRef,
1709                                                                                       tdNoTypes,
1710                                                                                       CLASS_LOAD_APPROXPARENTS
1711                                                                                      );
1712
1713                 SigTypeContext::InitTypeContext(thOwner, &sigTypeContext);
1714                 break;
1715             }
1716
1717             case mdtMethodDef:
1718             {
1719                 // the type variable is declared by a method - load its method desc
1720                 MethodDesc *pMD = pTyModule->LookupMethodDef(tkOwnerToken);
1721
1722                 SigTypeContext::InitTypeContext(pMD, &sigTypeContext);
1723                 break;
1724             }
1725
1726             default:
1727             {
1728                 COMPlusThrow(kBadImageFormatException);
1729             }
1730         }
1731
1732         // load the (typical instantiation of) constraint type
1733         return ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pTyModule,
1734                                                            tkConstraintType,
1735                                                            &sigTypeContext,
1736                                                            ClassLoader::ThrowIfNotFound, 
1737                                                            ClassLoader::FailIfUninstDefOrRef,
1738                                                            ClassLoader::LoadTypes,
1739                                                            CLASS_DEPENDENCIES_LOADED);
1740     }
1741 }
1742
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.
1747 //
1748 // This routine will return TRUE if it can prove that argument "pTyArg" has a constraint that will satisfy the special constraint.
1749 //
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 //---------------------------------------------------------------------------------------------------------------------
1753 static
1754 BOOL SatisfiesSpecialConstraintRecursive(TypeVarTypeDesc *pTyArg, DWORD specialConstraint, TypeHandleList *pVisitedVars = NULL)
1755 {
1756     CONTRACTL
1757     {
1758         THROWS;
1759         GC_TRIGGERS;
1760         INJECT_FAULT(COMPlusThrowOM());
1761         MODE_ANY;
1762         PRECONDITION(CheckPointer(pTyArg));
1763     }
1764     CONTRACTL_END;
1765
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);
1771
1772     IMDInternalImport* pInternalImport = pTyArg->GetModule()->GetMDImport();
1773
1774     // Get the argument type's own special constraints
1775     DWORD argFlags;
1776     IfFailThrow(pTyArg->GetModule()->GetMDImport()->GetGenericParamProps(pTyArg->GetToken(), NULL, &argFlags, NULL, NULL, NULL));
1777     
1778     DWORD argSpecialConstraints = argFlags & gpSpecialConstraintMask;
1779
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)
1783     {
1784         case gpNotNullableValueTypeConstraint:
1785         {
1786             if ((argSpecialConstraints & gpNotNullableValueTypeConstraint) != 0)
1787             {
1788                 return TRUE;
1789             }
1790             break;
1791         }
1792     
1793         case gpReferenceTypeConstraint:
1794         {
1795             // gpReferenceTypeConstraint is not "inherited" so ignore it if pTyArg is a variable
1796             // constraining the argument rather than the argument itself.
1797
1798             if (pVisitedVars == NULL && (argSpecialConstraints & gpReferenceTypeConstraint) != 0)
1799             {
1800                 return TRUE;
1801             }
1802             break;
1803         }
1804  
1805         case gpDefaultConstructorConstraint:
1806         {
1807             // gpDefaultConstructorConstraint is not "inherited" so ignore it if pTyArg is a variable
1808             // constraining the argument rather than the argument itself.
1809
1810             if ((pVisitedVars == NULL && (argSpecialConstraints & gpDefaultConstructorConstraint) != 0) ||
1811                 (argSpecialConstraints & gpNotNullableValueTypeConstraint) != 0)
1812             {
1813                 return TRUE;
1814             }
1815             break;
1816         }
1817     }
1818
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());
1823
1824     mdGenericParamConstraint tkConstraint;
1825     while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
1826     {
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);
1830
1831         if (thConstraint.IsGenericVariable())
1832         {
1833             // The variable is constrained by another variable, which we need to check recursively. An
1834             // example of why this is necessary follows:
1835             // 
1836             // class A<T> where T : class
1837             // { }
1838             // class B<S, R> : A<S> where S : R where R : EventArgs
1839             // { }
1840             // 
1841             if (!TypeHandleList::Exists(pVisitedVars, thConstraint))
1842             {
1843                 TypeHandleList newVisitedVars(thConstraint, pVisitedVars);
1844                 if (SatisfiesSpecialConstraintRecursive(thConstraint.AsGenericVariable(),
1845                                                         specialConstraint,
1846                                                         &newVisitedVars))
1847                 {
1848                     return TRUE;
1849                 }
1850             }
1851         }
1852         else if (thConstraint.IsInterface())
1853         {
1854             // This is a secondary constraint - this tells us nothing about the eventual instantiation that
1855             // we can use here.
1856         }
1857         else 
1858         {
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.
1861
1862             TypeHandle thAncestorOfType = thConstraint;
1863
1864             if (specialConstraint == gpNotNullableValueTypeConstraint)
1865             {
1866                 if (thAncestorOfType.IsValueType() && !(thAncestorOfType.AsMethodTable()->IsNullable()))
1867                 {
1868                     return TRUE;
1869                 }
1870             }
1871             
1872             if (specialConstraint == gpReferenceTypeConstraint)
1873             {
1874
1875                 if (!thAncestorOfType.IsTypeDesc())
1876                 {
1877                     MethodTable *pAncestorMT = thAncestorOfType.AsMethodTable();
1878
1879                     if ((!(pAncestorMT->IsValueType())) && pAncestorMT != g_pObjectClass && pAncestorMT != g_pValueTypeClass)
1880                     {
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();
1885                         while (pParentMT)
1886                         {
1887                             if (pParentMT == g_pValueTypeClass)
1888                             {
1889                                 fIsValueTypeAnAncestor = TRUE;
1890                                 break;
1891                             }
1892                             pParentMT = pParentMT->GetParentMethodTable();
1893                         }
1894
1895                         if (!fIsValueTypeAnAncestor)
1896                         {
1897                             return TRUE;
1898                         }
1899                     }
1900                 }
1901             }
1902          
1903             if (specialConstraint == gpDefaultConstructorConstraint)
1904             {
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())
1908                 {
1909                     return TRUE;
1910                 }
1911             }
1912             
1913         }
1914     }
1915
1916     // If we got here, we found no evidence that the argument's constraints are strict enough to satisfy the parameter's constraints.
1917     return FALSE;
1918 }
1919
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.
1924 //
1925 // E.g.
1926 // class A<S, T> where S : T, IComparable where T : EventArgs
1927 // {
1928 //     void f<U>(U u) where U : S, IDisposable { }
1929 // }
1930 // This would put 5 types to the U's list: S, T, IDisposable, IComparable, and EventArgs.
1931 //---------------------------------------------------------------------------------------------------------------------
1932 static
1933 void GatherConstraintsRecursive(TypeVarTypeDesc *pTyArg, ArrayList *pArgList, const InstantiationContext *pInstContext,
1934                                 TypeHandleList *pVisitedVars = NULL)
1935 {
1936     CONTRACTL
1937     {
1938         THROWS;
1939         GC_TRIGGERS;
1940         INJECT_FAULT(COMPlusThrowOM());
1941         MODE_ANY;
1942         PRECONDITION(CheckPointer(pTyArg));
1943         PRECONDITION(CheckPointer(pArgList));
1944     }
1945     CONTRACTL_END;
1946
1947     IMDInternalImport* pInternalImport = pTyArg->GetModule()->GetMDImport();
1948
1949     // enumerate constraints of the pTyArg
1950     HENUMInternalHolder hEnum(pInternalImport);
1951     hEnum.EnumInit(mdtGenericParamConstraint, pTyArg->GetToken());
1952
1953     mdGenericParamConstraint tkConstraint;
1954     while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
1955     {
1956         TypeHandle thConstraint = LoadTypeVarConstraint(pTyArg, tkConstraint, pInstContext);
1957
1958         if (thConstraint.IsGenericVariable())
1959         {
1960             // see if it's safe to recursively call ourselves
1961             if (!TypeHandleList::Exists(pVisitedVars, thConstraint))
1962             {
1963                 pArgList->Append(thConstraint.AsPtr());
1964
1965                 TypeHandleList newVisitedVars(thConstraint, pVisitedVars);
1966                 GatherConstraintsRecursive(thConstraint.AsGenericVariable(), pArgList, pInstContext, &newVisitedVars);
1967             }
1968
1969             // Note: circular type parameter constraints will be detected and reported later in
1970             // MethodTable::DoFullyLoad, we just have to avoid SO here.
1971         }
1972         else
1973         {
1974             pArgList->Append(thConstraint.AsPtr());
1975         }
1976     }
1977 }
1978
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
1981 //                                    "where T:X".
1982 //                                    Caution: Do NOT use it to load types or constraints attached to "thArg".
1983 //                                     
1984 // thArg                            = typehandle of the type being substituted for the type parameter.
1985 // 
1986 // pInstContext                     = the instantiation context (type context + substitution chain) to be
1987 //                                    used when loading constraints attached to "thArg".
1988 //
1989 BOOL TypeVarTypeDesc::SatisfiesConstraints(SigTypeContext *pTypeContextOfConstraintDeclarer, TypeHandle thArg,
1990                                            const InstantiationContext *pInstContext/*=NULL*/)
1991 {
1992     CONTRACTL
1993     {
1994         THROWS;
1995         GC_TRIGGERS;
1996         MODE_ANY;
1997
1998         PRECONDITION(!thArg.IsNull());
1999         INJECT_FAULT(COMPlusThrowOM());
2000     }
2001     CONTRACTL_END;
2002
2003     IMDInternalImport* pInternalImport = GetModule()->GetMDImport();
2004     mdGenericParamConstraint tkConstraint;
2005         
2006     INDEBUG(mdToken defToken = GetTypeOrMethodDef());
2007     _ASSERTE(TypeFromToken(defToken) == mdtMethodDef || TypeFromToken(defToken) == mdtTypeDef);
2008
2009     // prepare for the enumeration of this variable's general constraints
2010     mdGenericParam genericParamToken = GetToken();
2011     
2012     HENUMInternalHolder hEnum(pInternalImport);
2013     hEnum.EnumInit(mdtGenericParamConstraint, genericParamToken);
2014
2015     ArrayList argList;
2016
2017     // First check special constraints (must-be-reference-type, must-be-value-type, and must-have-default-constructor)
2018     DWORD flags;
2019     IfFailThrow(pInternalImport->GetGenericParamProps(genericParamToken, NULL, &flags, NULL, NULL, NULL));
2020     
2021     DWORD specialConstraints = flags & gpSpecialConstraintMask;
2022
2023     if (thArg.IsGenericVariable())
2024     {
2025         TypeVarTypeDesc *pTyVar = thArg.AsGenericVariable();
2026
2027         if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
2028         {
2029             if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpNotNullableValueTypeConstraint))
2030             {
2031                 return FALSE;
2032             }
2033         }
2034
2035         if ((specialConstraints & gpReferenceTypeConstraint) != 0)
2036         {
2037             if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpReferenceTypeConstraint))
2038             {
2039                 return FALSE;
2040             }
2041         }
2042
2043         if ((specialConstraints & gpDefaultConstructorConstraint) != 0)
2044         {
2045             if (!SatisfiesSpecialConstraintRecursive(pTyVar, gpDefaultConstructorConstraint))
2046             {
2047                 return FALSE;
2048             }
2049         }
2050
2051         if (hEnum.EnumGetCount() == 0)
2052         {
2053             // return immediately if there are no general constraints to satisfy (fast path)
2054             return TRUE;
2055         }
2056
2057         // Now walk the "constraining chain" of type variables and gather all constraint types.
2058         // 
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.
2063         // 
2064         // Consider:
2065         // 
2066         // class A<T>
2067         // {
2068         //     void f<U>(B<U, T> b) where U : A<T> { }
2069         // }
2070         // class B<S, R> where S : A<R> { }
2071         // 
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.
2075         //  
2076         GatherConstraintsRecursive(pTyVar, &argList, pInstContext);
2077     }
2078     else
2079     {
2080         if ((specialConstraints & gpNotNullableValueTypeConstraint) != 0)
2081         { 
2082             if (!thArg.IsValueType()) 
2083                 return FALSE;
2084             else
2085             {
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())
2089                     return FALSE;
2090             }
2091         }
2092        
2093         if ((specialConstraints & gpReferenceTypeConstraint) != 0)
2094         {
2095             if (thArg.IsValueType())
2096                 return FALSE;
2097         }
2098     
2099         if ((specialConstraints & gpDefaultConstructorConstraint) != 0)
2100         {
2101             if (thArg.IsTypeDesc() || (!thArg.AsMethodTable()->HasExplicitOrImplicitPublicDefaultConstructor()))
2102                 return FALSE;
2103         }
2104     }
2105
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());
2111
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.
2115
2116     // Now check general subtype constraints
2117     while (pInternalImport->EnumNext(&hEnum, &tkConstraint))
2118     {
2119         mdToken tkConstraintType, tkParam;
2120         IfFailThrow(pInternalImport->GetGenericParamConstraintProps(tkConstraint, &tkParam, &tkConstraintType));
2121         
2122         _ASSERTE(tkParam == GetToken());
2123         TypeHandle thConstraint = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(GetModule(), 
2124                                                                               tkConstraintType, 
2125                                                                               pTypeContextOfConstraintDeclarer, 
2126                                                                               ClassLoader::ThrowIfNotFound, 
2127                                                                               ClassLoader::FailIfUninstDefOrRef,
2128                                                                               ClassLoader::LoadTypes,
2129                                                                               CLASS_DEPENDENCIES_LOADED);
2130
2131         // System.Object constraint will be always satisfied - even if argList is empty
2132         if (!thConstraint.IsObjectType())
2133         {
2134             BOOL fCanCast = FALSE;
2135             
2136             // loop over all types that we know the arg will be assignable to
2137             ArrayList::Iterator iter = argList.Iterate();
2138             while (iter.Next())  
2139             {
2140                 TypeHandle thElem = TypeHandle::FromPtr(iter.GetElement());
2141
2142                 if (thElem.IsGenericVariable())
2143                 {
2144                     // if a generic variable equals to the constraint, then this constraint will be satisfied
2145                     if (thElem == thConstraint)
2146                     {
2147                         fCanCast = TRUE;
2148                         break;
2149                     }
2150
2151                     // and any variable with the gpNotNullableValueTypeConstraint special constraint
2152                     // satisfies the "derived from System.ValueType" general subtype constraint
2153                     if (thConstraint == g_pValueTypeClass)
2154                     {
2155                         TypeVarTypeDesc *pTyElem = thElem.AsGenericVariable();
2156                         IfFailThrow(pTyElem->GetModule()->GetMDImport()->GetGenericParamProps(
2157                             pTyElem->GetToken(), 
2158                             NULL, 
2159                             &flags, 
2160                             NULL, 
2161                             NULL, 
2162                             NULL));
2163                         
2164                         if ((flags & gpNotNullableValueTypeConstraint) != 0)
2165                         {
2166                             fCanCast = TRUE;
2167                             break;
2168                         }
2169                     }
2170                 }
2171                 else
2172                 {
2173                     // if a concrete type can be cast to the constraint, then this constraint will be satisifed
2174                     if (thElem.CanCastTo(thConstraint))
2175                     {
2176                         fCanCast = TRUE;
2177                         break;
2178                     }
2179                 }
2180             }
2181
2182             if (!fCanCast)
2183                 return FALSE;
2184         }
2185     }      
2186     return TRUE;
2187 }
2188
2189
2190 #ifndef CROSSGEN_COMPILE
2191 OBJECTREF TypeVarTypeDesc::GetManagedClassObject()
2192 {
2193     CONTRACTL {
2194         THROWS;
2195         GC_TRIGGERS;
2196         MODE_COOPERATIVE;
2197
2198         INJECT_FAULT(COMPlusThrowOM());
2199         
2200         PRECONDITION(IsGenericVariable());
2201     }
2202     CONTRACTL_END;
2203             
2204     if (m_hExposedClassObject == NULL) {
2205         REFLECTCLASSBASEREF  refClass = NULL;
2206         GCPROTECT_BEGIN(refClass);
2207         refClass = (REFLECTCLASSBASEREF) AllocateObject(g_pRuntimeTypeClass);
2208
2209         LoaderAllocator *pLoaderAllocator = GetLoaderAllocator();
2210         TypeHandle th = TypeHandle(this);
2211         ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetType(th);
2212         ((ReflectClassBaseObject*)OBJECTREFToObject(refClass))->SetKeepAlive(pLoaderAllocator->GetExposedObject());
2213
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);
2217
2218         if (FastInterlockCompareExchangePointer(EnsureWritablePages(&m_hExposedClassObject), hExposedClassObject, static_cast<LOADERHANDLE>(NULL)))
2219         {
2220             pLoaderAllocator->FreeHandle(hExposedClassObject);
2221         }
2222
2223         GCPROTECT_END();
2224     }
2225     return GetManagedClassObjectIfExists();
2226 }
2227 #endif // CROSSGEN_COMPILE
2228
2229 #endif //!DACCESS_COMPILE
2230
2231 TypeHandle * 
2232 FnPtrTypeDesc::GetRetAndArgTypes()
2233
2234     CONTRACTL
2235     {
2236         THROWS;
2237         GC_TRIGGERS;
2238         MODE_ANY;
2239     }
2240     CONTRACTL_END;
2241
2242     // Decode encoded type handles on demand
2243 #if defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
2244     for (DWORD i = 0; i <= m_NumArgs; i++)
2245     {
2246         Module::RestoreTypeHandlePointerRaw(&m_RetAndArgTypes[i]);
2247     }
2248 #endif //defined(FEATURE_PREJIT) && !defined(DACCESS_COMPILE)
2249
2250     return m_RetAndArgTypes;
2251 } // FnPtrTypeDesc::GetRetAndArgTypes
2252
2253 #ifndef DACCESS_COMPILE
2254
2255 // Returns TRUE if all return and argument types are externally visible.
2256 BOOL 
2257 FnPtrTypeDesc::IsExternallyVisible() const
2258 {
2259     CONTRACTL
2260     {
2261         THROWS;
2262         GC_TRIGGERS;
2263         MODE_ANY;
2264     }
2265     CONTRACTL_END;
2266     
2267     const TypeHandle * rgRetAndArgTypes = GetRetAndArgTypes();
2268     for (DWORD i = 0; i <= m_NumArgs; i++)
2269     {
2270         if (!rgRetAndArgTypes[i].IsExternallyVisible())
2271         {
2272             return FALSE;
2273         }
2274     }
2275     // All return/arguments types are externally visible
2276     return TRUE;
2277 } // FnPtrTypeDesc::IsExternallyVisible
2278
2279 #endif //DACCESS_COMPILE
2280
2281 #if defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
2282
2283 void FnPtrTypeDesc::Save(DataImage * image)
2284 {
2285     STANDARD_VM_CONTRACT;
2286
2287     image->StoreStructure(
2288         this, 
2289         sizeof(FnPtrTypeDesc) + (m_NumArgs * sizeof(TypeHandle)), 
2290         DataImage::ITEM_FPTR_TYPEDESC);
2291 }
2292
2293 void FnPtrTypeDesc::Fixup(DataImage * image)
2294 {
2295     STANDARD_VM_CONTRACT;
2296
2297     for (DWORD i = 0; i <= m_NumArgs; i++)
2298     {
2299         image->FixupTypeHandlePointerInPlace(
2300             this, 
2301             (BYTE *)&m_RetAndArgTypes[i] - (BYTE *)this);
2302     }
2303 }
2304
2305 #endif //defined(FEATURE_NATIVE_IMAGE_GENERATION) && !defined(DACCESS_COMPILE)
2306
2307 #ifdef DACCESS_COMPILE
2308
2309 void
2310 ParamTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2311 {
2312     SUPPORTS_DAC;
2313     DAC_ENUM_DTHIS();
2314
2315     PTR_MethodTable pTemplateMT = GetTemplateMethodTableInternal();
2316     if (pTemplateMT.IsValid())
2317     {
2318         pTemplateMT->EnumMemoryRegions(flags);
2319     }
2320
2321     m_Arg.EnumMemoryRegions(flags);
2322 }
2323
2324 void
2325 TypeVarTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2326 {
2327     SUPPORTS_DAC;
2328     DAC_ENUM_DTHIS();
2329
2330     PTR_TypeVarTypeDesc ptrThis(this);
2331
2332     if (GetModule().IsValid())
2333     {
2334         GetModule()->EnumMemoryRegions(flags, true);
2335     }
2336
2337     if (m_numConstraints != (DWORD)-1)
2338     {
2339         PTR_TypeHandle constraint = m_constraints;
2340         for (DWORD i = 0; i < m_numConstraints; i++)
2341         {
2342             if (constraint.IsValid())
2343             {
2344                 constraint->EnumMemoryRegions(flags);
2345             }
2346             constraint++;
2347         }
2348     }
2349 } // TypeVarTypeDesc::EnumMemoryRegions
2350
2351 void
2352 FnPtrTypeDesc::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
2353 {
2354     SUPPORTS_DAC;
2355     DAC_ENUM_DTHIS();
2356
2357     for (DWORD i = 0; i < m_NumArgs; i++)
2358     {
2359         m_RetAndArgTypes[i].EnumMemoryRegions(flags);
2360     }
2361 }
2362
2363 #endif //DACCESS_COMPILE