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: typehandle.cpp |
6 | // |
7 | |
8 | |
9 | // |
10 | |
11 | // |
12 | // ============================================================================ |
13 | |
14 | |
15 | #include "common.h" |
16 | #include "class.h" |
17 | #include "typehandle.h" |
18 | #include "eeconfig.h" |
19 | #include "generics.h" |
20 | #include "typedesc.h" |
21 | #include "typekey.h" |
22 | #include "typestring.h" |
23 | #include "classloadlevel.h" |
24 | #include "array.h" |
25 | #ifdef FEATURE_PREJIT |
26 | #include "zapsig.h" |
27 | #endif |
28 | |
29 | // This method is not being called by all the constructors of TypeHandle |
30 | // because of the following reason. SystemDomain::LoadBaseSystemClasses() |
31 | // loads TYPE__OBJECT_ARRAY which causes the following issues: |
32 | // |
33 | // If mscorlib is JIT-compiled, Module::CreateArrayMethodTable calls |
34 | // TypeString::AppendName() with a TypeHandle that wraps the MethodTable |
35 | // being created. |
36 | // If mscorlib is ngenned, Module::RestoreMethodTablePointer() needs |
37 | // a TypeHandle to call ClassLoader::EnsureLoaded(). |
38 | // |
39 | |
40 | #if 0 |
41 | |
42 | void TypeHandle::NormalizeUnsharedArrayMT() |
43 | { |
44 | WRAPPER_NO_CONTRACT; |
45 | STATIC_CONTRACT_SO_TOLERANT; // @TODO: This is probably incorrect |
46 | |
47 | if (IsNull() || IsTypeDesc()) |
48 | return; |
49 | |
50 | if (!AsMethodTable()->IsArray()) |
51 | return; |
52 | |
53 | // This is an array type with a unique unshared MethodTable. |
54 | // We know that there must exist an ArrayTypeDesc for it, and it |
55 | // must have been restored. |
56 | // Let's look it up and use it. |
57 | |
58 | ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); |
59 | |
60 | TypeHandle elemType = AsMethodTable()->GetApproxArrayElementTypeHandle(); |
61 | CorElementType kind = AsMethodTable()->GetInternalCorElementType(); |
62 | unsigned rank = AsMethodTable()->GetRank(); |
63 | |
64 | // @todo This should be turned into a probe with a hard SO when we have one |
65 | CONTRACT_VIOLATION(SOToleranceViolation); |
66 | // == FailIfNotLoadedOrNotRestored |
67 | TypeHandle arrayType = ClassLoader::LoadArrayTypeThrowing( elemType, |
68 | kind, |
69 | rank, |
70 | ClassLoader::DontLoadTypes); |
71 | CONSISTENCY_CHECK(!arrayType.IsNull() && arrayType.IsArray()); |
72 | |
73 | // |
74 | // Update the current TypeHandle to use the ArrayTypeDesc |
75 | // |
76 | m_asPtr = arrayType.AsPtr(); |
77 | |
78 | INDEBUGIMPL(Verify()); |
79 | } |
80 | |
81 | #endif |
82 | |
83 | #ifdef _DEBUG_IMPL |
84 | |
85 | BOOL TypeHandle::Verify() |
86 | { |
87 | STATIC_CONTRACT_NOTHROW; |
88 | STATIC_CONTRACT_GC_NOTRIGGER; |
89 | STATIC_CONTRACT_FORBID_FAULT; |
90 | STATIC_CONTRACT_CANNOT_TAKE_LOCK; |
91 | STATIC_CONTRACT_DEBUG_ONLY; |
92 | STATIC_CONTRACT_SUPPORTS_DAC; |
93 | |
94 | if (IsNull()) |
95 | return(TRUE); |
96 | |
97 | // If you try to do IBC logging of a type being created, the type |
98 | // will look inconsistent. IBC logging knows to filter out such types. |
99 | if (g_IBCLogger.InstrEnabled()) |
100 | return TRUE; |
101 | |
102 | if (!IsRestored_NoLogging()) |
103 | return TRUE; |
104 | |
105 | if (!IsTypeDesc()) |
106 | { |
107 | _ASSERTE(AsMethodTable()->SanityCheck()); // Sane method table |
108 | |
109 | // @TODO: See TypeHandle::IsArrayType() for an explanation |
110 | // of why this assert is commented out. |
111 | // |
112 | // _ASSERTE(!AsMethodTable()->IsArray()); |
113 | } |
114 | else |
115 | { |
116 | if (IsArray()) |
117 | AsArray()->Verify(); |
118 | } |
119 | return(TRUE); |
120 | } |
121 | |
122 | #endif // _DEBUG_IMPL |
123 | |
124 | unsigned TypeHandle::GetSize() const |
125 | { |
126 | LIMITED_METHOD_DAC_CONTRACT; |
127 | |
128 | CorElementType type = GetInternalCorElementType(); |
129 | |
130 | if (type == ELEMENT_TYPE_VALUETYPE) |
131 | { |
132 | if (IsTypeDesc()) |
133 | return(AsNativeValueType()->GetNativeSize()); |
134 | else |
135 | return(AsMethodTable()->GetNumInstanceFieldBytes()); |
136 | } |
137 | |
138 | return(GetSizeForCorElementType(type)); |
139 | } |
140 | |
141 | PTR_Module TypeHandle::GetModule() const { |
142 | LIMITED_METHOD_DAC_CONTRACT; |
143 | |
144 | if (IsTypeDesc()) |
145 | return AsTypeDesc()->GetModule(); |
146 | return(AsMethodTable()->GetModule()); |
147 | } |
148 | |
149 | Assembly* TypeHandle::GetAssembly() const { |
150 | LIMITED_METHOD_DAC_CONTRACT; |
151 | |
152 | if (IsTypeDesc()) |
153 | return AsTypeDesc()->GetAssembly(); |
154 | return(AsMethodTable()->GetAssembly()); |
155 | } |
156 | |
157 | BOOL TypeHandle::IsArray() const { |
158 | LIMITED_METHOD_DAC_CONTRACT; |
159 | |
160 | return(IsTypeDesc() && AsTypeDesc()->IsArray()); |
161 | } |
162 | |
163 | BOOL TypeHandle::IsArrayType() const { |
164 | LIMITED_METHOD_DAC_CONTRACT; |
165 | |
166 | if (IsTypeDesc()) |
167 | { |
168 | return AsTypeDesc()->IsArray(); |
169 | } |
170 | else |
171 | { |
172 | return AsMethodTable()->IsArray(); |
173 | } |
174 | } |
175 | |
176 | BOOL TypeHandle::IsGenericVariable() const { |
177 | LIMITED_METHOD_DAC_CONTRACT; |
178 | |
179 | return(IsTypeDesc() && CorTypeInfo::IsGenericVariable_NoThrow(AsTypeDesc()->GetInternalCorElementType())); |
180 | } |
181 | |
182 | BOOL TypeHandle::HasTypeParam() const { |
183 | LIMITED_METHOD_DAC_CONTRACT; |
184 | |
185 | if (!IsTypeDesc()) return FALSE; |
186 | |
187 | CorElementType etype = AsTypeDesc()->GetInternalCorElementType(); |
188 | return(CorTypeInfo::IsModifier_NoThrow(etype) || etype == ELEMENT_TYPE_VALUETYPE); |
189 | } |
190 | |
191 | Module *TypeHandle::GetDefiningModuleForOpenType() const |
192 | { |
193 | WRAPPER_NO_CONTRACT; |
194 | SUPPORTS_DAC; |
195 | |
196 | Module* returnValue = NULL; |
197 | |
198 | INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(goto Exit;); |
199 | |
200 | if (IsGenericVariable()) |
201 | { |
202 | PTR_TypeVarTypeDesc pTyVar = dac_cast<PTR_TypeVarTypeDesc>(AsTypeDesc()); |
203 | returnValue = pTyVar->GetModule(); |
204 | goto Exit; |
205 | } |
206 | |
207 | if (HasTypeParam()) |
208 | { |
209 | returnValue = GetTypeParam().GetDefiningModuleForOpenType(); |
210 | } |
211 | else if (HasInstantiation()) |
212 | { |
213 | returnValue = GetMethodTable()->GetDefiningModuleForOpenType(); |
214 | } |
215 | Exit: |
216 | ; |
217 | END_INTERIOR_STACK_PROBE; |
218 | |
219 | return returnValue; |
220 | } |
221 | |
222 | BOOL TypeHandle::ContainsGenericVariables(BOOL methodOnly /*=FALSE*/) const |
223 | { |
224 | STATIC_CONTRACT_SO_TOLERANT; |
225 | STATIC_CONTRACT_NOTHROW; |
226 | SUPPORTS_DAC; |
227 | |
228 | if (IsTypeDesc()) |
229 | { |
230 | if (IsGenericVariable()) |
231 | { |
232 | if (!methodOnly) |
233 | return TRUE; |
234 | |
235 | PTR_TypeVarTypeDesc pTyVar = dac_cast<PTR_TypeVarTypeDesc>(AsTypeDesc()); |
236 | return TypeFromToken(pTyVar->GetTypeOrMethodDef()) == mdtMethodDef; |
237 | } |
238 | |
239 | if (HasTypeParam()) |
240 | { |
241 | return GetTypeParam().ContainsGenericVariables(methodOnly); |
242 | } |
243 | } |
244 | else if (HasInstantiation()) |
245 | { |
246 | if (GetMethodTable()->ContainsGenericVariables(methodOnly)) |
247 | return TRUE; |
248 | } |
249 | |
250 | return FALSE; |
251 | } |
252 | |
253 | //@GENERICS: |
254 | // Return the number of type parameters in the instantiation of an instantiated type |
255 | // or the number of type parameters to a generic type |
256 | // Return 0 otherwise. |
257 | DWORD TypeHandle::GetNumGenericArgs() const { |
258 | LIMITED_METHOD_DAC_CONTRACT; |
259 | |
260 | if (IsTypeDesc()) |
261 | return 0; |
262 | else |
263 | return GetMethodTable()->GetNumGenericArgs(); |
264 | } |
265 | |
266 | BOOL TypeHandle::IsGenericTypeDefinition() const { |
267 | LIMITED_METHOD_DAC_CONTRACT; |
268 | |
269 | if (!IsTypeDesc()) |
270 | return AsMethodTable()->IsGenericTypeDefinition(); |
271 | else |
272 | return FALSE; |
273 | } |
274 | |
275 | PTR_MethodTable TypeHandle::GetCanonicalMethodTable() const |
276 | { |
277 | LIMITED_METHOD_DAC_CONTRACT; |
278 | |
279 | if (IsTypeDesc()) |
280 | { |
281 | PTR_MethodTable pMT = AsTypeDesc()->GetMethodTable(); |
282 | if (pMT != NULL) |
283 | pMT = pMT->GetCanonicalMethodTable(); |
284 | return pMT; |
285 | } |
286 | else |
287 | { |
288 | return AsMethodTable()->GetCanonicalMethodTable(); |
289 | } |
290 | } |
291 | |
292 | // Obtain instantiation from an instantiated type or a pointer to the |
293 | // element type of an array or pointer type |
294 | Instantiation TypeHandle::GetClassOrArrayInstantiation() const |
295 | { |
296 | LIMITED_METHOD_DAC_CONTRACT; |
297 | |
298 | if (IsTypeDesc()) |
299 | { |
300 | return AsTypeDesc()->GetClassOrArrayInstantiation(); |
301 | } |
302 | else if (IsArrayType()) |
303 | { |
304 | return AsMethodTable()->GetArrayInstantiation(); |
305 | } |
306 | else |
307 | { |
308 | return GetInstantiation(); |
309 | } |
310 | } |
311 | |
312 | Instantiation TypeHandle::GetInstantiationOfParentClass(MethodTable *pWhichParent) const |
313 | { |
314 | LIMITED_METHOD_DAC_CONTRACT; |
315 | |
316 | return GetMethodTable()->GetInstantiationOfParentClass(pWhichParent); |
317 | } |
318 | |
319 | // Obtain element type from an array or pointer type |
320 | TypeHandle TypeHandle::GetTypeParam() const |
321 | { |
322 | LIMITED_METHOD_DAC_CONTRACT; |
323 | |
324 | if (IsTypeDesc()) |
325 | return AsTypeDesc()->GetTypeParam(); |
326 | else |
327 | return TypeHandle(); |
328 | } |
329 | |
330 | #ifndef DACCESS_COMPILE |
331 | TypeHandle TypeHandle::Instantiate(Instantiation inst) const |
332 | { |
333 | STATIC_CONTRACT_WRAPPER; |
334 | return ClassLoader::LoadGenericInstantiationThrowing(GetModule(), GetCl(), inst); |
335 | } |
336 | |
337 | TypeHandle TypeHandle::MakePointer() const |
338 | { |
339 | STATIC_CONTRACT_WRAPPER; |
340 | return ClassLoader::LoadPointerOrByrefTypeThrowing(ELEMENT_TYPE_PTR, *this); |
341 | } |
342 | |
343 | TypeHandle TypeHandle::MakeByRef() const |
344 | { |
345 | STATIC_CONTRACT_WRAPPER; |
346 | return ClassLoader::LoadPointerOrByrefTypeThrowing(ELEMENT_TYPE_BYREF, *this); |
347 | } |
348 | |
349 | TypeHandle TypeHandle::MakeSZArray() const |
350 | { |
351 | STATIC_CONTRACT_WRAPPER; |
352 | return ClassLoader::LoadArrayTypeThrowing(*this); |
353 | } |
354 | |
355 | TypeHandle TypeHandle::MakeArray(int rank) const |
356 | { |
357 | STATIC_CONTRACT_WRAPPER; |
358 | return ClassLoader::LoadArrayTypeThrowing(*this, ELEMENT_TYPE_ARRAY, rank); |
359 | } |
360 | |
361 | // The returned TypeHandle is a ParamTypeDesc that acts like a facade for the original valuetype. It makes the |
362 | // valuetype look like its unmanaged view, i.e. GetSize() returns GetNativeSize(), IsBlittable() returns TRUE, |
363 | // and JIT interface special-cases it when reporting GC pointers to the JIT. |
364 | TypeHandle TypeHandle::MakeNativeValueType() const |
365 | { |
366 | STATIC_CONTRACT_WRAPPER; |
367 | return ClassLoader::LoadNativeValueTypeThrowing(*this); |
368 | } |
369 | |
370 | #endif // #ifndef DACCESS_COMPILE |
371 | |
372 | PTR_Module TypeHandle::GetLoaderModule() const |
373 | { |
374 | LIMITED_METHOD_DAC_CONTRACT; |
375 | |
376 | if (IsTypeDesc()) |
377 | return AsTypeDesc()->GetLoaderModule(); |
378 | else |
379 | return AsMethodTable()->GetLoaderModule(); |
380 | } |
381 | |
382 | PTR_Module TypeHandle::GetZapModule() const |
383 | { |
384 | LIMITED_METHOD_DAC_CONTRACT; |
385 | |
386 | if (IsTypeDesc()) |
387 | return AsTypeDesc()->GetZapModule(); |
388 | else |
389 | return AsMethodTable()->GetZapModule(); |
390 | } |
391 | |
392 | PTR_BaseDomain TypeHandle::GetDomain() const |
393 | { |
394 | LIMITED_METHOD_DAC_CONTRACT; |
395 | |
396 | if (IsTypeDesc()) |
397 | return AsTypeDesc()->GetDomain(); |
398 | else |
399 | return AsMethodTable()->GetDomain(); |
400 | |
401 | } |
402 | |
403 | PTR_LoaderAllocator TypeHandle::GetLoaderAllocator() const |
404 | { |
405 | STATIC_CONTRACT_NOTHROW; |
406 | STATIC_CONTRACT_GC_NOTRIGGER; |
407 | STATIC_CONTRACT_FORBID_FAULT; |
408 | STATIC_CONTRACT_SO_INTOLERANT; |
409 | STATIC_CONTRACT_SUPPORTS_DAC; |
410 | |
411 | if (IsTypeDesc()) |
412 | { |
413 | return AsTypeDesc()->GetLoaderAllocator(); |
414 | } |
415 | else |
416 | { |
417 | return AsMethodTable()->GetLoaderAllocator(); |
418 | } |
419 | } |
420 | |
421 | BOOL TypeHandle::IsSharedByGenericInstantiations() const |
422 | { |
423 | LIMITED_METHOD_DAC_CONTRACT; |
424 | |
425 | if (IsTypeDesc()) |
426 | { |
427 | // Arrays are the only typedesc in valid generic instantiations (see code:Generics::CheckInstantiation) |
428 | |
429 | if (HasTypeParam()) |
430 | { |
431 | return GetTypeParam().IsCanonicalSubtype(); |
432 | } |
433 | return FALSE; |
434 | } |
435 | else |
436 | return AsMethodTable()->IsSharedByGenericInstantiations(); |
437 | } |
438 | |
439 | BOOL TypeHandle::IsCanonicalSubtype() const |
440 | { |
441 | LIMITED_METHOD_DAC_CONTRACT; |
442 | |
443 | return (*this == TypeHandle(g_pCanonMethodTableClass)) || IsSharedByGenericInstantiations(); |
444 | } |
445 | |
446 | /* static */ BOOL TypeHandle::IsCanonicalSubtypeInstantiation(Instantiation inst) |
447 | { |
448 | LIMITED_METHOD_DAC_CONTRACT; |
449 | |
450 | for (DWORD i = 0; i < inst.GetNumArgs(); i++) |
451 | { |
452 | if (inst[i].IsCanonicalSubtype()) |
453 | return TRUE; |
454 | } |
455 | return FALSE; |
456 | } |
457 | |
458 | // Obtain instantiation from an instantiated type. |
459 | // Return NULL if it's not one. |
460 | Instantiation TypeHandle::GetInstantiation() const |
461 | { |
462 | LIMITED_METHOD_DAC_CONTRACT; |
463 | |
464 | if (!IsTypeDesc()) return AsMethodTable()->GetInstantiation(); |
465 | else return Instantiation(); |
466 | } |
467 | |
468 | |
469 | BOOL TypeHandle::IsValueType() const |
470 | { |
471 | LIMITED_METHOD_DAC_CONTRACT; |
472 | |
473 | if (!IsTypeDesc()) return AsMethodTable()->IsValueType(); |
474 | else return AsTypeDesc()->IsNativeValueType(); |
475 | } |
476 | |
477 | BOOL TypeHandle::IsInterface() const |
478 | { |
479 | LIMITED_METHOD_DAC_CONTRACT; |
480 | |
481 | return !IsTypeDesc() && AsMethodTable()->IsInterface(); |
482 | } |
483 | |
484 | BOOL TypeHandle::IsAbstract() const |
485 | { |
486 | WRAPPER_NO_CONTRACT; |
487 | PREFIX_ASSUME(GetMethodTable() != NULL); |
488 | return GetMethodTable()->IsAbstract(); |
489 | } |
490 | |
491 | bool TypeHandle::IsHFA() const |
492 | { |
493 | WRAPPER_NO_CONTRACT; |
494 | |
495 | if (!IsTypeDesc()) |
496 | return AsMethodTable()->IsHFA(); |
497 | |
498 | if (AsTypeDesc()->IsNativeValueType()) |
499 | return AsNativeValueType()->IsNativeHFA(); |
500 | |
501 | return false; |
502 | } |
503 | |
504 | CorElementType TypeHandle::GetHFAType() const |
505 | { |
506 | WRAPPER_NO_CONTRACT; |
507 | |
508 | if (!IsTypeDesc()) |
509 | return AsMethodTable()->GetHFAType(); |
510 | |
511 | if (AsTypeDesc()->IsNativeValueType()) |
512 | return AsNativeValueType()->GetNativeHFAType(); |
513 | |
514 | return ELEMENT_TYPE_END; |
515 | } |
516 | |
517 | |
518 | #ifdef FEATURE_64BIT_ALIGNMENT |
519 | bool TypeHandle::RequiresAlign8() const |
520 | { |
521 | WRAPPER_NO_CONTRACT; |
522 | |
523 | if (IsNativeValueType()) |
524 | return AsNativeValueType()->NativeRequiresAlign8(); |
525 | |
526 | return GetMethodTable()->RequiresAlign8(); |
527 | } |
528 | #endif // FEATURE_64BIT_ALIGNMENT |
529 | |
530 | #ifndef DACCESS_COMPILE |
531 | |
532 | BOOL TypeHandle::IsBlittable() const |
533 | { |
534 | LIMITED_METHOD_CONTRACT; |
535 | |
536 | if (!IsTypeDesc()) |
537 | { |
538 | // This is a simple type (not an array, ptr or byref) so if |
539 | // simply check to see if the type is blittable. |
540 | return AsMethodTable()->IsBlittable(); |
541 | } |
542 | |
543 | if (AsTypeDesc()->IsArray()) |
544 | { |
545 | // Single dimentional array's of blittable types are also blittable. |
546 | if (AsArray()->GetRank() == 1) |
547 | { |
548 | if (AsArray()->GetArrayElementTypeHandle().IsBlittable()) |
549 | return TRUE; |
550 | } |
551 | } |
552 | else if (AsTypeDesc()->IsNativeValueType()) |
553 | { |
554 | return TRUE; |
555 | } |
556 | |
557 | return FALSE; |
558 | } |
559 | |
560 | BOOL TypeHandle::HasLayout() const |
561 | { |
562 | WRAPPER_NO_CONTRACT; |
563 | MethodTable *pMT = GetMethodTable(); |
564 | return pMT ? pMT->HasLayout() : FALSE; |
565 | } |
566 | |
567 | #ifdef FEATURE_COMINTEROP |
568 | |
569 | TypeHandle TypeHandle::GetCoClassForInterface() const |
570 | { |
571 | WRAPPER_NO_CONTRACT; |
572 | PREFIX_ASSUME(GetMethodTable() != NULL); |
573 | return GetMethodTable()->GetCoClassForInterface(); |
574 | } |
575 | |
576 | DWORD TypeHandle::IsComClassInterface() const |
577 | { |
578 | WRAPPER_NO_CONTRACT; |
579 | PREFIX_ASSUME(GetMethodTable() != NULL); |
580 | return GetMethodTable()->IsComClassInterface(); |
581 | } |
582 | |
583 | BOOL TypeHandle::IsComObjectType() const |
584 | { |
585 | WRAPPER_NO_CONTRACT; |
586 | PREFIX_ASSUME(GetMethodTable() != NULL); |
587 | return GetMethodTable()->IsComObjectType(); |
588 | } |
589 | |
590 | BOOL TypeHandle::IsComEventItfType() const |
591 | { |
592 | WRAPPER_NO_CONTRACT; |
593 | PREFIX_ASSUME(GetMethodTable() != NULL); |
594 | return GetMethodTable()->IsComEventItfType(); |
595 | } |
596 | |
597 | CorIfaceAttr TypeHandle::GetComInterfaceType() const |
598 | { |
599 | WRAPPER_NO_CONTRACT; |
600 | PREFIX_ASSUME(GetMethodTable() != NULL); |
601 | return GetMethodTable()->GetComInterfaceType(); |
602 | } |
603 | |
604 | TypeHandle TypeHandle::GetDefItfForComClassItf() const |
605 | { |
606 | WRAPPER_NO_CONTRACT; |
607 | PREFIX_ASSUME(GetMethodTable() != NULL); |
608 | return GetMethodTable()->GetDefItfForComClassItf(); |
609 | } |
610 | |
611 | BOOL TypeHandle::IsProjectedFromWinRT() const |
612 | { |
613 | LIMITED_METHOD_CONTRACT; |
614 | PREFIX_ASSUME(GetMethodTable() != NULL); |
615 | return GetMethodTable()->IsProjectedFromWinRT(); |
616 | } |
617 | |
618 | BOOL TypeHandle::IsExportedToWinRT() const |
619 | { |
620 | LIMITED_METHOD_CONTRACT; |
621 | PREFIX_ASSUME(GetMethodTable() != NULL); |
622 | return GetMethodTable()->IsExportedToWinRT(); |
623 | } |
624 | |
625 | ComCallWrapperTemplate *TypeHandle::GetComCallWrapperTemplate() const |
626 | { |
627 | LIMITED_METHOD_CONTRACT; |
628 | PRECONDITION(IsArray() || !IsTypeDesc()); |
629 | |
630 | if (IsTypeDesc()) |
631 | { |
632 | return AsArray()->GetComCallWrapperTemplate(); |
633 | } |
634 | return AsMethodTable()->GetComCallWrapperTemplate(); |
635 | } |
636 | |
637 | BOOL TypeHandle::SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate) |
638 | { |
639 | CONTRACTL |
640 | { |
641 | THROWS; |
642 | GC_NOTRIGGER; |
643 | MODE_ANY; |
644 | } |
645 | CONTRACTL_END; |
646 | |
647 | PRECONDITION(IsArray() || !IsTypeDesc()); |
648 | |
649 | if (IsTypeDesc()) |
650 | { |
651 | return AsArray()->SetComCallWrapperTemplate(pTemplate); |
652 | } |
653 | return AsMethodTable()->SetComCallWrapperTemplate(pTemplate); |
654 | } |
655 | |
656 | #endif // FEATURE_COMINTEROP |
657 | |
658 | //-------------------------------------------------------------------------------------- |
659 | // CanCastTo is necessary but not sufficient, as it assumes that any valuetype |
660 | // involved is in its boxed form. |
661 | |
662 | BOOL TypeHandle::IsBoxedAndCanCastTo(TypeHandle type, TypeHandlePairList *pPairList) const |
663 | { |
664 | CONTRACTL |
665 | { |
666 | THROWS; |
667 | GC_TRIGGERS; |
668 | INJECT_FAULT(COMPlusThrowOM()); |
669 | |
670 | LOADS_TYPE(CLASS_DEPENDENCIES_LOADED); |
671 | |
672 | // The caller should check for an exact match. |
673 | // That will cover the cast of a (unboxed) valuetype to itself. |
674 | PRECONDITION(*this != type); |
675 | } |
676 | CONTRACTL_END |
677 | |
678 | |
679 | CorElementType fromParamCorType = GetVerifierCorElementType(); |
680 | |
681 | if (CorTypeInfo::IsObjRef(fromParamCorType)) |
682 | { |
683 | // fromParamCorType is a reference type. We can just use CanCastTo |
684 | return CanCastTo(type, pPairList); |
685 | } |
686 | else if (CorTypeInfo::IsGenericVariable(fromParamCorType)) |
687 | { |
688 | TypeVarTypeDesc* varFromParam = AsGenericVariable(); |
689 | |
690 | if (!varFromParam->ConstraintsLoaded()) |
691 | varFromParam->LoadConstraints(CLASS_DEPENDENCIES_LOADED); |
692 | |
693 | // A generic type parameter cannot be compatible with another type |
694 | // as it could be substitued with a valuetype. However, if it is |
695 | // constrained to a reference type, then we can use CanCastTo. |
696 | if (varFromParam->ConstrainedAsObjRef()) |
697 | return CanCastTo(type, pPairList); |
698 | } |
699 | |
700 | return FALSE; |
701 | } |
702 | |
703 | //-------------------------------------------------------------------------------------- |
704 | // CanCastTo is necessary but not sufficient, as it assumes that any valuetype |
705 | // involved is in its boxed form. See IsBoxedAndCanCastTo() if the valuetype |
706 | // is not guaranteed to be in its boxed form. |
707 | |
708 | BOOL TypeHandle::CanCastTo(TypeHandle type, TypeHandlePairList *pVisited) const |
709 | { |
710 | CONTRACTL |
711 | { |
712 | THROWS; |
713 | GC_TRIGGERS; |
714 | INJECT_FAULT(COMPlusThrowOM()); |
715 | |
716 | LOADS_TYPE(CLASS_DEPENDENCIES_LOADED); |
717 | } |
718 | CONTRACTL_END |
719 | |
720 | if (*this == type) |
721 | return(true); |
722 | |
723 | if (IsTypeDesc()) |
724 | return AsTypeDesc()->CanCastTo(type, pVisited); |
725 | |
726 | if (type.IsTypeDesc()) |
727 | return(false); |
728 | |
729 | return AsMethodTable()->CanCastToClassOrInterface(type.AsMethodTable(), pVisited); |
730 | } |
731 | |
732 | #include <optsmallperfcritical.h> |
733 | TypeHandle::CastResult TypeHandle::CanCastToNoGC(TypeHandle type) const |
734 | { |
735 | LIMITED_METHOD_CONTRACT; |
736 | |
737 | if (*this == type) |
738 | return(CanCast); |
739 | |
740 | if (IsTypeDesc()) |
741 | return AsTypeDesc()->CanCastToNoGC(type); |
742 | |
743 | if (type.IsTypeDesc()) |
744 | return(CannotCast); |
745 | |
746 | return AsMethodTable()->CanCastToClassOrInterfaceNoGC(type.AsMethodTable()); |
747 | } |
748 | #include <optdefault.h> |
749 | |
750 | #endif // #ifndef DACCESS_COMPILE |
751 | |
752 | void TypeHandle::GetName(SString &result) const |
753 | { |
754 | CONTRACTL |
755 | { |
756 | THROWS; |
757 | GC_NOTRIGGER; |
758 | SO_TOLERANT; |
759 | INJECT_FAULT(COMPlusThrowOM();); |
760 | } |
761 | CONTRACTL_END |
762 | |
763 | INTERIOR_STACK_PROBE_NOTHROW_CHECK_THREAD(goto Exit;); |
764 | { |
765 | |
766 | if (IsTypeDesc()) |
767 | { |
768 | AsTypeDesc()->GetName(result); |
769 | goto Exit; |
770 | } |
771 | |
772 | AsMethodTable()->_GetFullyQualifiedNameForClass(result); |
773 | |
774 | // Tack the instantiation on the end |
775 | Instantiation inst = GetInstantiation(); |
776 | if (!inst.IsEmpty()) |
777 | TypeString::AppendInst(result, inst); |
778 | } |
779 | Exit: |
780 | ; |
781 | END_INTERIOR_STACK_PROBE; |
782 | } |
783 | |
784 | TypeHandle TypeHandle::GetParent() const |
785 | { |
786 | STATIC_CONTRACT_NOTHROW; |
787 | STATIC_CONTRACT_GC_NOTRIGGER; |
788 | STATIC_CONTRACT_FORBID_FAULT; |
789 | STATIC_CONTRACT_SO_TOLERANT; |
790 | |
791 | if (IsTypeDesc()) |
792 | return(AsTypeDesc()->GetParent()); |
793 | else |
794 | return TypeHandle(AsMethodTable()->GetParentMethodTable()); |
795 | } |
796 | #ifndef DACCESS_COMPILE |
797 | |
798 | /* static */ |
799 | TypeHandle TypeHandle::MergeClassWithInterface(TypeHandle tClass, TypeHandle tInterface) |
800 | { |
801 | CONTRACTL |
802 | { |
803 | THROWS; |
804 | GC_TRIGGERS; |
805 | INJECT_FAULT(COMPlusThrowOM()); |
806 | } |
807 | CONTRACTL_END |
808 | |
809 | MethodTable *pMTClass = tClass.AsMethodTable(); |
810 | |
811 | // Check if the class implements the interface |
812 | if (pMTClass->ImplementsEquivalentInterface(tInterface.AsMethodTable())) |
813 | { |
814 | // The class implements the interface or its equivalent, so our merged state should be the interface |
815 | return tInterface; |
816 | } |
817 | |
818 | // Check if the class and the interface implement a common interface |
819 | MethodTable *pMTInterface = tInterface.AsMethodTable(); |
820 | MethodTable::InterfaceMapIterator intIt = pMTInterface->IterateInterfaceMap(); |
821 | while (intIt.Next()) |
822 | { |
823 | MethodTable *pMT = intIt.GetInterface(); |
824 | if (pMTClass->ImplementsEquivalentInterface(pMT)) |
825 | { |
826 | // Found a common interface. If there are multiple common interfaces, then |
827 | // the problem is ambiguous so we'll just take the first one--it's the best |
828 | // we can do. If an ensuing code path relies on another common interface, |
829 | // the verifier will think the code is unverifiable, but it would require a |
830 | // major redesign of the verifier to fix that. |
831 | return TypeHandle(pMT); |
832 | } |
833 | } |
834 | |
835 | // No compatible merge found - using Object |
836 | return TypeHandle(g_pObjectClass); |
837 | } |
838 | |
839 | /* static */ |
840 | TypeHandle TypeHandle::MergeTypeHandlesToCommonParent(TypeHandle ta, TypeHandle tb) |
841 | { |
842 | CONTRACTL |
843 | { |
844 | THROWS; |
845 | GC_TRIGGERS; |
846 | INJECT_FAULT(COMPlusThrowOM()); |
847 | } |
848 | CONTRACTL_END |
849 | |
850 | _ASSERTE(!ta.IsNull() && !tb.IsNull()); |
851 | |
852 | if (ta == tb) |
853 | return ta; |
854 | |
855 | // Handle the array case |
856 | if (ta.IsArray()) |
857 | { |
858 | if (tb.IsArray()) |
859 | return MergeArrayTypeHandlesToCommonParent(ta, tb); |
860 | else if (tb.IsInterface()) |
861 | { |
862 | //Check to see if we can merge the array to a common interface (such as Derived[] and IList<Base>) |
863 | if (ArraySupportsBizarreInterface(ta.AsArray(), tb.AsMethodTable())) |
864 | return tb; |
865 | } |
866 | ta = TypeHandle(g_pArrayClass); // keep merging from here. |
867 | } |
868 | else if (tb.IsArray()) |
869 | { |
870 | if (ta.IsInterface() && ArraySupportsBizarreInterface(tb.AsArray(), ta.AsMethodTable())) |
871 | return ta; |
872 | |
873 | tb = TypeHandle(g_pArrayClass); |
874 | } |
875 | |
876 | |
877 | // If either is a (by assumption boxed) type variable |
878 | // return the supertype, if they are related, or object if they are incomparable. |
879 | if (ta.IsGenericVariable() || tb.IsGenericVariable()) |
880 | { |
881 | if (ta.CanCastTo(tb)) |
882 | return tb; |
883 | if (tb.CanCastTo(ta)) |
884 | return ta; |
885 | return TypeHandle(g_pObjectClass); |
886 | } |
887 | |
888 | |
889 | _ASSERTE(!ta.IsTypeDesc() && !tb.IsTypeDesc()); |
890 | |
891 | |
892 | MethodTable *pMTa = ta.AsMethodTable(); |
893 | MethodTable *pMTb = tb.AsMethodTable(); |
894 | |
895 | if (pMTb->IsInterface()) |
896 | { |
897 | |
898 | if (pMTa->IsInterface()) |
899 | { |
900 | // |
901 | // Both classes are interfaces. Check that if one |
902 | // interface extends the other. |
903 | // |
904 | // Does tb extend ta ? |
905 | // |
906 | |
907 | if (pMTb->ImplementsEquivalentInterface(pMTa)) |
908 | { |
909 | // tb extends ta, so our merged state should be ta |
910 | return ta; |
911 | } |
912 | |
913 | // |
914 | // Does tb extend ta ? |
915 | // |
916 | if (pMTa->ImplementsEquivalentInterface(pMTb)) |
917 | { |
918 | // ta extends tb, so our merged state should be tb |
919 | return tb; |
920 | } |
921 | |
922 | // No compatible merge found - using Object |
923 | return TypeHandle(g_pObjectClass); |
924 | } |
925 | else |
926 | return MergeClassWithInterface(ta, tb); |
927 | } |
928 | else if (pMTa->IsInterface()) |
929 | return MergeClassWithInterface(tb, ta); |
930 | |
931 | DWORD aDepth = 0; |
932 | DWORD bDepth = 0; |
933 | TypeHandle tSearch; |
934 | |
935 | // find the depth in the class hierarchy for each class |
936 | for (tSearch = ta; (!tSearch.IsNull()); tSearch = tSearch.GetParent()) |
937 | aDepth++; |
938 | |
939 | for (tSearch = tb; (!tSearch.IsNull()); tSearch = tSearch.GetParent()) |
940 | bDepth++; |
941 | |
942 | // for whichever class is lower down in the hierarchy, walk up the superclass chain |
943 | // to the same level as the other class |
944 | while (aDepth > bDepth) |
945 | { |
946 | ta = ta.GetParent(); |
947 | aDepth--; |
948 | } |
949 | |
950 | while (bDepth > aDepth) |
951 | { |
952 | tb = tb.GetParent(); |
953 | bDepth--; |
954 | } |
955 | |
956 | while (!ta.IsEquivalentTo(tb)) |
957 | { |
958 | ta = ta.GetParent(); |
959 | tb = tb.GetParent(); |
960 | } |
961 | |
962 | // If no compatible merge is found, we end up using Object |
963 | |
964 | _ASSERTE(!ta.IsNull()); |
965 | |
966 | return ta; |
967 | } |
968 | |
969 | /* static */ |
970 | TypeHandle TypeHandle::MergeArrayTypeHandlesToCommonParent(TypeHandle ta, TypeHandle tb) |
971 | { |
972 | CONTRACTL |
973 | { |
974 | THROWS; |
975 | GC_TRIGGERS; |
976 | INJECT_FAULT(COMPlusThrowOM()); |
977 | } |
978 | CONTRACTL_END |
979 | |
980 | CorElementType taKind = ta.GetInternalCorElementType(); |
981 | CorElementType tbKind = tb.GetInternalCorElementType(); |
982 | _ASSERTE(CorTypeInfo::IsArray(taKind) && CorTypeInfo::IsArray(tbKind)); |
983 | |
984 | TypeHandle taElem; |
985 | TypeHandle tMergeElem; |
986 | |
987 | // If they match we are good to go. |
988 | if (ta == tb) |
989 | return ta; |
990 | |
991 | if (ta == TypeHandle(g_pArrayClass)) |
992 | return ta; |
993 | else if (tb == TypeHandle(g_pArrayClass)) |
994 | return tb; |
995 | |
996 | // Get the rank and kind of the first array |
997 | DWORD rank = ta.AsArray()->GetRank(); |
998 | CorElementType mergeKind = taKind; |
999 | |
1000 | // if no match on the rank the common ancestor is System.Array |
1001 | if (rank != tb.AsArray()->GetRank()) |
1002 | return TypeHandle(g_pArrayClass); |
1003 | |
1004 | if (tbKind != taKind) |
1005 | { |
1006 | if (CorTypeInfo::IsArray(tbKind) && |
1007 | CorTypeInfo::IsArray(taKind) && rank == 1) |
1008 | mergeKind = ELEMENT_TYPE_ARRAY; |
1009 | else |
1010 | return TypeHandle(g_pArrayClass); |
1011 | } |
1012 | |
1013 | // If both are arrays of reference types, return an array of the common |
1014 | // ancestor. |
1015 | taElem = ta.AsArray()->GetArrayElementTypeHandle(); |
1016 | if (taElem.IsEquivalentTo(tb.AsArray()->GetArrayElementTypeHandle())) |
1017 | { |
1018 | // The element types match/are equivalent, so we are good to go. |
1019 | tMergeElem = taElem; |
1020 | } |
1021 | else if (taElem.IsArray() && tb.AsArray()->GetArrayElementTypeHandle().IsArray()) |
1022 | { |
1023 | // Arrays - Find the common ancestor of the element types. |
1024 | tMergeElem = MergeArrayTypeHandlesToCommonParent(taElem, tb.AsArray()->GetArrayElementTypeHandle()); |
1025 | } |
1026 | else if (CorTypeInfo::IsObjRef(taElem.GetSignatureCorElementType()) && |
1027 | CorTypeInfo::IsObjRef(tb.AsArray()->GetArrayElementTypeHandle().GetSignatureCorElementType())) |
1028 | { |
1029 | // Find the common ancestor of the element types. |
1030 | tMergeElem = MergeTypeHandlesToCommonParent(taElem, tb.AsArray()->GetArrayElementTypeHandle()); |
1031 | } |
1032 | else |
1033 | { |
1034 | // The element types have nothing in common. |
1035 | return TypeHandle(g_pArrayClass); |
1036 | } |
1037 | |
1038 | |
1039 | { |
1040 | // This should just result in resolving an already loaded type. |
1041 | ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE(); |
1042 | // == FailIfNotLoadedOrNotRestored |
1043 | TypeHandle result = ClassLoader::LoadArrayTypeThrowing(tMergeElem, mergeKind, rank, ClassLoader::DontLoadTypes); |
1044 | _ASSERTE(!result.IsNull()); |
1045 | |
1046 | // <TODO> should be able to assert IsRestored here </TODO> |
1047 | return result; |
1048 | } |
1049 | } |
1050 | |
1051 | #endif // #ifndef DACCESS_COMPILE |
1052 | |
1053 | BOOL TypeHandle::IsEnum() const |
1054 | { |
1055 | LIMITED_METHOD_CONTRACT; |
1056 | |
1057 | return (!IsTypeDesc() && AsMethodTable()->IsEnum()); |
1058 | } |
1059 | |
1060 | BOOL TypeHandle::IsFnPtrType() const |
1061 | { |
1062 | LIMITED_METHOD_DAC_CONTRACT; |
1063 | |
1064 | return (IsTypeDesc() && |
1065 | (GetSignatureCorElementType() == ELEMENT_TYPE_FNPTR)); |
1066 | } |
1067 | |
1068 | BOOL TypeHandle::IsRestored_NoLogging() const |
1069 | { |
1070 | LIMITED_METHOD_CONTRACT; |
1071 | |
1072 | if (!IsTypeDesc()) |
1073 | { |
1074 | return GetMethodTable()->IsRestored_NoLogging(); |
1075 | } |
1076 | else |
1077 | { |
1078 | return AsTypeDesc()->IsRestored_NoLogging(); |
1079 | } |
1080 | } |
1081 | |
1082 | BOOL TypeHandle::IsRestored() const |
1083 | { |
1084 | LIMITED_METHOD_DAC_CONTRACT; |
1085 | |
1086 | if (!IsTypeDesc()) |
1087 | { |
1088 | return GetMethodTable()->IsRestored(); |
1089 | } |
1090 | else |
1091 | { |
1092 | return AsTypeDesc()->IsRestored(); |
1093 | } |
1094 | } |
1095 | |
1096 | BOOL TypeHandle::IsEncodedFixup() const |
1097 | { |
1098 | LIMITED_METHOD_DAC_CONTRACT; |
1099 | |
1100 | return CORCOMPILE_IS_POINTER_TAGGED(m_asTAddr); |
1101 | } |
1102 | |
1103 | BOOL TypeHandle::HasUnrestoredTypeKey() const |
1104 | { |
1105 | WRAPPER_NO_CONTRACT; |
1106 | SUPPORTS_DAC; |
1107 | |
1108 | if (IsTypeDesc()) |
1109 | return AsTypeDesc()->HasUnrestoredTypeKey(); |
1110 | else |
1111 | return AsMethodTable()->HasUnrestoredTypeKey(); |
1112 | } |
1113 | |
1114 | #ifdef FEATURE_PREJIT |
1115 | void TypeHandle::DoRestoreTypeKey() |
1116 | { |
1117 | CONTRACT_VOID |
1118 | { |
1119 | THROWS; |
1120 | GC_TRIGGERS; |
1121 | PRECONDITION(!IsEncodedFixup()); |
1122 | } |
1123 | CONTRACT_END |
1124 | |
1125 | #ifndef DACCESS_COMPILE |
1126 | if (IsTypeDesc()) |
1127 | { |
1128 | AsTypeDesc()->DoRestoreTypeKey(); |
1129 | } |
1130 | |
1131 | if (!IsTypeDesc() || IsArray()) |
1132 | { |
1133 | MethodTable* pMT = GetMethodTable(); |
1134 | PREFIX_ASSUME(pMT != NULL); |
1135 | pMT->DoRestoreTypeKey(); |
1136 | } |
1137 | #endif |
1138 | |
1139 | #ifdef _DEBUG |
1140 | #ifndef DACCESS_COMPILE |
1141 | if (LoggingOn(LF_CLASSLOADER, LL_INFO10000)) |
1142 | { |
1143 | StackSString name; |
1144 | TypeString::AppendTypeDebug(name, *this); |
1145 | LOG((LF_CLASSLOADER, LL_INFO10000, "GENERICS:RestoreTypeKey: type %S at %p\n" , name.GetUnicode(), AsPtr())); |
1146 | } |
1147 | #endif |
1148 | #endif |
1149 | |
1150 | |
1151 | RETURN; |
1152 | } |
1153 | #endif |
1154 | |
1155 | void TypeHandle::CheckRestore() const |
1156 | { |
1157 | CONTRACTL |
1158 | { |
1159 | if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; |
1160 | if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; |
1161 | PRECONDITION(!IsEncodedFixup()); |
1162 | } |
1163 | CONTRACTL_END |
1164 | |
1165 | if (!IsFullyLoaded()) |
1166 | { |
1167 | ClassLoader::EnsureLoaded(*this); |
1168 | _ASSERTE(IsFullyLoaded()); |
1169 | } |
1170 | |
1171 | g_IBCLogger.LogTypeMethodTableAccess(this); |
1172 | } |
1173 | |
1174 | #ifndef DACCESS_COMPILE |
1175 | |
1176 | #ifdef FEATURE_NATIVE_IMAGE_GENERATION |
1177 | BOOL TypeHandle::ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited) const |
1178 | { |
1179 | STATIC_STANDARD_VM_CONTRACT; |
1180 | |
1181 | _ASSERTE(GetAppDomain()->IsCompilationDomain()); |
1182 | |
1183 | if (!IsTypeDesc()) |
1184 | return GetMethodTable()->ComputeNeedsRestore(image, pVisited); |
1185 | else |
1186 | return AsTypeDesc()->ComputeNeedsRestore(image, pVisited); |
1187 | } |
1188 | #endif // FEATURE_NATIVE_IMAGE_GENERATION |
1189 | |
1190 | BOOL |
1191 | TypeHandle::IsExternallyVisible() const |
1192 | { |
1193 | CONTRACTL |
1194 | { |
1195 | THROWS; |
1196 | GC_TRIGGERS; |
1197 | MODE_ANY; |
1198 | } |
1199 | CONTRACTL_END |
1200 | |
1201 | if (!IsTypeDesc()) |
1202 | { |
1203 | return AsMethodTable()->IsExternallyVisible(); |
1204 | } |
1205 | |
1206 | if (IsGenericVariable()) |
1207 | { // VAR, MVAR |
1208 | return TRUE; |
1209 | } |
1210 | |
1211 | if (IsFnPtrType()) |
1212 | { // FNPTR |
1213 | // Function pointer has to check its all argument types |
1214 | return AsFnPtrType()->IsExternallyVisible(); |
1215 | } |
1216 | // ARRAY, SZARRAY, PTR, BYREF |
1217 | _ASSERTE(HasTypeParam()); |
1218 | |
1219 | TypeHandle paramType = AsTypeDesc()->GetTypeParam(); |
1220 | _ASSERTE(!paramType.IsNull()); |
1221 | |
1222 | return paramType.IsExternallyVisible(); |
1223 | } // TypeHandle::IsExternallyVisible |
1224 | |
1225 | #ifndef CROSSGEN_COMPILE |
1226 | OBJECTREF TypeHandle::GetManagedClassObject() const |
1227 | { |
1228 | CONTRACTL |
1229 | { |
1230 | THROWS; |
1231 | GC_TRIGGERS; |
1232 | MODE_COOPERATIVE; |
1233 | |
1234 | INJECT_FAULT(COMPlusThrowOM()); |
1235 | } |
1236 | CONTRACTL_END; |
1237 | |
1238 | #ifdef _DEBUG |
1239 | // Force a GC here because GetManagedClassObject could trigger GC nondeterminsticaly |
1240 | GCStress<cfg_any, PulseGcTriggerPolicy>::MaybeTrigger(); |
1241 | #endif // _DEBUG |
1242 | |
1243 | if (!IsTypeDesc()) |
1244 | { |
1245 | return AsMethodTable()->GetManagedClassObject(); |
1246 | } |
1247 | else |
1248 | { |
1249 | switch(GetInternalCorElementType()) |
1250 | { |
1251 | case ELEMENT_TYPE_ARRAY: |
1252 | case ELEMENT_TYPE_SZARRAY: |
1253 | case ELEMENT_TYPE_BYREF: |
1254 | case ELEMENT_TYPE_PTR: |
1255 | return ((ParamTypeDesc*)AsTypeDesc())->GetManagedClassObject(); |
1256 | |
1257 | case ELEMENT_TYPE_VAR: |
1258 | case ELEMENT_TYPE_MVAR: |
1259 | return ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObject(); |
1260 | |
1261 | // for this release a function pointer is mapped into an IntPtr. This result in a loss of information. Fix next release |
1262 | case ELEMENT_TYPE_FNPTR: |
1263 | return MscorlibBinder::GetElementType(ELEMENT_TYPE_I)->GetManagedClassObject(); |
1264 | |
1265 | default: |
1266 | _ASSERTE(!"Bad Element Type" ); |
1267 | return NULL; |
1268 | } |
1269 | } |
1270 | } |
1271 | |
1272 | |
1273 | OBJECTREF TypeHandle::GetManagedClassObjectFast() const |
1274 | { |
1275 | CONTRACTL { |
1276 | NOTHROW; |
1277 | GC_NOTRIGGER; |
1278 | MODE_ANY; |
1279 | SO_TOLERANT; |
1280 | |
1281 | FORBID_FAULT; |
1282 | } |
1283 | CONTRACTL_END; |
1284 | |
1285 | OBJECTREF o = NULL; |
1286 | |
1287 | if (!IsTypeDesc()) { |
1288 | o = AsMethodTable()->GetManagedClassObjectIfExists(); |
1289 | } |
1290 | else |
1291 | { |
1292 | switch(GetInternalCorElementType()) |
1293 | { |
1294 | case ELEMENT_TYPE_ARRAY: |
1295 | case ELEMENT_TYPE_SZARRAY: |
1296 | case ELEMENT_TYPE_BYREF: |
1297 | case ELEMENT_TYPE_PTR: |
1298 | o = ((ParamTypeDesc*)AsTypeDesc())->GetManagedClassObjectFast(); |
1299 | break; |
1300 | |
1301 | case ELEMENT_TYPE_VAR: |
1302 | case ELEMENT_TYPE_MVAR: |
1303 | o = ((TypeVarTypeDesc*)AsTypeDesc())->GetManagedClassObjectFast(); |
1304 | break; |
1305 | |
1306 | // for this release a function pointer is mapped into an IntPtr. This result in a loss of information. Fix next release |
1307 | case ELEMENT_TYPE_FNPTR: |
1308 | // because TheFnPtrClass() can throw we return NULL for now. That is not a major deal because it just means we will |
1309 | // not take advantage of this optimization, but the case is rather rare. |
1310 | //o = TheFnPtrClass()->GetManagedClassObjectFast(); |
1311 | break; |
1312 | |
1313 | default: |
1314 | _ASSERTE(!"Bad Element Type" ); |
1315 | return NULL; |
1316 | } |
1317 | } |
1318 | return o; |
1319 | } |
1320 | #endif // CROSSGEN_COMPILE |
1321 | |
1322 | #endif // #ifndef DACCESS_COMPILE |
1323 | |
1324 | BOOL TypeHandle::IsByRef() const |
1325 | { |
1326 | LIMITED_METHOD_CONTRACT; |
1327 | |
1328 | return(IsTypeDesc() && AsTypeDesc()->IsByRef()); |
1329 | |
1330 | } |
1331 | |
1332 | BOOL TypeHandle::IsByRefLike() const |
1333 | { |
1334 | LIMITED_METHOD_CONTRACT; |
1335 | |
1336 | return(!IsTypeDesc() && AsMethodTable()->IsByRefLike()); |
1337 | |
1338 | } |
1339 | |
1340 | BOOL TypeHandle::IsPointer() const |
1341 | { |
1342 | LIMITED_METHOD_CONTRACT; |
1343 | |
1344 | return(IsTypeDesc() && AsTypeDesc()->IsPointer()); |
1345 | |
1346 | } |
1347 | |
1348 | // |
1349 | // The internal type is the type that most of the runtime cares about. This type has had two normalizations |
1350 | // applied to it |
1351 | // |
1352 | // * Enumerated type have been normalized to the primitive type that underlies them (typically int) |
1353 | // * Value types that look like ints (which include RuntimeTypeHandles, etc), have been morphed to be |
1354 | // their underlying type (much like enumeration types. See |
1355 | // * see code:MethodTable#KindsOfElementTypes for more |
1356 | // * This value is set by code:EEClass::ComputeInternalCorElementTypeForValueType |
1357 | CorElementType TypeHandle::GetInternalCorElementType() const |
1358 | { |
1359 | LIMITED_METHOD_DAC_CONTRACT; |
1360 | |
1361 | if (IsTypeDesc()) |
1362 | return AsTypeDesc()->GetInternalCorElementType(); |
1363 | else |
1364 | return AsMethodTable()->GetInternalCorElementType(); |
1365 | } |
1366 | |
1367 | BOOL TypeHandle::HasInstantiation() const |
1368 | { |
1369 | LIMITED_METHOD_DAC_CONTRACT; |
1370 | |
1371 | if (IsTypeDesc()) return false; |
1372 | if (IsNull()) return false; |
1373 | return AsMethodTable()->HasInstantiation(); |
1374 | } |
1375 | |
1376 | ClassLoadLevel TypeHandle::GetLoadLevel() const |
1377 | { |
1378 | LIMITED_METHOD_DAC_CONTRACT; |
1379 | |
1380 | if (IsTypeDesc()) |
1381 | { |
1382 | return AsTypeDesc()->GetLoadLevel(); |
1383 | } |
1384 | else |
1385 | { |
1386 | return AsMethodTable()->GetLoadLevel(); |
1387 | } |
1388 | } |
1389 | |
1390 | BOOL TypeHandle::IsFullyLoaded() const |
1391 | { |
1392 | LIMITED_METHOD_CONTRACT; |
1393 | |
1394 | if (IsTypeDesc()) |
1395 | { |
1396 | return AsTypeDesc()->IsFullyLoaded(); |
1397 | } |
1398 | else |
1399 | { |
1400 | return AsMethodTable()->IsFullyLoaded(); |
1401 | } |
1402 | } |
1403 | |
1404 | void TypeHandle::DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level, |
1405 | DFLPendingList *pPending, BOOL *pfBailed, const InstantiationContext *pInstContext) |
1406 | { |
1407 | CONTRACTL |
1408 | { |
1409 | THROWS; |
1410 | GC_TRIGGERS; |
1411 | MODE_ANY; |
1412 | } |
1413 | CONTRACTL_END; |
1414 | |
1415 | _ASSERTE(level == CLASS_LOADED || level == CLASS_DEPENDENCIES_LOADED); |
1416 | _ASSERTE(pfBailed != NULL); |
1417 | _ASSERTE(!(level == CLASS_LOADED && pPending == NULL)); |
1418 | |
1419 | |
1420 | if (IsTypeDesc()) |
1421 | { |
1422 | return AsTypeDesc()->DoFullyLoad(pVisited, level, pPending, pfBailed, pInstContext); |
1423 | } |
1424 | else |
1425 | { |
1426 | return AsMethodTable()->DoFullyLoad(pVisited, level, pPending, pfBailed, pInstContext); |
1427 | } |
1428 | } |
1429 | |
1430 | // As its name suggests, this returns the type as it is in the meta-data signature. No morphing to deal |
1431 | // with verification or with value types that are treated as primitives is done. |
1432 | // see code:MethodTable#KindsOfElementTypes for more |
1433 | CorElementType TypeHandle::GetSignatureCorElementType() const |
1434 | { |
1435 | LIMITED_METHOD_DAC_CONTRACT; |
1436 | |
1437 | // This gets used by |
1438 | // MethodTable::DoRestoreTypeKey() --> |
1439 | // Module::RestoreMethodTablePointer() --> |
1440 | // ZapSig::DecodeType() --> |
1441 | // SigPointer::GetTypeHandleThrowing --> |
1442 | // TypeHandle::GetSignatureCorElementType |
1443 | // early on during the process of restoring, i.e. after the EEClass for the |
1444 | // MT is restored but not the parent method table. Thus we cannot |
1445 | // assume that the parent method table is even yet a valid pointer. |
1446 | // However both MethodTable::GetClass and MethodTable::IsValueType work |
1447 | // even if the parent method table pointer has not been restored. |
1448 | |
1449 | if (IsTypeDesc()) |
1450 | { |
1451 | return AsTypeDesc()->GetInternalCorElementType(); |
1452 | } |
1453 | else |
1454 | { |
1455 | return AsMethodTable()->GetSignatureCorElementType(); |
1456 | } |
1457 | } |
1458 | |
1459 | // As its name suggests, this returns the type used by the IL verifier. The basic difference between this |
1460 | // type and the type in the meta-data is that enumerations have been normalized to their underlieing |
1461 | // primitive type. see code:MethodTable#KindsOfElementTypes for more |
1462 | CorElementType TypeHandle::GetVerifierCorElementType() const |
1463 | { |
1464 | LIMITED_METHOD_CONTRACT; |
1465 | |
1466 | if (IsTypeDesc()) |
1467 | { |
1468 | return AsTypeDesc()->GetInternalCorElementType(); |
1469 | } |
1470 | else |
1471 | { |
1472 | return AsMethodTable()->GetVerifierCorElementType(); |
1473 | } |
1474 | } |
1475 | |
1476 | |
1477 | #ifdef DACCESS_COMPILE |
1478 | |
1479 | void |
1480 | TypeHandle::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) |
1481 | { |
1482 | SUPPORTS_DAC; |
1483 | if (!m_asTAddr) |
1484 | { |
1485 | return; |
1486 | } |
1487 | |
1488 | CATCH_ALL_EXCEPT_RETHROW_COR_E_OPERATIONCANCELLED |
1489 | ( |
1490 | if (IsArray()) |
1491 | { |
1492 | AsArray()->EnumMemoryRegions(flags); |
1493 | } |
1494 | else if (IsGenericVariable()) |
1495 | { |
1496 | AsGenericVariable()->EnumMemoryRegions(flags); |
1497 | } |
1498 | else if (IsFnPtrType()) |
1499 | { |
1500 | AsFnPtrType()->EnumMemoryRegions(flags); |
1501 | } |
1502 | else if (IsTypeDesc()) |
1503 | { |
1504 | DacEnumMemoryRegion(dac_cast<TADDR>(AsTypeDesc()), sizeof(TypeDesc)); |
1505 | } |
1506 | else |
1507 | { |
1508 | GetMethodTable()->EnumMemoryRegions(flags); |
1509 | } |
1510 | ); |
1511 | } |
1512 | |
1513 | #endif // DACCESS_COMPILE |
1514 | |
1515 | |
1516 | |
1517 | //-------------------------------------------------------------------------------------- |
1518 | // For generic instantiations, check that it satisfies constraints. |
1519 | // |
1520 | // Because this is really a part of DoFullyLoad() that is broken out for readability reasons, |
1521 | // it takes both the typehandle and its template typehandle as a parameter (DoFullyLoad |
1522 | // already has the latter typehandle so this way, we avoid a second call to the loader.) |
1523 | // |
1524 | // Return value: |
1525 | // |
1526 | // Returns TRUE if constraints are satisfied. |
1527 | // |
1528 | // Returns FALSE if constraints are violated and the type is a canonical instantiation. (We |
1529 | // have to let these load as these form the basis of every instantiation. The canonical |
1530 | // methodtable is not available to users. |
1531 | // |
1532 | // THROWS if constraints are violated |
1533 | // |
1534 | // |
1535 | //-------------------------------------------------------------------------------------- |
1536 | BOOL SatisfiesClassConstraints(TypeHandle instanceTypeHnd, TypeHandle typicalTypeHnd, |
1537 | const InstantiationContext *pInstContext) |
1538 | { |
1539 | CONTRACTL |
1540 | { |
1541 | THROWS; |
1542 | GC_TRIGGERS; |
1543 | PRECONDITION(!instanceTypeHnd.IsCanonicalSubtype()); |
1544 | } |
1545 | CONTRACTL_END; |
1546 | |
1547 | #ifndef DACCESS_COMPILE |
1548 | |
1549 | Instantiation formalInst = typicalTypeHnd.GetInstantiation(); |
1550 | Instantiation actualInst = instanceTypeHnd.GetInstantiation(); |
1551 | _ASSERTE(formalInst.GetNumArgs() == actualInst.GetNumArgs()); |
1552 | |
1553 | for (DWORD i = 0; i < actualInst.GetNumArgs(); i++) |
1554 | { |
1555 | TypeHandle thActualArg = actualInst[i]; |
1556 | |
1557 | SigTypeContext typeContext; |
1558 | SigTypeContext::InitTypeContext(instanceTypeHnd, &typeContext); |
1559 | |
1560 | // Log the TypeVarTypeDesc access |
1561 | g_IBCLogger.LogTypeMethodTableWriteableAccess(&thActualArg); |
1562 | |
1563 | BOOL bSatisfiesConstraints = |
1564 | formalInst[i].AsGenericVariable()->SatisfiesConstraints(&typeContext, thActualArg, pInstContext); |
1565 | |
1566 | if (!bSatisfiesConstraints) |
1567 | { |
1568 | SString argNum; |
1569 | argNum.Printf("%d" , i); |
1570 | |
1571 | SString typicalTypeHndName; |
1572 | TypeString::AppendType(typicalTypeHndName, typicalTypeHnd); |
1573 | |
1574 | SString actualParamName; |
1575 | TypeString::AppendType(actualParamName, actualInst[i]); |
1576 | |
1577 | SString formalParamName; |
1578 | TypeString::AppendType(formalParamName, formalInst[i]); |
1579 | |
1580 | COMPlusThrow(kTypeLoadException, |
1581 | IDS_EE_CLASS_CONSTRAINTS_VIOLATION, |
1582 | argNum, |
1583 | actualParamName, |
1584 | typicalTypeHndName, |
1585 | formalParamName |
1586 | ); |
1587 | } |
1588 | } |
1589 | |
1590 | return TRUE; |
1591 | |
1592 | #else |
1593 | return TRUE; |
1594 | #endif |
1595 | } |
1596 | |
1597 | |
1598 | |
1599 | |
1600 | #ifndef DACCESS_COMPILE |
1601 | BOOL TypeHandle::SatisfiesClassConstraints() const |
1602 | { |
1603 | CONTRACTL |
1604 | { |
1605 | THROWS; |
1606 | GC_TRIGGERS; |
1607 | MODE_ANY; |
1608 | SO_INTOLERANT; |
1609 | |
1610 | INJECT_FAULT(COMPlusThrowOM()); |
1611 | } |
1612 | CONTRACTL_END; |
1613 | |
1614 | BOOL returnValue = FALSE; |
1615 | Instantiation classInst; |
1616 | TypeHandle thCanonical; |
1617 | Instantiation typicalInst; |
1618 | SigTypeContext typeContext; |
1619 | TypeHandle thParent; |
1620 | |
1621 | INTERIOR_STACK_PROBE_CHECK_THREAD; |
1622 | |
1623 | //TODO: cache (positive?) result in methodtable using, say, enum_flag2_UNUSEDxxx |
1624 | |
1625 | //TODO: reconsider this check |
1626 | thParent = GetParent(); |
1627 | |
1628 | if (!thParent.IsNull() && !thParent.SatisfiesClassConstraints()) |
1629 | { |
1630 | returnValue = FALSE; |
1631 | goto Exit; |
1632 | } |
1633 | |
1634 | if (!HasInstantiation()) |
1635 | { |
1636 | returnValue = TRUE; |
1637 | goto Exit; |
1638 | } |
1639 | |
1640 | classInst = GetInstantiation(); |
1641 | thCanonical = ClassLoader::LoadTypeDefThrowing( |
1642 | GetModule(), |
1643 | GetCl(), |
1644 | ClassLoader::ThrowIfNotFound, |
1645 | ClassLoader::PermitUninstDefOrRef); |
1646 | typicalInst = thCanonical.GetInstantiation(); |
1647 | |
1648 | SigTypeContext::InitTypeContext(*this, &typeContext); |
1649 | |
1650 | for (DWORD i = 0; i < classInst.GetNumArgs(); i++) |
1651 | { |
1652 | TypeHandle thArg = classInst[i]; |
1653 | _ASSERTE(!thArg.IsNull()); |
1654 | |
1655 | TypeVarTypeDesc* tyvar = typicalInst[i].AsGenericVariable(); |
1656 | _ASSERTE(tyvar != NULL); |
1657 | _ASSERTE(TypeFromToken(tyvar->GetTypeOrMethodDef()) == mdtTypeDef); |
1658 | |
1659 | tyvar->LoadConstraints(); //TODO: is this necessary for anything but the typical class? |
1660 | |
1661 | if (!tyvar->SatisfiesConstraints(&typeContext, thArg)) |
1662 | { |
1663 | returnValue = FALSE; |
1664 | goto Exit; |
1665 | } |
1666 | |
1667 | } |
1668 | returnValue = TRUE; |
1669 | Exit: |
1670 | ; |
1671 | END_INTERIOR_STACK_PROBE; |
1672 | |
1673 | return returnValue; |
1674 | } |
1675 | |
1676 | TypeKey TypeHandle::GetTypeKey() const |
1677 | { |
1678 | LIMITED_METHOD_CONTRACT; |
1679 | STATIC_CONTRACT_SO_TOLERANT; |
1680 | PRECONDITION(!IsGenericVariable()); |
1681 | |
1682 | if (IsTypeDesc()) |
1683 | { |
1684 | TypeDesc *pTD = AsTypeDesc(); |
1685 | CorElementType etype = pTD->GetInternalCorElementType(); |
1686 | if (CorTypeInfo::IsArray_NoThrow(etype)) |
1687 | { |
1688 | TypeKey tk(etype, pTD->GetTypeParam(), FALSE, pTD->GetMethodTable()->GetRank()); |
1689 | return tk; |
1690 | } |
1691 | else if (CorTypeInfo::IsModifier_NoThrow(etype) || etype == ELEMENT_TYPE_VALUETYPE) |
1692 | { |
1693 | TypeKey tk(etype, pTD->GetTypeParam()); |
1694 | return tk; |
1695 | } |
1696 | else |
1697 | { |
1698 | CONSISTENCY_CHECK(etype == ELEMENT_TYPE_FNPTR); |
1699 | FnPtrTypeDesc* pFTD = (FnPtrTypeDesc*) pTD; |
1700 | TypeKey tk(pFTD->GetCallConv(), pFTD->GetNumArgs(), pFTD->GetRetAndArgTypesPointer()); |
1701 | return tk; |
1702 | } |
1703 | } |
1704 | else |
1705 | { |
1706 | MethodTable *pMT = AsMethodTable(); |
1707 | if (pMT->IsArray()) |
1708 | { |
1709 | TypeKey tk(pMT->GetInternalCorElementType(), pMT->GetApproxArrayElementTypeHandle(), TRUE, pMT->GetRank()); |
1710 | return tk; |
1711 | } |
1712 | else if (pMT->IsTypicalTypeDefinition()) |
1713 | { |
1714 | TypeKey tk(pMT->GetModule(), pMT->GetCl()); |
1715 | return tk; |
1716 | } |
1717 | else |
1718 | { |
1719 | TypeKey tk(pMT->GetModule(), pMT->GetCl(), pMT->GetInstantiation()); |
1720 | return tk; |
1721 | } |
1722 | } |
1723 | } |
1724 | |
1725 | |
1726 | #ifdef _DEBUG |
1727 | // Check that a type handle matches the key provided |
1728 | CHECK TypeHandle::CheckMatchesKey(TypeKey *pKey) const |
1729 | { |
1730 | WRAPPER_NO_CONTRACT; |
1731 | CONTRACT_VIOLATION(TakesLockViolation); // this is debug-only code |
1732 | CONSISTENCY_CHECK(!IsGenericVariable()); |
1733 | |
1734 | // Check first to avoid creating debug name |
1735 | if (!GetTypeKey().Equals(pKey)) |
1736 | { |
1737 | StackSString typeKeyString; |
1738 | CONTRACT_VIOLATION(GCViolation|ThrowsViolation); |
1739 | TypeString::AppendTypeKeyDebug(typeKeyString, pKey); |
1740 | if (!IsTypeDesc() && AsMethodTable()->IsArray()) |
1741 | { |
1742 | MethodTable *pMT = AsMethodTable(); |
1743 | CHECK_MSGF(pMT->GetInternalCorElementType() == pKey->GetKind(), |
1744 | ("CorElementType %d of Array MethodTable does not match key %S" , pMT->GetArrayElementType(), typeKeyString.GetUnicode())); |
1745 | |
1746 | CHECK_MSGF(pMT->GetApproxArrayElementTypeHandle() == pKey->GetElementType(), |
1747 | ("Element type of Array MethodTable does not match key %S" ,typeKeyString.GetUnicode())); |
1748 | |
1749 | CHECK_MSGF(pMT->GetRank() == pKey->GetRank(), |
1750 | ("Rank %d of Array MethodTable does not match key %S" , pMT->GetRank(), typeKeyString.GetUnicode())); |
1751 | } |
1752 | else |
1753 | if (IsTypeDesc()) |
1754 | { |
1755 | TypeDesc *pTD = AsTypeDesc(); |
1756 | CHECK_MSGF(pTD->GetInternalCorElementType() == pKey->GetKind(), |
1757 | ("CorElementType %d of TypeDesc does not match key %S" , pTD->GetInternalCorElementType(), typeKeyString.GetUnicode())); |
1758 | |
1759 | if (CorTypeInfo::IsModifier(pKey->GetKind())) |
1760 | { |
1761 | CHECK_MSGF(pTD->GetTypeParam() == pKey->GetElementType(), |
1762 | ("Element type of TypeDesc does not match key %S" ,typeKeyString.GetUnicode())); |
1763 | } |
1764 | if (CorTypeInfo::IsArray(pKey->GetKind())) |
1765 | { |
1766 | CHECK_MSGF(pTD->GetMethodTable()->GetRank() == pKey->GetRank(), |
1767 | ("Rank %d of array TypeDesc does not match key %S" , pTD->GetMethodTable()->GetRank(), typeKeyString.GetUnicode())); |
1768 | } |
1769 | } |
1770 | else |
1771 | { |
1772 | MethodTable *pMT = AsMethodTable(); |
1773 | CHECK_MSGF(pMT->GetModule() == pKey->GetModule(), ("Module of MethodTable does not match key %S" , typeKeyString.GetUnicode())); |
1774 | CHECK_MSGF(pMT->GetCl() == pKey->GetTypeToken(), |
1775 | ("TypeDef %x of Methodtable does not match TypeDef %x of key %S" , pMT->GetCl(), pKey->GetTypeToken(), |
1776 | typeKeyString.GetUnicode())); |
1777 | |
1778 | if (pMT->IsTypicalTypeDefinition()) |
1779 | { |
1780 | CHECK_MSGF(pKey->GetNumGenericArgs() == 0 && !pKey->HasInstantiation(), |
1781 | ("Key %S for Typical MethodTable has non-zero number of generic arguments" , typeKeyString.GetUnicode())); |
1782 | } |
1783 | else |
1784 | { |
1785 | CHECK_MSGF(pMT->GetNumGenericArgs() == pKey->GetNumGenericArgs(), |
1786 | ("Number of generic params %d in MethodTable does not match key %S" , pMT->GetNumGenericArgs(), typeKeyString.GetUnicode())); |
1787 | if (pKey->HasInstantiation()) |
1788 | { |
1789 | for (DWORD i = 0; i < pMT->GetNumGenericArgs(); i++) |
1790 | { |
1791 | #ifdef FEATURE_PREJIT |
1792 | CHECK_MSGF(ZapSig::CompareTypeHandleFieldToTypeHandle(pMT->GetInstantiation().GetRawArgs()[i].GetValuePtr(), pKey->GetInstantiation()[i]), |
1793 | ("Generic argument %d in MethodTable does not match key %S" , i, typeKeyString.GetUnicode())); |
1794 | #else |
1795 | CHECK_MSGF(pMT->GetInstantiation()[i] == pKey->GetInstantiation()[i], |
1796 | ("Generic argument %d in MethodTable does not match key %S" , i, typeKeyString.GetUnicode())); |
1797 | #endif |
1798 | } |
1799 | } |
1800 | } |
1801 | } |
1802 | } |
1803 | CHECK_OK; |
1804 | } |
1805 | |
1806 | const char * const classLoadLevelName[] = |
1807 | { |
1808 | "BEGIN" , |
1809 | "UNRESTOREDTYPEKEY" , |
1810 | "UNRESTORED" , |
1811 | "APPROXPARENTS" , |
1812 | "EXACTPARENTS" , |
1813 | "DEPENDENCIES_LOADED" , |
1814 | "LOADED" , |
1815 | }; |
1816 | |
1817 | // Check that this type is loaded up to the level indicated |
1818 | // Also check that it is non-null |
1819 | CHECK TypeHandle::CheckLoadLevel(ClassLoadLevel requiredLevel) |
1820 | { |
1821 | CHECK(!IsNull()); |
1822 | // CHECK_MSGF(!IsNull(), ("Type is null, required load level is %s", classLoadLevelName[requiredLevel])); |
1823 | static_assert_no_msg(NumItems(classLoadLevelName) == (1 + CLASS_LOAD_LEVEL_FINAL)); |
1824 | |
1825 | // Quick check to avoid creating debug string |
1826 | ClassLoadLevel actualLevel = GetLoadLevel(); |
1827 | if (actualLevel < requiredLevel) |
1828 | { |
1829 | // SString debugTypeName; |
1830 | // TypeString::AppendTypeDebug(debugTypeName, *this); |
1831 | CHECK(actualLevel >= requiredLevel); |
1832 | // CHECK_MSGF(actualLevel >= requiredLevel, |
1833 | // ("Type has not been sufficiently loaded (actual level is %d, required level is %d)", |
1834 | // /* debugTypeName.GetUnicode(), */ actualLevel, requiredLevel /* classLoadLevelName[actualLevel], classLoadLevelName[requiredLevel] */)); |
1835 | } |
1836 | CONSISTENCY_CHECK((actualLevel > CLASS_LOAD_UNRESTORED) == IsRestored()); |
1837 | CONSISTENCY_CHECK((actualLevel == CLASS_LOAD_UNRESTOREDTYPEKEY) == HasUnrestoredTypeKey()); |
1838 | CHECK_OK; |
1839 | } |
1840 | |
1841 | // Check that this type is fully loaded (i.e. to level CLASS_LOADED) |
1842 | CHECK TypeHandle::CheckFullyLoaded() |
1843 | { |
1844 | CONTRACTL |
1845 | { |
1846 | NOTHROW; |
1847 | GC_NOTRIGGER; |
1848 | SO_TOLERANT; |
1849 | MODE_ANY; |
1850 | } |
1851 | CONTRACTL_END; |
1852 | if (IsGenericVariable()) |
1853 | { |
1854 | CHECK_OK; |
1855 | } |
1856 | CheckLoadLevel(CLASS_LOADED); |
1857 | CHECK_OK; |
1858 | } |
1859 | |
1860 | #endif //DEBUG |
1861 | |
1862 | #endif //DACCESS_COMPILE |
1863 | |