1 /*
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
19 #include "gc/accounting/card_table.h"
20 #include "ir_builder.h"
21 #include "monitor.h"
22 #include "mirror/object.h"
23 #include "runtime_support_llvm_func_list.h"
24 #include "thread.h"
25
26 #include <llvm/IR/DerivedTypes.h>
27 #include <llvm/IR/Function.h>
28 #include <llvm/IR/Module.h>
29 #include <llvm/IR/Type.h>
30
31 using ::llvm::BasicBlock;
32 using ::llvm::CallInst;
33 using ::llvm::Function;
34 using ::llvm::Value;
35
36 namespace art {
37 namespace llvm {
38
RuntimeSupportBuilder(::llvm::LLVMContext & context,::llvm::Module & module,IRBuilder & irb)39 RuntimeSupportBuilder::RuntimeSupportBuilder(::llvm::LLVMContext& context,
40 ::llvm::Module& module,
41 IRBuilder& irb)
42 : context_(context), module_(module), irb_(irb) {
43 memset(target_runtime_support_func_, 0, sizeof(target_runtime_support_func_));
44 #define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
45 do { \
46 ::llvm::Function* fn = module_.getFunction(#NAME); \
47 DCHECK(fn != NULL) << "Function not found: " << #NAME; \
48 runtime_support_func_decls_[runtime_support::ID] = fn; \
49 } while (0);
50
51 RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
52 }
53
54
55 /* Thread */
56
EmitGetCurrentThread()57 ::llvm::Value* RuntimeSupportBuilder::EmitGetCurrentThread() {
58 Function* func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
59 CallInst* call_inst = irb_.CreateCall(func);
60 call_inst->setOnlyReadsMemory();
61 irb_.SetTBAA(call_inst, kTBAAConstJObject);
62 return call_inst;
63 }
64
EmitLoadFromThreadOffset(int64_t offset,::llvm::Type * type,TBAASpecialType s_ty)65 ::llvm::Value* RuntimeSupportBuilder::EmitLoadFromThreadOffset(int64_t offset, ::llvm::Type* type,
66 TBAASpecialType s_ty) {
67 Value* thread = EmitGetCurrentThread();
68 return irb_.LoadFromObjectOffset(thread, offset, type, s_ty);
69 }
70
EmitStoreToThreadOffset(int64_t offset,::llvm::Value * value,TBAASpecialType s_ty)71 void RuntimeSupportBuilder::EmitStoreToThreadOffset(int64_t offset, ::llvm::Value* value,
72 TBAASpecialType s_ty) {
73 Value* thread = EmitGetCurrentThread();
74 irb_.StoreToObjectOffset(thread, offset, value, s_ty);
75 }
76
EmitSetCurrentThread(::llvm::Value * thread)77 ::llvm::Value* RuntimeSupportBuilder::EmitSetCurrentThread(::llvm::Value* thread) {
78 Function* func = GetRuntimeSupportFunction(runtime_support::SetCurrentThread);
79 return irb_.CreateCall(func, thread);
80 }
81
82
83 /* ShadowFrame */
84
EmitPushShadowFrame(::llvm::Value * new_shadow_frame,::llvm::Value * method,uint32_t num_vregs)85 ::llvm::Value* RuntimeSupportBuilder::EmitPushShadowFrame(::llvm::Value* new_shadow_frame,
86 ::llvm::Value* method,
87 uint32_t num_vregs) {
88 Value* old_shadow_frame = EmitLoadFromThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
89 irb_.getArtFrameTy()->getPointerTo(),
90 kTBAARuntimeInfo);
91 EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
92 new_shadow_frame,
93 kTBAARuntimeInfo);
94
95 // Store the method pointer
96 irb_.StoreToObjectOffset(new_shadow_frame,
97 ShadowFrame::MethodOffset(),
98 method,
99 kTBAAShadowFrame);
100
101 // Store the number of vregs
102 irb_.StoreToObjectOffset(new_shadow_frame,
103 ShadowFrame::NumberOfVRegsOffset(),
104 irb_.getInt32(num_vregs),
105 kTBAAShadowFrame);
106
107 // Store the link to previous shadow frame
108 irb_.StoreToObjectOffset(new_shadow_frame,
109 ShadowFrame::LinkOffset(),
110 old_shadow_frame,
111 kTBAAShadowFrame);
112
113 return old_shadow_frame;
114 }
115
116 ::llvm::Value*
EmitPushShadowFrameNoInline(::llvm::Value * new_shadow_frame,::llvm::Value * method,uint32_t num_vregs)117 RuntimeSupportBuilder::EmitPushShadowFrameNoInline(::llvm::Value* new_shadow_frame,
118 ::llvm::Value* method,
119 uint32_t num_vregs) {
120 Function* func = GetRuntimeSupportFunction(runtime_support::PushShadowFrame);
121 ::llvm::CallInst* call_inst =
122 irb_.CreateCall4(func,
123 EmitGetCurrentThread(),
124 new_shadow_frame,
125 method,
126 irb_.getInt32(num_vregs));
127 irb_.SetTBAA(call_inst, kTBAARuntimeInfo);
128 return call_inst;
129 }
130
EmitPopShadowFrame(::llvm::Value * old_shadow_frame)131 void RuntimeSupportBuilder::EmitPopShadowFrame(::llvm::Value* old_shadow_frame) {
132 // Store old shadow frame to TopShadowFrame
133 EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
134 old_shadow_frame,
135 kTBAARuntimeInfo);
136 }
137
138
139 /* Exception */
140
EmitGetAndClearException()141 ::llvm::Value* RuntimeSupportBuilder::EmitGetAndClearException() {
142 Function* slow_func = GetRuntimeSupportFunction(runtime_support::GetAndClearException);
143 return irb_.CreateCall(slow_func, EmitGetCurrentThread());
144 }
145
EmitIsExceptionPending()146 ::llvm::Value* RuntimeSupportBuilder::EmitIsExceptionPending() {
147 Value* exception = EmitLoadFromThreadOffset(Thread::ExceptionOffset().Int32Value(),
148 irb_.getJObjectTy(),
149 kTBAARuntimeInfo);
150 // If exception not null
151 return irb_.CreateIsNotNull(exception);
152 }
153
154
155 /* Suspend */
156
EmitTestSuspend()157 void RuntimeSupportBuilder::EmitTestSuspend() {
158 Function* slow_func = GetRuntimeSupportFunction(runtime_support::TestSuspend);
159 CallInst* call_inst = irb_.CreateCall(slow_func, EmitGetCurrentThread());
160 irb_.SetTBAA(call_inst, kTBAAJRuntime);
161 }
162
163
164 /* Monitor */
165
EmitLockObject(::llvm::Value * object)166 void RuntimeSupportBuilder::EmitLockObject(::llvm::Value* object) {
167 Value* monitor =
168 irb_.LoadFromObjectOffset(object,
169 mirror::Object::MonitorOffset().Int32Value(),
170 irb_.getJIntTy(),
171 kTBAARuntimeInfo);
172
173 Value* real_monitor =
174 irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
175
176 // Is thin lock, unheld and not recursively acquired.
177 Value* unheld = irb_.CreateICmpEQ(real_monitor, irb_.getInt32(0));
178
179 Function* parent_func = irb_.GetInsertBlock()->getParent();
180 BasicBlock* bb_fast = BasicBlock::Create(context_, "lock_fast", parent_func);
181 BasicBlock* bb_slow = BasicBlock::Create(context_, "lock_slow", parent_func);
182 BasicBlock* bb_cont = BasicBlock::Create(context_, "lock_cont", parent_func);
183 irb_.CreateCondBr(unheld, bb_fast, bb_slow, kLikely);
184
185 irb_.SetInsertPoint(bb_fast);
186
187 // Calculate new monitor: new = old | (lock_id << LW_LOCK_OWNER_SHIFT)
188 Value* lock_id =
189 EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(),
190 irb_.getInt32Ty(), kTBAARuntimeInfo);
191
192 Value* owner = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT);
193 Value* new_monitor = irb_.CreateOr(monitor, owner);
194
195 // Atomically update monitor.
196 Value* old_monitor =
197 irb_.CompareExchangeObjectOffset(object,
198 mirror::Object::MonitorOffset().Int32Value(),
199 monitor, new_monitor, kTBAARuntimeInfo);
200
201 Value* retry_slow_path = irb_.CreateICmpEQ(old_monitor, monitor);
202 irb_.CreateCondBr(retry_slow_path, bb_cont, bb_slow, kLikely);
203
204 irb_.SetInsertPoint(bb_slow);
205 Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject);
206 irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
207 irb_.CreateBr(bb_cont);
208
209 irb_.SetInsertPoint(bb_cont);
210 }
211
EmitUnlockObject(::llvm::Value * object)212 void RuntimeSupportBuilder::EmitUnlockObject(::llvm::Value* object) {
213 Value* lock_id =
214 EmitLoadFromThreadOffset(Thread::ThinLockIdOffset().Int32Value(),
215 irb_.getJIntTy(),
216 kTBAARuntimeInfo);
217 Value* monitor =
218 irb_.LoadFromObjectOffset(object,
219 mirror::Object::MonitorOffset().Int32Value(),
220 irb_.getJIntTy(),
221 kTBAARuntimeInfo);
222
223 Value* my_monitor = irb_.CreateShl(lock_id, LW_LOCK_OWNER_SHIFT);
224 Value* hash_state = irb_.CreateAnd(monitor, (LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
225 Value* real_monitor = irb_.CreateAnd(monitor, ~(LW_HASH_STATE_MASK << LW_HASH_STATE_SHIFT));
226
227 // Is thin lock, held by us and not recursively acquired
228 Value* is_fast_path = irb_.CreateICmpEQ(real_monitor, my_monitor);
229
230 Function* parent_func = irb_.GetInsertBlock()->getParent();
231 BasicBlock* bb_fast = BasicBlock::Create(context_, "unlock_fast", parent_func);
232 BasicBlock* bb_slow = BasicBlock::Create(context_, "unlock_slow", parent_func);
233 BasicBlock* bb_cont = BasicBlock::Create(context_, "unlock_cont", parent_func);
234 irb_.CreateCondBr(is_fast_path, bb_fast, bb_slow, kLikely);
235
236 irb_.SetInsertPoint(bb_fast);
237 // Set all bits to zero (except hash state)
238 irb_.StoreToObjectOffset(object,
239 mirror::Object::MonitorOffset().Int32Value(),
240 hash_state,
241 kTBAARuntimeInfo);
242 irb_.CreateBr(bb_cont);
243
244 irb_.SetInsertPoint(bb_slow);
245 Function* slow_func = GetRuntimeSupportFunction(runtime_support::UnlockObject);
246 irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
247 irb_.CreateBr(bb_cont);
248
249 irb_.SetInsertPoint(bb_cont);
250 }
251
252
EmitMarkGCCard(::llvm::Value * value,::llvm::Value * target_addr)253 void RuntimeSupportBuilder::EmitMarkGCCard(::llvm::Value* value, ::llvm::Value* target_addr) {
254 Function* parent_func = irb_.GetInsertBlock()->getParent();
255 BasicBlock* bb_mark_gc_card = BasicBlock::Create(context_, "mark_gc_card", parent_func);
256 BasicBlock* bb_cont = BasicBlock::Create(context_, "mark_gc_card_cont", parent_func);
257
258 ::llvm::Value* not_null = irb_.CreateIsNotNull(value);
259 irb_.CreateCondBr(not_null, bb_mark_gc_card, bb_cont);
260
261 irb_.SetInsertPoint(bb_mark_gc_card);
262 Value* card_table = EmitLoadFromThreadOffset(Thread::CardTableOffset().Int32Value(),
263 irb_.getInt8Ty()->getPointerTo(),
264 kTBAAConstJObject);
265 Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
266 Value* card_no = irb_.CreateLShr(target_addr_int,
267 irb_.getPtrEquivInt(gc::accounting::CardTable::kCardShift));
268 Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
269 irb_.CreateStore(irb_.getInt8(gc::accounting::CardTable::kCardDirty), card_table_entry,
270 kTBAARuntimeInfo);
271 irb_.CreateBr(bb_cont);
272
273 irb_.SetInsertPoint(bb_cont);
274 }
275
276
277 } // namespace llvm
278 } // namespace art
279