summaryrefslogtreecommitdiffstats
path: root/compiler/dex
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex')
-rw-r--r--compiler/dex/quick/arm/call_arm.cc8
-rw-r--r--compiler/dex/quick/arm64/call_arm64.cc8
-rw-r--r--compiler/dex/quick/arm64/codegen_arm64.h2
-rw-r--r--compiler/dex/quick/arm64/int_arm64.cc3
-rw-r--r--compiler/dex/quick/arm64/target_arm64.cc2
-rw-r--r--compiler/dex/quick/codegen_util.cc7
-rw-r--r--compiler/dex/quick/gen_common.cc19
-rwxr-xr-xcompiler/dex/quick/gen_invoke.cc42
-rw-r--r--compiler/dex/quick/mir_to_lir.h5
-rw-r--r--compiler/dex/quick/x86/assemble_x86.cc21
-rw-r--r--compiler/dex/quick/x86/call_x86.cc67
-rw-r--r--compiler/dex/quick/x86/codegen_x86.h5
-rwxr-xr-xcompiler/dex/quick/x86/int_x86.cc2
-rwxr-xr-xcompiler/dex/quick/x86/target_x86.cc23
-rw-r--r--compiler/dex/quick/x86/utility_x86.cc22
-rw-r--r--compiler/dex/quick/x86/x86_lir.h1
16 files changed, 156 insertions, 81 deletions
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 04d6898..9d4c6b7 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -190,7 +190,7 @@ void ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) {
null_check_branch = nullptr; // No null check.
} else {
// If the null-check fails its handled by the slow-path to reduce exception related meta-data.
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, NULL);
}
}
@@ -261,7 +261,7 @@ void ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) {
null_check_branch = nullptr; // No null check.
} else {
// If the null-check fails its handled by the slow-path to reduce exception related meta-data.
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
null_check_branch = OpCmpImmBranch(kCondEq, rs_r0, 0, NULL);
}
}
@@ -362,7 +362,7 @@ void ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
Thread::kStackOverflowSignalReservedBytes;
bool large_frame = (static_cast<size_t>(frame_size_) > kStackOverflowReservedUsableBytes);
if (!skip_overflow_check) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
if (!large_frame) {
/* Load stack limit */
LockTemp(rs_r12);
@@ -401,7 +401,7 @@ void ArmMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
const int spill_size = spill_count * 4;
const int frame_size_without_spills = frame_size_ - spill_size;
if (!skip_overflow_check) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
class StackOverflowSlowPath : public LIRSlowPath {
public:
StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, bool restore_lr, size_t sp_displace)
diff --git a/compiler/dex/quick/arm64/call_arm64.cc b/compiler/dex/quick/arm64/call_arm64.cc
index 56dcbe5..d319f53 100644
--- a/compiler/dex/quick/arm64/call_arm64.cc
+++ b/compiler/dex/quick/arm64/call_arm64.cc
@@ -202,7 +202,7 @@ void Arm64Mir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) {
null_check_branch = nullptr; // No null check.
} else {
// If the null-check fails its handled by the slow-path to reduce exception related meta-data.
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
null_check_branch = OpCmpImmBranch(kCondEq, rs_x0, 0, NULL);
}
}
@@ -250,7 +250,7 @@ void Arm64Mir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) {
null_check_branch = nullptr; // No null check.
} else {
// If the null-check fails its handled by the slow-path to reduce exception related meta-data.
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
null_check_branch = OpCmpImmBranch(kCondEq, rs_x0, 0, NULL);
}
}
@@ -338,7 +338,7 @@ void Arm64Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method)
const int frame_size_without_spills = frame_size_ - spill_size;
if (!skip_overflow_check) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
if (!large_frame) {
// Load stack limit
LoadWordDisp(rs_xSELF, Thread::StackEndOffset<8>().Int32Value(), rs_x9);
@@ -371,7 +371,7 @@ void Arm64Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method)
}
if (!skip_overflow_check) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
class StackOverflowSlowPath: public LIRSlowPath {
public:
StackOverflowSlowPath(Mir2Lir* m2l, LIR* branch, size_t sp_displace) :
diff --git a/compiler/dex/quick/arm64/codegen_arm64.h b/compiler/dex/quick/arm64/codegen_arm64.h
index 7d75da9..01d6354 100644
--- a/compiler/dex/quick/arm64/codegen_arm64.h
+++ b/compiler/dex/quick/arm64/codegen_arm64.h
@@ -96,7 +96,7 @@ class Arm64Mir2Lir FINAL : public Mir2Lir {
RegStorage r_src, OpSize size) OVERRIDE;
void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg) OVERRIDE;
LIR* OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
- int offset, int check_value, LIR* target) OVERRIDE;
+ int offset, int check_value, LIR* target, LIR** compare) OVERRIDE;
// Required for target - register utilities.
RegStorage TargetReg(SpecialTargetRegister reg) OVERRIDE;
diff --git a/compiler/dex/quick/arm64/int_arm64.cc b/compiler/dex/quick/arm64/int_arm64.cc
index e8f5cb9..6be66a2 100644
--- a/compiler/dex/quick/arm64/int_arm64.cc
+++ b/compiler/dex/quick/arm64/int_arm64.cc
@@ -163,7 +163,8 @@ LIR* Arm64Mir2Lir::OpCmpImmBranch(ConditionCode cond, RegStorage reg, int check_
LIR* Arm64Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg,
RegStorage base_reg, int offset, int check_value,
- LIR* target) {
+ LIR* target, LIR** compare) {
+ DCHECK(compare == nullptr);
// It is possible that temp register is 64-bit. (ArgReg or RefReg)
// Always compare 32-bit value no matter what temp_reg is.
if (temp_reg.Is64Bit()) {
diff --git a/compiler/dex/quick/arm64/target_arm64.cc b/compiler/dex/quick/arm64/target_arm64.cc
index ef9dbdd..949295d 100644
--- a/compiler/dex/quick/arm64/target_arm64.cc
+++ b/compiler/dex/quick/arm64/target_arm64.cc
@@ -1190,7 +1190,7 @@ int Arm64Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
if (pcrLabel) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
*pcrLabel = GenExplicitNullCheck(TargetReg(kArg1), info->opt_flags);
} else {
*pcrLabel = nullptr;
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 048aca3..95468d2 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1172,9 +1172,12 @@ bool Mir2Lir::BadOverlap(RegLocation rl_src, RegLocation rl_dest) {
}
LIR *Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
- int offset, int check_value, LIR* target) {
+ int offset, int check_value, LIR* target, LIR** compare) {
// Handle this for architectures that can't compare to memory.
- Load32Disp(base_reg, offset, temp_reg);
+ LIR* inst = Load32Disp(base_reg, offset, temp_reg);
+ if (compare != nullptr) {
+ *compare = inst;
+ }
LIR* branch = OpCmpImmBranch(cond, temp_reg, check_value, target);
return branch;
}
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index 6dc019a..b559cf5 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -176,7 +176,7 @@ LIR* Mir2Lir::GenNullCheck(RegStorage reg) {
/* Perform null-check on a register. */
LIR* Mir2Lir::GenNullCheck(RegStorage m_reg, int opt_flags) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
return GenExplicitNullCheck(m_reg, opt_flags);
}
return nullptr;
@@ -191,16 +191,17 @@ LIR* Mir2Lir::GenExplicitNullCheck(RegStorage m_reg, int opt_flags) {
}
void Mir2Lir::MarkPossibleNullPointerException(int opt_flags) {
- if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
return;
}
+ // Insert after last instruction.
MarkSafepointPC(last_lir_insn_);
}
}
void Mir2Lir::MarkPossibleNullPointerExceptionAfter(int opt_flags, LIR* after) {
- if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
return;
}
@@ -209,13 +210,13 @@ void Mir2Lir::MarkPossibleNullPointerExceptionAfter(int opt_flags, LIR* after) {
}
void Mir2Lir::MarkPossibleStackOverflowException() {
- if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitStackOverflowChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
MarkSafepointPC(last_lir_insn_);
}
}
void Mir2Lir::ForceImplicitNullCheck(RegStorage reg, int opt_flags) {
- if (!cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
return;
}
@@ -622,7 +623,7 @@ void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, bool is_long_or_double,
LockTemp(r_tmp);
LIR* uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
mirror::Class::StatusOffset().Int32Value(),
- mirror::Class::kStatusInitialized, NULL);
+ mirror::Class::kStatusInitialized, nullptr, nullptr);
LIR* cont = NewLIR0(kPseudoTargetLabel);
AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont,
@@ -715,7 +716,7 @@ void Mir2Lir::GenSget(MIR* mir, RegLocation rl_dest,
LockTemp(r_tmp);
LIR* uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base,
mirror::Class::StatusOffset().Int32Value(),
- mirror::Class::kStatusInitialized, NULL);
+ mirror::Class::kStatusInitialized, nullptr, nullptr);
LIR* cont = NewLIR0(kPseudoTargetLabel);
AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont,
@@ -2189,7 +2190,7 @@ class SuspendCheckSlowPath : public Mir2Lir::LIRSlowPath {
/* Check if we need to check for pending suspend request */
void Mir2Lir::GenSuspendTest(int opt_flags) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitSuspendChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitSuspendChecks()) {
if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
return;
}
@@ -2209,7 +2210,7 @@ void Mir2Lir::GenSuspendTest(int opt_flags) {
/* Check if we need to check for pending suspend request */
void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitSuspendChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitSuspendChecks()) {
if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) {
OpUnconditionalBranch(target);
return;
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 6c0dfe8..1dbf2ea 100755
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -981,21 +981,35 @@ int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info,
type, skip_this);
if (pcrLabel) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
*pcrLabel = GenExplicitNullCheck(TargetRefReg(kArg1), info->opt_flags);
} else {
*pcrLabel = nullptr;
+ if (!(cu_->disable_opt & (1 << kNullCheckElimination)) &&
+ (info->opt_flags & MIR_IGNORE_NULL_CHECK)) {
+ return call_state;
+ }
// In lieu of generating a check for kArg1 being null, we need to
// perform a load when doing implicit checks.
- RegStorage tmp = AllocTemp();
- Load32Disp(TargetRefReg(kArg1), 0, tmp);
- MarkPossibleNullPointerException(info->opt_flags);
- FreeTemp(tmp);
+ GenImplicitNullCheck(TargetReg(kArg1, false), info->opt_flags);
}
}
return call_state;
}
+// Default implementation of implicit null pointer check.
+// Overridden by arch specific as necessary.
+void Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) {
+ if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
+ return;
+ }
+ RegStorage tmp = AllocTemp();
+ Load32Disp(reg, 0, tmp);
+ MarkPossibleNullPointerException(opt_flags);
+ FreeTemp(tmp);
+}
+
+
/*
* May have 0+ arguments (also used for jumbo). Note that
* source virtual registers may be in physical registers, so may
@@ -1208,16 +1222,17 @@ int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
if (pcrLabel) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
*pcrLabel = GenExplicitNullCheck(TargetRefReg(kArg1), info->opt_flags);
} else {
*pcrLabel = nullptr;
+ if (!(cu_->disable_opt & (1 << kNullCheckElimination)) &&
+ (info->opt_flags & MIR_IGNORE_NULL_CHECK)) {
+ return call_state;
+ }
// In lieu of generating a check for kArg1 being null, we need to
// perform a load when doing implicit checks.
- RegStorage tmp = AllocTemp();
- Load32Disp(TargetRefReg(kArg1), 0, tmp);
- MarkPossibleNullPointerException(info->opt_flags);
- FreeTemp(tmp);
+ GenImplicitNullCheck(TargetReg(kArg1, false), info->opt_flags);
}
}
return call_state;
@@ -1293,11 +1308,14 @@ bool Mir2Lir::GenInlinedCharAt(CallInfo* info) {
// On x86, we can compare to memory directly
// Set up a launch pad to allow retry in case of bounds violation */
if (rl_idx.is_const) {
+ LIR* comparison;
range_check_branch = OpCmpMemImmBranch(
kCondUlt, RegStorage::InvalidReg(), rl_obj.reg, count_offset,
- mir_graph_->ConstantValue(rl_idx.orig_sreg), nullptr);
- } else {
+ mir_graph_->ConstantValue(rl_idx.orig_sreg), nullptr, &comparison);
+ MarkPossibleNullPointerExceptionAfter(0, comparison);
+ } else {
OpRegMem(kOpCmp, rl_idx.reg, rl_obj.reg, count_offset);
+ MarkPossibleNullPointerException(0);
range_check_branch = OpCondBranch(kCondUge, nullptr);
}
}
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 4885501..e93c6e3 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -838,6 +838,7 @@ class Mir2Lir : public Backend {
LIR* GenImmedCheck(ConditionCode c_code, RegStorage reg, int imm_val, ThrowKind kind);
LIR* GenNullCheck(RegStorage m_reg, int opt_flags);
LIR* GenExplicitNullCheck(RegStorage m_reg, int opt_flags);
+ virtual void GenImplicitNullCheck(RegStorage reg, int opt_flags);
void GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1,
RegLocation rl_src2, LIR* taken, LIR* fall_through);
void GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src,
@@ -1147,10 +1148,12 @@ class Mir2Lir : public Backend {
* @param base_reg The register holding the base address.
* @param offset The offset from the base.
* @param check_value The immediate to compare to.
+ * @param target branch target (or nullptr)
+ * @param compare output for getting LIR for comparison (or nullptr)
* @returns The branch instruction that was generated.
*/
virtual LIR* OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
- int offset, int check_value, LIR* target);
+ int offset, int check_value, LIR* target, LIR** compare);
// Required for target - codegen helpers.
virtual bool SmallLiteralDivRem(Instruction::Code dalvik_opcode, bool is_div,
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 8df5b6d..ebe3f0a 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -271,21 +271,22 @@ ENCODING_MAP(Cmp, IS_LOAD, 0, 0,
{ kX86Shrd64RRI, kRegRegImmStore, IS_TERTIARY_OP | REG_DEF0_USE01 | SETS_CCODES, { REX_W, 0, 0x0F, 0xAC, 0, 0, 0, 1, false }, "Shrd64RRI", "!0r,!1r,!2d" },
{ kX86Shrd64MRI, kMemRegImm, IS_QUAD_OP | REG_USE02 | IS_LOAD | IS_STORE | SETS_CCODES, { REX_W, 0, 0x0F, 0xAC, 0, 0, 0, 1, false }, "Shrd64MRI", "[!0r+!1d],!2r,!3d" },
- { kX86Test8RI, kRegImm, IS_BINARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF6, 0, 0, 0, 0, 1, true }, "Test8RI", "!0r,!1d" },
- { kX86Test8MI, kMemImm, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF6, 0, 0, 0, 0, 1, true }, "Test8MI", "[!0r+!1d],!2d" },
- { kX86Test8AI, kArrayImm, IS_LOAD | IS_QUIN_OP | REG_USE01 | SETS_CCODES, { 0, 0, 0xF6, 0, 0, 0, 0, 1, true }, "Test8AI", "[!0r+!1r<<!2d+!3d],!4d" },
- { kX86Test16RI, kRegImm, IS_BINARY_OP | REG_USE0 | SETS_CCODES, { 0x66, 0, 0xF7, 0, 0, 0, 0, 2, false }, "Test16RI", "!0r,!1d" },
- { kX86Test16MI, kMemImm, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { 0x66, 0, 0xF7, 0, 0, 0, 0, 2, false }, "Test16MI", "[!0r+!1d],!2d" },
- { kX86Test16AI, kArrayImm, IS_LOAD | IS_QUIN_OP | REG_USE01 | SETS_CCODES, { 0x66, 0, 0xF7, 0, 0, 0, 0, 2, false }, "Test16AI", "[!0r+!1r<<!2d+!3d],!4d" },
- { kX86Test32RI, kRegImm, IS_BINARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test32RI", "!0r,!1d" },
- { kX86Test32MI, kMemImm, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test32MI", "[!0r+!1d],!2d" },
- { kX86Test32AI, kArrayImm, IS_LOAD | IS_QUIN_OP | REG_USE01 | SETS_CCODES, { 0, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test32AI", "[!0r+!1r<<!2d+!3d],!4d" },
+ { kX86Test8RI, kRegImm, IS_BINARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF6, 0, 0, 0, 0, 1, true }, "Test8RI", "!0r,!1d" },
+ { kX86Test8MI, kMemImm, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF6, 0, 0, 0, 0, 1, true }, "Test8MI", "[!0r+!1d],!2d" },
+ { kX86Test8AI, kArrayImm, IS_LOAD | IS_QUIN_OP | REG_USE01 | SETS_CCODES, { 0, 0, 0xF6, 0, 0, 0, 0, 1, true }, "Test8AI", "[!0r+!1r<<!2d+!3d],!4d" },
+ { kX86Test16RI, kRegImm, IS_BINARY_OP | REG_USE0 | SETS_CCODES, { 0x66, 0, 0xF7, 0, 0, 0, 0, 2, false }, "Test16RI", "!0r,!1d" },
+ { kX86Test16MI, kMemImm, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { 0x66, 0, 0xF7, 0, 0, 0, 0, 2, false }, "Test16MI", "[!0r+!1d],!2d" },
+ { kX86Test16AI, kArrayImm, IS_LOAD | IS_QUIN_OP | REG_USE01 | SETS_CCODES, { 0x66, 0, 0xF7, 0, 0, 0, 0, 2, false }, "Test16AI", "[!0r+!1r<<!2d+!3d],!4d" },
+ { kX86Test32RI, kRegImm, IS_BINARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test32RI", "!0r,!1d" },
+ { kX86Test32MI, kMemImm, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test32MI", "[!0r+!1d],!2d" },
+ { kX86Test32AI, kArrayImm, IS_LOAD | IS_QUIN_OP | REG_USE01 | SETS_CCODES, { 0, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test32AI", "[!0r+!1r<<!2d+!3d],!4d" },
{ kX86Test64RI, kRegImm, IS_BINARY_OP | REG_USE0 | SETS_CCODES, { REX_W, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test64RI", "!0r,!1d" },
{ kX86Test64MI, kMemImm, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { REX_W, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test64MI", "[!0r+!1d],!2d" },
{ kX86Test64AI, kArrayImm, IS_LOAD | IS_QUIN_OP | REG_USE01 | SETS_CCODES, { REX_W, 0, 0xF7, 0, 0, 0, 0, 4, false }, "Test64AI", "[!0r+!1r<<!2d+!3d],!4d" },
- { kX86Test32RR, kRegReg, IS_BINARY_OP | REG_USE01 | SETS_CCODES, { 0, 0, 0x85, 0, 0, 0, 0, 0, false }, "Test32RR", "!0r,!1r" },
+ { kX86Test32RR, kRegReg, IS_BINARY_OP | REG_USE01 | SETS_CCODES, { 0, 0, 0x85, 0, 0, 0, 0, 0, false }, "Test32RR", "!0r,!1r" },
{ kX86Test64RR, kRegReg, IS_BINARY_OP | REG_USE01 | SETS_CCODES, { REX_W, 0, 0x85, 0, 0, 0, 0, 0, false }, "Test64RR", "!0r,!1r" },
+ { kX86Test32RM, kRegMem, IS_LOAD | IS_TERTIARY_OP | REG_USE0 | SETS_CCODES, { 0, 0, 0x85, 0, 0, 0, 0, 0, false }, "Test32RM", "!0r,[!1r+!1d]" },
#define UNARY_ENCODING_MAP(opname, modrm, is_store, sets_ccodes, \
reg, reg_kind, reg_flags, \
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 8e2a1e3..a5767a1 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -222,15 +222,28 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
LockTemp(rs_rX86_ARG1);
LockTemp(rs_rX86_ARG2);
- /* Build frame, return address already on stack */
- stack_decrement_ = OpRegImm(kOpSub, rs_rX86_SP, frame_size_ - GetInstructionSetPointerSize(cu_->instruction_set));
-
/*
* We can safely skip the stack overflow check if we're
* a leaf *and* our frame size < fudge factor.
*/
- const bool skip_overflow_check = mir_graph_->MethodIsLeaf() &&
- !IsLargeFrame(frame_size_, cu_->target64 ? kX86_64 : kX86);
+ InstructionSet isa = cu_->target64 ? kX86_64 : kX86;
+ const bool skip_overflow_check = mir_graph_->MethodIsLeaf() && !IsLargeFrame(frame_size_, isa);
+
+ // If we doing an implicit stack overflow check, perform the load immediately
+ // before the stack pointer is decremented and anything is saved.
+ if (!skip_overflow_check &&
+ cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
+ // Implicit stack overflow check.
+ // test eax,[esp + -overflow]
+ int overflow = GetStackOverflowReservedBytes(isa);
+ NewLIR3(kX86Test32RM, rs_rAX.GetReg(), rs_rX86_SP.GetReg(), -overflow);
+ MarkPossibleStackOverflowException();
+ }
+
+ /* Build frame, return address already on stack */
+ stack_decrement_ = OpRegImm(kOpSub, rs_rX86_SP, frame_size_ -
+ GetInstructionSetPointerSize(cu_->instruction_set));
+
NewLIR0(kPseudoMethodEntry);
/* Spill core callee saves */
SpillCoreRegs();
@@ -260,25 +273,27 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) {
private:
const size_t sp_displace_;
};
- // TODO: for large frames we should do something like:
- // spill ebp
- // lea ebp, [esp + frame_size]
- // cmp ebp, fs:[stack_end_]
- // jcc stack_overflow_exception
- // mov esp, ebp
- // in case a signal comes in that's not using an alternate signal stack and the large frame may
- // have moved us outside of the reserved area at the end of the stack.
- // cmp rs_rX86_SP, fs:[stack_end_]; jcc throw_slowpath
- if (cu_->target64) {
- OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<8>());
- } else {
- OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>());
- }
- LIR* branch = OpCondBranch(kCondUlt, nullptr);
- AddSlowPath(
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) {
+ // TODO: for large frames we should do something like:
+ // spill ebp
+ // lea ebp, [esp + frame_size]
+ // cmp ebp, fs:[stack_end_]
+ // jcc stack_overflow_exception
+ // mov esp, ebp
+ // in case a signal comes in that's not using an alternate signal stack and the large frame
+ // may have moved us outside of the reserved area at the end of the stack.
+ // cmp rs_rX86_SP, fs:[stack_end_]; jcc throw_slowpath
+ if (cu_->target64) {
+ OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<8>());
+ } else {
+ OpRegThreadMem(kOpCmp, rs_rX86_SP, Thread::StackEndOffset<4>());
+ }
+ LIR* branch = OpCondBranch(kCondUlt, nullptr);
+ AddSlowPath(
new(arena_)StackOverflowSlowPath(this, branch,
frame_size_ -
GetInstructionSetPointerSize(cu_->instruction_set)));
+ }
}
FlushIns(ArgLocs, rl_method);
@@ -318,4 +333,14 @@ void X86Mir2Lir::GenSpecialExitSequence() {
NewLIR0(kX86Ret);
}
+void X86Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) {
+ if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) {
+ return;
+ }
+ // Implicit null pointer check.
+ // test eax,[arg1+0]
+ NewLIR3(kX86Test32RM, rs_rAX.GetReg(), reg.GetReg(), 0);
+ MarkPossibleNullPointerException(opt_flags);
+}
+
} // namespace art
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index b0c54e8..e40d45e 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -85,6 +85,7 @@ class X86Mir2Lir : public Mir2Lir {
LIR* StoreBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int scale, int displacement,
RegStorage r_src, OpSize size) OVERRIDE;
void MarkGCCard(RegStorage val_reg, RegStorage tgt_addr_reg);
+ void GenImplicitNullCheck(RegStorage reg, int opt_flags);
// Required for target - register utilities.
RegStorage TargetReg(SpecialTargetRegister reg) OVERRIDE;
@@ -798,9 +799,11 @@ class X86Mir2Lir : public Mir2Lir {
* @param base_reg The register holding the base address.
* @param offset The offset from the base.
* @param check_value The immediate to compare to.
+ * @param target branch target (or nullptr)
+ * @param compare output for getting LIR for comparison (or nullptr)
*/
LIR* OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
- int offset, int check_value, LIR* target);
+ int offset, int check_value, LIR* target, LIR** compare);
/*
* Can this operation be using core registers without temporaries?
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index f1166f6..e8118dc 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1092,6 +1092,7 @@ void X86Mir2Lir::GenArrayBoundsCheck(RegStorage index,
};
OpRegMem(kOpCmp, index, array_base, len_offset);
+ MarkPossibleNullPointerException(0);
LIR* branch = OpCondBranch(kCondUge, nullptr);
AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch,
index, array_base, len_offset));
@@ -1132,6 +1133,7 @@ void X86Mir2Lir::GenArrayBoundsCheck(int32_t index,
};
NewLIR3(IS_SIMM8(index) ? kX86Cmp32MI8 : kX86Cmp32MI, array_base.GetReg(), len_offset, index);
+ MarkPossibleNullPointerException(0);
LIR* branch = OpCondBranch(kCondLs, nullptr);
AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch,
index, array_base, len_offset));
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 1ebbbbd..c283b40 100755
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -892,8 +892,12 @@ RegStorage X86Mir2Lir::LoadHelper(ThreadOffset<8> offset) {
}
LIR* X86Mir2Lir::CheckSuspendUsingLoad() {
- LOG(FATAL) << "Unexpected use of CheckSuspendUsingLoad in x86";
- return nullptr;
+ // First load the pointer in fs:[suspend-trigger] into eax
+ // Then use a test instruction to indirect via that address.
+ NewLIR2(kX86Mov32RT, rs_rAX.GetReg(), cu_->target64 ?
+ Thread::ThreadSuspendTriggerOffset<8>().Int32Value() :
+ Thread::ThreadSuspendTriggerOffset<4>().Int32Value());
+ return NewLIR3(kX86Test32RM, rs_rAX.GetReg(), rs_rAX.GetReg(), 0);
}
uint64_t X86Mir2Lir::GetTargetInstFlags(int opcode) {
@@ -1256,6 +1260,7 @@ bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
// Is the string non-NULL?
LoadValueDirectFixed(rl_obj, rs_rDX);
GenNullCheck(rs_rDX, info->opt_flags);
+ // uint32_t opt_flags = info->opt_flags;
info->opt_flags |= MIR_IGNORE_NULL_CHECK; // Record that we've null checked.
// Does the character fit in 16 bits?
@@ -1282,12 +1287,20 @@ bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
// Character is in EAX.
// Object pointer is in EDX.
+ // Compute the number of words to search in to rCX.
+ Load32Disp(rs_rDX, count_offset, rs_rCX);
+
+ // Possible signal here due to null pointer dereference.
+ // Note that the signal handler will expect the top word of
+ // the stack to be the ArtMethod*. If the PUSH edi instruction
+ // below is ahead of the load above then this will not be true
+ // and the signal handler will not work.
+ MarkPossibleNullPointerException(0);
+
// We need to preserve EDI, but have no spare registers, so push it on the stack.
// We have to remember that all stack addresses after this are offset by sizeof(EDI).
NewLIR1(kX86Push32R, rs_rDI.GetReg());
- // Compute the number of words to search in to rCX.
- Load32Disp(rs_rDX, count_offset, rs_rCX);
LIR *length_compare = nullptr;
int start_value = 0;
bool is_index_on_stack = false;
@@ -2678,7 +2691,7 @@ int X86Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state,
call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx,
direct_code, direct_method, type);
if (pcrLabel) {
- if (cu_->compiler_driver->GetCompilerOptions().GetExplicitNullChecks()) {
+ if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) {
*pcrLabel = GenExplicitNullCheck(TargetRefReg(kArg1), info->opt_flags);
} else {
*pcrLabel = nullptr;
diff --git a/compiler/dex/quick/x86/utility_x86.cc b/compiler/dex/quick/x86/utility_x86.cc
index 5c7c91b..952c700 100644
--- a/compiler/dex/quick/x86/utility_x86.cc
+++ b/compiler/dex/quick/x86/utility_x86.cc
@@ -684,9 +684,9 @@ LIR* X86Mir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int
} else {
DCHECK(!r_dest.IsFloat()); // Make sure we're not still using a pair here.
if (r_base == r_dest.GetLow()) {
- load2 = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(),
+ load = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(),
displacement + HIWORD_OFFSET);
- load = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
+ load2 = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
} else {
load = NewLIR3(opcode, r_dest.GetLowReg(), r_base.GetReg(), displacement + LOWORD_OFFSET);
load2 = NewLIR3(opcode, r_dest.GetHighReg(), r_base.GetReg(),
@@ -712,16 +712,16 @@ LIR* X86Mir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int
if (r_dest.GetHigh() == r_index) {
// We can't use either register for the first load.
RegStorage temp = AllocTemp();
- load2 = NewLIR5(opcode, temp.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load = NewLIR5(opcode, temp.GetReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + HIWORD_OFFSET);
- load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load2 = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + LOWORD_OFFSET);
OpRegCopy(r_dest.GetHigh(), temp);
FreeTemp(temp);
} else {
- load2 = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load = NewLIR5(opcode, r_dest.GetHighReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + HIWORD_OFFSET);
- load = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
+ load2 = NewLIR5(opcode, r_dest.GetLowReg(), r_base.GetReg(), r_index.GetReg(), scale,
displacement + LOWORD_OFFSET);
}
} else {
@@ -744,6 +744,7 @@ LIR* X86Mir2Lir::LoadBaseIndexedDisp(RegStorage r_base, RegStorage r_index, int
}
}
+ // Always return first load generated as this might cause a fault if base is nullptr.
return load;
}
@@ -881,9 +882,12 @@ LIR* X86Mir2Lir::StoreBaseDisp(RegStorage r_base, int displacement, RegStorage r
}
LIR* X86Mir2Lir::OpCmpMemImmBranch(ConditionCode cond, RegStorage temp_reg, RegStorage base_reg,
- int offset, int check_value, LIR* target) {
- NewLIR3(IS_SIMM8(check_value) ? kX86Cmp32MI8 : kX86Cmp32MI, base_reg.GetReg(), offset,
- check_value);
+ int offset, int check_value, LIR* target, LIR** compare) {
+ LIR* inst = NewLIR3(IS_SIMM8(check_value) ? kX86Cmp32MI8 : kX86Cmp32MI, base_reg.GetReg(),
+ offset, check_value);
+ if (compare != nullptr) {
+ *compare = inst;
+ }
LIR* branch = OpCondBranch(cond, target);
return branch;
}
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 5657381..17f9b91 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -499,6 +499,7 @@ enum X86OpCode {
UnaryOpcode(kX86Test, RI, MI, AI),
kX86Test32RR,
kX86Test64RR,
+ kX86Test32RM,
UnaryOpcode(kX86Not, R, M, A),
UnaryOpcode(kX86Neg, R, M, A),
UnaryOpcode(kX86Mul, DaR, DaM, DaA),