Acquire lock for synchronized methods.
(cherry picked from commit f0adce1240dac0939f26188e2ae16e2e3e00d127)
Change-Id: I4aa09b2a334780b52211437f8421c81746fd6496
diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc
index 255e99a..936fb66 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -63,7 +63,11 @@
CompiledMethod* JniCompiler::Compile() {
- bool is_static = method_->IsStatic();
+ const bool is_static = (access_flags_ & kAccStatic) != 0;
+ const bool is_synchronized = (access_flags_ & kAccSynchronized) != 0;
+ DexFile::MethodId const& method_id = dex_file_->GetMethodId(method_idx_);
+ char const return_shorty = dex_file_->GetMethodShorty(method_id)[0];
+ llvm::Value* this_object_or_class_object;
CreateFunction();
@@ -76,11 +80,23 @@
arg_iter->setName("method");
llvm::Value* method_object_addr = arg_iter++;
- // Actual argument (ignore method)
+ if (!is_static) {
+ // Non-static, the second argument is "this object"
+ this_object_or_class_object = arg_iter++;
+ } else {
+ // Load class object
+ this_object_or_class_object =
+ LoadFromObjectOffset(method_object_addr,
+ Method::DeclaringClassOffset().Int32Value(),
+ irb_.getJObjectTy());
+ }
+ // Actual argument (ignore method and this object)
arg_begin = arg_iter;
// Count the number of Object* arguments
- uint32_t sirt_size = (is_static ? 1 : 0); // Class object for static function
+ uint32_t sirt_size = 1;
+ // "this" object pointer for non-static
+ // "class" object pointer for static
for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) {
arg_iter->setName(StringPrintf("a%u", i));
if (arg_iter->getType() == irb_.getJObjectTy()) {
@@ -88,16 +104,13 @@
}
}
- // Start to build IR
- irb_.SetInsertPoint(basic_block_);
-
// Get thread object
llvm::Value* thread_object_addr =
irb_.CreateCall(irb_.GetRuntime(runtime_support::GetCurrentThread));
// Shadow stack
llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(sirt_size);
- shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
+ llvm::AllocaInst* shadow_frame_ = irb_.CreateAlloca(shadow_frame_type);
// Zero-initialization of the shadow frame
llvm::ConstantAggregateZero* zero_initializer =
@@ -157,19 +170,12 @@
size_t sirt_member_index = 0;
- // Push class argument if this method is static
- if (is_static) {
- // Load class object
- llvm::Value* class_object_addr =
- LoadFromObjectOffset(method_object_addr,
- Method::DeclaringClassOffset().Int32Value(),
- irb_.getJObjectTy());
- gep_index[2] = irb_.getInt32(sirt_member_index++);
- // Store the class argument to SIRT
- llvm::Value* sirt_field_addr = irb_.CreateGEP(shadow_frame_, gep_index);
- irb_.CreateStore(class_object_addr, sirt_field_addr);
- args.push_back(irb_.CreateBitCast(sirt_field_addr, irb_.getJObjectTy()));
- }
+ // Store the "this object or class object" to SIRT
+ gep_index[2] = irb_.getInt32(sirt_member_index++);
+ llvm::Value* sirt_field_addr = irb_.CreateGEP(shadow_frame_, gep_index);
+ irb_.CreateStore(this_object_or_class_object, sirt_field_addr);
+ // Push the "this object or class object" to out args
+ args.push_back(irb_.CreateBitCast(sirt_field_addr, irb_.getJObjectTy()));
// Store arguments to SIRT, and push back to args
for (arg_iter = arg_begin; arg_iter != arg_end; ++arg_iter) {
if (arg_iter->getType() == irb_.getJObjectTy()) {
@@ -190,6 +196,38 @@
}
}
+ // Acquire lock for synchronized methods.
+ if (is_synchronized) {
+ // Acquire lock
+ irb_.CreateCall(irb_.GetRuntime(runtime_support::LockObject), this_object_or_class_object);
+
+ // Check exception pending
+ llvm::Value* exception_pending =
+ irb_.CreateCall(irb_.GetRuntime(runtime_support::IsExceptionPending));
+
+ // Create two basic block for branch
+ llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "B.cont", func_);
+ llvm::BasicBlock* block_exception_ = llvm::BasicBlock::Create(*context_, "B.exception", func_);
+
+ // Branch by exception_pending
+ irb_.CreateCondBr(exception_pending, block_exception_, block_cont);
+
+
+ // If exception pending
+ irb_.SetInsertPoint(block_exception_);
+ // TODO: Set thread state?
+ // Pop the shadow frame
+ irb_.CreateCall(irb_.GetRuntime(runtime_support::PopShadowFrame));
+ // Unwind
+ if (return_shorty != 'V') {
+ irb_.CreateRet(irb_.getJZero(return_shorty));
+ } else {
+ irb_.CreateRetVoid();
+ }
+
+ // If no exception pending
+ irb_.SetInsertPoint(block_cont);
+ }
// saved_local_ref_cookie = env->local_ref_cookie
llvm::Value* saved_local_ref_cookie =
@@ -211,18 +249,17 @@
llvm::Value* retval = irb_.CreateCall(code_addr, args);
+ // Release lock for synchronized methods.
+ if (is_synchronized) {
+ irb_.CreateCall(irb_.GetRuntime(runtime_support::UnlockObject), this_object_or_class_object);
+ }
+
// Set thread state to kRunnable
StoreToObjectOffset(thread_object_addr,
Thread::StateOffset().Int32Value(),
irb_.getInt32(Thread::kRunnable));
- // Get return shorty
- DexFile::MethodId const& method_id = dex_file_->GetMethodId(method_idx_);
- uint32_t shorty_size;
- char ret_shorty = dex_file_->GetMethodShorty(method_id, &shorty_size)[0];
- CHECK_GE(shorty_size, 1u);
-
- if (ret_shorty == 'L') {
+ if (return_shorty == 'L') {
// If the return value is reference, it may point to SIRT, we should decode it.
retval = irb_.CreateCall2(irb_.GetRuntime(runtime_support::DecodeJObjectInThread),
thread_object_addr,
@@ -247,15 +284,12 @@
irb_.CreateCall(irb_.GetRuntime(runtime_support::PopShadowFrame));
// Return!
- if (ret_shorty != 'V') {
+ if (return_shorty != 'V') {
irb_.CreateRet(retval);
} else {
irb_.CreateRetVoid();
}
- // For debug
- //func_->dump();
-
// Verify the generated bitcode
llvm::verifyFunction(*func_, llvm::PrintMessageAction);
@@ -277,12 +311,15 @@
func_name, module_);
// Create basic block
- basic_block_ = llvm::BasicBlock::Create(*context_, "B0", func_);
+ llvm::BasicBlock* basic_block = llvm::BasicBlock::Create(*context_, "B0", func_);
+
+ // Set insert point
+ irb_.SetInsertPoint(basic_block);
}
llvm::FunctionType* JniCompiler::GetFunctionType(uint32_t method_idx,
- bool is_static, bool is_target_function) {
+ bool is_static, bool is_native_function) {
// Get method signature
DexFile::MethodId const& method_id = dex_file_->GetMethodId(method_idx);
@@ -298,9 +335,9 @@
args_type.push_back(irb_.getJObjectTy()); // method object pointer
- if (!is_static || is_target_function) {
+ if (!is_static || is_native_function) {
// "this" object pointer for non-static
- // "class" object pointer for static
+ // "class" object pointer for static naitve
args_type.push_back(irb_.getJType('L', kAccurate));
}
diff --git a/src/compiler_llvm/jni_compiler.h b/src/compiler_llvm/jni_compiler.h
index a6ddce3..392c14d 100644
--- a/src/compiler_llvm/jni_compiler.h
+++ b/src/compiler_llvm/jni_compiler.h
@@ -85,9 +85,6 @@
DexFile const* dex_file_;
Method* method_;
- llvm::BasicBlock* basic_block_;
- llvm::AllocaInst* shadow_frame_;
-
llvm::Function* func_;
};