blob: be4c00dc2fe18f4c4ff393e6ee5d03a0bce2baa3 [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
19#include "compiler.h"
20#include "compiled_method.h"
21#include "compiler_llvm.h"
22#include "ir_builder.h"
23#include "logging.h"
24#include "object.h"
25#include "runtime_support_func.h"
26
27#include <llvm/Analysis/Verifier.h>
28#include <llvm/BasicBlock.h>
29#include <llvm/Function.h>
30#include <llvm/GlobalVariable.h>
31#include <llvm/Intrinsics.h>
32
33#include <string>
34#include <string.h>
35
36namespace art {
37namespace compiler_llvm {
38
39using namespace runtime_support;
40
41
42UpcallCompiler::UpcallCompiler(InstructionSet insn_set,
43 Compiler& compiler)
44: insn_set_(insn_set), compiler_(&compiler),
45 compiler_llvm_(compiler_->GetCompilerLLVM()),
46 module_(compiler_llvm_->GetModule()),
47 context_(compiler_llvm_->GetLLVMContext()),
48 irb_(*compiler_llvm_->GetIRBuilder()) {
49}
50
51
52CompiledInvokeStub* UpcallCompiler::CreateStub(bool is_static,
53 char const* shorty) {
54
55 CHECK_NE(shorty, static_cast<char const*>(NULL));
56 size_t shorty_size = strlen(shorty);
57
58 // Function name
59 std::string func_name;
60
61 if (is_static) {
62 StringAppendF(&func_name, "ArtSUpcall_%s", shorty);
63 } else {
64 StringAppendF(&func_name, "ArtUpcall_%s", shorty);
65 }
66
67 // Get argument types
68 llvm::Type* arg_types[] = {
Logan Chienf04364f2012-02-10 12:01:39 +080069 irb_.getJObjectTy(), // Method object pointer
70 irb_.getJObjectTy(), // "this" object pointer (NULL for static)
71 irb_.getJObjectTy(), // Thread object pointer
72 irb_.getJValueTy()->getPointerTo(),
73 irb_.getJValueTy()->getPointerTo(),
74 };
75
76 // Function type
77 llvm::FunctionType* func_type =
78 llvm::FunctionType::get(irb_.getVoidTy(), arg_types, false);
79
80 // Create function
81 llvm::Function* func =
82 llvm::Function::Create(func_type, llvm::Function::ExternalLinkage,
83 func_name, module_);
84
85
86 // Create basic block for the body of this function
87 llvm::BasicBlock* block_body =
88 llvm::BasicBlock::Create(*context_, "upcall", func);
89
90 irb_.SetInsertPoint(block_body);
91
92 // Actual arguments
93 llvm::Function::arg_iterator arg_iter = func->arg_begin();
94
Logan Chienf04364f2012-02-10 12:01:39 +080095 llvm::Value* method_object_addr = arg_iter++;
96 llvm::Value* callee_this_addr = arg_iter++;
97 llvm::Value* thread_object_addr = arg_iter++;
98 llvm::Value* actual_args_array_addr = arg_iter++;
99 llvm::Value* retval_addr = arg_iter++;
100
101 // Setup thread pointer
102 irb_.CreateCall(irb_.GetRuntime(SetCurrentThread), thread_object_addr);
103
104 // Accurate function type
105 llvm::Type* accurate_ret_type = irb_.getJType(shorty[0], kAccurate);
106
107 std::vector<llvm::Type*> accurate_arg_types;
108
109 accurate_arg_types.push_back(irb_.getJObjectTy()); // method object pointer
110
111 if (!is_static) {
112 accurate_arg_types.push_back(irb_.getJObjectTy());
113 }
114
115 for (size_t i = 1; i < shorty_size; ++i) {
116 accurate_arg_types.push_back(irb_.getJType(shorty[i], kAccurate));
117 }
118
119 llvm::FunctionType* accurate_func_type =
120 llvm::FunctionType::get(accurate_ret_type, accurate_arg_types, false);
121
122 // Load actual arguments
123 std::vector<llvm::Value*> args;
124
125 args.push_back(method_object_addr);
126
127 if (!is_static) {
128 args.push_back(callee_this_addr);
129 }
130
131 for (size_t i = 1; i < shorty_size; ++i) {
132 char arg_shorty = shorty[i];
133
134 if (arg_shorty == 'Z' || arg_shorty == 'B' || arg_shorty == 'C' ||
135 arg_shorty == 'S' || arg_shorty == 'I' || arg_shorty == 'J' ||
136 arg_shorty == 'F' || arg_shorty == 'D' || arg_shorty == 'L') {
137
138 llvm::Type* arg_type =
139 irb_.getJType(shorty[i], kAccurate)->getPointerTo();
140
141 llvm::Value* arg_jvalue_addr =
142 irb_.CreateConstGEP1_32(actual_args_array_addr, i - 1);
143
144 llvm::Value* arg_addr = irb_.CreateBitCast(arg_jvalue_addr, arg_type);
145
146 args.push_back(irb_.CreateLoad(arg_addr));
147
148 } else {
Shih-wei Liao90d50992012-02-19 03:32:05 -0800149 LOG(FATAL) << "Unexpected arg shorty for invoke stub: " << shorty[i];
Logan Chienf04364f2012-02-10 12:01:39 +0800150 }
151 }
152
153 // Invoke managed method now!
154 llvm::Value* code_field_offset_value =
155 irb_.getPtrEquivInt(Method::GetCodeOffset().Int32Value());
156
157 llvm::Value* code_field_addr =
158 irb_.CreatePtrDisp(method_object_addr, code_field_offset_value,
159 accurate_func_type->getPointerTo()->getPointerTo());
160
161 llvm::Value* code_addr = irb_.CreateLoad(code_field_addr);
162
163 llvm::Value* retval = irb_.CreateCall(code_addr, args);
164
165 // Store the returned value
166 if (shorty[0] != 'V') {
167 llvm::Value* ret_addr =
168 irb_.CreateBitCast(retval_addr, accurate_ret_type->getPointerTo());
169
170 irb_.CreateStore(retval, ret_addr);
171 }
172
173 irb_.CreateRetVoid();
174
175 llvm::verifyFunction(*func, llvm::PrintMessageAction);
176
177 return new CompiledInvokeStub(func);
178}
179
180
181} // namespace compiler_llvm
182} // namespace art