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 above this are completely described by the enumeration
34 #if defined(_TARGET_64BIT_)
35 #define TI_I_IMPL TI_LONG
37 #define TI_I_IMPL TI_INT
42 #define TI_DUMP_PADDING " "
47 SELECTANY const char* g_ti_type_names_map[] =
49 #define DEF_TI(ti, nm) nm,
56 #endif // VERBOSE_VERIFY
63 SELECTANY const ti_types g_jit_types_map[] =
65 #define DEF_TP(tn,nm,jitType,verType,sz,sze,asze,st,al,tf,howUsed) verType,
75 inline const char* tiType2Str(ti_types type)
77 return g_ti_type_names_map[type];
79 #endif // VERBOSE_VERIFY
82 // typeInfo does not care about distinction between signed/unsigned
83 // This routine converts all unsigned types to signed ones
84 inline ti_types varType2tiType(var_types type)
86 assert(g_jit_types_map[TYP_BYTE] == TI_BYTE);
87 assert(g_jit_types_map[TYP_INT] == TI_INT);
88 assert(g_jit_types_map[TYP_UINT] == TI_INT);
89 assert(g_jit_types_map[TYP_FLOAT] == TI_FLOAT);
90 assert(g_jit_types_map[TYP_BYREF] == TI_ERROR);
91 assert(g_jit_types_map[type] != TI_ERROR);
92 return g_jit_types_map[type];
99 SELECTANY const ti_types g_ti_types_map[CORINFO_TYPE_COUNT] =
100 { // see the definition of enum CorInfoType in file inc/corinfo.h
101 TI_ERROR, // CORINFO_TYPE_UNDEF = 0x0,
102 TI_ERROR, // CORINFO_TYPE_VOID = 0x1,
103 TI_BYTE, // CORINFO_TYPE_BOOL = 0x2,
104 TI_SHORT, // CORINFO_TYPE_CHAR = 0x3,
105 TI_BYTE, // CORINFO_TYPE_BYTE = 0x4,
106 TI_BYTE, // CORINFO_TYPE_UBYTE = 0x5,
107 TI_SHORT, // CORINFO_TYPE_SHORT = 0x6,
108 TI_SHORT, // CORINFO_TYPE_USHORT = 0x7,
109 TI_INT, // CORINFO_TYPE_INT = 0x8,
110 TI_INT, // CORINFO_TYPE_UINT = 0x9,
111 TI_LONG, // CORINFO_TYPE_LONG = 0xa,
112 TI_LONG, // CORINFO_TYPE_ULONG = 0xb,
113 TI_I_IMPL, // CORINFO_TYPE_NATIVEINT = 0xc,
114 TI_I_IMPL, // CORINFO_TYPE_NATIVEUINT = 0xd,
115 TI_FLOAT, // CORINFO_TYPE_FLOAT = 0xe,
116 TI_DOUBLE, // CORINFO_TYPE_DOUBLE = 0xf,
117 TI_REF, // CORINFO_TYPE_STRING = 0x10,
118 TI_ERROR, // CORINFO_TYPE_PTR = 0x11,
119 TI_ERROR, // CORINFO_TYPE_BYREF = 0x12,
120 TI_STRUCT, // CORINFO_TYPE_VALUECLASS = 0x13,
121 TI_REF, // CORINFO_TYPE_CLASS = 0x14,
122 TI_STRUCT, // CORINFO_TYPE_REFANY = 0x15,
123 TI_REF, // CORINFO_TYPE_VAR = 0x16,
129 // Convert the type returned from the VM to a ti_type.
131 inline ti_types JITtype2tiType(CorInfoType type)
133 // spot check to make certain enumerations have not changed
135 assert(g_ti_types_map[CORINFO_TYPE_CLASS] == TI_REF);
136 assert(g_ti_types_map[CORINFO_TYPE_BYREF] == TI_ERROR);
137 assert(g_ti_types_map[CORINFO_TYPE_DOUBLE] == TI_DOUBLE);
138 assert(g_ti_types_map[CORINFO_TYPE_VALUECLASS] == TI_STRUCT);
139 assert(g_ti_types_map[CORINFO_TYPE_STRING] == TI_REF);
141 type = CorInfoType(type & CORINFO_TYPE_MASK); // strip off modifiers
143 assert(type < CORINFO_TYPE_COUNT);
145 assert(g_ti_types_map[type] != TI_ERROR || type == CORINFO_TYPE_VOID);
146 return g_ti_types_map[type];
149 /*****************************************************************************
150 * Declares the typeInfo class, which represents the type of an entity on the
151 * stack, in a local variable or an argument.
153 * Flags: LLLLLLLLLLLLLLLLffffffffffTTTTTT
155 * L = local var # or instance field #
160 * The lower bits are used to store the type component, and may be one of:
162 * TI_* (primitive) - see tyelist.h for enumeration (BYTE, SHORT, INT..)
163 * TI_REF - OBJREF / ARRAY use m_cls for the type
164 * (including arrays and null objref)
165 * TI_STRUCT - VALUE type, use m_cls for the actual type
167 * NOTE carefully that BYREF info is not stored here. You will never see a
168 * TI_BYREF in this component. For example, the type component
169 * of a "byref TI_INT" is TI_FLAG_BYREF | TI_INT.
171 * NOTE carefully that Generic Type Variable info is
172 * only stored here in part. Values of type "T" (e.g "!0" in ILASM syntax),
173 * i.e. some generic variable type, appear only when verifying generic
174 * code. They come in two flavours: unboxed and boxed. Unboxed
175 * is the norm, e.g. a local, field or argument of type T. Boxed
176 * values arise from an IL instruction such as "box !0".
177 * The EE provides type handles for each different type
178 * variable and the EE's "canCast" operation decides casting
179 * for boxed type variable. Thus:
181 * (TI_REF, <type-variable-type-handle>) == boxed type variable
183 * (TI_REF, <type-variable-type-handle>)
184 * + TI_FLAG_GENERIC_TYPE_VAR == unboxed type variable
186 * Using TI_REF for these may seem odd but using TI_STRUCT means the
187 * code-generation parts of the importer get confused when they
188 * can't work out the size, GC-ness etc. of the "struct". So using TI_REF
189 * just tricks these backend parts into generating pseudo-trees for
190 * the generic code we're verifying. These trees then get thrown away
191 * anyway as we do verification of genreic code in import-only mode.
195 // TI_COUNT is less than or equal to TI_FLAG_DATA_MASK
197 #define TI_FLAG_DATA_BITS 6
198 #define TI_FLAG_DATA_MASK ((1 << TI_FLAG_DATA_BITS)-1)
200 // Flag indicating this item is uninitialized
201 // Note that if UNINIT and BYREF are both set,
202 // it means byref (uninit x) - i.e. we are pointing to an uninit <something>
204 #define TI_FLAG_UNINIT_OBJREF 0x00000040
206 // Flag indicating this item is a byref <something>
208 #define TI_FLAG_BYREF 0x00000080
210 // This item is a byref generated using the readonly. prefix
211 // to a ldelema or Address function on an array type. The
212 // runtime type check is ignored in these cases, but the
213 // resulting byref can only be used in order to perform a
216 #define TI_FLAG_BYREF_READONLY 0x00000100
218 // This item is the MSIL 'I' type which is pointer-sized
219 // (different size depending on platform) but which on ALL platforms
220 // is implicitly convertible with a 32-bit int but not with a 64-bit one.
222 // Note: this flag is currently used only in 64-bit systems to annotate
223 // native int types. In 32 bits, since you can transparently coalesce int32
224 // and native-int and both are the same size, JIT32 had no need to model
225 // native-ints as a separate entity. For 64-bit though, since they have
226 // different size, it's important to discern between a long and a native int
227 // since conversions between them are not verifiable.
228 #define TI_FLAG_NATIVE_INT 0x00000200
230 // This item contains the 'this' pointer (used for tracking)
232 #define TI_FLAG_THIS_PTR 0x00001000
235 // This item is a byref to something which has a permanent home
236 // (e.g. a static field, or instance field of an object in GC heap, as
237 // opposed to the stack or a local variable). TI_FLAG_BYREF must also be
238 // set. This information is useful for tail calls and return byrefs.
240 // Instructions that generate a permanent home byref:
243 // ldflda of a ref object or another permanent home byref
244 // array element address Get() helper
245 // call or calli to a method that returns a byref and is verifiable or SkipVerify
249 #define TI_FLAG_BYREF_PERMANENT_HOME 0x00002000
252 // This is for use when verifying generic code.
253 // This indicates that the type handle is really an unboxed
254 // generic type variable (e.g. the result of loading an argument
255 // of type T in a class List<T>). Without this flag
256 // the same type handle indicates a boxed generic value,
257 // e.g. the result of a "box T" instruction.
258 #define TI_FLAG_GENERIC_TYPE_VAR 0x00004000
260 // Number of bits local var # is shifted
262 #define TI_FLAG_LOCAL_VAR_SHIFT 16
263 #define TI_FLAG_LOCAL_VAR_MASK 0xFFFF0000
265 // Field info uses the same space as the local info
267 #define TI_FLAG_FIELD_SHIFT TI_FLAG_LOCAL_VAR_SHIFT
268 #define TI_FLAG_FIELD_MASK TI_FLAG_LOCAL_VAR_MASK
270 #define TI_ALL_BYREF_FLAGS (TI_FLAG_BYREF| \
271 TI_FLAG_BYREF_READONLY | \
272 TI_FLAG_BYREF_PERMANENT_HOME)
274 /*****************************************************************************
275 * A typeInfo can be one of several types:
276 * - A primitive type (I4,I8,R4,R8,I)
277 * - A type (ref, array, value type) (m_cls describes the type)
278 * - An array (m_cls describes the array type)
279 * - A byref (byref flag set, otherwise the same as the above),
280 * - A Function Pointer (m_method)
281 * - A byref local variable (byref and byref local flags set), can be
284 * The reason that there can be 2 types of byrefs (general byrefs, and byref
285 * locals) is that byref locals initially point to uninitialized items.
286 * Therefore these byrefs must be tracked specialy.
296 unsigned uninitobj : 1; // used
297 unsigned byref : 1; // used
298 unsigned byref_readonly : 1; // used
299 unsigned nativeInt : 1; // used
300 unsigned : 2; // unused
301 unsigned thisPtr : 1; // used
302 unsigned thisPermHome : 1; // used
303 unsigned generic_type_var : 1; // used
310 CORINFO_CLASS_HANDLE m_cls;
311 // Valid only for type TI_METHOD
312 CORINFO_METHOD_HANDLE m_method;
316 static bool isInvalidHandle(const T handle)
318 static_assert(std::is_same<T, CORINFO_CLASS_HANDLE>::value || std::is_same<T, CORINFO_METHOD_HANDLE>::value, "");
320 return handle == reinterpret_cast<T>(0xcccccccccccccccc);
322 return handle == reinterpret_cast<T>(0xcccccccc);
327 typeInfo():m_flags(TI_ERROR)
329 m_cls = NO_CLASS_HANDLE;
332 typeInfo(ti_types tiType)
334 assert((tiType >= TI_BYTE) && (tiType <= TI_NULL));
335 assert(tiType <= TI_FLAG_DATA_MASK);
337 m_flags = (DWORD) tiType;
338 m_cls = NO_CLASS_HANDLE;
341 typeInfo(var_types varType)
343 m_flags = (DWORD) varType2tiType(varType);
344 m_cls = NO_CLASS_HANDLE;
347 static typeInfo nativeInt()
349 typeInfo result = typeInfo(TI_I_IMPL);
350 #ifdef _TARGET_64BIT_
351 result.m_flags |= TI_FLAG_NATIVE_INT;
356 typeInfo(ti_types tiType, CORINFO_CLASS_HANDLE cls, bool typeVar = false)
358 assert(tiType == TI_STRUCT || tiType == TI_REF);
359 assert(cls != 0 && !isInvalidHandle(cls));
362 m_flags |= TI_FLAG_GENERIC_TYPE_VAR;
366 typeInfo(CORINFO_METHOD_HANDLE method)
368 assert(method != 0 && !isInvalidHandle(method));
376 #endif // VERBOSE_VERIFY
380 // Note that we specifically ignore the permanent byref here. The rationale is that
381 // the type system doesn't know about this (it's jit only), ie, signatures don't specify if
382 // a byref is safe, so they are fully equivalent for the jit, except for the RET instruction
383 // , instructions that load safe byrefs and the stack merging logic, which need to know about
385 static bool AreEquivalent(const typeInfo& li, const typeInfo& ti)
387 DWORD allFlags = TI_FLAG_DATA_MASK|TI_FLAG_BYREF|TI_FLAG_BYREF_READONLY|TI_FLAG_GENERIC_TYPE_VAR|TI_FLAG_UNINIT_OBJREF;
388 #ifdef _TARGET_64BIT_
389 allFlags |= TI_FLAG_NATIVE_INT;
390 #endif // _TARGET_64BIT_
392 if ((li.m_flags & allFlags) != (ti.m_flags & allFlags))
397 unsigned type = li.m_flags & TI_FLAG_DATA_MASK;
398 assert(TI_ERROR < TI_ONLY_ENUM); // TI_ERROR looks like it needs more than enum. This optimises the success case a bit
399 if (type > TI_ONLY_ENUM)
401 if (type == TI_ERROR)
402 return false; // TI_ERROR != TI_ERROR
403 assert(li.m_cls != NO_CLASS_HANDLE && ti.m_cls != NO_CLASS_HANDLE);
404 return li.m_cls == ti.m_cls;
408 // On 64-bit systems, nodes whose "proper" type is "native int" get labeled TYP_LONG.
409 // In the verification type system, we always transform "native int" to "TI_LONG" with the
410 // native int flag set.
411 // Ideally, we would keep track of which nodes labeled "TYP_LONG" are really "native int", but
412 // attempts to do that have proved too difficult. So in situations where we try to compare the
413 // verification type system and the node type system, we use this method, which allows the specific
414 // mismatch where "verTi" is TI_LONG with the native int flag and "nodeTi" is TI_LONG without the
415 // native int flag set.
416 static bool AreEquivalentModuloNativeInt(const typeInfo& verTi, const typeInfo& nodeTi)
418 if (AreEquivalent(verTi, nodeTi)) return true;
420 #ifdef _TARGET_64BIT_
421 return (nodeTi.IsType(TI_I_IMPL) && tiCompatibleWith(0, verTi, typeInfo::nativeInt(), true)) ||
422 (verTi.IsType(TI_I_IMPL) && tiCompatibleWith(0, typeInfo::nativeInt(), nodeTi, true));
423 #else // _TARGET_64BIT_
425 #endif // !_TARGET_64BIT_
431 static BOOL tiMergeToCommonParent (COMP_HANDLE CompHnd, typeInfo *pDest,
432 const typeInfo *pSrc,
434 static BOOL tiCompatibleWith (COMP_HANDLE CompHnd, const typeInfo& child,
435 const typeInfo& parent,
436 bool normalisedForStack) ;
438 static BOOL tiMergeCompatibleWith (COMP_HANDLE CompHnd, const typeInfo& child,
439 const typeInfo& parent,
440 bool normalisedForStack) ;
443 /////////////////////////////////////////////////////////////////////////
445 /////////////////////////////////////////////////////////////////////////
449 m_flags |= TI_FLAG_THIS_PTR;
450 assert(m_bits.thisPtr);
455 m_flags &= ~(TI_FLAG_THIS_PTR);
458 void SetIsPermanentHomeByRef()
461 m_flags |= TI_FLAG_BYREF_PERMANENT_HOME;
464 void SetIsReadonlyByRef()
467 m_flags |= TI_FLAG_BYREF_READONLY;
470 // Set that this item is uninitialized.
471 void SetUninitialisedObjRef()
473 assert((IsObjRef() && IsThisPtr()));
474 // For now, this is used only to track uninit this ptrs in ctors
476 m_flags |= TI_FLAG_UNINIT_OBJREF;
477 assert(m_bits.uninitobj);
480 // Set that this item is initialised.
481 void SetInitialisedObjRef()
483 assert((IsObjRef() && IsThisPtr()));
484 // For now, this is used only to track uninit this ptrs in ctors
486 m_flags &= ~TI_FLAG_UNINIT_OBJREF;
489 typeInfo& DereferenceByRef()
493 INDEBUG(m_cls = NO_CLASS_HANDLE);
495 m_flags &= ~(TI_FLAG_THIS_PTR | TI_ALL_BYREF_FLAGS);
499 typeInfo& MakeByRef()
502 m_flags &= ~(TI_FLAG_THIS_PTR);
503 m_flags |= TI_FLAG_BYREF;
509 // objref, arrays, byrefs, value classes are unchanged
511 typeInfo& NormaliseForStack()
529 /////////////////////////////////////////////////////////////////////////
531 /////////////////////////////////////////////////////////////////////////
533 CORINFO_CLASS_HANDLE GetClassHandle() const
538 CORINFO_CLASS_HANDLE GetClassHandleForValueClass() const
540 assert(IsType(TI_STRUCT));
541 assert(m_cls != NO_CLASS_HANDLE);
545 CORINFO_CLASS_HANDLE GetClassHandleForObjRef() const
547 assert(IsType(TI_REF));
548 assert(m_cls != NO_CLASS_HANDLE);
552 CORINFO_METHOD_HANDLE GetMethod() const
554 assert(GetType() == TI_METHOD);
558 // If FEATURE_CORECLR is enabled, GetMethod can be called
559 // before the pointer type is known to be a method pointer type.
560 CORINFO_METHOD_HANDLE GetMethod2() const
565 // Get this item's type
566 // If primitive, returns the primitive type (TI_*)
567 // If not primitive, returns:
568 // - TI_ERROR if a byref anything
569 // - TI_REF if a class or array or null or a generic type variable
570 // - TI_STRUCT if a value class
571 ti_types GetType() const
573 if (m_flags & TI_FLAG_BYREF)
576 // objref/array/null (objref), value class, ptr, primitive
577 return (ti_types)(m_flags & TI_FLAG_DATA_MASK);
580 BOOL IsType(ti_types type) const {
581 assert(type != TI_ERROR);
582 return (m_flags & (TI_FLAG_DATA_MASK|TI_FLAG_BYREF|TI_FLAG_BYREF_READONLY|
583 TI_FLAG_BYREF_PERMANENT_HOME|TI_FLAG_GENERIC_TYPE_VAR)) == DWORD(type);
586 // Returns whether this is an objref
587 BOOL IsObjRef() const
589 return IsType(TI_REF) || IsType(TI_NULL);
592 // Returns whether this is a by-ref
595 return (m_flags & TI_FLAG_BYREF);
598 // Returns whether this is the this pointer
599 BOOL IsThisPtr() const
601 return (m_flags & TI_FLAG_THIS_PTR);
604 BOOL IsUnboxedGenericTypeVar() const
606 return !IsByRef() && (m_flags & TI_FLAG_GENERIC_TYPE_VAR);
609 BOOL IsReadonlyByRef() const
611 return IsByRef() && (m_flags & TI_FLAG_BYREF_READONLY);
614 BOOL IsPermanentHomeByRef() const
616 return IsByRef() && (m_flags & TI_FLAG_BYREF_PERMANENT_HOME);
619 // Returns whether this is a method desc
620 BOOL IsMethod() const
622 return (GetType() == TI_METHOD);
625 BOOL IsStruct() const
627 return IsType(TI_STRUCT);
630 // A byref value class is NOT a value class
631 BOOL IsValueClass() const
633 return (IsStruct() || IsPrimitiveType());
636 // Does not return true for primitives. Will return true for value types that behave
638 BOOL IsValueClassWithClsHnd() const
640 if ((GetType() == TI_STRUCT) ||
641 (m_cls && GetType() != TI_REF &&
642 GetType() != TI_METHOD &&
643 GetType() != TI_ERROR)) // necessary because if byref bit is set, we return TI_ERROR)
653 // Returns whether this is an integer or real number
654 // NOTE: Use NormaliseToPrimitiveType() if you think you may have a
655 // System.Int32 etc., because those types are not considered number
656 // types by this function.
657 BOOL IsNumberType() const
659 ti_types Type = GetType();
661 // I1, I2, Boolean, character etc. cannot exist plainly -
662 // everything is at least an I4
664 return (Type == TI_INT ||
669 // Returns whether this is an integer
670 // NOTE: Use NormaliseToPrimitiveType() if you think you may have a
671 // System.Int32 etc., because those types are not considered number
672 // types by this function.
673 BOOL IsIntegerType() const
675 ti_types Type = GetType();
677 // I1, I2, Boolean, character etc. cannot exist plainly -
678 // everything is at least an I4
680 return (Type == TI_INT ||
684 // Returns true whether this is an integer or a native int.
685 BOOL IsIntOrNativeIntType() const
687 #ifdef _TARGET_64BIT_
688 return (GetType() == TI_INT) || AreEquivalent(*this, nativeInt());
690 return IsType(TI_INT);
694 BOOL IsNativeIntType() const
696 return AreEquivalent(*this, nativeInt());
699 // Returns whether this is a primitive type (not a byref, objref,
700 // array, null, value class, invalid value)
701 // May Need to normalise first (m/r/I4 --> I4)
702 BOOL IsPrimitiveType() const
704 DWORD Type = GetType();
706 // boolean, char, u1,u2 never appear on the operand stack
707 return (Type == TI_BYTE ||
715 // Returns whether this is the null objref
716 BOOL IsNullObjRef() const
718 return (IsType(TI_NULL));
721 // must be for a local which is an object type (i.e. has a slot >= 0)
722 // for primitive locals, use the liveness bitmap instead
723 // Note that this works if the error is 'Byref'
726 return (m_flags & (TI_FLAG_DATA_MASK)) == TI_ERROR;
729 BOOL IsUninitialisedObjRef() const
731 return (m_flags & TI_FLAG_UNINIT_OBJREF);
735 // used to make functions that return typeinfo efficient.
736 typeInfo(DWORD flags, CORINFO_CLASS_HANDLE cls)
742 friend typeInfo ByRef(const typeInfo& ti);
743 friend typeInfo DereferenceByRef(const typeInfo& ti);
744 friend typeInfo NormaliseForStack(const typeInfo& ti);
748 typeInfo NormaliseForStack(const typeInfo& ti)
750 return typeInfo(ti).NormaliseForStack();
753 // given ti make a byref to that type.
755 typeInfo ByRef(const typeInfo& ti)
757 return typeInfo(ti).MakeByRef();
761 // given ti which is a byref, return the type it points at
763 typeInfo DereferenceByRef(const typeInfo& ti)
765 return typeInfo(ti).DereferenceByRef();
767 /*****************************************************************************/
768 #endif // _TYPEINFO_H_
769 /*****************************************************************************/