From 42924c80d75313c45abb049d2e38fbb9f538f589 Mon Sep 17 00:00:00 2001 From: Jonghyun Park Date: Wed, 5 Apr 2017 09:30:08 +0900 Subject: [PATCH] [x86/Linux] Use GCInfo for funclet unwinding --- src/gcdump/i386/gcdumpx86.cpp | 3 +++ src/jit/emit.cpp | 12 +++++++++--- src/jit/emit.h | 1 + src/jit/gcencode.cpp | 2 ++ src/jit/morph.cpp | 7 +++++++ src/vm/eetwain.cpp | 39 +++++++++++++++++++++++++++------------ 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/gcdump/i386/gcdumpx86.cpp b/src/gcdump/i386/gcdumpx86.cpp index 23e6c68..9096085 100644 --- a/src/gcdump/i386/gcdumpx86.cpp +++ b/src/gcdump/i386/gcdumpx86.cpp @@ -452,7 +452,10 @@ size_t GCDump::DumpGCTable(PTR_CBYTE table, /* non-ptr arg push */ curOffs += (val & 0x07); +#ifndef UNIX_X86_ABI + // For x86/Linux, non-ptr arg pushes can be reported even for EBP frames _ASSERTE(!header.ebpFrame); +#endif // UNIX_X86_ABI argCnt++; DumpEncoding(bp, table-bp); bp = table; diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp index e9ba4e5..ede1f14 100644 --- a/src/jit/emit.cpp +++ b/src/jit/emit.cpp @@ -4405,6 +4405,12 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, emitFullyInt = fullyInt; emitFullGCinfo = fullPtrMap; +#ifndef UNIX_X86_ABI + emitFullArgInfo = !emitHasFramePtr; +#else + emitFullArgInfo = fullPtrMap; +#endif + #if EMITTER_STATS GCrefsTable.record(emitGCrFrameOffsCnt); emitSizeTable.record(static_cast(emitSizeMethod)); @@ -6817,7 +6823,7 @@ void emitter::emitStackPushLargeStk(BYTE* addr, GCtype gcType, unsigned count) *u2.emitArgTrackTop++ = (BYTE)gcType; assert(u2.emitArgTrackTop <= u2.emitArgTrackTab + emitMaxStackDepth); - if (!emitHasFramePtr || needsGC(gcType)) + if (emitFullArgInfo || needsGC(gcType)) { if (emitFullGCinfo) { @@ -6889,7 +6895,7 @@ void emitter::emitStackPopLargeStk(BYTE* addr, bool isCall, unsigned char callIn // This is an "interesting" argument - if (!emitHasFramePtr || needsGC(gcType)) + if (emitFullArgInfo || needsGC(gcType)) { argRecCnt += 1; } @@ -7037,7 +7043,7 @@ void emitter::emitStackKillArgs(BYTE* addr, unsigned count, unsigned char callIn /* We're about to kill the corresponding (pointer) arg records */ - if (emitHasFramePtr) + if (!emitFullArgInfo) { u2.emitGcArgTrackCnt -= gcCnt.Value(); } diff --git a/src/jit/emit.h b/src/jit/emit.h index 91cf96e..64f9eb9 100644 --- a/src/jit/emit.h +++ b/src/jit/emit.h @@ -2040,6 +2040,7 @@ public: /* The following logic keeps track of live GC ref values */ /************************************************************************/ + bool emitFullArgInfo; // full arg info (including non-ptr arg)? bool emitFullGCinfo; // full GC pointer maps? bool emitFullyInt; // fully interruptible code? diff --git a/src/jit/gcencode.cpp b/src/jit/gcencode.cpp index caf9131..1e9f288 100644 --- a/src/jit/gcencode.cpp +++ b/src/jit/gcencode.cpp @@ -2424,7 +2424,9 @@ DONE_VLT: assert((codeDelta & 0x7) == codeDelta); *dest++ = 0xB0 | (BYTE)codeDelta; +#ifndef UNIX_X86_ABI assert(!compiler->isFramePointerUsed()); +#endif /* Remember the new 'last' offset */ diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp index bb2e7e4..40e9b35 100644 --- a/src/jit/morph.cpp +++ b/src/jit/morph.cpp @@ -16202,7 +16202,14 @@ void Compiler::fgSetOptions() // to use a frame pointer because of EH. But until all the code uses // the same test, leave info.compXcptnsCount here. if (info.compXcptnsCount > 0) + { codeGen->setFramePointerRequiredEH(true); +#ifdef UNIX_X86_ABI + assert(!codeGen->isGCTypeFixed()); + // Enforce fully interruptible codegen for funclet unwinding + genInterruptible = true; +#endif // UNIX_X86_ABI + } #else // !_TARGET_X86_ diff --git a/src/vm/eetwain.cpp b/src/vm/eetwain.cpp index aff2507..4f0bbbc 100644 --- a/src/vm/eetwain.cpp +++ b/src/vm/eetwain.cpp @@ -2413,6 +2413,18 @@ unsigned scanArgRegTableI(PTR_CBYTE table, _ASSERTE(*castto(table, unsigned short *)++ == 0xBABE); #endif + bool isPartialArgInfo; + +#ifndef UNIX_X86_ABI + isPartialArgInfo = info->ebpFrame; +#else + // For x86/Linux, interruptible code always has full arg info + // + // This should be aligned with emitFullArgInfo setting at + // emitter::emitEndCodeGen (in JIT) + isPartialArgInfo = false; +#endif + /* Encoding table for methods that are fully interruptible @@ -2611,9 +2623,9 @@ unsigned scanArgRegTableI(PTR_CBYTE table, argOfs--; } - else if (info->ebpFrame) + else if (isPartialArgInfo) argCnt--; - else /* !ebpFrame && not a ref */ + else /* full arg info && not a ref */ argOfs--; /* Continue with the next lower bit */ @@ -2622,11 +2634,11 @@ unsigned scanArgRegTableI(PTR_CBYTE table, } while (argOfs); - _ASSERTE((info->ebpFrame != 0) || + _ASSERTE(!isPartialArgInfo || isZero(argHigh) || (argHigh == CONSTRUCT_ptrArgTP(1, (argCnt-1)))); - if (info->ebpFrame) + if (isPartialArgInfo) { while (!intersect(argHigh, ptrArgs) && (!isZero(argHigh))) argHigh >>= 1; @@ -2643,10 +2655,10 @@ unsigned scanArgRegTableI(PTR_CBYTE table, } else { - /* For ESP-frames, all pushes are reported, and so + /* Full arg info reports all pushes, and thus argOffs has to be consistent with argCnt */ - _ASSERTE(info->ebpFrame || argCnt == argOfs); + _ASSERTE(isPartialArgInfo || argCnt == argOfs); /* store arg count */ @@ -2692,7 +2704,7 @@ unsigned scanArgRegTableI(PTR_CBYTE table, } else { /* non-ptr arg push */ - _ASSERTE(!(info->ebpFrame)); + _ASSERTE(!isPartialArgInfo); ptrOffs += (val & 0x07); if (ptrOffs > curOffs) { iptr = isThis = false; @@ -2753,9 +2765,9 @@ unsigned scanArgRegTableI(PTR_CBYTE table, } } - // For ebp-frames, need to find the next higest pointer for argHigh + // For partial arg info, need to find the next higest pointer for argHigh - if (info->ebpFrame) + if (isPartialArgInfo) { for(argHigh = ptrArgTP(0); !isZero(argMask); argMask >>= 1) { @@ -2794,7 +2806,7 @@ REPORT_REFS: info->thisPtrResult = thisPtrReg; _ASSERTE(thisPtrReg == REGI_NA || (regNumToMask(thisPtrReg) & info->regMaskResult)); - if (info->ebpFrame) + if (isPartialArgInfo) { return 0; } @@ -3789,7 +3801,9 @@ bool UnwindEbpDoubleAlignFrame( PREGDISPLAY pContext, EECodeInfo *pCodeInfo, hdrInfo *info, + PTR_CBYTE table, PTR_CBYTE methodStart, + DWORD curOffs, unsigned flags, StackwalkCacheUnwindInfo *pUnwindInfo) // out-only, perf improvement { @@ -3815,8 +3829,9 @@ bool UnwindEbpDoubleAlignFrame( // TODO Currently we assume that ESP of funclet frames is always fixed but actually it could change. if (pCodeInfo->IsFunclet()) { + baseSP = curESP; // Set baseSP as initial SP - baseSP = pContext->pCurrentContext->ResumeEsp; + baseSP += GetPushedArgSize(info, table, curOffs); // 16-byte stack alignment padding (allocated in genFuncletProlog) baseSP += 12; @@ -4014,7 +4029,7 @@ bool UnwindStackFrame(PREGDISPLAY pContext, * Now we know that have an EBP frame */ - if (!UnwindEbpDoubleAlignFrame(pContext, pCodeInfo, info, methodStart, flags, pUnwindInfo)) + if (!UnwindEbpDoubleAlignFrame(pContext, pCodeInfo, info, table, methodStart, curOffs, flags, pUnwindInfo)) return false; } -- 2.7.4