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 
6 #ifndef __GCINFOTYPES_H__
7 #define __GCINFOTYPES_H__
8 
9 #ifndef FEATURE_REDHAWK
10 #include "gcinfo.h"
11 #endif
12 
13 
14 #define PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
15 
16 #define FIXED_STACK_PARAMETER_SCRATCH_AREA
17 
18 
19 #define BITS_PER_SIZE_T ((int)sizeof(size_t)*8)
20 
21 //--------------------------------------------------------------------------------
22 // It turns out, that ((size_t)x) << y == x, when y is not a literal
23 //      and its value is BITS_PER_SIZE_T
24 // I guess the processor only shifts of the right operand modulo BITS_PER_SIZE_T
25 // In many cases, we want the above operation to yield 0,
26 //      hence the following macros
27 //--------------------------------------------------------------------------------
SAFE_SHIFT_LEFT(size_t x,size_t count)28 __forceinline size_t SAFE_SHIFT_LEFT(size_t x, size_t count)
29 {
30     _ASSERTE(count <= BITS_PER_SIZE_T);
31     return (x << 1) << (count - 1);
32 }
SAFE_SHIFT_RIGHT(size_t x,size_t count)33 __forceinline size_t SAFE_SHIFT_RIGHT(size_t x, size_t count)
34 {
35     _ASSERTE(count <= BITS_PER_SIZE_T);
36     return (x >> 1) >> (count - 1);
37 }
38 
CeilOfLog2(size_t x)39 inline UINT32 CeilOfLog2(size_t x)
40 {
41     _ASSERTE(x > 0);
42     UINT32 result = (x & (x - 1)) ? 1 : 0;
43     while (x != 1)
44     {
45         result++;
46         x >>= 1;
47     }
48     return result;
49 }
50 
51 enum GcSlotFlags
52 {
53     GC_SLOT_BASE      = 0x0,
54     GC_SLOT_INTERIOR  = 0x1,
55     GC_SLOT_PINNED    = 0x2,
56     GC_SLOT_UNTRACKED = 0x4,
57 
58     // For internal use by the encoder/decoder
59     GC_SLOT_IS_REGISTER = 0x8,
60     GC_SLOT_IS_DELETED  = 0x10,
61 };
62 
63 enum GcStackSlotBase
64 {
65     GC_CALLER_SP_REL = 0x0,
66     GC_SP_REL        = 0x1,
67     GC_FRAMEREG_REL  = 0x2,
68 
69     GC_SPBASE_FIRST  = GC_CALLER_SP_REL,
70     GC_SPBASE_LAST   = GC_FRAMEREG_REL,
71 };
72 
73 #ifdef _DEBUG
74 const char* const GcStackSlotBaseNames[] =
75 {
76     "caller.sp",
77     "sp",
78     "frame",
79 };
80 #endif
81 
82 enum GcSlotState
83 {
84     GC_SLOT_DEAD = 0x0,
85     GC_SLOT_LIVE = 0x1,
86 };
87 
88 struct GcStackSlot
89 {
90     INT32 SpOffset;
91     GcStackSlotBase Base;
92 
93     bool operator==(const GcStackSlot& other)
94     {
95         return ((SpOffset == other.SpOffset) && (Base == other.Base));
96     }
97     bool operator!=(const GcStackSlot& other)
98     {
99         return ((SpOffset != other.SpOffset) || (Base != other.Base));
100     }
101 };
102 
103 //--------------------------------------------------------------------------------
104 // ReturnKind -- encoding return type information in GcInfo
105 //
106 // When a method is stopped at a call - site for GC (ex: via return-address
107 // hijacking) the runtime needs to know whether the value is a GC - value
108 // (gc - pointer or gc - pointers stored in an aggregate).
109 // It needs this information so that mark - phase can preserve the gc-pointers
110 // being returned.
111 //
112 // The Runtime doesn't need the precise return-type of a method.
113 // It only needs to find the GC-pointers in the return value.
114 // The only scenarios currently supported by CoreCLR are:
115 // 1. Object references
116 // 2. ByRef pointers
117 // 3. ARM64/X64 only : Structs returned in two registers
118 // 4. X86 only : Floating point returns to perform the correct save/restore
119 //    of the return value around return-hijacking.
120 //
121 // Based on these cases, the legal set of ReturnKind enumerations are specified
122 // for each architecture/encoding.
123 // A value of this enumeration is stored in the GcInfo header.
124 //
125 //--------------------------------------------------------------------------------
126 
127 // RT_Unset: An intermediate step for staged bringup.
128 // When ReturnKind is RT_Unset, it means that the JIT did not set
129 // the ReturnKind in the GCInfo, and therefore the VM cannot rely on it,
130 // and must use other mechanisms (similar to GcInfo ver 1) to determine
131 // the Return type's GC information.
132 //
133 // RT_Unset is only used in the following situations:
134 // X64: Used by JIT64 until updated to use GcInfo v2 API
135 // ARM: Used by JIT32 until updated to use GcInfo v2 API
136 //
137 // RT_Unset should have a valid encoding, whose bits are actually stored in the image.
138 // For X86, there are no free bits, and there's no RT_Unused enumeration.
139 
140 #if defined(_TARGET_X86_)
141 
142 // 00    RT_Scalar
143 // 01    RT_Object
144 // 10    RT_ByRef
145 // 11    RT_Float
146 
147 #elif defined(_TARGET_ARM_)
148 
149 // 00    RT_Scalar
150 // 01    RT_Object
151 // 10    RT_ByRef
152 // 11    RT_Unset
153 
154 #elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
155 
156 // Slim Header:
157 
158 // 00    RT_Scalar
159 // 01    RT_Object
160 // 10    RT_ByRef
161 // 11    RT_Unset
162 
163 // Fat Header:
164 
165 // 0000  RT_Scalar
166 // 0001  RT_Object
167 // 0010  RT_ByRef
168 // 0011  RT_Unset
169 // 0100  RT_Scalar_Obj
170 // 1000  RT_Scalar_ByRef
171 // 0101  RT_Obj_Obj
172 // 1001  RT_Obj_ByRef
173 // 0110  RT_ByRef_Obj
174 // 1010  RT_ByRef_ByRef
175 
176 #else
177 #ifdef PORTABILITY_WARNING
178 PORTABILITY_WARNING("Need ReturnKind for new Platform")
179 #endif // PORTABILITY_WARNING
180 #endif // Target checks
181 
182 enum ReturnKind {
183 
184     // Cases for Return in one register
185 
186     RT_Scalar = 0,
187     RT_Object = 1,
188     RT_ByRef = 2,
189 
190 #ifdef _TARGET_X86_
191     RT_Float = 3,       // Encoding 3 means RT_Float on X86
192 #else
193     RT_Unset = 3,       // RT_Unset on other platforms
194 #endif // _TARGET_X86_
195 
196     // Cases for Struct Return in two registers
197     //
198     // We have the following equivalencies, because the VM's behavior is the same
199     // for both cases:
200     // RT_Scalar_Scalar == RT_Scalar
201     // RT_Obj_Scalar    == RT_Object
202     // RT_ByRef_Scalar  == RT_Byref
203     // The encoding for these equivalencies will play out well because
204     // RT_Scalar is zero.
205     //
206     // Naming: RT_firstReg_secondReg
207     // Encoding: <Two bits for secondRef> <Two bits for first Reg>
208     //
209     // This encoding with exclusive bits for each register is chosen for ease of use,
210     // and because it doesn't cost any more bits.
211     // It can be changed (ex: to a linear sequence) if necessary.
212     // For example, we can encode the GC-information for the two registers in 3 bits (instead of 4)
213     // if we approximate RT_Obj_ByRef and RT_ByRef_Obj as RT_ByRef_ByRef.
214 
215     // RT_Scalar_Scalar = RT_Scalar
216     RT_Scalar_Obj   = RT_Object << 2 | RT_Scalar,
217     RT_Scalar_ByRef = RT_ByRef << 2  | RT_Scalar,
218 
219     // RT_Obj_Scalar   = RT_Object
220     RT_Obj_Obj      = RT_Object << 2 | RT_Object,
221     RT_Obj_ByRef    = RT_ByRef << 2  | RT_Object,
222 
223     // RT_ByRef_Scalar  = RT_Byref
224     RT_ByRef_Obj    = RT_Object << 2 | RT_ByRef,
225     RT_ByRef_ByRef  = RT_ByRef << 2  | RT_ByRef,
226 
227     // Illegal or uninitialized value,
228     // Not a valid encoding, never written to image.
229     RT_Illegal = 0xFF
230 };
231 
232 // Identify ReturnKinds containing useful information
IsValidReturnKind(ReturnKind returnKind)233 inline bool IsValidReturnKind(ReturnKind returnKind)
234 {
235     return (returnKind != RT_Illegal)
236 #ifndef _TARGET_X86_
237         && (returnKind != RT_Unset)
238 #endif // _TARGET_X86_
239         ;
240 }
241 
242 // Identify ReturnKinds that can be a part of a multi-reg struct return
IsValidFieldReturnKind(ReturnKind returnKind)243 inline bool IsValidFieldReturnKind(ReturnKind returnKind)
244 {
245     return (returnKind == RT_Scalar || returnKind == RT_Object || returnKind == RT_ByRef);
246 }
247 
IsValidReturnRegister(size_t regNo)248 inline bool IsValidReturnRegister(size_t regNo)
249 {
250     return (regNo == 0)
251 #ifdef FEATURE_MULTIREG_RETURN
252         || (regNo == 1)
253 #endif // FEATURE_MULTIREG_RETURN
254         ;
255 }
256 
IsStructReturnKind(ReturnKind returnKind)257 inline bool IsStructReturnKind(ReturnKind returnKind)
258 {
259     // Two bits encode integer/ref/float return-kinds.
260     // Encodings needing more than two bits are (non-scalar) struct-returns.
261     return returnKind > 3;
262 }
263 
264 // Helpers for combining/extracting individual ReturnKinds from/to Struct ReturnKinds.
265 // Encoding is two bits per register
266 
GetStructReturnKind(ReturnKind reg0,ReturnKind reg1)267 inline ReturnKind GetStructReturnKind(ReturnKind reg0, ReturnKind reg1)
268 {
269     _ASSERTE(IsValidFieldReturnKind(reg0) && IsValidFieldReturnKind(reg1));
270 
271     ReturnKind structReturnKind = (ReturnKind)(reg1 << 2 | reg0);
272 
273     _ASSERTE(IsValidReturnKind(structReturnKind));
274 
275     return structReturnKind;
276 }
277 
278 // Extract returnKind for the specified return register.
279 // Also determines if higher ordinal return registers contain object references
ExtractRegReturnKind(ReturnKind returnKind,size_t returnRegOrdinal,bool & moreRegs)280 inline ReturnKind ExtractRegReturnKind(ReturnKind returnKind, size_t returnRegOrdinal, bool& moreRegs)
281 {
282     _ASSERTE(IsValidReturnKind(returnKind));
283     _ASSERTE(IsValidReturnRegister(returnRegOrdinal));
284 
285     // Return kind of each return register is encoded in two bits at returnRegOrdinal*2 position from LSB
286     ReturnKind regReturnKind = (ReturnKind)((returnKind >> (returnRegOrdinal * 2)) & 3);
287 
288     // Check if any other higher ordinal return registers have object references.
289     // ReturnKind of higher ordinal return registers are encoded at (returnRegOrdinal+1)*2) position from LSB
290     // If all of the remaining bits are 0 then there isn't any more RT_Object or RT_ByRef encoded in returnKind.
291     moreRegs = (returnKind >> ((returnRegOrdinal+1) * 2)) != 0;
292 
293     _ASSERTE(IsValidReturnKind(regReturnKind));
294     _ASSERTE((returnRegOrdinal == 0) || IsValidFieldReturnKind(regReturnKind));
295 
296     return regReturnKind;
297 }
298 
ReturnKindToString(ReturnKind returnKind)299 inline const char *ReturnKindToString(ReturnKind returnKind)
300 {
301     switch (returnKind) {
302     case RT_Scalar: return "Scalar";
303     case RT_Object: return "Object";
304     case RT_ByRef:  return "ByRef";
305 #ifdef _TARGET_X86_
306     case RT_Float:  return "Float";
307 #else
308     case RT_Unset:         return "UNSET";
309 #endif // _TARGET_X86_
310     case RT_Scalar_Obj:    return "{Scalar, Object}";
311     case RT_Scalar_ByRef:  return "{Scalar, ByRef}";
312     case RT_Obj_Obj:       return "{Object, Object}";
313     case RT_Obj_ByRef:     return "{Object, ByRef}";
314     case RT_ByRef_Obj:     return "{ByRef, Object}";
315     case RT_ByRef_ByRef:   return "{ByRef, ByRef}";
316 
317     case RT_Illegal:   return "<Illegal>";
318     default: return "!Impossible!";
319     }
320 }
321 
322 #ifdef _TARGET_X86_
323 
324 #include <stdlib.h>     // For memcmp()
325 #include "bitvector.h"  // for ptrArgTP
326 
327 #ifndef FASTCALL
328 #define FASTCALL __fastcall
329 #endif
330 
331 // we use offsetof to get the offset of a field
332 #include <stddef.h> // offsetof
333 #ifndef offsetof
334 #define offsetof(s,m)   ((size_t)&(((s *)0)->m))
335 #endif
336 
337 enum infoHdrAdjustConstants {
338     // Constants
339     SET_FRAMESIZE_MAX = 7,
340     SET_ARGCOUNT_MAX = 8,  // Change to 6
341     SET_PROLOGSIZE_MAX = 16,
342     SET_EPILOGSIZE_MAX = 10,  // Change to 6
343     SET_EPILOGCNT_MAX = 4,
344     SET_UNTRACKED_MAX = 3,
345     SET_RET_KIND_MAX = 4,   // 2 bits for ReturnKind
346     ADJ_ENCODING_MAX = 0x7f, // Maximum valid encoding in a byte
347                              // Also used to mask off next bit from each encoding byte.
348     MORE_BYTES_TO_FOLLOW = 0x80 // If the High-bit of a header or adjustment byte
349                                // is set, then there are more adjustments to follow.
350 };
351 
352 //
353 // Enum to define codes that are used to incrementally adjust the InfoHdr structure.
354 // First set of opcodes
355 enum infoHdrAdjust {
356 
357     SET_FRAMESIZE = 0,                                            // 0x00
358     SET_ARGCOUNT = SET_FRAMESIZE + SET_FRAMESIZE_MAX + 1,      // 0x08
359     SET_PROLOGSIZE = SET_ARGCOUNT + SET_ARGCOUNT_MAX + 1,      // 0x11
360     SET_EPILOGSIZE = SET_PROLOGSIZE + SET_PROLOGSIZE_MAX + 1,      // 0x22
361     SET_EPILOGCNT = SET_EPILOGSIZE + SET_EPILOGSIZE_MAX + 1,      // 0x2d
362     SET_UNTRACKED = SET_EPILOGCNT + (SET_EPILOGCNT_MAX + 1) * 2, // 0x37
363 
364     FIRST_FLIP = SET_UNTRACKED + SET_UNTRACKED_MAX + 1,
365 
366     FLIP_EDI_SAVED = FIRST_FLIP, // 0x3b
367     FLIP_ESI_SAVED,           // 0x3c
368     FLIP_EBX_SAVED,           // 0x3d
369     FLIP_EBP_SAVED,           // 0x3e
370     FLIP_EBP_FRAME,           // 0x3f
371     FLIP_INTERRUPTIBLE,       // 0x40
372     FLIP_DOUBLE_ALIGN,        // 0x41
373     FLIP_SECURITY,            // 0x42
374     FLIP_HANDLERS,            // 0x43
375     FLIP_LOCALLOC,            // 0x44
376     FLIP_EDITnCONTINUE,       // 0x45
377     FLIP_VAR_PTR_TABLE_SZ,    // 0x46 Flip whether a table-size exits after the header encoding
378     FFFF_UNTRACKED_CNT,       // 0x47 There is a count (>SET_UNTRACKED_MAX) after the header encoding
379     FLIP_VARARGS,             // 0x48
380     FLIP_PROF_CALLBACKS,      // 0x49
381     FLIP_HAS_GS_COOKIE,       // 0x4A - The offset of the GuardStack cookie follows after the header encoding
382     FLIP_SYNC,                // 0x4B
383     FLIP_HAS_GENERICS_CONTEXT,// 0x4C
384     FLIP_GENERICS_CONTEXT_IS_METHODDESC,// 0x4D
385     FLIP_REV_PINVOKE_FRAME,   // 0x4E
386     NEXT_OPCODE,              // 0x4F -- see next Adjustment enumeration
387     NEXT_FOUR_START = 0x50,
388     NEXT_FOUR_FRAMESIZE = 0x50,
389     NEXT_FOUR_ARGCOUNT = 0x60,
390     NEXT_THREE_PROLOGSIZE = 0x70,
391     NEXT_THREE_EPILOGSIZE = 0x78
392 };
393 
394 // Second set of opcodes, when first code is 0x4F
395 enum infoHdrAdjust2 {
396     SET_RETURNKIND = 0,  // 0x00-SET_RET_KIND_MAX Set ReturnKind to value
397 };
398 
399 #define HAS_UNTRACKED               ((unsigned int) -1)
400 #define HAS_VARPTR                  ((unsigned int) -1)
401 
402 #define INVALID_REV_PINVOKE_OFFSET   0
403 #define HAS_REV_PINVOKE_FRAME_OFFSET ((unsigned int) -1)
404 // 0 is not a valid offset for EBP-frames as all locals are at a negative offset
405 // For ESP frames, the cookie is above (at a higher address than) the buffers,
406 // and so cannot be at offset 0.
407 #define INVALID_GS_COOKIE_OFFSET    0
408 // Temporary value to indicate that the offset needs to be read after the header
409 #define HAS_GS_COOKIE_OFFSET        ((unsigned int) -1)
410 
411 // 0 is not a valid sync offset
412 #define INVALID_SYNC_OFFSET         0
413 // Temporary value to indicate that the offset needs to be read after the header
414 #define HAS_SYNC_OFFSET             ((unsigned int) -1)
415 
416 #define INVALID_ARGTAB_OFFSET       0
417 
418 #include "pshpack1.h"
419 
420 // Working set optimization: saving 12 * 128 = 1536 bytes in infoHdrShortcut
421 struct InfoHdr;
422 
423 struct InfoHdrSmall {
424     unsigned char  prologSize;        // 0
425     unsigned char  epilogSize;        // 1
426     unsigned char  epilogCount : 3; // 2 [0:2]
427     unsigned char  epilogAtEnd : 1; // 2 [3]
428     unsigned char  ediSaved : 1; // 2 [4]      which callee-saved regs are pushed onto stack
429     unsigned char  esiSaved : 1; // 2 [5]
430     unsigned char  ebxSaved : 1; // 2 [6]
431     unsigned char  ebpSaved : 1; // 2 [7]
432     unsigned char  ebpFrame : 1; // 3 [0]      locals accessed relative to ebp
433     unsigned char  interruptible : 1; // 3 [1]      is intr. at all points (except prolog/epilog), not just call-sites
434     unsigned char  doubleAlign : 1; // 3 [2]      uses double-aligned stack (ebpFrame will be false)
435     unsigned char  security : 1; // 3 [3]      has slot for security object
436     unsigned char  handlers : 1; // 3 [4]      has callable handlers
437     unsigned char  localloc : 1; // 3 [5]      uses localloc
438     unsigned char  editNcontinue : 1; // 3 [6]      was JITed in EnC mode
439     unsigned char  varargs : 1; // 3 [7]      function uses varargs calling convention
440     unsigned char  profCallbacks : 1; // 4 [0]
441     unsigned char  genericsContext : 1;//4 [1]      function reports a generics context parameter is present
442     unsigned char  genericsContextIsMethodDesc : 1;//4[2]
443     unsigned char  returnKind : 2; // 4 [4]  Available GcInfo v2 onwards, previously undefined
444     unsigned short argCount;          // 5,6        in bytes
445     unsigned int   frameSize;         // 7,8,9,10   in bytes
446     unsigned int   untrackedCnt;      // 11,12,13,14
447     unsigned int   varPtrTableSize;   // 15.16,17,18
448 
449                                       // Checks whether "this" is compatible with "target".
450                                       // It is not an exact bit match as "this" could have some
451                                       // marker/place-holder values, which will have to be written out
452                                       // after the header.
453 
454     bool isHeaderMatch(const InfoHdr& target) const;
455 };
456 
457 
458 struct InfoHdr : public InfoHdrSmall {
459     // 0 (zero) means that there is no GuardStack cookie
460     // The cookie is either at ESP+gsCookieOffset or EBP-gsCookieOffset
461     unsigned int   gsCookieOffset;    // 19,20,21,22
462     unsigned int   syncStartOffset;   // 23,24,25,26
463     unsigned int   syncEndOffset;     // 27,28,29,30
464     unsigned int   revPInvokeOffset;  // 31,32,33,34 Available GcInfo v2 onwards, previously undefined
465                                       // 35 bytes total
466 
467                                       // Checks whether "this" is compatible with "target".
468                                       // It is not an exact bit match as "this" could have some
469                                       // marker/place-holder values, which will have to be written out
470                                       // after the header.
471 
isHeaderMatchInfoHdr472     bool isHeaderMatch(const InfoHdr& target) const
473     {
474 #ifdef _ASSERTE
475         // target cannot have place-holder values.
476         _ASSERTE(target.untrackedCnt != HAS_UNTRACKED &&
477             target.varPtrTableSize != HAS_VARPTR &&
478             target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
479             target.syncStartOffset != HAS_SYNC_OFFSET &&
480             target.revPInvokeOffset != HAS_REV_PINVOKE_FRAME_OFFSET);
481 #endif
482 
483         // compare two InfoHdr's up to but not including the untrackCnt field
484         if (memcmp(this, &target, offsetof(InfoHdr, untrackedCnt)) != 0)
485             return false;
486 
487         if (untrackedCnt != target.untrackedCnt) {
488             if (target.untrackedCnt <= SET_UNTRACKED_MAX)
489                 return false;
490             else if (untrackedCnt != HAS_UNTRACKED)
491                 return false;
492         }
493 
494         if (varPtrTableSize != target.varPtrTableSize) {
495             if ((varPtrTableSize != 0) != (target.varPtrTableSize != 0))
496                 return false;
497         }
498 
499         if ((gsCookieOffset == INVALID_GS_COOKIE_OFFSET) !=
500             (target.gsCookieOffset == INVALID_GS_COOKIE_OFFSET))
501             return false;
502 
503         if ((syncStartOffset == INVALID_SYNC_OFFSET) !=
504             (target.syncStartOffset == INVALID_SYNC_OFFSET))
505             return false;
506 
507         if ((revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET) !=
508             (target.revPInvokeOffset == INVALID_REV_PINVOKE_OFFSET))
509             return false;
510 
511         return true;
512     }
513 };
514 
515 
516 union CallPattern {
517     struct {
518         unsigned char argCnt;
519         unsigned char regMask;  // EBP=0x8, EBX=0x4, ESI=0x2, EDI=0x1
520         unsigned char argMask;
521         unsigned char codeDelta;
522     }            fld;
523     unsigned     val;
524 };
525 
526 #include "poppack.h"
527 
528 #define IH_MAX_PROLOG_SIZE (51)
529 
530 extern const InfoHdrSmall infoHdrShortcut[];
531 extern int                infoHdrLookup[];
532 
GetInfoHdr(int index,InfoHdr * header)533 inline void GetInfoHdr(int index, InfoHdr * header)
534 {
535     *((InfoHdrSmall *)header) = infoHdrShortcut[index];
536 
537     header->gsCookieOffset = INVALID_GS_COOKIE_OFFSET;
538     header->syncStartOffset = INVALID_SYNC_OFFSET;
539     header->syncEndOffset = INVALID_SYNC_OFFSET;
540     header->revPInvokeOffset = INVALID_REV_PINVOKE_OFFSET;
541 }
542 
543 PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, UINT32 version, InfoHdr* header);
544 
545 uint8_t FASTCALL encodeHeaderFirst(const InfoHdr& header, InfoHdr* state, int* more, int *pCached);
546 uint8_t FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state, uint8_t &codeSet);
547 
548 size_t FASTCALL decodeUnsigned(PTR_CBYTE src, unsigned* value);
549 size_t FASTCALL decodeUDelta(PTR_CBYTE src, unsigned* value, unsigned lastValue);
550 size_t FASTCALL decodeSigned(PTR_CBYTE src, int     * value);
551 
552 #define CP_MAX_CODE_DELTA  (0x23)
553 #define CP_MAX_ARG_CNT     (0x02)
554 #define CP_MAX_ARG_MASK    (0x00)
555 
556 extern const unsigned callPatternTable[];
557 extern const unsigned callCommonDelta[];
558 
559 
560 int  FASTCALL lookupCallPattern(unsigned    argCnt,
561     unsigned    regMask,
562     unsigned    argMask,
563     unsigned    codeDelta);
564 
565 void FASTCALL decodeCallPattern(int         pattern,
566     unsigned *  argCnt,
567     unsigned *  regMask,
568     unsigned *  argMask,
569     unsigned *  codeDelta);
570 
571 #endif // _TARGET_86_
572 
573 // Stack offsets must be 8-byte aligned, so we use this unaligned
574 //  offset to represent that the method doesn't have a security object
575 #define NO_SECURITY_OBJECT        (-1)
576 #define NO_GS_COOKIE              (-1)
577 #define NO_STACK_BASE_REGISTER    (0xffffffff)
578 #define NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA (0xffffffff)
579 #define NO_GENERICS_INST_CONTEXT  (-1)
580 #define NO_REVERSE_PINVOKE_FRAME  (-1)
581 #define NO_PSP_SYM                (-1)
582 
583 #if defined(_TARGET_AMD64_)
584 
585 #ifndef TARGET_POINTER_SIZE
586 #define TARGET_POINTER_SIZE 8    // equal to sizeof(void*) and the managed pointer size in bytes for this target
587 #endif
588 #define NUM_NORM_CODE_OFFSETS_PER_CHUNK (64)
589 #define NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 (6)
590 #define NORMALIZE_STACK_SLOT(x) ((x)>>3)
591 #define DENORMALIZE_STACK_SLOT(x) ((x)<<3)
592 #define NORMALIZE_CODE_LENGTH(x) (x)
593 #define DENORMALIZE_CODE_LENGTH(x) (x)
594 // Encode RBP as 0
595 #define NORMALIZE_STACK_BASE_REGISTER(x) ((x) ^ 5)
596 #define DENORMALIZE_STACK_BASE_REGISTER(x) ((x) ^ 5)
597 #define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>3)
598 #define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<3)
599 #define CODE_OFFSETS_NEED_NORMALIZATION 0
600 #define NORMALIZE_CODE_OFFSET(x) (x)
601 #define DENORMALIZE_CODE_OFFSET(x) (x)
602 #define NORMALIZE_REGISTER(x) (x)
603 #define DENORMALIZE_REGISTER(x) (x)
604 #define NORMALIZE_NUM_SAFE_POINTS(x) (x)
605 #define DENORMALIZE_NUM_SAFE_POINTS(x) (x)
606 #define NORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
607 #define DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
608 
609 #define PSP_SYM_STACK_SLOT_ENCBASE 6
610 #define GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE 6
611 #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6
612 #define GS_COOKIE_STACK_SLOT_ENCBASE 6
613 #define CODE_LENGTH_ENCBASE 8
614 #define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2
615 #define SIZE_OF_RETURN_KIND_IN_FAT_HEADER  4
616 #define STACK_BASE_REGISTER_ENCBASE 3
617 #define SIZE_OF_STACK_AREA_ENCBASE 3
618 #define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 4
619 #define REVERSE_PINVOKE_FRAME_ENCBASE 6
620 #define NUM_REGISTERS_ENCBASE 2
621 #define NUM_STACK_SLOTS_ENCBASE 2
622 #define NUM_UNTRACKED_SLOTS_ENCBASE 1
623 #define NORM_PROLOG_SIZE_ENCBASE 5
624 #define NORM_EPILOG_SIZE_ENCBASE 3
625 #define NORM_CODE_OFFSET_DELTA_ENCBASE 3
626 #define INTERRUPTIBLE_RANGE_DELTA1_ENCBASE 6
627 #define INTERRUPTIBLE_RANGE_DELTA2_ENCBASE 6
628 #define REGISTER_ENCBASE 3
629 #define REGISTER_DELTA_ENCBASE 2
630 #define STACK_SLOT_ENCBASE 6
631 #define STACK_SLOT_DELTA_ENCBASE 4
632 #define NUM_SAFE_POINTS_ENCBASE 2
633 #define NUM_INTERRUPTIBLE_RANGES_ENCBASE 1
634 #define NUM_EH_CLAUSES_ENCBASE 2
635 #define POINTER_SIZE_ENCBASE 3
636 #define LIVESTATE_RLE_RUN_ENCBASE 2
637 #define LIVESTATE_RLE_SKIP_ENCBASE 4
638 
639 #elif defined(_TARGET_ARM_)
640 
641 #ifndef TARGET_POINTER_SIZE
642 #define TARGET_POINTER_SIZE 4   // equal to sizeof(void*) and the managed pointer size in bytes for this target
643 #endif
644 #define NUM_NORM_CODE_OFFSETS_PER_CHUNK (64)
645 #define NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 (6)
646 #define NORMALIZE_STACK_SLOT(x) ((x)>>2)
647 #define DENORMALIZE_STACK_SLOT(x) ((x)<<2)
648 #define NORMALIZE_CODE_LENGTH(x) ((x)>>1)
649 #define DENORMALIZE_CODE_LENGTH(x) ((x)<<1)
650 // Encode R11 as zero
651 #define NORMALIZE_STACK_BASE_REGISTER(x) ((((x) - 4) & 7) ^ 7)
652 #define DENORMALIZE_STACK_BASE_REGISTER(x) (((x) ^ 7) + 4)
653 #define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>2)
654 #define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<2)
655 #define CODE_OFFSETS_NEED_NORMALIZATION 1
656 #define NORMALIZE_CODE_OFFSET(x) (x)   // Instructions are 2/4 bytes long in Thumb/ARM states,
657 #define DENORMALIZE_CODE_OFFSET(x) (x) // but the safe-point offsets are encoded with a -1 adjustment.
658 #define NORMALIZE_REGISTER(x) (x)
659 #define DENORMALIZE_REGISTER(x) (x)
660 #define NORMALIZE_NUM_SAFE_POINTS(x) (x)
661 #define DENORMALIZE_NUM_SAFE_POINTS(x) (x)
662 #define NORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
663 #define DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
664 
665 // The choices of these encoding bases only affects space overhead
666 // and performance, not semantics/correctness.
667 #define PSP_SYM_STACK_SLOT_ENCBASE 5
668 #define GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE 5
669 #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 5
670 #define GS_COOKIE_STACK_SLOT_ENCBASE 5
671 #define CODE_LENGTH_ENCBASE 7
672 #define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2
673 #define SIZE_OF_RETURN_KIND_IN_FAT_HEADER  2
674 #define STACK_BASE_REGISTER_ENCBASE 1
675 #define SIZE_OF_STACK_AREA_ENCBASE 3
676 #define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 3
677 #define REVERSE_PINVOKE_FRAME_ENCBASE 5
678 #define NUM_REGISTERS_ENCBASE 2
679 #define NUM_STACK_SLOTS_ENCBASE 3
680 #define NUM_UNTRACKED_SLOTS_ENCBASE 3
681 #define NORM_PROLOG_SIZE_ENCBASE 5
682 #define NORM_EPILOG_SIZE_ENCBASE 3
683 #define NORM_CODE_OFFSET_DELTA_ENCBASE 3
684 #define INTERRUPTIBLE_RANGE_DELTA1_ENCBASE 4
685 #define INTERRUPTIBLE_RANGE_DELTA2_ENCBASE 6
686 #define REGISTER_ENCBASE 2
687 #define REGISTER_DELTA_ENCBASE 1
688 #define STACK_SLOT_ENCBASE 6
689 #define STACK_SLOT_DELTA_ENCBASE 4
690 #define NUM_SAFE_POINTS_ENCBASE 3
691 #define NUM_INTERRUPTIBLE_RANGES_ENCBASE 2
692 #define NUM_EH_CLAUSES_ENCBASE 3
693 #define POINTER_SIZE_ENCBASE 3
694 #define LIVESTATE_RLE_RUN_ENCBASE 2
695 #define LIVESTATE_RLE_SKIP_ENCBASE 4
696 
697 #elif defined(_TARGET_ARM64_)
698 
699 #ifndef TARGET_POINTER_SIZE
700 #define TARGET_POINTER_SIZE 8    // equal to sizeof(void*) and the managed pointer size in bytes for this target
701 #endif
702 #define NUM_NORM_CODE_OFFSETS_PER_CHUNK (64)
703 #define NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 (6)
704 #define NORMALIZE_STACK_SLOT(x) ((x)>>3)   // GC Pointers are 8-bytes aligned
705 #define DENORMALIZE_STACK_SLOT(x) ((x)<<3)
706 #define NORMALIZE_CODE_LENGTH(x) ((x)>>2)   // All Instructions are 4 bytes long
707 #define DENORMALIZE_CODE_LENGTH(x) ((x)<<2)
708 #define NORMALIZE_STACK_BASE_REGISTER(x) ((x)^29) // Encode Frame pointer X29 as zero
709 #define DENORMALIZE_STACK_BASE_REGISTER(x) ((x)^29)
710 #define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>3)
711 #define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<3)
712 #define CODE_OFFSETS_NEED_NORMALIZATION 0
713 #define NORMALIZE_CODE_OFFSET(x) (x)   // Instructions are 4 bytes long, but the safe-point
714 #define DENORMALIZE_CODE_OFFSET(x) (x) // offsets are encoded with a -1 adjustment.
715 #define NORMALIZE_REGISTER(x) (x)
716 #define DENORMALIZE_REGISTER(x) (x)
717 #define NORMALIZE_NUM_SAFE_POINTS(x) (x)
718 #define DENORMALIZE_NUM_SAFE_POINTS(x) (x)
719 #define NORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
720 #define DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
721 
722 #define PSP_SYM_STACK_SLOT_ENCBASE 6
723 #define GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE 6
724 #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6
725 #define GS_COOKIE_STACK_SLOT_ENCBASE 6
726 #define CODE_LENGTH_ENCBASE 8
727 #define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2
728 #define SIZE_OF_RETURN_KIND_IN_FAT_HEADER  4
729 #define STACK_BASE_REGISTER_ENCBASE 2 // FP encoded as 0, SP as 2.
730 #define SIZE_OF_STACK_AREA_ENCBASE 3
731 #define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 4
732 #define REVERSE_PINVOKE_FRAME_ENCBASE 6
733 #define NUM_REGISTERS_ENCBASE 3
734 #define NUM_STACK_SLOTS_ENCBASE 2
735 #define NUM_UNTRACKED_SLOTS_ENCBASE 1
736 #define NORM_PROLOG_SIZE_ENCBASE 5
737 #define NORM_EPILOG_SIZE_ENCBASE 3
738 #define NORM_CODE_OFFSET_DELTA_ENCBASE 3
739 #define INTERRUPTIBLE_RANGE_DELTA1_ENCBASE 6
740 #define INTERRUPTIBLE_RANGE_DELTA2_ENCBASE 6
741 #define REGISTER_ENCBASE 3
742 #define REGISTER_DELTA_ENCBASE 2
743 #define STACK_SLOT_ENCBASE 6
744 #define STACK_SLOT_DELTA_ENCBASE 4
745 #define NUM_SAFE_POINTS_ENCBASE 3
746 #define NUM_INTERRUPTIBLE_RANGES_ENCBASE 1
747 #define NUM_EH_CLAUSES_ENCBASE 2
748 #define POINTER_SIZE_ENCBASE 3
749 #define LIVESTATE_RLE_RUN_ENCBASE 2
750 #define LIVESTATE_RLE_SKIP_ENCBASE 4
751 
752 #else
753 
754 #ifndef _TARGET_X86_
755 #ifdef PORTABILITY_WARNING
756 PORTABILITY_WARNING("Please specialize these definitions for your platform!")
757 #endif
758 #endif
759 
760 #ifndef TARGET_POINTER_SIZE
761 #define TARGET_POINTER_SIZE 4   // equal to sizeof(void*) and the managed pointer size in bytes for this target
762 #endif
763 #define NUM_NORM_CODE_OFFSETS_PER_CHUNK (64)
764 #define NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 (6)
765 #define NORMALIZE_STACK_SLOT(x) (x)
766 #define DENORMALIZE_STACK_SLOT(x) (x)
767 #define NORMALIZE_CODE_LENGTH(x) (x)
768 #define DENORMALIZE_CODE_LENGTH(x) (x)
769 #define NORMALIZE_STACK_BASE_REGISTER(x) (x)
770 #define DENORMALIZE_STACK_BASE_REGISTER(x) (x)
771 #define NORMALIZE_SIZE_OF_STACK_AREA(x) (x)
772 #define DENORMALIZE_SIZE_OF_STACK_AREA(x) (x)
773 #define CODE_OFFSETS_NEED_NORMALIZATION 0
774 #define NORMALIZE_CODE_OFFSET(x) (x)
775 #define DENORMALIZE_CODE_OFFSET(x) (x)
776 #define NORMALIZE_REGISTER(x) (x)
777 #define DENORMALIZE_REGISTER(x) (x)
778 #define NORMALIZE_NUM_SAFE_POINTS(x) (x)
779 #define DENORMALIZE_NUM_SAFE_POINTS(x) (x)
780 #define NORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
781 #define DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
782 
783 #define PSP_SYM_STACK_SLOT_ENCBASE 6
784 #define GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE 6
785 #define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6
786 #define GS_COOKIE_STACK_SLOT_ENCBASE 6
787 #define CODE_LENGTH_ENCBASE 6
788 #define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2
789 #define SIZE_OF_RETURN_KIND_IN_FAT_HEADER  2
790 #define STACK_BASE_REGISTER_ENCBASE 3
791 #define SIZE_OF_STACK_AREA_ENCBASE 6
792 #define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 3
793 #define REVERSE_PINVOKE_FRAME_ENCBASE 6
794 #define NUM_REGISTERS_ENCBASE 3
795 #define NUM_STACK_SLOTS_ENCBASE 5
796 #define NUM_UNTRACKED_SLOTS_ENCBASE 5
797 #define NORM_PROLOG_SIZE_ENCBASE 4
798 #define NORM_EPILOG_SIZE_ENCBASE 3
799 #define NORM_CODE_OFFSET_DELTA_ENCBASE 3
800 #define INTERRUPTIBLE_RANGE_DELTA1_ENCBASE 5
801 #define INTERRUPTIBLE_RANGE_DELTA2_ENCBASE 5
802 #define REGISTER_ENCBASE 3
803 #define REGISTER_DELTA_ENCBASE REGISTER_ENCBASE
804 #define STACK_SLOT_ENCBASE 6
805 #define STACK_SLOT_DELTA_ENCBASE 4
806 #define NUM_SAFE_POINTS_ENCBASE 4
807 #define NUM_INTERRUPTIBLE_RANGES_ENCBASE 1
808 #define NUM_EH_CLAUSES_ENCBASE 2
809 #define POINTER_SIZE_ENCBASE 3
810 #define LIVESTATE_RLE_RUN_ENCBASE 2
811 #define LIVESTATE_RLE_SKIP_ENCBASE 4
812 
813 #endif
814 
815 #endif // !__GCINFOTYPES_H__
816 
817