Refactor runtime support builder.

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

Change-Id: I5c32c04a5ab9a8574acbaf8ee3e08761ebe33d4f
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll
index cebc76c..f831736 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -43,8 +43,8 @@
 
 declare void @art_test_suspend_from_code(%JavaObject*)
 
-declare %ShadowFrame* @art_push_shadow_frame_from_code(%ShadowFrame*, %JavaObject*, i32)
-declare %ShadowFrame* @art_push_shadow_frame_noinline_from_code(%ShadowFrame*, %JavaObject*, i32)
+declare %ShadowFrame* @art_push_shadow_frame_from_code(%JavaObject*, %ShadowFrame*,
+                                                       %JavaObject*, i32)
 declare void @art_pop_shadow_frame_from_code(%ShadowFrame*)
 
 
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index b4bdd5d..266377e 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -142,10 +142,8 @@
     irb_->SetInsertPoint(bb->getTerminator());
 
     using art::compiler_llvm::runtime_support::TestSuspend;
-    using art::compiler_llvm::runtime_support::GetCurrentThread;
     llvm::Value* runtime_func = irb_->GetRuntime(TestSuspend);
-    llvm::Value* thread_object_addr = irb_->CreateCall(irb_->GetRuntime(GetCurrentThread));
-    irb_->CreateCall(runtime_func, thread_object_addr);
+    irb_->CreateCall(runtime_func, irb_->getJNull());
 
     return true;
   }
diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc
index 1f88e8d..2a8100b 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -83,6 +83,7 @@
  /*isVarArg=*/false);
 
 std::vector<Type*>FuncTy_6_args;
+FuncTy_6_args.push_back(PointerTy_1);
 FuncTy_6_args.push_back(PointerTy_2);
 FuncTy_6_args.push_back(PointerTy_1);
 FuncTy_6_args.push_back(IntegerType::get(mod->getContext(), 32));
@@ -425,17 +426,6 @@
 AttrListPtr func_art_push_shadow_frame_from_code_PAL;
 func_art_push_shadow_frame_from_code->setAttributes(func_art_push_shadow_frame_from_code_PAL);
 
-Function* func_art_push_shadow_frame_noinline_from_code = mod->getFunction("art_push_shadow_frame_noinline_from_code");
-if (!func_art_push_shadow_frame_noinline_from_code) {
-func_art_push_shadow_frame_noinline_from_code = Function::Create(
- /*Type=*/FuncTy_6,
- /*Linkage=*/GlobalValue::ExternalLinkage,
- /*Name=*/"art_push_shadow_frame_noinline_from_code", mod); // (external, no body)
-func_art_push_shadow_frame_noinline_from_code->setCallingConv(CallingConv::C);
-}
-AttrListPtr func_art_push_shadow_frame_noinline_from_code_PAL;
-func_art_push_shadow_frame_noinline_from_code->setAttributes(func_art_push_shadow_frame_noinline_from_code_PAL);
-
 Function* func_art_pop_shadow_frame_from_code = mod->getFunction("art_pop_shadow_frame_from_code");
 if (!func_art_pop_shadow_frame_from_code) {
 func_art_pop_shadow_frame_from_code = Function::Create(
diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h
index 46c37f1..f21cfaf 100644
--- a/src/compiler_llvm/ir_builder.h
+++ b/src/compiler_llvm/ir_builder.h
@@ -120,8 +120,8 @@
     StoreToObjectOffset(object_addr, offset, new_value, tbaa_.GetMemoryJType(special_ty, j_ty));
   }
 
-  void SetTBAACall(llvm::CallInst* call_inst, TBAASpecialType special_ty) {
-    call_inst->setMetadata(llvm::LLVMContext::MD_tbaa, tbaa_.GetSpecialType(special_ty));
+  void SetTBAA(llvm::Instruction* inst, TBAASpecialType special_ty) {
+    inst->setMetadata(llvm::LLVMContext::MD_tbaa, tbaa_.GetSpecialType(special_ty));
   }
 
 
@@ -217,10 +217,16 @@
   // Runtime Helper Function
   //--------------------------------------------------------------------------
 
+  RuntimeSupportBuilder& Runtime() {
+    return *runtime_support_;
+  }
+
+  // TODO: Deprecate
   llvm::Function* GetRuntime(runtime_support::RuntimeId rt) {
     return runtime_support_->GetRuntimeSupportFunction(rt);
   }
 
+  // TODO: Deprecate
   void SetRuntimeSupport(RuntimeSupportBuilder* runtime_support) {
     // Can only set once. We can't do this on constructor, because RuntimeSupportBuilder needs
     // IRBuilder.
diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc
index e66674c..838c89d 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -109,7 +109,7 @@
   }
 
   // Get thread object
-  llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
   // Shadow stack
   llvm::StructType* shadow_frame_type = irb_.getShadowFrameTy(sirt_size);
@@ -124,21 +124,18 @@
   // Push the shadow frame
   llvm::Value* shadow_frame_upcast = irb_.CreateConstGEP2_32(shadow_frame_, 0, 0);
   llvm::Value* old_shadow_frame =
-      irb_.CreateCall3(irb_.GetRuntime(PushShadowFrame),
-                       shadow_frame_upcast, method_object_addr, irb_.getInt32(sirt_size));
+      irb_.Runtime().EmitPushShadowFrame(shadow_frame_upcast, method_object_addr, sirt_size);
 
   // Get JNIEnv
   llvm::Value* jni_env_object_addr =
-      irb_.LoadFromObjectOffset(thread_object_addr,
-                                Thread::JniEnvOffset().Int32Value(),
-                                irb_.getJObjectTy(),
-                                kTBAAJRuntime);
+      irb_.Runtime().EmitLoadFromThreadOffset(Thread::JniEnvOffset().Int32Value(),
+                                          irb_.getJObjectTy(),
+                                          kTBAAJRuntime);
 
   // Set thread state to kNative
-  irb_.StoreToObjectOffset(thread_object_addr,
-                           Thread::StateOffset().Int32Value(),
-                           irb_.getInt32(kNative),
-                           kTBAARuntimeInfo);
+  irb_.Runtime().EmitStoreToThreadOffset(Thread::StateOffset().Int32Value(),
+                                     irb_.getInt32(kNative),
+                                     kTBAARuntimeInfo);
 
   // Get callee code_addr
   llvm::Value* code_addr =
@@ -227,13 +224,12 @@
   }
 
   // Set thread state to kRunnable
-  irb_.StoreToObjectOffset(thread_object_addr,
-                           Thread::StateOffset().Int32Value(),
-                           irb_.getInt32(kRunnable),
-                           kTBAARuntimeInfo);
+  irb_.Runtime().EmitStoreToThreadOffset(Thread::StateOffset().Int32Value(),
+                                     irb_.getInt32(kRunnable),
+                                     kTBAARuntimeInfo);
 
   // Do a suspend check
-  irb_.CreateCall(irb_.GetRuntime(TestSuspend), thread_object_addr);
+  irb_.Runtime().EmitTestSuspend();
 
   if (return_shorty == 'L') {
     // If the return value is reference, it may point to SIRT, we should decode it.
@@ -260,7 +256,7 @@
                            kTBAARuntimeInfo);
 
   // Pop the shadow frame
-  irb_.CreateCall(irb_.GetRuntime(PopShadowFrame), old_shadow_frame);
+  irb_.Runtime().EmitPopShadowFrame(old_shadow_frame);
 
   // Return!
   if (return_shorty != 'V') {
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index bdad82b..620ba39 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -214,14 +214,10 @@
   frame_address = irb_.CreatePtrToInt(frame_address, irb_.getPtrEquivIntTy());
 
   // Get thread.stack_end_
-  llvm::Value* thread_object_addr =
-    irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
-
   llvm::Value* stack_end =
-    irb_.LoadFromObjectOffset(thread_object_addr,
-                              Thread::StackEndOffset().Int32Value(),
-                              irb_.getPtrEquivIntTy(),
-                              kTBAARuntimeInfo);
+    irb_.Runtime().EmitLoadFromThreadOffset(Thread::StackEndOffset().Int32Value(),
+                                            irb_.getPtrEquivIntTy(),
+                                            kTBAARuntimeInfo);
 
   // Check the frame address < thread.stack_end_ ?
   llvm::Value* is_stack_overflow = irb_.CreateICmpULT(frame_address, stack_end);
@@ -1263,22 +1259,16 @@
 
   DecodedInstruction dec_insn(insn);
 
-  // Get thread
-  llvm::Value* thread_object_addr =
-    irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
-
   // Get thread-local exception field address
   llvm::Value* exception_object_addr =
-    irb_.LoadFromObjectOffset(thread_object_addr,
-                              Thread::ExceptionOffset().Int32Value(),
-                              irb_.getJObjectTy(),
-                              kTBAAJRuntime);
+    irb_.Runtime().EmitLoadFromThreadOffset(Thread::ExceptionOffset().Int32Value(),
+                                            irb_.getJObjectTy(),
+                                            kTBAAJRuntime);
 
   // Set thread-local exception field address to NULL
-  irb_.StoreToObjectOffset(thread_object_addr,
-                           Thread::ExceptionOffset().Int32Value(),
-                           irb_.getJNull(),
-                           kTBAAJRuntime);
+  irb_.Runtime().EmitStoreToThreadOffset(Thread::ExceptionOffset().Int32Value(),
+                                         irb_.getJNull(),
+                                         kTBAAJRuntime);
 
   // Keep the exception object in the Dalvik register
   EmitStoreDalvikReg(dec_insn.vA, kObject, kAccurate, exception_object_addr);
@@ -1464,7 +1454,7 @@
 
     llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
 
-    llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+    llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
     llvm::Function* runtime_func =
       irb_.GetRuntime(InitializeTypeAndVerifyAccess);
@@ -1512,7 +1502,7 @@
 
     llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
 
-    llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+    llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
     EmitUpdateDexPC(dex_pc);
 
@@ -1562,7 +1552,7 @@
     EmitGuard_NullPointerException(dex_pc, object_addr);
   }
 
-  llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
   irb_.CreateCall2(irb_.GetRuntime(LockObject), object_addr, thread_object_addr);
 
@@ -1584,7 +1574,7 @@
 
   EmitUpdateDexPC(dex_pc);
 
-  llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
   irb_.CreateCall2(irb_.GetRuntime(UnlockObject), object_addr, thread_object_addr);
 
@@ -1762,7 +1752,7 @@
 
   llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
 
-  llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
   EmitUpdateDexPC(dex_pc);
 
@@ -1805,7 +1795,7 @@
 
   llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
 
-  llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
   EmitUpdateDexPC(dex_pc);
 
@@ -2508,7 +2498,7 @@
 
   llvm::Value* method_object_addr = EmitLoadMethodObjectAddr();
 
-  llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
   EmitUpdateDexPC(dex_pc);
 
@@ -3039,7 +3029,7 @@
 
   llvm::Value* caller_method_object_addr = EmitLoadMethodObjectAddr();
 
-  llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
+  llvm::Value* thread_object_addr = irb_.Runtime().EmitGetCurrentThread();
 
   EmitUpdateDexPC(dex_pc);
 
@@ -3694,8 +3684,7 @@
     return;
   }
 
-  llvm::Value* exception_pending =
-    irb_.CreateCall(irb_.GetRuntime(IsExceptionPending));
+  llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending();
 
   llvm::BasicBlock* block_cont = CreateBasicBlockWithDexPC(dex_pc, "cont");
 
@@ -3715,11 +3704,7 @@
     return;
   }
 
-  llvm::Value* runtime_func = irb_.GetRuntime(TestSuspend);
-
-  llvm::Value* thread_object_addr = irb_.CreateCall(irb_.GetRuntime(GetCurrentThread));
-
-  irb_.CreateCall(runtime_func, thread_object_addr);
+  irb_.Runtime().EmitTestSuspend();
 }
 
 
@@ -3960,9 +3945,15 @@
   llvm::Value* shadow_frame_upcast =
     irb_.CreateConstGEP2_32(shadow_frame_, 0, 0);
 
-  llvm::Value* result =
-      irb_.CreateCall3(irb_.GetRuntime(is_inline ? PushShadowFrame : PushShadowFrameNoInline),
-                       shadow_frame_upcast, method_object_addr, irb_.getJInt(shadow_frame_size_));
+  llvm::Value* result;
+  if (is_inline) {
+    result = irb_.Runtime().EmitPushShadowFrame(shadow_frame_upcast, method_object_addr,
+                                                shadow_frame_size_);
+  } else {
+    DCHECK(shadow_frame_size_ == 0);
+    result = irb_.Runtime().EmitPushShadowFrameNoInline(shadow_frame_upcast, method_object_addr,
+                                                        shadow_frame_size_);
+  }
   irb_.CreateStore(result, old_shadow_frame_, kTBAARegister);
 }
 
@@ -3981,14 +3972,12 @@
     irb_.CreateCondBr(need_pop, bb_pop, bb_cont, kUnlikely);
 
     irb_.SetInsertPoint(bb_pop);
-    irb_.CreateCall(irb_.GetRuntime(PopShadowFrame),
-                    irb_.CreateLoad(old_shadow_frame_, kTBAARegister));
+    irb_.Runtime().EmitPopShadowFrame(irb_.CreateLoad(old_shadow_frame_, kTBAARegister));
     irb_.CreateBr(bb_cont);
 
     irb_.SetInsertPoint(bb_cont);
   } else {
-    irb_.CreateCall(irb_.GetRuntime(PopShadowFrame),
-                    irb_.CreateLoad(old_shadow_frame_, kTBAARegister));
+    irb_.Runtime().EmitPopShadowFrame(irb_.CreateLoad(old_shadow_frame_, kTBAARegister));
   }
 }
 
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);
diff --git a/src/compiler_llvm/runtime_support_builder.h b/src/compiler_llvm/runtime_support_builder.h
index 422285c..89cf30a 100644
--- a/src/compiler_llvm/runtime_support_builder.h
+++ b/src/compiler_llvm/runtime_support_builder.h
@@ -17,13 +17,18 @@
 #ifndef ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
 #define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
 
+#include "backend_types.h"
 #include "logging.h"
 #include "runtime_support_func.h"
 
+#include <stdint.h>
+
 namespace llvm {
   class LLVMContext;
   class Module;
   class Function;
+  class Type;
+  class Value;
 }
 
 namespace art {
@@ -36,6 +41,25 @@
  public:
   RuntimeSupportBuilder(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb);
 
+  /* Thread */
+  virtual llvm::Value* EmitGetCurrentThread();
+  virtual llvm::Value* EmitLoadFromThreadOffset(int64_t offset, llvm::Type* type,
+                                                TBAASpecialType s_ty);
+  virtual void EmitStoreToThreadOffset(int64_t offset, llvm::Value* value,
+                                       TBAASpecialType s_ty);
+  virtual void EmitSetCurrentThread(llvm::Value* thread);
+
+  /* ShadowFrame */
+  virtual llvm::Value* EmitPushShadowFrame(llvm::Value* new_shadow_frame,
+                                       llvm::Value* method, uint32_t size);
+  virtual llvm::Value* EmitPushShadowFrameNoInline(llvm::Value* new_shadow_frame,
+                                               llvm::Value* method, uint32_t size);
+  virtual void EmitPopShadowFrame(llvm::Value* old_shadow_frame);
+
+  /* Check */
+  virtual llvm::Value* EmitIsExceptionPending();
+  virtual void EmitTestSuspend();
+
   llvm::Function* GetRuntimeSupportFunction(runtime_support::RuntimeId id) {
     if (id >= 0 && id < runtime_support::MAX_ID) {
       return runtime_support_func_decls_[id];
@@ -56,10 +80,6 @@
 
   void OverrideRuntimeSupportFunction(runtime_support::RuntimeId id, llvm::Function* function);
 
- private:
-  // Target can override this function to make some runtime support more efficient.
-  virtual void TargetOptimizeRuntimeSupport() {}
-
 
  protected:
   llvm::LLVMContext& context_;
diff --git a/src/compiler_llvm/runtime_support_builder_arm.cc b/src/compiler_llvm/runtime_support_builder_arm.cc
index 6d5c1e7..a180520 100644
--- a/src/compiler_llvm/runtime_support_builder_arm.cc
+++ b/src/compiler_llvm/runtime_support_builder_arm.cc
@@ -33,37 +33,43 @@
 namespace art {
 namespace compiler_llvm {
 
-using namespace runtime_support;
 
+llvm::Value* RuntimeSupportBuilderARM::EmitGetCurrentThread() {
+  Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
+  InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), "mov $0, r9", "=r", false);
+  CallInst* thread = irb_.CreateCall(func);
+  thread->setDoesNotAccessMemory();
+  irb_.SetTBAA(thread, kTBAAConstJObject);
+  return thread;
+}
 
-void RuntimeSupportBuilderARM::TargetOptimizeRuntimeSupport() {
-  {
-    Function* func = GetRuntimeSupportFunction(GetCurrentThread);
-    MakeFunctionInline(func);
-    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
-    irb_.SetInsertPoint(basic_block);
+llvm::Value* RuntimeSupportBuilderARM::EmitLoadFromThreadOffset(int64_t offset, llvm::Type* type,
+                                                                TBAASpecialType s_ty) {
+  FunctionType* func_ty = FunctionType::get(/*Result=*/type,
+                                            /*isVarArg=*/false);
+  std::string inline_asm(StringPrintf("ldr $0, [r9, #%d]", static_cast<int>(offset)));
+  InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "=r", true);
+  CallInst* result = irb_.CreateCall(func);
+  result->setOnlyReadsMemory();
+  irb_.SetTBAA(result, s_ty);
+  return result;
+}
 
-    InlineAsm* get_r9 = InlineAsm::get(func->getFunctionType(), "mov $0, r9", "=r", false);
-    CallInst* r9 = irb_.CreateCall(get_r9);
-    r9->setOnlyReadsMemory();
-    irb_.CreateRet(r9);
+void RuntimeSupportBuilderARM::EmitStoreToThreadOffset(int64_t offset, llvm::Value* value,
+                                                       TBAASpecialType s_ty) {
+  FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_),
+                                            /*Params=*/value->getType(),
+                                            /*isVarArg=*/false);
+  std::string inline_asm(StringPrintf("str $0, [r9, #%d]", static_cast<int>(offset)));
+  InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "r", true);
+  CallInst* call_inst = irb_.CreateCall(func, value);
+  irb_.SetTBAA(call_inst, s_ty);
+}
 
-    VERIFY_LLVM_FUNCTION(*func);
-  }
-
-  {
-    Function* func = GetRuntimeSupportFunction(SetCurrentThread);
-    MakeFunctionInline(func);
-    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
-    irb_.SetInsertPoint(basic_block);
-
-    InlineAsm* set_r9 = InlineAsm::get(func->getFunctionType(), "mov r9, $0", "r", true);
-    Value* thread = func->arg_begin();
-    irb_.CreateCall(set_r9, thread);
-    irb_.CreateRetVoid();
-
-    VERIFY_LLVM_FUNCTION(*func);
-  }
+void RuntimeSupportBuilderARM::EmitSetCurrentThread(llvm::Value* thread) {
+  Function* ori_func = GetRuntimeSupportFunction(runtime_support::SetCurrentThread);
+  InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), "mov r9, $0", "r", true);
+  irb_.CreateCall(func, thread);
 }
 
 
diff --git a/src/compiler_llvm/runtime_support_builder_arm.h b/src/compiler_llvm/runtime_support_builder_arm.h
index e179366..bf8a589 100644
--- a/src/compiler_llvm/runtime_support_builder_arm.h
+++ b/src/compiler_llvm/runtime_support_builder_arm.h
@@ -26,8 +26,14 @@
  public:
   RuntimeSupportBuilderARM(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb)
     : RuntimeSupportBuilder(context, module, irb) {}
- private:
-  virtual void TargetOptimizeRuntimeSupport();
+
+  /* Thread */
+  virtual llvm::Value* EmitGetCurrentThread();
+  virtual llvm::Value* EmitLoadFromThreadOffset(int64_t offset, llvm::Type* type,
+                                                TBAASpecialType s_ty);
+  virtual void EmitStoreToThreadOffset(int64_t offset, llvm::Value* value,
+                                       TBAASpecialType s_ty);
+  virtual void EmitSetCurrentThread(llvm::Value* thread);
 };
 
 } // namespace compiler_llvm
diff --git a/src/compiler_llvm/runtime_support_builder_x86.cc b/src/compiler_llvm/runtime_support_builder_x86.cc
index c83c22d..1a0a78a 100644
--- a/src/compiler_llvm/runtime_support_builder_x86.cc
+++ b/src/compiler_llvm/runtime_support_builder_x86.cc
@@ -17,6 +17,7 @@
 #include "runtime_support_builder_x86.h"
 
 #include "ir_builder.h"
+#include "stringprintf.h"
 #include "thread.h"
 #include "utils_llvm.h"
 
@@ -33,38 +34,42 @@
 namespace art {
 namespace compiler_llvm {
 
-using namespace runtime_support;
 
+llvm::Value* RuntimeSupportBuilderX86::EmitGetCurrentThread() {
+  Function* ori_func = GetRuntimeSupportFunction(runtime_support::GetCurrentThread);
+  std::string inline_asm(StringPrintf("movl %%fs:%d, $0", Thread::SelfOffset().Int32Value()));
+  InlineAsm* func = InlineAsm::get(ori_func->getFunctionType(), inline_asm, "=r", false);
+  CallInst* thread = irb_.CreateCall(func);
+  thread->setDoesNotAccessMemory();
+  irb_.SetTBAA(thread, kTBAAConstJObject);
+  return thread;
+}
 
-void RuntimeSupportBuilderX86::TargetOptimizeRuntimeSupport() {
-  {
-    Function* func = GetRuntimeSupportFunction(GetCurrentThread);
-    MakeFunctionInline(func);
-    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
-    irb_.SetInsertPoint(basic_block);
+llvm::Value* RuntimeSupportBuilderX86::EmitLoadFromThreadOffset(int64_t offset, llvm::Type* type,
+                                                                TBAASpecialType s_ty) {
+  FunctionType* func_ty = FunctionType::get(/*Result=*/type,
+                                            /*isVarArg=*/false);
+  std::string inline_asm(StringPrintf("movl %%fs:%d, $0", static_cast<int>(offset)));
+  InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "=r", true);
+  CallInst* result = irb_.CreateCall(func);
+  result->setOnlyReadsMemory();
+  irb_.SetTBAA(result, s_ty);
+  return result;
+}
 
-    std::vector<Type*> func_ty_args;
-    func_ty_args.push_back(irb_.getPtrEquivIntTy());
-    FunctionType* func_ty = FunctionType::get(/*Result=*/irb_.getJObjectTy(),
-                                              /*Params=*/func_ty_args,
-                                              /*isVarArg=*/false);
-    InlineAsm* get_fp = InlineAsm::get(func_ty, "movl %fs:($1), $0", "=r,r", false);
-    CallInst* fp = irb_.CreateCall(get_fp, irb_.getPtrEquivInt(Thread::SelfOffset().Int32Value()));
-    fp->setDoesNotAccessMemory();
-    irb_.CreateRet(fp);
+void RuntimeSupportBuilderX86::EmitStoreToThreadOffset(int64_t offset, llvm::Value* value,
+                                                       TBAASpecialType s_ty) {
+  FunctionType* func_ty = FunctionType::get(/*Result=*/Type::getVoidTy(context_),
+                                            /*Params=*/value->getType(),
+                                            /*isVarArg=*/false);
+  std::string inline_asm(StringPrintf("movl $0, %%fs:%d", static_cast<int>(offset)));
+  InlineAsm* func = InlineAsm::get(func_ty, inline_asm, "r", true);
+  CallInst* call_inst = irb_.CreateCall(func, value);
+  irb_.SetTBAA(call_inst, s_ty);
+}
 
-    VERIFY_LLVM_FUNCTION(*func);
-  }
-
-  {
-    Function* func = GetRuntimeSupportFunction(SetCurrentThread);
-    MakeFunctionInline(func);
-    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
-    irb_.SetInsertPoint(basic_block);
-    irb_.CreateRetVoid();
-
-    VERIFY_LLVM_FUNCTION(*func);
-  }
+void RuntimeSupportBuilderX86::EmitSetCurrentThread(llvm::Value*) {
+  /* Nothing to be done. */
 }
 
 
diff --git a/src/compiler_llvm/runtime_support_builder_x86.h b/src/compiler_llvm/runtime_support_builder_x86.h
index 37de81b..ee5d0a3 100644
--- a/src/compiler_llvm/runtime_support_builder_x86.h
+++ b/src/compiler_llvm/runtime_support_builder_x86.h
@@ -26,8 +26,14 @@
  public:
   RuntimeSupportBuilderX86(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb)
     : RuntimeSupportBuilder(context, module, irb) {}
- private:
-  virtual void TargetOptimizeRuntimeSupport();
+
+  /* Thread */
+  virtual llvm::Value* EmitGetCurrentThread();
+  virtual llvm::Value* EmitLoadFromThreadOffset(int64_t offset, llvm::Type* type,
+                                                TBAASpecialType s_ty);
+  virtual void EmitStoreToThreadOffset(int64_t offset, llvm::Value* value,
+                                       TBAASpecialType s_ty);
+  virtual void EmitSetCurrentThread(llvm::Value* thread);
 };
 
 } // namespace compiler_llvm
diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h
index 74af5da..62729c6 100644
--- a/src/compiler_llvm/runtime_support_func_list.h
+++ b/src/compiler_llvm/runtime_support_func_list.h
@@ -20,7 +20,6 @@
   V(GetCurrentThread, art_get_current_thread_from_code) \
   V(SetCurrentThread, art_set_current_thread_from_code) \
   V(PushShadowFrame, art_push_shadow_frame_from_code) \
-  V(PushShadowFrameNoInline, art_push_shadow_frame_noinline_from_code) \
   V(PopShadowFrame, art_pop_shadow_frame_from_code) \
   V(TestSuspend, art_test_suspend_from_code) \
   V(ThrowException, art_throw_exception_from_code) \
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 08e5921..578f84e 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -80,15 +80,12 @@
   Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
 }
 
-void* art_push_shadow_frame_from_code(void* new_shadow_frame, Object* method, uint32_t size) {
-  LOG(FATAL) << "Implemented by IRBuilder.";
-  return NULL;
-}
-
-void* art_push_shadow_frame_noinline_from_code(void* new_shadow_frame,
-                                               Object* method, uint32_t size) {
-  LOG(FATAL) << "Implemented by IRBuilder.";
-  return NULL;
+ShadowFrame* art_push_shadow_frame_from_code(Thread* thread, ShadowFrame* new_shadow_frame,
+                                             Method* method, uint32_t size) {
+  ShadowFrame* old_frame = thread->PushShadowFrame(new_shadow_frame);
+  new_shadow_frame->SetMethod(method);
+  new_shadow_frame->SetNumberOfReferences(size);
+  return old_frame;
 }
 
 void art_pop_shadow_frame_from_code(void*) {
diff --git a/src/compiler_llvm/runtime_support_llvm.h b/src/compiler_llvm/runtime_support_llvm.h
index 5647c54..bca9528 100644
--- a/src/compiler_llvm/runtime_support_llvm.h
+++ b/src/compiler_llvm/runtime_support_llvm.h
@@ -36,10 +36,8 @@
 // Thread
 //----------------------------------------------------------------------------
 
-void* art_push_shadow_frame_from_code(void* new_shadow_frame, Object* method, uint32_t size);
-
-void* art_push_shadow_frame_noinline_from_code(void* new_shadow_frame,
-                                               Object* method, uint32_t size);
+ShadowFrame* art_push_shadow_frame_from_code(Thread* thread, ShadowFrame* new_shadow_frame,
+                                             Method* method, uint32_t size);
 
 void art_pop_shadow_frame_from_code(void*);
 
diff --git a/src/compiler_llvm/upcall_compiler.cc b/src/compiler_llvm/upcall_compiler.cc
index 37dc981..0f3a92e 100644
--- a/src/compiler_llvm/upcall_compiler.cc
+++ b/src/compiler_llvm/upcall_compiler.cc
@@ -91,7 +91,7 @@
   llvm::Value* retval_addr = arg_iter++;
 
   // Setup thread pointer
-  irb_.CreateCall(irb_.GetRuntime(SetCurrentThread), thread_object_addr);
+  irb_.Runtime().EmitSetCurrentThread(thread_object_addr);
 
   // Accurate function type
   llvm::Type* accurate_ret_type = irb_.getJType(shorty[0], kAccurate);
@@ -158,7 +158,7 @@
   llvm::Value* code_addr = irb_.CreatePointerCast(result, accurate_func_type->getPointerTo());
 
   // Exception unwind.
-  llvm::Value* exception_pending = irb_.CreateCall(irb_.GetRuntime(IsExceptionPending));
+  llvm::Value* exception_pending = irb_.Runtime().EmitIsExceptionPending();
   llvm::BasicBlock* block_unwind = llvm::BasicBlock::Create(*context_, "exception_unwind", func);
   llvm::BasicBlock* block_cont = llvm::BasicBlock::Create(*context_, "cont", func);
   irb_.CreateCondBr(exception_pending, block_unwind, block_cont);
diff --git a/src/shadow_frame.h b/src/shadow_frame.h
index b1ec81f..c4a633f 100644
--- a/src/shadow_frame.h
+++ b/src/shadow_frame.h
@@ -32,11 +32,19 @@
     return number_of_references_;
   }
 
+  void SetNumberOfReferences(uint32_t number_of_references) {
+    number_of_references_ = number_of_references;
+  }
+
   // Caller dex pc
   uint32_t GetDexPC() const {
     return dex_pc_;
   }
 
+  void SetDexPC(uint32_t dex_pc) {
+    dex_pc_ = dex_pc;
+  }
+
   // Link to previous shadow frame or NULL
   ShadowFrame* GetLink() const {
     return link_;
@@ -62,6 +70,11 @@
     return method_;
   }
 
+  void SetMethod(Method* method) {
+    DCHECK_NE(method, static_cast<void*>(NULL));
+    method_ = method;
+  }
+
   bool Contains(Object** shadow_frame_entry) const {
     // A ShadowFrame should at least contain a reference. Even if a
     // native method has no argument, we put jobject or jclass as a
diff --git a/src/thread.cc b/src/thread.cc
index ed6c80f..51b8e31 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1182,18 +1182,6 @@
   return pc;
 }
 
-void Thread::PushShadowFrame(ShadowFrame* frame) {
-  frame->SetLink(top_shadow_frame_);
-  top_shadow_frame_ = frame;
-}
-
-ShadowFrame* Thread::PopShadowFrame() {
-  CHECK(top_shadow_frame_ != NULL);
-  ShadowFrame* frame = top_shadow_frame_;
-  top_shadow_frame_ = frame->GetLink();
-  return frame;
-}
-
 void Thread::PushSirt(StackIndirectReferenceTable* sirt) {
   sirt->SetLink(top_sirt_);
   top_sirt_ = sirt;
diff --git a/src/thread.h b/src/thread.h
index 9ebe00c..f51b581 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -35,6 +35,7 @@
 #include "oat/runtime/oat_support_entrypoints.h"
 #include "offsets.h"
 #include "runtime_stats.h"
+#include "shadow_frame.h"
 #include "stack.h"
 #include "trace.h"
 #include "UniquePtr.h"
@@ -436,8 +437,19 @@
     return ThreadOffset(OFFSETOF_MEMBER(Thread, top_of_managed_stack_pc_));
   }
 
-  void PushShadowFrame(ShadowFrame* frame);
-  ShadowFrame* PopShadowFrame();
+  ShadowFrame* PushShadowFrame(ShadowFrame* frame) {
+    ShadowFrame* old_frame = top_shadow_frame_;
+    top_shadow_frame_ = frame;
+    frame->SetLink(old_frame);
+    return old_frame;
+  }
+
+  ShadowFrame* PopShadowFrame() {
+    CHECK(top_shadow_frame_ != NULL);
+    ShadowFrame* frame = top_shadow_frame_;
+    top_shadow_frame_ = frame->GetLink();
+    return frame;
+  }
 
   static ThreadOffset TopShadowFrameOffset() {
     return ThreadOffset(OFFSETOF_MEMBER(Thread, top_shadow_frame_));