Merge pull request #6467 from briansull/multireg-return2
[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 above this are completely described by the enumeration
31     TI_COUNT
32 };
33
34 #if defined(_TARGET_64BIT_)
35 #define TI_I_IMPL TI_LONG
36 #else
37 #define TI_I_IMPL TI_INT
38 #endif
39
40 #ifdef DEBUG
41 #if VERBOSE_VERIFY
42 #define TI_DUMP_PADDING "                                          "
43 #ifdef _MSC_VER
44 namespace
45 {
46 #endif // _MSC_VER
47     SELECTANY const char* g_ti_type_names_map[] =
48     {
49 #define DEF_TI(ti, nm) nm,
50 #include "titypes.h"
51 #undef DEF_TI
52     };
53 #ifdef _MSC_VER
54 }
55 #endif // _MSC_VER
56 #endif // VERBOSE_VERIFY
57 #endif // DEBUG
58
59 #ifdef _MSC_VER
60 namespace
61 {
62 #endif //  _MSC_VER
63     SELECTANY const ti_types g_jit_types_map[] =
64     {
65 #define DEF_TP(tn,nm,jitType,verType,sz,sze,asze,st,al,tf,howUsed) verType,
66 #include "typelist.h"
67 #undef  DEF_TP
68     };
69 #ifdef _MSC_VER
70 }
71 #endif // _MSC_VER
72
73 #ifdef DEBUG
74 #if VERBOSE_VERIFY
75 inline const char* tiType2Str(ti_types type)
76 {
77     return g_ti_type_names_map[type];
78 }
79 #endif // VERBOSE_VERIFY
80 #endif // DEBUG
81
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)
85 {
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];
93 }
94
95 #ifdef _MSC_VER
96 namespace
97 {
98 #endif // _MSC_VER
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,
124     };
125 #ifdef  _MSC_VER
126 }
127 #endif // _MSC_VER
128
129 // Convert the type returned from the VM to a ti_type.
130
131 inline ti_types JITtype2tiType(CorInfoType type)
132 {
133     // spot check to make certain enumerations have not changed
134
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);
140
141     type = CorInfoType(type & CORINFO_TYPE_MASK); // strip off modifiers
142
143     assert(type < CORINFO_TYPE_COUNT);
144
145     assert(g_ti_types_map[type] != TI_ERROR || type == CORINFO_TYPE_VOID);
146     return g_ti_types_map[type];
147 };
148
149 /*****************************************************************************
150  * Declares the typeInfo class, which represents the type of an entity on the
151  * stack, in a local variable or an argument. 
152  *
153  * Flags: LLLLLLLLLLLLLLLLffffffffffTTTTTT
154  *
155  * L = local var # or instance field #
156  * x = unused
157  * f = flags
158  * T = type
159  *
160  * The lower bits are used to store the type component, and may be one of:
161  *
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
166  *
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.
170  *
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:
180  *
181  *    (TI_REF, <type-variable-type-handle>) == boxed type variable
182  *
183  *    (TI_REF, <type-variable-type-handle>) 
184  *          + TI_FLAG_GENERIC_TYPE_VAR      == unboxed type variable
185  *
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.
192  *
193  */
194
195     // TI_COUNT is less than or equal to TI_FLAG_DATA_MASK
196
197 #define TI_FLAG_DATA_BITS              6
198 #define TI_FLAG_DATA_MASK              ((1 << TI_FLAG_DATA_BITS)-1)
199
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>
203
204 #define TI_FLAG_UNINIT_OBJREF        0x00000040
205
206     // Flag indicating this item is a byref <something>
207
208 #define TI_FLAG_BYREF                0x00000080
209
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 
214     // constraint call.
215
216 #define TI_FLAG_BYREF_READONLY       0x00000100
217
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.
221
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
229
230     // This item contains the 'this' pointer (used for tracking)
231
232 #define TI_FLAG_THIS_PTR             0x00001000
233
234
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.
239 //
240 // Instructions that generate a permanent home byref:
241 //  
242 //  ldelema
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
246 //  dup
247 //  unbox
248
249 #define TI_FLAG_BYREF_PERMANENT_HOME 0x00002000
250
251
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
259
260     // Number of bits local var # is shifted
261
262 #define TI_FLAG_LOCAL_VAR_SHIFT       16
263 #define TI_FLAG_LOCAL_VAR_MASK        0xFFFF0000
264
265     // Field info uses the same space as the local info
266
267 #define TI_FLAG_FIELD_SHIFT           TI_FLAG_LOCAL_VAR_SHIFT
268 #define TI_FLAG_FIELD_MASK            TI_FLAG_LOCAL_VAR_MASK
269
270 #define TI_ALL_BYREF_FLAGS           (TI_FLAG_BYREF|                    \
271                                       TI_FLAG_BYREF_READONLY |          \
272                                       TI_FLAG_BYREF_PERMANENT_HOME)
273
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 
282  *   uninitialized
283  *
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.
287  */
288
289 class typeInfo
290 {
291
292 private:
293     union {
294         struct {
295             ti_types type             : 6;
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
304         } m_bits; 
305         
306         DWORD       m_flags;
307     };
308     
309     union {            
310         CORINFO_CLASS_HANDLE  m_cls;  
311         // Valid only for type TI_METHOD 
312         CORINFO_METHOD_HANDLE m_method;
313     };
314
315     template<typename T>
316     static bool isInvalidHandle(const T handle)
317     {
318         static_assert(std::is_same<T, CORINFO_CLASS_HANDLE>::value || std::is_same<T, CORINFO_METHOD_HANDLE>::value, "");
319 #ifdef _HOST_64BIT_
320         return handle == reinterpret_cast<T>(0xcccccccccccccccc);
321 #else
322         return handle == reinterpret_cast<T>(0xcccccccc);
323 #endif
324     }
325
326 public:
327     typeInfo():m_flags(TI_ERROR) 
328     {
329         m_cls = NO_CLASS_HANDLE;
330     }
331
332     typeInfo(ti_types tiType) 
333     { 
334         assert((tiType >= TI_BYTE) && (tiType <= TI_NULL));
335         assert(tiType <= TI_FLAG_DATA_MASK);
336
337         m_flags = (DWORD) tiType;
338         m_cls = NO_CLASS_HANDLE;
339     }
340
341     typeInfo(var_types varType) 
342     { 
343         m_flags = (DWORD) varType2tiType(varType);
344         m_cls = NO_CLASS_HANDLE;
345     }
346
347     static typeInfo nativeInt()
348     {
349         typeInfo result = typeInfo(TI_I_IMPL);
350 #ifdef _TARGET_64BIT_ 
351         result.m_flags |= TI_FLAG_NATIVE_INT;
352 #endif
353         return result;
354     }
355
356     typeInfo(ti_types tiType, CORINFO_CLASS_HANDLE cls, bool typeVar = false) 
357     {
358         assert(tiType == TI_STRUCT || tiType == TI_REF);
359         assert(cls != 0 && !isInvalidHandle(cls));
360         m_flags = tiType;
361         if (typeVar) 
362             m_flags |= TI_FLAG_GENERIC_TYPE_VAR;
363         m_cls   = cls;
364     }
365
366     typeInfo(CORINFO_METHOD_HANDLE method)
367     {
368         assert(method != 0 && !isInvalidHandle(method));
369         m_flags = TI_METHOD;
370         m_method = method;
371     }
372
373 #ifdef DEBUG
374 #if VERBOSE_VERIFY
375     void Dump() const;
376 #endif // VERBOSE_VERIFY
377 #endif // DEBUG
378
379 public:   
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
384     // the bit
385     static bool AreEquivalent(const typeInfo& li, const typeInfo& ti)
386     {
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_
391
392         if ((li.m_flags & allFlags) != (ti.m_flags & allFlags))
393         {
394             return false;
395         }
396
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) 
400             return true;
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;
405     }
406
407 #ifdef DEBUG
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)
417     {
418         if (AreEquivalent(verTi, nodeTi)) return true;
419         // Otherwise...
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_
424         return false;
425 #endif // !_TARGET_64BIT_
426
427     }
428 #endif // DEBUG
429
430
431     static BOOL tiMergeToCommonParent     (COMP_HANDLE CompHnd, typeInfo *pDest, 
432                                                   const typeInfo *pSrc,
433                                                   bool* changed) ;
434     static BOOL tiCompatibleWith          (COMP_HANDLE CompHnd, const typeInfo& child,
435                                                   const typeInfo& parent,
436                                                   bool normalisedForStack) ;
437
438     static BOOL tiMergeCompatibleWith     (COMP_HANDLE CompHnd, const typeInfo& child,
439                                           const typeInfo& parent,
440                                           bool normalisedForStack) ;
441
442
443     /////////////////////////////////////////////////////////////////////////
444     // Operations
445     /////////////////////////////////////////////////////////////////////////
446
447     void SetIsThisPtr()
448     {
449         m_flags |= TI_FLAG_THIS_PTR;
450         assert(m_bits.thisPtr);
451     }
452
453     void ClearThisPtr()
454     {
455         m_flags &= ~(TI_FLAG_THIS_PTR);
456     }
457
458     void SetIsPermanentHomeByRef()
459     {
460         assert(IsByRef());
461         m_flags |= TI_FLAG_BYREF_PERMANENT_HOME;
462     }
463     
464     void SetIsReadonlyByRef()
465     {
466         assert(IsByRef());
467         m_flags |= TI_FLAG_BYREF_READONLY;
468     }
469
470     // Set that this item is uninitialized.  
471     void SetUninitialisedObjRef()
472     {
473         assert((IsObjRef() && IsThisPtr()));
474         // For now, this is used only  to track uninit this ptrs in ctors
475
476         m_flags |= TI_FLAG_UNINIT_OBJREF;
477         assert(m_bits.uninitobj);
478     }
479
480     // Set that this item is initialised.
481     void SetInitialisedObjRef()
482     {
483         assert((IsObjRef() && IsThisPtr()));
484         // For now, this is used only  to track uninit this ptrs in ctors
485
486         m_flags &= ~TI_FLAG_UNINIT_OBJREF;
487     }
488
489     typeInfo& DereferenceByRef()
490     {
491         if (!IsByRef()) {
492             m_flags = TI_ERROR;
493             INDEBUG(m_cls = NO_CLASS_HANDLE);
494         }
495         m_flags &= ~(TI_FLAG_THIS_PTR | TI_ALL_BYREF_FLAGS);
496         return *this;
497     }
498
499     typeInfo& MakeByRef()
500     {
501         assert(!IsByRef());
502         m_flags &= ~(TI_FLAG_THIS_PTR);
503         m_flags |= TI_FLAG_BYREF;
504         return *this;
505     }
506
507     // I1,I2 --> I4
508     // FLOAT --> DOUBLE
509     // objref, arrays, byrefs, value classes are unchanged
510     //
511     typeInfo& NormaliseForStack()
512     {
513         switch (GetType())
514         {
515         case TI_BYTE:
516         case TI_SHORT:
517             m_flags = TI_INT;
518             break;
519
520         case TI_FLOAT:
521             m_flags = TI_DOUBLE;
522             break;
523         default:
524             break;
525         }
526         return (*this);
527     }
528
529     /////////////////////////////////////////////////////////////////////////
530     // Getters
531     /////////////////////////////////////////////////////////////////////////
532
533     CORINFO_CLASS_HANDLE GetClassHandle()  const
534     {
535         return m_cls;
536     }
537
538     CORINFO_CLASS_HANDLE GetClassHandleForValueClass()  const
539     {
540         assert(IsType(TI_STRUCT));
541         assert(m_cls != NO_CLASS_HANDLE);
542         return m_cls;
543     }
544
545     CORINFO_CLASS_HANDLE GetClassHandleForObjRef()  const
546     {
547         assert(IsType(TI_REF));
548         assert(m_cls != NO_CLASS_HANDLE);
549         return m_cls;
550     }
551
552     CORINFO_METHOD_HANDLE GetMethod()  const
553     {
554         assert(GetType() == TI_METHOD);
555         return m_method;
556     }
557
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
561     {
562         return m_method;
563     }    
564     
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
572     {
573         if (m_flags & TI_FLAG_BYREF)
574             return TI_ERROR;
575
576         // objref/array/null (objref), value class, ptr, primitive
577         return (ti_types)(m_flags & TI_FLAG_DATA_MASK); 
578     }
579
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);
584     }
585
586     // Returns whether this is an objref
587     BOOL IsObjRef() const
588     {
589         return IsType(TI_REF) || IsType(TI_NULL);
590     }
591
592     // Returns whether this is a by-ref
593     BOOL IsByRef() const
594     {
595         return (m_flags & TI_FLAG_BYREF);
596     }
597
598     // Returns whether this is the this pointer
599     BOOL IsThisPtr() const
600     {
601         return (m_flags & TI_FLAG_THIS_PTR);
602     }
603
604     BOOL IsUnboxedGenericTypeVar() const
605     {
606         return !IsByRef() && (m_flags & TI_FLAG_GENERIC_TYPE_VAR);
607     }
608
609     BOOL IsReadonlyByRef() const
610     {
611         return IsByRef() && (m_flags & TI_FLAG_BYREF_READONLY);
612     }
613
614     BOOL IsPermanentHomeByRef() const
615     {
616         return IsByRef() && (m_flags & TI_FLAG_BYREF_PERMANENT_HOME);
617     }
618
619     // Returns whether this is a method desc
620     BOOL IsMethod() const
621     {
622         return (GetType() == TI_METHOD);
623     }
624
625     BOOL IsStruct() const
626     {
627         return IsType(TI_STRUCT); 
628     }
629    
630     // A byref value class is NOT a value class
631     BOOL IsValueClass() const
632     {
633         return (IsStruct() || IsPrimitiveType());     
634     }
635
636     // Does not return true for primitives. Will return true for value types that behave
637     // as primitives
638     BOOL IsValueClassWithClsHnd() const
639     {
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)
644         {
645             return TRUE;
646         }
647         else
648         {
649             return FALSE;
650         }
651     }
652
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
658     {
659         ti_types Type = GetType();
660
661         // I1, I2, Boolean, character etc. cannot exist plainly - 
662         // everything is at least an I4
663
664         return (Type == TI_INT || 
665                 Type == TI_LONG || 
666                 Type == TI_DOUBLE);
667     }
668
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
674     {
675         ti_types Type = GetType();
676
677         // I1, I2, Boolean, character etc. cannot exist plainly - 
678         // everything is at least an I4
679
680         return (Type == TI_INT || 
681                 Type == TI_LONG);
682     }
683
684     // Returns true whether this is an integer or a native int.
685     BOOL IsIntOrNativeIntType() const
686     {
687 #ifdef _TARGET_64BIT_
688         return (GetType() == TI_INT) || AreEquivalent(*this, nativeInt());
689 #else
690         return IsType(TI_INT);
691 #endif
692     }
693
694     BOOL IsNativeIntType() const
695     {
696         return AreEquivalent(*this, nativeInt());
697     }
698
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
703     {
704         DWORD Type = GetType();
705
706         // boolean, char, u1,u2 never appear on the operand stack
707         return (Type == TI_BYTE || 
708                 Type == TI_SHORT ||
709                 Type == TI_INT || 
710                 Type == TI_LONG ||
711                 Type == TI_FLOAT || 
712                 Type == TI_DOUBLE);
713     }
714
715     // Returns whether this is the null objref
716     BOOL IsNullObjRef() const
717     {
718         return (IsType(TI_NULL));
719     }
720
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' 
724     BOOL IsDead() const
725     {
726         return (m_flags & (TI_FLAG_DATA_MASK)) == TI_ERROR;
727     }
728
729     BOOL IsUninitialisedObjRef() const
730     {
731         return (m_flags & TI_FLAG_UNINIT_OBJREF);
732     }
733
734 private:
735     // used to make functions that return typeinfo efficient.
736     typeInfo(DWORD flags, CORINFO_CLASS_HANDLE cls) 
737     {
738         m_cls   = cls;
739         m_flags = flags;
740     }
741      
742     friend typeInfo ByRef(const typeInfo& ti);
743     friend typeInfo DereferenceByRef(const typeInfo& ti);
744     friend typeInfo NormaliseForStack(const typeInfo& ti);
745 };
746
747 inline
748 typeInfo NormaliseForStack(const typeInfo& ti) 
749 {
750     return typeInfo(ti).NormaliseForStack();
751 }
752
753 // given ti make a byref to that type. 
754 inline
755 typeInfo ByRef(const typeInfo& ti) 
756 {
757     return typeInfo(ti).MakeByRef();
758 }
759
760  
761 // given ti which is a byref, return the type it points at
762 inline
763 typeInfo DereferenceByRef(const typeInfo& ti) 
764 {
765     return typeInfo(ti).DereferenceByRef();
766 }
767 /*****************************************************************************/
768 #endif // _TYPEINFO_H_
769 /*****************************************************************************/