diff options
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/Android.mk | 1 | ||||
-rw-r--r-- | compiler/dex/quick/arm/call_arm.cc | 168 | ||||
-rw-r--r-- | compiler/dex/quick/arm/int_arm.cc | 3 | ||||
-rw-r--r-- | compiler/dex/quick/gen_common.cc | 12 | ||||
-rw-r--r-- | compiler/dex/quick/mips/call_mips.cc | 31 | ||||
-rw-r--r-- | compiler/dex/quick/mips/codegen_mips.h | 2 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 6 | ||||
-rw-r--r-- | compiler/dex/quick/x86/call_x86.cc | 37 | ||||
-rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 2 | ||||
-rw-r--r-- | compiler/image_test.cc | 4 | ||||
-rw-r--r-- | compiler/llvm/llvm_compilation_unit.cc | 5 | ||||
-rw-r--r-- | compiler/llvm/runtime_support_builder.cc | 76 | ||||
-rw-r--r-- | compiler/llvm/runtime_support_builder.h | 4 | ||||
-rw-r--r-- | compiler/llvm/runtime_support_builder_arm.cc | 19 | ||||
-rw-r--r-- | compiler/llvm/runtime_support_builder_arm.h | 4 | ||||
-rw-r--r-- | compiler/llvm/runtime_support_builder_thumb2.cc | 90 | ||||
-rw-r--r-- | compiler/llvm/runtime_support_builder_thumb2.h | 37 |
17 files changed, 124 insertions, 377 deletions
diff --git a/compiler/Android.mk b/compiler/Android.mk index 66ff46163b..fc2f02b59e 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -74,7 +74,6 @@ LIBART_COMPILER_SRC_FILES := \ llvm/md_builder.cc \ llvm/runtime_support_builder.cc \ llvm/runtime_support_builder_arm.cc \ - llvm/runtime_support_builder_thumb2.cc \ llvm/runtime_support_builder_x86.cc \ trampolines/trampoline_compiler.cc \ utils/arm/assembler_arm.cc \ diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc index bba2ec5c4e..401da2abd4 100644 --- a/compiler/dex/quick/arm/call_arm.cc +++ b/compiler/dex/quick/arm/call_arm.cc @@ -440,88 +440,120 @@ void ArmMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { } /* - * Handle simple case (thin lock) inline. If it's complicated, bail - * out to the heavyweight lock/unlock routines. We'll use dedicated - * registers here in order to be in the right position in case we - * to bail to oat[Lock/Unlock]Object(self, object) - * - * r0 -> self pointer [arg0 for oat[Lock/Unlock]Object - * r1 -> object [arg1 for oat[Lock/Unlock]Object - * r2 -> intial contents of object->lock, later result of strex - * r3 -> self->thread_id - * r12 -> allow to be used by utilities as general temp - * - * The result of the strex is 0 if we acquire the lock. - * - * See comments in monitor.cc for the layout of the lock word. - * Of particular interest to this code is the test for the - * simple case - which we handle inline. For monitor enter, the - * simple case is thin lock, held by no-one. For monitor exit, - * the simple case is thin lock, held by the unlocking thread with - * a recurse count of 0. - * - * A minor complication is that there is a field in the lock word - * unrelated to locking: the hash state. This field must be ignored, but - * preserved. - * + * Handle unlocked -> thin locked transition inline or else call out to quick entrypoint. For more + * details see monitor.cc. */ void ArmMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { FlushAllRegs(); - DCHECK_EQ(LW_SHAPE_THIN, 0); LoadValueDirectFixed(rl_src, r0); // Get obj LockCallTemps(); // Prepare for explicit register usage - GenNullCheck(rl_src.s_reg_low, r0, opt_flags); - LoadWordDisp(rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2); - NewLIR3(kThumb2Ldrex, r1, r0, - mirror::Object::MonitorOffset().Int32Value() >> 2); // Get object->lock - // Align owner - OpRegImm(kOpLsl, r2, LW_LOCK_OWNER_SHIFT); - // Is lock unheld on lock or held by us (==thread_id) on unlock? - NewLIR4(kThumb2Bfi, r2, r1, 0, LW_LOCK_OWNER_SHIFT - 1); - NewLIR3(kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1); - OpRegImm(kOpCmp, r1, 0); - OpIT(kCondEq, ""); - NewLIR4(kThumb2Strex, r1, r2, r0, - mirror::Object::MonitorOffset().Int32Value() >> 2); - OpRegImm(kOpCmp, r1, 0); - OpIT(kCondNe, "T"); - // Go expensive route - artLockObjectFromCode(self, obj); - LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR); - ClobberCalleeSave(); - LIR* call_inst = OpReg(kOpBlx, rARM_LR); - MarkSafepointPC(call_inst); - GenMemBarrier(kLoadLoad); + constexpr bool kArchVariantHasGoodBranchPredictor = false; // TODO: true if cortex-A15. + if (kArchVariantHasGoodBranchPredictor) { + LIR* null_check_branch; + if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) { + 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. + null_check_branch = OpCmpImmBranch(kCondEq, r0, 0, NULL); + } + LoadWordDisp(rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2); + NewLIR3(kThumb2Ldrex, r1, r0, mirror::Object::MonitorOffset().Int32Value() >> 2); + LIR* not_unlocked_branch = OpCmpImmBranch(kCondNe, r1, 0, NULL); + NewLIR4(kThumb2Strex, r1, r2, r0, mirror::Object::MonitorOffset().Int32Value() >> 2); + LIR* lock_success_branch = OpCmpImmBranch(kCondEq, r1, 0, NULL); + + + LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); + not_unlocked_branch->target = slow_path_target; + if (null_check_branch != nullptr) { + null_check_branch->target = slow_path_target; + } + // TODO: move to a slow path. + // Go expensive route - artLockObjectFromCode(obj); + LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR); + ClobberCalleeSave(); + LIR* call_inst = OpReg(kOpBlx, rARM_LR); + MarkSafepointPC(call_inst); + + LIR* success_target = NewLIR0(kPseudoTargetLabel); + lock_success_branch->target = success_target; + GenMemBarrier(kLoadLoad); + } else { + // Explicit null-check as slow-path is entered using an IT. + GenNullCheck(rl_src.s_reg_low, r0, opt_flags); + LoadWordDisp(rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2); + NewLIR3(kThumb2Ldrex, r1, r0, mirror::Object::MonitorOffset().Int32Value() >> 2); + OpRegImm(kOpCmp, r1, 0); + OpIT(kCondEq, ""); + NewLIR4(kThumb2Strex/*eq*/, r1, r2, r0, mirror::Object::MonitorOffset().Int32Value() >> 2); + OpRegImm(kOpCmp, r1, 0); + OpIT(kCondNe, "T"); + // Go expensive route - artLockObjectFromCode(self, obj); + LoadWordDisp/*ne*/(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR); + ClobberCalleeSave(); + LIR* call_inst = OpReg(kOpBlx/*ne*/, rARM_LR); + MarkSafepointPC(call_inst); + GenMemBarrier(kLoadLoad); + } } /* - * For monitor unlock, we don't have to use ldrex/strex. Once - * we've determined that the lock is thin and that we own it with - * a zero recursion count, it's safe to punch it back to the - * initial, unlock thin state with a store word. + * Handle thin locked -> unlocked transition inline or else call out to quick entrypoint. For more + * details see monitor.cc. Note the code below doesn't use ldrex/strex as the code holds the lock + * and can only give away ownership if its suspended. */ void ArmMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { - DCHECK_EQ(LW_SHAPE_THIN, 0); FlushAllRegs(); LoadValueDirectFixed(rl_src, r0); // Get obj LockCallTemps(); // Prepare for explicit register usage - GenNullCheck(rl_src.s_reg_low, r0, opt_flags); - LoadWordDisp(r0, mirror::Object::MonitorOffset().Int32Value(), r1); // Get lock + LIR* null_check_branch; LoadWordDisp(rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2); - // Is lock unheld on lock or held by us (==thread_id) on unlock? - OpRegRegImm(kOpAnd, r3, r1, - (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); - // Align owner - OpRegImm(kOpLsl, r2, LW_LOCK_OWNER_SHIFT); - NewLIR3(kThumb2Bfc, r1, LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1); - OpRegReg(kOpSub, r1, r2); - OpIT(kCondEq, "EE"); - StoreWordDisp(r0, mirror::Object::MonitorOffset().Int32Value(), r3); - // Go expensive route - UnlockObjectFromCode(obj); - LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR); - ClobberCalleeSave(); - LIR* call_inst = OpReg(kOpBlx, rARM_LR); - MarkSafepointPC(call_inst); - GenMemBarrier(kStoreLoad); + constexpr bool kArchVariantHasGoodBranchPredictor = false; // TODO: true if cortex-A15. + if (kArchVariantHasGoodBranchPredictor) { + if ((opt_flags & MIR_IGNORE_NULL_CHECK) && !(cu_->disable_opt & (1 << kNullCheckElimination))) { + 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. + null_check_branch = OpCmpImmBranch(kCondEq, r0, 0, NULL); + } + LoadWordDisp(r0, mirror::Object::MonitorOffset().Int32Value(), r1); + LoadConstantNoClobber(r3, 0); + LIR* slow_unlock_branch = OpCmpBranch(kCondNe, r1, r2, NULL); + StoreWordDisp(r0, mirror::Object::MonitorOffset().Int32Value(), r3); + LIR* unlock_success_branch = OpUnconditionalBranch(NULL); + + LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); + slow_unlock_branch->target = slow_path_target; + if (null_check_branch != nullptr) { + null_check_branch->target = slow_path_target; + } + // TODO: move to a slow path. + // Go expensive route - artUnlockObjectFromCode(obj); + LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR); + ClobberCalleeSave(); + LIR* call_inst = OpReg(kOpBlx, rARM_LR); + MarkSafepointPC(call_inst); + + LIR* success_target = NewLIR0(kPseudoTargetLabel); + unlock_success_branch->target = success_target; + GenMemBarrier(kStoreLoad); + } else { + // Explicit null-check as slow-path is entered using an IT. + GenNullCheck(rl_src.s_reg_low, r0, opt_flags); + LoadWordDisp(r0, mirror::Object::MonitorOffset().Int32Value(), r1); // Get lock + LoadWordDisp(rARM_SELF, Thread::ThinLockIdOffset().Int32Value(), r2); + LoadConstantNoClobber(r3, 0); + // Is lock unheld on lock or held by us (==thread_id) on unlock? + OpRegReg(kOpCmp, r1, r2); + OpIT(kCondEq, "EE"); + StoreWordDisp/*eq*/(r0, mirror::Object::MonitorOffset().Int32Value(), r3); + // Go expensive route - UnlockObjectFromCode(obj); + LoadWordDisp/*ne*/(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR); + ClobberCalleeSave(); + LIR* call_inst = OpReg(kOpBlx/*ne*/, rARM_LR); + MarkSafepointPC(call_inst); + GenMemBarrier(kStoreLoad); + } } void ArmMir2Lir::GenMoveException(RegLocation rl_dest) { diff --git a/compiler/dex/quick/arm/int_arm.cc b/compiler/dex/quick/arm/int_arm.cc index 07782d957f..4fa038763c 100644 --- a/compiler/dex/quick/arm/int_arm.cc +++ b/compiler/dex/quick/arm/int_arm.cc @@ -24,8 +24,7 @@ namespace art { -LIR* ArmMir2Lir::OpCmpBranch(ConditionCode cond, int src1, - int src2, LIR* target) { +LIR* ArmMir2Lir::OpCmpBranch(ConditionCode cond, int src1, int src2, LIR* target) { OpRegReg(kOpCmp, src1, src2); return OpCondBranch(cond, target); } diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc index 4dd55d763a..f38225a934 100644 --- a/compiler/dex/quick/gen_common.cc +++ b/compiler/dex/quick/gen_common.cc @@ -1761,4 +1761,16 @@ void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) { suspend_launchpads_.Insert(launch_pad); } +/* Call out to helper assembly routine that will null check obj and then lock it. */ +void Mir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { + FlushAllRegs(); + CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(pLockObject), rl_src, true); +} + +/* Call out to helper assembly routine that will null check obj and then unlock it. */ +void Mir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { + FlushAllRegs(); + CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(pUnlockObject), rl_src, true); +} + } // namespace art diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc index d53c012466..9a5ca2ce67 100644 --- a/compiler/dex/quick/mips/call_mips.cc +++ b/compiler/dex/quick/mips/call_mips.cc @@ -261,36 +261,6 @@ void MipsMir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { MarkSafepointPC(call_inst); } -/* - * TODO: implement fast path to short-circuit thin-lock case - */ -void MipsMir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { - FlushAllRegs(); - LoadValueDirectFixed(rl_src, rMIPS_ARG0); // Get obj - LockCallTemps(); // Prepare for explicit register usage - GenNullCheck(rl_src.s_reg_low, rMIPS_ARG0, opt_flags); - // Go expensive route - artLockObjectFromCode(self, obj); - int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pLockObject)); - ClobberCalleeSave(); - LIR* call_inst = OpReg(kOpBlx, r_tgt); - MarkSafepointPC(call_inst); -} - -/* - * TODO: implement fast path to short-circuit thin-lock case - */ -void MipsMir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { - FlushAllRegs(); - LoadValueDirectFixed(rl_src, rMIPS_ARG0); // Get obj - LockCallTemps(); // Prepare for explicit register usage - GenNullCheck(rl_src.s_reg_low, rMIPS_ARG0, opt_flags); - // Go expensive route - UnlockObjectFromCode(obj); - int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pUnlockObject)); - ClobberCalleeSave(); - LIR* call_inst = OpReg(kOpBlx, r_tgt); - MarkSafepointPC(call_inst); -} - void MipsMir2Lir::GenMoveException(RegLocation rl_dest) { int ex_offset = Thread::ExceptionOffset().Int32Value(); RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); @@ -318,6 +288,7 @@ void MipsMir2Lir::MarkGCCard(int val_reg, int tgt_addr_reg) { FreeTemp(reg_card_base); FreeTemp(reg_card_no); } + void MipsMir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { int spill_count = num_core_spills_ + num_fp_spills_; /* diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h index 8d0b347a34..95b2e77dd9 100644 --- a/compiler/dex/quick/mips/codegen_mips.h +++ b/compiler/dex/quick/mips/codegen_mips.h @@ -123,8 +123,6 @@ class MipsMir2Lir : public Mir2Lir { void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir); void GenSelect(BasicBlock* bb, MIR* mir); void GenMemBarrier(MemBarrierKind barrier_kind); - void GenMonitorEnter(int opt_flags, RegLocation rl_src); - void GenMonitorExit(int opt_flags, RegLocation rl_src); void GenMoveException(RegLocation rl_dest); void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit, int first_bit, int second_bit); diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index 7d6f968da5..71b68fe258 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -629,8 +629,6 @@ class Mir2Lir : public Backend { virtual void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir) = 0; virtual void GenSelect(BasicBlock* bb, MIR* mir) = 0; virtual void GenMemBarrier(MemBarrierKind barrier_kind) = 0; - virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src) = 0; - virtual void GenMonitorExit(int opt_flags, RegLocation rl_src) = 0; virtual void GenMoveException(RegLocation rl_dest) = 0; virtual void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit, int first_bit, @@ -689,6 +687,10 @@ class Mir2Lir : public Backend { virtual bool InexpensiveConstantLong(int64_t value) = 0; virtual bool InexpensiveConstantDouble(int64_t value) = 0; + // May be optimized by targets. + virtual void GenMonitorEnter(int opt_flags, RegLocation rl_src); + virtual void GenMonitorExit(int opt_flags, RegLocation rl_src); + // Temp workaround void Workaround7250540(RegLocation rl_dest, int value); diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index 2be2aa9a0e..7fad6f07d1 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -150,43 +150,6 @@ void X86Mir2Lir::GenFillArrayData(uint32_t table_offset, RegLocation rl_src) { rX86_ARG1, true); } -void X86Mir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { - FlushAllRegs(); - LoadValueDirectFixed(rl_src, rCX); // Get obj - LockCallTemps(); // Prepare for explicit register usage - GenNullCheck(rl_src.s_reg_low, rCX, opt_flags); - // If lock is unheld, try to grab it quickly with compare and exchange - // TODO: copy and clear hash state? - NewLIR2(kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value()); - NewLIR2(kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT); - NewLIR2(kX86Xor32RR, rAX, rAX); - NewLIR3(kX86LockCmpxchgMR, rCX, mirror::Object::MonitorOffset().Int32Value(), rDX); - LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondEq); - // If lock is held, go the expensive route - artLockObjectFromCode(self, obj); - CallRuntimeHelperReg(QUICK_ENTRYPOINT_OFFSET(pLockObject), rCX, true); - branch->target = NewLIR0(kPseudoTargetLabel); -} - -void X86Mir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { - FlushAllRegs(); - LoadValueDirectFixed(rl_src, rAX); // Get obj - LockCallTemps(); // Prepare for explicit register usage - GenNullCheck(rl_src.s_reg_low, rAX, opt_flags); - // If lock is held by the current thread, clear it to quickly release it - // TODO: clear hash state? - NewLIR2(kX86Mov32RT, rDX, Thread::ThinLockIdOffset().Int32Value()); - NewLIR2(kX86Sal32RI, rDX, LW_LOCK_OWNER_SHIFT); - NewLIR3(kX86Mov32RM, rCX, rAX, mirror::Object::MonitorOffset().Int32Value()); - OpRegReg(kOpSub, rCX, rDX); - LIR* branch = NewLIR2(kX86Jcc8, 0, kX86CondNe); - NewLIR3(kX86Mov32MR, rAX, mirror::Object::MonitorOffset().Int32Value(), rCX); - LIR* branch2 = NewLIR1(kX86Jmp8, 0); - branch->target = NewLIR0(kPseudoTargetLabel); - // Otherwise, go the expensive route - UnlockObjectFromCode(obj); - CallRuntimeHelperReg(QUICK_ENTRYPOINT_OFFSET(pUnlockObject), rAX, true); - branch2->target = NewLIR0(kPseudoTargetLabel); -} - void X86Mir2Lir::GenMoveException(RegLocation rl_dest) { int ex_offset = Thread::ExceptionOffset().Int32Value(); RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 0f281106b2..29fb3a519f 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -123,8 +123,6 @@ class X86Mir2Lir : public Mir2Lir { void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir); void GenSelect(BasicBlock* bb, MIR* mir); void GenMemBarrier(MemBarrierKind barrier_kind); - void GenMonitorEnter(int opt_flags, RegLocation rl_src); - void GenMonitorExit(int opt_flags, RegLocation rl_src); void GenMoveException(RegLocation rl_dest); void GenMultiplyByTwoBitMultiplier(RegLocation rl_src, RegLocation rl_result, int lit, int first_bit, int second_bit); diff --git a/compiler/image_test.cc b/compiler/image_test.cc index 6464a4c78e..d4be7c0cdc 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -23,6 +23,8 @@ #include "compiler/oat_writer.h" #include "gc/space/image_space.h" #include "image.h" +#include "lock_word.h" +#include "mirror/object-inl.h" #include "signal_catcher.h" #include "UniquePtr.h" #include "utils.h" @@ -158,7 +160,7 @@ TEST_F(ImageTest, WriteRead) { // non image classes should be in a space after the image. EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor; } - EXPECT_TRUE(Monitor::IsValidLockWord(*klass->GetRawLockWordAddress())); + EXPECT_TRUE(Monitor::IsValidLockWord(klass->GetLockWord())); } } diff --git a/compiler/llvm/llvm_compilation_unit.cc b/compiler/llvm/llvm_compilation_unit.cc index aa439ccbae..feb495e35f 100644 --- a/compiler/llvm/llvm_compilation_unit.cc +++ b/compiler/llvm/llvm_compilation_unit.cc @@ -82,7 +82,6 @@ #include "ir_builder.h" #include "os.h" #include "runtime_support_builder_arm.h" -#include "runtime_support_builder_thumb2.h" #include "runtime_support_builder_x86.h" #include "utils_llvm.h" @@ -118,12 +117,10 @@ LlvmCompilationUnit::LlvmCompilationUnit(const CompilerLLVM* compiler_llvm, size default: runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_)); break; + case kThumb2: case kArm: runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_)); break; - case kThumb2: - runtime_support_.reset(new RuntimeSupportBuilderThumb2(*context_, *module_, *irb_)); - break; case kX86: runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_)); break; diff --git a/compiler/llvm/runtime_support_builder.cc b/compiler/llvm/runtime_support_builder.cc index 24e283d309..c825fbf190 100644 --- a/compiler/llvm/runtime_support_builder.cc +++ b/compiler/llvm/runtime_support_builder.cc @@ -164,89 +164,13 @@ void RuntimeSupportBuilder::EmitTestSuspend() { /* Monitor */ void RuntimeSupportBuilder::EmitLockObject(::llvm::Value* object) { - Value* monitor = - irb_.LoadFromObjectOffset(object, - mirror::Object::MonitorOffset().Int32Value(), - irb_.getJIntTy(), - kTBAARuntimeInfo); - - Value* real_monitor = - irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); - - // Is thin lock, unheld and not recursively acquired. - Value* unheld = irb_.CreateICmpEQ(real_monitor, irb_.getInt32(0)); - - Function* parent_func = irb_.GetInsertBlock()->getParent(); - BasicBlock* bb_fast = BasicBlock::Create(context_, "lock_fast", parent_func); - BasicBlock* bb_slow = BasicBlock::Create(context_, "lock_slow", parent_func); - BasicBlock* bb_cont = BasicBlock::Create(context_, "lock_cont", parent_func); - irb_.CreateCondBr(unheld, bb_fast, bb_slow, kLikely); - - irb_.SetInsertPoint(bb_fast); - - // Calculate new monitor: new = old | (lock_id << LW_LOCK_OWNER_SHIFT) - Value* lock_id = - EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(), - irb_.getInt32Ty(), kTBAARuntimeInfo); - - Value* owner = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT); - Value* new_monitor = irb_.CreateOr(monitor, owner); - - // Atomically update monitor. - Value* old_monitor = - irb_.CompareExchangeObjectOffset(object, - mirror::Object::MonitorOffset().Int32Value(), - monitor, new_monitor, kTBAARuntimeInfo); - - Value* retry_slow_path = irb_.CreateICmpEQ(old_monitor, monitor); - irb_.CreateCondBr(retry_slow_path, bb_cont, bb_slow, kLikely); - - irb_.SetInsertPoint(bb_slow); Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject); irb_.CreateCall2(slow_func, object, EmitGetCurrentThread()); - irb_.CreateBr(bb_cont); - - irb_.SetInsertPoint(bb_cont); } void RuntimeSupportBuilder::EmitUnlockObject(::llvm::Value* object) { - Value* lock_id = - EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(), - irb_.getJIntTy(), - kTBAARuntimeInfo); - Value* monitor = - irb_.LoadFromObjectOffset(object, - mirror::Object::MonitorOffset().Int32Value(), - irb_.getJIntTy(), - kTBAARuntimeInfo); - - Value* my_monitor = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT); - Value* hash_state = irb_.CreateAnd(monitor, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); - Value* real_monitor = irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT)); - - // Is thin lock, held by us and not recursively acquired - Value* is_fast_path = irb_.CreateICmpEQ(real_monitor, my_monitor); - - Function* parent_func = irb_.GetInsertBlock()->getParent(); - BasicBlock* bb_fast = BasicBlock::Create(context_, "unlock_fast", parent_func); - BasicBlock* bb_slow = BasicBlock::Create(context_, "unlock_slow", parent_func); - BasicBlock* bb_cont = BasicBlock::Create(context_, "unlock_cont", parent_func); - irb_.CreateCondBr(is_fast_path, bb_fast, bb_slow, kLikely); - - irb_.SetInsertPoint(bb_fast); - // Set all bits to zero (except hash state) - irb_.StoreToObjectOffset(object, - mirror::Object::MonitorOffset().Int32Value(), - hash_state, - kTBAARuntimeInfo); - irb_.CreateBr(bb_cont); - - irb_.SetInsertPoint(bb_slow); Function* slow_func = GetRuntimeSupportFunction(runtime_support::UnlockObject); irb_.CreateCall2(slow_func, object, EmitGetCurrentThread()); - irb_.CreateBr(bb_cont); - - irb_.SetInsertPoint(bb_cont); } diff --git a/compiler/llvm/runtime_support_builder.h b/compiler/llvm/runtime_support_builder.h index e92ac0a908..898611af75 100644 --- a/compiler/llvm/runtime_support_builder.h +++ b/compiler/llvm/runtime_support_builder.h @@ -64,8 +64,8 @@ class RuntimeSupportBuilder { virtual void EmitTestSuspend(); /* Monitor */ - virtual void EmitLockObject(::llvm::Value* object); - virtual void EmitUnlockObject(::llvm::Value* object); + void EmitLockObject(::llvm::Value* object); + void EmitUnlockObject(::llvm::Value* object); /* MarkGCCard */ virtual void EmitMarkGCCard(::llvm::Value* value, ::llvm::Value* target_addr); diff --git a/compiler/llvm/runtime_support_builder_arm.cc b/compiler/llvm/runtime_support_builder_arm.cc index 569d825272..cad46247fd 100644 --- a/compiler/llvm/runtime_support_builder_arm.cc +++ b/compiler/llvm/runtime_support_builder_arm.cc @@ -116,24 +116,5 @@ Value* RuntimeSupportBuilderARM::EmitSetCurrentThread(Value* thread) { return old_thread_register; } - -/* Monitor */ - -void RuntimeSupportBuilderARM::EmitLockObject(Value* object) { - RuntimeSupportBuilder::EmitLockObject(object); - FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), - /*isVarArg=*/false); - InlineAsm* func = InlineAsm::get(func_ty, "dmb sy", "", true); - irb_.CreateCall(func); -} - -void RuntimeSupportBuilderARM::EmitUnlockObject(Value* object) { - RuntimeSupportBuilder::EmitUnlockObject(object); - FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), - /*isVarArg=*/false); - InlineAsm* func = InlineAsm::get(func_ty, "dmb sy", "", true); - irb_.CreateCall(func); -} - } // namespace llvm } // namespace art diff --git a/compiler/llvm/runtime_support_builder_arm.h b/compiler/llvm/runtime_support_builder_arm.h index 5a353d7f30..0d01509be0 100644 --- a/compiler/llvm/runtime_support_builder_arm.h +++ b/compiler/llvm/runtime_support_builder_arm.h @@ -34,10 +34,6 @@ class RuntimeSupportBuilderARM : public RuntimeSupportBuilder { virtual void EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value, TBAASpecialType s_ty); virtual ::llvm::Value* EmitSetCurrentThread(::llvm::Value* thread); - - /* Monitor */ - virtual void EmitLockObject(::llvm::Value* object); - virtual void EmitUnlockObject(::llvm::Value* object); }; } // namespace llvm diff --git a/compiler/llvm/runtime_support_builder_thumb2.cc b/compiler/llvm/runtime_support_builder_thumb2.cc deleted file mode 100644 index eff29c8b04..0000000000 --- a/compiler/llvm/runtime_support_builder_thumb2.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "runtime_support_builder_thumb2.h" - -#include "ir_builder.h" -#include "mirror/object.h" -#include "monitor.h" -#include "thread.h" -#include "utils_llvm.h" - -#include <llvm/IR/DerivedTypes.h> -#include <llvm/IR/Function.h> -#include <llvm/IR/InlineAsm.h> -#include <llvm/IR/Module.h> -#include <llvm/IR/Type.h> - -#include <inttypes.h> -#include <vector> - -using ::llvm::BasicBlock; -using ::llvm::Function; -using ::llvm::FunctionType; -using ::llvm::InlineAsm; -using ::llvm::Type; -using ::llvm::Value; - -namespace art { -namespace llvm { - - -void RuntimeSupportBuilderThumb2::EmitLockObject(Value* object) { - FunctionType* func_ty = FunctionType::get(/*Result=*/irb_.getInt32Ty(), - /*Params=*/irb_.getJObjectTy(), - /*isVarArg=*/false); - // $0: result - // $1: object - // $2: temp - // $3: temp - std::string asms; - StringAppendF(&asms, "add $3, $1, #%" PRId32 "\n", mirror::Object::MonitorOffset().Int32Value()); - StringAppendF(&asms, "ldr $2, [r9, #%" PRId32 "]\n", Thread::ThinLockIdOffset().Int32Value()); - StringAppendF(&asms, "ldrex $0, [$3]\n"); - StringAppendF(&asms, "lsl $2, $2, %d\n", LW_LOCK_OWNER_SHIFT); - StringAppendF(&asms, "bfi $2, $0, #0, #%d\n", LW_LOCK_OWNER_SHIFT - 1); - StringAppendF(&asms, "bfc $0, #%d, #%d\n", LW_HASH_STATE_SHIFT, LW_LOCK_OWNER_SHIFT - 1); - StringAppendF(&asms, "cmp $0, #0\n"); - StringAppendF(&asms, "it eq\n"); - StringAppendF(&asms, "strexeq $0, $2, [$3]\n"); - - InlineAsm* func = InlineAsm::get(func_ty, asms, "=&l,l,~l,~l", true); - - Value* retry_slow_path = irb_.CreateCall(func, object); - retry_slow_path = irb_.CreateICmpNE(retry_slow_path, irb_.getJInt(0)); - - Function* parent_func = irb_.GetInsertBlock()->getParent(); - BasicBlock* basic_block_lock = BasicBlock::Create(context_, "lock", parent_func); - BasicBlock* basic_block_cont = BasicBlock::Create(context_, "lock_cont", parent_func); - irb_.CreateCondBr(retry_slow_path, basic_block_lock, basic_block_cont, kUnlikely); - - irb_.SetInsertPoint(basic_block_lock); - Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject); - irb_.CreateCall2(slow_func, object, EmitGetCurrentThread()); - irb_.CreateBr(basic_block_cont); - - irb_.SetInsertPoint(basic_block_cont); - { // Memory barrier - FunctionType* asm_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_), - /*isVarArg=*/false); - InlineAsm* func = InlineAsm::get(asm_ty, "dmb sy", "", true); - irb_.CreateCall(func); - } -} - - -} // namespace llvm -} // namespace art diff --git a/compiler/llvm/runtime_support_builder_thumb2.h b/compiler/llvm/runtime_support_builder_thumb2.h deleted file mode 100644 index c47a2744ef..0000000000 --- a/compiler/llvm/runtime_support_builder_thumb2.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_ -#define ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_ - -#include "runtime_support_builder_arm.h" - -namespace art { -namespace llvm { - -class RuntimeSupportBuilderThumb2 : public RuntimeSupportBuilderARM { - public: - RuntimeSupportBuilderThumb2(::llvm::LLVMContext& context, ::llvm::Module& module, IRBuilder& irb) - : RuntimeSupportBuilderARM(context, module, irb) {} - - /* Monitor */ - virtual void EmitLockObject(::llvm::Value* object); -}; - -} // namespace llvm -} // namespace art - -#endif // ART_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_ |