Merge "Inline monitor-enter in portable." into dalvik-dev
diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h
index 4a58515..60a0f2a 100644
--- a/src/compiler_llvm/ir_builder.h
+++ b/src/compiler_llvm/ir_builder.h
@@ -65,6 +65,15 @@
return inst;
}
+ llvm::AtomicCmpXchgInst*
+ CreateAtomicCmpXchgInst(llvm::Value* ptr, llvm::Value* cmp, llvm::Value* val,
+ llvm::MDNode* tbaa_info) {
+ llvm::AtomicCmpXchgInst* inst =
+ LLVMIRBuilder::CreateAtomicCmpXchg(ptr, cmp, val, llvm::Acquire);
+ inst->setMetadata(llvm::LLVMContext::MD_tbaa, tbaa_info);
+ return inst;
+ }
+
//--------------------------------------------------------------------------
// TBAA
@@ -120,6 +129,17 @@
StoreToObjectOffset(object_addr, offset, new_value, mdb_.GetTBAAMemoryJType(special_ty, j_ty));
}
+ llvm::AtomicCmpXchgInst*
+ CompareExchangeObjectOffset(llvm::Value* object_addr,
+ int64_t offset,
+ llvm::Value* cmp_value,
+ llvm::Value* new_value,
+ TBAASpecialType special_ty) {
+ DCHECK_NE(special_ty, kTBAAConstJObject) << "ConstJObject is read only!";
+ return CompareExchangeObjectOffset(object_addr, offset, cmp_value, new_value,
+ mdb_.GetTBAASpecialType(special_ty));
+ }
+
void SetTBAA(llvm::Instruction* inst, TBAASpecialType special_ty) {
inst->setMetadata(llvm::LLVMContext::MD_tbaa, mdb_.GetTBAASpecialType(special_ty));
}
@@ -210,6 +230,21 @@
CreateStore(new_value, value_addr, tbaa_info);
}
+ llvm::AtomicCmpXchgInst* CompareExchangeObjectOffset(llvm::Value* object_addr,
+ int64_t offset,
+ llvm::Value* cmp_value,
+ llvm::Value* new_value,
+ llvm::MDNode* tbaa_info) {
+ // Convert offset to llvm::value
+ llvm::Value* llvm_offset = getPtrEquivInt(offset);
+ // Calculate the value's address
+ llvm::Value* value_addr = CreatePtrDisp(object_addr,
+ llvm_offset,
+ new_value->getType()->getPointerTo());
+ // Atomic compare and exchange
+ return CreateAtomicCmpXchgInst(value_addr, cmp_value, new_value, tbaa_info);
+ }
+
//--------------------------------------------------------------------------
// Runtime Helper Function
diff --git a/src/compiler_llvm/runtime_support_builder.cc b/src/compiler_llvm/runtime_support_builder.cc
index 36b5fa1..e661ec4 100644
--- a/src/compiler_llvm/runtime_support_builder.cc
+++ b/src/compiler_llvm/runtime_support_builder.cc
@@ -167,9 +167,49 @@
/* Monitor */
void RuntimeSupportBuilder::EmitLockObject(llvm::Value* object) {
- // TODO: Implement a fast path.
+ 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) {