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