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 Function* slow_func = GetRuntimeSupportFunction(runtime_support::LockObject); 168 irb_.CreateCall2(slow_func, object, EmitGetCurrentThread()); 169 } 170 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 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