• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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