diff options
author | Swaroop Sridhar <Swaroop.Sridhar@microsoft.com> | 2016-07-20 21:11:30 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-20 21:11:30 -0700 |
commit | 0d5eac078847baebb32653655373086d6729f923 (patch) | |
tree | 88141f3f44e841444bf6af772b29d28d0f94c6e2 | |
parent | 32a020e47a0797bba4167e85efc38a34397f633e (diff) | |
parent | f915aebaf5db0b829f062dc9940e23bb5c38d575 (diff) | |
download | coreclr-0d5eac078847baebb32653655373086d6729f923.tar.gz coreclr-0d5eac078847baebb32653655373086d6729f923.tar.bz2 coreclr-0d5eac078847baebb32653655373086d6729f923.zip |
Merge pull request #6325 from swaroop-sridhar/R2Rver
GCInfo: Support versioning.
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 20395f0018..ba3995b1f7 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(®disp, 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; |