summaryrefslogtreecommitdiff
path: root/src/inc/gcinfotypes.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/inc/gcinfotypes.h')
-rw-r--r--src/inc/gcinfotypes.h832
1 files changed, 832 insertions, 0 deletions
diff --git a/src/inc/gcinfotypes.h b/src/inc/gcinfotypes.h
new file mode 100644
index 0000000000..cd19759634
--- /dev/null
+++ b/src/inc/gcinfotypes.h
@@ -0,0 +1,832 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+#ifndef __GCINFOTYPES_H__
+#define __GCINFOTYPES_H__
+
+#include "gcinfo.h"
+
+// This file is included when building an "alt jit". In that case, we are doing a cross-compile:
+// we may be building the ARM jit on x86, for example. We generally make that work by conditionalizing on
+// a _TARGET_XXX_ variable that we explicitly set in the build, rather than the _XXX_ variable implicitly
+// set by the compiler. But this file is *also* included by the runtime, and needs in that case to be
+// conditionalized by the actual platform we're compiling for. We solve this by:
+// 1) conditionalizing on _TARGET_XXX_ in this file,
+// 2) having a _TARGET_SET_ variable so we know whether we're in a compilation for JIT in which some
+// _TARGET_XXX_ has already been set, and
+// 3) if _TARGET_SET_ is not set, set the _TARGET_XXX_ variable appropriate for the current _XXX_.
+//
+#ifndef _TARGET_SET_
+
+//#ifdef _X86_
+//#define _TARGET_X86_
+//#endif
+
+//#ifdef _AMD64_
+//#define _TARGET_AMD64_
+//#endif
+
+//#ifdef _ARM_
+//#define _TARGET_ARM_
+//#endif
+
+#endif // _TARGET_SET_
+
+#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
+#define PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
+#endif
+
+#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
+//
+// The EH vector mechanism is not completely worked out,
+// so it's temporarily disabled. We rely on fully-interruptible instead.
+//
+#define DISABLE_EH_VECTORS
+#endif
+
+#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM_) || defined(_TARGET_ARM64_)
+#define FIXED_STACK_PARAMETER_SCRATCH_AREA
+#endif
+
+#define BITS_PER_SIZE_T ((int)sizeof(size_t)*8)
+
+
+//--------------------------------------------------------------------------------
+// It turns out, that ((size_t)x) << y == x, when y is not a literal
+// and its value is BITS_PER_SIZE_T
+// I guess the processor only shifts of the right operand modulo BITS_PER_SIZE_T
+// In many cases, we want the above operation to yield 0,
+// hence the following macros
+//--------------------------------------------------------------------------------
+__forceinline size_t SAFE_SHIFT_LEFT(size_t x, size_t count)
+{
+ _ASSERTE(count <= BITS_PER_SIZE_T);
+ return (x << 1) << (count - 1);
+}
+__forceinline size_t SAFE_SHIFT_RIGHT(size_t x, size_t count)
+{
+ _ASSERTE(count <= BITS_PER_SIZE_T);
+ return (x >> 1) >> (count - 1);
+}
+
+inline UINT32 CeilOfLog2(size_t x)
+{
+ _ASSERTE(x > 0);
+ UINT32 result = (x & (x - 1)) ? 1 : 0;
+ while (x != 1)
+ {
+ result++;
+ x >>= 1;
+ }
+ return result;
+}
+
+enum GcSlotFlags
+{
+ GC_SLOT_BASE = 0x0,
+ GC_SLOT_INTERIOR = 0x1,
+ GC_SLOT_PINNED = 0x2,
+ GC_SLOT_UNTRACKED = 0x4,
+
+ // For internal use by the encoder/decoder
+ GC_SLOT_IS_REGISTER = 0x8,
+ GC_SLOT_IS_DELETED = 0x10,
+};
+
+enum GcStackSlotBase
+{
+ GC_CALLER_SP_REL = 0x0,
+ GC_SP_REL = 0x1,
+ GC_FRAMEREG_REL = 0x2,
+
+ GC_SPBASE_FIRST = GC_CALLER_SP_REL,
+ GC_SPBASE_LAST = GC_FRAMEREG_REL,
+};
+
+#ifdef _DEBUG
+const char* const GcStackSlotBaseNames[] =
+{
+ "caller.sp",
+ "sp",
+ "frame",
+};
+#endif
+
+enum GcSlotState
+{
+ GC_SLOT_DEAD = 0x0,
+ GC_SLOT_LIVE = 0x1,
+};
+
+struct GcStackSlot
+{
+ INT32 SpOffset;
+ GcStackSlotBase Base;
+
+ bool operator==(const GcStackSlot& other)
+ {
+ return ((SpOffset == other.SpOffset) && (Base == other.Base));
+ }
+ bool operator!=(const GcStackSlot& other)
+ {
+ return ((SpOffset != other.SpOffset) || (Base != other.Base));
+ }
+};
+
+//--------------------------------------------------------------------------------
+// ReturnKind -- encoding return type information in GcInfo
+//
+// When a method is stopped at a call - site for GC (ex: via return-address
+// hijacking) the runtime needs to know whether the value is a GC - value
+// (gc - pointer or gc - pointers stored in an aggregate).
+// It needs this information so that mark - phase can preserve the gc-pointers
+// being returned.
+//
+// The Runtime doesn't need the precise return-type of a method.
+// It only needs to find the GC-pointers in the return value.
+// The only scenarios currently supported by CoreCLR are:
+// 1. Object references
+// 2. ByRef pointers
+// 3. ARM64/X64 only : Structs returned in two registers
+// 4. X86 only : Floating point returns to perform the correct save/restore
+// of the return value around return-hijacking.
+//
+// Based on these cases, the legal set of ReturnKind enumerations are specified
+// for each architecture/encoding.
+// A value of this enumeration is stored in the GcInfo header.
+//
+//--------------------------------------------------------------------------------
+
+// RT_Unset: An intermediate step for staged bringup.
+// When ReturnKind is RT_Unset, it means that the JIT did not set
+// the ReturnKind in the GCInfo, and therefore the VM cannot rely on it,
+// and must use other mechanisms (similar to GcInfo ver 1) to determine
+// the Return type's GC information.
+//
+// RT_Unset is only used in the following situations:
+// X64: Used by JIT64 until updated to use GcInfo v2 API
+// ARM: Used by JIT32 until updated to use GcInfo v2 API
+//
+// RT_Unset should have a valid encoding, whose bits are actually stored in the image.
+// For X86, there are no free bits, and there's no RT_Unused enumeration.
+
+#if defined(_TARGET_X86_)
+
+// 00 RT_Scalar
+// 01 RT_Object
+// 10 RT_ByRef
+// 11 RT_Float
+
+#elif defined(_TARGET_ARM_)
+
+// 00 RT_Scalar
+// 01 RT_Object
+// 10 RT_ByRef
+// 11 RT_Unset
+
+#elif defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
+
+// Slim Header:
+
+// 00 RT_Scalar
+// 01 RT_Object
+// 10 RT_ByRef
+// 11 RT_Unset
+
+// Fat Header:
+
+// 0000 RT_Scalar
+// 0001 RT_Object
+// 0010 RT_ByRef
+// 0011 RT_Unset
+// 0100 RT_Scalar_Obj
+// 1000 RT_Scalar_ByRef
+// 0101 RT_Obj_Obj
+// 1001 RT_Obj_ByRef
+// 0110 RT_ByRef_Obj
+// 1010 RT_ByRef_ByRef
+
+#else
+#ifdef PORTABILITY_WARNING
+PORTABILITY_WARNING("Need ReturnKind for new Platform")
+#endif // PORTABILITY_WARNING
+#endif // Target checks
+
+enum ReturnKind {
+
+ // Cases for Return in one register
+
+ RT_Scalar = 0,
+ RT_Object = 1,
+ RT_ByRef = 2,
+
+#ifdef _TARGET_X86_
+ RT_Float = 3, // Encoding 3 means RT_Float on X86
+#else
+ RT_Unset = 3, // RT_Unset on other platforms
+#endif // _TARGET_X86_
+
+ // Cases for Struct Return in two registers
+ //
+ // We have the following equivalencies, because the VM's behavior is the same
+ // for both cases:
+ // RT_Scalar_Scalar == RT_Scalar
+ // RT_Obj_Scalar == RT_Object
+ // RT_ByRef_Scalar == RT_Byref
+ // The encoding for these equivalencies will play out well because
+ // RT_Scalar is zero.
+ //
+ // Naming: RT_firstReg_secondReg
+ // Encoding: <Two bits for secondRef> <Two bits for first Reg>
+ //
+ // This encoding with exclusive bits for each register is chosen for ease of use,
+ // and because it doesn't cost any more bits.
+ // It can be changed (ex: to a linear sequence) if necessary.
+ // For example, we can encode the GC-information for the two registers in 3 bits (instead of 4)
+ // if we approximate RT_Obj_ByRef and RT_ByRef_Obj as RT_ByRef_ByRef.
+
+ // RT_Scalar_Scalar = RT_Scalar
+ RT_Scalar_Obj = RT_Object << 2 | RT_Scalar,
+ RT_Scalar_ByRef = RT_ByRef << 2 | RT_Scalar,
+
+ // RT_Obj_Scalar = RT_Object
+ RT_Obj_Obj = RT_Object << 2 | RT_Object,
+ RT_Obj_ByRef = RT_ByRef << 2 | RT_Object,
+
+ // RT_ByRef_Scalar = RT_Byref
+ RT_ByRef_Obj = RT_Object << 2 | RT_ByRef,
+ RT_ByRef_ByRef = RT_ByRef << 2 | RT_ByRef,
+
+ // Illegal or uninitialized value,
+ // Not a valid encoding, never written to image.
+ RT_Illegal = 0xFF
+};
+
+// Identify ReturnKinds containing useful information
+inline bool IsValidReturnKind(ReturnKind returnKind)
+{
+ return (returnKind != RT_Illegal)
+#ifndef _TARGET_X86_
+ && (returnKind != RT_Unset)
+#endif // _TARGET_X86_
+ ;
+}
+
+// Identify ReturnKinds that can be a part of a multi-reg struct return
+inline bool IsValidFieldReturnKind(ReturnKind returnKind)
+{
+ return (returnKind == RT_Scalar || returnKind == RT_Object || returnKind == RT_ByRef);
+}
+
+inline bool IsValidReturnRegister(size_t regNo)
+{
+ return (regNo == 0)
+#ifdef FEATURE_MULTIREG_RETURN
+ || (regNo == 1)
+#endif // FEATURE_MULTIREG_RETURN
+ ;
+}
+
+inline bool IsStructReturnKind(ReturnKind returnKind)
+{
+ // Two bits encode integer/ref/float return-kinds.
+ // Encodings needing more than two bits are (non-scalar) struct-returns.
+ return returnKind > 3;
+}
+
+// Helpers for combining/extracting individual ReturnKinds from/to Struct ReturnKinds.
+// Encoding is two bits per register
+
+inline ReturnKind GetStructReturnKind(ReturnKind reg0, ReturnKind reg1)
+{
+ _ASSERTE(IsValidFieldReturnKind(reg0) && IsValidFieldReturnKind(reg1));
+
+ ReturnKind structReturnKind = (ReturnKind)(reg1 << 2 | reg0);
+
+ _ASSERTE(IsValidReturnKind(structReturnKind));
+
+ return structReturnKind;
+}
+
+// Extract returnKind for the specified return register.
+// Also determines if higher ordinal return registers contain object references
+inline ReturnKind ExtractRegReturnKind(ReturnKind returnKind, size_t returnRegOrdinal, bool& moreRegs)
+{
+ _ASSERTE(IsValidReturnKind(returnKind));
+ _ASSERTE(IsValidReturnRegister(returnRegOrdinal));
+
+ // Return kind of each return register is encoded in two bits at returnRegOrdinal*2 position from LSB
+ ReturnKind regReturnKind = (ReturnKind)((returnKind >> (returnRegOrdinal * 2)) & 3);
+
+ // Check if any other higher ordinal return registers have object references.
+ // ReturnKind of higher ordinal return registers are encoded at (returnRegOrdinal+1)*2) position from LSB
+ // If all of the remaining bits are 0 then there isn't any more RT_Object or RT_ByRef encoded in returnKind.
+ moreRegs = (returnKind >> ((returnRegOrdinal+1) * 2)) != 0;
+
+ _ASSERTE(IsValidReturnKind(regReturnKind));
+ _ASSERTE((returnRegOrdinal == 0) || IsValidFieldReturnKind(regReturnKind));
+
+ return regReturnKind;
+}
+
+inline const char *ReturnKindToString(ReturnKind returnKind)
+{
+ switch (returnKind) {
+ case RT_Scalar: return "Scalar";
+ case RT_Object: return "Object";
+ case RT_ByRef: return "ByRef";
+#ifdef _TARGET_X86_
+ case RT_Float: return "Float";
+#else
+ case RT_Unset: return "UNSET";
+#endif // _TARGET_X86_
+ case RT_Scalar_Obj: return "{Scalar, Object}";
+ case RT_Scalar_ByRef: return "{Scalar, ByRef}";
+ case RT_Obj_Obj: return "{Object, Object}";
+ case RT_Obj_ByRef: return "{Object, ByRef}";
+ case RT_ByRef_Obj: return "{ByRef, Object}";
+ case RT_ByRef_ByRef: return "{ByRef, ByRef}";
+
+ case RT_Illegal: return "<Illegal>";
+ default: return "!Impossible!";
+ }
+}
+
+#ifdef _TARGET_X86_
+
+#include <stdlib.h> // For memcmp()
+#include "bitvector.h" // for ptrArgTP
+
+#ifndef FASTCALL
+#define FASTCALL __fastcall
+#endif
+
+// we use offsetof to get the offset of a field
+#include <stddef.h> // offsetof
+#ifndef offsetof
+#define offsetof(s,m) ((size_t)&(((s *)0)->m))
+#endif
+
+enum infoHdrAdjustConstants {
+ // Constants
+ SET_FRAMESIZE_MAX = 7,
+ SET_ARGCOUNT_MAX = 8, // Change to 6
+ SET_PROLOGSIZE_MAX = 16,
+ SET_EPILOGSIZE_MAX = 10, // Change to 6
+ SET_EPILOGCNT_MAX = 4,
+ SET_UNTRACKED_MAX = 3
+};
+
+//
+// Enum to define the 128 codes that are used to incrementally adjust the InfoHdr structure
+//
+enum infoHdrAdjust {
+
+ SET_FRAMESIZE = 0, // 0x00
+ SET_ARGCOUNT = SET_FRAMESIZE + SET_FRAMESIZE_MAX + 1, // 0x08
+ SET_PROLOGSIZE = SET_ARGCOUNT + SET_ARGCOUNT_MAX + 1, // 0x11
+ SET_EPILOGSIZE = SET_PROLOGSIZE + SET_PROLOGSIZE_MAX + 1, // 0x22
+ SET_EPILOGCNT = SET_EPILOGSIZE + SET_EPILOGSIZE_MAX + 1, // 0x2d
+ SET_UNTRACKED = SET_EPILOGCNT + (SET_EPILOGCNT_MAX + 1) * 2, // 0x37
+
+ FIRST_FLIP = SET_UNTRACKED + SET_UNTRACKED_MAX + 1,
+
+ FLIP_EDI_SAVED = FIRST_FLIP, // 0x3b
+ FLIP_ESI_SAVED, // 0x3c
+ FLIP_EBX_SAVED, // 0x3d
+ FLIP_EBP_SAVED, // 0x3e
+ FLIP_EBP_FRAME, // 0x3f
+ FLIP_INTERRUPTIBLE, // 0x40
+ FLIP_DOUBLE_ALIGN, // 0x41
+ FLIP_SECURITY, // 0x42
+ FLIP_HANDLERS, // 0x43
+ FLIP_LOCALLOC, // 0x44
+ FLIP_EDITnCONTINUE, // 0x45
+ FLIP_VAR_PTR_TABLE_SZ, // 0x46 Flip whether a table-size exits after the header encoding
+ FFFF_UNTRACKED_CNT, // 0x47 There is a count (>SET_UNTRACKED_MAX) after the header encoding
+ FLIP_VARARGS, // 0x48
+ FLIP_PROF_CALLBACKS, // 0x49
+ FLIP_HAS_GS_COOKIE, // 0x4A - The offset of the GuardStack cookie follows after the header encoding
+ FLIP_SYNC, // 0x4B
+ FLIP_HAS_GENERICS_CONTEXT,// 0x4C
+ FLIP_GENERICS_CONTEXT_IS_METHODDESC,// 0x4D
+
+ // 0x4E .. 0x4f unused
+
+ NEXT_FOUR_START = 0x50,
+ NEXT_FOUR_FRAMESIZE = 0x50,
+ NEXT_FOUR_ARGCOUNT = 0x60,
+ NEXT_THREE_PROLOGSIZE = 0x70,
+ NEXT_THREE_EPILOGSIZE = 0x78
+};
+
+#define HAS_UNTRACKED ((unsigned int) -1)
+#define HAS_VARPTR ((unsigned int) -1)
+// 0 is not a valid offset for EBP-frames as all locals are at a negative offset
+// For ESP frames, the cookie is above (at a higher address than) the buffers,
+// and so cannot be at offset 0.
+#define INVALID_GS_COOKIE_OFFSET 0
+// Temporary value to indicate that the offset needs to be read after the header
+#define HAS_GS_COOKIE_OFFSET ((unsigned int) -1)
+
+// 0 is not a valid sync offset
+#define INVALID_SYNC_OFFSET 0
+// Temporary value to indicate that the offset needs to be read after the header
+#define HAS_SYNC_OFFSET ((unsigned int) -1)
+
+#define INVALID_ARGTAB_OFFSET 0
+
+#include <pshpack1.h>
+
+// Working set optimization: saving 12 * 128 = 1536 bytes in infoHdrShortcut
+struct InfoHdr;
+
+struct InfoHdrSmall {
+ unsigned char prologSize; // 0
+ unsigned char epilogSize; // 1
+ unsigned char epilogCount : 3; // 2 [0:2]
+ unsigned char epilogAtEnd : 1; // 2 [3]
+ unsigned char ediSaved : 1; // 2 [4] which callee-saved regs are pushed onto stack
+ unsigned char esiSaved : 1; // 2 [5]
+ unsigned char ebxSaved : 1; // 2 [6]
+ unsigned char ebpSaved : 1; // 2 [7]
+ unsigned char ebpFrame : 1; // 3 [0] locals accessed relative to ebp
+ unsigned char interruptible : 1; // 3 [1] is intr. at all points (except prolog/epilog), not just call-sites
+ unsigned char doubleAlign : 1; // 3 [2] uses double-aligned stack (ebpFrame will be false)
+ unsigned char security : 1; // 3 [3] has slot for security object
+ unsigned char handlers : 1; // 3 [4] has callable handlers
+ unsigned char localloc : 1; // 3 [5] uses localloc
+ unsigned char editNcontinue : 1; // 3 [6] was JITed in EnC mode
+ unsigned char varargs : 1; // 3 [7] function uses varargs calling convention
+ unsigned char profCallbacks : 1; // 4 [0]
+ unsigned char genericsContext : 1;//4 [1] function reports a generics context parameter is present
+ unsigned char genericsContextIsMethodDesc : 1;//4[2]
+ unsigned short argCount; // 5,6 in bytes
+ unsigned int frameSize; // 7,8,9,10 in bytes
+ unsigned int untrackedCnt; // 11,12,13,14
+ unsigned int varPtrTableSize; // 15.16,17,18
+
+ // Checks whether "this" is compatible with "target".
+ // It is not an exact bit match as "this" could have some
+ // marker/place-holder values, which will have to be written out
+ // after the header.
+
+ bool isHeaderMatch(const InfoHdr& target) const;
+};
+
+
+struct InfoHdr : public InfoHdrSmall {
+ // 0 (zero) means that there is no GuardStack cookie
+ // The cookie is either at ESP+gsCookieOffset or EBP-gsCookieOffset
+ unsigned int gsCookieOffset; // 19,20,21,22
+ unsigned int syncStartOffset; // 23,24,25,26
+ unsigned int syncEndOffset; // 27,28,29,30
+
+ // 31 bytes total
+
+ // Checks whether "this" is compatible with "target".
+ // It is not an exact bit match as "this" could have some
+ // marker/place-holder values, which will have to be written out
+ // after the header.
+
+ bool isHeaderMatch(const InfoHdr& target) const
+ {
+#ifdef _ASSERTE
+ // target cannot have place-holder values.
+ _ASSERTE(target.untrackedCnt != HAS_UNTRACKED &&
+ target.varPtrTableSize != HAS_VARPTR &&
+ target.gsCookieOffset != HAS_GS_COOKIE_OFFSET &&
+ target.syncStartOffset != HAS_SYNC_OFFSET);
+#endif
+
+ // compare two InfoHdr's up to but not including the untrackCnt field
+ if (memcmp(this, &target, offsetof(InfoHdr, untrackedCnt)) != 0)
+ return false;
+
+ if (untrackedCnt != target.untrackedCnt) {
+ if (target.untrackedCnt <= SET_UNTRACKED_MAX)
+ return false;
+ else if (untrackedCnt != HAS_UNTRACKED)
+ return false;
+ }
+
+ if (varPtrTableSize != target.varPtrTableSize) {
+ if ((varPtrTableSize != 0) != (target.varPtrTableSize != 0))
+ return false;
+ }
+
+ if ((gsCookieOffset == INVALID_GS_COOKIE_OFFSET) !=
+ (target.gsCookieOffset == INVALID_GS_COOKIE_OFFSET))
+ return false;
+
+ if ((syncStartOffset == INVALID_SYNC_OFFSET) !=
+ (target.syncStartOffset == INVALID_SYNC_OFFSET))
+ return false;
+
+ return true;
+ }
+};
+
+
+union CallPattern {
+ struct {
+ unsigned char argCnt;
+ unsigned char regMask; // EBP=0x8, EBX=0x4, ESI=0x2, EDI=0x1
+ unsigned char argMask;
+ unsigned char codeDelta;
+ } fld;
+ unsigned val;
+};
+
+#include <poppack.h>
+
+#define IH_MAX_PROLOG_SIZE (51)
+
+extern const InfoHdrSmall infoHdrShortcut[];
+extern int infoHdrLookup[];
+
+inline void GetInfoHdr(int index, InfoHdr * header)
+{
+ *((InfoHdrSmall *)header) = infoHdrShortcut[index];
+
+ header->gsCookieOffset = 0;
+ header->syncStartOffset = 0;
+ header->syncEndOffset = 0;
+}
+
+PTR_CBYTE FASTCALL decodeHeader(PTR_CBYTE table, InfoHdr* header);
+
+BYTE FASTCALL encodeHeaderFirst(const InfoHdr& header, InfoHdr* state, int* more, int *pCached);
+BYTE FASTCALL encodeHeaderNext(const InfoHdr& header, InfoHdr* state);
+
+size_t FASTCALL decodeUnsigned(PTR_CBYTE src, unsigned* value);
+size_t FASTCALL decodeUDelta(PTR_CBYTE src, unsigned* value, unsigned lastValue);
+size_t FASTCALL decodeSigned(PTR_CBYTE src, int * value);
+
+#define CP_MAX_CODE_DELTA (0x23)
+#define CP_MAX_ARG_CNT (0x02)
+#define CP_MAX_ARG_MASK (0x00)
+
+extern const unsigned callPatternTable[];
+extern const unsigned callCommonDelta[];
+
+
+int FASTCALL lookupCallPattern(unsigned argCnt,
+ unsigned regMask,
+ unsigned argMask,
+ unsigned codeDelta);
+
+void FASTCALL decodeCallPattern(int pattern,
+ unsigned * argCnt,
+ unsigned * regMask,
+ unsigned * argMask,
+ unsigned * codeDelta);
+
+#endif // _TARGET_86_
+
+// Stack offsets must be 8-byte aligned, so we use this unaligned
+// offset to represent that the method doesn't have a security object
+#define NO_SECURITY_OBJECT (-1)
+#define NO_GS_COOKIE (-1)
+#define NO_STACK_BASE_REGISTER (0xffffffff)
+#define NO_SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA (0xffffffff)
+#define NO_GENERICS_INST_CONTEXT (-1)
+#define NO_REVERSE_PINVOKE_FRAME (-1)
+#define NO_PSP_SYM (-1)
+
+#if defined(_TARGET_AMD64_)
+
+#ifndef TARGET_POINTER_SIZE
+#define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
+#endif
+#define NUM_NORM_CODE_OFFSETS_PER_CHUNK (64)
+#define NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 (6)
+#define NORMALIZE_STACK_SLOT(x) ((x)>>3)
+#define DENORMALIZE_STACK_SLOT(x) ((x)<<3)
+#define NORMALIZE_CODE_LENGTH(x) (x)
+#define DENORMALIZE_CODE_LENGTH(x) (x)
+// Encode RBP as 0
+#define NORMALIZE_STACK_BASE_REGISTER(x) ((x) ^ 5)
+#define DENORMALIZE_STACK_BASE_REGISTER(x) ((x) ^ 5)
+#define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>3)
+#define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<3)
+#define CODE_OFFSETS_NEED_NORMALIZATION 0
+#define NORMALIZE_CODE_OFFSET(x) (x)
+#define DENORMALIZE_CODE_OFFSET(x) (x)
+#define NORMALIZE_REGISTER(x) (x)
+#define DENORMALIZE_REGISTER(x) (x)
+#define NORMALIZE_NUM_SAFE_POINTS(x) (x)
+#define DENORMALIZE_NUM_SAFE_POINTS(x) (x)
+#define NORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
+#define DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
+
+#define PSP_SYM_STACK_SLOT_ENCBASE 6
+#define GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE 6
+#define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6
+#define GS_COOKIE_STACK_SLOT_ENCBASE 6
+#define CODE_LENGTH_ENCBASE 8
+#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2
+#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 4
+#define STACK_BASE_REGISTER_ENCBASE 3
+#define SIZE_OF_STACK_AREA_ENCBASE 3
+#define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 4
+#define REVERSE_PINVOKE_FRAME_ENCBASE 6
+#define NUM_REGISTERS_ENCBASE 2
+#define NUM_STACK_SLOTS_ENCBASE 2
+#define NUM_UNTRACKED_SLOTS_ENCBASE 1
+#define NORM_PROLOG_SIZE_ENCBASE 5
+#define NORM_EPILOG_SIZE_ENCBASE 3
+#define NORM_CODE_OFFSET_DELTA_ENCBASE 3
+#define INTERRUPTIBLE_RANGE_DELTA1_ENCBASE 6
+#define INTERRUPTIBLE_RANGE_DELTA2_ENCBASE 6
+#define REGISTER_ENCBASE 3
+#define REGISTER_DELTA_ENCBASE 2
+#define STACK_SLOT_ENCBASE 6
+#define STACK_SLOT_DELTA_ENCBASE 4
+#define NUM_SAFE_POINTS_ENCBASE 2
+#define NUM_INTERRUPTIBLE_RANGES_ENCBASE 1
+#define NUM_EH_CLAUSES_ENCBASE 2
+#define POINTER_SIZE_ENCBASE 3
+#define LIVESTATE_RLE_RUN_ENCBASE 2
+#define LIVESTATE_RLE_SKIP_ENCBASE 4
+
+#elif defined(_TARGET_ARM_)
+
+#ifndef TARGET_POINTER_SIZE
+#define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this target
+#endif
+#define NUM_NORM_CODE_OFFSETS_PER_CHUNK (64)
+#define NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 (6)
+#define NORMALIZE_STACK_SLOT(x) ((x)>>2)
+#define DENORMALIZE_STACK_SLOT(x) ((x)<<2)
+#define NORMALIZE_CODE_LENGTH(x) ((x)>>1)
+#define DENORMALIZE_CODE_LENGTH(x) ((x)<<1)
+// Encode R11 as zero
+#define NORMALIZE_STACK_BASE_REGISTER(x) ((((x) - 4) & 7) ^ 7)
+#define DENORMALIZE_STACK_BASE_REGISTER(x) (((x) ^ 7) + 4)
+#define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>2)
+#define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<2)
+#define CODE_OFFSETS_NEED_NORMALIZATION 1
+#define NORMALIZE_CODE_OFFSET(x) (x) // Instructions are 2/4 bytes long in Thumb/ARM states,
+#define DENORMALIZE_CODE_OFFSET(x) (x) // but the safe-point offsets are encoded with a -1 adjustment.
+#define NORMALIZE_REGISTER(x) (x)
+#define DENORMALIZE_REGISTER(x) (x)
+#define NORMALIZE_NUM_SAFE_POINTS(x) (x)
+#define DENORMALIZE_NUM_SAFE_POINTS(x) (x)
+#define NORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
+#define DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
+
+// The choices of these encoding bases only affects space overhead
+// and performance, not semantics/correctness.
+#define PSP_SYM_STACK_SLOT_ENCBASE 5
+#define GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE 5
+#define SECURITY_OBJECT_STACK_SLOT_ENCBASE 5
+#define GS_COOKIE_STACK_SLOT_ENCBASE 5
+#define CODE_LENGTH_ENCBASE 7
+#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2
+#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 2
+#define STACK_BASE_REGISTER_ENCBASE 1
+#define SIZE_OF_STACK_AREA_ENCBASE 3
+#define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 3
+#define REVERSE_PINVOKE_FRAME_ENCBASE 5
+#define NUM_REGISTERS_ENCBASE 2
+#define NUM_STACK_SLOTS_ENCBASE 3
+#define NUM_UNTRACKED_SLOTS_ENCBASE 3
+#define NORM_PROLOG_SIZE_ENCBASE 5
+#define NORM_EPILOG_SIZE_ENCBASE 3
+#define NORM_CODE_OFFSET_DELTA_ENCBASE 3
+#define INTERRUPTIBLE_RANGE_DELTA1_ENCBASE 4
+#define INTERRUPTIBLE_RANGE_DELTA2_ENCBASE 6
+#define REGISTER_ENCBASE 2
+#define REGISTER_DELTA_ENCBASE 1
+#define STACK_SLOT_ENCBASE 6
+#define STACK_SLOT_DELTA_ENCBASE 4
+#define NUM_SAFE_POINTS_ENCBASE 3
+#define NUM_INTERRUPTIBLE_RANGES_ENCBASE 2
+#define NUM_EH_CLAUSES_ENCBASE 3
+#define POINTER_SIZE_ENCBASE 3
+#define LIVESTATE_RLE_RUN_ENCBASE 2
+#define LIVESTATE_RLE_SKIP_ENCBASE 4
+
+#elif defined(_TARGET_ARM64_)
+
+#ifndef TARGET_POINTER_SIZE
+#define TARGET_POINTER_SIZE 8 // equal to sizeof(void*) and the managed pointer size in bytes for this target
+#endif
+#define NUM_NORM_CODE_OFFSETS_PER_CHUNK (64)
+#define NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 (6)
+#define NORMALIZE_STACK_SLOT(x) ((x)>>3) // GC Pointers are 8-bytes aligned
+#define DENORMALIZE_STACK_SLOT(x) ((x)<<3)
+#define NORMALIZE_CODE_LENGTH(x) ((x)>>2) // All Instructions are 4 bytes long
+#define DENORMALIZE_CODE_LENGTH(x) ((x)<<2)
+#define NORMALIZE_STACK_BASE_REGISTER(x) ((x)^29) // Encode Frame pointer X29 as zero
+#define DENORMALIZE_STACK_BASE_REGISTER(x) ((x)^29)
+#define NORMALIZE_SIZE_OF_STACK_AREA(x) ((x)>>3)
+#define DENORMALIZE_SIZE_OF_STACK_AREA(x) ((x)<<3)
+#define CODE_OFFSETS_NEED_NORMALIZATION 0
+#define NORMALIZE_CODE_OFFSET(x) (x) // Instructions are 4 bytes long, but the safe-point
+#define DENORMALIZE_CODE_OFFSET(x) (x) // offsets are encoded with a -1 adjustment.
+#define NORMALIZE_REGISTER(x) (x)
+#define DENORMALIZE_REGISTER(x) (x)
+#define NORMALIZE_NUM_SAFE_POINTS(x) (x)
+#define DENORMALIZE_NUM_SAFE_POINTS(x) (x)
+#define NORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
+#define DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
+
+#define PSP_SYM_STACK_SLOT_ENCBASE 6
+#define GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE 6
+#define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6
+#define GS_COOKIE_STACK_SLOT_ENCBASE 6
+#define CODE_LENGTH_ENCBASE 8
+#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2
+#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 4
+#define STACK_BASE_REGISTER_ENCBASE 2 // FP encoded as 0, SP as 2.
+#define SIZE_OF_STACK_AREA_ENCBASE 3
+#define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 4
+#define REVERSE_PINVOKE_FRAME_ENCBASE 6
+#define NUM_REGISTERS_ENCBASE 3
+#define NUM_STACK_SLOTS_ENCBASE 2
+#define NUM_UNTRACKED_SLOTS_ENCBASE 1
+#define NORM_PROLOG_SIZE_ENCBASE 5
+#define NORM_EPILOG_SIZE_ENCBASE 3
+#define NORM_CODE_OFFSET_DELTA_ENCBASE 3
+#define INTERRUPTIBLE_RANGE_DELTA1_ENCBASE 6
+#define INTERRUPTIBLE_RANGE_DELTA2_ENCBASE 6
+#define REGISTER_ENCBASE 3
+#define REGISTER_DELTA_ENCBASE 2
+#define STACK_SLOT_ENCBASE 6
+#define STACK_SLOT_DELTA_ENCBASE 4
+#define NUM_SAFE_POINTS_ENCBASE 3
+#define NUM_INTERRUPTIBLE_RANGES_ENCBASE 1
+#define NUM_EH_CLAUSES_ENCBASE 2
+#define POINTER_SIZE_ENCBASE 3
+#define LIVESTATE_RLE_RUN_ENCBASE 2
+#define LIVESTATE_RLE_SKIP_ENCBASE 4
+
+#else
+
+#ifndef _TARGET_X86_
+#ifdef PORTABILITY_WARNING
+PORTABILITY_WARNING("Please specialize these definitions for your platform!")
+#endif
+#endif
+
+#ifndef TARGET_POINTER_SIZE
+#define TARGET_POINTER_SIZE 4 // equal to sizeof(void*) and the managed pointer size in bytes for this target
+#endif
+#define NUM_NORM_CODE_OFFSETS_PER_CHUNK (64)
+#define NUM_NORM_CODE_OFFSETS_PER_CHUNK_LOG2 (6)
+#define NORMALIZE_STACK_SLOT(x) (x)
+#define DENORMALIZE_STACK_SLOT(x) (x)
+#define NORMALIZE_CODE_LENGTH(x) (x)
+#define DENORMALIZE_CODE_LENGTH(x) (x)
+#define NORMALIZE_STACK_BASE_REGISTER(x) (x)
+#define DENORMALIZE_STACK_BASE_REGISTER(x) (x)
+#define NORMALIZE_SIZE_OF_STACK_AREA(x) (x)
+#define DENORMALIZE_SIZE_OF_STACK_AREA(x) (x)
+#define CODE_OFFSETS_NEED_NORMALIZATION 0
+#define NORMALIZE_CODE_OFFSET(x) (x)
+#define DENORMALIZE_CODE_OFFSET(x) (x)
+#define NORMALIZE_REGISTER(x) (x)
+#define DENORMALIZE_REGISTER(x) (x)
+#define NORMALIZE_NUM_SAFE_POINTS(x) (x)
+#define DENORMALIZE_NUM_SAFE_POINTS(x) (x)
+#define NORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
+#define DENORMALIZE_NUM_INTERRUPTIBLE_RANGES(x) (x)
+
+#define PSP_SYM_STACK_SLOT_ENCBASE 6
+#define GENERICS_INST_CONTEXT_STACK_SLOT_ENCBASE 6
+#define SECURITY_OBJECT_STACK_SLOT_ENCBASE 6
+#define GS_COOKIE_STACK_SLOT_ENCBASE 6
+#define CODE_LENGTH_ENCBASE 6
+#define SIZE_OF_RETURN_KIND_IN_SLIM_HEADER 2
+#define SIZE_OF_RETURN_KIND_IN_FAT_HEADER 2
+#define STACK_BASE_REGISTER_ENCBASE 3
+#define SIZE_OF_STACK_AREA_ENCBASE 6
+#define SIZE_OF_EDIT_AND_CONTINUE_PRESERVED_AREA_ENCBASE 3
+#define REVERSE_PINVOKE_FRAME_ENCBASE 6
+#define NUM_REGISTERS_ENCBASE 3
+#define NUM_STACK_SLOTS_ENCBASE 5
+#define NUM_UNTRACKED_SLOTS_ENCBASE 5
+#define NORM_PROLOG_SIZE_ENCBASE 4
+#define NORM_EPILOG_SIZE_ENCBASE 3
+#define NORM_CODE_OFFSET_DELTA_ENCBASE 3
+#define INTERRUPTIBLE_RANGE_DELTA1_ENCBASE 5
+#define INTERRUPTIBLE_RANGE_DELTA2_ENCBASE 5
+#define REGISTER_ENCBASE 3
+#define REGISTER_DELTA_ENCBASE REGISTER_ENCBASE
+#define STACK_SLOT_ENCBASE 6
+#define STACK_SLOT_DELTA_ENCBASE 4
+#define NUM_SAFE_POINTS_ENCBASE 4
+#define NUM_INTERRUPTIBLE_RANGES_ENCBASE 1
+#define NUM_EH_CLAUSES_ENCBASE 2
+#define POINTER_SIZE_ENCBASE 3
+#define LIVESTATE_RLE_RUN_ENCBASE 2
+#define LIVESTATE_RLE_SKIP_ENCBASE 4
+
+#endif
+
+#endif // !__GCINFOTYPES_H__
+