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