summaryrefslogtreecommitdiff
path: root/src/jit/_typeinfo.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/jit/_typeinfo.h')
-rwxr-xr-xsrc/jit/_typeinfo.h764
1 files changed, 764 insertions, 0 deletions
diff --git a/src/jit/_typeinfo.h b/src/jit/_typeinfo.h
new file mode 100755
index 0000000000..08273adc8d
--- /dev/null
+++ b/src/jit/_typeinfo.h
@@ -0,0 +1,764 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XX XX
+XX _typeInfo XX
+XX XX
+XX XX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+*/
+
+/*****************************************************************************
+ This header file is named _typeInfo.h to be distinguished from typeinfo.h
+ in the NT SDK
+******************************************************************************/
+
+/*****************************************************************************/
+#ifndef _TYPEINFO_H_
+#define _TYPEINFO_H_
+/*****************************************************************************/
+
+enum ti_types
+{
+#define DEF_TI(ti, nm) ti,
+#include "titypes.h"
+#undef DEF_TI
+ TI_ONLY_ENUM = TI_METHOD, // Enum values above this are completely described by the enumeration
+ TI_COUNT
+};
+
+#if defined(_TARGET_64BIT_)
+#define TI_I_IMPL TI_LONG
+#else
+#define TI_I_IMPL TI_INT
+#endif
+
+#ifdef DEBUG
+#if VERBOSE_VERIFY
+#define TI_DUMP_PADDING " "
+#ifdef _MSC_VER
+namespace
+{
+#endif // _MSC_VER
+SELECTANY const char* g_ti_type_names_map[] = {
+#define DEF_TI(ti, nm) nm,
+#include "titypes.h"
+#undef DEF_TI
+};
+#ifdef _MSC_VER
+}
+#endif // _MSC_VER
+#endif // VERBOSE_VERIFY
+#endif // DEBUG
+
+#ifdef _MSC_VER
+namespace
+{
+#endif // _MSC_VER
+SELECTANY const ti_types g_jit_types_map[] = {
+#define DEF_TP(tn, nm, jitType, verType, sz, sze, asze, st, al, tf, howUsed) verType,
+#include "typelist.h"
+#undef DEF_TP
+};
+#ifdef _MSC_VER
+}
+#endif // _MSC_VER
+
+#ifdef DEBUG
+#if VERBOSE_VERIFY
+inline const char* tiType2Str(ti_types type)
+{
+ return g_ti_type_names_map[type];
+}
+#endif // VERBOSE_VERIFY
+#endif // DEBUG
+
+// typeInfo does not care about distinction between signed/unsigned
+// This routine converts all unsigned types to signed ones
+inline ti_types varType2tiType(var_types type)
+{
+ assert(g_jit_types_map[TYP_BYTE] == TI_BYTE);
+ assert(g_jit_types_map[TYP_INT] == TI_INT);
+ assert(g_jit_types_map[TYP_UINT] == TI_INT);
+ assert(g_jit_types_map[TYP_FLOAT] == TI_FLOAT);
+ assert(g_jit_types_map[TYP_BYREF] == TI_ERROR);
+ assert(g_jit_types_map[type] != TI_ERROR);
+ return g_jit_types_map[type];
+}
+
+#ifdef _MSC_VER
+namespace
+{
+#endif // _MSC_VER
+SELECTANY const ti_types g_ti_types_map[CORINFO_TYPE_COUNT] = {
+ // see the definition of enum CorInfoType in file inc/corinfo.h
+ TI_ERROR, // CORINFO_TYPE_UNDEF = 0x0,
+ TI_ERROR, // CORINFO_TYPE_VOID = 0x1,
+ TI_BYTE, // CORINFO_TYPE_BOOL = 0x2,
+ TI_SHORT, // CORINFO_TYPE_CHAR = 0x3,
+ TI_BYTE, // CORINFO_TYPE_BYTE = 0x4,
+ TI_BYTE, // CORINFO_TYPE_UBYTE = 0x5,
+ TI_SHORT, // CORINFO_TYPE_SHORT = 0x6,
+ TI_SHORT, // CORINFO_TYPE_USHORT = 0x7,
+ TI_INT, // CORINFO_TYPE_INT = 0x8,
+ TI_INT, // CORINFO_TYPE_UINT = 0x9,
+ TI_LONG, // CORINFO_TYPE_LONG = 0xa,
+ TI_LONG, // CORINFO_TYPE_ULONG = 0xb,
+ TI_I_IMPL, // CORINFO_TYPE_NATIVEINT = 0xc,
+ TI_I_IMPL, // CORINFO_TYPE_NATIVEUINT = 0xd,
+ TI_FLOAT, // CORINFO_TYPE_FLOAT = 0xe,
+ TI_DOUBLE, // CORINFO_TYPE_DOUBLE = 0xf,
+ TI_REF, // CORINFO_TYPE_STRING = 0x10,
+ TI_ERROR, // CORINFO_TYPE_PTR = 0x11,
+ TI_ERROR, // CORINFO_TYPE_BYREF = 0x12,
+ TI_STRUCT, // CORINFO_TYPE_VALUECLASS = 0x13,
+ TI_REF, // CORINFO_TYPE_CLASS = 0x14,
+ TI_STRUCT, // CORINFO_TYPE_REFANY = 0x15,
+ TI_REF, // CORINFO_TYPE_VAR = 0x16,
+};
+#ifdef _MSC_VER
+}
+#endif // _MSC_VER
+
+// Convert the type returned from the VM to a ti_type.
+
+inline ti_types JITtype2tiType(CorInfoType type)
+{
+ // spot check to make certain enumerations have not changed
+
+ assert(g_ti_types_map[CORINFO_TYPE_CLASS] == TI_REF);
+ assert(g_ti_types_map[CORINFO_TYPE_BYREF] == TI_ERROR);
+ assert(g_ti_types_map[CORINFO_TYPE_DOUBLE] == TI_DOUBLE);
+ assert(g_ti_types_map[CORINFO_TYPE_VALUECLASS] == TI_STRUCT);
+ assert(g_ti_types_map[CORINFO_TYPE_STRING] == TI_REF);
+
+ type = CorInfoType(type & CORINFO_TYPE_MASK); // strip off modifiers
+
+ assert(type < CORINFO_TYPE_COUNT);
+
+ assert(g_ti_types_map[type] != TI_ERROR || type == CORINFO_TYPE_VOID);
+ return g_ti_types_map[type];
+};
+
+/*****************************************************************************
+ * Declares the typeInfo class, which represents the type of an entity on the
+ * stack, in a local variable or an argument.
+ *
+ * Flags: LLLLLLLLLLLLLLLLffffffffffTTTTTT
+ *
+ * L = local var # or instance field #
+ * x = unused
+ * f = flags
+ * T = type
+ *
+ * The lower bits are used to store the type component, and may be one of:
+ *
+ * TI_* (primitive) - see tyelist.h for enumeration (BYTE, SHORT, INT..)
+ * TI_REF - OBJREF / ARRAY use m_cls for the type
+ * (including arrays and null objref)
+ * TI_STRUCT - VALUE type, use m_cls for the actual type
+ *
+ * NOTE carefully that BYREF info is not stored here. You will never see a
+ * TI_BYREF in this component. For example, the type component
+ * of a "byref TI_INT" is TI_FLAG_BYREF | TI_INT.
+ *
+ * NOTE carefully that Generic Type Variable info is
+ * only stored here in part. Values of type "T" (e.g "!0" in ILASM syntax),
+ * i.e. some generic variable type, appear only when verifying generic
+ * code. They come in two flavours: unboxed and boxed. Unboxed
+ * is the norm, e.g. a local, field or argument of type T. Boxed
+ * values arise from an IL instruction such as "box !0".
+ * The EE provides type handles for each different type
+ * variable and the EE's "canCast" operation decides casting
+ * for boxed type variable. Thus:
+ *
+ * (TI_REF, <type-variable-type-handle>) == boxed type variable
+ *
+ * (TI_REF, <type-variable-type-handle>)
+ * + TI_FLAG_GENERIC_TYPE_VAR == unboxed type variable
+ *
+ * Using TI_REF for these may seem odd but using TI_STRUCT means the
+ * code-generation parts of the importer get confused when they
+ * can't work out the size, GC-ness etc. of the "struct". So using TI_REF
+ * just tricks these backend parts into generating pseudo-trees for
+ * the generic code we're verifying. These trees then get thrown away
+ * anyway as we do verification of genreic code in import-only mode.
+ *
+ */
+
+// TI_COUNT is less than or equal to TI_FLAG_DATA_MASK
+
+#define TI_FLAG_DATA_BITS 6
+#define TI_FLAG_DATA_MASK ((1 << TI_FLAG_DATA_BITS) - 1)
+
+// Flag indicating this item is uninitialized
+// Note that if UNINIT and BYREF are both set,
+// it means byref (uninit x) - i.e. we are pointing to an uninit <something>
+
+#define TI_FLAG_UNINIT_OBJREF 0x00000040
+
+// Flag indicating this item is a byref <something>
+
+#define TI_FLAG_BYREF 0x00000080
+
+// This item is a byref generated using the readonly. prefix
+// to a ldelema or Address function on an array type. The
+// runtime type check is ignored in these cases, but the
+// resulting byref can only be used in order to perform a
+// constraint call.
+
+#define TI_FLAG_BYREF_READONLY 0x00000100
+
+// This item is the MSIL 'I' type which is pointer-sized
+// (different size depending on platform) but which on ALL platforms
+// is implicitly convertible with a 32-bit int but not with a 64-bit one.
+
+// Note: this flag is currently used only in 64-bit systems to annotate
+// native int types. In 32 bits, since you can transparently coalesce int32
+// and native-int and both are the same size, JIT32 had no need to model
+// native-ints as a separate entity. For 64-bit though, since they have
+// different size, it's important to discern between a long and a native int
+// since conversions between them are not verifiable.
+#define TI_FLAG_NATIVE_INT 0x00000200
+
+// This item contains the 'this' pointer (used for tracking)
+
+#define TI_FLAG_THIS_PTR 0x00001000
+
+// This item is a byref to something which has a permanent home
+// (e.g. a static field, or instance field of an object in GC heap, as
+// opposed to the stack or a local variable). TI_FLAG_BYREF must also be
+// set. This information is useful for tail calls and return byrefs.
+//
+// Instructions that generate a permanent home byref:
+//
+// ldelema
+// ldflda of a ref object or another permanent home byref
+// array element address Get() helper
+// call or calli to a method that returns a byref and is verifiable or SkipVerify
+// dup
+// unbox
+
+#define TI_FLAG_BYREF_PERMANENT_HOME 0x00002000
+
+// This is for use when verifying generic code.
+// This indicates that the type handle is really an unboxed
+// generic type variable (e.g. the result of loading an argument
+// of type T in a class List<T>). Without this flag
+// the same type handle indicates a boxed generic value,
+// e.g. the result of a "box T" instruction.
+#define TI_FLAG_GENERIC_TYPE_VAR 0x00004000
+
+// Number of bits local var # is shifted
+
+#define TI_FLAG_LOCAL_VAR_SHIFT 16
+#define TI_FLAG_LOCAL_VAR_MASK 0xFFFF0000
+
+// Field info uses the same space as the local info
+
+#define TI_FLAG_FIELD_SHIFT TI_FLAG_LOCAL_VAR_SHIFT
+#define TI_FLAG_FIELD_MASK TI_FLAG_LOCAL_VAR_MASK
+
+#define TI_ALL_BYREF_FLAGS (TI_FLAG_BYREF | TI_FLAG_BYREF_READONLY | TI_FLAG_BYREF_PERMANENT_HOME)
+
+/*****************************************************************************
+ * A typeInfo can be one of several types:
+ * - A primitive type (I4,I8,R4,R8,I)
+ * - A type (ref, array, value type) (m_cls describes the type)
+ * - An array (m_cls describes the array type)
+ * - A byref (byref flag set, otherwise the same as the above),
+ * - A Function Pointer (m_method)
+ * - A byref local variable (byref and byref local flags set), can be
+ * uninitialized
+ *
+ * The reason that there can be 2 types of byrefs (general byrefs, and byref
+ * locals) is that byref locals initially point to uninitialized items.
+ * Therefore these byrefs must be tracked specialy.
+ */
+
+class typeInfo
+{
+
+private:
+ union {
+ struct
+ {
+ ti_types type : 6;
+ unsigned uninitobj : 1; // used
+ unsigned byref : 1; // used
+ unsigned byref_readonly : 1; // used
+ unsigned nativeInt : 1; // used
+ unsigned : 2; // unused
+ unsigned thisPtr : 1; // used
+ unsigned thisPermHome : 1; // used
+ unsigned generic_type_var : 1; // used
+ } m_bits;
+
+ DWORD m_flags;
+ };
+
+ union {
+ CORINFO_CLASS_HANDLE m_cls;
+ // Valid only for type TI_METHOD
+ CORINFO_METHOD_HANDLE m_method;
+ };
+
+ template <typename T>
+ static bool isInvalidHandle(const T handle)
+ {
+ static_assert(std::is_same<T, CORINFO_CLASS_HANDLE>::value || std::is_same<T, CORINFO_METHOD_HANDLE>::value,
+ "");
+#ifdef _HOST_64BIT_
+ return handle == reinterpret_cast<T>(0xcccccccccccccccc);
+#else
+ return handle == reinterpret_cast<T>(0xcccccccc);
+#endif
+ }
+
+public:
+ typeInfo() : m_flags(TI_ERROR)
+ {
+ m_cls = NO_CLASS_HANDLE;
+ }
+
+ typeInfo(ti_types tiType)
+ {
+ assert((tiType >= TI_BYTE) && (tiType <= TI_NULL));
+ assert(tiType <= TI_FLAG_DATA_MASK);
+
+ m_flags = (DWORD)tiType;
+ m_cls = NO_CLASS_HANDLE;
+ }
+
+ typeInfo(var_types varType)
+ {
+ m_flags = (DWORD)varType2tiType(varType);
+ m_cls = NO_CLASS_HANDLE;
+ }
+
+ static typeInfo nativeInt()
+ {
+ typeInfo result = typeInfo(TI_I_IMPL);
+#ifdef _TARGET_64BIT_
+ result.m_flags |= TI_FLAG_NATIVE_INT;
+#endif
+ return result;
+ }
+
+ typeInfo(ti_types tiType, CORINFO_CLASS_HANDLE cls, bool typeVar = false)
+ {
+ assert(tiType == TI_STRUCT || tiType == TI_REF);
+ assert(cls != nullptr && !isInvalidHandle(cls));
+ m_flags = tiType;
+ if (typeVar)
+ {
+ m_flags |= TI_FLAG_GENERIC_TYPE_VAR;
+ }
+ m_cls = cls;
+ }
+
+ typeInfo(CORINFO_METHOD_HANDLE method)
+ {
+ assert(method != nullptr && !isInvalidHandle(method));
+ m_flags = TI_METHOD;
+ m_method = method;
+ }
+
+#ifdef DEBUG
+#if VERBOSE_VERIFY
+ void Dump() const;
+#endif // VERBOSE_VERIFY
+#endif // DEBUG
+
+public:
+ // Note that we specifically ignore the permanent byref here. The rationale is that
+ // the type system doesn't know about this (it's jit only), ie, signatures don't specify if
+ // a byref is safe, so they are fully equivalent for the jit, except for the RET instruction
+ // , instructions that load safe byrefs and the stack merging logic, which need to know about
+ // the bit
+ static bool AreEquivalent(const typeInfo& li, const typeInfo& ti)
+ {
+ DWORD allFlags = TI_FLAG_DATA_MASK | TI_FLAG_BYREF | TI_FLAG_BYREF_READONLY | TI_FLAG_GENERIC_TYPE_VAR |
+ TI_FLAG_UNINIT_OBJREF;
+#ifdef _TARGET_64BIT_
+ allFlags |= TI_FLAG_NATIVE_INT;
+#endif // _TARGET_64BIT_
+
+ if ((li.m_flags & allFlags) != (ti.m_flags & allFlags))
+ {
+ return false;
+ }
+
+ unsigned type = li.m_flags & TI_FLAG_DATA_MASK;
+ assert(TI_ERROR <
+ TI_ONLY_ENUM); // TI_ERROR looks like it needs more than enum. This optimises the success case a bit
+ if (type > TI_ONLY_ENUM)
+ {
+ return true;
+ }
+ if (type == TI_ERROR)
+ {
+ return false; // TI_ERROR != TI_ERROR
+ }
+ assert(li.m_cls != NO_CLASS_HANDLE && ti.m_cls != NO_CLASS_HANDLE);
+ return li.m_cls == ti.m_cls;
+ }
+
+#ifdef DEBUG
+ // On 64-bit systems, nodes whose "proper" type is "native int" get labeled TYP_LONG.
+ // In the verification type system, we always transform "native int" to "TI_LONG" with the
+ // native int flag set.
+ // Ideally, we would keep track of which nodes labeled "TYP_LONG" are really "native int", but
+ // attempts to do that have proved too difficult. So in situations where we try to compare the
+ // verification type system and the node type system, we use this method, which allows the specific
+ // mismatch where "verTi" is TI_LONG with the native int flag and "nodeTi" is TI_LONG without the
+ // native int flag set.
+ static bool AreEquivalentModuloNativeInt(const typeInfo& verTi, const typeInfo& nodeTi)
+ {
+ if (AreEquivalent(verTi, nodeTi))
+ {
+ return true;
+ }
+#ifdef _TARGET_64BIT_
+ return (nodeTi.IsType(TI_I_IMPL) && tiCompatibleWith(nullptr, verTi, typeInfo::nativeInt(), true)) ||
+ (verTi.IsType(TI_I_IMPL) && tiCompatibleWith(nullptr, typeInfo::nativeInt(), nodeTi, true));
+#else // _TARGET_64BIT_
+ return false;
+#endif // !_TARGET_64BIT_
+ }
+#endif // DEBUG
+
+ static BOOL tiMergeToCommonParent(COMP_HANDLE CompHnd, typeInfo* pDest, const typeInfo* pSrc, bool* changed);
+ static BOOL tiCompatibleWith(COMP_HANDLE CompHnd,
+ const typeInfo& child,
+ const typeInfo& parent,
+ bool normalisedForStack);
+
+ static BOOL tiMergeCompatibleWith(COMP_HANDLE CompHnd,
+ const typeInfo& child,
+ const typeInfo& parent,
+ bool normalisedForStack);
+
+ /////////////////////////////////////////////////////////////////////////
+ // Operations
+ /////////////////////////////////////////////////////////////////////////
+
+ void SetIsThisPtr()
+ {
+ m_flags |= TI_FLAG_THIS_PTR;
+ assert(m_bits.thisPtr);
+ }
+
+ void ClearThisPtr()
+ {
+ m_flags &= ~(TI_FLAG_THIS_PTR);
+ }
+
+ void SetIsPermanentHomeByRef()
+ {
+ assert(IsByRef());
+ m_flags |= TI_FLAG_BYREF_PERMANENT_HOME;
+ }
+
+ void SetIsReadonlyByRef()
+ {
+ assert(IsByRef());
+ m_flags |= TI_FLAG_BYREF_READONLY;
+ }
+
+ // Set that this item is uninitialized.
+ void SetUninitialisedObjRef()
+ {
+ assert((IsObjRef() && IsThisPtr()));
+ // For now, this is used only to track uninit this ptrs in ctors
+
+ m_flags |= TI_FLAG_UNINIT_OBJREF;
+ assert(m_bits.uninitobj);
+ }
+
+ // Set that this item is initialised.
+ void SetInitialisedObjRef()
+ {
+ assert((IsObjRef() && IsThisPtr()));
+ // For now, this is used only to track uninit this ptrs in ctors
+
+ m_flags &= ~TI_FLAG_UNINIT_OBJREF;
+ }
+
+ typeInfo& DereferenceByRef()
+ {
+ if (!IsByRef())
+ {
+ m_flags = TI_ERROR;
+ INDEBUG(m_cls = NO_CLASS_HANDLE);
+ }
+ m_flags &= ~(TI_FLAG_THIS_PTR | TI_ALL_BYREF_FLAGS);
+ return *this;
+ }
+
+ typeInfo& MakeByRef()
+ {
+ assert(!IsByRef());
+ m_flags &= ~(TI_FLAG_THIS_PTR);
+ m_flags |= TI_FLAG_BYREF;
+ return *this;
+ }
+
+ // I1,I2 --> I4
+ // FLOAT --> DOUBLE
+ // objref, arrays, byrefs, value classes are unchanged
+ //
+ typeInfo& NormaliseForStack()
+ {
+ switch (GetType())
+ {
+ case TI_BYTE:
+ case TI_SHORT:
+ m_flags = TI_INT;
+ break;
+
+ case TI_FLOAT:
+ m_flags = TI_DOUBLE;
+ break;
+ default:
+ break;
+ }
+ return (*this);
+ }
+
+ /////////////////////////////////////////////////////////////////////////
+ // Getters
+ /////////////////////////////////////////////////////////////////////////
+
+ CORINFO_CLASS_HANDLE GetClassHandle() const
+ {
+ return m_cls;
+ }
+
+ CORINFO_CLASS_HANDLE GetClassHandleForValueClass() const
+ {
+ assert(IsType(TI_STRUCT));
+ assert(m_cls != NO_CLASS_HANDLE);
+ return m_cls;
+ }
+
+ CORINFO_CLASS_HANDLE GetClassHandleForObjRef() const
+ {
+ assert(IsType(TI_REF));
+ assert(m_cls != NO_CLASS_HANDLE);
+ return m_cls;
+ }
+
+ CORINFO_METHOD_HANDLE GetMethod() const
+ {
+ assert(GetType() == TI_METHOD);
+ return m_method;
+ }
+
+ // If FEATURE_CORECLR is enabled, GetMethod can be called
+ // before the pointer type is known to be a method pointer type.
+ CORINFO_METHOD_HANDLE GetMethod2() const
+ {
+ return m_method;
+ }
+
+ // Get this item's type
+ // If primitive, returns the primitive type (TI_*)
+ // If not primitive, returns:
+ // - TI_ERROR if a byref anything
+ // - TI_REF if a class or array or null or a generic type variable
+ // - TI_STRUCT if a value class
+ ti_types GetType() const
+ {
+ if (m_flags & TI_FLAG_BYREF)
+ {
+ return TI_ERROR;
+ }
+
+ // objref/array/null (objref), value class, ptr, primitive
+ return (ti_types)(m_flags & TI_FLAG_DATA_MASK);
+ }
+
+ BOOL IsType(ti_types type) const
+ {
+ assert(type != TI_ERROR);
+ return (m_flags & (TI_FLAG_DATA_MASK | TI_FLAG_BYREF | TI_FLAG_BYREF_READONLY | TI_FLAG_BYREF_PERMANENT_HOME |
+ TI_FLAG_GENERIC_TYPE_VAR)) == DWORD(type);
+ }
+
+ // Returns whether this is an objref
+ BOOL IsObjRef() const
+ {
+ return IsType(TI_REF) || IsType(TI_NULL);
+ }
+
+ // Returns whether this is a by-ref
+ BOOL IsByRef() const
+ {
+ return (m_flags & TI_FLAG_BYREF);
+ }
+
+ // Returns whether this is the this pointer
+ BOOL IsThisPtr() const
+ {
+ return (m_flags & TI_FLAG_THIS_PTR);
+ }
+
+ BOOL IsUnboxedGenericTypeVar() const
+ {
+ return !IsByRef() && (m_flags & TI_FLAG_GENERIC_TYPE_VAR);
+ }
+
+ BOOL IsReadonlyByRef() const
+ {
+ return IsByRef() && (m_flags & TI_FLAG_BYREF_READONLY);
+ }
+
+ BOOL IsPermanentHomeByRef() const
+ {
+ return IsByRef() && (m_flags & TI_FLAG_BYREF_PERMANENT_HOME);
+ }
+
+ // Returns whether this is a method desc
+ BOOL IsMethod() const
+ {
+ return (GetType() == TI_METHOD);
+ }
+
+ BOOL IsStruct() const
+ {
+ return IsType(TI_STRUCT);
+ }
+
+ // A byref value class is NOT a value class
+ BOOL IsValueClass() const
+ {
+ return (IsStruct() || IsPrimitiveType());
+ }
+
+ // Does not return true for primitives. Will return true for value types that behave
+ // as primitives
+ BOOL IsValueClassWithClsHnd() const
+ {
+ if ((GetType() == TI_STRUCT) ||
+ (m_cls && GetType() != TI_REF && GetType() != TI_METHOD &&
+ GetType() != TI_ERROR)) // necessary because if byref bit is set, we return TI_ERROR)
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ // Returns whether this is an integer or real number
+ // NOTE: Use NormaliseToPrimitiveType() if you think you may have a
+ // System.Int32 etc., because those types are not considered number
+ // types by this function.
+ BOOL IsNumberType() const
+ {
+ ti_types Type = GetType();
+
+ // I1, I2, Boolean, character etc. cannot exist plainly -
+ // everything is at least an I4
+
+ return (Type == TI_INT || Type == TI_LONG || Type == TI_DOUBLE);
+ }
+
+ // Returns whether this is an integer
+ // NOTE: Use NormaliseToPrimitiveType() if you think you may have a
+ // System.Int32 etc., because those types are not considered number
+ // types by this function.
+ BOOL IsIntegerType() const
+ {
+ ti_types Type = GetType();
+
+ // I1, I2, Boolean, character etc. cannot exist plainly -
+ // everything is at least an I4
+
+ return (Type == TI_INT || Type == TI_LONG);
+ }
+
+ // Returns true whether this is an integer or a native int.
+ BOOL IsIntOrNativeIntType() const
+ {
+#ifdef _TARGET_64BIT_
+ return (GetType() == TI_INT) || AreEquivalent(*this, nativeInt());
+#else
+ return IsType(TI_INT);
+#endif
+ }
+
+ BOOL IsNativeIntType() const
+ {
+ return AreEquivalent(*this, nativeInt());
+ }
+
+ // Returns whether this is a primitive type (not a byref, objref,
+ // array, null, value class, invalid value)
+ // May Need to normalise first (m/r/I4 --> I4)
+ BOOL IsPrimitiveType() const
+ {
+ DWORD Type = GetType();
+
+ // boolean, char, u1,u2 never appear on the operand stack
+ return (Type == TI_BYTE || Type == TI_SHORT || Type == TI_INT || Type == TI_LONG || Type == TI_FLOAT ||
+ Type == TI_DOUBLE);
+ }
+
+ // Returns whether this is the null objref
+ BOOL IsNullObjRef() const
+ {
+ return (IsType(TI_NULL));
+ }
+
+ // must be for a local which is an object type (i.e. has a slot >= 0)
+ // for primitive locals, use the liveness bitmap instead
+ // Note that this works if the error is 'Byref'
+ BOOL IsDead() const
+ {
+ return (m_flags & (TI_FLAG_DATA_MASK)) == TI_ERROR;
+ }
+
+ BOOL IsUninitialisedObjRef() const
+ {
+ return (m_flags & TI_FLAG_UNINIT_OBJREF);
+ }
+
+private:
+ // used to make functions that return typeinfo efficient.
+ typeInfo(DWORD flags, CORINFO_CLASS_HANDLE cls)
+ {
+ m_cls = cls;
+ m_flags = flags;
+ }
+
+ friend typeInfo ByRef(const typeInfo& ti);
+ friend typeInfo DereferenceByRef(const typeInfo& ti);
+ friend typeInfo NormaliseForStack(const typeInfo& ti);
+};
+
+inline typeInfo NormaliseForStack(const typeInfo& ti)
+{
+ return typeInfo(ti).NormaliseForStack();
+}
+
+// given ti make a byref to that type.
+inline typeInfo ByRef(const typeInfo& ti)
+{
+ return typeInfo(ti).MakeByRef();
+}
+
+// given ti which is a byref, return the type it points at
+inline typeInfo DereferenceByRef(const typeInfo& ti)
+{
+ return typeInfo(ti).DereferenceByRef();
+}
+/*****************************************************************************/
+#endif // _TYPEINFO_H_
+/*****************************************************************************/