summaryrefslogtreecommitdiff
path: root/src/inc/gcinfotypes.h
diff options
context:
space:
mode:
authorSwaroop Sridhar <swaroops@microsoft.com>2016-07-15 00:41:30 -0700
committerSwaroop Sridhar <swaroops@microsoft.com>2016-07-20 19:51:50 -0700
commitf915aebaf5db0b829f062dc9940e23bb5c38d575 (patch)
treef1eafbb504ba2a0fa0253ffcce362ed81a0add80 /src/inc/gcinfotypes.h
parent34e1626bc3a49b50900ca192bed1f97524d81e6a (diff)
downloadcoreclr-f915aebaf5db0b829f062dc9940e23bb5c38d575.tar.gz
coreclr-f915aebaf5db0b829f062dc9940e23bb5c38d575.tar.bz2
coreclr-f915aebaf5db0b829f062dc9940e23bb5c38d575.zip
GCInfo: Support versioning.
This change enables the VM to support multiple versions GCInfo concurrently. This is necessary in light of upcoming work to add ReturnType and other modifications to the GCInfo format -- so that existing ReadyToRun images will continue to run correctly. The version# is not stored in the GcInfo structure -- because it is wasteful to store the version once for every method. Instead, it is tracked per range-section of generated/loaded methods. The GCInfo version is computed as: 1) The current GCINFO_VERSION for JITted and Ngened images 2) A function of the Ready-to-run major version stored in READYTORUN_HEADER for ready-to-run images. ReadyToRunJitManager::JitTokenToGCInfoVersion() provides the GcInfo version for any Method. Currently, there's only one version of GCInfo. An abstraction GCInfoToken is added to the GcInfo interface, which tracks the {GcInfo, Version} pair in-memory. Several GcInfo APIs are modified to use GCInfoToken in place of GcInfo pointers. Notes: 1) SOS GcDump: The GCDump API has separate dump routines for Header and the pointer-liveness information (DumpGCTable and DumpGCHeader) each of which advance a pointer to the GCInfo block. These APIs are not changed to recieve a GCInfoToken in place of the GcInfo block pointer. Instead, they recieve the GcInfo version at the time of construction. 2) Some routines that are specific to x86 gcInfo (ex: crackMethodInfoHdr) are not yet updated to use versioning, since the development plan is to update the Non-x86 GcInfo structure first. 3) The x86 specific structs defining GcInfo headers are moved to GcInfoTypes.h, along with the non-x86 GcInfo type definitions.
Diffstat (limited to 'src/inc/gcinfotypes.h')
-rw-r--r--src/inc/gcinfotypes.h270
1 files changed, 251 insertions, 19 deletions
diff --git a/src/inc/gcinfotypes.h b/src/inc/gcinfotypes.h
index a54cec30e5..fc624b2c0a 100644
--- a/src/inc/gcinfotypes.h
+++ b/src/inc/gcinfotypes.h
@@ -6,6 +6,8 @@
#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
@@ -62,19 +64,19 @@
__forceinline size_t SAFE_SHIFT_LEFT(size_t x, size_t count)
{
_ASSERTE(count <= BITS_PER_SIZE_T);
- return (x << 1) << (count-1);
+ 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);
+ return (x >> 1) >> (count - 1);
}
inline UINT32 CeilOfLog2(size_t x)
{
_ASSERTE(x > 0);
- UINT32 result = (x & (x-1)) ? 1 : 0;
- while(x != 1)
+ UINT32 result = (x & (x - 1)) ? 1 : 0;
+ while (x != 1)
{
result++;
x >>= 1;
@@ -84,24 +86,24 @@ inline UINT32 CeilOfLog2(size_t x)
enum GcSlotFlags
{
- GC_SLOT_BASE = 0x0,
- GC_SLOT_INTERIOR = 0x1,
- GC_SLOT_PINNED = 0x2,
- GC_SLOT_UNTRACKED = 0x4,
+ 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,
+ 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_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,
+ GC_SPBASE_FIRST = GC_CALLER_SP_REL,
+ GC_SPBASE_LAST = GC_FRAMEREG_REL,
};
#ifdef _DEBUG
@@ -113,11 +115,10 @@ const char* const GcStackSlotBaseNames[] =
};
#endif
-
enum GcSlotState
{
- GC_SLOT_DEAD = 0x0,
- GC_SLOT_LIVE = 0x1,
+ GC_SLOT_DEAD = 0x0,
+ GC_SLOT_LIVE = 0x1,
};
struct GcStackSlot
@@ -135,6 +136,238 @@ struct GcStackSlot
}
};
+#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)
@@ -144,7 +377,6 @@ struct GcStackSlot
#define NO_GENERICS_INST_CONTEXT (-1)
#define NO_PSP_SYM (-1)
-
#if defined(_TARGET_AMD64_)
#ifndef TARGET_POINTER_SIZE