diff options
Diffstat (limited to 'compiler/dex')
-rw-r--r-- | compiler/dex/quick/arm/call_arm.cc | 8 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/call_arm64.cc | 8 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/codegen_arm64.h | 2 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/int_arm64.cc | 3 | ||||
-rw-r--r-- | compiler/dex/quick/arm64/target_arm64.cc | 2 | ||||
-rw-r--r-- | compiler/dex/quick/codegen_util.cc | 7 | ||||
-rw-r--r-- | compiler/dex/quick/gen_common.cc | 19 | ||||
-rwxr-xr-x | compiler/dex/quick/gen_invoke.cc | 42 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 5 | ||||
-rw-r--r-- | compiler/dex/quick/x86/assemble_x86.cc | 21 | ||||
-rw-r--r-- | compiler/dex/quick/x86/call_x86.cc | 67 | ||||
-rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 5 | ||||
-rwxr-xr-x | compiler/dex/quick/x86/int_x86.cc | 2 | ||||
-rwxr-xr-x | compiler/dex/quick/x86/target_x86.cc | 23 | ||||
-rw-r--r-- | compiler/dex/quick/x86/utility_x86.cc | 22 | ||||
-rw-r--r-- | compiler/dex/quick/x86/x86_lir.h | 1 |
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), |