Jit: Make most Jit compile failures non-fatal; just abort offending translation

Issue 2175597 Jit compile failures should abort translation, but not the VM

Added new dvmCompileAbort() to replace uses of dvmAbort() when something goes
wrong during the compliation of a trace.  In that case, we'll abort the translation
and set it's head to the interpret-only "translation".
diff --git a/vm/compiler/Compiler.c b/vm/compiler/Compiler.c
index 13749ac..597fbb2 100644
--- a/vm/compiler/Compiler.c
+++ b/vm/compiler/Compiler.c
@@ -479,11 +479,17 @@
                 if (gDvmJit.haltCompilerThread) {
                     LOGD("Compiler shutdown in progress - discarding request");
                 } else if (!gDvmJit.codeCacheFull) {
-                    /* If compilation failed, use interpret-template */
-                    if (!dvmCompilerDoWork(&work)) {
-                        work.result.codeAddress = gDvmJit.interpretTemplate;
+                    bool compileOK = false;
+                    jmp_buf jmpBuf;
+                    work.bailPtr = &jmpBuf;
+                    bool aborted = setjmp(jmpBuf);
+                    if (!aborted) {
+                        compileOK = dvmCompilerDoWork(&work);
                     }
-                    if (!work.result.discardResult) {
+                    if (aborted || !compileOK) {
+                        dvmCompilerArenaReset();
+                        work.result.codeAddress = gDvmJit.interpretTemplate;
+                    } else if (!work.result.discardResult) {
                         dvmJitSetCodeAddr(work.pc, work.result.codeAddress,
                                           work.result.instructionSet);
                     }
diff --git a/vm/compiler/Compiler.h b/vm/compiler/Compiler.h
index 932f41d..21c86ab 100644
--- a/vm/compiler/Compiler.h
+++ b/vm/compiler/Compiler.h
@@ -15,6 +15,7 @@
  */
 
 #include <Thread.h>
+#include <setjmp.h>
 
 #ifndef _DALVIK_VM_COMPILER
 #define _DALVIK_VM_COMPILER
@@ -56,6 +57,7 @@
     WorkOrderKind kind;
     void* info;
     JitTranslationInfo result;
+    jmp_buf *bailPtr;
 } CompilerWorkOrder;
 
 /* Chain cell for predicted method invocation */
@@ -152,7 +154,7 @@
 void *dvmCheckCodeCache(void *method);
 bool dvmCompileMethod(const Method *method, JitTranslationInfo *info);
 bool dvmCompileTrace(JitTraceDescription *trace, int numMaxInsts,
-                     JitTranslationInfo *info);
+                     JitTranslationInfo *info, jmp_buf *bailPtr);
 void dvmCompilerDumpStats(void);
 void dvmCompilerDrainQueue(void);
 void dvmJitUnchainAll(void);
@@ -184,5 +186,4 @@
 void dvmCompilerStateRefresh(void);
 JitTraceDescription *dvmCopyTraceDescriptor(const u2 *pc,
                                             const struct JitEntry *desc);
-
 #endif /* _DALVIK_VM_COMPILER */
diff --git a/vm/compiler/CompilerIR.h b/vm/compiler/CompilerIR.h
index 00892fa..00a45f9 100644
--- a/vm/compiler/CompilerIR.h
+++ b/vm/compiler/CompilerIR.h
@@ -157,6 +157,7 @@
     LIR *chainingCellBottom;
     struct RegisterPool *regPool;
     int optRound;                       // round number to tell an LIR's age
+    jmp_buf *bailPtr;
     JitInstructionSetType instructionSet;
     /* Number of total regs used in the whole cUnit after SSA transformation */
     int numSSARegs;
@@ -195,6 +196,8 @@
 
 void dvmCompilerInsertLIRAfter(LIR *currentLIR, LIR *newLIR);
 
+void dvmCompilerAbort(CompilationUnit *cUnit);
+
 /* Debug Utilities */
 void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit);
 
diff --git a/vm/compiler/Frontend.c b/vm/compiler/Frontend.c
index 0c8a8df..d97001f 100644
--- a/vm/compiler/Frontend.c
+++ b/vm/compiler/Frontend.c
@@ -286,7 +286,7 @@
  * bytecode into machine code.
  */
 bool dvmCompileTrace(JitTraceDescription *desc, int numMaxInsts,
-                     JitTranslationInfo *info)
+                     JitTranslationInfo *info, jmp_buf *bailPtr)
 {
     const DexCode *dexCode = dvmGetMethodCode(desc->method);
     const JitTraceRun* currRun = &desc->trace[0];
@@ -316,6 +316,9 @@
     methodStats = analyzeMethodBody(desc->method);
 #endif
 
+    /* Set the recover buffer pointer */
+    cUnit.bailPtr = bailPtr;
+
     /* Initialize the printMe flag */
     cUnit.printMe = gDvmJit.printMe;
 
@@ -760,7 +763,7 @@
 
     /* Halve the instruction count and retry again */
     } else {
-        return dvmCompileTrace(desc, cUnit.numInsts / 2, info);
+        return dvmCompileTrace(desc, cUnit.numInsts / 2, info, bailPtr);
     }
 }
 
@@ -896,7 +899,7 @@
 
     if (numBlocks != cUnit.numBlocks) {
         LOGE("Expect %d vs %d basic blocks\n", numBlocks, cUnit.numBlocks);
-        dvmAbort();
+        dvmCompilerAbort(&cUnit);
     }
 
     /* Connect the basic blocks through the taken links */
@@ -930,7 +933,7 @@
             if (j == numBlocks && !isInvoke) {
                 LOGE("Target not found for insn %x: expect target %x\n",
                      curBB->lastMIRInsn->offset, target);
-                dvmAbort();
+                dvmCompilerAbort(&cUnit);
             }
         }
     }
diff --git a/vm/compiler/IntermediateRep.c b/vm/compiler/IntermediateRep.c
index 018d890..b3e6490 100644
--- a/vm/compiler/IntermediateRep.c
+++ b/vm/compiler/IntermediateRep.c
@@ -81,8 +81,7 @@
  */
 void dvmCompilerInsertLIRBefore(LIR *currentLIR, LIR *newLIR)
 {
-    if (currentLIR->prev == NULL)
-        dvmAbort();
+    assert(currentLIR->prev != NULL);
     LIR *prevLIR = currentLIR->prev;
 
     prevLIR->next = newLIR;
diff --git a/vm/compiler/Loop.c b/vm/compiler/Loop.c
index e996ca2..ef76c50 100644
--- a/vm/compiler/Loop.c
+++ b/vm/compiler/Loop.c
@@ -314,7 +314,8 @@
                     break;
                 default:
                     refIdx = 0;
-                    dvmAbort();
+                    LOGE("Jit: bad case in doLoopBodyCodeMotion");
+                    dvmCompilerAbort(cUnit);
             }
 
             int useIdx = refIdx + 1;
@@ -449,7 +450,8 @@
                     dvmCompilerAppendMIR(entry, boundCheckMIR);
                 }
             } else {
-                dvmAbort();
+                LOGE("Jit: bad case in genHoistedChecks");
+                dvmCompilerAbort(cUnit);
             }
         }
 
diff --git a/vm/compiler/Utility.c b/vm/compiler/Utility.c
index 26bb3d0..83caab7 100644
--- a/vm/compiler/Utility.c
+++ b/vm/compiler/Utility.c
@@ -66,11 +66,7 @@
          * could go above the limit we need to enhance the allocation
          * mechanism.
          */
-        if (size > ARENA_DEFAULT_SIZE) {
-            LOGE("Requesting %d bytes which exceed the maximal size allowed\n",
-                 size);
-            dvmAbort();
-        }
+        assert(size <= ARENA_DEFAULT_SIZE);
         /* Time to allocate a new arena */
         ArenaMemBlock *newArena = (ArenaMemBlock *)
             malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
@@ -281,3 +277,15 @@
         }
     }
 }
+
+void dvmCompilerAbort(CompilationUnit *cUnit)
+{
+    LOGE("Jit: aborting trace compilation, reverting to interpreter");
+    /* Force a traceback in debug builds */
+    assert(0);
+    /*
+     * Abort translation and force to interpret-only for this trace
+     * Matching setjmp in compiler thread work loop in Compiler.c.
+     */
+    longjmp(*cUnit->bailPtr, 1);
+}
diff --git a/vm/compiler/codegen/arm/Assemble.c b/vm/compiler/codegen/arm/Assemble.c
index 28dafe7..0d7895f 100644
--- a/vm/compiler/codegen/arm/Assemble.c
+++ b/vm/compiler/codegen/arm/Assemble.c
@@ -934,7 +934,7 @@
             int delta = target - pc;
             if (delta & 0x3) {
                 LOGE("PC-rel distance is not multiples of 4: %d\n", delta);
-                dvmAbort();
+                dvmCompilerAbort(cUnit);
             }
             if ((lir->opCode == kThumb2LdrPcRel12) && (delta > 4091)) {
                 return true;
@@ -978,7 +978,7 @@
             int delta = target - pc;
             if (delta > 2046 || delta < -2048) {
                 LOGE("Unconditional branch distance out of range: %d\n", delta);
-                dvmAbort();
+                dvmCompilerAbort(cUnit);
             }
             lir->operands[0] = delta >> 1;
         } else if (lir->opCode == kThumbBlx1) {
@@ -1626,7 +1626,7 @@
                 default:
                     targetOffset = 0; // make gcc happy
                     LOGE("Unexpected chaining type: %d", i);
-                    dvmAbort();
+                    dvmAbort();  // dvmAbort OK here - can't safely recover
             }
             COMPILER_TRACE_CHAINING(
                 LOGD("Jit Runtime: unchaining 0x%x", (int)pChainCells));
diff --git a/vm/compiler/codegen/arm/CodegenCommon.c b/vm/compiler/codegen/arm/CodegenCommon.c
index 6d2ddcd..8f5c11d 100644
--- a/vm/compiler/codegen/arm/CodegenCommon.c
+++ b/vm/compiler/codegen/arm/CodegenCommon.c
@@ -60,7 +60,8 @@
             break;
         default:
             LOGE("Jit: invalid memref kind - %d", memType);
-            dvmAbort();
+            assert(0);  // Bail if debug build, set worst-case in the field
+            *maskPtr |= ENCODE_ALL;
     }
 }
 
diff --git a/vm/compiler/codegen/arm/CodegenDriver.c b/vm/compiler/codegen/arm/CodegenDriver.c
index a496152..21a52d8 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.c
+++ b/vm/compiler/codegen/arm/CodegenDriver.c
@@ -612,7 +612,7 @@
         }
         default:
             LOGE("Invalid long arith op");
-            dvmAbort();
+            dvmCompilerAbort(cUnit);
     }
     if (!callOut) {
         genLong3Addr(cUnit, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
@@ -716,7 +716,7 @@
         default:
             LOGE("Invalid word arith op: 0x%x(%d)",
                  mir->dalvikInsn.opCode, mir->dalvikInsn.opCode);
-            dvmAbort();
+            dvmCompilerAbort(cUnit);
     }
     if (!callOut) {
         rlSrc1 = loadValue(cUnit, rlSrc1, kCoreReg);
@@ -1836,7 +1836,7 @@
         default:
             cond = 0;
             LOGE("Unexpected opcode (%d) for Fmt21t\n", dalvikOpCode);
-            dvmAbort();
+            dvmCompilerAbort(cUnit);
     }
     genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
     /* This mostly likely will be optimized away in a later phase */
@@ -2234,7 +2234,7 @@
         default:
             cond = 0;
             LOGE("Unexpected opcode (%d) for Fmt22t\n", dalvikOpCode);
-            dvmAbort();
+            dvmCompilerAbort(cUnit);
     }
     genConditionalBranch(cUnit, cond, &labelList[bb->taken->id]);
     /* This mostly likely will be optimized away in a later phase */
@@ -3106,7 +3106,7 @@
                 case INLINE_MATH_SIN:
                     break;   /* Handle with C routine */
                 default:
-                    dvmAbort();
+                    dvmCompilerAbort(cUnit);
             }
             dvmCompilerFlushAllRegs(cUnit);   /* Everything to home location */
             dvmCompilerClobberCallRegs(cUnit);
@@ -3723,7 +3723,7 @@
                      mir->offset,
                      dalvikOpCode, getOpcodeName(dalvikOpCode),
                      dalvikFormat);
-                dvmAbort();
+                dvmCompilerAbort(cUnit);
                 break;
             }
         }
@@ -3804,8 +3804,7 @@
 #endif
                 default:
                     LOGE("Bad blocktype %d", blockList[blockId]->blockType);
-                    dvmAbort();
-                    break;
+                    dvmCompilerAbort(cUnit);
             }
         }
     }
@@ -3851,19 +3850,22 @@
             break;
         case kWorkOrderTrace:
             /* Start compilation with maximally allowed trace length */
-            res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
+            res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
+                                  work->bailPtr);
             break;
         case kWorkOrderTraceDebug: {
             bool oldPrintMe = gDvmJit.printMe;
             gDvmJit.printMe = true;
             /* Start compilation with maximally allowed trace length */
-            res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result);
+            res = dvmCompileTrace(work->info, JIT_MAX_TRACE_LEN, &work->result,
+                                  work->bailPtr);
             gDvmJit.printMe = oldPrintMe;;
             break;
         }
         default:
             res = false;
-            dvmAbort();
+            LOGE("Jit: unknown work order type");
+            assert(0);  // Bail if debug build, discard oteherwise
     }
     return res;
 }
@@ -3923,7 +3925,7 @@
         if (EncodingMap[i].opCode != i) {
             LOGE("Encoding order for %s is wrong: expecting %d, seeing %d",
                  EncodingMap[i].name, i, EncodingMap[i].opCode);
-            dvmAbort();
+            dvmAbort();  // OK to dvmAbort - build error
         }
     }
 
diff --git a/vm/compiler/codegen/arm/RallocUtil.c b/vm/compiler/codegen/arm/RallocUtil.c
index 131df2c..6d83e73 100644
--- a/vm/compiler/codegen/arm/RallocUtil.c
+++ b/vm/compiler/codegen/arm/RallocUtil.c
@@ -123,7 +123,7 @@
         }
     }
     LOGE("Tried to get info on a non-existant temp: r%d",reg);
-    dvmAbort();  // FIXME: abort translation intead of vm
+    dvmCompilerAbort(cUnit);
     return NULL;
 }
 
@@ -249,7 +249,7 @@
     }
     if (required) {
         LOGE("No free temp registers");
-        dvmAbort();  // FIXME: abort translation instead of vm
+        dvmCompilerAbort(cUnit);
     }
     return -1;  // No register available
 }
@@ -298,7 +298,7 @@
         next += 2;
     }
     LOGE("No free temp registers");
-    dvmAbort(); // FIXME: abort translation instead of vm
+    dvmCompilerAbort(cUnit);
     return -1;
 }
 
@@ -359,7 +359,7 @@
             break;
         default:
             LOGE("Invalid register type");
-            dvmAbort();    //FIXME: abort translation instead of vm
+            dvmCompilerAbort(cUnit);
     }
     return res;
 }
@@ -386,7 +386,7 @@
         }
     }
     LOGE("Tried to free a non-existant temp: r%d",reg);
-    dvmAbort();  // FIXME: abort translation instead of vm
+    dvmCompilerAbort(cUnit);
 }
 
 /*
@@ -460,7 +460,7 @@
         }
     }
     LOGE("Tried to lock a non-existant temp: r%d",reg);
-    dvmAbort();  // FIXME: abort translation instead of vm
+    dvmCompilerAbort(cUnit);
 }
 
 static void lockArgRegs(CompilationUnit *cUnit)
diff --git a/vm/compiler/codegen/arm/Thumb/Factory.c b/vm/compiler/codegen/arm/Thumb/Factory.c
index 0a44280..ba64922 100644
--- a/vm/compiler/codegen/arm/Thumb/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb/Factory.c
@@ -124,7 +124,8 @@
             opCode = kThumbBUncond;
             break;
         default:
-            dvmAbort(); // FIXME: abort trace instead of VM
+            LOGE("Jit: bad case in opNone");
+            dvmCompilerAbort(cUnit);
     }
     return newLIR0(cUnit, opCode);
 }
@@ -145,7 +146,8 @@
             opCode = kThumbPop;
             break;
         default:
-            dvmAbort(); // FIXME: abort trace instead of VM
+            LOGE("Jit: bad case in opCondBranch");
+            dvmCompilerAbort(cUnit);
     }
     return newLIR1(cUnit, opCode, value);
 }
@@ -158,7 +160,8 @@
             opCode = kThumbBlxR;
             break;
         default:
-            dvmAbort(); // FIXME: abort trace instead of VM
+            LOGE("Jit: bad case in opReg");
+            dvmCompilerAbort(cUnit);
     }
     return newLIR1(cUnit, opCode, rDestSrc);
 }
@@ -203,7 +206,8 @@
             }
             break;
         default:
-            dvmAbort();  // FIXME: abort trace instead of VM
+            LOGE("Jit: bad case in opRegImm");
+            dvmCompilerAbort(cUnit);
             break;
     }
     if (shortForm)
@@ -323,7 +327,8 @@
                 }
                 return res;
         default:
-            dvmAbort();  // FIXME - abort trace instead of VM
+            LOGE("Jit: bad case in opRegRegImm");
+            dvmCompilerAbort(cUnit);
             break;
     }
     if (shortForm)
@@ -420,7 +425,8 @@
              opRegRegImm(cUnit, kOpLsr, rDestSrc1, rDestSrc1, 16);
              return res;
         default:
-            dvmAbort();  // FIXME - abort trace instead of VM
+            LOGE("Jit: bad case in opRegReg");
+            dvmCompilerAbort(cUnit);
             break;
     }
     return newLIR2(cUnit, opCode, rDestSrc1, rSrc2);
@@ -465,7 +471,8 @@
             opCode = kThumbLdrsbRRR;
             break;
         default:
-            dvmAbort();  // FIXME: abort trace instead of VM
+            LOGE("Jit: bad case in loadBaseIndexed");
+            dvmCompilerAbort(cUnit);
     }
     res = newLIR3(cUnit, opCode, rDest, rBase, rNewIndex);
 #if defined(WITH_SELF_VERIFICATION)
@@ -502,7 +509,8 @@
             opCode = kThumbStrbRRR;
             break;
         default:
-            dvmAbort();  // FIXME - abort trace instead of VM
+            LOGE("Jit: bad case in storeBaseIndexed");
+            dvmCompilerAbort(cUnit);
     }
     res = newLIR3(cUnit, opCode, rSrc, rBase, rNewIndex);
 #if defined(WITH_SELF_VERIFICATION)
@@ -619,7 +627,8 @@
             opCode = kThumbLdrsbRRR;
             break;
         default:
-            dvmAbort();  // FIXME - abort trace instead of VM
+            LOGE("Jit: bad case in loadBaseIndexedBody");
+            dvmCompilerAbort(cUnit);
     }
     if (shortForm) {
         load = res = newLIR3(cUnit, opCode, rDest, rBase, encodedDisp);
@@ -736,7 +745,8 @@
             }
             break;
         default:
-            dvmAbort(); // FIXME - abort trace instead of VM
+            LOGE("Jit: bad case in storeBaseIndexedBody");
+            dvmCompilerAbort(cUnit);
     }
     if (shortForm) {
         store = res = newLIR3(cUnit, opCode, rSrc, rBase, encodedDisp);
diff --git a/vm/compiler/codegen/arm/Thumb2/Factory.c b/vm/compiler/codegen/arm/Thumb2/Factory.c
index c4d2c28..eb36193 100644
--- a/vm/compiler/codegen/arm/Thumb2/Factory.c
+++ b/vm/compiler/codegen/arm/Thumb2/Factory.c
@@ -163,7 +163,7 @@
         return res;
     }
     /* No shortcut - go ahead and use literal pool */
-    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 255);
+    ArmLIR *dataTarget = scanLiteralPool(cUnit, value, 0);
     if (dataTarget == NULL) {
         dataTarget = addWordData(cUnit, value, false);
     }
diff --git a/vm/compiler/codegen/arm/Thumb2/Gen.c b/vm/compiler/codegen/arm/Thumb2/Gen.c
index b51cdd4..8a574b3 100644
--- a/vm/compiler/codegen/arm/Thumb2/Gen.c
+++ b/vm/compiler/codegen/arm/Thumb2/Gen.c
@@ -142,8 +142,8 @@
         case 0:
             break;
         default:
-            assert(0);
-            dvmAbort();
+            LOGE("Jit: bad case in genIT");
+            dvmCompilerAbort(cUnit);
     }
     mask = (mask3 << 3) | (mask2 << 2) | (mask1 << 1) |
            (1 << (3 - strlen(guide)));