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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
15 /*****************************************************************************
16 This header file is named _typeInfo.h to be distinguished from typeinfo.h
18 ******************************************************************************/
20 /*****************************************************************************/
23 /*****************************************************************************/
27 #define DEF_TI(ti, nm) ti,
30 TI_ONLY_ENUM = TI_METHOD, // Enum values with greater value are completely described by the enumeration.
33 #if defined(_TARGET_64BIT_)
34 #define TI_I_IMPL TI_LONG
36 #define TI_I_IMPL TI_INT
41 #define TI_DUMP_PADDING " "
46 SELECTANY const char* g_ti_type_names_map[] = {
47 #define DEF_TI(ti, nm) nm,
54 #endif // VERBOSE_VERIFY
61 SELECTANY const ti_types g_jit_types_map[] = {
62 #define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) verType,
72 inline const char* tiType2Str(ti_types type)
74 return g_ti_type_names_map[type];
76 #endif // VERBOSE_VERIFY
79 // typeInfo does not care about distinction between signed/unsigned
80 // This routine converts all unsigned types to signed ones
81 inline ti_types varType2tiType(var_types type)
83 assert(g_jit_types_map[TYP_BYTE] == TI_BYTE);
84 assert(g_jit_types_map[TYP_INT] == TI_INT);
85 assert(g_jit_types_map[TYP_UINT] == TI_INT);
86 assert(g_jit_types_map[TYP_FLOAT] == TI_FLOAT);
87 assert(g_jit_types_map[TYP_BYREF] == TI_ERROR);
88 assert(g_jit_types_map[type] != TI_ERROR);
89 return g_jit_types_map[type];
96 SELECTANY const ti_types g_ti_types_map[CORINFO_TYPE_COUNT] = {
97 // see the definition of enum CorInfoType in file inc/corinfo.h
98 TI_ERROR, // CORINFO_TYPE_UNDEF = 0x0,
99 TI_ERROR, // CORINFO_TYPE_VOID = 0x1,
100 TI_BYTE, // CORINFO_TYPE_BOOL = 0x2,
101 TI_SHORT, // CORINFO_TYPE_CHAR = 0x3,
102 TI_BYTE, // CORINFO_TYPE_BYTE = 0x4,
103 TI_BYTE, // CORINFO_TYPE_UBYTE = 0x5,
104 TI_SHORT, // CORINFO_TYPE_SHORT = 0x6,
105 TI_SHORT, // CORINFO_TYPE_USHORT = 0x7,
106 TI_INT, // CORINFO_TYPE_INT = 0x8,
107 TI_INT, // CORINFO_TYPE_UINT = 0x9,
108 TI_LONG, // CORINFO_TYPE_LONG = 0xa,
109 TI_LONG, // CORINFO_TYPE_ULONG = 0xb,
110 TI_I_IMPL, // CORINFO_TYPE_NATIVEINT = 0xc,
111 TI_I_IMPL, // CORINFO_TYPE_NATIVEUINT = 0xd,
112 TI_FLOAT, // CORINFO_TYPE_FLOAT = 0xe,
113 TI_DOUBLE, // CORINFO_TYPE_DOUBLE = 0xf,
114 TI_REF, // CORINFO_TYPE_STRING = 0x10,
115 TI_ERROR, // CORINFO_TYPE_PTR = 0x11,
116 TI_ERROR, // CORINFO_TYPE_BYREF = 0x12,
117 TI_STRUCT, // CORINFO_TYPE_VALUECLASS = 0x13,
118 TI_REF, // CORINFO_TYPE_CLASS = 0x14,
119 TI_STRUCT, // CORINFO_TYPE_REFANY = 0x15,
120 TI_REF, // CORINFO_TYPE_VAR = 0x16,
126 // Convert the type returned from the VM to a ti_type.
128 inline ti_types JITtype2tiType(CorInfoType type)
130 // spot check to make certain enumerations have not changed
132 assert(g_ti_types_map[CORINFO_TYPE_CLASS] == TI_REF);
133 assert(g_ti_types_map[CORINFO_TYPE_BYREF] == TI_ERROR);
134 assert(g_ti_types_map[CORINFO_TYPE_DOUBLE] == TI_DOUBLE);
135 assert(g_ti_types_map[CORINFO_TYPE_VALUECLASS] == TI_STRUCT);
136 assert(g_ti_types_map[CORINFO_TYPE_STRING] == TI_REF);
138 type = CorInfoType(type & CORINFO_TYPE_MASK); // strip off modifiers
140 assert(type < CORINFO_TYPE_COUNT);
142 assert(g_ti_types_map[type] != TI_ERROR || type == CORINFO_TYPE_VOID);
143 return g_ti_types_map[type];
146 /*****************************************************************************
147 * Declares the typeInfo class, which represents the type of an entity on the
148 * stack, in a local variable or an argument.
150 * Flags: LLLLLLLLLLLLLLLLffffffffffTTTTTT
152 * L = local var # or instance field #
157 * The lower bits are used to store the type component, and may be one of:
159 * TI_* (primitive) - see tyelist.h for enumeration (BYTE, SHORT, INT..)
160 * TI_REF - OBJREF / ARRAY use m_cls for the type
161 * (including arrays and null objref)
162 * TI_STRUCT - VALUE type, use m_cls for the actual type
164 * NOTE carefully that BYREF info is not stored here. You will never see a
165 * TI_BYREF in this component. For example, the type component
166 * of a "byref TI_INT" is TI_FLAG_BYREF | TI_INT.
168 * NOTE carefully that Generic Type Variable info is
169 * only stored here in part. Values of type "T" (e.g "!0" in ILASM syntax),
170 * i.e. some generic variable type, appear only when verifying generic
171 * code. They come in two flavours: unboxed and boxed. Unboxed
172 * is the norm, e.g. a local, field or argument of type T. Boxed
173 * values arise from an IL instruction such as "box !0".
174 * The EE provides type handles for each different type
175 * variable and the EE's "canCast" operation decides casting
176 * for boxed type variable. Thus:
178 * (TI_REF, <type-variable-type-handle>) == boxed type variable
180 * (TI_REF, <type-variable-type-handle>)
181 * + TI_FLAG_GENERIC_TYPE_VAR == unboxed type variable
183 * Using TI_REF for these may seem odd but using TI_STRUCT means the
184 * code-generation parts of the importer get confused when they
185 * can't work out the size, GC-ness etc. of the "struct". So using TI_REF
186 * just tricks these backend parts into generating pseudo-trees for
187 * the generic code we're verifying. These trees then get thrown away
188 * anyway as we do verification of genreic code in import-only mode.
192 #define TI_FLAG_DATA_BITS 6
193 #define TI_FLAG_DATA_MASK ((1 << TI_FLAG_DATA_BITS) - 1)
195 // Flag indicating this item is uninitialized
196 // Note that if UNINIT and BYREF are both set,
197 // it means byref (uninit x) - i.e. we are pointing to an uninit <something>
199 #define TI_FLAG_UNINIT_OBJREF 0x00000040
201 // Flag indicating this item is a byref <something>
203 #define TI_FLAG_BYREF 0x00000080
205 // This item is a byref generated using the readonly. prefix
206 // to a ldelema or Address function on an array type. The
207 // runtime type check is ignored in these cases, but the
208 // resulting byref can only be used in order to perform a
211 #define TI_FLAG_BYREF_READONLY 0x00000100
213 // This item is the MSIL 'I' type which is pointer-sized
214 // (different size depending on platform) but which on ALL platforms
215 // is implicitly convertible with a 32-bit int but not with a 64-bit one.
217 // Note: this flag is currently used only in 64-bit systems to annotate
218 // native int types. In 32 bits, since you can transparently coalesce int32
219 // and native-int and both are the same size, JIT32 had no need to model
220 // native-ints as a separate entity. For 64-bit though, since they have
221 // different size, it's important to discern between a long and a native int
222 // since conversions between them are not verifiable.
223 #define TI_FLAG_NATIVE_INT 0x00000200
225 // This item contains resolved token. It is used for ctor delegate optimization.
226 #define TI_FLAG_TOKEN 0x00000400
228 // This item contains the 'this' pointer (used for tracking)
230 #define TI_FLAG_THIS_PTR 0x00001000
232 // This item is a byref to something which has a permanent home
233 // (e.g. a static field, or instance field of an object in GC heap, as
234 // opposed to the stack or a local variable). TI_FLAG_BYREF must also be
235 // set. This information is useful for tail calls and return byrefs.
237 // Instructions that generate a permanent home byref:
240 // ldflda of a ref object or another permanent home byref
241 // array element address Get() helper
242 // call or calli to a method that returns a byref and is verifiable or SkipVerify
246 #define TI_FLAG_BYREF_PERMANENT_HOME 0x00002000
248 // This is for use when verifying generic code.
249 // This indicates that the type handle is really an unboxed
250 // generic type variable (e.g. the result of loading an argument
251 // of type T in a class List<T>). Without this flag
252 // the same type handle indicates a boxed generic value,
253 // e.g. the result of a "box T" instruction.
254 #define TI_FLAG_GENERIC_TYPE_VAR 0x00004000
256 // Number of bits local var # is shifted
258 #define TI_FLAG_LOCAL_VAR_SHIFT 16
259 #define TI_FLAG_LOCAL_VAR_MASK 0xFFFF0000
261 // Field info uses the same space as the local info
263 #define TI_FLAG_FIELD_SHIFT TI_FLAG_LOCAL_VAR_SHIFT
264 #define TI_FLAG_FIELD_MASK TI_FLAG_LOCAL_VAR_MASK
266 #define TI_ALL_BYREF_FLAGS (TI_FLAG_BYREF | TI_FLAG_BYREF_READONLY | TI_FLAG_BYREF_PERMANENT_HOME)
268 /*****************************************************************************
269 * A typeInfo can be one of several types:
270 * - A primitive type (I4,I8,R4,R8,I)
271 * - A type (ref, array, value type) (m_cls describes the type)
272 * - An array (m_cls describes the array type)
273 * - A byref (byref flag set, otherwise the same as the above),
274 * - A Function Pointer (m_method)
275 * - A byref local variable (byref and byref local flags set), can be
278 * The reason that there can be 2 types of byrefs (general byrefs, and byref
279 * locals) is that byref locals initially point to uninitialized items.
280 * Therefore these byrefs must be tracked specialy.
290 ti_types type : TI_FLAG_DATA_BITS;
291 unsigned uninitobj : 1; // used
292 unsigned byref : 1; // used
293 unsigned byref_readonly : 1; // used
294 unsigned nativeInt : 1; // used
295 unsigned token : 1; // used
296 unsigned : 1; // unused
297 unsigned thisPtr : 1; // used
298 unsigned thisPermHome : 1; // used
299 unsigned generic_type_var : 1; // used
306 CORINFO_CLASS_HANDLE m_cls;
307 // Valid only for type TI_METHOD without IsToken
308 CORINFO_METHOD_HANDLE m_method;
309 // Valid only for TI_TOKEN with IsToken
310 CORINFO_RESOLVED_TOKEN* m_token;
313 template <typename T>
314 static bool isInvalidHandle(const T handle)
316 static_assert(std::is_same<T, CORINFO_CLASS_HANDLE>::value || std::is_same<T, CORINFO_METHOD_HANDLE>::value,
319 return handle == reinterpret_cast<T>(0xcccccccccccccccc);
321 return handle == reinterpret_cast<T>(0xcccccccc);
326 typeInfo() : m_flags(TI_ERROR)
328 m_cls = NO_CLASS_HANDLE;
331 typeInfo(ti_types tiType)
333 assert((tiType >= TI_BYTE) && (tiType <= TI_NULL));
334 assert(tiType <= TI_FLAG_DATA_MASK);
336 m_flags = (DWORD)tiType;
337 m_cls = NO_CLASS_HANDLE;
340 typeInfo(var_types varType)
342 m_flags = (DWORD)varType2tiType(varType);
343 m_cls = NO_CLASS_HANDLE;
346 static typeInfo nativeInt()
348 typeInfo result = typeInfo(TI_I_IMPL);
349 #ifdef _TARGET_64BIT_
350 result.m_flags |= TI_FLAG_NATIVE_INT;
355 typeInfo(ti_types tiType, CORINFO_CLASS_HANDLE cls, bool typeVar = false)
357 assert(tiType == TI_STRUCT || tiType == TI_REF);
358 assert(cls != nullptr && !isInvalidHandle(cls));
362 m_flags |= TI_FLAG_GENERIC_TYPE_VAR;
367 typeInfo(CORINFO_METHOD_HANDLE method)
369 assert(method != nullptr && !isInvalidHandle(method));
374 typeInfo(CORINFO_RESOLVED_TOKEN* token)
376 assert(token != nullptr);
377 assert(token->hMethod != nullptr);
378 assert(!isInvalidHandle(token->hMethod));
387 #endif // VERBOSE_VERIFY
391 // Note that we specifically ignore the permanent byref here. The rationale is that
392 // the type system doesn't know about this (it's jit only), ie, signatures don't specify if
393 // a byref is safe, so they are fully equivalent for the jit, except for the RET instruction
394 // , instructions that load safe byrefs and the stack merging logic, which need to know about
396 static bool AreEquivalent(const typeInfo& li, const typeInfo& ti)
398 DWORD allFlags = TI_FLAG_DATA_MASK | TI_FLAG_BYREF | TI_FLAG_BYREF_READONLY | TI_FLAG_GENERIC_TYPE_VAR |
399 TI_FLAG_UNINIT_OBJREF;
400 #ifdef _TARGET_64BIT_
401 allFlags |= TI_FLAG_NATIVE_INT;
402 #endif // _TARGET_64BIT_
404 if ((li.m_flags & allFlags) != (ti.m_flags & allFlags))
409 unsigned type = li.m_flags & TI_FLAG_DATA_MASK;
411 TI_ONLY_ENUM); // TI_ERROR looks like it needs more than enum. This optimises the success case a bit
412 if (type > TI_ONLY_ENUM)
416 if (type == TI_ERROR)
418 return false; // TI_ERROR != TI_ERROR
420 assert(li.m_cls != NO_CLASS_HANDLE && ti.m_cls != NO_CLASS_HANDLE);
421 return li.m_cls == ti.m_cls;
425 // On 64-bit systems, nodes whose "proper" type is "native int" get labeled TYP_LONG.
426 // In the verification type system, we always transform "native int" to "TI_LONG" with the
427 // native int flag set.
428 // Ideally, we would keep track of which nodes labeled "TYP_LONG" are really "native int", but
429 // attempts to do that have proved too difficult. So in situations where we try to compare the
430 // verification type system and the node type system, we use this method, which allows the specific
431 // mismatch where "verTi" is TI_LONG with the native int flag and "nodeTi" is TI_LONG without the
432 // native int flag set.
433 static bool AreEquivalentModuloNativeInt(const typeInfo& verTi, const typeInfo& nodeTi)
435 if (AreEquivalent(verTi, nodeTi))
439 #ifdef _TARGET_64BIT_
440 return (nodeTi.IsType(TI_I_IMPL) && tiCompatibleWith(nullptr, verTi, typeInfo::nativeInt(), true)) ||
441 (verTi.IsType(TI_I_IMPL) && tiCompatibleWith(nullptr, typeInfo::nativeInt(), nodeTi, true));
442 #else // _TARGET_64BIT_
444 #endif // !_TARGET_64BIT_
448 static BOOL tiMergeToCommonParent(COMP_HANDLE CompHnd, typeInfo* pDest, const typeInfo* pSrc, bool* changed);
449 static BOOL tiCompatibleWith(COMP_HANDLE CompHnd,
450 const typeInfo& child,
451 const typeInfo& parent,
452 bool normalisedForStack);
454 static BOOL tiMergeCompatibleWith(COMP_HANDLE CompHnd,
455 const typeInfo& child,
456 const typeInfo& parent,
457 bool normalisedForStack);
459 /////////////////////////////////////////////////////////////////////////
461 /////////////////////////////////////////////////////////////////////////
465 m_flags |= TI_FLAG_TOKEN;
466 assert(m_bits.token);
471 m_flags |= TI_FLAG_THIS_PTR;
472 assert(m_bits.thisPtr);
477 m_flags &= ~(TI_FLAG_THIS_PTR);
480 void SetIsPermanentHomeByRef()
483 m_flags |= TI_FLAG_BYREF_PERMANENT_HOME;
486 void SetIsReadonlyByRef()
489 m_flags |= TI_FLAG_BYREF_READONLY;
492 // Set that this item is uninitialized.
493 void SetUninitialisedObjRef()
495 assert((IsObjRef() && IsThisPtr()));
496 // For now, this is used only to track uninit this ptrs in ctors
498 m_flags |= TI_FLAG_UNINIT_OBJREF;
499 assert(m_bits.uninitobj);
502 // Set that this item is initialised.
503 void SetInitialisedObjRef()
505 assert((IsObjRef() && IsThisPtr()));
506 // For now, this is used only to track uninit this ptrs in ctors
508 m_flags &= ~TI_FLAG_UNINIT_OBJREF;
511 typeInfo& DereferenceByRef()
516 INDEBUG(m_cls = NO_CLASS_HANDLE);
518 m_flags &= ~(TI_FLAG_THIS_PTR | TI_ALL_BYREF_FLAGS);
522 typeInfo& MakeByRef()
525 m_flags &= ~(TI_FLAG_THIS_PTR);
526 m_flags |= TI_FLAG_BYREF;
532 // objref, arrays, byrefs, value classes are unchanged
534 typeInfo& NormaliseForStack()
552 /////////////////////////////////////////////////////////////////////////
554 /////////////////////////////////////////////////////////////////////////
556 CORINFO_CLASS_HANDLE GetClassHandle() const
561 CORINFO_CLASS_HANDLE GetClassHandleForValueClass() const
563 assert(IsType(TI_STRUCT));
564 assert(m_cls != NO_CLASS_HANDLE);
568 CORINFO_CLASS_HANDLE GetClassHandleForObjRef() const
570 assert(IsType(TI_REF));
571 assert(m_cls != NO_CLASS_HANDLE);
575 CORINFO_METHOD_HANDLE GetMethod() const
577 assert(GetType() == TI_METHOD);
580 return m_token->hMethod;
585 CORINFO_RESOLVED_TOKEN* GetToken() const
591 // Get this item's type
592 // If primitive, returns the primitive type (TI_*)
593 // If not primitive, returns:
594 // - TI_ERROR if a byref anything
595 // - TI_REF if a class or array or null or a generic type variable
596 // - TI_STRUCT if a value class
597 ti_types GetType() const
599 if (m_flags & TI_FLAG_BYREF)
604 // objref/array/null (objref), value class, ptr, primitive
605 return (ti_types)(m_flags & TI_FLAG_DATA_MASK);
608 BOOL IsType(ti_types type) const
610 assert(type != TI_ERROR);
611 return (m_flags & (TI_FLAG_DATA_MASK | TI_FLAG_BYREF | TI_FLAG_BYREF_READONLY | TI_FLAG_BYREF_PERMANENT_HOME |
612 TI_FLAG_GENERIC_TYPE_VAR)) == DWORD(type);
615 // Returns whether this is an objref
616 BOOL IsObjRef() const
618 return IsType(TI_REF) || IsType(TI_NULL);
621 // Returns whether this is a by-ref
624 return (m_flags & TI_FLAG_BYREF);
627 // Returns whether this is the this pointer
628 BOOL IsThisPtr() const
630 return (m_flags & TI_FLAG_THIS_PTR);
633 BOOL IsUnboxedGenericTypeVar() const
635 return !IsByRef() && (m_flags & TI_FLAG_GENERIC_TYPE_VAR);
638 BOOL IsReadonlyByRef() const
640 return IsByRef() && (m_flags & TI_FLAG_BYREF_READONLY);
643 BOOL IsPermanentHomeByRef() const
645 return IsByRef() && (m_flags & TI_FLAG_BYREF_PERMANENT_HOME);
648 // Returns whether this is a method desc
649 BOOL IsMethod() const
651 return GetType() == TI_METHOD;
654 BOOL IsStruct() const
656 return IsType(TI_STRUCT);
659 // A byref value class is NOT a value class
660 BOOL IsValueClass() const
662 return (IsStruct() || IsPrimitiveType());
665 // Does not return true for primitives. Will return true for value types that behave
667 BOOL IsValueClassWithClsHnd() const
669 if ((GetType() == TI_STRUCT) ||
670 (m_cls && GetType() != TI_REF && GetType() != TI_METHOD &&
671 GetType() != TI_ERROR)) // necessary because if byref bit is set, we return TI_ERROR)
681 // Returns whether this is an integer or real number
682 // NOTE: Use NormaliseToPrimitiveType() if you think you may have a
683 // System.Int32 etc., because those types are not considered number
684 // types by this function.
685 BOOL IsNumberType() const
687 ti_types Type = GetType();
689 // I1, I2, Boolean, character etc. cannot exist plainly -
690 // everything is at least an I4
692 return (Type == TI_INT || Type == TI_LONG || Type == TI_DOUBLE);
695 // Returns whether this is an integer
696 // NOTE: Use NormaliseToPrimitiveType() if you think you may have a
697 // System.Int32 etc., because those types are not considered number
698 // types by this function.
699 BOOL IsIntegerType() const
701 ti_types Type = GetType();
703 // I1, I2, Boolean, character etc. cannot exist plainly -
704 // everything is at least an I4
706 return (Type == TI_INT || Type == TI_LONG);
709 // Returns true whether this is an integer or a native int.
710 BOOL IsIntOrNativeIntType() const
712 #ifdef _TARGET_64BIT_
713 return (GetType() == TI_INT) || AreEquivalent(*this, nativeInt());
715 return IsType(TI_INT);
719 BOOL IsNativeIntType() const
721 return AreEquivalent(*this, nativeInt());
724 // Returns whether this is a primitive type (not a byref, objref,
725 // array, null, value class, invalid value)
726 // May Need to normalise first (m/r/I4 --> I4)
727 BOOL IsPrimitiveType() const
729 DWORD Type = GetType();
731 // boolean, char, u1,u2 never appear on the operand stack
732 return (Type == TI_BYTE || Type == TI_SHORT || Type == TI_INT || Type == TI_LONG || Type == TI_FLOAT ||
736 // Returns whether this is the null objref
737 BOOL IsNullObjRef() const
739 return (IsType(TI_NULL));
742 // must be for a local which is an object type (i.e. has a slot >= 0)
743 // for primitive locals, use the liveness bitmap instead
744 // Note that this works if the error is 'Byref'
747 return (m_flags & (TI_FLAG_DATA_MASK)) == TI_ERROR;
750 BOOL IsUninitialisedObjRef() const
752 return (m_flags & TI_FLAG_UNINIT_OBJREF);
757 return IsMethod() && ((m_flags & TI_FLAG_TOKEN) != 0);
761 // used to make functions that return typeinfo efficient.
762 typeInfo(DWORD flags, CORINFO_CLASS_HANDLE cls)
768 friend typeInfo ByRef(const typeInfo& ti);
769 friend typeInfo DereferenceByRef(const typeInfo& ti);
770 friend typeInfo NormaliseForStack(const typeInfo& ti);
773 inline typeInfo NormaliseForStack(const typeInfo& ti)
775 return typeInfo(ti).NormaliseForStack();
778 // given ti make a byref to that type.
779 inline typeInfo ByRef(const typeInfo& ti)
781 return typeInfo(ti).MakeByRef();
784 // given ti which is a byref, return the type it points at
785 inline typeInfo DereferenceByRef(const typeInfo& ti)
787 return typeInfo(ti).DereferenceByRef();
789 /*****************************************************************************/
790 #endif // _TYPEINFO_H_
791 /*****************************************************************************/