| 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 | |