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
6XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7XX XX
8XX _typeInfo XX
9XX XX
10XX XX
11XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
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
25enum 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
43namespace
44{
45#endif // _MSC_VER
46SELECTANY 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
58namespace
59{
60#endif // _MSC_VER
61SELECTANY 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
72inline 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
81inline 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
93namespace
94{
95#endif // _MSC_VER
96SELECTANY 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
128inline 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 generic 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 specially.
281 */
282
283class typeInfo
284{
285
286private:
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
325public:
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
390public:
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
760private:
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
773inline typeInfo NormaliseForStack(const typeInfo& ti)
774{
775 return typeInfo(ti).NormaliseForStack();
776}
777
778// given ti make a byref to that type.
779inline 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
785inline typeInfo DereferenceByRef(const typeInfo& ti)
786{
787 return typeInfo(ti).DereferenceByRef();
788}
789/*****************************************************************************/
790#endif // _TYPEINFO_H_
791/*****************************************************************************/
792