[x86/Linux] Use GCInfo for funclet unwinding
authorJonghyun Park <parjong@gmail.com>
Wed, 5 Apr 2017 00:30:08 +0000 (09:30 +0900)
committerJonghyun Park <parjong@gmail.com>
Thu, 6 Apr 2017 23:48:17 +0000 (08:48 +0900)
src/gcdump/i386/gcdumpx86.cpp
src/jit/emit.cpp
src/jit/emit.h
src/jit/gcencode.cpp
src/jit/morph.cpp
src/vm/eetwain.cpp

index 23e6c68..9096085 100644 (file)
@@ -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;
index e9ba4e5..ede1f14 100644 (file)
@@ -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<unsigned>(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();
         }
index 91cf96e..64f9eb9 100644 (file)
@@ -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?
 
index caf9131..1e9f288 100644 (file)
@@ -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 */
 
index bb2e7e4..40e9b35 100644 (file)
@@ -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_
 
index aff2507..4f0bbbc 100644 (file)
@@ -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;
     }