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 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 | |
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 | /*****************************************************************************/ |
792 | |