blob: 37dc9816a6f7739d0c3630ca63ed6648f0b52088 [file] [log] [blame]
Logan Chienf04364f2012-02-10 12:01:39 +08001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "upcall_compiler.h"
18
Logan Chien8b977d32012-02-21 19:14:55 +080019#include "compilation_unit.h"
Logan Chienf04364f2012-02-10 12:01:39 +080020#include "compiled_method.h"
Logan Chien8b977d32012-02-21 19:14:55 +080021#include "compiler.h"
Logan Chienf04364f2012-02-10 12:01:39 +080022#include "compiler_llvm.h"
23#include "ir_builder.h"
24#include "logging.h"
25#include "object.h"
26#include "runtime_support_func.h"
Logan Chien937105a2012-04-02 02:37:37 +080027#include "utils_llvm.h"
Logan Chienf04364f2012-02-10 12:01:39 +080028
Logan Chienf04364f2012-02-10 12:01:39 +080029#include <llvm/BasicBlock.h>
30#include <llvm/Function.h>
31#include <llvm/GlobalVariable.h>
32#include <llvm/Intrinsics.h>
33
34#include <string>
35#include <string.h>
36
37namespace art {
38namespace compiler_llvm {
39
40using namespace runtime_support;
41
42
Logan Chien8b977d32012-02-21 19:14:55 +080043UpcallCompiler::UpcallCompiler(CompilationUnit* cunit, Compiler& compiler)
44: cunit_(cunit), compiler_(&compiler), module_(cunit_->GetModule()),
Logan Chien937105a2012-04-02 02:37:37 +080045 context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()),
46 elf_func_idx_(cunit_->AcquireUniqueElfFuncIndex()) {
Logan Chienf04364f2012-02-10 12:01:39 +080047}
48
49
50CompiledInvokeStub* UpcallCompiler::CreateStub(bool is_static,
51 char const* shorty) {
52
53 CHECK_NE(shorty, static_cast<char const*>(NULL));
54 size_t shorty_size = strlen(shorty);
55
56 // Function name
Logan Chien937105a2012-04-02 02:37:37 +080057 std::string func_name(ElfFuncName(elf_func_idx_));
Logan Chienf04364f2012-02-10 12:01:39 +080058
59 // Get argument types
60 llvm::Type* arg_types[] = {
Logan Chienf04364f2012-02-10 12:01:39 +080061 irb_.getJObjectTy(), // Method object pointer
62 irb_.getJObjectTy(), // "this" object pointer (NULL for static)
63 irb_.getJObjectTy(), // Thread object pointer
64 irb_.getJValueTy()->getPointerTo(),
65 irb_.getJValueTy()->getPointerTo(),
66 };
67
68 // Function type
69 llvm::FunctionType* func_type =
70 llvm::FunctionType::get(irb_.getVoidTy(), arg_types, false);
71
72 // Create function
73 llvm::Function* func =
74 llvm::Function::Create(func_type, llvm::Function::ExternalLinkage,
75 func_name, module_);
76
77
78 // Create basic block for the body of this function
79 llvm::BasicBlock* block_body =
80 llvm::BasicBlock::Create(*context_, "upcall", func);
81
82 irb_.SetInsertPoint(block_body);
83
84 // Actual arguments
85 llvm::Function::arg_iterator arg_iter = func->arg_begin();
86
Logan Chienf04364f2012-02-10 12:01:39 +080087 llvm::Value* method_object_addr = arg_iter++;
88 llvm::Value* callee_this_addr = arg_iter++;
89 llvm::Value* thread_object_addr = arg_iter++;
90 llvm::Value* actual_args_array_addr = arg_iter++;
91 llvm::Value* retval_addr = arg_iter++;
92
93 // Setup thread pointer
94 irb_.CreateCall(irb_.GetRuntime(SetCurrentThread), thread_object_addr);
95
96 // Accurate function type
97 llvm::Type* accurate_ret_type = irb_.getJType(shorty[0], kAccurate);
98
99 std::vector<llvm::Type*> accurate_arg_types;
100
101 accurate_arg_types.push_back(irb_.getJObjectTy()); // method object pointer
102
103 if (!is_static) {
104 accurate_arg_types.push_back(irb_.getJObjectTy());
105 }
106
107 for (size_t i = 1; i < shorty_size; ++i) {
108 accurate_arg_types.push_back(irb_.getJType(shorty[i], kAccurate));
109 }
110
111 llvm::FunctionType* accurate_func_type =
112 llvm::FunctionType::get(accurate_ret_type, accurate_arg_types, false);
113
114 // Load actual arguments
115 std::vector<llvm::Value*> args;
116
117 args.push_back(method_object_addr);
118
119 if (!is_static) {
120 args.push_back(callee_this_addr);
121 }
122
123 for (size_t i = 1; i < shorty_size; ++i) {
124 char arg_shorty = shorty[i];
125
126 if (arg_shorty == 'Z' || arg_shorty == 'B' || arg_shorty == 'C' ||
127 arg_shorty == 'S' || arg_shorty == 'I' || arg_shorty == 'J' ||
128 arg_shorty == 'F' || arg_shorty == 'D' || arg_shorty == 'L') {
129
130 llvm::Type* arg_type =
131 irb_.getJType(shorty[i], kAccurate)->getPointerTo();
132
133 llvm::Value* arg_jvalue_addr =
134 irb_.CreateConstGEP1_32(actual_args_array_addr, i - 1);
135
136 llvm::Value* arg_addr = irb_.CreateBitCast(arg_jvalue_addr, arg_type);
137
TDYa127aba61122012-05-04 18:28:36 -0700138 args.push_back(irb_.CreateLoad(arg_addr, kTBAAStackTemp));
Logan Chienf04364f2012-02-10 12:01:39 +0800139
140 } else {
Shih-wei Liao90d50992012-02-19 03:32:05 -0800141 LOG(FATAL) << "Unexpected arg shorty for invoke stub: " << shorty[i];
Logan Chienf04364f2012-02-10 12:01:39 +0800142 }
143 }
144
145 // Invoke managed method now!
TDYa1270b686e52012-04-09 22:43:35 -0700146 // TODO: If we solve the trampoline related problems, we can just get the code address and call.
147#if 0
Logan Chienf04364f2012-02-10 12:01:39 +0800148 llvm::Value* code_field_offset_value =
149 irb_.getPtrEquivInt(Method::GetCodeOffset().Int32Value());
150
151 llvm::Value* code_field_addr =
152 irb_.CreatePtrDisp(method_object_addr, code_field_offset_value,
153 accurate_func_type->getPointerTo()->getPointerTo());
154
TDYa1278ca10052012-05-05 19:57:06 -0700155 llvm::Value* code_addr = irb_.CreateLoad(code_field_addr, kTBAAJRuntime);
TDYa1270b686e52012-04-09 22:43:35 -0700156#else
157 llvm::Value* result = irb_.CreateCall(irb_.GetRuntime(FixStub), method_object_addr);
158 llvm::Value* code_addr = irb_.CreatePointerCast(result, accurate_func_type->getPointerTo());
159
160 // Exception unwind.
161 llvm::Value* exception_pending = irb_.CreateCall(irb_.GetRuntime(IsExceptionPending));
162 llvm::BasicBlock* block_unwind = llvm::BasicBlock::Create(*context_, "exception_unwind", func);
163 llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "cont", func);
164 irb_.CreateCondBr(exception_pending, block_unwind, block_cont);
165 irb_.SetInsertPoint(block_unwind);
166 irb_.CreateRetVoid();
167 irb_.SetInsertPoint(block_cont);
168#endif
Logan Chienf04364f2012-02-10 12:01:39 +0800169
170 llvm::Value* retval = irb_.CreateCall(code_addr, args);
171
172 // Store the returned value
173 if (shorty[0] != 'V') {
174 llvm::Value* ret_addr =
175 irb_.CreateBitCast(retval_addr, accurate_ret_type->getPointerTo());
176
TDYa127aba61122012-05-04 18:28:36 -0700177 irb_.CreateStore(retval, ret_addr, kTBAAStackTemp);
Logan Chienf04364f2012-02-10 12:01:39 +0800178 }
179
180 irb_.CreateRetVoid();
181
Logan Chien8b977d32012-02-21 19:14:55 +0800182 // Verify the generated function
TDYa127853cd092012-04-21 22:15:31 -0700183 VERIFY_LLVM_FUNCTION(*func);
Logan Chienf04364f2012-02-10 12:01:39 +0800184
Logan Chien8b977d32012-02-21 19:14:55 +0800185 // Add the memory usage approximation of the compilation unit
TDYa1270200d072012-04-17 20:55:08 -0700186 cunit_->AddMemUsageApproximation((shorty_size * 3 + 8) * 50);
Logan Chien8b977d32012-02-21 19:14:55 +0800187 // NOTE: We will emit 3 LLVM instructions per shorty for the argument,
188 // plus 3 for pointer arithmetic, and 5 for code_addr, retval, ret_addr,
189 // store ret_addr, and ret_void. Beside, we guess that we have to use
190 // 50 bytes to represent one LLVM instruction.
191
Logan Chien937105a2012-04-02 02:37:37 +0800192 return new CompiledInvokeStub(cunit_->GetElfIndex(), elf_func_idx_);
Logan Chienf04364f2012-02-10 12:01:39 +0800193}
194
195
196} // namespace compiler_llvm
197} // namespace art