Implement thin-lock fast path for compiler-llvm.
Change-Id: I09d6a0dba4df7cbeb0c0e3f432ab3b09fce0846d
diff --git a/build/Android.libart-compiler-llvm.mk b/build/Android.libart-compiler-llvm.mk
index f27e83e..e2c66e4 100644
--- a/build/Android.libart-compiler-llvm.mk
+++ b/build/Android.libart-compiler-llvm.mk
@@ -28,6 +28,7 @@
src/compiler_llvm/method_compiler.cc \
src/compiler_llvm/runtime_support_builder.cc \
src/compiler_llvm/runtime_support_builder_arm.cc \
+ src/compiler_llvm/runtime_support_builder_thumb2.cc \
src/compiler_llvm/runtime_support_builder_x86.cc \
src/compiler_llvm/runtime_support_llvm.cc \
src/compiler_llvm/stub_compiler.cc \
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index 5f239ab..5dc03c3 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -24,6 +24,7 @@
#include "os.h"
#include "runtime_support_builder_arm.h"
+#include "runtime_support_builder_thumb2.h"
#include "runtime_support_builder_x86.h"
#include <llvm/ADT/OwningPtr.h>
@@ -180,13 +181,15 @@
// We always need a switch case, so just use a normal function.
switch(insn_set_) {
- default:
- runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
- break;
+ default:
+ runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
+ break;
case kArm:
- case kThumb2:
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;
@@ -254,13 +257,13 @@
switch (insn_set_) {
case kThumb2:
target_triple = "thumb-none-linux-gnueabi";
- target_attr = "+thumb2,+neon,+neonfp,+vfp3";
+ target_attr = "+thumb2,+neon,+neonfp,+vfp3,+db";
break;
case kArm:
target_triple = "armv7-none-linux-gnueabi";
// TODO: Fix for Xoom.
- target_attr = "+v7,+neon,+neonfp,+vfp3";
+ target_attr = "+v7,+neon,+neonfp,+vfp3,+db";
break;
case kX86:
diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc
index 838c89d..bb45fac 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -108,9 +108,6 @@
}
}
- // Get thread object
- llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
// Shadow stack
llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(sirt_size);
llvm::AllocaInst* shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
@@ -187,10 +184,7 @@
// Acquire lock for synchronized methods.
if (is_synchronized) {
- // Acquire lock
- irb_.CreateCall2(irb_.GetRuntime(LockObject),
- this_object_or_class_object,
- thread_object_addr);
+ irb_.Runtime().EmitLockObject(this_object_or_class_object);
}
// saved_local_ref_cookie = env->local_ref_cookie
@@ -218,9 +212,7 @@
// Release lock for synchronized methods.
if (is_synchronized) {
- irb_.CreateCall2(irb_.GetRuntime(UnlockObject),
- this_object_or_class_object,
- thread_object_addr);
+ irb_.Runtime().EmitUnlockObject(this_object_or_class_object);
}
// Set thread state to kRunnable
@@ -232,6 +224,9 @@
irb_.Runtime().EmitTestSuspend();
if (return_shorty == 'L') {
+ // Get thread object
+ llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
+
// If the return value is reference, it may point to SIRT, we should decode it.
retval = irb_.CreateCall2(irb_.GetRuntime(DecodeJObjectInThread),
thread_object_addr,
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index eecace0..4021f7b 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -1551,9 +1551,7 @@
EmitGuard_NullPointerException(dex_pc, object_addr);
}
- llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
- irb_.CreateCall2(irb_.GetRuntime(LockObject), object_addr, thread_object_addr);
+ irb_.Runtime().EmitLockObject(object_addr);
irb_.CreateBr(GetNextBasicBlock(dex_pc));
}
@@ -1573,9 +1571,7 @@
EmitUpdateDexPC(dex_pc);
- llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
-
- irb_.CreateCall2(irb_.GetRuntime(UnlockObject), object_addr, thread_object_addr);
+ irb_.Runtime().EmitUnlockObject(object_addr);
EmitGuard_ExceptionLandingPad(dex_pc, true);
diff --git a/src/compiler_llvm/runtime_support_builder.cc b/src/compiler_llvm/runtime_support_builder.cc
index b0823d6..9095c02 100644
--- a/src/compiler_llvm/runtime_support_builder.cc
+++ b/src/compiler_llvm/runtime_support_builder.cc
@@ -18,6 +18,8 @@
#include "card_table.h"
#include "ir_builder.h"
+#include "monitor.h"
+#include "object.h"
#include "shadow_frame.h"
#include "thread.h"
#include "utils_llvm.h"
@@ -179,6 +181,55 @@
}
+/* Monitor */
+
+void RuntimeSupportBuilder::EmitLockObject(llvm::Value* object) {
+ // TODO: Implement a fast path.
+ Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject);
+ irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
+}
+
+void RuntimeSupportBuilder::EmitUnlockObject(llvm::Value* object) {
+ llvm::Value* lock_id =
+ EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(),
+ irb_.getJIntTy(),
+ kTBAARuntimeInfo);
+ llvm::Value* monitor =
+ irb_.LoadFromObjectOffset(object,
+ Object::MonitorOffset().Int32Value(),
+ irb_.getJIntTy(),
+ kTBAARuntimeInfo);
+
+ llvm::Value* my_monitor = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT);
+ llvm::Value* hash_state = irb_.CreateAnd(monitor, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
+ llvm::Value* real_monitor = irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
+
+ // Is thin lock, held by us and not recursively acquired
+ llvm::Value* is_fast_path = irb_.CreateICmpEQ(real_monitor, my_monitor);
+
+ llvm::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,
+ 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);
+}
+
+
void RuntimeSupportBuilder::OptimizeRuntimeSupport() {
// TODO: Remove this after we remove suspend loop pass.
if (!target_runtime_support_func_[runtime_support::TestSuspend]) {
diff --git a/src/compiler_llvm/runtime_support_builder.h b/src/compiler_llvm/runtime_support_builder.h
index 89cf30a..7b54c69 100644
--- a/src/compiler_llvm/runtime_support_builder.h
+++ b/src/compiler_llvm/runtime_support_builder.h
@@ -60,6 +60,10 @@
virtual llvm::Value* EmitIsExceptionPending();
virtual void EmitTestSuspend();
+ /* Monitor */
+ virtual void EmitLockObject(llvm::Value* object);
+ virtual void EmitUnlockObject(llvm::Value* object);
+
llvm::Function* GetRuntimeSupportFunction(runtime_support::RuntimeId id) {
if (id >= 0 && id < runtime_support::MAX_ID) {
return runtime_support_func_decls_[id];
diff --git a/src/compiler_llvm/runtime_support_builder_arm.cc b/src/compiler_llvm/runtime_support_builder_arm.cc
index a180520..6ce9ea4 100644
--- a/src/compiler_llvm/runtime_support_builder_arm.cc
+++ b/src/compiler_llvm/runtime_support_builder_arm.cc
@@ -33,6 +33,7 @@
namespace art {
namespace compiler_llvm {
+/* Thread */
llvm::Value* RuntimeSupportBuilderARM::EmitGetCurrentThread() {
Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
@@ -73,5 +74,23 @@
}
+/* Monitor */
+
+void RuntimeSupportBuilderARM::EmitLockObject(llvm::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(llvm::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 compiler_llvm
} // namespace art
diff --git a/src/compiler_llvm/runtime_support_builder_arm.h b/src/compiler_llvm/runtime_support_builder_arm.h
index bf8a589..8828925 100644
--- a/src/compiler_llvm/runtime_support_builder_arm.h
+++ b/src/compiler_llvm/runtime_support_builder_arm.h
@@ -34,6 +34,10 @@
virtual void EmitStoreToThreadOffset(int64_t offset, llvm::Value* value,
TBAASpecialType s_ty);
virtual void EmitSetCurrentThread(llvm::Value* thread);
+
+ /* Monitor */
+ virtual void EmitLockObject(llvm::Value* object);
+ virtual void EmitUnlockObject(llvm::Value* object);
};
} // namespace compiler_llvm
diff --git a/src/compiler_llvm/runtime_support_builder_thumb2.cc b/src/compiler_llvm/runtime_support_builder_thumb2.cc
new file mode 100644
index 0000000..3299afe
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_thumb2.cc
@@ -0,0 +1,85 @@
+/*
+ * 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 "monitor.h"
+#include "object.h"
+#include "thread.h"
+#include "utils_llvm.h"
+
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/InlineAsm.h>
+#include <llvm/Module.h>
+#include <llvm/Type.h>
+
+#include <inttypes.h>
+#include <vector>
+
+using namespace llvm;
+
+namespace art {
+namespace compiler_llvm {
+
+
+void RuntimeSupportBuilderThumb2::EmitLockObject(llvm::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", 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);
+
+ llvm::Value* retry_slow_path = irb_.CreateCall(func, object);
+ retry_slow_path = irb_.CreateICmpNE(retry_slow_path, irb_.getJInt(0));
+
+ llvm::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 compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/runtime_support_builder_thumb2.h b/src/compiler_llvm/runtime_support_builder_thumb2.h
new file mode 100644
index 0000000..3ac0b9f
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_thumb2.h
@@ -0,0 +1,37 @@
+/*
+ * 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_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_
+#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_
+
+#include "runtime_support_builder_arm.h"
+
+namespace art {
+namespace compiler_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 compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_THUMB2_H_
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index bf74e06..99f9fee 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -62,7 +62,7 @@
}
void art_set_current_thread_from_code(void* thread_object_addr) {
- LOG(FATAL) << "Implemented by IRBuilder.";
+ // Nothing to be done.
}
void art_lock_object_from_code(Object* obj, Thread* thread) {
diff --git a/src/compiler_llvm/runtime_support_llvm.h b/src/compiler_llvm/runtime_support_llvm.h
index 8f73079..6757ff5 100644
--- a/src/compiler_llvm/runtime_support_llvm.h
+++ b/src/compiler_llvm/runtime_support_llvm.h
@@ -21,9 +21,6 @@
namespace art {
-class Method;
-class Object;
-
//----------------------------------------------------------------------------
// Thread
//----------------------------------------------------------------------------