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.h |
6 | // |
7 | |
8 | |
9 | // |
10 | |
11 | // |
12 | // ============================================================================ |
13 | |
14 | |
15 | #ifndef TYPEHANDLE_H |
16 | #define TYPEHANDLE_H |
17 | |
18 | #include "check.h" |
19 | #include "classloadlevel.h" |
20 | #include "fixuppointer.h" |
21 | |
22 | class TypeDesc; |
23 | class TypeHandle; |
24 | class Instantiation; |
25 | class ArrayTypeDesc; |
26 | class FnPtrTypeDesc; |
27 | class ParamTypeDesc; |
28 | class TypeVarTypeDesc; |
29 | class MethodTable; |
30 | class EEClass; |
31 | class Module; |
32 | class Assembly; |
33 | class BaseDomain; |
34 | class MethodDesc; |
35 | class TypeKey; |
36 | class TypeHandleList; |
37 | class InstantiationContext; |
38 | class DataImage; |
39 | namespace Generics { class RecursionGraph; } |
40 | struct CORINFO_CLASS_STRUCT_; |
41 | |
42 | typedef DPTR(class TypeVarTypeDesc) PTR_TypeVarTypeDesc; |
43 | typedef SPTR(class FnPtrTypeDesc) PTR_FnPtrTypeDesc; |
44 | typedef DPTR(class ParamTypeDesc) PTR_ParamTypeDesc; |
45 | typedef DPTR(class ArrayTypeDesc) PTR_ArrayTypeDesc; |
46 | typedef DPTR(class TypeDesc) PTR_TypeDesc; |
47 | typedef DPTR(class TypeHandle) PTR_TypeHandle; |
48 | |
49 | |
50 | typedef CUnorderedArray<TypeHandle, 40> DFLPendingList; |
51 | |
52 | class TypeHandlePairList; |
53 | |
54 | #ifdef FEATURE_COMINTEROP |
55 | class ComCallWrapperTemplate; |
56 | #endif // FEATURE_COMINTEROP |
57 | |
58 | /*************************************************************************/ |
59 | // A TypeHandle is the FUNDAMENTAL concept of type identity in the CLR. |
60 | // That is two types are equal if and only if their type handles |
61 | // are equal. A TypeHandle, is a pointer sized struture that encodes |
62 | // everything you need to know to figure out what kind of type you are |
63 | // actually dealing with. |
64 | |
65 | // At the present time a TypeHandle can point at two possible things |
66 | // |
67 | // 1) A MethodTable (Intrinsics, Classes, Value Types and their instantiations) |
68 | // 2) A TypeDesc (all other cases: arrays, byrefs, pointer types, function pointers, generic type variables) |
69 | // |
70 | // or with IL stubs, a third thing: |
71 | // |
72 | // 3) A MethodTable for a native value type. |
73 | // |
74 | // Array MTs are not valid TypeHandles: for example no allocated object will |
75 | // ever return such a type handle from Object::GetTypeHandle(), and |
76 | // these type handles should not be passed across the JIT Interface |
77 | // as CORINFO_CLASS_HANDLEs. However some code in the EE does create |
78 | // temporary TypeHandles out of these MTs, so we can't yet assert |
79 | // !pMT->IsArray() in the TypeHandle constructor. |
80 | // |
81 | // Wherever possible, you should be using TypeHandles or MethodTables. |
82 | // Code that is known to work over Class/ValueClass types (including their |
83 | // instantaitions) is currently written to use MethodTables. |
84 | // |
85 | // TypeDescs in turn break down into several variants and are |
86 | // for special cases around the edges |
87 | // - array types whose method tables get share |
88 | // - types for function pointers for verification and reflection |
89 | // - types for generic parameters for verification and reflection |
90 | // |
91 | // Generic type instantiations (in C# syntax: C<ty_1,...,ty_n>) are represented by |
92 | // MethodTables, i.e. a new MethodTable gets allocated for each such instantiation. |
93 | // The entries in these tables (i.e. the code) are, however, often shared. |
94 | // Clients of TypeHandle don't need to know any of this detail; just use the |
95 | // GetInstantiation and HasInstantiation methods. |
96 | |
97 | class TypeHandle |
98 | { |
99 | public: |
100 | TypeHandle() { |
101 | LIMITED_METHOD_DAC_CONTRACT; |
102 | |
103 | m_asTAddr = 0; |
104 | } |
105 | |
106 | static TypeHandle FromPtr(PTR_VOID aPtr) |
107 | { |
108 | LIMITED_METHOD_DAC_CONTRACT; |
109 | |
110 | return TypeHandle(dac_cast<TADDR>(aPtr)); |
111 | } |
112 | // Create a TypeHandle from the target address of a MethodTable |
113 | static TypeHandle FromTAddr(TADDR data) |
114 | { |
115 | LIMITED_METHOD_DAC_CONTRACT; |
116 | |
117 | return TypeHandle(data); |
118 | } |
119 | |
120 | // When you ask for a class in JitInterface when all you have |
121 | // is a methodDesc of an array method... |
122 | // Convert from a JitInterface handle to an internal EE TypeHandle |
123 | explicit TypeHandle(struct CORINFO_CLASS_STRUCT_*aPtr) |
124 | { |
125 | LIMITED_METHOD_DAC_CONTRACT; |
126 | |
127 | m_asTAddr = dac_cast<TADDR>(aPtr); |
128 | // NormalizeUnsharedArrayMT(); |
129 | INDEBUGIMPL(Verify()); |
130 | } |
131 | |
132 | TypeHandle(MethodTable const * aMT) { |
133 | LIMITED_METHOD_DAC_CONTRACT; |
134 | |
135 | m_asTAddr = dac_cast<TADDR>(aMT); |
136 | // NormalizeUnsharedArrayMT(); |
137 | INDEBUGIMPL(Verify()); |
138 | } |
139 | |
140 | explicit TypeHandle(TypeDesc *aType) { |
141 | LIMITED_METHOD_DAC_CONTRACT; |
142 | _ASSERTE(aType); |
143 | |
144 | m_asTAddr = (dac_cast<TADDR>(aType) | 2); |
145 | INDEBUGIMPL(Verify()); |
146 | } |
147 | |
148 | inline BOOL IsNativeValueType() const; |
149 | inline MethodTable *AsNativeValueType() const; |
150 | |
151 | private: |
152 | // This constructor has been made private. You must use the explicit static functions |
153 | // TypeHandle::FromPtr and TypeHandle::TAddr instead of these constructors. |
154 | // Allowing a public constructor that takes a "void *" or a "TADDR" is error-prone. |
155 | explicit TypeHandle(TADDR aTAddr) |
156 | { |
157 | LIMITED_METHOD_DAC_CONTRACT; |
158 | m_asTAddr = aTAddr; |
159 | // NormalizeUnsharedArrayMT(); |
160 | INDEBUGIMPL(Verify()); |
161 | } |
162 | |
163 | |
164 | public: |
165 | FORCEINLINE int operator==(const TypeHandle& typeHnd) const { |
166 | LIMITED_METHOD_DAC_CONTRACT; |
167 | |
168 | return(m_asTAddr == typeHnd.m_asTAddr); |
169 | } |
170 | |
171 | FORCEINLINE int operator!=(const TypeHandle& typeHnd) const { |
172 | LIMITED_METHOD_DAC_CONTRACT; |
173 | |
174 | return(m_asTAddr != typeHnd.m_asTAddr); |
175 | } |
176 | |
177 | // Methods for probing exactly what kind of a type handle we have |
178 | FORCEINLINE BOOL IsNull() const { |
179 | LIMITED_METHOD_DAC_CONTRACT; |
180 | #ifdef _PREFIX_ |
181 | if (m_asTAddr == 0) { |
182 | #ifndef DACCESS_COMPILE |
183 | PREFIX_ASSUME(m_asPtr == NULL); |
184 | #endif |
185 | return true; |
186 | } |
187 | else { |
188 | #ifndef DACCESS_COMPILE |
189 | PREFIX_ASSUME(m_asPtr != NULL); |
190 | #endif |
191 | return false; |
192 | } |
193 | #else |
194 | return(m_asTAddr == 0); |
195 | #endif |
196 | } |
197 | |
198 | // Note that this returns denormalized BOOL to help the compiler with optimizations |
199 | FORCEINLINE BOOL IsTypeDesc() const { |
200 | LIMITED_METHOD_DAC_CONTRACT; |
201 | #ifdef _PREFIX_ |
202 | if (m_asTAddr & 2) { |
203 | PREFIX_ASSUME(m_asTAddr != NULL); |
204 | #ifndef DACCESS_COMPILE |
205 | PREFIX_ASSUME(m_asPtr != NULL); |
206 | #endif |
207 | return true; |
208 | } |
209 | else { |
210 | return false; |
211 | } |
212 | #else |
213 | return(m_asTAddr & 2); |
214 | #endif |
215 | } |
216 | |
217 | BOOL IsEnum() const; |
218 | |
219 | BOOL IsFnPtrType() const; |
220 | |
221 | inline PTR_MethodTable AsMethodTable() const; |
222 | |
223 | inline PTR_TypeDesc AsTypeDesc() const; |
224 | |
225 | // To the extent possible, you should try to use methods like the ones |
226 | // below that treat all types uniformly. |
227 | |
228 | // Gets the size that this type would take up embedded in another object |
229 | // thus objects all return sizeof(void*). |
230 | unsigned GetSize() const; |
231 | |
232 | // Returns the type name, including the generic instantiation if possible. |
233 | // See the TypeString class for better control over name formatting. |
234 | void GetName(SString &result) const; |
235 | |
236 | // Returns the ELEMENT_TYPE_* that you would use in a signature |
237 | // The only normalization that happens is that for type handles |
238 | // for instantiated types (e.g. class List<String> or |
239 | // value type Pair<int,int>)) this returns either ELEMENT_TYPE_CLASS |
240 | // or ELEMENT_TYPE_VALUE, _not_ ELEMENT_TYPE_WITH. |
241 | CorElementType GetSignatureCorElementType() const; |
242 | |
243 | // This helper: |
244 | // - Will return enums underlying type |
245 | // - Will return underlying primitive for System.Int32 etc... |
246 | // - Will return underlying primitive as will be used in the calling convention |
247 | // For example |
248 | // struct t |
249 | // { |
250 | // public int i; |
251 | // } |
252 | // will return ELEMENT_TYPE_I4 in x86 instead of ELEMENT_TYPE_VALUETYPE. We |
253 | // call this type of value type a primitive value type |
254 | // |
255 | // Internal representation is used among another things for the calling convention |
256 | // (jit benefits of primitive value types) or optimizing marshalling. |
257 | // |
258 | // This will NOT convert E_T_ARRAY, E_T_SZARRAY etc. to E_T_CLASS (though it probably |
259 | // should). Use CorTypeInfo::IsObjRef for that. |
260 | CorElementType GetInternalCorElementType() const; |
261 | |
262 | // This helper will return the same as GetSignatureCorElementType except: |
263 | // - Will return enums underlying type |
264 | CorElementType GetVerifierCorElementType() const; |
265 | |
266 | //------------------------------------------------------------------- |
267 | // CASTING |
268 | // |
269 | // There are two variants of the "CanCastTo" method: |
270 | // |
271 | // CanCastTo |
272 | // - restore encoded pointers on demand |
273 | // - might throw, might trigger GC |
274 | // - return type is boolean (FALSE = cannot cast, TRUE = can cast) |
275 | // |
276 | // CanCastToNoGC |
277 | // - do not restore encoded pointers on demand |
278 | // - does not throw, does not trigger GC |
279 | // - return type is three-valued (CanCast, CannotCast, MaybeCast) |
280 | // - MaybeCast indicates that the test tripped on an encoded pointer |
281 | // so the caller should now call CanCastTo if it cares |
282 | // |
283 | // Note that if the TypeHandle is a valuetype, the caller is responsible |
284 | // for checking that the valuetype is in its boxed form before calling |
285 | // CanCastTo. Otherwise, the caller should be using IsBoxedAndCanCastTo() |
286 | typedef enum { CannotCast, CanCast, MaybeCast } CastResult; |
287 | |
288 | BOOL CanCastTo(TypeHandle type, TypeHandlePairList *pVisited = NULL) const; |
289 | BOOL IsBoxedAndCanCastTo(TypeHandle type, TypeHandlePairList *pVisited) const; |
290 | CastResult CanCastToNoGC(TypeHandle type) const; |
291 | |
292 | #ifndef DACCESS_COMPILE |
293 | // Type equivalence based on Guid and TypeIdentifier attributes |
294 | inline BOOL IsEquivalentTo(TypeHandle type COMMA_INDEBUG(TypeHandlePairList *pVisited = NULL)) const; |
295 | #endif |
296 | |
297 | // Get the parent, known to be decoded |
298 | TypeHandle GetParent() const; |
299 | |
300 | // Obtain element type for an array or pointer, returning NULL otherwise |
301 | TypeHandle GetTypeParam() const; |
302 | |
303 | // Obtain instantiation from an instantiated type |
304 | // NULL if not instantiated |
305 | Instantiation GetInstantiation() const; |
306 | |
307 | // Does this type satisfy its class constraints, recursively up the hierarchy |
308 | BOOL SatisfiesClassConstraints() const; |
309 | |
310 | TypeHandle Instantiate(Instantiation inst) const; |
311 | TypeHandle MakePointer() const; |
312 | TypeHandle MakeByRef() const; |
313 | TypeHandle MakeSZArray() const; |
314 | TypeHandle MakeArray(int rank) const; |
315 | TypeHandle MakeNativeValueType() const; |
316 | |
317 | // Obtain instantiation from an instantiated type *or* a pointer to the element type for an array |
318 | Instantiation GetClassOrArrayInstantiation() const; |
319 | |
320 | // Is this type instantiated? |
321 | BOOL HasInstantiation() const; |
322 | |
323 | // Is this a generic type whose type arguments are its formal type parameters? |
324 | BOOL IsGenericTypeDefinition() const; |
325 | |
326 | // Is this either a non-generic type (e.g. a non-genric class type or an array type or a pointer type etc.) |
327 | // or a generic type whose type arguments are its formal type parameters? |
328 | //Equivalent to (!HasInstantiation() || IsGenericTypeDefinition()); |
329 | inline BOOL IsTypicalTypeDefinition() const; |
330 | |
331 | enum InteropKind |
332 | { |
333 | Interop_ManagedToNative, // use for RCW-related queries |
334 | Interop_NativeToManaged, // use for CCW-related queries |
335 | }; |
336 | |
337 | inline BOOL SupportsGenericInterop(InteropKind interopKind) const; |
338 | |
339 | BOOL IsSharedByGenericInstantiations() const; |
340 | |
341 | // Recursively search the type arguments and if |
342 | // one of the type arguments is Canon then return TRUE |
343 | // |
344 | // A<__Canon> is the canonical TypeHandle (aka "representative" generic MT) |
345 | // A<B<__Canon>> is a subtype that contains a Canonical type |
346 | // |
347 | BOOL IsCanonicalSubtype() const; |
348 | |
349 | // Similar to IsCanonicalSubtype, but applied to a vector. |
350 | static BOOL IsCanonicalSubtypeInstantiation(Instantiation inst); |
351 | |
352 | // For an uninstantiated generic type, return the number of type parameters required for instantiation |
353 | // For an instantiated type, return the number of type parameters in the instantiation |
354 | // Otherwise return 0 |
355 | DWORD GetNumGenericArgs() const; |
356 | |
357 | BOOL IsValueType() const; |
358 | BOOL IsInterface() const; |
359 | BOOL IsAbstract() const; |
360 | |
361 | inline DWORD IsObjectType() const |
362 | { |
363 | LIMITED_METHOD_CONTRACT; |
364 | return *this == TypeHandle(g_pObjectClass); |
365 | } |
366 | |
367 | // Retrieve the key corresponding to this handle |
368 | TypeKey GetTypeKey() const; |
369 | |
370 | // To what level has this type been loaded? |
371 | ClassLoadLevel GetLoadLevel() const; |
372 | |
373 | // Equivalent to GetLoadLevel() == CLASS_LOADED |
374 | BOOL IsFullyLoaded() const; |
375 | |
376 | void DoFullyLoad(Generics::RecursionGraph *pVisited, ClassLoadLevel level, DFLPendingList *pPending, BOOL *pfBailed, |
377 | const InstantiationContext *pInstContext); |
378 | |
379 | inline void SetIsFullyLoaded(); |
380 | |
381 | |
382 | #ifdef _DEBUG |
383 | // Check that this type matches the key given |
384 | // i.e. that all aspects (element type, module/token, rank for arrays, instantiation for generic types) match up |
385 | CHECK CheckMatchesKey(TypeKey *pKey) const; |
386 | |
387 | // Check that this type is loaded up to the level indicated |
388 | // Also check that it is non-null |
389 | CHECK CheckLoadLevel(ClassLoadLevel level); |
390 | |
391 | // Equivalent to CheckLoadLevel(CLASS_LOADED) |
392 | CHECK CheckFullyLoaded(); |
393 | #endif |
394 | |
395 | bool IsHFA() const; |
396 | CorElementType GetHFAType() const; |
397 | |
398 | #ifdef FEATURE_64BIT_ALIGNMENT |
399 | bool RequiresAlign8() const; |
400 | #endif // FEATURE_64BIT_ALIGNMENT |
401 | |
402 | #ifndef DACCESS_COMPILE |
403 | |
404 | BOOL IsBlittable() const; |
405 | BOOL HasLayout() const; |
406 | |
407 | #ifdef FEATURE_COMINTEROP |
408 | TypeHandle GetCoClassForInterface() const; |
409 | DWORD IsComClassInterface() const; |
410 | BOOL IsComObjectType() const; |
411 | BOOL IsComEventItfType() const; |
412 | CorIfaceAttr GetComInterfaceType() const; |
413 | TypeHandle GetDefItfForComClassItf() const; |
414 | |
415 | BOOL IsProjectedFromWinRT() const; |
416 | BOOL IsExportedToWinRT() const; |
417 | |
418 | ComCallWrapperTemplate *GetComCallWrapperTemplate() const; |
419 | BOOL SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate); |
420 | #endif // FEATURE_COMINTEROP |
421 | |
422 | #endif |
423 | |
424 | // Unlike AsMethodTable, GetMethodTable will get the method table |
425 | // of the type, regardless of whether it is an array etc. Note, however |
426 | // this method table may be shared, and some types (like TypeByRef), have |
427 | // no method table (and this function returns NULL for them) |
428 | inline PTR_MethodTable GetMethodTable() const; |
429 | |
430 | // Returns the method table which should be used for visibility checking. |
431 | // Like GetMethodTable except for TypeDescs returns the root ElementType. |
432 | // So for Foo[] instead of returning Array returns Foo. |
433 | inline MethodTable* GetMethodTableOfElementType() const; |
434 | |
435 | // Returns the MethodTable for the SZARRAY or ARRAY type |
436 | inline MethodTable * GetPossiblySharedArrayMethodTable() const; |
437 | |
438 | // As above but returns a TypeHandle (so it will return a non-null result |
439 | // for generic type variables, for instance). |
440 | inline TypeHandle GetElementType() const; |
441 | |
442 | // Return the canonical representative MT amongst the set of MT's that share |
443 | // code with the MT for the given TypeHandle because of generics. |
444 | PTR_MethodTable GetCanonicalMethodTable() const; |
445 | |
446 | // The module that defined the underlying type |
447 | // (First strip off array/ptr qualifiers and generic type arguments) |
448 | PTR_Module GetModule() const; |
449 | |
450 | // The ngen'ed module where this type lives |
451 | PTR_Module GetZapModule() const; |
452 | |
453 | // Does this immediate item live in an NGEN module? |
454 | BOOL IsZapped() const; |
455 | |
456 | // The module where this type lives for the purposes of loading and prejitting |
457 | // Note: NGen time result might differ from runtime result for parametrized types (generics, arrays, etc.) |
458 | // See code:ClassLoader::ComputeLoaderModule or file:clsload.hpp#LoaderModule for more information |
459 | PTR_Module GetLoaderModule() const; |
460 | |
461 | // The assembly that defined this type (== GetModule()->GetAssembly()) |
462 | Assembly * GetAssembly() const; |
463 | |
464 | // GetDomain on an instantiated type, e.g. C<ty1,ty2> returns the SharedDomain if all the |
465 | // constituent parts of the type are SharedDomain (i.e. domain-neutral), |
466 | // and returns an AppDomain if any of the parts are from an AppDomain, |
467 | // i.e. are domain-bound. If any of the parts are domain-bound |
468 | // then they will all belong to the same domain. |
469 | PTR_BaseDomain GetDomain() const; |
470 | |
471 | PTR_LoaderAllocator GetLoaderAllocator() const; |
472 | |
473 | // Get the class token, assuming the type handle represents a named type, |
474 | // i.e. a class, a value type, a generic instantiation etc. |
475 | inline mdTypeDef GetCl() const; |
476 | |
477 | // Shortcuts |
478 | |
479 | // ARRAY or SZARRAY TypeDesc (arrays with a shared MethodTable) |
480 | // If this is TRUE, it is OK to call AsArray() |
481 | // Also see IsArrayType() |
482 | BOOL IsArray() const; |
483 | |
484 | // See comment of IsArrayType() for the explanation of this method |
485 | #if 0 |
486 | void NormalizeUnsharedArrayMT(); |
487 | #endif |
488 | |
489 | // ARRAY or SZARRAY |
490 | // Note that this does not imply that it is OK to call AsArray(). See IsArray() |
491 | // |
492 | // All arrays, even those with a unique unshared MethodTable, have an ArrayTypeDesc |
493 | // which is used for type identity. However, over time, people have started |
494 | // wrapping the MethodTables directly in a TypeHandle. Note that such |
495 | // TypeHandles cannot be used for type identity. However, IsArrayType() lets |
496 | // you check even for such cases where IsArray() returns FALSE, but the type |
497 | // still is an array type. |
498 | // |
499 | // @TODO: Change all the constructors of TypeHandle which take a MethodTable |
500 | // to call NormalizeUnsharedArrayMT(). TypeHandle::Verify() can then enforce |
501 | // that IsArray() is fully correct. |
502 | BOOL IsArrayType() const; |
503 | |
504 | // VAR or MVAR |
505 | BOOL IsGenericVariable() const; |
506 | |
507 | // BYREF |
508 | BOOL IsByRef() const; |
509 | |
510 | // BYREFLIKE (does not return TRUE for IsByRef types) |
511 | BOOL IsByRefLike() const; |
512 | |
513 | // PTR |
514 | BOOL IsPointer() const; |
515 | |
516 | // True if this type *is* a formal generic type parameter or any component of it is a formal generic type parameter |
517 | BOOL ContainsGenericVariables(BOOL methodOnly=FALSE) const; |
518 | |
519 | Module* GetDefiningModuleForOpenType() const; |
520 | |
521 | // Is actually ParamTypeDesc (ARRAY, SZARRAY, BYREF, PTR) |
522 | BOOL HasTypeParam() const; |
523 | |
524 | BOOL IsRestored_NoLogging() const; |
525 | BOOL IsRestored() const; |
526 | |
527 | // Does this type have zap-encoded components (generic arguments, etc)? |
528 | BOOL HasUnrestoredTypeKey() const; |
529 | |
530 | // True if this type handle is a zap-encoded fixup |
531 | BOOL IsEncodedFixup() const; |
532 | |
533 | // Only used at NGEN-time |
534 | BOOL ComputeNeedsRestore(DataImage *image, TypeHandleList *pVisited) const; |
535 | |
536 | void DoRestoreTypeKey(); |
537 | |
538 | void CheckRestore() const; |
539 | BOOL IsExternallyVisible() const; |
540 | |
541 | // Does this type participate in type equivalence? |
542 | inline BOOL HasTypeEquivalence() const; |
543 | |
544 | // Not clear we should have this. |
545 | inline PTR_ArrayTypeDesc AsArray() const; |
546 | |
547 | FnPtrTypeDesc* AsFnPtrType() const; |
548 | |
549 | TypeVarTypeDesc* AsGenericVariable() const; |
550 | |
551 | Instantiation GetInstantiationOfParentClass(MethodTable *pWhichParent) const; |
552 | |
553 | PTR_VOID AsPtr() const { // Please don't use this if you can avoid it |
554 | LIMITED_METHOD_DAC_CONTRACT; |
555 | |
556 | return(PTR_VOID(m_asTAddr)); |
557 | } |
558 | |
559 | TADDR AsTAddr() const { |
560 | LIMITED_METHOD_DAC_CONTRACT; |
561 | |
562 | return m_asTAddr; |
563 | } |
564 | |
565 | INDEBUGIMPL(BOOL Verify();) // DEBUGGING Make certain this is a valid type handle |
566 | |
567 | #ifdef DACCESS_COMPILE |
568 | void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); |
569 | #endif |
570 | |
571 | OBJECTREF GetManagedClassObject() const; |
572 | OBJECTREF GetManagedClassObjectFast() const; |
573 | |
574 | static TypeHandle MergeArrayTypeHandlesToCommonParent( |
575 | TypeHandle ta, TypeHandle tb); |
576 | |
577 | static TypeHandle MergeTypeHandlesToCommonParent( |
578 | TypeHandle ta, TypeHandle tb); |
579 | |
580 | |
581 | BOOL NotifyDebuggerLoad(AppDomain *domain, BOOL attaching) const; |
582 | void NotifyDebuggerUnload(AppDomain *domain) const; |
583 | |
584 | // Execute the callback functor for each MethodTable that makes up the given type handle. This method |
585 | // does not invoke the functor for generic variables |
586 | template<class T> |
587 | inline void ForEachComponentMethodTable(T &callback) const; |
588 | |
589 | private: |
590 | static TypeHandle MergeClassWithInterface( |
591 | TypeHandle tClass, TypeHandle tInterface); |
592 | |
593 | union |
594 | { |
595 | TADDR m_asTAddr; // we look at the low order bits |
596 | #ifndef DACCESS_COMPILE |
597 | void * m_asPtr; |
598 | PTR_MethodTable m_asMT; |
599 | PTR_TypeDesc m_asTypeDesc; |
600 | PTR_ArrayTypeDesc m_asArrayTypeDesc; |
601 | PTR_ParamTypeDesc m_asParamTypeDesc; |
602 | PTR_TypeVarTypeDesc m_asTypeVarTypeDesc; |
603 | PTR_FnPtrTypeDesc m_asFnPtrTypeDesc; |
604 | #endif |
605 | }; |
606 | }; |
607 | |
608 | class TypeHandleList |
609 | { |
610 | TypeHandle m_typeHandle; |
611 | TypeHandleList* m_pNext; |
612 | bool m_fBrokenCycle; |
613 | public: |
614 | TypeHandleList(TypeHandle t, TypeHandleList* pNext) : m_typeHandle(t),m_pNext(pNext),m_fBrokenCycle(false) { }; |
615 | static BOOL Exists(TypeHandleList* pList, TypeHandle t) |
616 | { |
617 | LIMITED_METHOD_CONTRACT; |
618 | while (pList != NULL) { if (pList->m_typeHandle == t) return TRUE; pList = pList->m_pNext; } |
619 | return FALSE; |
620 | } |
621 | |
622 | // Supports enumeration of the list. |
623 | static BOOL GetNext(TypeHandleList** ppList, TypeHandle* pHandle) |
624 | { |
625 | LIMITED_METHOD_CONTRACT; |
626 | if (*ppList != NULL) |
627 | { |
628 | *pHandle = (*ppList)->m_typeHandle; |
629 | (*ppList) = (*ppList)->m_pNext; |
630 | return TRUE; |
631 | } |
632 | return FALSE; |
633 | } |
634 | |
635 | void MarkBrokenCycle(TypeHandle th) |
636 | { |
637 | LIMITED_METHOD_CONTRACT; |
638 | TypeHandleList* pList = this; |
639 | while (pList->m_typeHandle != th) { pList->m_fBrokenCycle = true; pList = pList->m_pNext; } |
640 | } |
641 | bool HasBrokenCycleMark() |
642 | { |
643 | LIMITED_METHOD_CONTRACT; |
644 | return m_fBrokenCycle; |
645 | } |
646 | }; |
647 | |
648 | class TypeHandlePairList // TODO: Template for TypeHandleList, TypeHandlePairList, TokenPairList? |
649 | { |
650 | TypeHandle m_typeHandle1; |
651 | TypeHandle m_typeHandle2; |
652 | TypeHandlePairList *m_pNext; |
653 | public: |
654 | TypeHandlePairList(TypeHandle t1, TypeHandle t2, TypeHandlePairList *pNext) : m_typeHandle1(t1), m_typeHandle2(t2), m_pNext(pNext) { }; |
655 | static BOOL Exists(TypeHandlePairList *pList, TypeHandle t1, TypeHandle t2) |
656 | { |
657 | LIMITED_METHOD_CONTRACT; |
658 | while (pList != NULL) |
659 | { |
660 | if (pList->m_typeHandle1 == t1 && pList->m_typeHandle2 == t2) |
661 | return TRUE; |
662 | if (pList->m_typeHandle1 == t2 && pList->m_typeHandle2 == t1) |
663 | return TRUE; |
664 | |
665 | pList = pList->m_pNext; |
666 | } |
667 | return FALSE; |
668 | } |
669 | }; |
670 | |
671 | #if CHECK_INVARIANTS |
672 | inline CHECK CheckPointer(TypeHandle th, IsNullOK ok = NULL_NOT_OK) |
673 | { |
674 | STATIC_CONTRACT_NOTHROW; |
675 | STATIC_CONTRACT_GC_NOTRIGGER; |
676 | STATIC_CONTRACT_FORBID_FAULT; |
677 | STATIC_CONTRACT_SO_TOLERANT; |
678 | SUPPORTS_DAC; |
679 | STATIC_CONTRACT_CANNOT_TAKE_LOCK; |
680 | |
681 | if (th.IsNull()) |
682 | { |
683 | CHECK_MSG(ok, "Illegal null TypeHandle" ); |
684 | } |
685 | else |
686 | { |
687 | __if_exists(TypeHandle::Check) |
688 | { |
689 | CHECK(th.Check()); |
690 | } |
691 | #if 0 |
692 | CHECK(CheckInvariant(o)); |
693 | #endif |
694 | } |
695 | |
696 | CHECK_OK; |
697 | } |
698 | |
699 | #endif // CHECK_INVARIANTS |
700 | |
701 | /*************************************************************************/ |
702 | // dac_casts for TypeHandle makes FixupPointer<TypeHandle> work. |
703 | // |
704 | // TypeHandle is wrapper around pointer to MethodTable or TypeDesc. Even though |
705 | // it may feel counterintuitive, it is possible to treat it like a pointer and |
706 | // use the regular FixupPointer to implement TypeHandle indirection cells. |
707 | // The lowest bit of TypeHandle (when wrapped inside FixupPointer) is |
708 | // used to mark optional indirection. |
709 | // |
710 | template<> |
711 | inline TADDR dac_cast(TypeHandle src) |
712 | { |
713 | SUPPORTS_DAC; |
714 | return src.AsTAddr(); |
715 | } |
716 | |
717 | template<> |
718 | inline TypeHandle dac_cast(TADDR src) |
719 | { |
720 | SUPPORTS_DAC; |
721 | return TypeHandle::FromTAddr(src); |
722 | } |
723 | |
724 | /*************************************************************************/ |
725 | // Instantiation is representation of generic instantiation. |
726 | // It is simple read-only array of TypeHandles. In NGen, the type handles |
727 | // may be encoded using indirections. That's one reason why it is convenient |
728 | // to have wrapper class that performs the decoding. |
729 | class Instantiation |
730 | { |
731 | public: |
732 | // Construct empty instantiation |
733 | Instantiation() |
734 | : m_pArgs(NULL), m_nArgs(0) |
735 | { |
736 | LIMITED_METHOD_DAC_CONTRACT; |
737 | } |
738 | |
739 | // Copy construct |
740 | Instantiation(const Instantiation & inst) |
741 | : m_pArgs(inst.m_pArgs), m_nArgs(inst.m_nArgs) |
742 | { |
743 | LIMITED_METHOD_DAC_CONTRACT; |
744 | _ASSERTE(m_nArgs == 0 || m_pArgs != NULL); |
745 | } |
746 | |
747 | // Construct instantiation from array of FixupPointers |
748 | Instantiation(FixupPointer<TypeHandle> * pArgs, DWORD nArgs) |
749 | : m_pArgs(pArgs), m_nArgs(nArgs) |
750 | { |
751 | LIMITED_METHOD_DAC_CONTRACT; |
752 | _ASSERTE(m_nArgs == 0 || m_pArgs != NULL); |
753 | } |
754 | |
755 | // Construct instantiation from array of TypeHandles |
756 | Instantiation(TypeHandle * pArgs, DWORD nArgs) |
757 | : m_nArgs(nArgs) |
758 | { |
759 | LIMITED_METHOD_DAC_CONTRACT; |
760 | |
761 | DACCOP_IGNORE(CastOfMarshalledType, "Dual mode DAC problem, but since the size is the same, the cast is safe" ); |
762 | m_pArgs = (FixupPointer<TypeHandle> *)pArgs; |
763 | _ASSERTE(m_nArgs == 0 || m_pArgs != NULL); |
764 | } |
765 | |
766 | #ifdef DACCESS_COMPILE |
767 | // Construct instantiation from target array of FixupPointers in DAC. |
768 | // This method will create local copy of the instantiation arguments. |
769 | Instantiation(DPTR(FixupPointer<TypeHandle>) pArgs, DWORD nArgs) |
770 | { |
771 | LIMITED_METHOD_DAC_CONTRACT; |
772 | |
773 | // Create a local copy of the instanitation under DAC |
774 | PVOID pLocalArgs = PTR_READ(dac_cast<TADDR>(pArgs), nArgs * sizeof(TypeHandle)); |
775 | m_pArgs = (FixupPointer<TypeHandle> *)pLocalArgs; |
776 | |
777 | m_nArgs = nArgs; |
778 | |
779 | _ASSERTE(m_nArgs == 0 || m_pArgs != NULL); |
780 | } |
781 | #endif |
782 | |
783 | // Return i-th instantiation argument |
784 | TypeHandle operator[](DWORD iArg) const |
785 | { |
786 | LIMITED_METHOD_DAC_CONTRACT; |
787 | _ASSERTE(iArg < m_nArgs); |
788 | return m_pArgs[iArg].GetValue(); |
789 | } |
790 | |
791 | DWORD GetNumArgs() const |
792 | { |
793 | LIMITED_METHOD_DAC_CONTRACT; |
794 | return m_nArgs; |
795 | } |
796 | |
797 | BOOL IsEmpty() const |
798 | { |
799 | LIMITED_METHOD_DAC_CONTRACT; |
800 | return m_nArgs == 0; |
801 | } |
802 | |
803 | // Unsafe access to the instantiation. Do not use unless absolutely necessary!!! |
804 | FixupPointer<TypeHandle> * GetRawArgs() const |
805 | { |
806 | LIMITED_METHOD_DAC_CONTRACT; |
807 | return m_pArgs; |
808 | } |
809 | |
810 | private: |
811 | // Note that for DAC builds, m_pArgs may be host allocated buffer, not a copy of an object marshalled by DAC. |
812 | FixupPointer<TypeHandle> * m_pArgs; |
813 | DWORD m_nArgs; |
814 | }; |
815 | |
816 | #endif // TYPEHANDLE_H |
817 | |