Merge "Update exception test with new traceback" into dalvik-dev
diff --git a/src/compiler/codegen/RallocUtil.cc b/src/compiler/codegen/RallocUtil.cc
index 47d5ac0..9df80bd 100644
--- a/src/compiler/codegen/RallocUtil.cc
+++ b/src/compiler/codegen/RallocUtil.cc
@@ -884,6 +884,7 @@
             if (infoLo->pair) {
                 oatClobber(cUnit, infoLo->reg);
                 oatClobber(cUnit, infoLo->partner);
+                oatFreeTemp(cUnit, infoLo->reg);
             } else {
                 loc.lowReg = infoLo->reg;
                 loc.location = kLocPhysReg;
@@ -957,14 +958,16 @@
             DCHECK(!FPREG(loc.lowReg) || ((loc.lowReg & 0x1) == 0));
             return loc;
         }
-        // Can't easily reuse - clobber any overlaps
+        // Can't easily reuse - clobber and free any overlaps
         if (infoLo) {
             oatClobber(cUnit, infoLo->reg);
+            oatFreeTemp(cUnit, infoLo->reg);
             if (infoLo->pair)
                 oatClobber(cUnit, infoLo->partner);
         }
         if (infoHi) {
             oatClobber(cUnit, infoHi->reg);
+            oatFreeTemp(cUnit, infoHi->reg);
             if (infoHi->pair)
                 oatClobber(cUnit, infoHi->partner);
         }
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index ec37876..a68727f 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -51,6 +51,19 @@
 #endif
 }
 
+STATIC ArmLIR* genCheck(CompilationUnit* cUnit, ArmConditionCode cCode,
+                        MIR* mir, ArmThrowKind kind)
+{
+    ArmLIR* tgt = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
+    tgt->opcode = kArmPseudoThrowTarget;
+    tgt->operands[0] = kind;
+    tgt->operands[1] = mir ? mir->offset : 0;
+    ArmLIR* branch = genConditionalBranch(cUnit, cCode, tgt);
+    // Remember branch target - will process later
+    oatInsertGrowableList(&cUnit->throwLaunchpads, (intptr_t)tgt);
+    return branch;
+}
+
 STATIC ArmLIR* genImmedCheck(CompilationUnit* cUnit, ArmConditionCode cCode,
                              int reg, int immVal, MIR* mir, ArmThrowKind kind)
 {
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 8f71571..3b2e986 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -534,7 +534,7 @@
                                    [0000] rm[3..0] */
     kThumb2SubRRI12,     /* sub rd, rn, #imm12 [11110] i [01010] rn[19..16]
                                        [0] imm3[14..12] rd[11..8] imm8[7..0] */
-    kThumb2MvnImmShift,  /* mov(T2) rd, #<const> [11110] i [00011011110]
+    kThumb2MvnImm12,     /* mov(T2) rd, #<const> [11110] i [00011011110]
                                        imm3 rd[11..8] imm8 */
     kThumb2Sel,          /* sel rd, rn, rm [111110101010] rn[19-16] rd[11-8]
                                        rm[3-0] */
@@ -691,6 +691,8 @@
     kThumb2MovImm16HST,  /* Special purpose version for switch table use */
     kThumb2LdmiaWB,      /* ldmia  [111010011001[ rn[19..16] mask[15..0] */
     kThumb2SubsRRI12,    /* setflags encoding */
+    kThumb2OrrRRRs,      /* orrx [111010100101] rn[19..16] [0000] rd[11..8]
+                                   [0000] rm[3..0] */
     kArmLast,
 } ArmOpcode;
 
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index dff9ddd..c42b4b8 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -571,8 +571,8 @@
                  kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1,/* Note: doesn't affect flags */
                  "sub", "!0C,!1C,#!2d", 2),
-    ENCODING_MAP(kThumb2MvnImmShift,  0xf06f0000, /* no setflags encoding */
-                 kFmtBitBlt, 11, 8, kFmtModImm, -1, -1, kFmtUnused, -1, -1,
+    ENCODING_MAP(kThumb2MvnImm12,  0xf06f0000, /* no setflags encoding */
+                 kFmtBitBlt, 11, 8, kFmtImm12, -1, -1, kFmtUnused, -1, -1,
                  kFmtUnused, -1, -1, IS_BINARY_OP | REG_DEF0,
                  "mvn", "!0C, #!1n", 2),
     ENCODING_MAP(kThumb2Sel,       0xfaa0f080,
@@ -955,6 +955,10 @@
                  kFmtUnused, -1, -1,
                  IS_TERTIARY_OP | REG_DEF0_USE1 | SETS_CCODES,
                  "subs", "!0C,!1C,#!2d", 2),
+    ENCODING_MAP(kThumb2OrrRRRs,  0xea500000,
+                 kFmtBitBlt, 11, 8, kFmtBitBlt, 19, 16, kFmtBitBlt, 3, 0,
+                 kFmtShift, -1, -1, IS_QUAD_OP | REG_DEF0_USE12 | SETS_CCODES,
+                 "orrs", "!0C, !1C, !2C!3H", 2),
 
 };
 
@@ -1039,7 +1043,7 @@
              &iterator);
         if (tabRec == NULL) break;
         alignBuffer(cUnit->codeBuffer, tabRec->offset);
-        for (int i = 0; i < (tabRec->size / 2) ; i++) {
+        for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
             cUnit->codeBuffer.push_back( tabRec->table[i]);
         }
     }
diff --git a/src/compiler/codegen/arm/Thumb2/Factory.cc b/src/compiler/codegen/arm/Thumb2/Factory.cc
index c8e428f..3ee23ea 100644
--- a/src/compiler/codegen/arm/Thumb2/Factory.cc
+++ b/src/compiler/codegen/arm/Thumb2/Factory.cc
@@ -163,7 +163,7 @@
     }
     modImm = modifiedImmediate(~value);
     if (modImm >= 0) {
-        res = newLIR2(cUnit, kThumb2MvnImmShift, rDest, modImm);
+        res = newLIR2(cUnit, kThumb2MvnImm12, rDest, modImm);
         return res;
     }
     /* 16-bit immediate? */
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 5ef7687..3f7a7ae 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -460,7 +460,7 @@
         rlObj = loadValue(cUnit, rlObj, kCoreReg);
         rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
         genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
-        loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, size);
+        loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, kWord);
         oatGenMemBarrier(cUnit, kSY);
         storeValue(cUnit, rlDest, rlResult);
     } else {
@@ -474,7 +474,7 @@
         rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
         genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
         loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
-                     size, rlObj.sRegLow);
+                     kWord, rlObj.sRegLow);
         if (isVolatile) {
             oatGenMemBarrier(cUnit, kSY);
         }
@@ -495,7 +495,7 @@
         rlSrc = loadValue(cUnit, rlSrc, regClass);
         genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
         oatGenMemBarrier(cUnit, kSY);
-        storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, size);
+        storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, kWord);
     } else {
 #if ANDROID_SMP != 0
         bool isVolatile = fieldPtr->IsVolatile();
@@ -510,7 +510,7 @@
         if (isVolatile) {
             oatGenMemBarrier(cUnit, kST);
         }
-        storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, size);
+        storeBaseDisp(cUnit, rlObj.lowReg, fieldOffset, rlSrc.lowReg, kWord);
         if (isVolatile) {
             oatGenMemBarrier(cUnit, kSY);
         }
@@ -1498,6 +1498,7 @@
     OpKind firstOp = kOpBkpt;
     OpKind secondOp = kOpBkpt;
     bool callOut = false;
+    bool checkZero = false;
     int funcOffset;
     int retReg = r0;
 
@@ -1538,6 +1539,7 @@
         case OP_DIV_LONG:
         case OP_DIV_LONG_2ADDR:
             callOut = true;
+            checkZero = true;
             retReg = r0;
             funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
             break;
@@ -1545,6 +1547,7 @@
         case OP_REM_LONG:
         case OP_REM_LONG_2ADDR:
             callOut = true;
+            checkZero = true;
             funcOffset = OFFSETOF_MEMBER(Thread, pLdivmod);
             retReg = r2;
             break;
@@ -1592,12 +1595,22 @@
     if (!callOut) {
         genLong3Addr(cUnit, mir, firstOp, secondOp, rlDest, rlSrc1, rlSrc2);
     } else {
-        // Adjust return regs in to handle case of rem returning r2/r3
         oatFlushAllRegs(cUnit);   /* Send everything to home location */
-        loadWordDisp(cUnit, rSELF, funcOffset, rLR);
-        loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
-        loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+        if (checkZero) {
+            loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+            loadWordDisp(cUnit, rSELF, funcOffset, rLR);
+            loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+            int tReg = oatAllocTemp(cUnit);
+            newLIR4(cUnit, kThumb2OrrRRRs, tReg, r2, r3, 0);
+            oatFreeTemp(cUnit, tReg);
+            genCheck(cUnit, kArmCondEq, mir, kArmThrowDivZero);
+        } else {
+            loadWordDisp(cUnit, rSELF, funcOffset, rLR);
+            loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+            loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+        }
         callRuntimeHelper(cUnit, rLR);
+        // Adjust return regs in to handle case of rem returning r2/r3
         if (retReg == r0)
             rlResult = oatGetReturnWide(cUnit);
         else