Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / _typeinfo.h
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 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                          _typeInfo                                         XX
9 XX                                                                           XX
10 XX                                                                           XX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 */
14
15 /*****************************************************************************
16  This header file is named _typeInfo.h to be distinguished from typeinfo.h
17  in the NT SDK
18 ******************************************************************************/
19
20 /*****************************************************************************/
21 #ifndef _TYPEINFO_H_
22 #define _TYPEINFO_H_
23 /*****************************************************************************/
24
25 enum ti_types
26 {
27 #define DEF_TI(ti, nm) ti,
28 #include "titypes.h"
29 #undef DEF_TI
30     TI_ONLY_ENUM = TI_METHOD, // Enum values with greater value are completely described by the enumeration.
31 };
32
33 #if defined(_TARGET_64BIT_)
34 #define TI_I_IMPL TI_LONG
35 #else
36 #define TI_I_IMPL TI_INT
37 #endif
38
39 #ifdef DEBUG
40 #if VERBOSE_VERIFY
41 #define TI_DUMP_PADDING "                                          "
42 #ifdef _MSC_VER
43 namespace
44 {
45 #endif // _MSC_VER
46 SELECTANY const char* g_ti_type_names_map[] = {
47 #define DEF_TI(ti, nm) nm,
48 #include "titypes.h"
49 #undef DEF_TI
50 };
51 #ifdef _MSC_VER
52 }
53 #endif // _MSC_VER
54 #endif // VERBOSE_VERIFY
55 #endif // DEBUG
56
57 #ifdef _MSC_VER
58 namespace
59 {
60 #endif //  _MSC_VER
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,
63 #include "typelist.h"
64 #undef DEF_TP
65 };
66 #ifdef _MSC_VER
67 }
68 #endif // _MSC_VER
69
70 #ifdef DEBUG
71 #if VERBOSE_VERIFY
72 inline const char* tiType2Str(ti_types type)
73 {
74     return g_ti_type_names_map[type];
75 }
76 #endif // VERBOSE_VERIFY
77 #endif // DEBUG
78
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)
82 {
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];
90 }
91
92 #ifdef _MSC_VER
93 namespace
94 {
95 #endif // _MSC_VER
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,
121 };
122 #ifdef _MSC_VER
123 }
124 #endif // _MSC_VER
125
126 // Convert the type returned from the VM to a ti_type.
127
128 inline ti_types JITtype2tiType(CorInfoType type)
129 {
130     // spot check to make certain enumerations have not changed
131
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);
137
138     type = CorInfoType(type & CORINFO_TYPE_MASK); // strip off modifiers
139
140     assert(type < CORINFO_TYPE_COUNT);
141
142     assert(g_ti_types_map[type] != TI_ERROR || type == CORINFO_TYPE_VOID);
143     return g_ti_types_map[type];
144 };
145
146 /*****************************************************************************
147  * Declares the typeInfo class, which represents the type of an entity on the
148  * stack, in a local variable or an argument.
149  *
150  * Flags: LLLLLLLLLLLLLLLLffffffffffTTTTTT
151  *
152  * L = local var # or instance field #
153  * x = unused
154  * f = flags
155  * T = type
156  *
157  * The lower bits are used to store the type component, and may be one of:
158  *
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
163  *
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.
167  *
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:
177  *
178  *    (TI_REF, <type-variable-type-handle>) == boxed type variable
179  *
180  *    (TI_REF, <type-variable-type-handle>)
181  *          + TI_FLAG_GENERIC_TYPE_VAR      == unboxed type variable
182  *
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.
189  *
190  */
191
192 #define TI_FLAG_DATA_BITS 6
193 #define TI_FLAG_DATA_MASK ((1 << TI_FLAG_DATA_BITS) - 1)
194
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>
198
199 #define TI_FLAG_UNINIT_OBJREF 0x00000040
200
201 // Flag indicating this item is a byref <something>
202
203 #define TI_FLAG_BYREF 0x00000080
204
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
209 // constraint call.
210
211 #define TI_FLAG_BYREF_READONLY 0x00000100
212
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.
216
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
224
225 // This item contains resolved token. It is used for ctor delegate optimization.
226 #define TI_FLAG_TOKEN 0x00000400
227
228 // This item contains the 'this' pointer (used for tracking)
229
230 #define TI_FLAG_THIS_PTR 0x00001000
231
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.
236 //
237 // Instructions that generate a permanent home byref:
238 //
239 //  ldelema
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
243 //  dup
244 //  unbox
245
246 #define TI_FLAG_BYREF_PERMANENT_HOME 0x00002000
247
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
255
256 // Number of bits local var # is shifted
257
258 #define TI_FLAG_LOCAL_VAR_SHIFT 16
259 #define TI_FLAG_LOCAL_VAR_MASK 0xFFFF0000
260
261 // Field info uses the same space as the local info
262
263 #define TI_FLAG_FIELD_SHIFT TI_FLAG_LOCAL_VAR_SHIFT
264 #define TI_FLAG_FIELD_MASK TI_FLAG_LOCAL_VAR_MASK
265
266 #define TI_ALL_BYREF_FLAGS (TI_FLAG_BYREF | TI_FLAG_BYREF_READONLY | TI_FLAG_BYREF_PERMANENT_HOME)
267
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
276  *   uninitialized
277  *
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.
281  */
282
283 class typeInfo
284 {
285
286 private:
287     union {
288         struct
289         {
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
300         } m_bits;
301
302         DWORD m_flags;
303     };
304
305     union {
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;
311     };
312
313     template <typename T>
314     static bool isInvalidHandle(const T handle)
315     {
316         static_assert(std::is_same<T, CORINFO_CLASS_HANDLE>::value || std::is_same<T, CORINFO_METHOD_HANDLE>::value,
317                       "");
318 #ifdef _HOST_64BIT_
319         return handle == reinterpret_cast<T>(0xcccccccccccccccc);
320 #else
321         return handle == reinterpret_cast<T>(0xcccccccc);
322 #endif
323     }
324
325 public:
326     typeInfo() : m_flags(TI_ERROR)
327     {
328         m_cls = NO_CLASS_HANDLE;
329     }
330
331     typeInfo(ti_types tiType)
332     {
333         assert((tiType >= TI_BYTE) && (tiType <= TI_NULL));
334         assert(tiType <= TI_FLAG_DATA_MASK);
335
336         m_flags = (DWORD)tiType;
337         m_cls   = NO_CLASS_HANDLE;
338     }
339
340     typeInfo(var_types varType)
341     {
342         m_flags = (DWORD)varType2tiType(varType);
343         m_cls   = NO_CLASS_HANDLE;
344     }
345
346     static typeInfo nativeInt()
347     {
348         typeInfo result = typeInfo(TI_I_IMPL);
349 #ifdef _TARGET_64BIT_
350         result.m_flags |= TI_FLAG_NATIVE_INT;
351 #endif
352         return result;
353     }
354
355     typeInfo(ti_types tiType, CORINFO_CLASS_HANDLE cls, bool typeVar = false)
356     {
357         assert(tiType == TI_STRUCT || tiType == TI_REF);
358         assert(cls != nullptr && !isInvalidHandle(cls));
359         m_flags = tiType;
360         if (typeVar)
361         {
362             m_flags |= TI_FLAG_GENERIC_TYPE_VAR;
363         }
364         m_cls = cls;
365     }
366
367     typeInfo(CORINFO_METHOD_HANDLE method)
368     {
369         assert(method != nullptr && !isInvalidHandle(method));
370         m_flags  = TI_METHOD;
371         m_method = method;
372     }
373
374     typeInfo(CORINFO_RESOLVED_TOKEN* token)
375     {
376         assert(token != nullptr);
377         assert(token->hMethod != nullptr);
378         assert(!isInvalidHandle(token->hMethod));
379         m_flags = TI_METHOD;
380         SetIsToken();
381         m_token = token;
382     }
383
384 #ifdef DEBUG
385 #if VERBOSE_VERIFY
386     void Dump() const;
387 #endif // VERBOSE_VERIFY
388 #endif // DEBUG
389
390 public:
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
395     // the bit
396     static bool AreEquivalent(const typeInfo& li, const typeInfo& ti)
397     {
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_
403
404         if ((li.m_flags & allFlags) != (ti.m_flags & allFlags))
405         {
406             return false;
407         }
408
409         unsigned type = li.m_flags & TI_FLAG_DATA_MASK;
410         assert(TI_ERROR <
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)
413         {
414             return true;
415         }
416         if (type == TI_ERROR)
417         {
418             return false; // TI_ERROR != TI_ERROR
419         }
420         assert(li.m_cls != NO_CLASS_HANDLE && ti.m_cls != NO_CLASS_HANDLE);
421         return li.m_cls == ti.m_cls;
422     }
423
424 #ifdef DEBUG
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)
434     {
435         if (AreEquivalent(verTi, nodeTi))
436         {
437             return true;
438         }
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_
443         return false;
444 #endif // !_TARGET_64BIT_
445     }
446 #endif // DEBUG
447
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);
453
454     static BOOL tiMergeCompatibleWith(COMP_HANDLE     CompHnd,
455                                       const typeInfo& child,
456                                       const typeInfo& parent,
457                                       bool            normalisedForStack);
458
459     /////////////////////////////////////////////////////////////////////////
460     // Operations
461     /////////////////////////////////////////////////////////////////////////
462
463     void SetIsToken()
464     {
465         m_flags |= TI_FLAG_TOKEN;
466         assert(m_bits.token);
467     }
468
469     void SetIsThisPtr()
470     {
471         m_flags |= TI_FLAG_THIS_PTR;
472         assert(m_bits.thisPtr);
473     }
474
475     void ClearThisPtr()
476     {
477         m_flags &= ~(TI_FLAG_THIS_PTR);
478     }
479
480     void SetIsPermanentHomeByRef()
481     {
482         assert(IsByRef());
483         m_flags |= TI_FLAG_BYREF_PERMANENT_HOME;
484     }
485
486     void SetIsReadonlyByRef()
487     {
488         assert(IsByRef());
489         m_flags |= TI_FLAG_BYREF_READONLY;
490     }
491
492     // Set that this item is uninitialized.
493     void SetUninitialisedObjRef()
494     {
495         assert((IsObjRef() && IsThisPtr()));
496         // For now, this is used only  to track uninit this ptrs in ctors
497
498         m_flags |= TI_FLAG_UNINIT_OBJREF;
499         assert(m_bits.uninitobj);
500     }
501
502     // Set that this item is initialised.
503     void SetInitialisedObjRef()
504     {
505         assert((IsObjRef() && IsThisPtr()));
506         // For now, this is used only  to track uninit this ptrs in ctors
507
508         m_flags &= ~TI_FLAG_UNINIT_OBJREF;
509     }
510
511     typeInfo& DereferenceByRef()
512     {
513         if (!IsByRef())
514         {
515             m_flags = TI_ERROR;
516             INDEBUG(m_cls = NO_CLASS_HANDLE);
517         }
518         m_flags &= ~(TI_FLAG_THIS_PTR | TI_ALL_BYREF_FLAGS);
519         return *this;
520     }
521
522     typeInfo& MakeByRef()
523     {
524         assert(!IsByRef());
525         m_flags &= ~(TI_FLAG_THIS_PTR);
526         m_flags |= TI_FLAG_BYREF;
527         return *this;
528     }
529
530     // I1,I2 --> I4
531     // FLOAT --> DOUBLE
532     // objref, arrays, byrefs, value classes are unchanged
533     //
534     typeInfo& NormaliseForStack()
535     {
536         switch (GetType())
537         {
538             case TI_BYTE:
539             case TI_SHORT:
540                 m_flags = TI_INT;
541                 break;
542
543             case TI_FLOAT:
544                 m_flags = TI_DOUBLE;
545                 break;
546             default:
547                 break;
548         }
549         return (*this);
550     }
551
552     /////////////////////////////////////////////////////////////////////////
553     // Getters
554     /////////////////////////////////////////////////////////////////////////
555
556     CORINFO_CLASS_HANDLE GetClassHandle() const
557     {
558         return m_cls;
559     }
560
561     CORINFO_CLASS_HANDLE GetClassHandleForValueClass() const
562     {
563         assert(IsType(TI_STRUCT));
564         assert(m_cls != NO_CLASS_HANDLE);
565         return m_cls;
566     }
567
568     CORINFO_CLASS_HANDLE GetClassHandleForObjRef() const
569     {
570         assert(IsType(TI_REF));
571         assert(m_cls != NO_CLASS_HANDLE);
572         return m_cls;
573     }
574
575     CORINFO_METHOD_HANDLE GetMethod() const
576     {
577         assert(GetType() == TI_METHOD);
578         if (IsToken())
579         {
580             return m_token->hMethod;
581         }
582         return m_method;
583     }
584
585     CORINFO_RESOLVED_TOKEN* GetToken() const
586     {
587         assert(IsToken());
588         return m_token;
589     }
590
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
598     {
599         if (m_flags & TI_FLAG_BYREF)
600         {
601             return TI_ERROR;
602         }
603
604         // objref/array/null (objref), value class, ptr, primitive
605         return (ti_types)(m_flags & TI_FLAG_DATA_MASK);
606     }
607
608     BOOL IsType(ti_types type) const
609     {
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);
613     }
614
615     // Returns whether this is an objref
616     BOOL IsObjRef() const
617     {
618         return IsType(TI_REF) || IsType(TI_NULL);
619     }
620
621     // Returns whether this is a by-ref
622     BOOL IsByRef() const
623     {
624         return (m_flags & TI_FLAG_BYREF);
625     }
626
627     // Returns whether this is the this pointer
628     BOOL IsThisPtr() const
629     {
630         return (m_flags & TI_FLAG_THIS_PTR);
631     }
632
633     BOOL IsUnboxedGenericTypeVar() const
634     {
635         return !IsByRef() && (m_flags & TI_FLAG_GENERIC_TYPE_VAR);
636     }
637
638     BOOL IsReadonlyByRef() const
639     {
640         return IsByRef() && (m_flags & TI_FLAG_BYREF_READONLY);
641     }
642
643     BOOL IsPermanentHomeByRef() const
644     {
645         return IsByRef() && (m_flags & TI_FLAG_BYREF_PERMANENT_HOME);
646     }
647
648     // Returns whether this is a method desc
649     BOOL IsMethod() const
650     {
651         return GetType() == TI_METHOD;
652     }
653
654     BOOL IsStruct() const
655     {
656         return IsType(TI_STRUCT);
657     }
658
659     // A byref value class is NOT a value class
660     BOOL IsValueClass() const
661     {
662         return (IsStruct() || IsPrimitiveType());
663     }
664
665     // Does not return true for primitives. Will return true for value types that behave
666     // as primitives
667     BOOL IsValueClassWithClsHnd() const
668     {
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)
672         {
673             return TRUE;
674         }
675         else
676         {
677             return FALSE;
678         }
679     }
680
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
686     {
687         ti_types Type = GetType();
688
689         // I1, I2, Boolean, character etc. cannot exist plainly -
690         // everything is at least an I4
691
692         return (Type == TI_INT || Type == TI_LONG || Type == TI_DOUBLE);
693     }
694
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
700     {
701         ti_types Type = GetType();
702
703         // I1, I2, Boolean, character etc. cannot exist plainly -
704         // everything is at least an I4
705
706         return (Type == TI_INT || Type == TI_LONG);
707     }
708
709     // Returns true whether this is an integer or a native int.
710     BOOL IsIntOrNativeIntType() const
711     {
712 #ifdef _TARGET_64BIT_
713         return (GetType() == TI_INT) || AreEquivalent(*this, nativeInt());
714 #else
715         return IsType(TI_INT);
716 #endif
717     }
718
719     BOOL IsNativeIntType() const
720     {
721         return AreEquivalent(*this, nativeInt());
722     }
723
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
728     {
729         DWORD Type = GetType();
730
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 ||
733                 Type == TI_DOUBLE);
734     }
735
736     // Returns whether this is the null objref
737     BOOL IsNullObjRef() const
738     {
739         return (IsType(TI_NULL));
740     }
741
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'
745     BOOL IsDead() const
746     {
747         return (m_flags & (TI_FLAG_DATA_MASK)) == TI_ERROR;
748     }
749
750     BOOL IsUninitialisedObjRef() const
751     {
752         return (m_flags & TI_FLAG_UNINIT_OBJREF);
753     }
754
755     BOOL IsToken() const
756     {
757         return IsMethod() && ((m_flags & TI_FLAG_TOKEN) != 0);
758     }
759
760 private:
761     // used to make functions that return typeinfo efficient.
762     typeInfo(DWORD flags, CORINFO_CLASS_HANDLE cls)
763     {
764         m_cls   = cls;
765         m_flags = flags;
766     }
767
768     friend typeInfo ByRef(const typeInfo& ti);
769     friend typeInfo DereferenceByRef(const typeInfo& ti);
770     friend typeInfo NormaliseForStack(const typeInfo& ti);
771 };
772
773 inline typeInfo NormaliseForStack(const typeInfo& ti)
774 {
775     return typeInfo(ti).NormaliseForStack();
776 }
777
778 // given ti make a byref to that type.
779 inline typeInfo ByRef(const typeInfo& ti)
780 {
781     return typeInfo(ti).MakeByRef();
782 }
783
784 // given ti which is a byref, return the type it points at
785 inline typeInfo DereferenceByRef(const typeInfo& ti)
786 {
787     return typeInfo(ti).DereferenceByRef();
788 }
789 /*****************************************************************************/
790 #endif // _TYPEINFO_H_
791 /*****************************************************************************/