Implement LLVM version of jni_compiler to pass 17 jni_compiler tests.
Because we now have both shadow_frame and sirt (which is just for SirtRef<>
in the LLVM version), we define a new function NumStackReferences() as follows:
NumStackReferences() = NumSirtReferences() + NumShadowFrameReferences().
(cherry picked from commit 18fe89a14d212da9ec6841f4d19d08482a9610b7)
Change-Id: Idd95ee4276801b1555be87934cd9c4f33ab8a88a
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll
index 78d388b..8eb1783 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -130,6 +130,9 @@
%JavaObject*,
%JavaObject*)
+declare %JavaObject* @art_decode_jobject_in_thread(%JavaObject*,
+ %JavaObject*)
+
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; RTTI
diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc
index fe708ae..18432d5 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -46,10 +46,10 @@
std::vector<Type*>StructTy_ShadowFrame_fields;
PointerType* PointerTy_2 = PointerType::get(StructTy_ShadowFrame, 0);
+StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
StructTy_ShadowFrame_fields.push_back(PointerTy_2);
StructTy_ShadowFrame_fields.push_back(PointerTy_1);
StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
-StructTy_ShadowFrame_fields.push_back(IntegerType::get(mod->getContext(), 32));
if (StructTy_ShadowFrame->isOpaque()) {
StructTy_ShadowFrame->setBody(StructTy_ShadowFrame_fields, /*isPacked=*/false);
}
@@ -256,6 +256,14 @@
/*Params=*/FuncTy_26_args,
/*isVarArg=*/false);
+std::vector<Type*>FuncTy_27_args;
+FuncTy_27_args.push_back(PointerTy_1);
+FuncTy_27_args.push_back(PointerTy_1);
+FunctionType* FuncTy_27 = FunctionType::get(
+ /*Result=*/PointerTy_1,
+ /*Params=*/FuncTy_27_args,
+ /*isVarArg=*/false);
+
// Function Declarations
@@ -732,6 +740,17 @@
AttrListPtr func_art_get_obj_instance_from_code_PAL;
func_art_get_obj_instance_from_code->setAttributes(func_art_get_obj_instance_from_code_PAL);
+Function* func_art_decode_jobject_in_thread = mod->getFunction("art_decode_jobject_in_thread");
+if (!func_art_decode_jobject_in_thread) {
+func_art_decode_jobject_in_thread = Function::Create(
+ /*Type=*/FuncTy_27,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_decode_jobject_in_thread", mod); // (external, no body)
+func_art_decode_jobject_in_thread->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_decode_jobject_in_thread_PAL;
+func_art_decode_jobject_in_thread->setAttributes(func_art_decode_jobject_in_thread_PAL);
+
Function* func_art_is_assignable_from_code = mod->getFunction("art_is_assignable_from_code");
if (!func_art_is_assignable_from_code) {
func_art_is_assignable_from_code = Function::Create(
diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc
index 0e02846..6cccbe1 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -26,8 +26,11 @@
#include "oat_compilation_unit.h"
#include "object.h"
#include "runtime.h"
+#include "runtime_support_func.h"
#include "utils_llvm.h"
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/BasicBlock.h>
#include <llvm/DerivedTypes.h>
#include <llvm/Function.h>
#include <llvm/Type.h>
@@ -59,8 +62,197 @@
CompiledMethod* JniCompiler::Compile() {
+ bool is_static = method_->IsStatic();
+
CreateFunction();
+ // Set argument name
+ llvm::Function::arg_iterator arg_begin(func_->arg_begin());
+ llvm::Function::arg_iterator arg_end(func_->arg_end());
+ llvm::Function::arg_iterator arg_iter(arg_begin);
+
+ DCHECK_NE(arg_iter, arg_end);
+ arg_iter->setName("method");
+ llvm::Value* method_object_addr = arg_iter++;
+
+ // Actual argument (ignore method)
+ arg_begin = arg_iter;
+
+ // Count the number of Object* arguments
+ uint32_t sirt_size = (is_static ? 1 : 0); // Class object for static function
+ for (unsigned i = 0; arg_iter != arg_end; ++i, ++arg_iter) {
+ arg_iter->setName(StringPrintf("a%u", i));
+ if (arg_iter->getType() == irb_.getJObjectTy()) {
+ ++sirt_size;
+ }
+ }
+
+ // Start to build IR
+ irb_.SetInsertPoint(basic_block_);
+
+ 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);
+
+ // Zero-initialization of the shadow frame
+ llvm::ConstantAggregateZero* zero_initializer =
+ llvm::ConstantAggregateZero::get(shadow_frame_type);
+
+ irb_.CreateStore(zero_initializer, shadow_frame_);
+
+ // Variables for GetElementPtr
+ llvm::Constant* zero = irb_.getInt32(0);
+ llvm::Value* gep_index[] = {
+ zero, // No displacement for shadow frame pointer
+ zero, // Get the %ArtFrame data structure
+ NULL,
+ };
+
+ // Store the method pointer
+ gep_index[2] = irb_.getInt32(2);
+ llvm::Value* method_field_addr = irb_.CreateGEP(shadow_frame_, gep_index);
+ irb_.CreateStore(method_object_addr, method_field_addr);
+
+ // Store the number of the pointer slots
+ gep_index[2] = irb_.getInt32(0);
+ llvm::Value* size_field_addr = irb_.CreateGEP(shadow_frame_, gep_index);
+ llvm::ConstantInt* sirt_size_value = irb_.getInt32(sirt_size);
+ irb_.CreateStore(sirt_size_value, size_field_addr);
+
+ // Push the shadow frame
+ llvm::Value* shadow_frame_upcast = irb_.CreateConstGEP2_32(shadow_frame_, 0, 0);
+ irb_.CreateCall(irb_.GetRuntime(runtime_support::PushShadowFrame), shadow_frame_upcast);
+
+ // Set top of managed stack to the method field in the SIRT
+ StoreToObjectOffset(thread_object_addr, Thread::TopOfManagedStackOffset().Int32Value(),
+ method_field_addr->getType(), method_field_addr);
+
+ // Get JNIEnv
+ llvm::Value* jni_env_object_addr = LoadFromObjectOffset(thread_object_addr,
+ Thread::JniEnvOffset().Int32Value(),
+ irb_.getJObjectTy());
+
+ // Set thread state to kNative
+ StoreToObjectOffset(thread_object_addr, Thread::StateOffset().Int32Value(),
+ irb_.getInt32Ty(), irb_.getInt32(Thread::kNative));
+
+ // Get callee code_addr
+ llvm::Value* code_addr =
+ LoadFromObjectOffset(method_object_addr,
+ Method::NativeMethodOffset().Int32Value(),
+ GetFunctionType(method_idx_, is_static, true)->getPointerTo());
+
+
+ // Load actual parameters
+ std::vector<llvm::Value*> args;
+
+ args.push_back(jni_env_object_addr);
+ //args.push_back(method_object_addr); // method object for callee
+
+ // Store arguments to SIRT, and push back to args
+ gep_index[1] = irb_.getInt32(1); // SIRT
+ size_t sirt_member_index = 0;
+
+ // Push class argument if this method is static
+ if (is_static) {
+ llvm::Value* class_object_addr =
+ LoadFromObjectOffset(method_object_addr,
+ Method::DeclaringClassOffset().Int32Value(),
+ irb_.getJObjectTy());
+ gep_index[2] = irb_.getInt32(sirt_member_index++);
+ 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()));
+ }
+ for (arg_iter = arg_begin; arg_iter != arg_end; ++arg_iter) {
+ if (arg_iter->getType() == irb_.getJObjectTy()) {
+ gep_index[2] = irb_.getInt32(sirt_member_index++);
+ llvm::Value* sirt_field_addr = irb_.CreateGEP(shadow_frame_, gep_index);
+ irb_.CreateStore(arg_iter, sirt_field_addr);
+ // Note null is placed in the SIRT but the jobject passed to the native code must be null
+ // (not a pointer into the SIRT as with regular references).
+ llvm::Value* equal_null = irb_.CreateICmpEQ(arg_iter, irb_.getJNull());
+ llvm::Value* arg =
+ irb_.CreateSelect(equal_null,
+ irb_.getJNull(),
+ irb_.CreateBitCast(sirt_field_addr, irb_.getJObjectTy()));
+ args.push_back(arg);
+ } else {
+ args.push_back(arg_iter);
+ }
+ }
+
+
+ // saved_local_ref_cookie = env->local_ref_cookie
+ llvm::Value* saved_local_ref_cookie =
+ LoadFromObjectOffset(jni_env_object_addr,
+ JNIEnvExt::LocalRefCookieOffset().Int32Value(),
+ irb_.getInt32Ty());
+
+ // env->local_ref_cookie = env->locals.segment_state
+ llvm::Value* segment_state =
+ LoadFromObjectOffset(jni_env_object_addr,
+ JNIEnvExt::SegmentStateOffset().Int32Value(),
+ irb_.getInt32Ty());
+ StoreToObjectOffset(jni_env_object_addr,
+ JNIEnvExt::LocalRefCookieOffset().Int32Value(),
+ irb_.getInt32Ty(),
+ segment_state);
+
+
+ // Call!!!
+ llvm::Value* retval = irb_.CreateCall(code_addr, args);
+
+
+ // Set thread state to kRunnable
+ StoreToObjectOffset(thread_object_addr, Thread::StateOffset().Int32Value(),
+ irb_.getInt32Ty(), 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 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, retval);
+ }
+
+ // env->locals.segment_state = env->local_ref_cookie
+ llvm::Value* local_ref_cookie =
+ LoadFromObjectOffset(jni_env_object_addr,
+ JNIEnvExt::LocalRefCookieOffset().Int32Value(),
+ irb_.getInt32Ty());
+ StoreToObjectOffset(jni_env_object_addr,
+ JNIEnvExt::SegmentStateOffset().Int32Value(),
+ irb_.getInt32Ty(),
+ local_ref_cookie);
+
+ // env->local_ref_cookie = saved_local_ref_cookie
+ StoreToObjectOffset(jni_env_object_addr, JNIEnvExt::LocalRefCookieOffset().Int32Value(),
+ irb_.getInt32Ty(), saved_local_ref_cookie);
+
+ // Pop the shadow frame
+ irb_.CreateCall(irb_.GetRuntime(runtime_support::PopShadowFrame));
+
+ // Return!
+ if (ret_shorty != 'V') {
+ irb_.CreateRet(retval);
+ } else {
+ irb_.CreateRetVoid();
+ }
+
+ // For debug
+ //func_->dump();
+
+ // Verify the generated bitcode
+ llvm::verifyFunction(*func_, llvm::PrintMessageAction);
+
return new CompiledMethod(cunit_->GetInstructionSet(), func_);
}
@@ -71,16 +263,19 @@
// Get function type
llvm::FunctionType* func_type =
- GetFunctionType(method_idx_, method_->IsStatic());
+ GetFunctionType(method_idx_, method_->IsStatic(), false);
// Create function
func_ = llvm::Function::Create(func_type, llvm::Function::ExternalLinkage,
func_name, module_);
+
+ // Create basic block
+ basic_block_ = llvm::BasicBlock::Create(*context_, "B0", func_);
}
llvm::FunctionType* JniCompiler::GetFunctionType(uint32_t method_idx,
- bool is_static) {
+ bool is_static, bool is_target_function) {
// Get method signature
DexFile::MethodId const& method_id = dex_file_->GetMethodId(method_idx);
@@ -96,8 +291,10 @@
args_type.push_back(irb_.getJObjectTy()); // method object pointer
- if (!is_static) {
- args_type.push_back(irb_.getJType('L', kAccurate)); // "this" object pointer
+ if (!is_static || is_target_function) {
+ // "this" object pointer for non-static
+ // "class" object pointer for static
+ args_type.push_back(irb_.getJType('L', kAccurate));
}
for (uint32_t i = 1; i < shorty_size; ++i) {
@@ -107,6 +304,25 @@
return llvm::FunctionType::get(ret_type, args_type, false);
}
+llvm::Value* JniCompiler::LoadFromObjectOffset(llvm::Value* object_addr, int32_t offset,
+ llvm::Type* type) {
+ // Convert offset to llvm::value
+ llvm::Value* llvm_offset = irb_.getPtrEquivInt(offset);
+ // Calculate the value's address
+ llvm::Value* value_addr = irb_.CreatePtrDisp(object_addr, llvm_offset, type->getPointerTo());
+ // Load
+ return irb_.CreateLoad(value_addr);
+}
+
+void JniCompiler::StoreToObjectOffset(llvm::Value* object_addr, int32_t offset,
+ llvm::Type* type, llvm::Value* value) {
+ // Convert offset to llvm::value
+ llvm::Value* llvm_offset = irb_.getPtrEquivInt(offset);
+ // Calculate the value's address
+ llvm::Value* value_addr = irb_.CreatePtrDisp(object_addr, llvm_offset, type->getPointerTo());
+ // Store
+ irb_.CreateStore(value, value_addr);
+}
} // namespace compiler_llvm
} // namespace art
diff --git a/src/compiler_llvm/jni_compiler.h b/src/compiler_llvm/jni_compiler.h
index a6cdd9c..98129d1 100644
--- a/src/compiler_llvm/jni_compiler.h
+++ b/src/compiler_llvm/jni_compiler.h
@@ -33,10 +33,14 @@
}
namespace llvm {
+ class AllocaInst;
class Function;
class FunctionType;
+ class BasicBlock;
class LLVMContext;
class Module;
+ class Type;
+ class Value;
}
namespace art {
@@ -57,9 +61,14 @@
void CreateFunction();
llvm::FunctionType* GetFunctionType(uint32_t method_idx,
- bool is_static);
+ bool is_static, bool is_target_function);
private:
+ llvm::Value* LoadFromObjectOffset(llvm::Value* object_addr, int32_t offset, llvm::Type* type);
+
+ void StoreToObjectOffset(llvm::Value* object_addr, int32_t offset,
+ llvm::Type* type, llvm::Value* value);
+
CompilationUnit* cunit_;
Compiler const* compiler_;
@@ -77,6 +86,9 @@
DexFile const* dex_file_;
Method* method_;
+ llvm::BasicBlock* basic_block_;
+ llvm::AllocaInst* shadow_frame_;
+
llvm::Function* func_;
};
diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h
index 0170148..38d7a89 100644
--- a/src/compiler_llvm/runtime_support_func_list.h
+++ b/src/compiler_llvm/runtime_support_func_list.h
@@ -54,4 +54,5 @@
V(GetObjectInstance, art_get_obj_instance_from_code) \
V(InitializeStaticStorage, art_initialize_static_storage_from_code) \
V(IsExceptionPending, art_is_exception_pending_from_code) \
- V(FindCatchBlock, art_find_catch_block_from_code)
+ V(FindCatchBlock, art_find_catch_block_from_code) \
+ V(DecodeJObjectInThread, art_decode_jobject_in_thread)
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index b6ca288..ff4123a 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -425,6 +425,12 @@
return 0;
}
+Object* art_decode_jobject_in_thread(Thread* thread, jobject obj) {
+ if (thread->IsExceptionPending()) {
+ return NULL;
+ }
+ return thread->DecodeJObject(obj);
+}
//----------------------------------------------------------------------------
// RTTI
@@ -437,7 +443,6 @@
void art_check_cast_from_code(Object* dest_type, Object* src_type) {
}
-
//----------------------------------------------------------------------------
// Runtime Support Function Lookup Callback
//----------------------------------------------------------------------------
diff --git a/src/compiler_llvm/runtime_support_llvm.h b/src/compiler_llvm/runtime_support_llvm.h
index 0b38bb7..b93138a 100644
--- a/src/compiler_llvm/runtime_support_llvm.h
+++ b/src/compiler_llvm/runtime_support_llvm.h
@@ -39,7 +39,6 @@
void art_set_current_thread_from_code(void* thread_object_addr);
-
//----------------------------------------------------------------------------
// Runtime Support Function Lookup Callback
//----------------------------------------------------------------------------