Refactor runtime support builder.

Also, add inline assembly for load offset from current thread.

Change-Id: I5c32c04a5ab9a8574acbaf8ee3e08761ebe33d4f
diff --git a/src/compiler_llvm/runtime_support_builder.cc b/src/compiler_llvm/runtime_support_builder.cc
index 2e86938..b0823d6 100644
--- a/src/compiler_llvm/runtime_support_builder.cc
+++ b/src/compiler_llvm/runtime_support_builder.cc
@@ -45,7 +45,7 @@
   do { \
     llvm::Function* fn = module_.getFunction(#NAME); \
     DCHECK_NE(fn, (void*)NULL) << "Function not found: " << #NAME; \
-    runtime_support_func_decls_[ID] = fn; \
+    runtime_support_func_decls_[runtime_support::ID] = fn; \
   } while (0);
 
 #include "runtime_support_func_list.h"
@@ -69,115 +69,120 @@
   }
 }
 
+
+/* Thread */
+
+llvm::Value* RuntimeSupportBuilder::EmitGetCurrentThread() {
+  Function* func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
+  llvm::CallInst* call_inst = irb_.CreateCall(func);
+  call_inst->setOnlyReadsMemory();
+  irb_.SetTBAA(call_inst, kTBAAConstJObject);
+  return call_inst;
+}
+
+llvm::Value* RuntimeSupportBuilder::EmitLoadFromThreadOffset(int64_t offset, llvm::Type* type,
+                                                             TBAASpecialType s_ty) {
+  llvm::Value* thread = EmitGetCurrentThread();
+  return irb_.LoadFromObjectOffset(thread, offset, type, s_ty);
+}
+
+void RuntimeSupportBuilder::EmitStoreToThreadOffset(int64_t offset, llvm::Value* value,
+                                                    TBAASpecialType s_ty) {
+  llvm::Value* thread = EmitGetCurrentThread();
+  irb_.StoreToObjectOffset(thread, offset, value, s_ty);
+}
+
+void RuntimeSupportBuilder::EmitSetCurrentThread(llvm::Value* thread) {
+  Function* func = GetRuntimeSupportFunction(runtime_support::SetCurrentThread);
+  irb_.CreateCall(func, thread);
+}
+
+
+/* ShadowFrame */
+
+llvm::Value* RuntimeSupportBuilder::EmitPushShadowFrame(llvm::Value* new_shadow_frame,
+                                                        llvm::Value* method, uint32_t size) {
+  Value* old_shadow_frame = EmitLoadFromThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
+                                                     irb_.getArtFrameTy()->getPointerTo(),
+                                                     kTBAARuntimeInfo);
+  EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
+                          new_shadow_frame,
+                          kTBAARuntimeInfo);
+
+  // Store the method pointer
+  irb_.StoreToObjectOffset(new_shadow_frame,
+                           ShadowFrame::MethodOffset(),
+                           method,
+                           kTBAAShadowFrame);
+
+  // Store the number of the pointer slots
+  irb_.StoreToObjectOffset(new_shadow_frame,
+                           ShadowFrame::NumberOfReferencesOffset(),
+                           irb_.getInt32(size),
+                           kTBAAShadowFrame);
+
+  // Store the link to previous shadow frame
+  irb_.StoreToObjectOffset(new_shadow_frame,
+                           ShadowFrame::LinkOffset(),
+                           old_shadow_frame,
+                           kTBAAShadowFrame);
+
+  return old_shadow_frame;
+}
+
+llvm::Value*
+RuntimeSupportBuilder::EmitPushShadowFrameNoInline(llvm::Value* new_shadow_frame,
+                                                   llvm::Value* method, uint32_t size) {
+  Function* func = GetRuntimeSupportFunction(runtime_support::PushShadowFrame);
+  llvm::CallInst* call_inst =
+      irb_.CreateCall4(func, EmitGetCurrentThread(), new_shadow_frame, method, irb_.getInt32(size));
+  irb_.SetTBAA(call_inst, kTBAARuntimeInfo);
+  return call_inst;
+}
+
+void RuntimeSupportBuilder::EmitPopShadowFrame(llvm::Value* old_shadow_frame) {
+  // Store old shadow frame to TopShadowFrame
+  EmitStoreToThreadOffset(Thread::TopShadowFrameOffset().Int32Value(),
+                          old_shadow_frame,
+                          kTBAARuntimeInfo);
+}
+
+
+/* Check */
+
+llvm::Value* RuntimeSupportBuilder::EmitIsExceptionPending() {
+  Value* exception = EmitLoadFromThreadOffset(Thread::ExceptionOffset().Int32Value(),
+                                              irb_.getJObjectTy(),
+                                              kTBAAJRuntime);
+  // If exception not null
+  return irb_.CreateICmpNE(exception, irb_.getJNull());
+}
+
+void RuntimeSupportBuilder::EmitTestSuspend() {
+  Function* slow_func = GetRuntimeSupportFunction(runtime_support::TestSuspend);
+  Value* suspend_count = EmitLoadFromThreadOffset(Thread::SuspendCountOffset().Int32Value(),
+                                                  irb_.getJIntTy(),
+                                                  kTBAARuntimeInfo);
+  Value* is_suspend = irb_.CreateICmpNE(suspend_count, irb_.getJInt(0));
+
+  llvm::Function* parent_func = irb_.GetInsertBlock()->getParent();
+  BasicBlock* basic_block_suspend = BasicBlock::Create(context_, "suspend", parent_func);
+  BasicBlock* basic_block_cont = BasicBlock::Create(context_, "suspend_cont", parent_func);
+  irb_.CreateCondBr(is_suspend, basic_block_suspend, basic_block_cont, kUnlikely);
+
+  irb_.SetInsertPoint(basic_block_suspend);
+  CallInst* call_inst = irb_.CreateCall(slow_func, EmitGetCurrentThread());
+  irb_.SetTBAA(call_inst, kTBAARuntimeInfo);
+  irb_.CreateBr(basic_block_cont);
+
+  irb_.SetInsertPoint(basic_block_cont);
+}
+
+
 void RuntimeSupportBuilder::OptimizeRuntimeSupport() {
-  TargetOptimizeRuntimeSupport();
-
-  if (!target_runtime_support_func_[PushShadowFrame]) {
-    Function* func = GetRuntimeSupportFunction(PushShadowFrame);
-    MakeFunctionInline(func);
-    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
-    irb_.SetInsertPoint(basic_block);
-
-    Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
-    Value* thread = irb_.CreateCall(get_thread);
-    Function::arg_iterator arg_iter = func->arg_begin();
-    Value* new_shadow_frame = arg_iter++;
-    Value* method_object_addr = arg_iter++;
-    Value* shadow_frame_size = arg_iter++;
-    Value* old_shadow_frame = irb_.LoadFromObjectOffset(thread,
-                                                        Thread::TopShadowFrameOffset().Int32Value(),
-                                                        irb_.getArtFrameTy()->getPointerTo(),
-                                                        kTBAARuntimeInfo);
-    irb_.StoreToObjectOffset(thread,
-                             Thread::TopShadowFrameOffset().Int32Value(),
-                             new_shadow_frame,
-                             kTBAARuntimeInfo);
-
-    // Store the method pointer
-    irb_.StoreToObjectOffset(new_shadow_frame,
-                             ShadowFrame::MethodOffset(),
-                             method_object_addr,
-                             kTBAAShadowFrame);
-
-    // Store the number of the pointer slots
-    irb_.StoreToObjectOffset(new_shadow_frame,
-                             ShadowFrame::NumberOfReferencesOffset(),
-                             shadow_frame_size,
-                             kTBAAShadowFrame);
-
-    // Store the link to previous shadow frame
-    irb_.StoreToObjectOffset(new_shadow_frame,
-                             ShadowFrame::LinkOffset(),
-                             old_shadow_frame,
-                             kTBAAShadowFrame);
-
-    irb_.CreateRet(old_shadow_frame);
-
-    VERIFY_LLVM_FUNCTION(*func);
-  }
-
-  if (!target_runtime_support_func_[PushShadowFrameNoInline]) {
-    Function* func = GetRuntimeSupportFunction(PushShadowFrameNoInline);
-
-    func->setLinkage(GlobalValue::PrivateLinkage);
-    func->addFnAttr(Attribute::NoInline);
-
-    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
-    irb_.SetInsertPoint(basic_block);
-
-    Function::arg_iterator arg_iter = func->arg_begin();
-    Value* new_shadow_frame = arg_iter++;
-    Value* method_object_addr = arg_iter++;
-    Value* shadow_frame_size = arg_iter++;
-
-    // Call inline version
-    Value* old_shadow_frame =
-      irb_.CreateCall3(GetRuntimeSupportFunction(PushShadowFrame),
-                       new_shadow_frame, method_object_addr, shadow_frame_size);
-    irb_.CreateRet(old_shadow_frame);
-
-    VERIFY_LLVM_FUNCTION(*func);
-  }
-
-  if (!target_runtime_support_func_[PopShadowFrame]) {
-    Function* func = GetRuntimeSupportFunction(PopShadowFrame);
-    MakeFunctionInline(func);
-    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
-    irb_.SetInsertPoint(basic_block);
-
-    Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
-    Value* thread = irb_.CreateCall(get_thread);
-    Value* old_shadow_frame = func->arg_begin();
-    irb_.StoreToObjectOffset(thread,
-                             Thread::TopShadowFrameOffset().Int32Value(),
-                             old_shadow_frame,
-                             kTBAARuntimeInfo);
-    irb_.CreateRetVoid();
-
-    VERIFY_LLVM_FUNCTION(*func);
-  }
-
-  if (!target_runtime_support_func_[IsExceptionPending]) {
-    Function* func = GetRuntimeSupportFunction(IsExceptionPending);
-    MakeFunctionInline(func);
-    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
-    irb_.SetInsertPoint(basic_block);
-
-    Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
-    Value* thread = irb_.CreateCall(get_thread);
-    Value* exception = irb_.LoadFromObjectOffset(thread,
-                                                 Thread::ExceptionOffset().Int32Value(),
-                                                 irb_.getJObjectTy(),
-                                                 kTBAAJRuntime);
-    Value* is_exception_not_null = irb_.CreateICmpNE(exception, irb_.getJNull());
-    irb_.CreateRet(is_exception_not_null);
-
-    VERIFY_LLVM_FUNCTION(*func);
-  }
-
-  if (!target_runtime_support_func_[TestSuspend]) {
-    Function* slow_func = GetRuntimeSupportFunction(TestSuspend);
-
+  // TODO: Remove this after we remove suspend loop pass.
+  if (!target_runtime_support_func_[runtime_support::TestSuspend]) {
+    Function* slow_func = GetRuntimeSupportFunction(runtime_support::TestSuspend);
     Function* func = Function::Create(slow_func->getFunctionType(),
                                       GlobalValue::LinkOnceODRLinkage,
                                       "test_suspend_fast",
@@ -186,29 +191,11 @@
     BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
     irb_.SetInsertPoint(basic_block);
 
-    Value* thread = func->arg_begin();
-    llvm::LoadInst* suspend_count =
-        irb_.LoadFromObjectOffset(thread,
-                                  Thread::SuspendCountOffset().Int32Value(),
-                                  irb_.getJIntTy(),
-                                  kTBAARuntimeInfo);
-    suspend_count->setAlignment(4U);
-    suspend_count->setAtomic(Unordered, CrossThread);
-    Value* is_suspend = irb_.CreateICmpNE(suspend_count, irb_.getJInt(0));
+    EmitTestSuspend();
 
-    BasicBlock* basic_block_suspend = BasicBlock::Create(context_, "suspend", func);
-    BasicBlock* basic_block_else = BasicBlock::Create(context_, "else", func);
-    irb_.CreateCondBr(is_suspend, basic_block_suspend, basic_block_else, kUnlikely);
-
-    irb_.SetInsertPoint(basic_block_suspend);
-    CallInst* call_inst = irb_.CreateCall(slow_func, thread);
-    irb_.SetTBAACall(call_inst, kTBAARuntimeInfo);
-    irb_.CreateBr(basic_block_else);
-
-    irb_.SetInsertPoint(basic_block_else);
     irb_.CreateRetVoid();
 
-    OverrideRuntimeSupportFunction(TestSuspend, func);
+    OverrideRuntimeSupportFunction(runtime_support::TestSuspend, func);
 
     VERIFY_LLVM_FUNCTION(*func);
   }
@@ -233,12 +220,9 @@
     irb_.CreateRetVoid();
 
     irb_.SetInsertPoint(block_mark_gc_card);
-    Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
-    Value* thread = irb_.CreateCall(get_thread);
-    Value* card_table = irb_.LoadFromObjectOffset(thread,
-                                                  Thread::CardTableOffset().Int32Value(),
-                                                  irb_.getInt8Ty()->getPointerTo(),
-                                                  kTBAAConstJObject);
+    Value* card_table = EmitLoadFromThreadOffset(Thread::CardTableOffset().Int32Value(),
+                                                 irb_.getInt8Ty()->getPointerTo(),
+                                                 kTBAAConstJObject);
     Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
     Value* card_no = irb_.CreateLShr(target_addr_int, irb_.getPtrEquivInt(GC_CARD_SHIFT));
     Value* card_table_entry = irb_.CreateGEP(card_table, card_no);