Missing zero-checks in JIT compiler

Zero-checks were not generated by the JIT compiler for
some instructions. This caused crashes instead of
the expected ArithmeticException.

Change-Id: Ic8041741a7cccc1bd6b8c3c0723ba55a55af856b
diff --git a/tests/083-jit-regressions/expected.txt b/tests/083-jit-regressions/expected.txt
index 4b9ad5b..7f9f14c 100644
--- a/tests/083-jit-regressions/expected.txt
+++ b/tests/083-jit-regressions/expected.txt
@@ -2,3 +2,5 @@
 b2302318 passes
 b2487514 passes
 b5884080 passes
+longDivTest passes
+longModTest passes
diff --git a/tests/083-jit-regressions/src/Main.java b/tests/083-jit-regressions/src/Main.java
index 3b596db..68bfa37 100644
--- a/tests/083-jit-regressions/src/Main.java
+++ b/tests/083-jit-regressions/src/Main.java
@@ -25,6 +25,7 @@
         b2302318Test();
         b2487514Test();
         b5884080Test();
+        zeroTest();
     }
 
     static void b2296099Test() throws Exception {
@@ -111,13 +112,12 @@
         int vA = 1;
 
         int l = 0;
-        do
-        {
+        do {
             int k = 0;
             do
                 vA += 1;
             while(++k < 100);
-        } while(++l < 1000);
+        } while (++l < 1000);
         if (vA == 100001) {
             System.out.println("b5884080 passes");
         }
@@ -126,6 +126,20 @@
                                " (expecting 100001)");
         }
     }
+
+    static void zeroTest() throws Exception {
+        ZeroTests zt = new ZeroTests();
+        try {
+            zt.longDivTest();
+        } catch (Throwable th) {
+            th.printStackTrace();
+        }
+        try {
+            zt.longModTest();
+        } catch (Throwable th) {
+            th.printStackTrace();
+        }
+    }
 }
 
 class SpinThread extends Thread {
diff --git a/tests/083-jit-regressions/src/ZeroTests.java b/tests/083-jit-regressions/src/ZeroTests.java
new file mode 100644
index 0000000..57ca151
--- /dev/null
+++ b/tests/083-jit-regressions/src/ZeroTests.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.Random;
+
+/**
+ * Tests long division by zero for both / and %.
+ */
+public class ZeroTests {
+    public void longDivTest() throws Exception {
+      longTest("longDivTest", true);
+    }
+
+    public void longModTest() throws Exception {
+      longTest("longModTest", false);
+    }
+
+    private static void longTest(String name, boolean divide) throws Exception {
+      // Warm up JIT.
+      for (int i = 0; i < 10000; ++i) {
+        try {
+          // We won't JIT code that hasn't completed successfully, so rhs can't be 0 here!
+          if (divide) {
+            longDiv(1, 1);
+          } else {
+            longMod(1, 1);
+          }
+        } catch (ArithmeticException expected) {
+          throw new AssertionError(name + " threw during warmup");
+        }
+      }
+
+      // Boom?
+      int catchCount = 0;
+      for (int i = 0; i < 10000; ++i) {
+        try {
+          if (divide) {
+            longDiv(1, 0);
+          } else {
+            longMod(1, 0);
+          }
+          throw new AssertionError(name + " failed to throw: " + i);
+        } catch (ArithmeticException expected) {
+          ++catchCount;
+        }
+      }
+      if (catchCount != 10000) throw new AssertionError(name + " failed: " + catchCount);
+
+      System.out.println(name + " passes");
+    }
+
+    private static long longDiv(long lhs, long rhs) {
+      return lhs / rhs;
+    }
+
+    private static long longMod(long lhs, long rhs) {
+      return lhs % rhs;
+    }
+}
diff --git a/tests/etc/host-run-test-jar b/tests/etc/host-run-test-jar
index d3c0fd5..ab7278e 100755
--- a/tests/etc/host-run-test-jar
+++ b/tests/etc/host-run-test-jar
@@ -78,7 +78,7 @@
 done
 
 if [ "x$INTERP" = "x" ]; then
-    INTERP="fast"
+    INTERP="fast" # TODO: change this to "jit" when the x86 jit is merged.
     msg "Using fast interpreter by default"
 fi
 
diff --git a/tests/etc/push-and-run-test-jar b/tests/etc/push-and-run-test-jar
index e2fde42..b64f6a6 100755
--- a/tests/etc/push-and-run-test-jar
+++ b/tests/etc/push-and-run-test-jar
@@ -78,8 +78,8 @@
 
 if [ "$ZYGOTE" = "n" ]; then
     if [ "x$INTERP" = "x" ]; then
-        INTERP="fast"
-        msg "Using fast interpreter by default"
+        INTERP="jit"
+        msg "Using jit by default"
     fi
 
     if [ "$OPTIMIZE" = "y" ]; then
diff --git a/tests/run-test b/tests/run-test
index fb758d7..406e424 100755
--- a/tests/run-test
+++ b/tests/run-test
@@ -146,8 +146,8 @@
         echo '  Omitting the test name or specifying "-" will use the' \
              "current directory."
         echo "  Runtime Options:"
-        echo "    --fast         Use the fast interpreter (the default)."
-        echo "    --jit          Use the jit."
+        echo "    --fast         Use the fast interpreter."
+        echo "    --jit          Use the jit (the default)."
         echo "    --portable     Use the portable interpreter."
         echo "    --debug        Wait for a debugger to attach."
         #echo "    --gdb          Run under gdb; incompatible with some tests."
diff --git a/vm/compiler/codegen/arm/CodegenDriver.cpp b/vm/compiler/codegen/arm/CodegenDriver.cpp
index d7017b0..d96aa65 100644
--- a/vm/compiler/codegen/arm/CodegenDriver.cpp
+++ b/vm/compiler/codegen/arm/CodegenDriver.cpp
@@ -670,6 +670,7 @@
     OpKind firstOp = kOpBkpt;
     OpKind secondOp = kOpBkpt;
     bool callOut = false;
+    bool checkZero = false;
     void *callTgt;
     int retReg = r0;
 
@@ -700,6 +701,7 @@
         case OP_DIV_LONG_2ADDR:
             callOut = true;
             retReg = r0;
+            checkZero = true;
             callTgt = (void*)__aeabi_ldivmod;
             break;
         /* NOTE - result is in r2/r3 instead of r0/r1 */
@@ -708,6 +710,7 @@
             callOut = true;
             callTgt = (void*)__aeabi_ldivmod;
             retReg = r2;
+            checkZero = true;
             break;
         case OP_AND_LONG_2ADDR:
         case OP_AND_LONG:
@@ -746,9 +749,14 @@
     } else {
         // Adjust return regs in to handle case of rem returning r2/r3
         dvmCompilerFlushAllRegs(cUnit);   /* Send everything to home location */
+        loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
         loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
         LOAD_FUNC_ADDR(cUnit, r14lr, (int) callTgt);
-        loadValueDirectWideFixed(cUnit, rlSrc2, r2, r3);
+        if (checkZero) {
+            int tReg = r12; // Using fixed registers during call sequence
+            opRegRegReg(cUnit, kOpOr, tReg, r2, r3);
+            genRegImmCheck(cUnit, kArmCondEq, tReg, 0, mir->offset, NULL);
+        }
         opReg(cUnit, kOpBlx, r14lr);
         dvmCompilerClobberCallRegs(cUnit);
         if (retReg == r0)