blob: dbcbe89034d0b365fa1a14580770aa201adcaeb9 [file] [log] [blame]
TDYa127d668a062012-04-13 12:36:57 -07001/*
2 * Copyright (C) 2011 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 "runtime_support_builder.h"
18
Mathieu Chartier8ed6d612012-10-09 14:39:28 -070019#include "gc/card_table.h"
TDYa127d668a062012-04-13 12:36:57 -070020#include "ir_builder.h"
TDYa127b08ed122012-06-05 23:51:19 -070021#include "monitor.h"
22#include "object.h"
TDYa127d668a062012-04-13 12:36:57 -070023#include "thread.h"
24
25#include <llvm/DerivedTypes.h>
26#include <llvm/Function.h>
27#include <llvm/Module.h>
28#include <llvm/Type.h>
29
30using namespace llvm;
31
32namespace art {
33namespace compiler_llvm {
34
35using namespace runtime_support;
36
37
38RuntimeSupportBuilder::RuntimeSupportBuilder(llvm::LLVMContext& context,
39 llvm::Module& module,
40 IRBuilder& irb)
41 : context_(context), module_(module), irb_(irb)
42{
TDYa12783bb6622012-04-17 02:20:34 -070043 memset(target_runtime_support_func_, 0, sizeof(target_runtime_support_func_));
TDYa127d668a062012-04-13 12:36:57 -070044#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
45 do { \
46 llvm::Function* fn = module_.getFunction(#NAME); \
47 DCHECK_NE(fn, (void*)NULL) << "Function not found: " << #NAME; \
TDYa127de479be2012-05-31 08:03:26 -070048 runtime_support_func_decls_[runtime_support::ID] = fn; \
TDYa127d668a062012-04-13 12:36:57 -070049 } while (0);
50
51#include "runtime_support_func_list.h"
52 RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
53#undef RUNTIME_SUPPORT_FUNC_LIST
54#undef GET_RUNTIME_SUPPORT_FUNC_DECL
55}
56
TDYa127de479be2012-05-31 08:03:26 -070057
58/* Thread */
59
60llvm::Value* RuntimeSupportBuilder::EmitGetCurrentThread() {
61 Function* func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
TDYa1279a129452012-07-19 03:10:08 -070062 CallInst* call_inst = irb_.CreateCall(func);
TDYa127de479be2012-05-31 08:03:26 -070063 call_inst->setOnlyReadsMemory();
64 irb_.SetTBAA(call_inst, kTBAAConstJObject);
65 return call_inst;
66}
67
68llvm::Value* RuntimeSupportBuilder::EmitLoadFromThreadOffset(int64_t offset, llvm::Type* type,
69 TBAASpecialType s_ty) {
TDYa1279a129452012-07-19 03:10:08 -070070 Value* thread = EmitGetCurrentThread();
TDYa127de479be2012-05-31 08:03:26 -070071 return irb_.LoadFromObjectOffset(thread, offset, type, s_ty);
72}
73
74void RuntimeSupportBuilder::EmitStoreToThreadOffset(int64_t offset, llvm::Value* value,
75 TBAASpecialType s_ty) {
TDYa1279a129452012-07-19 03:10:08 -070076 Value* thread = EmitGetCurrentThread();
TDYa127de479be2012-05-31 08:03:26 -070077 irb_.StoreToObjectOffset(thread, offset, value, s_ty);
78}
79
TDYa127c1478262012-06-20 20:22:27 -070080llvm::Value* RuntimeSupportBuilder::EmitSetCurrentThread(llvm::Value* thread) {
TDYa127de479be2012-05-31 08:03:26 -070081 Function* func = GetRuntimeSupportFunction(runtime_support::SetCurrentThread);
TDYa127c1478262012-06-20 20:22:27 -070082 return irb_.CreateCall(func, thread);
TDYa127de479be2012-05-31 08:03:26 -070083}
84
85
86/* ShadowFrame */
87
88llvm::Value* RuntimeSupportBuilder::EmitPushShadowFrame(llvm::Value* new_shadow_frame,
Ian Rogers5438ad82012-10-15 17:22:44 -070089 llvm::Value* method, uint16_t num_refs,
90 uint16_t num_vregs) {
TDYa127de479be2012-05-31 08:03:26 -070091 Value* old_shadow_frame = EmitLoadFromThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
92 irb_.getArtFrameTy()->getPointerTo(),
93 kTBAARuntimeInfo);
94 EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
95 new_shadow_frame,
96 kTBAARuntimeInfo);
97
98 // Store the method pointer
99 irb_.StoreToObjectOffset(new_shadow_frame,
100 ShadowFrame::MethodOffset(),
101 method,
102 kTBAAShadowFrame);
103
Ian Rogers5438ad82012-10-15 17:22:44 -0700104 // Store the number of the reference slots
TDYa127de479be2012-05-31 08:03:26 -0700105 irb_.StoreToObjectOffset(new_shadow_frame,
106 ShadowFrame::NumberOfReferencesOffset(),
Ian Rogers5438ad82012-10-15 17:22:44 -0700107 irb_.getInt16(num_refs),
108 kTBAAShadowFrame);
109
110 // Store the number of vregs
111 irb_.StoreToObjectOffset(new_shadow_frame,
112 ShadowFrame::NumberOfVRegsOffset(),
113 irb_.getInt16(num_vregs),
TDYa127de479be2012-05-31 08:03:26 -0700114 kTBAAShadowFrame);
115
116 // Store the link to previous shadow frame
117 irb_.StoreToObjectOffset(new_shadow_frame,
118 ShadowFrame::LinkOffset(),
119 old_shadow_frame,
120 kTBAAShadowFrame);
121
122 return old_shadow_frame;
123}
124
125llvm::Value*
126RuntimeSupportBuilder::EmitPushShadowFrameNoInline(llvm::Value* new_shadow_frame,
TDYa127f54f3ac2012-10-16 22:39:00 -0700127 llvm::Value* method, uint16_t num_refs,
128 uint16_t num_vregs) {
TDYa127de479be2012-05-31 08:03:26 -0700129 Function* func = GetRuntimeSupportFunction(runtime_support::PushShadowFrame);
130 llvm::CallInst* call_inst =
TDYa127f54f3ac2012-10-16 22:39:00 -0700131 irb_.CreateCall5(func,
132 EmitGetCurrentThread(),
133 new_shadow_frame,
134 method,
135 irb_.getInt16(num_refs),
136 irb_.getInt16(num_vregs));
TDYa127de479be2012-05-31 08:03:26 -0700137 irb_.SetTBAA(call_inst, kTBAARuntimeInfo);
138 return call_inst;
139}
140
141void RuntimeSupportBuilder::EmitPopShadowFrame(llvm::Value* old_shadow_frame) {
142 // Store old shadow frame to TopShadowFrame
143 EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
144 old_shadow_frame,
145 kTBAARuntimeInfo);
146}
147
148
TDYa127823433d2012-09-26 16:03:51 -0700149/* Exception */
150
151llvm::Value* RuntimeSupportBuilder::EmitGetAndClearException() {
152 Function* slow_func = GetRuntimeSupportFunction(runtime_support::GetAndClearException);
153 return irb_.CreateCall(slow_func, EmitGetCurrentThread());
154}
TDYa127de479be2012-05-31 08:03:26 -0700155
156llvm::Value* RuntimeSupportBuilder::EmitIsExceptionPending() {
157 Value* exception = EmitLoadFromThreadOffset(Thread::ExceptionOffset().Int32Value(),
158 irb_.getJObjectTy(),
159 kTBAAJRuntime);
160 // If exception not null
TDYa1279a129452012-07-19 03:10:08 -0700161 return irb_.CreateIsNotNull(exception);
TDYa127de479be2012-05-31 08:03:26 -0700162}
163
TDYa127823433d2012-09-26 16:03:51 -0700164
165/* Suspend */
166
TDYa127de479be2012-05-31 08:03:26 -0700167void RuntimeSupportBuilder::EmitTestSuspend() {
168 Function* slow_func = GetRuntimeSupportFunction(runtime_support::TestSuspend);
TDYa127823433d2012-09-26 16:03:51 -0700169 Value* suspend_count = EmitLoadFromThreadOffset(Thread::ThreadFlagsOffset().Int32Value(),
170 irb_.getInt16Ty(),
TDYa127de479be2012-05-31 08:03:26 -0700171 kTBAARuntimeInfo);
TDYa127823433d2012-09-26 16:03:51 -0700172 Value* is_suspend = irb_.CreateICmpNE(suspend_count, irb_.getInt16(0));
TDYa127de479be2012-05-31 08:03:26 -0700173
TDYa1279a129452012-07-19 03:10:08 -0700174 Function* parent_func = irb_.GetInsertBlock()->getParent();
TDYa127de479be2012-05-31 08:03:26 -0700175 BasicBlock* basic_block_suspend = BasicBlock::Create(context_, "suspend", parent_func);
176 BasicBlock* basic_block_cont = BasicBlock::Create(context_, "suspend_cont", parent_func);
177 irb_.CreateCondBr(is_suspend, basic_block_suspend, basic_block_cont, kUnlikely);
178
179 irb_.SetInsertPoint(basic_block_suspend);
180 CallInst* call_inst = irb_.CreateCall(slow_func, EmitGetCurrentThread());
181 irb_.SetTBAA(call_inst, kTBAARuntimeInfo);
182 irb_.CreateBr(basic_block_cont);
183
184 irb_.SetInsertPoint(basic_block_cont);
185}
186
187
TDYa127b08ed122012-06-05 23:51:19 -0700188/* Monitor */
189
190void RuntimeSupportBuilder::EmitLockObject(llvm::Value* object) {
191 // TODO: Implement a fast path.
192 Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject);
193 irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
194}
195
196void RuntimeSupportBuilder::EmitUnlockObject(llvm::Value* object) {
TDYa1279a129452012-07-19 03:10:08 -0700197 Value* lock_id =
TDYa127b08ed122012-06-05 23:51:19 -0700198 EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(),
199 irb_.getJIntTy(),
200 kTBAARuntimeInfo);
TDYa1279a129452012-07-19 03:10:08 -0700201 Value* monitor =
TDYa127b08ed122012-06-05 23:51:19 -0700202 irb_.LoadFromObjectOffset(object,
203 Object::MonitorOffset().Int32Value(),
204 irb_.getJIntTy(),
205 kTBAARuntimeInfo);
206
TDYa1279a129452012-07-19 03:10:08 -0700207 Value* my_monitor = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT);
208 Value* hash_state = irb_.CreateAnd(monitor, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
209 Value* real_monitor = irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
TDYa127b08ed122012-06-05 23:51:19 -0700210
211 // Is thin lock, held by us and not recursively acquired
TDYa1279a129452012-07-19 03:10:08 -0700212 Value* is_fast_path = irb_.CreateICmpEQ(real_monitor, my_monitor);
TDYa127b08ed122012-06-05 23:51:19 -0700213
TDYa1279a129452012-07-19 03:10:08 -0700214 Function* parent_func = irb_.GetInsertBlock()->getParent();
TDYa127b08ed122012-06-05 23:51:19 -0700215 BasicBlock* bb_fast = BasicBlock::Create(context_, "unlock_fast", parent_func);
216 BasicBlock* bb_slow = BasicBlock::Create(context_, "unlock_slow", parent_func);
217 BasicBlock* bb_cont = BasicBlock::Create(context_, "unlock_cont", parent_func);
218 irb_.CreateCondBr(is_fast_path, bb_fast, bb_slow, kLikely);
219
220 irb_.SetInsertPoint(bb_fast);
221 // Set all bits to zero (except hash state)
222 irb_.StoreToObjectOffset(object,
223 Object::MonitorOffset().Int32Value(),
224 hash_state,
225 kTBAARuntimeInfo);
226 irb_.CreateBr(bb_cont);
227
228 irb_.SetInsertPoint(bb_slow);
229 Function* slow_func = GetRuntimeSupportFunction(runtime_support::UnlockObject);
230 irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
231 irb_.CreateBr(bb_cont);
232
233 irb_.SetInsertPoint(bb_cont);
234}
235
236
TDYa1279a129452012-07-19 03:10:08 -0700237void RuntimeSupportBuilder::EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr) {
238 Function* parent_func = irb_.GetInsertBlock()->getParent();
239 BasicBlock* bb_mark_gc_card = BasicBlock::Create(context_, "mark_gc_card", parent_func);
240 BasicBlock* bb_cont = BasicBlock::Create(context_, "mark_gc_card_cont", parent_func);
TDYa127d668a062012-04-13 12:36:57 -0700241
TDYa1279a129452012-07-19 03:10:08 -0700242 llvm::Value* not_null = irb_.CreateIsNotNull(value);
243 irb_.CreateCondBr(not_null, bb_mark_gc_card, bb_cont);
TDYa127d668a062012-04-13 12:36:57 -0700244
TDYa1279a129452012-07-19 03:10:08 -0700245 irb_.SetInsertPoint(bb_mark_gc_card);
246 Value* card_table = EmitLoadFromThreadOffset(Thread::CardTableOffset().Int32Value(),
247 irb_.getInt8Ty()->getPointerTo(),
248 kTBAAConstJObject);
249 Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
Mathieu Chartier8ed6d612012-10-09 14:39:28 -0700250 Value* card_no = irb_.CreateLShr(target_addr_int, irb_.getPtrEquivInt(CardTable::kCardShift));
TDYa1279a129452012-07-19 03:10:08 -0700251 Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
Mathieu Chartier8ed6d612012-10-09 14:39:28 -0700252 irb_.CreateStore(irb_.getInt8(CardTable::kCardDirty), card_table_entry, kTBAARuntimeInfo);
TDYa1279a129452012-07-19 03:10:08 -0700253 irb_.CreateBr(bb_cont);
TDYa127d668a062012-04-13 12:36:57 -0700254
TDYa1279a129452012-07-19 03:10:08 -0700255 irb_.SetInsertPoint(bb_cont);
TDYa127d668a062012-04-13 12:36:57 -0700256}
257
TDYa1279a129452012-07-19 03:10:08 -0700258
TDYa127d668a062012-04-13 12:36:57 -0700259} // namespace compiler_llvm
260} // namespace art