diff options
| author | 2012-02-10 12:01:39 +0800 | |
|---|---|---|
| committer | 2012-02-19 02:50:04 -0800 | |
| commit | f04364f0ff789935d05490ee684f01c3de431780 (patch) | |
| tree | a47070af79126f5aa315480280b7b44ba7205ef1 /src | |
| parent | 7caf37e2aebdb9e6f10f691a8148dd3d3405f157 (diff) | |
Add upcall compiler.
Upcall compiler compiles the invoke stub for native-to-managed
method invocation.
Change-Id: I09fb1e4b3f166e8da5de73e8f39509cd9be6c152
Diffstat (limited to 'src')
| -rw-r--r-- | src/compiled_method.cc | 6 | ||||
| -rw-r--r-- | src/compiled_method.h | 7 | ||||
| -rw-r--r-- | src/compiler.cc | 5 | ||||
| -rw-r--r-- | src/compiler_llvm/compiler_llvm.cc | 13 | ||||
| -rw-r--r-- | src/compiler_llvm/compiler_llvm.h | 3 | ||||
| -rw-r--r-- | src/compiler_llvm/ir_builder.cc | 4 | ||||
| -rw-r--r-- | src/compiler_llvm/ir_builder.h | 14 | ||||
| -rw-r--r-- | src/compiler_llvm/upcall_compiler.cc | 184 | ||||
| -rw-r--r-- | src/compiler_llvm/upcall_compiler.h | 60 |
9 files changed, 296 insertions, 0 deletions
diff --git a/src/compiled_method.cc b/src/compiled_method.cc index 7c7460c777..3c3f6ef5b4 100644 --- a/src/compiled_method.cc +++ b/src/compiled_method.cc @@ -171,10 +171,16 @@ const void* CompiledMethod::CodePointer(const void* code_pointer, } } +#if defined(ART_USE_LLVM_COMPILER) +CompiledInvokeStub::CompiledInvokeStub(llvm::Function* func) : func_(func) { + CHECK_NE(func, static_cast<llvm::Function*>(NULL)); +} +#else CompiledInvokeStub::CompiledInvokeStub(std::vector<uint8_t>& code) { CHECK_NE(code.size(), 0U); code_ = code; } +#endif CompiledInvokeStub::~CompiledInvokeStub() {} diff --git a/src/compiled_method.h b/src/compiled_method.h index 834ead0ad1..d11f0e4478 100644 --- a/src/compiled_method.h +++ b/src/compiled_method.h @@ -98,10 +98,17 @@ class CompiledMethod { class CompiledInvokeStub { public: +#if defined(ART_USE_LLVM_COMPILER) + explicit CompiledInvokeStub(llvm::Function* func); +#else explicit CompiledInvokeStub(std::vector<uint8_t>& code); +#endif ~CompiledInvokeStub(); const std::vector<uint8_t>& GetCode() const; private: +#if defined(ART_USE_LLVM_COMPILER) + llvm::Function* func_; +#endif std::vector<uint8_t> code_; }; diff --git a/src/compiler.cc b/src/compiler.cc index 08c6cc437f..c9177362da 100644 --- a/src/compiler.cc +++ b/src/compiler.cc @@ -988,6 +988,9 @@ void Compiler::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access bool is_static = (access_flags & kAccStatic) != 0; const CompiledInvokeStub* compiled_invoke_stub = FindInvokeStub(is_static, shorty); if (compiled_invoke_stub == NULL) { +#if defined(ART_USE_LLVM_COMPILER) + compiled_invoke_stub = compiler_llvm_->CreateInvokeStub(is_static, shorty); +#else if (instruction_set_ == kX86) { compiled_invoke_stub = ::art::x86::X86CreateInvokeStub(is_static, shorty); } else { @@ -995,6 +998,8 @@ void Compiler::CompileMethod(const DexFile::CodeItem* code_item, uint32_t access // Generates invocation stub using ARM instruction set compiled_invoke_stub = ::art::arm::ArmCreateInvokeStub(is_static, shorty); } +#endif + CHECK(compiled_invoke_stub != NULL); InsertInvokeStub(is_static, shorty, compiled_invoke_stub); } diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc index 8a9b3622e5..21a7bb95e9 100644 --- a/src/compiler_llvm/compiler_llvm.cc +++ b/src/compiler_llvm/compiler_llvm.cc @@ -19,6 +19,7 @@ #include "compiler.h" #include "ir_builder.h" #include "method_compiler.h" +#include "upcall_compiler.h" #include <llvm/ADT/OwningPtr.h> #include <llvm/Bitcode/ReaderWriter.h> @@ -104,5 +105,17 @@ CompilerLLVM::CompileDexMethod(DexFile::CodeItem const* code_item, } +CompiledInvokeStub* CompilerLLVM::CreateInvokeStub(bool is_static, + char const *shorty) { + + MutexLock GUARD(compiler_lock_); + + UniquePtr<UpcallCompiler> upcall_compiler( + new UpcallCompiler(insn_set_, *compiler_)); + + return upcall_compiler->CreateStub(is_static, shorty); +} + + } // namespace compiler_llvm } // namespace art diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h index 0de28f5309..f39f686bf6 100644 --- a/src/compiler_llvm/compiler_llvm.h +++ b/src/compiler_llvm/compiler_llvm.h @@ -27,6 +27,7 @@ namespace art { class ClassLoader; + class CompiledInvokeStub; class CompiledMethod; class Compiler; } @@ -83,6 +84,8 @@ class CompilerLLVM { ClassLoader const* class_loader, DexFile const& dex_file); + CompiledInvokeStub* CreateInvokeStub(bool is_static, char const *shorty); + private: Compiler* compiler_; diff --git a/src/compiler_llvm/ir_builder.cc b/src/compiler_llvm/ir_builder.cc index b2c795b9c4..4c432718ac 100644 --- a/src/compiler_llvm/ir_builder.cc +++ b/src/compiler_llvm/ir_builder.cc @@ -35,6 +35,10 @@ IRBuilder::IRBuilder(llvm::LLVMContext& context, llvm::Module& module) CHECK_NE(jobject_struct_type, static_cast<llvm::Type*>(NULL)); jobject_type_ = jobject_struct_type->getPointerTo(); + // Create JEnv* type + llvm::Type* jenv_struct_type = llvm::StructType::create(context, "JEnv"); + jenv_type_ = jenv_struct_type->getPointerTo(); + // Load the runtime support function declaration from module InitRuntimeSupportFuncDecl(module); } diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h index 617ed8de86..b38c7b0099 100644 --- a/src/compiler_llvm/ir_builder.h +++ b/src/compiler_llvm/ir_builder.h @@ -162,6 +162,18 @@ class IRBuilder : public LLVMIRBuilder { return jobject_type_; } + llvm::PointerType* getJEnvTy() { + return jenv_type_; + } + + llvm::Type* getJValueTy() { + // NOTE: JValue is an union type, which may contains boolean, byte, char, + // short, int, long, float, double, Object. However, LLVM itself does + // not support union type, so we have to return a type with biggest size, + // then bitcast it before we use it. + return getJLongTy(); + } + //-------------------------------------------------------------------------- // Constant Value Helper Function @@ -266,6 +278,8 @@ class IRBuilder : public LLVMIRBuilder { private: llvm::PointerType* jobject_type_; + llvm::PointerType* jenv_type_; + llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID]; }; diff --git a/src/compiler_llvm/upcall_compiler.cc b/src/compiler_llvm/upcall_compiler.cc new file mode 100644 index 0000000000..308790a71e --- /dev/null +++ b/src/compiler_llvm/upcall_compiler.cc @@ -0,0 +1,184 @@ +/* + * 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 "upcall_compiler.h" + +#include "compiler.h" +#include "compiled_method.h" +#include "compiler_llvm.h" +#include "ir_builder.h" +#include "logging.h" +#include "object.h" +#include "runtime_support_func.h" + +#include <llvm/Analysis/Verifier.h> +#include <llvm/BasicBlock.h> +#include <llvm/Function.h> +#include <llvm/GlobalVariable.h> +#include <llvm/Intrinsics.h> + +#include <string> +#include <string.h> + +namespace art { +namespace compiler_llvm { + +using namespace runtime_support; + + +UpcallCompiler::UpcallCompiler(InstructionSet insn_set, + Compiler& compiler) +: insn_set_(insn_set), compiler_(&compiler), + compiler_llvm_(compiler_->GetCompilerLLVM()), + module_(compiler_llvm_->GetModule()), + context_(compiler_llvm_->GetLLVMContext()), + irb_(*compiler_llvm_->GetIRBuilder()) { +} + + +CompiledInvokeStub* UpcallCompiler::CreateStub(bool is_static, + char const* shorty) { + + CHECK_NE(shorty, static_cast<char const*>(NULL)); + size_t shorty_size = strlen(shorty); + + // Function name + std::string func_name; + + if (is_static) { + StringAppendF(&func_name, "ArtSUpcall_%s", shorty); + } else { + StringAppendF(&func_name, "ArtUpcall_%s", shorty); + } + + // Get argument types + llvm::Type* arg_types[] = { + irb_.getJEnvTy(), // JEnv* + irb_.getJObjectTy(), // Method object pointer + irb_.getJObjectTy(), // "this" object pointer (NULL for static) + irb_.getJObjectTy(), // Thread object pointer + irb_.getJValueTy()->getPointerTo(), + irb_.getJValueTy()->getPointerTo(), + }; + + // Function type + llvm::FunctionType* func_type = + llvm::FunctionType::get(irb_.getVoidTy(), arg_types, false); + + // Create function + llvm::Function* func = + llvm::Function::Create(func_type, llvm::Function::ExternalLinkage, + func_name, module_); + + + // Create basic block for the body of this function + llvm::BasicBlock* block_body = + llvm::BasicBlock::Create(*context_, "upcall", func); + + irb_.SetInsertPoint(block_body); + + // Actual arguments + llvm::Function::arg_iterator arg_iter = func->arg_begin(); + + arg_iter++; // jenv_addr + llvm::Value* method_object_addr = arg_iter++; + llvm::Value* callee_this_addr = arg_iter++; + llvm::Value* thread_object_addr = arg_iter++; + llvm::Value* actual_args_array_addr = arg_iter++; + llvm::Value* retval_addr = arg_iter++; + + // Setup thread pointer + irb_.CreateCall(irb_.GetRuntime(SetCurrentThread), thread_object_addr); + + // Accurate function type + llvm::Type* accurate_ret_type = irb_.getJType(shorty[0], kAccurate); + + std::vector<llvm::Type*> accurate_arg_types; + + accurate_arg_types.push_back(irb_.getJObjectTy()); // method object pointer + + if (!is_static) { + accurate_arg_types.push_back(irb_.getJObjectTy()); + } + + for (size_t i = 1; i < shorty_size; ++i) { + accurate_arg_types.push_back(irb_.getJType(shorty[i], kAccurate)); + } + + llvm::FunctionType* accurate_func_type = + llvm::FunctionType::get(accurate_ret_type, accurate_arg_types, false); + + // Load actual arguments + std::vector<llvm::Value*> args; + + args.push_back(method_object_addr); + + if (!is_static) { + args.push_back(callee_this_addr); + } + + for (size_t i = 1; i < shorty_size; ++i) { + char arg_shorty = shorty[i]; + + if (arg_shorty == 'Z' || arg_shorty == 'B' || arg_shorty == 'C' || + arg_shorty == 'S' || arg_shorty == 'I' || arg_shorty == 'J' || + arg_shorty == 'F' || arg_shorty == 'D' || arg_shorty == 'L') { + + llvm::Type* arg_type = + irb_.getJType(shorty[i], kAccurate)->getPointerTo(); + + llvm::Value* arg_jvalue_addr = + irb_.CreateConstGEP1_32(actual_args_array_addr, i - 1); + + llvm::Value* arg_addr = irb_.CreateBitCast(arg_jvalue_addr, arg_type); + + args.push_back(irb_.CreateLoad(arg_addr)); + + } else { + LOG(ERROR) << "Unexpected arg shorty for invoke stub: " << shorty[i]; + } + } + + // Invoke managed method now! + llvm::Value* code_field_offset_value = + irb_.getPtrEquivInt(Method::GetCodeOffset().Int32Value()); + + llvm::Value* code_field_addr = + irb_.CreatePtrDisp(method_object_addr, code_field_offset_value, + accurate_func_type->getPointerTo()->getPointerTo()); + + llvm::Value* code_addr = irb_.CreateLoad(code_field_addr); + + llvm::Value* retval = irb_.CreateCall(code_addr, args); + + // Store the returned value + if (shorty[0] != 'V') { + llvm::Value* ret_addr = + irb_.CreateBitCast(retval_addr, accurate_ret_type->getPointerTo()); + + irb_.CreateStore(retval, ret_addr); + } + + irb_.CreateRetVoid(); + + llvm::verifyFunction(*func, llvm::PrintMessageAction); + + return new CompiledInvokeStub(func); +} + + +} // namespace compiler_llvm +} // namespace art diff --git a/src/compiler_llvm/upcall_compiler.h b/src/compiler_llvm/upcall_compiler.h new file mode 100644 index 0000000000..426919efc0 --- /dev/null +++ b/src/compiler_llvm/upcall_compiler.h @@ -0,0 +1,60 @@ +/* + * 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_UPCALL_COMPILER_H_ +#define ART_SRC_COMPILER_LLVM_UPCALL_COMPILER_H_ + +#include "constants.h" + +#include <stdint.h> + +namespace art { + class CompiledInvokeStub; + class Compiler; +} + +namespace llvm { + class LLVMContext; + class Module; +} + +namespace art { +namespace compiler_llvm { + +class CompilerLLVM; +class IRBuilder; + +class UpcallCompiler { + public: + UpcallCompiler(InstructionSet insn_set, Compiler& compiler); + + CompiledInvokeStub* CreateStub(bool is_static, char const* shorty); + + private: + InstructionSet insn_set_; + Compiler const* compiler_; + CompilerLLVM* compiler_llvm_; + llvm::Module* module_; + llvm::LLVMContext* context_; + IRBuilder& irb_; +}; + + +} // namespace compiler_llvm +} // namespace art + + +#endif // ART_SRC_COMPILER_LLVM_UPCALL_COMPILER_H_ |