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   Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject);
168   irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
169 }
170 
EmitUnlockObject(::llvm::Value * object)171 void RuntimeSupportBuilder::EmitUnlockObject(::llvm::Value* object) {
172   Function* slow_func = GetRuntimeSupportFunction(runtime_support::UnlockObject);
173   irb_.CreateCall2(slow_func, object, EmitGetCurrentThread());
174 }
175 
176 
EmitMarkGCCard(::llvm::Value * value,::llvm::Value * target_addr)177 void RuntimeSupportBuilder::EmitMarkGCCard(::llvm::Value* value, ::llvm::Value* target_addr) {
178   Function* parent_func = irb_.GetInsertBlock()->getParent();
179   BasicBlock* bb_mark_gc_card = BasicBlock::Create(context_, "mark_gc_card", parent_func);
180   BasicBlock* bb_cont = BasicBlock::Create(context_, "mark_gc_card_cont", parent_func);
181 
182   ::llvm::Value* not_null = irb_.CreateIsNotNull(value);
183   irb_.CreateCondBr(not_null, bb_mark_gc_card, bb_cont);
184 
185   irb_.SetInsertPoint(bb_mark_gc_card);
186   Value* card_table = EmitLoadFromThreadOffset(Thread::CardTableOffset().Int32Value(),
187                                                irb_.getInt8Ty()->getPointerTo(),
188                                                kTBAAConstJObject);
189   Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
190   Value* card_no = irb_.CreateLShr(target_addr_int,
191                                    irb_.getPtrEquivInt(gc::accounting::CardTable::kCardShift));
192   Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
193   irb_.CreateStore(irb_.getInt8(gc::accounting::CardTable::kCardDirty), card_table_entry,
194                    kTBAARuntimeInfo);
195   irb_.CreateBr(bb_cont);
196 
197   irb_.SetInsertPoint(bb_cont);
198 }
199 
200 
201 }  // namespace llvm
202 }  // namespace art
203