Revert "Revert "Use LIRSlowPath for throwing ArrayOutOfBoundsException.""

This adds back using LIRSlowPath for ArrayIndexOutOfBoundsException.
And fix the host test crash.

Change-Id: Idbb602f4bb2c5ce59233feb480a0ff1b216e4887
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 1847921..6781a9b 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -91,6 +91,59 @@
   AddSlowPath(new (arena_) DivZeroCheckSlowPath(this, branch));
 }
 
+void Mir2Lir::GenArrayBoundsCheck(RegStorage index, RegStorage length) {
+  class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
+   public:
+    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch, RegStorage index, RegStorage length)
+        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
+          index_(index), length_(length) {
+    }
+
+    void Compile() OVERRIDE {
+      m2l_->ResetRegPool();
+      m2l_->ResetDefTracking();
+      GenerateTargetLabel();
+      m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
+                                    index_, length_, true);
+    }
+
+   private:
+    const RegStorage index_;
+    const RegStorage length_;
+  };
+
+  LIR* branch = OpCmpBranch(kCondUge, index, length, nullptr);
+  AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch, index, length));
+}
+
+void Mir2Lir::GenArrayBoundsCheck(int index, RegStorage length) {
+  class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
+   public:
+    ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch, int index, RegStorage length)
+        : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
+          index_(index), length_(length) {
+    }
+
+    void Compile() OVERRIDE {
+      m2l_->ResetRegPool();
+      m2l_->ResetDefTracking();
+      GenerateTargetLabel();
+
+      m2l_->OpRegCopy(m2l_->TargetReg(kArg1), length_);
+      m2l_->LoadConstant(m2l_->TargetReg(kArg0), index_);
+      m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
+                                    m2l_->TargetReg(kArg0), m2l_->TargetReg(kArg1), true);
+    }
+
+   private:
+    const int32_t index_;
+    const RegStorage length_;
+  };
+
+  LIR* branch = OpCmpImmBranch(kCondLs, length, index, nullptr);
+  AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch, index, length));
+}
+
 LIR* Mir2Lir::GenNullCheck(RegStorage reg) {
   class NullCheckSlowPath : public Mir2Lir::LIRSlowPath {
    public:
@@ -685,58 +738,7 @@
     AppendLIR(lab);
     ThreadOffset<4> func_offset(-1);
     int v1 = lab->operands[2];
-    int v2 = lab->operands[3];
-    const bool target_x86 = cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64;
     switch (lab->operands[0]) {
-      case kThrowConstantArrayBounds:  // v1 is length reg (for Arm/Mips), v2 constant index
-        // v1 holds the constant array index.  Mips/Arm uses v2 for length, x86 reloads.
-        if (target_x86) {
-          OpRegMem(kOpMov, TargetReg(kArg1), RegStorage::Solo32(v1),
-                   mirror::Array::LengthOffset().Int32Value());
-        } else {
-          OpRegCopy(TargetReg(kArg1), RegStorage::Solo32(v1));
-        }
-        // Make sure the following LoadConstant doesn't mess with kArg1.
-        LockTemp(TargetReg(kArg1));
-        LoadConstant(TargetReg(kArg0), v2);
-        func_offset = QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds);
-        break;
-      case kThrowArrayBounds:
-        // Move v1 (array index) to kArg0 and v2 (array length) to kArg1
-        if (v2 != TargetReg(kArg0).GetReg()) {
-          OpRegCopy(TargetReg(kArg0), RegStorage::Solo32(v1));
-          if (target_x86) {
-            // x86 leaves the array pointer in v2, so load the array length that the handler expects
-            OpRegMem(kOpMov, TargetReg(kArg1), RegStorage::Solo32(v2),
-                     mirror::Array::LengthOffset().Int32Value());
-          } else {
-            OpRegCopy(TargetReg(kArg1), RegStorage::Solo32(v2));
-          }
-        } else {
-          if (v1 == TargetReg(kArg1).GetReg()) {
-            // Swap v1 and v2, using kArg2 as a temp
-            OpRegCopy(TargetReg(kArg2), RegStorage::Solo32(v1));
-            if (target_x86) {
-              // x86 leaves the array pointer in v2; load the array length that the handler expects
-              OpRegMem(kOpMov, TargetReg(kArg1), RegStorage::Solo32(v2),
-                       mirror::Array::LengthOffset().Int32Value());
-            } else {
-              OpRegCopy(TargetReg(kArg1), RegStorage::Solo32(v2));
-            }
-            OpRegCopy(TargetReg(kArg0), TargetReg(kArg2));
-          } else {
-            if (target_x86) {
-              // x86 leaves the array pointer in v2; load the array length that the handler expects
-              OpRegMem(kOpMov, TargetReg(kArg1), RegStorage::Solo32(v2),
-                       mirror::Array::LengthOffset().Int32Value());
-            } else {
-              OpRegCopy(TargetReg(kArg1), RegStorage::Solo32(v2));
-            }
-            OpRegCopy(TargetReg(kArg0), RegStorage::Solo32(v1));
-          }
-        }
-        func_offset = QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds);
-        break;
       case kThrowNoSuchMethod:
         OpRegCopy(TargetReg(kArg0), RegStorage::Solo32(v1));
         func_offset =