Home | History | Annotate | Download | only in llvm
      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