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 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 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 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 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 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 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* 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 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 141 ::llvm::Value* RuntimeSupportBuilder::EmitGetAndClearException() { 142 Function* slow_func = GetRuntimeSupportFunction(runtime_support::GetAndClearException); 143 return irb_.CreateCall(slow_func, EmitGetCurrentThread()); 144 } 145 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 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 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 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 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