Mark top of managed stack on helper transitions

To assist with unwind from a helper function, store current SP prior
to helper call in Thread.  NOTE: we may wish to push this into a
trampoline to reduce code expansion.  NOTE #2:  Because any helper
function which can throw will be non-leaf, it will spill lr at the saved
address - 4 (the word immediately below caller's Method*).  To identify
the callsite, load the spilled lr, clear the low bit, subtract 2, and use
that address in the native <-> dalvik mapping to identify the callsite.

Also in this CL are a ralloc fix and some extra SSA logging.

Change-Id: Idd442f0c55413a5146c24709b1db1150604f4554
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index e9933ff..0c83a94 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -197,6 +197,7 @@
     std::vector<uint32_t> mappingTable;
     bool printMe;
     bool printMeVerbose;
+    bool dumpCFG;
     bool hasClassLiterals;              // Contains class ptrs used as literals
     bool hasLoop;                       // Contains a loop
     bool hasInvoke;                     // Contains an invoke instruction
diff --git a/src/compiler/Dataflow.cc b/src/compiler/Dataflow.cc
index cb208a5..06f942f 100644
--- a/src/compiler/Dataflow.cc
+++ b/src/compiler/Dataflow.cc
@@ -1945,7 +1945,7 @@
     defs[regIndex] = ssaReg;
 }
 
-/* Loop up new SSA names for format_35c instructions */
+/* Look up new SSA names for format_35c instructions */
 static void dataFlowSSAFormat35C(CompilationUnit* cUnit, MIR* mir)
 {
     DecodedInstruction *dInsn = &mir->dalvikInsn;
@@ -1960,7 +1960,7 @@
     }
 }
 
-/* Loop up new SSA names for format_3rc instructions */
+/* Look up new SSA names for format_3rc instructions */
 static void dataFlowSSAFormat3RC(CompilationUnit* cUnit, MIR* mir)
 {
     DecodedInstruction *dInsn = &mir->dalvikInsn;
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 2e94516..887ae71 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -851,7 +851,9 @@
     oatMethodMIR2LIR(&cUnit);
 
     // Debugging only
-    //oatDumpCFG(&cUnit, "/sdcard/cfg/");
+    if (cUnit.dumpCFG) {
+        oatDumpCFG(&cUnit, "/sdcard/cfg/");
+    }
 
     /* Method is not empty */
     if (cUnit.firstLIRInsn) {
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
index 1fe680f..76cff17 100644
--- a/src/compiler/codegen/RallocUtil.cc
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -833,7 +833,11 @@
 {
     RegisterInfo* newInfo = getRegInfo(cUnit, newReg);
     RegisterInfo* oldInfo = getRegInfo(cUnit, oldReg);
+    // Target temp status must not change
+    bool isTemp = newInfo->isTemp;
     *newInfo = *oldInfo;
+    // Restore target's temp status
+    newInfo->isTemp = isTemp;
     newInfo->reg = newReg;
 }
 
@@ -1011,7 +1015,12 @@
 {
     RegLocation res = cUnit->regLocation[mir->ssaRep->defs[num]];
 #ifdef SSA_WORKAROUND
-    res.wide = false;
+    if (res.wide) {
+        LOG(WARNING) << "Invalid SSA renaming: " << PrettyMethod(cUnit->method);
+        cUnit->printMe = true;
+        cUnit->dumpCFG = true;
+        res.wide = false;
+    }
 #endif
     assert(!res.wide);
     return res;
@@ -1020,7 +1029,12 @@
 {
     RegLocation res = cUnit->regLocation[mir->ssaRep->uses[num]];
 #ifdef SSA_WORKAROUND
-    res.wide = false;
+    if (res.wide) {
+        LOG(WARNING) << "Invalid SSA renaming: " << PrettyMethod(cUnit->method);
+        cUnit->printMe = true;
+        cUnit->dumpCFG = true;
+        res.wide = false;
+    }
 #endif
     assert(!res.wide);
     return res;
@@ -1035,7 +1049,12 @@
 {
     RegLocation res = cUnit->regLocation[mir->ssaRep->defs[low]];
 #ifdef SSA_WORKAROUND
-    res.wide = true;
+    if (!res.wide) {
+        LOG(WARNING) << "Invalid SSA renaming: " << PrettyMethod(cUnit->method);
+        cUnit->printMe = true;
+        cUnit->dumpCFG = true;
+        res.wide = true;
+    }
 #endif
     assert(res.wide);
     return res;
@@ -1046,7 +1065,12 @@
 {
     RegLocation res = cUnit->regLocation[mir->ssaRep->uses[low]];
 #ifdef SSA_WORKAROUND
-    res.wide = true;
+    if (!res.wide) {
+        LOG(WARNING) << "Invalid SSA renaming: " << PrettyMethod(cUnit->method);
+        cUnit->printMe = true;
+        cUnit->dumpCFG = true;
+        res.wide = true;
+    }
 #endif
     assert(res.wide);
     return res;
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index 66eaf54..34a333d 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -62,7 +62,7 @@
     if (cCode == kArmCondAl) {
         branch = genUnconditionalBranch(cUnit, tgt);
     } else {
-        branch = genCmpImmBranch(cUnit, kArmCondEq, reg, 0);
+        branch = genCmpImmBranch(cUnit, cCode, reg, immVal);
         branch->generic.target = (LIR*)tgt;
     }
     // Remember branch target - will process later
@@ -86,18 +86,18 @@
     return genImmedCheck(cUnit, kArmCondEq, mReg, 0, mir, kArmThrowNullPointer);
 }
 
-/* Perform bound check on two registers */
-static TGT_LIR* genBoundsCheck(CompilationUnit* cUnit, int rIndex,
-                               int rBound, MIR* mir, ArmThrowKind kind)
+/* Perform check on two registers */
+static TGT_LIR* genRegRegCheck(CompilationUnit* cUnit, ArmConditionCode cCode,
+                               int reg1, int reg2, MIR* mir, ArmThrowKind kind)
 {
     ArmLIR* tgt = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
     tgt->opcode = kArmPseudoThrowTarget;
     tgt->operands[0] = kind;
-    tgt->operands[1] = mir->offset;
-    tgt->operands[2] = rIndex;
-    tgt->operands[3] = rBound;
-    opRegReg(cUnit, kOpCmp, rIndex, rBound);
-    ArmLIR* branch = genConditionalBranch(cUnit, kArmCondCs, tgt);
+    tgt->operands[1] = mir ? mir->offset : 0;
+    tgt->operands[2] = reg1;
+    tgt->operands[3] = reg2;
+    opRegReg(cUnit, kOpCmp, reg1, reg2);
+    ArmLIR* branch = genConditionalBranch(cUnit, cCode, tgt);
     // Remember branch target - will process later
     oatInsertGrowableList(&cUnit->throwLaunchpads, (intptr_t)tgt);
     return branch;
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index b35f39f..212358f 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -356,6 +356,7 @@
     kArmThrowInternalError,
     kArmThrowRuntimeException,
     kArmThrowNoSuchMethod,
+    kArmThrowStackOverflow,
 } ArmThrowKind;
 
 #define isPseudoOpcode(opcode) ((int)(opcode) < 0)
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 929bbef..7e09ccc 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -37,7 +37,7 @@
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, mir->dalvikInsn.vC);  // arg0 <- type_id
     loadValueDirectFixed(cUnit, rlSrc, r2);       // arg2 <- count
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     RegLocation rlResult = oatGetReturn(cUnit);
     storeValue(cUnit, rlDest, rlResult);
@@ -67,7 +67,7 @@
     loadCurrMethodDirect(cUnit, r1);              // arg1 <- Method*
     loadConstant(cUnit, r0, typeId);              // arg0 <- type_id
     loadConstant(cUnit, r2, elems);               // arg2 <- count
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     /*
      * NOTE: the implicit target for OP_FILLED_NEW_ARRAY is the
      * return region.  Because AllocFromCode placed the new array
@@ -154,7 +154,7 @@
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
         loadCurrMethodDirect(cUnit, r1);
         loadValueDirect(cUnit, rlSrc, r2);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
     } else {
         // fast path
@@ -181,7 +181,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
         loadConstant(cUnit, r0, typeIdx);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
         skipTarget->defMask = ENCODE_ALL;
         branchOver->generic.target = (LIR*)skipTarget;
@@ -212,7 +212,7 @@
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
         loadCurrMethodDirect(cUnit, r1);
         loadValueDirectWideFixed(cUnit, rlSrc, r2, r3);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
     } else {
         // fast path
@@ -239,7 +239,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
         loadConstant(cUnit, r0, typeIdx);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
         skipTarget->defMask = ENCODE_ALL;
         branchOver->generic.target = (LIR*)skipTarget;
@@ -269,7 +269,7 @@
         loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pGet64Static), rLR);
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
         loadCurrMethodDirect(cUnit, r1);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         RegLocation rlResult = oatGetReturnWide(cUnit);
         storeValueWide(cUnit, rlDest, rlResult);
     } else {
@@ -297,7 +297,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
         loadConstant(cUnit, r0, typeIdx);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
         skipTarget->defMask = ENCODE_ALL;
         branchOver->generic.target = (LIR*)skipTarget;
@@ -332,7 +332,7 @@
         loadWordDisp(cUnit, rSELF, funcOffset, rLR);
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
         loadCurrMethodDirect(cUnit, r1);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         RegLocation rlResult = oatGetReturn(cUnit);
         storeValue(cUnit, rlDest, rlResult);
     } else {
@@ -360,7 +360,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeStaticStorage), rLR);
         loadConstant(cUnit, r0, typeIdx);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         ArmLIR* skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
         skipTarget->defMask = ENCODE_ALL;
         branchOver->generic.target = (LIR*)skipTarget;
@@ -491,7 +491,7 @@
             loadWordDisp(cUnit, rSELF,
                          OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
             loadConstant(cUnit, r1, dInsn->vB);
-            newLIR1(cUnit, kThumbBlxR, rLR);
+            callUnwindableHelper(cUnit, rLR);
             genUnconditionalBranch(cUnit, rollback);
             // Resume normal slow path
             skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -658,7 +658,7 @@
             loadWordDisp(cUnit, rSELF,
                          OFFSETOF_MEMBER(Thread, pResolveMethodFromCode), rLR);
             loadConstant(cUnit, r1, dInsn->vB);
-            newLIR1(cUnit, kThumbBlxR, rLR);
+            callUnwindableHelper(cUnit, rLR);
             genUnconditionalBranch(cUnit, rollback);
             // Resume normal slow path
             skipTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -686,7 +686,8 @@
                 tReg = oatAllocTemp(cUnit);
                 loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
                              tReg);
-                genBoundsCheck(cUnit, tReg, rLR, mir, kArmThrowNoSuchMethod);
+                genRegRegCheck(cUnit, kArmCondCs, tReg, rLR, mir,
+                               kArmThrowNoSuchMethod);
                 oatFreeTemp(cUnit, tReg);
             }
             // Adjust vtable_ base past object header
@@ -731,7 +732,10 @@
      */
     for (unsigned int i=3; i < dInsn->vA; i++) {
         int reg;
-        rlArg = oatUpdateLoc(cUnit, oatGetSrc(cUnit, mir, i));
+        // Treating args as untyped 32-bit chunks
+        rlArg = oatGetRawSrc(cUnit, mir, i);
+        rlArg.wide = false;
+        rlArg = oatUpdateLoc(cUnit, rlArg);
         if (rlArg.location == kLocPhysReg) {
             reg = rlArg.lowReg;
         } else {
@@ -838,7 +842,7 @@
         opRegRegImm(cUnit, kOpAdd, r1, rSP, outsOffset);
         loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pMemcpy), rLR);
         loadConstant(cUnit, r2, (numArgs - 3) * 4);
-        newLIR1(cUnit, kThumbBlxR, rLR);
+        callNoUnwindHelper(cUnit, rLR);
     } else {
         // Use vldm/vstm pair using r3 as a temp
         int regsLeft = std::min(numArgs - 3, 16);
@@ -908,7 +912,7 @@
 #ifdef DISPLAY_MISSING_TARGETS
     genShowTarget(cUnit);
 #endif
-    newLIR1(cUnit, kThumbBlxR, rLR);
+    opReg(cUnit, kOpBlx, rLR);
 }
 
 /*
@@ -939,7 +943,7 @@
 #ifdef DISPLAY_MISSING_TARGETS
     genShowTarget(cUnit);
 #endif
-    newLIR1(cUnit, kThumbBlxR, rLR);
+    opReg(cUnit, kOpBlx, rLR);
 }
 
 static void genInvokeSuper(CompilationUnit* cUnit, MIR* mir)
@@ -991,7 +995,7 @@
 #ifdef DISPLAY_MISSING_TARGETS
     genShowTarget(cUnit);
 #endif
-    newLIR1(cUnit, kThumbBlxR, rLR);
+    opReg(cUnit, kOpBlx, rLR);
 }
 
 static void genInvokeVirtual(CompilationUnit* cUnit, MIR* mir)
@@ -1030,7 +1034,7 @@
 #ifdef DISPLAY_MISSING_TARGETS
     genShowTarget(cUnit);
 #endif
-    newLIR1(cUnit, kThumbBlxR, rLR);
+    opReg(cUnit, kOpBlx, rLR);
 }
 
 static bool compileDalvikInstruction(CompilationUnit* cUnit, MIR* mir,
@@ -1218,7 +1222,7 @@
                 OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
             loadConstant(cUnit, r0, mir->dalvikInsn.vA);
             loadConstant(cUnit, r1, mir->dalvikInsn.vB);
-            opReg(cUnit, kOpBlx, rLR);
+            callUnwindableHelper(cUnit, rLR);
             break;
 
         case OP_ARRAY_LENGTH:
@@ -1839,14 +1843,8 @@
         if (!skipOverflowCheck) {
             opRegRegImm(cUnit, kOpSub, rLR, rSP,
                         cUnit->frameSize - (cUnit->numSpills * 4));
-            opRegReg(cUnit, kOpCmp, rLR, r12);   // Stack overflow?
-            /* Begin conditional skip */
-            genIT(cUnit, kArmCondCc, "TT"); // Carry clear; unsigned <
-            loadWordDisp(cUnit, rSELF,
-                         OFFSETOF_MEMBER(Thread, pStackOverflowFromCode), rLR);
-            newLIR2(cUnit, kThumbAddRI8, rSP, cUnit->numSpills * 4);
-            opReg(cUnit, kOpBlx, rLR);
-            /* End conditional skip */
+            genRegRegCheck(cUnit, kArmCondCc, rLR, r12, NULL,
+                           kArmThrowStackOverflow);
             genRegCopy(cUnit, rSP, rLR);         // Establish stack
         } else {
             opRegImm(cUnit, kOpSub, rSP,
@@ -2054,11 +2052,17 @@
                 funcOffset =
                     OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
                 break;
+            case kArmThrowStackOverflow:
+                funcOffset =
+                    OFFSETOF_MEMBER(Thread, pStackOverflowFromCode);
+                // Restore stack alignment
+                opRegImm(cUnit, kOpAdd, rSP, cUnit->numSpills * 4);
+                break;
             default:
                 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
         }
         loadWordDisp(cUnit, rSELF, funcOffset, rLR);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
     }
 }
 
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 1ce7394..db4dd09 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -55,6 +55,23 @@
 }
 #endif
 
+/*
+ * If a helper routine might need to unwind, let it know the top
+ * of the managed stack.
+ */
+static ArmLIR* callUnwindableHelper(CompilationUnit* cUnit, int reg)
+{
+    // Starting point for managed traceback if we throw
+    storeWordDisp(cUnit, rSELF,
+                  art::Thread::TopOfManagedStackOffset().Int32Value(), rSP);
+    return opReg(cUnit, kOpBlx, reg);
+}
+
+static ArmLIR* callNoUnwindHelper(CompilationUnit* cUnit, int reg)
+{
+    return opReg(cUnit, kOpBlx, reg);
+}
+
 /* Generate unconditional branch instructions */
 static ArmLIR* genUnconditionalBranch(CompilationUnit* cUnit, ArmLIR* target)
 {
@@ -367,7 +384,7 @@
                  OFFSETOF_MEMBER(Thread, pHandleFillArrayDataFromCode), rLR);
     // Materialize a pointer to the fill data image
     newLIR3(cUnit, kThumb2AdrST, r1, 0, (intptr_t)tabRec);
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
 }
 
@@ -420,7 +437,7 @@
     loadWordDisp(cUnit, rSELF,
                  OFFSETOF_MEMBER(Thread, pFindFieldFromCode), rLR);
     loadConstant(cUnit, r0, fieldIdx);
-    opReg(cUnit, kOpBlx, rLR); // resolveTypeFromCode(idx, method)
+    callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
     target->defMask = ENCODE_ALL;
 #ifndef EXERCISE_SLOWEST_FIELD_PATH
@@ -615,7 +632,7 @@
                      OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
         genRegCopy(cUnit, r1, mReg);
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
-        opReg(cUnit, kOpBlx, rLR); // resolveTypeFromCode(idx, method)
+        callUnwindableHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
         RegLocation rlResult = oatGetReturn(cUnit);
         storeValue(cUnit, rlDest, rlResult);
@@ -657,7 +674,7 @@
                  OFFSETOF_MEMBER(Thread, pAllocObjectFromCode), rLR);
     loadCurrMethodDirect(cUnit, r1);              // arg1 <= Method*
     loadConstant(cUnit, r0, mir->dalvikInsn.vB);  // arg0 <- type_id
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     RegLocation rlResult = oatGetReturn(cUnit);
     storeValue(cUnit, rlDest, rlResult);
@@ -669,7 +686,7 @@
                  OFFSETOF_MEMBER(Thread, pThrowException), rLR);
     loadValueDirectFixed(cUnit, rlSrc, r1);  // Get exception object
     genRegCopy(cUnit, r0, rSELF);
-    opReg(cUnit, kOpBlx, rLR); // artThrowException(thread, exception);
+    callUnwindableHelper(cUnit, rLR); // artThrowException(thread, exception);
 }
 
 static void genInstanceof(CompilationUnit* cUnit, MIR* mir, RegLocation rlDest,
@@ -693,7 +710,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
         loadConstant(cUnit, r0, mir->dalvikInsn.vC);
-        opReg(cUnit, kOpBlx, rLR); // resolveTypeFromCode(idx, method)
+        callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
         genRegCopy(cUnit, r2, r0); // Align usage with fast path
         // Rejoin code paths
         ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -715,7 +732,7 @@
     ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq);
     genRegCopy(cUnit, r0, r3);
     genRegCopy(cUnit, r1, r2);
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     /* branch target here */
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -746,7 +763,7 @@
         loadWordDisp(cUnit, rSELF,
                      OFFSETOF_MEMBER(Thread, pInitializeTypeFromCode), rLR);
         loadConstant(cUnit, r0, mir->dalvikInsn.vB);
-        opReg(cUnit, kOpBlx, rLR); // resolveTypeFromCode(idx, method)
+        callUnwindableHelper(cUnit, rLR); // resolveTypeFromCode(idx, method)
         genRegCopy(cUnit, r2, r0); // Align usage with fast path
         // Rejoin code paths
         ArmLIR* hopTarget = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -767,7 +784,7 @@
     ArmLIR* branch2 = opCondBranch(cUnit, kArmCondEq); /* If equal, trivial yes */
     genRegCopy(cUnit, r0, r1);
     genRegCopy(cUnit, r1, r2);
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     /* branch target here */
     ArmLIR* target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -936,7 +953,7 @@
     loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pLockObjectFromCode),
                  rLR);
     genRegCopy(cUnit, r0, rSELF);
-    newLIR1(cUnit, kThumbBlxR, rLR);
+    callUnwindableHelper(cUnit, rLR);
 
     // Resume here
     target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -986,7 +1003,7 @@
     loadWordDisp(cUnit, rSELF, OFFSETOF_MEMBER(Thread, pUnlockObjectFromCode),
                  rLR);
     genRegCopy(cUnit, r0, rSELF);
-    newLIR1(cUnit, kThumbBlxR, rLR);
+    callUnwindableHelper(cUnit, rLR);
 
     // Resume here
     target = newLIR0(cUnit, kArmPseudoTargetLabel);
@@ -1074,7 +1091,7 @@
         rlSrc = oatGetSrcWide(cUnit, mir, 0, 1);
         loadValueDirectWideFixed(cUnit, rlSrc, r0, r1);
     }
-    opReg(cUnit, kOpBlx, rLR);
+    callNoUnwindHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     if (tgtSize == 1) {
         RegLocation rlResult;
@@ -1129,7 +1146,7 @@
     loadWordDisp(cUnit, rSELF, funcOffset, rLR);
     loadValueDirectFixed(cUnit, rlSrc1, r0);
     loadValueDirectFixed(cUnit, rlSrc2, r1);
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     rlResult = oatGetReturn(cUnit);
     storeValue(cUnit, rlDest, rlResult);
@@ -1175,7 +1192,7 @@
     loadWordDisp(cUnit, rSELF, funcOffset, rLR);
     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
     loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     rlResult = oatGetReturnWide(cUnit);
     storeValueWide(cUnit, rlDest, rlResult);
@@ -1261,7 +1278,7 @@
     loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), r1);
     /* Get the object's clazz */
     loadWordDisp(cUnit, r0, Object::ClassOffset().Int32Value(), r0);
-    opReg(cUnit, kOpBlx, rLR);
+    callUnwindableHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
 
     // Now, redo loadValues in case they didn't survive the call
@@ -1285,7 +1302,7 @@
         loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
         /* regPtr -> array data */
         opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
-        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir,
+        genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
                        kArmThrowArrayBounds);
         oatFreeTemp(cUnit, regLen);
     } else {
@@ -1328,7 +1345,7 @@
         loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
         /* regPtr -> array data */
         opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
-        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir,
+        genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
                        kArmThrowArrayBounds);
         oatFreeTemp(cUnit, regLen);
     } else {
@@ -1401,7 +1418,7 @@
         loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
         /* regPtr -> array data */
         opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
-        genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir,
+        genRegRegCheck(cUnit, kArmCondCs, rlIndex.lowReg, regLen, mir,
                        kArmThrowArrayBounds);
         oatFreeTemp(cUnit, regLen);
     } else {
@@ -1459,7 +1476,7 @@
     loadWordDisp(cUnit, rSELF, funcOffset, rLR);
     loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
     loadValueDirect(cUnit, rlShift, r2);
-    opReg(cUnit, kOpBlx, rLR);
+    callNoUnwindHelper(cUnit, rLR);
     oatClobberCallRegs(cUnit);
     RegLocation rlResult = oatGetReturnWide(cUnit);
     storeValueWide(cUnit, rlDest, rlResult);
@@ -1554,7 +1571,7 @@
         loadWordDisp(cUnit, rSELF, funcOffset, rLR);
         loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
         loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
         if (retReg == r0)
             rlResult = oatGetReturnWide(cUnit);
@@ -1676,7 +1693,7 @@
         if (checkZero) {
             genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
         }
-        opReg(cUnit, kOpBlx, rLR);
+        callUnwindableHelper(cUnit, rLR);
         oatClobberCallRegs(cUnit);
         if (retReg == r0)
             rlResult = oatGetReturn(cUnit);
@@ -1701,7 +1718,7 @@
     genRegCopy(cUnit, r0, rSELF);
     opRegImm(cUnit, kOpCmp, rSuspendCount, 0);
     genIT(cUnit, kArmCondNe, "");
-    opReg(cUnit, kOpBlx, rLR); // CheckSuspendFromCode(self)
+    callUnwindableHelper(cUnit, rLR); // CheckSuspendFromCode(self)
     oatFreeCallTemps(cUnit);
 }
 
@@ -1925,7 +1942,7 @@
             }
             loadWordDisp(cUnit, rSELF, funcOffset, rLR);
             loadConstant(cUnit, r1, lit);
-            opReg(cUnit, kOpBlx, rLR);
+            callUnwindableHelper(cUnit, rLR);
             oatClobberCallRegs(cUnit);
             if (isDiv)
                 rlResult = oatGetReturn(cUnit);