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/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc
index c876b3a..d5b34a5 100644
--- a/compiler/dex/quick/arm/int_arm.cc
+++ b/compiler/dex/quick/arm/int_arm.cc
@@ -1167,9 +1167,9 @@
if (needs_range_check) {
if (constant_index) {
- GenImmedCheck(kCondLs, reg_len, mir_graph_->ConstantValue(rl_index), kThrowConstantArrayBounds);
+ GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
} else {
- GenRegRegCheck(kCondLs, reg_len, rl_index.reg, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, reg_len);
}
FreeTemp(reg_len);
}
@@ -1196,7 +1196,7 @@
rl_result = EvalLoc(rl_dest, reg_class, true);
if (needs_range_check) {
- GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, reg_len);
FreeTemp(reg_len);
}
LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
@@ -1271,9 +1271,9 @@
}
if (needs_range_check) {
if (constant_index) {
- GenImmedCheck(kCondLs, reg_len, mir_graph_->ConstantValue(rl_index), kThrowConstantArrayBounds);
+ GenArrayBoundsCheck(mir_graph_->ConstantValue(rl_index), reg_len);
} else {
- GenRegRegCheck(kCondLs, reg_len, rl_index.reg, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, reg_len);
}
FreeTemp(reg_len);
}
@@ -1289,7 +1289,7 @@
OpRegRegImm(kOpAdd, reg_ptr, rl_array.reg, data_offset);
rl_src = LoadValue(rl_src, reg_class);
if (needs_range_check) {
- GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, reg_len);
FreeTemp(reg_len);
}
StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
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 =
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 4aae16d..758096b 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -255,12 +255,27 @@
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
+void Mir2Lir::CopyToArgumentRegs(RegStorage arg0, RegStorage arg1) {
+ if (arg1.GetReg() == TargetReg(kArg0).GetReg()) {
+ if (arg0.GetReg() == TargetReg(kArg1).GetReg()) {
+ // Swap kArg0 and kArg1 with kArg2 as temp.
+ OpRegCopy(TargetReg(kArg2), arg1);
+ OpRegCopy(TargetReg(kArg0), arg0);
+ OpRegCopy(TargetReg(kArg1), TargetReg(kArg2));
+ } else {
+ OpRegCopy(TargetReg(kArg1), arg1);
+ OpRegCopy(TargetReg(kArg0), arg0);
+ }
+ } else {
+ OpRegCopy(TargetReg(kArg0), arg0);
+ OpRegCopy(TargetReg(kArg1), arg1);
+ }
+}
+
void Mir2Lir::CallRuntimeHelperRegReg(ThreadOffset<4> helper_offset, RegStorage arg0,
RegStorage arg1, bool safepoint_pc) {
RegStorage r_tgt = CallHelperSetup(helper_offset);
- DCHECK_NE(TargetReg(kArg0).GetReg(), arg1.GetReg()); // check copy into arg0 won't clobber arg1
- OpRegCopy(TargetReg(kArg0), arg0);
- OpRegCopy(TargetReg(kArg1), arg1);
+ CopyToArgumentRegs(arg0, arg1);
ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
}
@@ -268,9 +283,7 @@
void Mir2Lir::CallRuntimeHelperRegRegImm(ThreadOffset<4> helper_offset, RegStorage arg0,
RegStorage arg1, int arg2, bool safepoint_pc) {
RegStorage r_tgt = CallHelperSetup(helper_offset);
- DCHECK_NE(TargetReg(kArg0).GetReg(), arg1.GetReg()); // check copy into arg0 won't clobber arg1
- OpRegCopy(TargetReg(kArg0), arg0);
- OpRegCopy(TargetReg(kArg1), arg1);
+ CopyToArgumentRegs(arg0, arg1);
LoadConstant(TargetReg(kArg2), arg2);
ClobberCallerSave();
CallHelper(r_tgt, helper_offset, safepoint_pc);
diff --git a/compiler/dex/quick/mips/int_mips.cc b/compiler/dex/quick/mips/int_mips.cc
index 60358b4..2375720 100644
--- a/compiler/dex/quick/mips/int_mips.cc
+++ b/compiler/dex/quick/mips/int_mips.cc
@@ -513,7 +513,7 @@
rl_result = EvalLoc(rl_dest, reg_class, true);
if (needs_range_check) {
- GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, reg_len);
FreeTemp(reg_len);
}
LoadBaseDispWide(reg_ptr, 0, rl_result.reg, INVALID_SREG);
@@ -524,7 +524,7 @@
rl_result = EvalLoc(rl_dest, reg_class, true);
if (needs_range_check) {
- GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, reg_len);
FreeTemp(reg_len);
}
LoadBaseIndexed(reg_ptr, rl_index.reg, rl_result.reg, scale, size);
@@ -590,7 +590,7 @@
rl_src = LoadValueWide(rl_src, reg_class);
if (needs_range_check) {
- GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, reg_len);
FreeTemp(reg_len);
}
@@ -598,7 +598,7 @@
} else {
rl_src = LoadValue(rl_src, reg_class);
if (needs_range_check) {
- GenRegRegCheck(kCondUge, rl_index.reg, reg_len, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, reg_len);
FreeTemp(reg_len);
}
StoreBaseIndexed(reg_ptr, rl_index.reg, rl_src.reg, scale, size);
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 65910e9..1f69eb5 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -567,6 +567,8 @@
void GenDivZeroCheck(ConditionCode c_code);
// reg holds divisor.
void GenDivZeroCheck(RegStorage reg);
+ void GenArrayBoundsCheck(RegStorage index, RegStorage length);
+ void GenArrayBoundsCheck(int32_t index, RegStorage length);
LIR* GenNullCheck(RegStorage reg);
void MarkPossibleNullPointerException(int opt_flags);
void MarkPossibleStackOverflowException();
@@ -1227,6 +1229,10 @@
void AddDivZeroCheckSlowPath(LIR* branch);
+ // Copy arg0 and arg1 to kArg0 and kArg1 safely, possibly using
+ // kArg2 as temp.
+ void CopyToArgumentRegs(RegStorage arg0, RegStorage arg1);
+
public:
// TODO: add accessors for these.
LIR* literal_list_; // Constants.
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 0b9823d..b802591 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -136,6 +136,8 @@
RegLocation GenDivRemLit(RegLocation rl_dest, RegStorage reg_lo, int lit, bool is_div);
void GenCmpLong(RegLocation rl_dest, RegLocation rl_src1, RegLocation rl_src2);
void GenDivZeroCheckWide(RegStorage reg);
+ void GenArrayBoundsCheck(RegStorage index, RegStorage array_base, int32_t len_offset);
+ void GenArrayBoundsCheck(int32_t index, RegStorage array_base, int32_t len_offset);
void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
void GenExitSequence();
void GenSpecialExitSequence();
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 4ffb9a4..84325b4 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -891,6 +891,86 @@
FreeTemp(t_reg);
}
+void X86Mir2Lir::GenArrayBoundsCheck(RegStorage index,
+ RegStorage array_base,
+ int len_offset) {
+ class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
+ public:
+ ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch,
+ RegStorage index, RegStorage array_base, int32_t len_offset)
+ : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
+ index_(index), array_base_(array_base), len_offset_(len_offset) {
+ }
+
+ void Compile() OVERRIDE {
+ m2l_->ResetRegPool();
+ m2l_->ResetDefTracking();
+ GenerateTargetLabel();
+
+ RegStorage new_index = index_;
+ // Move index out of kArg1, either directly to kArg0, or to kArg2.
+ if (index_.GetReg() == m2l_->TargetReg(kArg1).GetReg()) {
+ if (array_base_.GetReg() == m2l_->TargetReg(kArg0).GetReg()) {
+ m2l_->OpRegCopy(m2l_->TargetReg(kArg2), index_);
+ new_index = m2l_->TargetReg(kArg2);
+ } else {
+ m2l_->OpRegCopy(m2l_->TargetReg(kArg0), index_);
+ new_index = m2l_->TargetReg(kArg0);
+ }
+ }
+ // Load array length to kArg1.
+ m2l_->OpRegMem(kOpMov, m2l_->TargetReg(kArg1), array_base_, len_offset_);
+ m2l_->CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(4, pThrowArrayBounds),
+ new_index, m2l_->TargetReg(kArg1), true);
+ }
+
+ private:
+ const RegStorage index_;
+ const RegStorage array_base_;
+ const int32_t len_offset_;
+ };
+
+ OpRegMem(kOpCmp, index, array_base, len_offset);
+ LIR* branch = OpCondBranch(kCondUge, nullptr);
+ AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch,
+ index, array_base, len_offset));
+}
+
+void X86Mir2Lir::GenArrayBoundsCheck(int32_t index,
+ RegStorage array_base,
+ int32_t len_offset) {
+ class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath {
+ public:
+ ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch,
+ int32_t index, RegStorage array_base, int32_t len_offset)
+ : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch),
+ index_(index), array_base_(array_base), len_offset_(len_offset) {
+ }
+
+ void Compile() OVERRIDE {
+ m2l_->ResetRegPool();
+ m2l_->ResetDefTracking();
+ GenerateTargetLabel();
+
+ // Load array length to kArg1.
+ m2l_->OpRegMem(kOpMov, m2l_->TargetReg(kArg1), array_base_, len_offset_);
+ 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 array_base_;
+ const int32_t len_offset_;
+ };
+
+ NewLIR3(IS_SIMM8(index) ? kX86Cmp32MI8 : kX86Cmp32MI, array_base.GetReg(), len_offset, index);
+ LIR* branch = OpCondBranch(kCondLs, nullptr);
+ AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch,
+ index, array_base, len_offset));
+}
+
// Test suspend flag, return target of taken suspend branch
LIR* X86Mir2Lir::OpTestSuspend(LIR* target) {
OpTlsCmp(Thread::ThreadFlagsOffset<4>(), 0);
@@ -1348,10 +1428,9 @@
if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
if (constant_index) {
- GenMemImmedCheck(kCondLs, rl_array.reg, len_offset,
- constant_index_value, kThrowConstantArrayBounds);
+ GenArrayBoundsCheck(constant_index_value, rl_array.reg, len_offset);
} else {
- GenRegMemCheck(kCondUge, rl_index.reg, rl_array.reg, len_offset, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, rl_array.reg, len_offset);
}
}
rl_result = EvalLoc(rl_dest, reg_class, true);
@@ -1400,10 +1479,9 @@
if (!(opt_flags & MIR_IGNORE_RANGE_CHECK)) {
if (constant_index) {
- GenMemImmedCheck(kCondLs, rl_array.reg, len_offset,
- constant_index_value, kThrowConstantArrayBounds);
+ GenArrayBoundsCheck(constant_index_value, rl_array.reg, len_offset);
} else {
- GenRegMemCheck(kCondUge, rl_index.reg, rl_array.reg, len_offset, kThrowArrayBounds);
+ GenArrayBoundsCheck(rl_index.reg, rl_array.reg, len_offset);
}
}
if ((size == kLong) || (size == kDouble)) {