diff options
| author | 2012-06-03 07:15:25 -0700 | |
|---|---|---|
| committer | 2012-06-03 09:12:30 -0700 | |
| commit | eead4ac17ec9d5e750269a7d36bf6c36a6fd60c6 (patch) | |
| tree | 911602ed79cde974cba5b6a18d57fc27987436ef /src/compiler_llvm/stub_compiler.cc | |
| parent | de479be99328d2113bf483e082c9ecf235a34d69 (diff) | |
Implement proxy stub for compiler_llvm.
Change-Id: Id8ba59c62795d885a18b3cc634e7ef370a2d2f97
Diffstat (limited to 'src/compiler_llvm/stub_compiler.cc')
| -rw-r--r-- | src/compiler_llvm/stub_compiler.cc | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/src/compiler_llvm/stub_compiler.cc b/src/compiler_llvm/stub_compiler.cc new file mode 100644 index 0000000000..2cf5141d6e --- /dev/null +++ b/src/compiler_llvm/stub_compiler.cc @@ -0,0 +1,270 @@ +/* + * 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 "stub_compiler.h" + +#include "compilation_unit.h" +#include "compiled_method.h" +#include "compiler.h" +#include "compiler_llvm.h" +#include "ir_builder.h" +#include "logging.h" +#include "object.h" +#include "runtime_support_func.h" +#include "utils_llvm.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; + + +StubCompiler::StubCompiler(CompilationUnit* cunit, Compiler& compiler) +: cunit_(cunit), compiler_(&compiler), module_(cunit_->GetModule()), + context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()) { +} + + +uint16_t StubCompiler::CreateInvokeStub(bool is_static, + char const* shorty) { + uint16_t elf_func_idx = cunit_->AcquireUniqueElfFuncIndex(); + + CHECK_NE(shorty, static_cast<char const*>(NULL)); + size_t shorty_size = strlen(shorty); + + // Function name + std::string func_name(ElfFuncName(elf_func_idx)); + + // Get argument types + llvm::Type* arg_types[] = { + 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(); + + 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_.Runtime().EmitSetCurrentThread(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, kTBAAStackTemp)); + + } else { + LOG(FATAL) << "Unexpected arg shorty for invoke stub: " << shorty[i]; + } + } + + // Invoke managed method now! + // TODO: If we solve the trampoline related problems, we can just get the code address and call. +#if 0 + 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, kTBAAJRuntime); +#else + llvm::Value* result = irb_.CreateCall(irb_.GetRuntime(FixStub), method_object_addr); + llvm::Value* code_addr = irb_.CreatePointerCast(result, accurate_func_type->getPointerTo()); + + // Exception unwind. + llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending(); + llvm::BasicBlock* block_unwind = llvm::BasicBlock::Create(*context_, "exception_unwind", func); + llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "cont", func); + irb_.CreateCondBr(exception_pending, block_unwind, block_cont); + irb_.SetInsertPoint(block_unwind); + irb_.CreateRetVoid(); + irb_.SetInsertPoint(block_cont); +#endif + + 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, kTBAAStackTemp); + } + + irb_.CreateRetVoid(); + + // Verify the generated function + VERIFY_LLVM_FUNCTION(*func); + + // Add the memory usage approximation of the compilation unit + cunit_->AddMemUsageApproximation((shorty_size * 3 + 8) * 50); + // NOTE: We will emit 3 LLVM instructions per shorty for the argument, + // plus 3 for pointer arithmetic, and 5 for code_addr, retval, ret_addr, + // store ret_addr, and ret_void. Beside, we guess that we have to use + // 50 bytes to represent one LLVM instruction. + + return elf_func_idx; +} + +uint16_t StubCompiler::CreateProxyStub(bool is_static, + char const* shorty) { + // Static method dosen't need proxy stub. + if (is_static) { + return NULL; + } + + CHECK_NE(shorty, static_cast<char const*>(NULL)); + size_t shorty_size = strlen(shorty); + + uint16_t elf_func_idx = cunit_->AcquireUniqueElfFuncIndex(); + + // Function name + std::string func_name(ElfFuncName(elf_func_idx)); + + // 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 + accurate_arg_types.push_back(irb_.getJObjectTy()); // this + 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); + + // Create function + llvm::Function* func = + llvm::Function::Create(accurate_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_, "proxy", func); + irb_.SetInsertPoint(block_body); + + // JValue for proxy return + llvm::AllocaInst* jvalue_temp = irb_.CreateAlloca(irb_.getJValueTy()); + + // Load actual arguments + llvm::Function::arg_iterator arg_iter = func->arg_begin(); + std::vector<llvm::Value*> args; + args.push_back(arg_iter++); // method + args.push_back(arg_iter++); // this + args.push_back(irb_.Runtime().EmitGetCurrentThread()); // thread + for (size_t i = 1; i < shorty_size; ++i) { + args.push_back(arg_iter++); + } + if (shorty[0] != 'V') { + args.push_back(jvalue_temp); + } + + // Call ProxyInvokeHandler + // TODO: Partial inline ProxyInvokeHandler, don't use VarArg. + irb_.CreateCall(irb_.GetRuntime(ProxyInvokeHandler), args); + if (shorty[0] != 'V') { + llvm::Value* result_addr = + irb_.CreateBitCast(jvalue_temp, accurate_ret_type->getPointerTo()); + llvm::Value* retval = irb_.CreateLoad(result_addr, kTBAAStackTemp); + irb_.CreateRet(retval); + } else { + irb_.CreateRetVoid(); + } + + // Verify the generated function + VERIFY_LLVM_FUNCTION(*func); + + // Add the memory usage approximation of the compilation unit + cunit_->AddMemUsageApproximation((shorty_size + 2) * 50); + + return elf_func_idx; +} + + +} // namespace compiler_llvm +} // namespace art |