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 | |
34 | BOOL 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 | |
52 | BOOL 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 | |
72 | TypeHandle 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 | |
88 | PTR_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 | |
121 | PTR_Module TypeDesc::GetZapModule() |
122 | { |
123 | WRAPPER_NO_CONTRACT; |
124 | SUPPORTS_DAC; |
125 | return ExecutionManager::FindZapModule(dac_cast<TADDR>(this)); |
126 | } |
127 | |
128 | PTR_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 | |
142 | PTR_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 | |
174 | BOOL 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 | |
207 | Assembly* 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 | |
217 | void 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 | |
246 | void 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 | |
327 | BOOL TypeDesc::IsArray() |
328 | { |
329 | LIMITED_METHOD_DAC_CONTRACT; |
330 | return CorTypeInfo::IsArray_NoThrow(GetInternalCorElementType()); |
331 | } |
332 | |
333 | BOOL TypeDesc::IsGenericVariable() |
334 | { |
335 | LIMITED_METHOD_DAC_CONTRACT; |
336 | return CorTypeInfo::IsGenericVariable_NoThrow(GetInternalCorElementType()); |
337 | } |
338 | |
339 | BOOL TypeDesc::IsFnPtr() |
340 | { |
341 | LIMITED_METHOD_DAC_CONTRACT; |
342 | return (GetInternalCorElementType() == ELEMENT_TYPE_FNPTR); |
343 | } |
344 | |
345 | BOOL TypeDesc::IsNativeValueType() |
346 | { |
347 | WRAPPER_NO_CONTRACT; |
348 | return (GetInternalCorElementType() == ELEMENT_TYPE_VALUETYPE); |
349 | } |
350 | |
351 | BOOL 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 | |
361 | BOOL 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 | |
473 | BOOL 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 | |
537 | TypeHandle::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 | |
629 | TypeHandle::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 | |
704 | BOOL 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 | |
754 | TypeHandle 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 |
774 | OBJECTREF 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 | |
827 | BOOL 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 | |
840 | BOOL 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 | |
851 | ClassLoadLevel 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 | // |
919 | void 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 |
1018 | void 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 |
1053 | void 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 | |
1082 | void 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 | |
1119 | BOOL 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 | |
1135 | void 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 | |
1165 | void 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 | |
1205 | void 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 | |
1217 | BOOL 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 | |
1275 | void 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 | |
1288 | void 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 |
1325 | void 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 | |
1337 | void 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 | |
1351 | MethodDesc * 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 | |
1371 | TypeHandle 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 | |
1393 | TypeHandle* 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 | |
1406 | TypeHandle* 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 | |
1420 | void 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 | |
1536 | BOOL 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) |
1566 | BOOL 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 | |
1603 | BOOL 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 | //--------------------------------------------------------------------------------------------------------------------- |
1654 | static |
1655 | TypeHandle 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 | { |
1719 | LoadConstraintOnOpenType: |
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 | //--------------------------------------------------------------------------------------------------------------------- |
1776 | static |
1777 | BOOL 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 | //--------------------------------------------------------------------------------------------------------------------- |
1955 | static |
1956 | void 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 | // |
2012 | BOOL 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 |
2214 | OBJECTREF 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 | |
2254 | TypeHandle * |
2255 | FnPtrTypeDesc::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. |
2279 | BOOL |
2280 | FnPtrTypeDesc::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 | |
2306 | void 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 | |
2316 | void 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 | |
2332 | void |
2333 | ParamTypeDesc::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 | |
2347 | void |
2348 | TypeVarTypeDesc::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 | |
2374 | void |
2375 | FnPtrTypeDesc::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 | |