summaryrefslogtreecommitdiff
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
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.
-rw-r--r--src/ToolBox/SOS/Strike/disasm.cpp12
-rw-r--r--src/ToolBox/SOS/Strike/disasm.h8
-rw-r--r--src/ToolBox/SOS/Strike/disasmARM.cpp6
-rw-r--r--src/ToolBox/SOS/Strike/disasmARM64.cpp6
-rw-r--r--src/ToolBox/SOS/Strike/exts.h5
-rw-r--r--src/ToolBox/SOS/Strike/strike.cpp8
-rw-r--r--src/debug/daccess/daccess.cpp2
-rw-r--r--src/debug/daccess/enummem.cpp5
-rw-r--r--src/debug/daccess/nidump.cpp13
-rw-r--r--src/debug/daccess/request.cpp2
-rw-r--r--src/gcdump/gcdump.cpp11
-rw-r--r--src/gcdump/gcdumpnonx86.cpp12
-rw-r--r--src/gcinfo/gcinfodumper.cpp14
-rw-r--r--src/inc/eetwain.h10
-rw-r--r--src/inc/gcdecoder.cpp2
-rw-r--r--src/inc/gcdump.h15
-rw-r--r--src/inc/gcinfo.h249
-rw-r--r--src/inc/gcinfodecoder.h6
-rw-r--r--src/inc/gcinfodumper.h4
-rw-r--r--src/inc/gcinfotypes.h270
-rw-r--r--src/jit/gcencode.cpp8
-rw-r--r--src/jit/jitgcinfo.h4
-rw-r--r--src/vm/codeman.cpp50
-rw-r--r--src/vm/codeman.h34
-rw-r--r--src/vm/debughelp.cpp10
-rw-r--r--src/vm/eedbginterfaceimpl.cpp6
-rw-r--r--src/vm/eetwain.cpp63
-rw-r--r--src/vm/gccover.cpp20
-rw-r--r--src/vm/gccover.h2
-rw-r--r--src/vm/gcenv.ee.cpp10
-rw-r--r--src/vm/gcinfodecoder.cpp16
-rw-r--r--src/vm/stackwalk.h7
32 files changed, 481 insertions, 409 deletions
diff --git a/src/ToolBox/SOS/Strike/disasm.cpp b/src/ToolBox/SOS/Strike/disasm.cpp
index 097f4cd14c..e141f8038f 100644
--- a/src/ToolBox/SOS/Strike/disasm.cpp
+++ b/src/ToolBox/SOS/Strike/disasm.cpp
@@ -9,6 +9,7 @@
// ==--==
#include "strike.h"
+#include "gcinfo.h"
#include "util.h"
#include <dbghelp.h>
#include <limits.h>
@@ -1058,10 +1059,11 @@ void PrintNothing (const char *fmt, ...)
///
/// Dump X86 GCInfo header and table
///
-void X86Machine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
+void X86Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
{
X86GCDump::InfoHdr header;
- X86GCDump::GCDump gcDump(encBytes, 5, true);
+ X86GCDump::GCDump gcDump(gcInfoToken.Version, encBytes, 5, true);
+ BYTE* pTable = dac_cast<PTR_BYTE>(gcInfoToken.Info);
if (bPrintHeader)
{
gcDump.gcPrintf = gcPrintf;
@@ -1107,17 +1109,17 @@ LPCSTR AMD64Machine::s_SPName = "RSP";
///
/// Dump AMD64 GCInfo table
///
-void AMD64Machine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
+void AMD64Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
{
if (bPrintHeader)
{
ExtOut("Pointer table:\n");
}
- GCDump gcDump(encBytes, 5, true);
+ GCDump gcDump(gcInfoToken.Version, encBytes, 5, true);
gcDump.gcPrintf = gcPrintf;
- gcDump.DumpGCTable(pTable, methodSize, 0);
+ gcDump.DumpGCTable(dac_cast<PTR_BYTE>(gcInfoToken.Info), methodSize, 0);
}
#endif // SOS_TARGET_AMD64
diff --git a/src/ToolBox/SOS/Strike/disasm.h b/src/ToolBox/SOS/Strike/disasm.h
index 6972c39ccb..59fc168a6e 100644
--- a/src/ToolBox/SOS/Strike/disasm.h
+++ b/src/ToolBox/SOS/Strike/disasm.h
@@ -159,7 +159,7 @@ public:
virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
{ _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
private:
X86Machine() {}
@@ -225,7 +225,7 @@ public:
virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
{ _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
private:
ARMMachine() {}
@@ -293,7 +293,7 @@ public:
virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
{ _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs); }
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
private:
AMD64Machine() {}
@@ -357,7 +357,7 @@ public:
virtual void GetGCRegisters(LPCSTR** regNames, unsigned int* cntRegs) const
{ _ASSERTE(cntRegs != NULL); *regNames = s_GCRegs; *cntRegs = _countof(s_GCRegs);}
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const;
private:
ARM64Machine() {}
diff --git a/src/ToolBox/SOS/Strike/disasmARM.cpp b/src/ToolBox/SOS/Strike/disasmARM.cpp
index 80dce71890..a82d4b9b65 100644
--- a/src/ToolBox/SOS/Strike/disasmARM.cpp
+++ b/src/ToolBox/SOS/Strike/disasmARM.cpp
@@ -607,7 +607,7 @@ BOOL ARMMachine::GetExceptionContext (TADDR stack, TADDR PC, TADDR *cxrAddr, CRO
///
/// Dump ARM GCInfo table
///
-void ARMMachine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
+void ARMMachine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
{
#ifndef FEATURE_PAL
if (bPrintHeader)
@@ -615,10 +615,10 @@ void ARMMachine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrint
ExtOut("Pointer table:\n");
}
- ARMGCDump::GCDump gcDump(encBytes, 5, true);
+ ARMGCDump::GCDump gcDump(gcInfoToken.Version, encBytes, 5, true);
gcDump.gcPrintf = gcPrintf;
- gcDump.DumpGCTable(pTable, methodSize, 0);
+ gcDump.DumpGCTable(dac_cast<PTR_BYTE>(gcInfoToken.Info), methodSize, 0);
#endif // !FEATURE_PAL
}
diff --git a/src/ToolBox/SOS/Strike/disasmARM64.cpp b/src/ToolBox/SOS/Strike/disasmARM64.cpp
index 2c581bc946..4ac8c59105 100644
--- a/src/ToolBox/SOS/Strike/disasmARM64.cpp
+++ b/src/ToolBox/SOS/Strike/disasmARM64.cpp
@@ -377,16 +377,16 @@ BOOL ARM64Machine::GetExceptionContext (TADDR stack, TADDR PC, TADDR *cxrAddr, C
///
/// Dump ARM GCInfo table
///
-void ARM64Machine::DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
+void ARM64Machine::DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const
{
if (bPrintHeader)
{
ExtOut("Pointer table:\n");
}
- ARM64GCDump::GCDump gcDump(encBytes, 5, true);
+ ARM64GCDump::GCDump gcDump(gcInfoToken.Version, encBytes, 5, true);
gcDump.gcPrintf = gcPrintf;
- gcDump.DumpGCTable(pTable, methodSize, 0);
+ gcDump.DumpGCTable(dac_cast<PTR_BYTE>(gcInfoToken.Info), methodSize, 0);
}
diff --git a/src/ToolBox/SOS/Strike/exts.h b/src/ToolBox/SOS/Strike/exts.h
index baef6d7084..36b5230c37 100644
--- a/src/ToolBox/SOS/Strike/exts.h
+++ b/src/ToolBox/SOS/Strike/exts.h
@@ -23,7 +23,6 @@
#pragma warning(disable:4430) // missing type specifier: C++ doesn't support default-int
#endif
#include "strike.h"
-
#include <wdbgexts.h>
#include <dbgeng.h>
#include <stdio.h>
@@ -43,6 +42,8 @@
// the DAC to read the DAC-ized data structures.
#include "daccess.h"
+#include "gcinfo.h"
+
// Convert between CLRDATA_ADDRESS and TADDR.
#define TO_TADDR(cdaddr) ((TADDR)(cdaddr))
#define TO_CDADDR(taddr) ((CLRDATA_ADDRESS)(LONG_PTR)(taddr))
@@ -386,7 +387,7 @@ public:
typedef void (*printfFtn)(const char* fmt, ...);
// Dumps the GCInfo
- virtual void DumpGCInfo(BYTE* pTable, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const = 0;
+ virtual void DumpGCInfo(GCInfoToken gcInfoToken, unsigned methodSize, printfFtn gcPrintf, bool encBytes, bool bPrintHeader) const = 0;
protected:
IMachine() {}
diff --git a/src/ToolBox/SOS/Strike/strike.cpp b/src/ToolBox/SOS/Strike/strike.cpp
index 3b0086fdb7..df4a18443f 100644
--- a/src/ToolBox/SOS/Strike/strike.cpp
+++ b/src/ToolBox/SOS/Strike/strike.cpp
@@ -8017,10 +8017,10 @@ DECLARE_API(GCInfo)
// Mutable table pointer since we need to pass the appropriate
// offset into the table to DumpGCTable.
- BYTE *pTable = table;
+ GCInfoToken gcInfoToken = { table, GCINFO_VERSION };
unsigned int methodSize = (unsigned int)codeHeaderData.MethodSize;
- g_targetMachine->DumpGCInfo(pTable, methodSize, ExtOut, true /*encBytes*/, true /*bPrintHeader*/);
+ g_targetMachine->DumpGCInfo(gcInfoToken, methodSize, ExtOut, true /*encBytes*/, true /*bPrintHeader*/);
return Status;
}
@@ -8101,8 +8101,8 @@ void DecodeGCTableEntry (const char *fmt, ...)
VOID CALLBACK DumpGCTableFiberEntry (LPVOID pvGCEncodingInfo)
{
GCEncodingInfo *pInfo = (GCEncodingInfo*)pvGCEncodingInfo;
-
- g_targetMachine->DumpGCInfo(pInfo->table, pInfo->methodSize, DecodeGCTableEntry, false /*encBytes*/, false /*bPrintHeader*/);
+ GCInfoToken gcInfoToken = { pInfo, GCINFO_VERSION };
+ g_targetMachine->DumpGCInfo(gcInfoToken, pInfo->methodSize, DecodeGCTableEntry, false /*encBytes*/, false /*bPrintHeader*/);
pInfo->fDoneDecoding = true;
SwitchToFiber(pInfo->pvMainFiber);
diff --git a/src/debug/daccess/daccess.cpp b/src/debug/daccess/daccess.cpp
index 4f500d9e6a..dfe7909c2b 100644
--- a/src/debug/daccess/daccess.cpp
+++ b/src/debug/daccess/daccess.cpp
@@ -6012,7 +6012,7 @@ ClrDataAccess::GetMethodExtents(MethodDesc* methodDesc,
EECodeInfo codeInfo(methodStart);
_ASSERTE(codeInfo.IsValid());
- TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfo());
+ TADDR codeSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
*extents = new (nothrow) METH_EXTENTS;
if (!*extents)
diff --git a/src/debug/daccess/enummem.cpp b/src/debug/daccess/enummem.cpp
index f88fb628ba..068c2f2b13 100644
--- a/src/debug/daccess/enummem.cpp
+++ b/src/debug/daccess/enummem.cpp
@@ -979,10 +979,11 @@ HRESULT ClrDataAccess::EnumMemWalkStackHelper(CLRDataEnumMemoryFlags flags,
codeInfo.GetJitManager()->IsFilterFunclet(&codeInfo);
// The stackwalker needs GC info to find the parent 'stack pointer' or PSP
- PTR_BYTE pGCInfo = dac_cast<PTR_BYTE>(codeInfo.GetGCInfo());
+ GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
+ PTR_BYTE pGCInfo = dac_cast<PTR_BYTE>(gcInfoToken.Info);
if (pGCInfo != NULL)
{
- GcInfoDecoder gcDecoder(pGCInfo, DECODE_PSP_SYM, 0);
+ GcInfoDecoder gcDecoder(gcInfoToken, DECODE_PSP_SYM, 0);
DacEnumMemoryRegion(dac_cast<TADDR>(pGCInfo), gcDecoder.GetNumBytesRead(), true);
}
}
diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp
index 6de9ec0b94..d151a54212 100644
--- a/src/debug/daccess/nidump.cpp
+++ b/src/debug/daccess/nidump.cpp
@@ -3093,7 +3093,8 @@ void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi
unsigned gcInfoSize = UINT_MAX;
//parse GCInfo for size information.
- PTR_CBYTE gcInfo = dac_cast<PTR_CBYTE>(mi.GetGCInfo());
+ GCInfoToken gcInfoToken = mi.GetGCInfoToken();
+ PTR_CBYTE gcInfo = dac_cast<PTR_CBYTE>(gcInfoToken.Info);
void (* stringOutFn)(const char *, ...);
IF_OPT(GC_INFO)
@@ -3108,10 +3109,10 @@ void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi
{
PTR_CBYTE curGCInfoPtr = gcInfo;
g_holdStringOutData.Clear();
- GCDump gcDump;
+ GCDump gcDump(gcInfoToken.Version);
gcDump.gcPrintf = stringOutFn;
#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
- GcInfoDecoder gcInfoDecoder(curGCInfoPtr, DECODE_CODE_LENGTH, 0);
+ GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_CODE_LENGTH, 0);
methodSize = gcInfoDecoder.GetCodeLength();
#endif
@@ -3119,7 +3120,7 @@ void NativeImageDumper::DumpCompleteMethod(PTR_Module module, MethodIterator& mi
#ifdef _TARGET_X86_
InfoHdr hdr;
stringOutFn( "method info Block:\n" );
- curGCInfoPtr += gcDump.DumpInfoHdr(curGCInfoPtr, &hdr, &methodSize, 0);
+ curGCInfoPtr += gcDump.DumpInfoHdr(PTR_CBYTE(gcInfoToken.Info), &hdr, &methodSize, 0);
stringOutFn( "\n" );
#endif
@@ -9436,10 +9437,10 @@ void NativeImageDumper::DumpReadyToRunMethod(PCODE pEntryPoint, PTR_RUNTIME_FUNC
{
PTR_CBYTE curGCInfoPtr = gcInfo;
g_holdStringOutData.Clear();
- GCDump gcDump;
+ GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = stringOutFn;
#if !defined(_TARGET_X86_) && defined(USE_GC_INFO_DECODER)
- GcInfoDecoder gcInfoDecoder(curGCInfoPtr, DECODE_CODE_LENGTH, 0);
+ GcInfoDecoder gcInfoDecoder({ curGCInfoPtr, GCINFO_VERSION }, DECODE_CODE_LENGTH, 0);
methodSize = gcInfoDecoder.GetCodeLength();
#endif
diff --git a/src/debug/daccess/request.cpp b/src/debug/daccess/request.cpp
index 9e864769c4..62dd5f51f9 100644
--- a/src/debug/daccess/request.cpp
+++ b/src/debug/daccess/request.cpp
@@ -1148,7 +1148,7 @@ ClrDataAccess::GetCodeHeaderData(CLRDATA_ADDRESS ip, struct DacpCodeHeaderData *
codeHeaderData->MethodStart =
(CLRDATA_ADDRESS) codeInfo.GetStartAddress();
- size_t methodSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfo());
+ size_t methodSize = codeInfo.GetCodeManager()->GetFunctionSize(codeInfo.GetGCInfoToken());
_ASSERTE(FitsIn<DWORD>(methodSize));
codeHeaderData->MethodSize = static_cast<DWORD>(methodSize);
diff --git a/src/gcdump/gcdump.cpp b/src/gcdump/gcdump.cpp
index d2fda049fc..1c512c88e0 100644
--- a/src/gcdump/gcdump.cpp
+++ b/src/gcdump/gcdump.cpp
@@ -18,8 +18,9 @@
-GCDump::GCDump(bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
- : fDumpEncBytes (encBytes ),
+GCDump::GCDump(UINT32 gcInfoVer, bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
+ : gcInfoVersion (gcInfoVer),
+ fDumpEncBytes (encBytes ),
cMaxEncBytes (maxEncBytes ),
fDumpCodeOffsets(dumpCodeOffs)
{
@@ -32,7 +33,7 @@ GCDump::GCDump(bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
* Display the byte encodings for the given range of the GC tables.
*/
-PTR_CBYTE GCDump::DumpEncoding(PTR_CBYTE table, int cDumpBytes)
+PTR_CBYTE GCDump::DumpEncoding(PTR_CBYTE gcInfoBlock, int cDumpBytes)
{
_ASSERTE((cDumpBytes >= 0) && (cMaxEncBytes < 256));
@@ -42,7 +43,7 @@ PTR_CBYTE GCDump::DumpEncoding(PTR_CBYTE table, int cDumpBytes)
unsigned count;
int cBytesLeft;
- for (count = cMaxEncBytes, cBytesLeft = cDumpBytes, pCurPos = table;
+ for (count = cMaxEncBytes, cBytesLeft = cDumpBytes, pCurPos = gcInfoBlock;
count > 0;
count--, pCurPos++, cBytesLeft--)
{
@@ -60,7 +61,7 @@ PTR_CBYTE GCDump::DumpEncoding(PTR_CBYTE table, int cDumpBytes)
gcPrintf("| ");
}
- return table + cDumpBytes;
+ return gcInfoBlock + cDumpBytes;
}
/*****************************************************************************/
diff --git a/src/gcdump/gcdumpnonx86.cpp b/src/gcdump/gcdumpnonx86.cpp
index 8167d3abd8..b6562d9892 100644
--- a/src/gcdump/gcdumpnonx86.cpp
+++ b/src/gcdump/gcdumpnonx86.cpp
@@ -78,8 +78,9 @@ PCSTR GetRegName (UINT32 regnum)
/*****************************************************************************/
-GCDump::GCDump(bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
- : fDumpEncBytes (encBytes ),
+GCDump::GCDump(UINT32 gcInfoVer, bool encBytes, unsigned maxEncBytes, bool dumpCodeOffs)
+ : gcInfoVersion(gcInfoVer),
+ fDumpEncBytes (encBytes ),
cMaxEncBytes (maxEncBytes ),
fDumpCodeOffsets(dumpCodeOffs)
{
@@ -270,11 +271,12 @@ BOOL StackSlotStateChangeCallback (
}
-size_t GCDump::DumpGCTable(PTR_CBYTE table,
+size_t GCDump::DumpGCTable(PTR_CBYTE gcInfoBlock,
unsigned methodSize,
bool verifyGCTables)
{
- GcInfoDecoder hdrdecoder(table,
+ GCInfoToken gcInfoToken = { dac_cast<PTR_VOID>(gcInfoBlock), gcInfoVersion };
+ GcInfoDecoder hdrdecoder(gcInfoToken,
(GcInfoDecoderFlags)( DECODE_SECURITY_OBJECT
| DECODE_GS_COOKIE
| DECODE_CODE_LENGTH
@@ -439,7 +441,7 @@ size_t GCDump::DumpGCTable(PTR_CBYTE table,
UINT32 cbEncodedMethodSize = hdrdecoder.GetCodeLength();
gcPrintf("Code size: %x\n", cbEncodedMethodSize);
- GcInfoDumper dumper(table);
+ GcInfoDumper dumper(gcInfoToken);
GcInfoDumpState state;
state.LastCodeOffset = -1;
diff --git a/src/gcinfo/gcinfodumper.cpp b/src/gcinfo/gcinfodumper.cpp
index 432e7066ce..4e31871f67 100644
--- a/src/gcinfo/gcinfodumper.cpp
+++ b/src/gcinfo/gcinfodumper.cpp
@@ -21,9 +21,9 @@
#error pick suitable ADDRESS_SPACING for platform
#endif
-GcInfoDumper::GcInfoDumper (PTR_CBYTE pbGCInfo)
+GcInfoDumper::GcInfoDumper (GCInfoToken gcInfoToken)
{
- m_pbGCInfo = pbGCInfo;
+ m_gcTable = gcInfoToken;
m_pRecords = NULL;
m_gcInfoSize = 0;
}
@@ -492,7 +492,7 @@ GcInfoDumper::EnumerateStateChangesResults GcInfoDumper::EnumerateStateChanges (
//
// Decode header information
//
- GcInfoDecoder hdrdecoder(m_pbGCInfo,
+ GcInfoDecoder hdrdecoder(m_gcTable,
(GcInfoDecoderFlags)( DECODE_SECURITY_OBJECT
| DECODE_CODE_LENGTH
| DECODE_GC_LIFETIMES
@@ -617,11 +617,11 @@ PORTABILITY_ASSERT("GcInfoDumper::EnumerateStateChanges is not implemented on th
//
#ifdef PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED
- GcInfoDecoder safePointDecoder(m_pbGCInfo, (GcInfoDecoderFlags)0, 0);
+ GcInfoDecoder safePointDecoder(m_gcTable, (GcInfoDecoderFlags)0, 0);
#endif
{
- GcInfoDecoder untrackedDecoder(m_pbGCInfo, DECODE_GC_LIFETIMES, 0);
+ GcInfoDecoder untrackedDecoder(m_gcTable, DECODE_GC_LIFETIMES, 0);
untrackedDecoder.EnumerateUntrackedSlots(&regdisp,
0,
&LivePointerCallback,
@@ -646,7 +646,7 @@ PORTABILITY_ASSERT("GcInfoDumper::EnumerateStateChanges is not implemented on th
{
BOOL fNewInterruptible = FALSE;
- GcInfoDecoder decoder1(m_pbGCInfo,
+ GcInfoDecoder decoder1(m_gcTable,
(GcInfoDecoderFlags)( DECODE_SECURITY_OBJECT
| DECODE_CODE_LENGTH
| DECODE_VARARG
@@ -680,7 +680,7 @@ PORTABILITY_ASSERT("GcInfoDumper::EnumerateStateChanges is not implemented on th
}
#endif
- GcInfoDecoder decoder2(m_pbGCInfo,
+ GcInfoDecoder decoder2(m_gcTable,
(GcInfoDecoderFlags)( DECODE_SECURITY_OBJECT
| DECODE_CODE_LENGTH
| DECODE_VARARG
diff --git a/src/inc/eetwain.h b/src/inc/eetwain.h
index a7bab8701e..6e183c5546 100644
--- a/src/inc/eetwain.h
+++ b/src/inc/eetwain.h
@@ -30,6 +30,7 @@
#include "corjit.h" // For NativeVarInfo
#include "stackwalktypes.h"
#include "bitvector.h"
+#include "gcinfotypes.h"
#if !defined(_TARGET_X86_)
#define USE_GC_INFO_DECODER
@@ -218,7 +219,7 @@ virtual bool IsGcSafe(EECodeInfo *pCodeInfo,
*/
virtual unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset,
unsigned endOffset,
- PTR_VOID methodInfoPtr) = 0;
+ GCInfoToken gcInfoToken) = 0;
#endif // _TARGET_AMD64_ && _DEBUG
/*
@@ -293,7 +294,7 @@ virtual bool IsInSynchronizedRegion(
not take procedure splitting into account). For the actual size of
the hot region call IJitManager::JitTokenToMethodHotSize.
*/
-virtual size_t GetFunctionSize(PTR_VOID methodInfoPtr) = 0;
+virtual size_t GetFunctionSize(GCInfoToken gcInfoToken) = 0;
/*
Returns the size of the frame (barring localloc)
@@ -447,7 +448,7 @@ bool IsGcSafe( EECodeInfo *pCodeInfo,
virtual
unsigned FindEndOfLastInterruptibleRegion(unsigned curOffset,
unsigned endOffset,
- PTR_VOID methodInfoPtr);
+ GCInfoToken gcInfoToken);
#endif // _TARGET_AMD64_ && _DEBUG
/*
@@ -551,8 +552,7 @@ bool IsInSynchronizedRegion(
Returns the size of a given function.
*/
virtual
-size_t GetFunctionSize(
- PTR_VOID methodInfoPtr);
+size_t GetFunctionSize(GCInfoToken gcInfoToken);
/*
Returns the size of the frame (barring localloc)
diff --git a/src/inc/gcdecoder.cpp b/src/inc/gcdecoder.cpp
index 7472c9aa62..d337faeebc 100644
--- a/src/inc/gcdecoder.cpp
+++ b/src/inc/gcdecoder.cpp
@@ -18,7 +18,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
/* This file is shared between the VM and JIT/IL and SOS/Strike directories */
-#include "gcinfo.h"
+#include "gcinfotypes.h"
/*****************************************************************************/
/*
diff --git a/src/inc/gcdump.h b/src/inc/gcdump.h
index aded6bb102..cd73940ded 100644
--- a/src/inc/gcdump.h
+++ b/src/inc/gcdump.h
@@ -17,7 +17,7 @@
#define __GCDUMP_H__
/*****************************************************************************/
-#include "gcinfo.h" // For InfoHdr
+#include "gcinfotypes.h" // For InfoHdr
#ifndef FASTCALL
#ifndef FEATURE_PAL
@@ -32,7 +32,8 @@ class GCDump
{
public:
- GCDump (bool encBytes = true,
+ GCDump (UINT32 gcInfoVersion,
+ bool encBytes = true,
unsigned maxEncBytes = 5,
bool dumpCodeOffs = true);
@@ -44,7 +45,7 @@ public:
* Return value : Size in bytes of the header encoding
*/
- unsigned FASTCALL DumpInfoHdr (PTR_CBYTE table,
+ unsigned FASTCALL DumpInfoHdr (PTR_CBYTE gcInfoBlock,
InfoHdr * header, /* OUT */
unsigned * methodSize, /* OUT */
bool verifyGCTables = false);
@@ -52,13 +53,12 @@ public:
/*-------------------------------------------------------------------------
* Dumps the GC tables to 'stdout'
- * table : Ptr to the start of the table part of the GC info.
- * This immediately follows the GCinfo header
+ * table : The GCInfoToken
* verifyGCTables : If the JIT has been compiled with VERIFY_GC_TABLES
* Return value : Size in bytes of the GC table encodings
*/
- size_t FASTCALL DumpGCTable (PTR_CBYTE table,
+ size_t FASTCALL DumpGCTable (PTR_CBYTE gcInfoBlock,
#ifdef _TARGET_X86_
const InfoHdr& header,
#endif
@@ -79,6 +79,7 @@ public:
public:
typedef void (*printfFtn)(const char* fmt, ...);
printfFtn gcPrintf;
+ UINT32 gcInfoVersion;
//-------------------------------------------------------------------------
protected:
@@ -89,7 +90,7 @@ protected:
/* Helper methods */
- PTR_CBYTE DumpEncoding(PTR_CBYTE table,
+ PTR_CBYTE DumpEncoding(PTR_CBYTE gcInfoBlock,
int cDumpBytes);
void DumpOffset (unsigned o);
void DumpOffsetEx(unsigned o);
diff --git a/src/inc/gcinfo.h b/src/inc/gcinfo.h
index bb80620f31..500e1b7a02 100644
--- a/src/inc/gcinfo.h
+++ b/src/inc/gcinfo.h
@@ -8,11 +8,8 @@
#define _GCINFO_H_
/*****************************************************************************/
-#include <stdlib.h> // For memcmp()
-#include "windef.h" // For BYTE
#include "daccess.h"
-
-#include "bitvector.h" // for ptrArgTP
+#include "windef.h" // For BYTE
// Some declarations in this file are used on non-x86 platforms, but most are x86-specific.
@@ -31,234 +28,32 @@ const unsigned byref_OFFSET_FLAG = 0x1; // the offset is an interior ptr
const unsigned pinned_OFFSET_FLAG = 0x2; // the offset is a pinned ptr
const unsigned this_OFFSET_FLAG = 0x2; // the offset is "this"
-#ifdef _TARGET_X86_
-
-#ifndef FASTCALL
-#define FASTCALL __fastcall
-#endif
+//-----------------------------------------------------------------------------
+// The current GCInfo Version
+//-----------------------------------------------------------------------------
-// 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
-};
+#define GCINFO_VERSION 1
+//-----------------------------------------------------------------------------
+// GCInfoToken: A wrapper that contains the GcInfo data and version number.
//
-// Enum to define the 128 codes that are used to incrementally adjust the InfoHdr structure
+// The version# is not stored in the GcInfo structure -- because it is
+// wasteful to store the version once for every method.
+// Instead, the version# istracked per range-section of generated/loaded methods.
//
-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)
+// 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.
+//-----------------------------------------------------------------------------
+
+struct GCInfoToken
{
- * ((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_ || _TARGET_ARM_
+ PTR_VOID Info;
+ UINT32 Version;
+};
/*****************************************************************************/
#endif //_GCINFO_H_
diff --git a/src/inc/gcinfodecoder.h b/src/inc/gcinfodecoder.h
index 52e8ed8b62..466ac15b68 100644
--- a/src/inc/gcinfodecoder.h
+++ b/src/inc/gcinfodecoder.h
@@ -11,7 +11,7 @@
#ifndef _GC_INFO_DECODER_
#define _GC_INFO_DECODER_
-#include "daccess.h"
+#include "gcinfotypes.h"
#define _max(a, b) (((a) > (b)) ? (a) : (b))
#define _min(a, b) (((a) < (b)) ? (a) : (b))
@@ -433,12 +433,11 @@ public:
// If you are not insterested in interruptibility or gc lifetime information, pass 0 as instructionOffset
GcInfoDecoder(
- PTR_CBYTE gcInfoAddr,
+ GCInfoToken gcInfoToken,
GcInfoDecoderFlags flags,
UINT32 instructionOffset = 0
);
-
//------------------------------------------------------------------------
// Interruptibility
//------------------------------------------------------------------------
@@ -538,6 +537,7 @@ private:
#ifdef _DEBUG
GcInfoDecoderFlags m_Flags;
PTR_CBYTE m_GcInfoAddress;
+ UINT32 m_Version;
#endif
#ifdef VERIFY_GCINFO
diff --git a/src/inc/gcinfodumper.h b/src/inc/gcinfodumper.h
index 64801b06c2..296dd29543 100644
--- a/src/inc/gcinfodumper.h
+++ b/src/inc/gcinfodumper.h
@@ -18,7 +18,7 @@ class GcInfoDumper
{
public:
- GcInfoDumper (PTR_CBYTE pbGCInfo);
+ GcInfoDumper (GCInfoToken gcInfoToken);
~GcInfoDumper ();
// Returns TRUE to stop decoding.
@@ -80,7 +80,7 @@ private:
UINT marked;
};
- PTR_CBYTE m_pbGCInfo;
+ GCInfoToken m_gcTable;
UINT32 m_StackBaseRegister;
UINT32 m_SizeOfEditAndContinuePreservedArea;
LivePointerRecord *m_pRecords;
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
diff --git a/src/jit/gcencode.cpp b/src/jit/gcencode.cpp
index c3ae12bcf4..fb033ddfae 100644
--- a/src/jit/gcencode.cpp
+++ b/src/jit/gcencode.cpp
@@ -21,7 +21,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
#endif
-#include "gcinfo.h"
+#include "gcinfotypes.h"
#ifdef JIT32_GCENCODER
@@ -3236,7 +3236,7 @@ unsigned GCInfo::gcInfoBlockHdrDump(const BYTE* table,
InfoHdr* header,
unsigned* methodSize)
{
- GCDump gcDump;
+ GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
printf("Method info block:\n");
@@ -3252,7 +3252,7 @@ unsigned GCInfo::gcDumpPtrTable(const BYTE* table,
{
printf("Pointer table:\n");
- GCDump gcDump;
+ GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
return gcDump.DumpGCTable(table, header, methodSize, verifyGCTables);
@@ -3268,7 +3268,7 @@ void GCInfo::gcFindPtrsInFrame(const void* infoBlock,
const void* codeBlock,
unsigned offs)
{
- GCDump gcDump;
+ GCDump gcDump(GCINFO_VERSION);
gcDump.gcPrintf = gcDump_logf; // use my printf (which logs to VM)
gcDump.DumpPtrsInFrame((const BYTE*)infoBlock, (const BYTE*)codeBlock, offs, verifyGCTables);
diff --git a/src/jit/jitgcinfo.h b/src/jit/jitgcinfo.h
index 480f88491a..e5092cfaa1 100644
--- a/src/jit/jitgcinfo.h
+++ b/src/jit/jitgcinfo.h
@@ -8,11 +8,11 @@
#ifndef _JITGCINFO_H_
#define _JITGCINFO_H_
-#include "gcinfo.h"
+
+#include "gcinfotypes.h"
#ifndef JIT32_GCENCODER
#include "gcinfoencoder.h"
-#include "gcinfotypes.h"
#endif
/*****************************************************************************/
diff --git a/src/vm/codeman.cpp b/src/vm/codeman.cpp
index 7eea254646..b66215f5f2 100644
--- a/src/vm/codeman.cpp
+++ b/src/vm/codeman.cpp
@@ -3015,7 +3015,7 @@ void * EEJitManager::allocCodeFragmentBlock(size_t blockSize, unsigned alignment
#endif // !DACCESS_COMPILE
-PTR_VOID EEJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
+GCInfoToken EEJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken)
{
CONTRACTL {
NOTHROW;
@@ -3024,7 +3024,8 @@ PTR_VOID EEJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
SUPPORTS_DAC;
} CONTRACTL_END;
- return GetCodeHeader(MethodToken)->GetGCInfo();
+ // The JIT-ed code always has the current version of GCInfo
+ return{ GetCodeHeader(MethodToken)->GetGCInfo(), GCINFO_VERSION };
}
// creates an enumeration and returns the number of EH clauses
@@ -5035,7 +5036,7 @@ NativeImageJitManager::NativeImageJitManager()
#endif // #ifndef DACCESS_COMPILE
-PTR_VOID NativeImageJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
+GCInfoToken NativeImageJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken)
{
CONTRACTL {
NOTHROW;
@@ -5060,7 +5061,8 @@ PTR_VOID NativeImageJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
PTR_VOID pUnwindData = GetUnwindDataBlob(baseAddress, pRuntimeFunction, &nUnwindDataSize);
// GCInfo immediatelly follows unwind data
- return dac_cast<PTR_BYTE>(pUnwindData) + nUnwindDataSize;
+ // GCInfo from an NGEN-ed image is always the current version
+ return{ dac_cast<PTR_BYTE>(pUnwindData) + nUnwindDataSize, GCINFO_VERSION };
}
unsigned NativeImageJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState)
@@ -5681,7 +5683,7 @@ void NativeImageJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& Method
//
methodRegionInfo->hotStartAddress = JitTokenToStartAddress(MethodToken);
- methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfo(MethodToken));
+ methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfoToken(MethodToken));
methodRegionInfo->coldStartAddress = 0;
methodRegionInfo->coldSize = 0;
@@ -6274,14 +6276,17 @@ PTR_MethodDesc MethodIterator::GetMethodDesc()
return NativeUnwindInfoLookupTable::GetMethodDesc(m_pNgenLayout, GetRuntimeFunction(), m_ModuleBase);
}
-PTR_VOID MethodIterator::GetGCInfo()
+GCInfoToken MethodIterator::GetGCInfoToken()
{
LIMITED_METHOD_CONTRACT;
// get the gc info from the RT function
SIZE_T size;
PTR_VOID pUnwindData = GetUnwindDataBlob(m_ModuleBase, GetRuntimeFunction(), &size);
- return (PTR_VOID)((PTR_BYTE)pUnwindData + size);
+ PTR_VOID gcInfo = (PTR_VOID)((PTR_BYTE)pUnwindData + size);
+ // MethodIterator is used to iterate over methods of an NgenImage.
+ // So, GcInfo version is always current
+ return{ gcInfo, GCINFO_VERSION };
}
TADDR MethodIterator::GetMethodStartAddress()
@@ -6359,8 +6364,8 @@ void MethodIterator::GetMethodRegionInfo(IJitManager::MethodRegionInfo *methodRe
methodRegionInfo->hotStartAddress = GetMethodStartAddress();
methodRegionInfo->coldStartAddress = GetMethodColdStartAddress();
-
- methodRegionInfo->hotSize = ExecutionManager::GetNativeImageJitManager()->GetCodeManager()->GetFunctionSize(GetGCInfo());
+ GCInfoToken gcInfoToken = GetGCInfoToken();
+ methodRegionInfo->hotSize = ExecutionManager::GetNativeImageJitManager()->GetCodeManager()->GetFunctionSize(gcInfoToken);
methodRegionInfo->coldSize = 0;
if (methodRegionInfo->coldStartAddress != NULL)
@@ -6408,6 +6413,24 @@ ReadyToRunInfo * ReadyToRunJitManager::JitTokenToReadyToRunInfo(const METHODTOKE
return dac_cast<PTR_Module>(MethodToken.m_pRangeSection->pHeapListOrZapModule)->GetReadyToRunInfo();
}
+UINT32 ReadyToRunJitManager::JitTokenToGCInfoVersion(const METHODTOKEN& MethodToken)
+{
+ CONTRACTL{
+ NOTHROW;
+ GC_NOTRIGGER;
+ HOST_NOCALLS;
+ SUPPORTS_DAC;
+ } CONTRACTL_END;
+
+ READYTORUN_HEADER * header = JitTokenToReadyToRunInfo(MethodToken)->GetImage()->GetReadyToRunHeader();
+ UINT32 gcInfoVersion = header->MajorVersion;
+
+ // Currently there's only one version of GCInfo.
+ _ASSERTE(gcInfoVersion == GCINFO_VERSION);
+
+ return gcInfoVersion;
+}
+
PTR_RUNTIME_FUNCTION ReadyToRunJitManager::JitTokenToRuntimeFunction(const METHODTOKEN& MethodToken)
{
CONTRACTL {
@@ -6433,7 +6456,7 @@ TADDR ReadyToRunJitManager::JitTokenToStartAddress(const METHODTOKEN& MethodToke
RUNTIME_FUNCTION__BeginAddress(dac_cast<PTR_RUNTIME_FUNCTION>(MethodToken.m_pCodeHeader));
}
-PTR_VOID ReadyToRunJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
+GCInfoToken ReadyToRunJitManager::GetGCInfoToken(const METHODTOKEN& MethodToken)
{
CONTRACTL {
NOTHROW;
@@ -6458,7 +6481,10 @@ PTR_VOID ReadyToRunJitManager::GetGCInfo(const METHODTOKEN& MethodToken)
PTR_VOID pUnwindData = GetUnwindDataBlob(baseAddress, pRuntimeFunction, &nUnwindDataSize);
// GCInfo immediatelly follows unwind data
- return dac_cast<PTR_BYTE>(pUnwindData) + nUnwindDataSize;
+ PTR_BYTE gcInfo = dac_cast<PTR_BYTE>(pUnwindData) + nUnwindDataSize;
+ UINT32 gcInfoVersion = JitTokenToGCInfoVersion(MethodToken);
+
+ return{ gcInfo, gcInfoVersion };
}
unsigned ReadyToRunJitManager::InitializeEHEnumeration(const METHODTOKEN& MethodToken, EH_CLAUSE_ENUMERATOR* pEnumState)
@@ -6863,7 +6889,7 @@ void ReadyToRunJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& MethodT
// READYTORUN: FUTURE: Hot-cold spliting
methodRegionInfo->hotStartAddress = JitTokenToStartAddress(MethodToken);
- methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfo(MethodToken));
+ methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfoToken(MethodToken));
methodRegionInfo->coldStartAddress = 0;
methodRegionInfo->coldSize = 0;
}
diff --git a/src/vm/codeman.h b/src/vm/codeman.h
index 855c15125a..ae86a25e93 100644
--- a/src/vm/codeman.h
+++ b/src/vm/codeman.h
@@ -24,9 +24,10 @@ Abstract:
An IJitManager knows about which method bodies live in each RangeSection.
It can handle methods of one given CodeType. It can map a method body to
a MethodDesc. It knows where the GCInfo about the method lives.
- Today, we have 2 IJitManagers viz.
+ Today, we have three IJitManagers viz.
1. EEJitManager for JITcompiled code generated by clrjit.dll
2. NativeImageJitManager for ngenned code.
+ 3. ReadyToRunJitManager for version resiliant ReadyToRun code
An ICodeManager knows how to crack a specific format of GCInfo. There is
a default format (handled by ExecutionManager::GetDefaultCodeManager())
@@ -66,6 +67,7 @@ Abstract:
#include "debuginfostore.h"
#include "shash.h"
#include "pedecoder.h"
+#include "gcinfo.h"
class MethodDesc;
class ICorJitCompiler;
@@ -113,6 +115,7 @@ enum StubCodeBlockKind : int
// Method header which exists just before the code.
// Every IJitManager could have its own format for the header.
// Today CodeHeader is used by the EEJitManager.
+// The GCInfo version is always current GCINFO_VERSION in this header.
#ifdef USE_INDIRECT_CODEHEADER
typedef DPTR(struct _hpRealCodeHdr) PTR_RealCodeHeader;
@@ -735,7 +738,11 @@ public:
CrawlFrame *pCf)=0;
#endif // #ifndef DACCESS_COMPILE
- virtual PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken)=0;
+ virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken)=0;
+ PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken)
+ {
+ return GetGCInfoToken(MethodToken).Info;
+ }
TADDR JitTokenToModuleBase(const METHODTOKEN& MethodToken);
@@ -965,7 +972,7 @@ public:
virtual TypeHandle ResolveEHClause(EE_ILEXCEPTION_CLAUSE* pEHClause,
CrawlFrame *pCf);
#endif // !DACCESS_COMPILE
- PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken);
+ GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
#endif // !CROSSGEN_COMPILE
#if !defined DACCESS_COMPILE && !defined CROSSGEN_COMPILE
void RemoveJitData(CodeHeader * pCHdr, size_t GCinfo_len, size_t EHinfo_len);
@@ -1486,7 +1493,7 @@ inline void EEJitManager::JitTokenToMethodRegionInfo(const METHODTOKEN& MethodTo
} CONTRACTL_END;
methodRegionInfo->hotStartAddress = JitTokenToStartAddress(MethodToken);
- methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfo(MethodToken));
+ methodRegionInfo->hotSize = GetCodeManager()->GetFunctionSize(GetGCInfoToken(MethodToken));
methodRegionInfo->coldStartAddress = 0;
methodRegionInfo->coldSize = 0;
}
@@ -1543,7 +1550,7 @@ public:
CrawlFrame *pCf);
#endif // #ifndef DACCESS_COMPILE
- virtual PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken);
+ virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
#if defined(WIN64EXCEPTIONS)
virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo);
@@ -1638,6 +1645,8 @@ public:
virtual PCODE GetCodeAddressForRelOffset(const METHODTOKEN& MethodToken, DWORD relOffset);
static ReadyToRunInfo * JitTokenToReadyToRunInfo(const METHODTOKEN& MethodToken);
+ static UINT32 JitTokenToGCInfoVersion(const METHODTOKEN& MethodToken);
+
static PTR_RUNTIME_FUNCTION JitTokenToRuntimeFunction(const METHODTOKEN& MethodToken);
virtual TADDR JitTokenToStartAddress(const METHODTOKEN& MethodToken);
@@ -1653,7 +1662,7 @@ public:
CrawlFrame *pCf);
#endif // #ifndef DACCESS_COMPILE
- virtual PTR_VOID GetGCInfo(const METHODTOKEN& MethodToken);
+ virtual GCInfoToken GetGCInfoToken(const METHODTOKEN& MethodToken);
#if defined(WIN64EXCEPTIONS)
virtual PTR_RUNTIME_FUNCTION LazyGetFunctionEntry(EECodeInfo * pCodeInfo);
@@ -1754,10 +1763,15 @@ public:
return m_relOffset;
}
- PTR_VOID GetGCInfo()
+ GCInfoToken GetGCInfoToken()
{
WRAPPER_NO_CONTRACT;
- return GetJitManager()->GetGCInfo(GetMethodToken());
+ return GetJitManager()->GetGCInfoToken(GetMethodToken());
+ }
+
+ PTR_VOID GetGCInfo()
+ {
+ return GetGCInfoToken().Info;
}
void GetMethodRegionInfo(IJitManager::MethodRegionInfo *methodRegionInfo)
@@ -1824,7 +1838,7 @@ class MethodSectionIterator;
//
// MethodIterator class is used to iterate all the methods in an ngen image.
// It will match and report hot (and cold, if any) sections of a method at the same time.
-//
+// GcInfo version is always current
class MethodIterator
{
public:
@@ -1852,7 +1866,7 @@ private:
BOOL Next();
PTR_MethodDesc GetMethodDesc();
- PTR_VOID GetGCInfo();
+ GCInfoToken GetGCInfoToken();
TADDR GetMethodStartAddress();
TADDR GetMethodColdStartAddress();
ULONG GetHotCodeSize();
diff --git a/src/vm/debughelp.cpp b/src/vm/debughelp.cpp
index 7e4455a7ff..df769455aa 100644
--- a/src/vm/debughelp.cpp
+++ b/src/vm/debughelp.cpp
@@ -1198,24 +1198,24 @@ void DumpGCInfo(MethodDesc* method)
_ASSERTE(codeInfo.GetRelOffset() == 0);
ICodeManager* codeMan = codeInfo.GetCodeManager();
- BYTE* table = (BYTE*) codeInfo.GetGCInfo();
+ GCInfoToken table = codeInfo.GetGCInfoToken();
unsigned methodSize = (unsigned)codeMan->GetFunctionSize(table);
- GCDump gcDump;
+ GCDump gcDump(table.Version);
+ PTR_CBYTE gcInfo = PTR_CBYTE(table.Info);
gcDump.gcPrintf = printfToDbgOut;
InfoHdr header;
printfToDbgOut ("Method info block:\n");
-
- table += gcDump.DumpInfoHdr(table, &header, &methodSize, 0);
+ gcInfo += gcDump.DumpInfoHdr(gcInfo, &header, &methodSize, 0);
printfToDbgOut ("\n");
printfToDbgOut ("Pointer table:\n");
- table += gcDump.DumpGCTable(table, header, methodSize, 0);
+ gcInfo += gcDump.DumpGCTable(gcInfo, header, methodSize, 0);
}
void DumpGCInfoMD(size_t method)
diff --git a/src/vm/eedbginterfaceimpl.cpp b/src/vm/eedbginterfaceimpl.cpp
index 53cb288319..93decc9b0d 100644
--- a/src/vm/eedbginterfaceimpl.cpp
+++ b/src/vm/eedbginterfaceimpl.cpp
@@ -665,10 +665,8 @@ size_t EEDbgInterfaceImpl::GetFunctionSize(MethodDesc *pFD)
return 0;
EECodeInfo codeInfo(methodStart);
-
- PTR_VOID methodInfo = codeInfo.GetGCInfo();
-
- return codeInfo.GetCodeManager()->GetFunctionSize(methodInfo);
+ GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
+ return codeInfo.GetCodeManager()->GetFunctionSize(gcInfoToken);
}
#endif //!DACCESS_COMPILE
diff --git a/src/vm/eetwain.cpp b/src/vm/eetwain.cpp
index 69eb177542..82b76f69e0 100644
--- a/src/vm/eetwain.cpp
+++ b/src/vm/eetwain.cpp
@@ -11,8 +11,6 @@
#define RETURN_ADDR_OFFS 1 // in DWORDS
-#include "gcinfo.h"
-
#ifdef USE_GC_INFO_DECODER
#include "gcinfodecoder.h"
#endif
@@ -942,14 +940,14 @@ HRESULT EECodeManager::FixContextForEnC(PCONTEXT pCtx,
// GCInfo for old method
GcInfoDecoder oldGcDecoder(
- dac_cast<PTR_CBYTE>(pOldCodeInfo->GetGCInfo()),
+ pOldCodeInfo->GetGCInfoToken(),
GcInfoDecoderFlags(DECODE_SECURITY_OBJECT | DECODE_PSP_SYM | DECODE_EDIT_AND_CONTINUE),
0 // Instruction offset (not needed)
);
// GCInfo for new method
GcInfoDecoder newGcDecoder(
- dac_cast<PTR_CBYTE>(pNewCodeInfo->GetGCInfo()),
+ pNewCodeInfo->GetGCInfoToken(),
GcInfoDecoderFlags(DECODE_SECURITY_OBJECT | DECODE_PSP_SYM | DECODE_EDIT_AND_CONTINUE),
0 // Instruction offset (not needed)
);
@@ -1437,8 +1435,10 @@ bool EECodeManager::IsGcSafe( EECodeInfo *pCodeInfo,
GC_NOTRIGGER;
} CONTRACTL_END;
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
+
GcInfoDecoder gcInfoDecoder(
- dac_cast<PTR_CBYTE>(pCodeInfo->GetGCInfo()),
+ gcInfoToken,
DECODE_INTERRUPTIBILITY,
dwRelOffset
);
@@ -1502,13 +1502,11 @@ bool FindEndOfLastInterruptibleRegionCB (
*/
unsigned EECodeManager::FindEndOfLastInterruptibleRegion(unsigned curOffset,
unsigned endOffset,
- PTR_VOID methodInfoPtr)
+ GCInfoToken gcInfoToken)
{
#ifndef DACCESS_COMPILE
- BYTE* gcInfoAddr = (BYTE*) methodInfoPtr;
-
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_FOR_RANGES_CALLBACK,
0);
@@ -4758,7 +4756,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
methodName, curOffs));
#endif
- PTR_BYTE gcInfoAddr = dac_cast<PTR_BYTE>(pCodeInfo->GetGCInfo());
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
#if defined(STRESS_HEAP) && defined(PARTIALLY_INTERRUPTIBLE_GC_SUPPORTED)
#ifdef USE_GC_INFO_DECODER
@@ -4770,7 +4768,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
if (flags & ActiveStackFrame)
{
GcInfoDecoder _gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_INTERRUPTIBILITY,
curOffs
);
@@ -4778,7 +4776,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
{
// This must be the offset after a call
#ifdef _DEBUG
- GcInfoDecoder _safePointDecoder(gcInfoAddr, (GcInfoDecoderFlags)0, 0);
+ GcInfoDecoder _safePointDecoder(gcInfoToken, (GcInfoDecoderFlags)0, 0);
_ASSERTE(_safePointDecoder.IsSafePoint(curOffs));
#endif
flags &= ~((unsigned)ActiveStackFrame);
@@ -4791,7 +4789,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
if (flags & ActiveStackFrame)
{
GcInfoDecoder _gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_INTERRUPTIBILITY,
curOffs
);
@@ -4839,7 +4837,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
// We've been given an override offset for GC Info
#ifdef _DEBUG
GcInfoDecoder _gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_CODE_LENGTH,
0
);
@@ -4884,7 +4882,7 @@ bool EECodeManager::EnumGcRefs( PREGDISPLAY pRD,
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
GcInfoDecoderFlags (DECODE_GC_LIFETIMES | DECODE_SECURITY_OBJECT | DECODE_VARARG),
curOffs
);
@@ -5027,7 +5025,7 @@ OBJECTREF* EECodeManager::GetAddrOfSecurityObject(CrawlFrame *pCF)
unsigned relOffset = pCF->GetRelOffset();
CodeManState* pState = pCF->GetCodeManState();
- PTR_VOID methodInfoPtr = pJitMan->GetGCInfo(methodToken);
+ GCInfoToken gcInfoToken = pJitMan->GetGCInfoToken(methodToken);
_ASSERTE(sizeof(CodeManStateBuf) <= sizeof(pState->stateBuf));
@@ -5035,7 +5033,7 @@ OBJECTREF* EECodeManager::GetAddrOfSecurityObject(CrawlFrame *pCF)
CodeManStateBuf * stateBuf = (CodeManStateBuf*)pState->stateBuf;
/* Extract the necessary information from the info block header */
- stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(methodInfoPtr, // <TODO>truncation</TODO>
+ stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(gcInfoToken.Info, // <TODO>truncation</TODO>
relOffset,
&stateBuf->hdrInfoBody);
@@ -5051,10 +5049,8 @@ OBJECTREF* EECodeManager::GetAddrOfSecurityObject(CrawlFrame *pCF)
}
#elif defined(USE_GC_INFO_DECODER) && !defined(CROSSGEN_COMPILE)
- BYTE* gcInfoAddr = (BYTE*) methodInfoPtr;
-
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_SECURITY_OBJECT,
0
);
@@ -5270,11 +5266,10 @@ GenericParamContextType EECodeManager::GetParamContextType(PREGDISPLAY pCont
}
// On x86 the generic param context parameter is never this.
#elif defined(USE_GC_INFO_DECODER)
- PTR_VOID methodInfoPtr = pCodeInfo->GetGCInfo();
- PTR_CBYTE gcInfoAddr = PTR_CBYTE(methodInfoPtr);
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
GcInfoDecoderFlags (DECODE_GENERICS_INST_CONTEXT),
0
);
@@ -5363,11 +5358,10 @@ PTR_VOID EECodeManager::GetExactGenericsToken(SIZE_T baseStackSlot,
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
- PTR_VOID methodInfoPtr = pCodeInfo->GetGCInfo();
- PTR_CBYTE gcInfoAddr = PTR_CBYTE(methodInfoPtr);
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
GcInfoDecoderFlags (DECODE_PSP_SYM | DECODE_GENERICS_INST_CONTEXT),
0
);
@@ -5432,7 +5426,7 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY pContext,
_ASSERTE(sizeof(CodeManStateBuf) <= sizeof(pState->stateBuf));
- PTR_VOID methodInfoPtr = pCodeInfo->GetGCInfo();
+ GCInfoToken gcInfoToken = pCodeInfo->GetGCInfoToken();
unsigned relOffset = pCodeInfo->GetRelOffset();
#if defined(_TARGET_X86_)
@@ -5440,7 +5434,7 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY pContext,
/* Extract the necessary information from the info block header */
hdrInfo * info = &stateBuf->hdrInfoBody;
- stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(methodInfoPtr, // <TODO>truncation</TODO>
+ stateBuf->hdrInfoSize = (DWORD)crackMethodInfoHdr(gcInfoToken.Info, // <TODO>truncation</TODO>
relOffset,
info);
@@ -5459,22 +5453,20 @@ void * EECodeManager::GetGSCookieAddr(PREGDISPLAY pContext,
}
else
{
- PTR_CBYTE table = PTR_CBYTE(methodInfoPtr) + stateBuf->hdrInfoSize;
+ PTR_CBYTE table = PTR_CBYTE(gcInfoToken.Info) + stateBuf->hdrInfoSize;
unsigned argSize = GetPushedArgSize(info, table, relOffset);
return PVOID(SIZE_T(pContext->Esp + argSize + info->gsCookieOffset));
}
#elif defined(USE_GC_INFO_DECODER) && !defined(CROSSGEN_COMPILE)
- PTR_CBYTE gcInfoAddr = PTR_CBYTE(methodInfoPtr);
-
if (pCodeInfo->IsFunclet())
{
return NULL;
}
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_GS_COOKIE,
0
);
@@ -5567,7 +5559,7 @@ bool EECodeManager::IsInSynchronizedRegion(
*
* Returns the size of a given function.
*/
-size_t EECodeManager::GetFunctionSize(PTR_VOID methodInfoPtr)
+size_t EECodeManager::GetFunctionSize(GCInfoToken gcInfoToken)
{
CONTRACTL {
NOTHROW;
@@ -5577,16 +5569,15 @@ size_t EECodeManager::GetFunctionSize(PTR_VOID methodInfoPtr)
#if defined(_TARGET_X86_)
hdrInfo info;
+ PTR_VOID methodInfoPtr = gcInfoToken.Info;
crackMethodInfoHdr(methodInfoPtr, 0, &info);
return info.methodSize;
#elif defined(USE_GC_INFO_DECODER)
- PTR_BYTE gcInfoAddr = PTR_BYTE(methodInfoPtr);
-
GcInfoDecoder gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_CODE_LENGTH,
0
);
diff --git a/src/vm/gccover.cpp b/src/vm/gccover.cpp
index 2dd7c9e2a5..3220cddd8e 100644
--- a/src/vm/gccover.cpp
+++ b/src/vm/gccover.cpp
@@ -79,7 +79,7 @@ void SetupAndSprinkleBreakpoints(
gcCover->methodRegion = methodRegionInfo;
gcCover->codeMan = pCodeInfo->GetCodeManager();
- gcCover->gcInfo = pCodeInfo->GetGCInfo();
+ gcCover->gcInfoToken = pCodeInfo->GetGCInfoToken();
gcCover->callerThread = 0;
gcCover->doingEpilogChecks = true;
@@ -286,7 +286,7 @@ class GCCoverageRangeEnumerator
private:
ICodeManager *m_pCodeManager;
- LPVOID m_pvGCInfo;
+ GCInfoToken m_pvGCTable;
BYTE *m_codeStart;
BYTE *m_codeEnd;
BYTE *m_curFuncletEnd;
@@ -318,7 +318,7 @@ private:
unsigned ofsLastInterruptible = m_pCodeManager->FindEndOfLastInterruptibleRegion(
static_cast<unsigned int>(pCurFunclet - m_codeStart),
static_cast<unsigned int>(m_curFuncletEnd - m_codeStart),
- m_pvGCInfo);
+ m_pvGCTable);
if (ofsLastInterruptible)
{
@@ -332,10 +332,10 @@ private:
public:
- GCCoverageRangeEnumerator (ICodeManager *pCodeManager, LPVOID pvGCInfo, BYTE *codeStart, SIZE_T codeSize)
+ GCCoverageRangeEnumerator (ICodeManager *pCodeManager, GCInfoToken pvGCTable, BYTE *codeStart, SIZE_T codeSize)
{
m_pCodeManager = pCodeManager;
- m_pvGCInfo = pvGCInfo;
+ m_pvGCTable = pvGCTable;
m_codeStart = codeStart;
m_codeEnd = codeStart + codeSize;
m_nextFunclet = codeStart;
@@ -458,9 +458,9 @@ void GCCoverageInfo::SprinkleBreakpoints(
#ifdef _TARGET_AMD64_
- GCCoverageRangeEnumerator rangeEnum(codeMan, gcInfo, codeStart, codeSize);
+ GCCoverageRangeEnumerator rangeEnum(codeMan, gcInfoToken, codeStart, codeSize);
- GcInfoDecoder safePointDecoder((const BYTE*)gcInfo, (GcInfoDecoderFlags)0, 0);
+ GcInfoDecoder safePointDecoder(gcInfoToken, (GcInfoDecoderFlags)0, 0);
bool fSawPossibleSwitch = false;
#endif
@@ -582,7 +582,7 @@ void GCCoverageInfo::SprinkleBreakpoints(
#ifdef _TARGET_X86_
// we will whack every instruction in the prolog and epilog to make certain
// our unwinding logic works there.
- if (codeMan->IsInPrologOrEpilog((cur - codeStart) + (DWORD)regionOffsetAdj, gcInfo, NULL)) {
+ if (codeMan->IsInPrologOrEpilog((cur - codeStart) + (DWORD)regionOffsetAdj, gcInfoToken.Info, NULL)) {
*cur = INTERRUPT_INSTR;
}
#endif
@@ -632,7 +632,7 @@ void GCCoverageInfo::SprinkleBreakpoints(
}
}
- GcInfoDecoder safePointDecoder((const BYTE*)gcInfo, (GcInfoDecoderFlags)0, 0);
+ GcInfoDecoder safePointDecoder(gcInfoToken, (GcInfoDecoderFlags)0, 0);
assert(methodRegion.hotSize > 0);
@@ -1469,7 +1469,7 @@ void DoGcStress (PCONTEXT regs, MethodDesc *pMD)
/* are we in a prolog or epilog? If so just test the unwind logic
but don't actually do a GC since the prolog and epilog are not
GC safe points */
- if (gcCover->codeMan->IsInPrologOrEpilog(offset, gcCover->gcInfo, NULL))
+ if (gcCover->codeMan->IsInPrologOrEpilog(offset, gcCover->gcInfoToken.Info, NULL))
{
// We are not at a GC safe point so we can't Suspend EE (Suspend EE will yield to GC).
// But we still have to update the GC Stress instruction. We do it directly without suspending
diff --git a/src/vm/gccover.h b/src/vm/gccover.h
index 0308f473f2..b2dedefa31 100644
--- a/src/vm/gccover.h
+++ b/src/vm/gccover.h
@@ -26,7 +26,7 @@ public:
// Following 6 variables are for prolog / epilog walking coverage
ICodeManager* codeMan; // CodeMan for this method
- void* gcInfo; // gcInfo for this method
+ GCInfoToken gcInfoToken; // gcInfo for this method
Thread* callerThread; // Thread associated with context callerRegs
T_CONTEXT callerRegs; // register state when method was entered
diff --git a/src/vm/gcenv.ee.cpp b/src/vm/gcenv.ee.cpp
index aa1edbb555..5ecae4f8fc 100644
--- a/src/vm/gcenv.ee.cpp
+++ b/src/vm/gcenv.ee.cpp
@@ -132,7 +132,7 @@ inline bool SafeToReportGenericParamContext(CrawlFrame* pCF)
#else // USE_GC_INFO_DECODER
- GcInfoDecoder gcInfoDecoder((PTR_CBYTE)pCF->GetGCInfo(),
+ GcInfoDecoder gcInfoDecoder(pCF->GetGCInfoToken(),
DECODE_PROLOG_LENGTH,
0);
UINT32 prologLength = gcInfoDecoder.GetPrologSize();
@@ -199,8 +199,8 @@ bool FindFirstInterruptiblePointStateCB(
// the end is exclusive). Return -1 if no such point exists.
unsigned FindFirstInterruptiblePoint(CrawlFrame* pCF, unsigned offs, unsigned endOffs)
{
- PTR_BYTE gcInfoAddr = dac_cast<PTR_BYTE>(pCF->GetCodeInfo()->GetGCInfo());
- GcInfoDecoder gcInfoDecoder(gcInfoAddr, DECODE_FOR_RANGES_CALLBACK, 0);
+ GCInfoToken gcInfoToken = pCF->GetGCInfoToken();
+ GcInfoDecoder gcInfoDecoder(gcInfoToken, DECODE_FOR_RANGES_CALLBACK, 0);
FindFirstInterruptiblePointState state;
state.offs = offs;
@@ -281,9 +281,9 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData)
#if defined(WIN64EXCEPTIONS)
if (pCF->ShouldParentToFuncletUseUnwindTargetLocationForGCReporting())
{
- PTR_BYTE gcInfoAddr = dac_cast<PTR_BYTE>(pCF->GetCodeInfo()->GetGCInfo());
+ GCInfoToken gcInfoToken = pCF->GetGCInfoToken();
GcInfoDecoder _gcInfoDecoder(
- gcInfoAddr,
+ gcInfoToken,
DECODE_CODE_LENGTH,
0
);
diff --git a/src/vm/gcinfodecoder.cpp b/src/vm/gcinfodecoder.cpp
index 5a3bbd94eb..b2f5640331 100644
--- a/src/vm/gcinfodecoder.cpp
+++ b/src/vm/gcinfodecoder.cpp
@@ -6,7 +6,6 @@
#include "common.h"
#include "gcinfodecoder.h"
-
#ifdef USE_GC_INFO_DECODER
#ifndef CHECK_APP_DOMAIN
@@ -84,11 +83,11 @@ bool GcInfoDecoder::SetIsInterruptibleCB (UINT32 startOffset, UINT32 stopOffset,
GcInfoDecoder::GcInfoDecoder(
- PTR_CBYTE gcInfoAddr,
+ GCInfoToken gcInfoToken,
GcInfoDecoderFlags flags,
UINT32 breakOffset
)
- : m_Reader( gcInfoAddr
+ : m_Reader(dac_cast<PTR_CBYTE>(gcInfoToken.Info)
#ifdef VERIFY_GCINFO
+ sizeof(size_t)
#endif
@@ -97,13 +96,14 @@ GcInfoDecoder::GcInfoDecoder(
, m_IsInterruptible(false)
#ifdef _DEBUG
, m_Flags( flags )
- , m_GcInfoAddress(gcInfoAddr)
+ , m_GcInfoAddress(dac_cast<PTR_CBYTE>(gcInfoToken.Info))
+ , m_Version(gcInfoToken.Version)
#endif
#ifdef VERIFY_GCINFO
- , m_DbgDecoder(gcInfoAddr+
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoAddr)[3])<<24)+
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoAddr)[2])<<16)+
- (((UINT32)((PTR_BYTE)(TADDR)gcInfoAddr)[1])<<8)+
+ , m_DbgDecoder(dac_cast<PTR_CBYTE>(gcInfoToken.Info) +
+ (((UINT32)((PTR_BYTE)(TADDR)gcInfoToken.Info)[3])<<24)+
+ (((UINT32)((PTR_BYTE)(TADDR)gcInfoToken.Info)[2])<<16)+
+ (((UINT32)((PTR_BYTE)(TADDR)gcInfoToken.Info)[1])<<8)+
((PTR_BYTE)(TADDR)gcInfoAddr)[0],
flags, breakOffset)
#endif
diff --git a/src/vm/stackwalk.h b/src/vm/stackwalk.h
index 3d6dbdcb14..004d673a2a 100644
--- a/src/vm/stackwalk.h
+++ b/src/vm/stackwalk.h
@@ -324,6 +324,13 @@ public:
return &codeInfo;
}
+ GCInfoToken GetGCInfoToken()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(isFrameless);
+ return codeInfo.GetGCInfoToken();
+ }
+
PTR_VOID GetGCInfo()
{
LIMITED_METHOD_DAC_CONTRACT;