Fix interpreter int/long div/rem.

It didn't handle dividing by zero or dividing min int/long by -1.

Change-Id: Id1d7ea5b05a95f655bd7017ba9e331b2a577e8fa
diff --git a/src/interpreter/interpreter.cc b/src/interpreter/interpreter.cc
index 5c8ccdf..0cbe799 100644
--- a/src/interpreter/interpreter.cc
+++ b/src/interpreter/interpreter.cc
@@ -500,6 +500,54 @@
   }
 }
 
+static void DoIntDivide(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
+    int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const int32_t kMinInt = std::numeric_limits<int32_t>::min();
+  if (UNLIKELY(divisor == 0)) {
+    self->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
+  } else if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
+    shadow_frame.SetVReg(result_reg, kMinInt);
+  } else {
+    shadow_frame.SetVReg(result_reg, dividend / divisor);
+  }
+}
+
+static void DoIntRemainder(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
+    int32_t dividend, int32_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const int32_t kMinInt = std::numeric_limits<int32_t>::min();
+  if (UNLIKELY(divisor == 0)) {
+    self->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
+  } else if (UNLIKELY(dividend == kMinInt && divisor == -1)) {
+    shadow_frame.SetVReg(result_reg, 0);
+  } else {
+    shadow_frame.SetVReg(result_reg, dividend % divisor);
+  }
+}
+
+static void DoLongDivide(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
+    int64_t dividend, int64_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const int32_t kMinLong = std::numeric_limits<int64_t>::min();
+  if (UNLIKELY(divisor == 0)) {
+    self->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
+  } else if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
+    shadow_frame.SetVRegLong(result_reg, kMinLong);
+  } else {
+    shadow_frame.SetVRegLong(result_reg, dividend / divisor);
+  }
+}
+
+static void DoLongRemainder(Thread* self, ShadowFrame& shadow_frame, size_t result_reg,
+    int64_t dividend, int64_t divisor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  const int32_t kMinLong = std::numeric_limits<int64_t>::min();
+  if (UNLIKELY(divisor == 0)) {
+    self->ThrowNewException("Ljava/lang/ArithmeticException;", "divide by zero");
+  } else if (UNLIKELY(dividend == kMinLong && divisor == -1)) {
+    shadow_frame.SetVRegLong(result_reg, 0);
+  } else {
+    shadow_frame.SetVRegLong(result_reg, dividend % divisor);
+  }
+}
+
 static JValue Execute(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                       ShadowFrame& shadow_frame) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   const uint16_t* insns = code_item->insns_;
@@ -1287,12 +1335,12 @@
                              shadow_frame.GetVReg(dec_insn.vB) * shadow_frame.GetVReg(dec_insn.vC));
         break;
       case Instruction::REM_INT:
-        shadow_frame.SetVReg(dec_insn.vA,
-                             shadow_frame.GetVReg(dec_insn.vB) % shadow_frame.GetVReg(dec_insn.vC));
+        DoIntRemainder(self, shadow_frame, dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB),
+                       shadow_frame.GetVReg(dec_insn.vC));
         break;
       case Instruction::DIV_INT:
-        shadow_frame.SetVReg(dec_insn.vA,
-                             shadow_frame.GetVReg(dec_insn.vB) / shadow_frame.GetVReg(dec_insn.vC));
+        DoIntDivide(self, shadow_frame, dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB),
+                    shadow_frame.GetVReg(dec_insn.vC));
         break;
       case Instruction::SHL_INT:
         shadow_frame.SetVReg(dec_insn.vA,
@@ -1335,14 +1383,12 @@
                                  shadow_frame.GetVRegLong(dec_insn.vC));
         break;
       case Instruction::DIV_LONG:
-        shadow_frame.SetVRegLong(dec_insn.vA,
-                                 shadow_frame.GetVRegLong(dec_insn.vB) /
-                                 shadow_frame.GetVRegLong(dec_insn.vC));
+        DoLongDivide(self, shadow_frame, dec_insn.vA, shadow_frame.GetVRegLong(dec_insn.vB),
+                    shadow_frame.GetVRegLong(dec_insn.vC));
         break;
       case Instruction::REM_LONG:
-        shadow_frame.SetVRegLong(dec_insn.vA,
-                                 shadow_frame.GetVRegLong(dec_insn.vB) %
-                                 shadow_frame.GetVRegLong(dec_insn.vC));
+        DoLongRemainder(self, shadow_frame, dec_insn.vA, shadow_frame.GetVRegLong(dec_insn.vB),
+                        shadow_frame.GetVRegLong(dec_insn.vC));
         break;
       case Instruction::AND_LONG:
         shadow_frame.SetVRegLong(dec_insn.vA,
@@ -1437,8 +1483,8 @@
                              shadow_frame.GetVReg(dec_insn.vA) * shadow_frame.GetVReg(dec_insn.vB));
         break;
       case Instruction::REM_INT_2ADDR:
-        shadow_frame.SetVReg(dec_insn.vA,
-                             shadow_frame.GetVReg(dec_insn.vA) % shadow_frame.GetVReg(dec_insn.vB));
+        DoIntRemainder(self, shadow_frame, dec_insn.vA, shadow_frame.GetVReg(dec_insn.vA),
+                       shadow_frame.GetVReg(dec_insn.vB));
         break;
       case Instruction::SHL_INT_2ADDR:
         shadow_frame.SetVReg(dec_insn.vA,
@@ -1466,8 +1512,8 @@
                              shadow_frame.GetVReg(dec_insn.vA) ^ shadow_frame.GetVReg(dec_insn.vB));
         break;
       case Instruction::DIV_INT_2ADDR:
-        shadow_frame.SetVReg(dec_insn.vA,
-                             shadow_frame.GetVReg(dec_insn.vA) / shadow_frame.GetVReg(dec_insn.vB));
+        DoIntDivide(self, shadow_frame, dec_insn.vA, shadow_frame.GetVReg(dec_insn.vA),
+                    shadow_frame.GetVReg(dec_insn.vB));
         break;
       case Instruction::ADD_LONG_2ADDR:
         shadow_frame.SetVRegLong(dec_insn.vA,
@@ -1485,14 +1531,12 @@
                                  shadow_frame.GetVRegLong(dec_insn.vB));
         break;
       case Instruction::DIV_LONG_2ADDR:
-        shadow_frame.SetVRegLong(dec_insn.vA,
-                                 shadow_frame.GetVRegLong(dec_insn.vA) /
-                                 shadow_frame.GetVRegLong(dec_insn.vB));
+        DoLongDivide(self, shadow_frame, dec_insn.vA, shadow_frame.GetVRegLong(dec_insn.vA),
+                    shadow_frame.GetVRegLong(dec_insn.vB));
         break;
       case Instruction::REM_LONG_2ADDR:
-        shadow_frame.SetVRegLong(dec_insn.vA,
-                                 shadow_frame.GetVRegLong(dec_insn.vA) %
-                                 shadow_frame.GetVRegLong(dec_insn.vB));
+        DoLongRemainder(self, shadow_frame, dec_insn.vA, shadow_frame.GetVRegLong(dec_insn.vA),
+                        shadow_frame.GetVRegLong(dec_insn.vB));
         break;
       case Instruction::AND_LONG_2ADDR:
         shadow_frame.SetVRegLong(dec_insn.vA,
@@ -1588,11 +1632,13 @@
         break;
       case Instruction::DIV_INT_LIT16:
       case Instruction::DIV_INT_LIT8:
-        shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) / dec_insn.vC);
+        DoIntDivide(self, shadow_frame, dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB),
+                    dec_insn.vC);
         break;
       case Instruction::REM_INT_LIT16:
       case Instruction::REM_INT_LIT8:
-        shadow_frame.SetVReg(dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB) % dec_insn.vC);
+        DoIntRemainder(self, shadow_frame, dec_insn.vA, shadow_frame.GetVReg(dec_insn.vB),
+                       dec_insn.vC);
         break;
       case Instruction::AND_INT_LIT16:
       case Instruction::AND_INT_LIT8: