blob: 729980309d1cc7c8179317244df624841082dd8c [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
Ian Rogers1d54e732013-05-02 21:10:01 -070019#include "gc/accounting/card_table.h"
TDYa127d668a062012-04-13 12:36:57 -070020#include "ir_builder.h"
TDYa127b08ed122012-06-05 23:51:19 -070021#include "monitor.h"
Ian Rogers2dd0e2c2013-01-24 12:42:14 -080022#include "mirror/object.h"
TDYa127d668a062012-04-13 12:36:57 -070023#include "thread.h"
24
Brian Carlstrom37d48792013-03-22 14:14:45 -070025#include <llvm/IR/DerivedTypes.h>
26#include <llvm/IR/Function.h>
27#include <llvm/IR/Module.h>
28#include <llvm/IR/Type.h>
TDYa127d668a062012-04-13 12:36:57 -070029
Brian Carlstrom3e3d5912013-07-18 00:19:45 -070030using ::llvm::BasicBlock;
31using ::llvm::CallInst;
32using ::llvm::Function;
33using ::llvm::Value;
TDYa127d668a062012-04-13 12:36:57 -070034
35namespace art {
Ian Rogers4c1c2832013-03-04 18:30:13 -080036namespace llvm {
TDYa127d668a062012-04-13 12:36:57 -070037
Ian Rogers4c1c2832013-03-04 18:30:13 -080038RuntimeSupportBuilder::RuntimeSupportBuilder(::llvm::LLVMContext& context,
39 ::llvm::Module& module,
TDYa127d668a062012-04-13 12:36:57 -070040 IRBuilder& irb)
Brian Carlstrom2ce745c2013-07-17 17:44:30 -070041 : context_(context), module_(module), irb_(irb) {
TDYa12783bb6622012-04-17 02:20:34 -070042 memset(target_runtime_support_func_, 0, sizeof(target_runtime_support_func_));
TDYa127d668a062012-04-13 12:36:57 -070043#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
44 do { \
Ian Rogers4c1c2832013-03-04 18:30:13 -080045 ::llvm::Function* fn = module_.getFunction(#NAME); \
Brian Carlstrom2d888622013-07-18 17:02:00 -070046 DCHECK(fn != NULL) << "Function not found: " << #NAME; \
TDYa127de479be2012-05-31 08:03:26 -070047 runtime_support_func_decls_[runtime_support::ID] = fn; \
TDYa127d668a062012-04-13 12:36:57 -070048 } while (0);
49
Brian Carlstrom51c24672013-07-11 16:00:56 -070050#include "runtime_support_llvm_func_list.h"
TDYa127d668a062012-04-13 12:36:57 -070051 RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
52#undef RUNTIME_SUPPORT_FUNC_LIST
53#undef GET_RUNTIME_SUPPORT_FUNC_DECL
54}
55
TDYa127de479be2012-05-31 08:03:26 -070056
57/* Thread */
58
Ian Rogers4c1c2832013-03-04 18:30:13 -080059::llvm::Value* RuntimeSupportBuilder::EmitGetCurrentThread() {
TDYa127de479be2012-05-31 08:03:26 -070060 Function* func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
TDYa1279a129452012-07-19 03:10:08 -070061 CallInst* call_inst = irb_.CreateCall(func);
TDYa127de479be2012-05-31 08:03:26 -070062 call_inst->setOnlyReadsMemory();
63 irb_.SetTBAA(call_inst, kTBAAConstJObject);
64 return call_inst;
65}
66
Ian Rogers4c1c2832013-03-04 18:30:13 -080067::llvm::Value* RuntimeSupportBuilder::EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type,
TDYa127de479be2012-05-31 08:03:26 -070068 TBAASpecialType s_ty) {
TDYa1279a129452012-07-19 03:10:08 -070069 Value* thread = EmitGetCurrentThread();
TDYa127de479be2012-05-31 08:03:26 -070070 return irb_.LoadFromObjectOffset(thread, offset, type, s_ty);
71}
72
Ian Rogers4c1c2832013-03-04 18:30:13 -080073void RuntimeSupportBuilder::EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value,
TDYa127de479be2012-05-31 08:03:26 -070074 TBAASpecialType s_ty) {
TDYa1279a129452012-07-19 03:10:08 -070075 Value* thread = EmitGetCurrentThread();
TDYa127de479be2012-05-31 08:03:26 -070076 irb_.StoreToObjectOffset(thread, offset, value, s_ty);
77}
78
Ian Rogers4c1c2832013-03-04 18:30:13 -080079::llvm::Value* RuntimeSupportBuilder::EmitSetCurrentThread(::llvm::Value* thread) {
TDYa127de479be2012-05-31 08:03:26 -070080 Function* func = GetRuntimeSupportFunction(runtime_support::SetCurrentThread);
TDYa127c1478262012-06-20 20:22:27 -070081 return irb_.CreateCall(func, thread);
TDYa127de479be2012-05-31 08:03:26 -070082}
83
84
85/* ShadowFrame */
86
Ian Rogers4c1c2832013-03-04 18:30:13 -080087::llvm::Value* RuntimeSupportBuilder::EmitPushShadowFrame(::llvm::Value* new_shadow_frame,
88 ::llvm::Value* method,
TDYa127ce4cc0d2012-11-18 16:59:53 -080089 uint32_t num_vregs) {
TDYa127de479be2012-05-31 08:03:26 -070090 Value* old_shadow_frame = EmitLoadFromThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
91 irb_.getArtFrameTy()->getPointerTo(),
92 kTBAARuntimeInfo);
93 EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
94 new_shadow_frame,
95 kTBAARuntimeInfo);
96
97 // Store the method pointer
98 irb_.StoreToObjectOffset(new_shadow_frame,
99 ShadowFrame::MethodOffset(),
100 method,
101 kTBAAShadowFrame);
102
Ian Rogers5438ad82012-10-15 17:22:44 -0700103 // Store the number of vregs
104 irb_.StoreToObjectOffset(new_shadow_frame,
105 ShadowFrame::NumberOfVRegsOffset(),
TDYa127ce4cc0d2012-11-18 16:59:53 -0800106 irb_.getInt32(num_vregs),
TDYa127de479be2012-05-31 08:03:26 -0700107 kTBAAShadowFrame);
108
109 // Store the link to previous shadow frame
110 irb_.StoreToObjectOffset(new_shadow_frame,
111 ShadowFrame::LinkOffset(),
112 old_shadow_frame,
113 kTBAAShadowFrame);
114
115 return old_shadow_frame;
116}
117
Ian Rogers4c1c2832013-03-04 18:30:13 -0800118::llvm::Value*
119RuntimeSupportBuilder::EmitPushShadowFrameNoInline(::llvm::Value* new_shadow_frame,
120 ::llvm::Value* method,
TDYa127ce4cc0d2012-11-18 16:59:53 -0800121 uint32_t num_vregs) {
TDYa127de479be2012-05-31 08:03:26 -0700122 Function* func = GetRuntimeSupportFunction(runtime_support::PushShadowFrame);
Ian Rogers4c1c2832013-03-04 18:30:13 -0800123 ::llvm::CallInst* call_inst =
TDYa127ce4cc0d2012-11-18 16:59:53 -0800124 irb_.CreateCall4(func,
TDYa127f54f3ac2012-10-16 22:39:00 -0700125 EmitGetCurrentThread(),
126 new_shadow_frame,
127 method,
TDYa127ce4cc0d2012-11-18 16:59:53 -0800128 irb_.getInt32(num_vregs));
TDYa127de479be2012-05-31 08:03:26 -0700129 irb_.SetTBAA(call_inst, kTBAARuntimeInfo);
130 return call_inst;
131}
132
Ian Rogers4c1c2832013-03-04 18:30:13 -0800133void RuntimeSupportBuilder::EmitPopShadowFrame(::llvm::Value* old_shadow_frame) {
TDYa127de479be2012-05-31 08:03:26 -0700134 // Store old shadow frame to TopShadowFrame
135 EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
136 old_shadow_frame,
137 kTBAARuntimeInfo);
138}
139
140
TDYa127823433d2012-09-26 16:03:51 -0700141/* Exception */
142
Ian Rogers4c1c2832013-03-04 18:30:13 -0800143::llvm::Value* RuntimeSupportBuilder::EmitGetAndClearException() {
TDYa127823433d2012-09-26 16:03:51 -0700144 Function* slow_func = GetRuntimeSupportFunction(runtime_support::GetAndClearException);
145 return irb_.CreateCall(slow_func, EmitGetCurrentThread());
146}
TDYa127de479be2012-05-31 08:03:26 -0700147
Ian Rogers4c1c2832013-03-04 18:30:13 -0800148::llvm::Value* RuntimeSupportBuilder::EmitIsExceptionPending() {
Jeff Haoa8fd2d52013-01-17 23:10:27 +0000149 Value* exception = EmitLoadFromThreadOffset(Thread::ExceptionOffset().Int32Value(),
150 irb_.getJObjectTy(),
151 kTBAARuntimeInfo);
152 // If exception not null
153 return irb_.CreateIsNotNull(exception);
TDYa127de479be2012-05-31 08:03:26 -0700154}
155
TDYa127823433d2012-09-26 16:03:51 -0700156
157/* Suspend */
158
TDYa127de479be2012-05-31 08:03:26 -0700159void RuntimeSupportBuilder::EmitTestSuspend() {
160 Function* slow_func = GetRuntimeSupportFunction(runtime_support::TestSuspend);
TDYa127de479be2012-05-31 08:03:26 -0700161 CallInst* call_inst = irb_.CreateCall(slow_func, EmitGetCurrentThread());
TDYa127ce4cc0d2012-11-18 16:59:53 -0800162 irb_.SetTBAA(call_inst, kTBAAJRuntime);
TDYa127de479be2012-05-31 08:03:26 -0700163}
164
165
TDYa127b08ed122012-06-05 23:51:19 -0700166/* Monitor */
167
Ian Rogers4c1c2832013-03-04 18:30:13 -0800168void RuntimeSupportBuilder::EmitLockObject(::llvm::Value* object) {
Sebastien Hertz50a1abf2013-02-18 14:36:41 +0100169 Value* monitor =
170 irb_.LoadFromObjectOffset(object,
171 mirror::Object::MonitorOffset().Int32Value(),
172 irb_.getJIntTy(),
173 kTBAARuntimeInfo);
174
175 Value* real_monitor =
176 irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
177
178 // Is thin lock, unheld and not recursively acquired.
179 Value* unheld = irb_.CreateICmpEQ(real_monitor, irb_.getInt32(0));
180
181 Function* parent_func = irb_.GetInsertBlock()->getParent();
182 BasicBlock* bb_fast = BasicBlock::Create(context_, "lock_fast", parent_func);
183 BasicBlock* bb_slow = BasicBlock::Create(context_, "lock_slow", parent_func);
184 BasicBlock* bb_cont = BasicBlock::Create(context_, "lock_cont", parent_func);
185 irb_.CreateCondBr(unheld, bb_fast, bb_slow, kLikely);
186
187 irb_.SetInsertPoint(bb_fast);
188
189 // Calculate new monitor: new = old | (lock_id << LW_LOCK_OWNER_SHIFT)
190 Value* lock_id =
191 EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(),
192 irb_.getInt32Ty(), kTBAARuntimeInfo);
193
194 Value* owner = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT);
195 Value* new_monitor = irb_.CreateOr(monitor, owner);
196
197 // Atomically update monitor.
198 Value* old_monitor =
199 irb_.CompareExchangeObjectOffset(object,
200 mirror::Object::MonitorOffset().Int32Value(),
201 monitor, new_monitor, kTBAARuntimeInfo);
202
203 Value* retry_slow_path = irb_.CreateICmpEQ(old_monitor, monitor);
204 irb_.CreateCondBr(retry_slow_path, bb_cont, bb_slow, kLikely);
205
206 irb_.SetInsertPoint(bb_slow);
TDYa127b08ed122012-06-05 23:51:19 -0700207 Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject);
208 irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
Sebastien Hertz50a1abf2013-02-18 14:36:41 +0100209 irb_.CreateBr(bb_cont);
210
211 irb_.SetInsertPoint(bb_cont);
TDYa127b08ed122012-06-05 23:51:19 -0700212}
213
Ian Rogers4c1c2832013-03-04 18:30:13 -0800214void RuntimeSupportBuilder::EmitUnlockObject(::llvm::Value* object) {
TDYa1279a129452012-07-19 03:10:08 -0700215 Value* lock_id =
TDYa127b08ed122012-06-05 23:51:19 -0700216 EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(),
217 irb_.getJIntTy(),
218 kTBAARuntimeInfo);
TDYa1279a129452012-07-19 03:10:08 -0700219 Value* monitor =
TDYa127b08ed122012-06-05 23:51:19 -0700220 irb_.LoadFromObjectOffset(object,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800221 mirror::Object::MonitorOffset().Int32Value(),
TDYa127b08ed122012-06-05 23:51:19 -0700222 irb_.getJIntTy(),
223 kTBAARuntimeInfo);
224
TDYa1279a129452012-07-19 03:10:08 -0700225 Value* my_monitor = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT);
226 Value* hash_state = irb_.CreateAnd(monitor, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
227 Value* real_monitor = irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
TDYa127b08ed122012-06-05 23:51:19 -0700228
229 // Is thin lock, held by us and not recursively acquired
TDYa1279a129452012-07-19 03:10:08 -0700230 Value* is_fast_path = irb_.CreateICmpEQ(real_monitor, my_monitor);
TDYa127b08ed122012-06-05 23:51:19 -0700231
TDYa1279a129452012-07-19 03:10:08 -0700232 Function* parent_func = irb_.GetInsertBlock()->getParent();
TDYa127b08ed122012-06-05 23:51:19 -0700233 BasicBlock* bb_fast = BasicBlock::Create(context_, "unlock_fast", parent_func);
234 BasicBlock* bb_slow = BasicBlock::Create(context_, "unlock_slow", parent_func);
235 BasicBlock* bb_cont = BasicBlock::Create(context_, "unlock_cont", parent_func);
236 irb_.CreateCondBr(is_fast_path, bb_fast, bb_slow, kLikely);
237
238 irb_.SetInsertPoint(bb_fast);
239 // Set all bits to zero (except hash state)
240 irb_.StoreToObjectOffset(object,
Ian Rogers2dd0e2c2013-01-24 12:42:14 -0800241 mirror::Object::MonitorOffset().Int32Value(),
TDYa127b08ed122012-06-05 23:51:19 -0700242 hash_state,
243 kTBAARuntimeInfo);
244 irb_.CreateBr(bb_cont);
245
246 irb_.SetInsertPoint(bb_slow);
247 Function* slow_func = GetRuntimeSupportFunction(runtime_support::UnlockObject);
248 irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
249 irb_.CreateBr(bb_cont);
250
251 irb_.SetInsertPoint(bb_cont);
252}
253
254
Ian Rogers4c1c2832013-03-04 18:30:13 -0800255void RuntimeSupportBuilder::EmitMarkGCCard(::llvm::Value* value, ::llvm::Value* target_addr) {
TDYa1279a129452012-07-19 03:10:08 -0700256 Function* parent_func = irb_.GetInsertBlock()->getParent();
257 BasicBlock* bb_mark_gc_card = BasicBlock::Create(context_, "mark_gc_card", parent_func);
258 BasicBlock* bb_cont = BasicBlock::Create(context_, "mark_gc_card_cont", parent_func);
TDYa127d668a062012-04-13 12:36:57 -0700259
Ian Rogers4c1c2832013-03-04 18:30:13 -0800260 ::llvm::Value* not_null = irb_.CreateIsNotNull(value);
TDYa1279a129452012-07-19 03:10:08 -0700261 irb_.CreateCondBr(not_null, bb_mark_gc_card, bb_cont);
TDYa127d668a062012-04-13 12:36:57 -0700262
TDYa1279a129452012-07-19 03:10:08 -0700263 irb_.SetInsertPoint(bb_mark_gc_card);
264 Value* card_table = EmitLoadFromThreadOffset(Thread::CardTableOffset().Int32Value(),
265 irb_.getInt8Ty()->getPointerTo(),
266 kTBAAConstJObject);
267 Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
Ian Rogers1d54e732013-05-02 21:10:01 -0700268 Value* card_no = irb_.CreateLShr(target_addr_int,
269 irb_.getPtrEquivInt(gc::accounting::CardTable::kCardShift));
TDYa1279a129452012-07-19 03:10:08 -0700270 Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
Ian Rogers1d54e732013-05-02 21:10:01 -0700271 irb_.CreateStore(irb_.getInt8(gc::accounting::CardTable::kCardDirty), card_table_entry,
272 kTBAARuntimeInfo);
TDYa1279a129452012-07-19 03:10:08 -0700273 irb_.CreateBr(bb_cont);
TDYa127d668a062012-04-13 12:36:57 -0700274
TDYa1279a129452012-07-19 03:10:08 -0700275 irb_.SetInsertPoint(bb_cont);
TDYa127d668a062012-04-13 12:36:57 -0700276}
277
TDYa1279a129452012-07-19 03:10:08 -0700278
Brian Carlstrom7934ac22013-07-26 10:54:15 -0700279} // namespace llvm
280} // namespace art