Implement runtime support inlining.

Change-Id: I8608b246a4dfde9959b5b86872f65dfa61646c84
diff --git a/build/Android.libart-compiler-llvm.mk b/build/Android.libart-compiler-llvm.mk
index c8c091e..d52e6d2 100644
--- a/build/Android.libart-compiler-llvm.mk
+++ b/build/Android.libart-compiler-llvm.mk
@@ -27,6 +27,9 @@
 	src/compiler_llvm/ir_builder.cc \
 	src/compiler_llvm/jni_compiler.cc \
 	src/compiler_llvm/method_compiler.cc \
+	src/compiler_llvm/runtime_support_builder.cc \
+	src/compiler_llvm/runtime_support_builder_arm.cc \
+	src/compiler_llvm/runtime_support_builder_x86.cc \
 	src/compiler_llvm/runtime_support_llvm.cc \
 	src/compiler_llvm/upcall_compiler.cc
 
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index b3a9c71..fde023c 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -20,6 +20,9 @@
 #include "ir_builder.h"
 #include "logging.h"
 
+#include "runtime_support_builder_arm.h"
+#include "runtime_support_builder_x86.h"
+
 #include <llvm/ADT/OwningPtr.h>
 #include <llvm/ADT/StringSet.h>
 #include <llvm/ADT/Triple.h>
@@ -70,6 +73,24 @@
 
   // Create IRBuilder
   irb_.reset(new IRBuilder(*context_, *module_));
+
+  // We always need a switch case, so just use a normal function.
+  switch(insn_set_) {
+    default:
+      runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
+      break;
+  case kArm:
+  case kThumb2:
+    runtime_support_.reset(new RuntimeSupportBuilderARM(*context_, *module_, *irb_));
+    break;
+  case kX86:
+    runtime_support_.reset(new RuntimeSupportBuilderX86(*context_, *module_, *irb_));
+    break;
+  }
+
+  runtime_support_->OptimizeRuntimeSupport();
+
+  irb_->SetRuntimeSupport(runtime_support_.get());
 }
 
 
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
index 1db54fc..4b33ece 100644
--- a/src/compiler_llvm/compilation_unit.h
+++ b/src/compiler_llvm/compilation_unit.h
@@ -21,6 +21,8 @@
 #include "globals.h"
 #include "instruction_set.h"
 #include "logging.h"
+#include "runtime_support_builder.h"
+#include "runtime_support_func.h"
 
 #include <UniquePtr.h>
 #include <string>
@@ -100,6 +102,7 @@
 
   UniquePtr<llvm::LLVMContext> context_;
   UniquePtr<IRBuilder> irb_;
+  UniquePtr<RuntimeSupportBuilder> runtime_support_;
   llvm::Module* module_;
 
   std::string elf_image_;
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index f9af139..baa6b2f 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -42,6 +42,8 @@
   extern bool TimePassesIsEnabled;
 }
 
+extern llvm::cl::opt<bool> ReserveR9;
+// ReserveR9 is defined in llvm/lib/Target/ARM/ARMSubtarget.cpp
 extern llvm::cl::opt<bool> EnableARMLongCalls;
 // NOTE: Although EnableARMLongCalls is defined in llvm/lib/Target/ARM/
 // ARMISelLowering.cpp, however, it is not in the llvm namespace.
@@ -55,6 +57,9 @@
   // NOTE: Uncomment following line to show the time consumption of LLVM passes
   //llvm::TimePassesIsEnabled = true;
 
+  // Enable -arm-reserve-r9
+  ReserveR9 = true;
+
   // Initialize LLVM target, MC subsystem, asm printer, and asm parser
   llvm::InitializeAllTargets();
   llvm::InitializeAllTargetMCs();
diff --git a/src/compiler_llvm/ir_builder.cc b/src/compiler_llvm/ir_builder.cc
index 1a27d02..4afb8bc 100644
--- a/src/compiler_llvm/ir_builder.cc
+++ b/src/compiler_llvm/ir_builder.cc
@@ -15,7 +15,6 @@
  */
 
 #include "ir_builder.h"
-#include "runtime_support_func.h"
 #include "stringprintf.h"
 
 #include <llvm/Module.h>
@@ -44,41 +43,7 @@
   art_frame_type_ = module.getTypeByName("ShadowFrame");
   CHECK(art_frame_type_ != NULL);
 
-  // Load the runtime support function declaration from module
-  InitRuntimeSupportFuncDecl();
-}
-
-
-//----------------------------------------------------------------------------
-// Runtime Helper Function
-//----------------------------------------------------------------------------
-
-void IRBuilder::InitRuntimeSupportFuncDecl() {
-  using namespace runtime_support;
-
-#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
-  do { \
-    llvm::Function* fn = module_->getFunction(#NAME); \
-    DCHECK_NE(fn, (void*)NULL) << "Function not found: " << #NAME; \
-    runtime_support_func_decls_[ID] = fn; \
-  } while (0);
-
-#include "runtime_support_func_list.h"
-  RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
-#undef RUNTIME_SUPPORT_FUNC_LIST
-#undef GET_RUNTIME_SUPPORT_FUNC_DECL
-}
-
-
-llvm::Function* IRBuilder::GetRuntime(runtime_support::RuntimeId rt) const {
-  using namespace runtime_support;
-
-  if (rt >= 0 && rt < MAX_ID) {
-    return runtime_support_func_decls_[rt];
-  } else {
-    LOG(ERROR) << "Unknown runtime function id: " << rt;
-    return NULL;
-  }
+  runtime_support_ = NULL;
 }
 
 
diff --git a/src/compiler_llvm/ir_builder.h b/src/compiler_llvm/ir_builder.h
index d199b76..9c8e229 100644
--- a/src/compiler_llvm/ir_builder.h
+++ b/src/compiler_llvm/ir_builder.h
@@ -18,6 +18,7 @@
 #define ART_SRC_COMPILER_LLVM_IR_BUILDER_H_
 
 #include "backend_types.h"
+#include "runtime_support_builder.h"
 #include "runtime_support_func.h"
 
 #include <llvm/Constants.h>
@@ -114,7 +115,17 @@
   // Runtime Helper Function
   //--------------------------------------------------------------------------
 
-  llvm::Function* GetRuntime(runtime_support::RuntimeId rt) const;
+  llvm::Function* GetRuntime(runtime_support::RuntimeId rt) {
+    return runtime_support_->GetRuntimeSupportFunction(rt);
+  }
+
+  void SetRuntimeSupport(RuntimeSupportBuilder* runtime_support) {
+    // Can only set once. We can't do this on constructor, because RuntimeSupportBuilder needs
+    // IRBuilder.
+    if (runtime_support_ == NULL && runtime_support != NULL) {
+      runtime_support_ = runtime_support;
+    }
+  }
 
 
   //--------------------------------------------------------------------------
@@ -282,13 +293,6 @@
 
  private:
   //--------------------------------------------------------------------------
-  // Runtime Helper Function (Private)
-  //--------------------------------------------------------------------------
-
-  void InitRuntimeSupportFuncDecl();
-
-
-  //--------------------------------------------------------------------------
   // Type Helper Function (Private)
   //--------------------------------------------------------------------------
 
@@ -306,7 +310,7 @@
 
   llvm::StructType* art_frame_type_;
 
-  llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID];
+  RuntimeSupportBuilder* runtime_support_;
 
 };
 
diff --git a/src/compiler_llvm/runtime_support_builder.cc b/src/compiler_llvm/runtime_support_builder.cc
new file mode 100644
index 0000000..4183df6
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder.cc
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "runtime_support_builder.h"
+
+#include "ir_builder.h"
+#include "shadow_frame.h"
+#include "thread.h"
+
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/Module.h>
+#include <llvm/Type.h>
+
+using namespace llvm;
+
+namespace art {
+namespace compiler_llvm {
+
+using namespace runtime_support;
+
+
+RuntimeSupportBuilder::RuntimeSupportBuilder(llvm::LLVMContext& context,
+                                             llvm::Module& module,
+                                             IRBuilder& irb)
+    : context_(context), module_(module), irb_(irb)
+{
+#define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
+  do { \
+    llvm::Function* fn = module_.getFunction(#NAME); \
+    DCHECK_NE(fn, (void*)NULL) << "Function not found: " << #NAME; \
+    runtime_support_func_decls_[ID] = fn; \
+  } while (0);
+
+#include "runtime_support_func_list.h"
+  RUNTIME_SUPPORT_FUNC_LIST(GET_RUNTIME_SUPPORT_FUNC_DECL)
+#undef RUNTIME_SUPPORT_FUNC_LIST
+#undef GET_RUNTIME_SUPPORT_FUNC_DECL
+}
+
+void RuntimeSupportBuilder::MakeFunctionInline(llvm::Function* func) {
+  func->setLinkage(GlobalValue::LinkOnceODRLinkage);
+
+  SmallVector<AttributeWithIndex, 4> Attrs;
+  AttributeWithIndex PAWI;
+  PAWI.Index = ~0U;
+  PAWI.Attrs = Attribute::None | Attribute::NoUnwind | Attribute::AlwaysInline;
+  Attrs.push_back(PAWI);
+  AttrListPtr func_PAL = AttrListPtr::get(Attrs.begin(), Attrs.end());
+
+  func->setAttributes(func_PAL);
+}
+
+void RuntimeSupportBuilder::OverrideRuntimeSupportFunction(RuntimeId id, llvm::Function* function) {
+  // TODO: Check function prototype.
+  if (id >= 0 && id < MAX_ID) {
+    runtime_support_func_decls_[id] = function;
+    target_runtime_support_func_[id] = true;
+  } else {
+    LOG(ERROR) << "Unknown runtime function id: " << id;
+  }
+}
+
+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);
+    Value* new_shadow_frame = func->arg_begin();
+    Value* old_shadow_frame = irb_.LoadFromObjectOffset(thread,
+                                                        Thread::TopShadowFrameOffset().Int32Value(),
+                                                        irb_.getJObjectTy());
+    irb_.StoreToObjectOffset(new_shadow_frame,
+                             ShadowFrame::LinkOffset(),
+                             old_shadow_frame);
+    irb_.StoreToObjectOffset(thread,
+                             Thread::TopShadowFrameOffset().Int32Value(),
+                             new_shadow_frame);
+    irb_.CreateRetVoid();
+  }
+
+  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* new_shadow_frame = irb_.LoadFromObjectOffset(thread,
+                                                        Thread::TopShadowFrameOffset().Int32Value(),
+                                                        irb_.getJObjectTy());
+    Value* old_shadow_frame = irb_.LoadFromObjectOffset(new_shadow_frame,
+                                                        ShadowFrame::LinkOffset(),
+                                                        irb_.getJObjectTy());
+    irb_.StoreToObjectOffset(thread,
+                             Thread::TopShadowFrameOffset().Int32Value(),
+                             old_shadow_frame);
+    irb_.CreateRetVoid();
+  }
+
+  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());
+    Value* is_exception_not_null = irb_.CreateICmpNE(exception, irb_.getJNull());
+    irb_.CreateRet(is_exception_not_null);
+  }
+
+  if (!target_runtime_support_func_[TestSuspend]) {
+    Function* slow_func = GetRuntimeSupportFunction(TestSuspend);
+
+    Function* func = Function::Create(slow_func->getFunctionType(),
+                                      GlobalValue::LinkOnceODRLinkage,
+                                      "test_suspend_fast",
+                                      &module_);
+    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* suspend_count = irb_.LoadFromObjectOffset(thread,
+                                                     Thread::SuspendCountOffset().Int32Value(),
+                                                     irb_.getJIntTy());
+    Value* is_suspend = irb_.CreateICmpNE(suspend_count, irb_.getJInt(0));
+
+    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);
+    irb_.SetInsertPoint(basic_block_suspend);
+    irb_.CreateCall(slow_func);
+    irb_.CreateBr(basic_block_else);
+    irb_.SetInsertPoint(basic_block_else);
+    irb_.CreateRetVoid();
+
+    OverrideRuntimeSupportFunction(TestSuspend, func);
+  }
+}
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/runtime_support_builder.h b/src/compiler_llvm/runtime_support_builder.h
new file mode 100644
index 0000000..422285c
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
+#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
+
+#include "logging.h"
+#include "runtime_support_func.h"
+
+namespace llvm {
+  class LLVMContext;
+  class Module;
+  class Function;
+}
+
+namespace art {
+namespace compiler_llvm {
+
+class IRBuilder;
+
+
+class RuntimeSupportBuilder {
+ public:
+  RuntimeSupportBuilder(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb);
+
+  llvm::Function* GetRuntimeSupportFunction(runtime_support::RuntimeId id) {
+    if (id >= 0 && id < runtime_support::MAX_ID) {
+      return runtime_support_func_decls_[id];
+    } else {
+      LOG(ERROR) << "Unknown runtime function id: " << id;
+      return NULL;
+    }
+  }
+
+  void OptimizeRuntimeSupport();
+
+  virtual ~RuntimeSupportBuilder() {}
+
+ protected:
+  // Mark a function as inline function.
+  // You should implement the function, if mark as inline.
+  void MakeFunctionInline(llvm::Function* function);
+
+  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_;
+  llvm::Module& module_;
+  IRBuilder& irb_;
+
+ private:
+  llvm::Function* runtime_support_func_decls_[runtime_support::MAX_ID];
+  bool target_runtime_support_func_[runtime_support::MAX_ID];
+};
+
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_H_
diff --git a/src/compiler_llvm/runtime_support_builder_arm.cc b/src/compiler_llvm/runtime_support_builder_arm.cc
new file mode 100644
index 0000000..ab33967
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_arm.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "runtime_support_builder_arm.h"
+
+#include "ir_builder.h"
+#include "thread.h"
+
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/InlineAsm.h>
+#include <llvm/Module.h>
+#include <llvm/Type.h>
+
+#include <vector>
+
+using namespace llvm;
+
+namespace art {
+namespace compiler_llvm {
+
+using namespace runtime_support;
+
+
+void RuntimeSupportBuilderARM::TargetOptimizeRuntimeSupport() {
+  {
+    Function* func = GetRuntimeSupportFunction(GetCurrentThread);
+    MakeFunctionInline(func);
+    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+    irb_.SetInsertPoint(basic_block);
+
+    InlineAsm* get_r9 = InlineAsm::get(func->getFunctionType(), "mov $0, r9", "=r", false);
+    Value* r9 = irb_.CreateCall(get_r9);
+    irb_.CreateRet(r9);
+  }
+
+  {
+    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();
+  }
+}
+
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/runtime_support_builder_arm.h b/src/compiler_llvm/runtime_support_builder_arm.h
new file mode 100644
index 0000000..e179366
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_arm.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
+#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
+
+#include "runtime_support_builder.h"
+
+namespace art {
+namespace compiler_llvm {
+
+class RuntimeSupportBuilderARM : public RuntimeSupportBuilder {
+ public:
+  RuntimeSupportBuilderARM(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb)
+    : RuntimeSupportBuilder(context, module, irb) {}
+ private:
+  virtual void TargetOptimizeRuntimeSupport();
+};
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_ARM_H_
diff --git a/src/compiler_llvm/runtime_support_builder_x86.cc b/src/compiler_llvm/runtime_support_builder_x86.cc
new file mode 100644
index 0000000..c381874
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_x86.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "runtime_support_builder_x86.h"
+
+#include "ir_builder.h"
+#include "thread.h"
+
+#include <llvm/DerivedTypes.h>
+#include <llvm/Function.h>
+#include <llvm/InlineAsm.h>
+#include <llvm/Module.h>
+#include <llvm/Type.h>
+
+#include <vector>
+
+using namespace llvm;
+
+namespace art {
+namespace compiler_llvm {
+
+using namespace runtime_support;
+
+
+void RuntimeSupportBuilderX86::TargetOptimizeRuntimeSupport() {
+  {
+    Function* func = GetRuntimeSupportFunction(GetCurrentThread);
+    MakeFunctionInline(func);
+    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+    irb_.SetInsertPoint(basic_block);
+
+    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);
+    Value* fp = irb_.CreateCall(get_fp, irb_.getPtrEquivInt(Thread::SelfOffset().Int32Value()));
+    irb_.CreateRet(fp);
+  }
+
+  {
+    Function* func = GetRuntimeSupportFunction(SetCurrentThread);
+    MakeFunctionInline(func);
+    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+    irb_.SetInsertPoint(basic_block);
+    irb_.CreateRetVoid();
+  }
+}
+
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/runtime_support_builder_x86.h b/src/compiler_llvm/runtime_support_builder_x86.h
new file mode 100644
index 0000000..37de81b
--- /dev/null
+++ b/src/compiler_llvm/runtime_support_builder_x86.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
+#define ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
+
+#include "runtime_support_builder.h"
+
+namespace art {
+namespace compiler_llvm {
+
+class RuntimeSupportBuilderX86 : public RuntimeSupportBuilder {
+ public:
+  RuntimeSupportBuilderX86(llvm::LLVMContext& context, llvm::Module& module, IRBuilder& irb)
+    : RuntimeSupportBuilder(context, module, irb) {}
+ private:
+  virtual void TargetOptimizeRuntimeSupport();
+};
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_RUNTIME_SUPPORT_BUILDER_X86_H_
diff --git a/src/compiler_llvm/runtime_support_func.h b/src/compiler_llvm/runtime_support_func.h
index 480b054..de3ed26 100644
--- a/src/compiler_llvm/runtime_support_func.h
+++ b/src/compiler_llvm/runtime_support_func.h
@@ -19,8 +19,8 @@
 
 namespace art {
 namespace compiler_llvm {
-
 namespace runtime_support {
+
   enum RuntimeId {
 #define DEFINE_RUNTIME_SUPPORT_FUNC_ID(ID, NAME) ID,
 #include "runtime_support_func_list.h"
@@ -30,8 +30,8 @@
 
     MAX_ID
   };
-}
 
+} // namespace runtime_support
 } // namespace compiler_llvm
 } // namespace art
 
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index 18e4842..c526847 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -31,6 +31,8 @@
 #include <cstdarg>
 #include <stdint.h>
 
+#include "asm_support.h"
+
 namespace art {
 
 //----------------------------------------------------------------------------
@@ -38,16 +40,23 @@
 //----------------------------------------------------------------------------
 
 Thread* art_get_current_thread_from_code() {
+#if defined(__i386__)
+  Thread* ptr;
+  asm volatile("movl %%fs:(%1), %0"
+      : "=r"(ptr)  // output
+      : "r"(THREAD_SELF_OFFSET)  // input
+      :);  // clobber
+  return ptr;
+#else
   return Thread::Current();
+#endif
 }
 
 void art_set_current_thread_from_code(void* thread_object_addr) {
-  // TODO: LLVM IR generating something like "r9 = thread_object_addr"
-  // UNIMPLEMENTED(WARNING);
 }
 
 void art_lock_object_from_code(Object* obj) {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   DCHECK(obj != NULL);        // Assumed to have been checked before entry
   obj->MonitorEnter(thread);  // May block
   DCHECK(thread->HoldsLock(obj));
@@ -56,24 +65,24 @@
 }
 
 void art_unlock_object_from_code(Object* obj) {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   DCHECK(obj != NULL);  // Assumed to have been checked before entry
   // MonitorExit may throw exception
   obj->MonitorExit(thread);
 }
 
 void art_test_suspend_from_code() {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   Runtime::Current()->GetThreadList()->FullSuspendCheck(thread);
 }
 
 void art_push_shadow_frame_from_code(void* new_shadow_frame) {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   thread->PushShadowFrame(static_cast<ShadowFrame*>(new_shadow_frame));
 }
 
 void art_pop_shadow_frame_from_code() {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   thread->PopShadowFrame();
 }
 
@@ -84,23 +93,23 @@
 //----------------------------------------------------------------------------
 
 bool art_is_exception_pending_from_code() {
-  return Thread::Current()->IsExceptionPending();
+  return art_get_current_thread_from_code()->IsExceptionPending();
 }
 
 void art_throw_div_zero_from_code() {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   thread->ThrowNewException("Ljava/lang/ArithmeticException;",
                             "divide by zero");
 }
 
 void art_throw_array_bounds_from_code(int32_t length, int32_t index) {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   thread->ThrowNewExceptionF("Ljava/lang/ArrayIndexOutOfBoundsException;",
                              "length=%d; index=%d", length, index);
 }
 
 void art_throw_no_such_method_from_code(int32_t method_idx) {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   // We need the calling method as context for the method_idx
   Frame frame = thread->GetTopOfStack();
   frame.Next();
@@ -113,7 +122,7 @@
 }
 
 void art_throw_null_pointer_exception_from_code(uint32_t dex_pc) {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   NthCallerVisitor visitor(0);
   thread->WalkStack(&visitor);
   Method* throw_method = visitor.caller;
@@ -121,7 +130,7 @@
 }
 
 void art_throw_stack_overflow_from_code() {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   if (Runtime::Current()->IsMethodTracingActive()) {
     TraceMethodUnwindFromCode(thread);
   }
@@ -134,7 +143,7 @@
 }
 
 void art_throw_exception_from_code(Object* exception) {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   if (exception == NULL) {
     thread->ThrowNewException("Ljava/lang/NullPointerException;", "throw with null exception");
   } else {
@@ -145,11 +154,11 @@
 void art_throw_verification_error_from_code(Method* current_method,
                                             int32_t kind,
                                             int32_t ref) {
-  ThrowVerificationError(Thread::Current(), current_method, kind, ref);
+  ThrowVerificationError(art_get_current_thread_from_code(), current_method, kind, ref);
 }
 
 int32_t art_find_catch_block_from_code(Method* current_method, int32_t dex_pc) {
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   Class* exception_type = thread->GetException()->GetClass();
   MethodHelper mh(current_method);
   const DexFile::CodeItem* code_item = mh.GetCodeItem();
@@ -182,33 +191,33 @@
 //----------------------------------------------------------------------------
 
 Object* art_alloc_object_from_code(uint32_t type_idx, Method* referrer) {
-  return AllocObjectFromCode(type_idx, referrer, Thread::Current(), false);
+  return AllocObjectFromCode(type_idx, referrer, art_get_current_thread_from_code(), false);
 }
 
 Object* art_alloc_object_from_code_with_access_check(uint32_t type_idx, Method* referrer) {
-  return AllocObjectFromCode(type_idx, referrer, Thread::Current(), true);
+  return AllocObjectFromCode(type_idx, referrer, art_get_current_thread_from_code(), true);
 }
 
 Object* art_alloc_array_from_code(uint32_t type_idx, Method* referrer, uint32_t length) {
-  return AllocArrayFromCode(type_idx, referrer, length, Thread::Current(), false);
+  return AllocArrayFromCode(type_idx, referrer, length, art_get_current_thread_from_code(), false);
 }
 
 Object* art_alloc_array_from_code_with_access_check(uint32_t type_idx,
                                                     Method* referrer,
                                                     uint32_t length) {
-  return AllocArrayFromCode(type_idx, referrer, length, Thread::Current(), true);
+  return AllocArrayFromCode(type_idx, referrer, length, art_get_current_thread_from_code(), true);
 }
 
 Object* art_check_and_alloc_array_from_code(uint32_t type_idx,
                                             Method* referrer,
                                             uint32_t length) {
-  return CheckAndAllocArrayFromCode(type_idx, referrer, length, Thread::Current(), false);
+  return CheckAndAllocArrayFromCode(type_idx, referrer, length, art_get_current_thread_from_code(), false);
 }
 
 Object* art_check_and_alloc_array_from_code_with_access_check(uint32_t type_idx,
                                                               Method* referrer,
                                                               uint32_t length) {
-  return CheckAndAllocArrayFromCode(type_idx, referrer, length, Thread::Current(), true);
+  return CheckAndAllocArrayFromCode(type_idx, referrer, length, art_get_current_thread_from_code(), true);
 }
 
 static Method* FindMethodHelper(uint32_t method_idx, Object* this_object, Method* caller_method,
@@ -216,13 +225,13 @@
   Method* method = FindMethodFast(method_idx, this_object, caller_method, access_check, type);
   if (UNLIKELY(method == NULL)) {
     method = FindMethodFromCode(method_idx, this_object, caller_method,
-                                Thread::Current(), access_check, type);
+                                art_get_current_thread_from_code(), access_check, type);
     if (UNLIKELY(method == NULL)) {
-      CHECK(Thread::Current()->IsExceptionPending());
+      CHECK(art_get_current_thread_from_code()->IsExceptionPending());
       return 0;  // failure
     }
   }
-  DCHECK(!Thread::Current()->IsExceptionPending());
+  DCHECK(!art_get_current_thread_from_code()->IsExceptionPending());
   return method;
 }
 
@@ -264,17 +273,17 @@
 }
 
 Object* art_initialize_static_storage_from_code(uint32_t type_idx, Method* referrer) {
-  return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), true, false);
+  return ResolveVerifyAndClinit(type_idx, referrer, art_get_current_thread_from_code(), true, false);
 }
 
 Object* art_initialize_type_from_code(uint32_t type_idx, Method* referrer) {
-  return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), false, false);
+  return ResolveVerifyAndClinit(type_idx, referrer, art_get_current_thread_from_code(), false, false);
 }
 
 Object* art_initialize_type_and_verify_access_from_code(uint32_t type_idx, Method* referrer) {
   // Called when caller isn't guaranteed to have access to a type and the dex cache may be
   // unpopulated
-  return ResolveVerifyAndClinit(type_idx, referrer, Thread::Current(), false, true);
+  return ResolveVerifyAndClinit(type_idx, referrer, art_get_current_thread_from_code(), false, true);
 }
 
 Object* art_resolve_string_from_code(Method* referrer, uint32_t string_idx) {
@@ -287,7 +296,7 @@
     field->Set32(NULL, new_value);
     return 0;
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             true, true, true, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(NULL, new_value);
@@ -302,7 +311,7 @@
     field->Set64(NULL, new_value);
     return 0;
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             true, true, true, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(NULL, new_value);
@@ -317,7 +326,7 @@
     field->SetObj(NULL, new_value);
     return 0;
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             true, false, true, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     field->SetObj(NULL, new_value);
@@ -331,7 +340,7 @@
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             true, true, false, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(NULL);
@@ -344,7 +353,7 @@
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             true, true, false, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(NULL);
@@ -357,7 +366,7 @@
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             true, false, false, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(NULL);
@@ -372,7 +381,7 @@
     field->Set32(obj, new_value);
     return 0;
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             false, true, true, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     field->Set32(obj, new_value);
@@ -388,7 +397,7 @@
     field->Set64(obj, new_value);
     return 0;
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             false, true, true, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     field->Set64(obj, new_value);
@@ -404,7 +413,7 @@
     field->SetObj(obj, new_value);
     return 0;
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             false, false, true, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     field->SetObj(obj, new_value);
@@ -418,7 +427,7 @@
   if (LIKELY(field != NULL)) {
     return field->Get32(obj);
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             false, true, false, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
     return field->Get32(obj);
@@ -431,7 +440,7 @@
   if (LIKELY(field != NULL)) {
     return field->Get64(obj);
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             false, true, false, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
     return field->Get64(obj);
@@ -444,7 +453,7 @@
   if (LIKELY(field != NULL)) {
     return field->GetObj(obj);
   }
-  field = FindFieldFromCode(field_idx, referrer, Thread::Current(),
+  field = FindFieldFromCode(field_idx, referrer, art_get_current_thread_from_code(),
                             false, false, false, sizeof(Object*));
   if (LIKELY(field != NULL)) {
     return field->GetObj(obj);
@@ -473,10 +482,11 @@
   DCHECK(dest_type->IsClass()) << PrettyClass(dest_type);
   DCHECK(src_type->IsClass()) << PrettyClass(src_type);
   if (UNLIKELY(!dest_type->IsAssignableFrom(src_type))) {
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
-        "%s cannot be cast to %s",
-        PrettyDescriptor(dest_type).c_str(),
-        PrettyDescriptor(src_type).c_str());
+    Thread* thread = art_get_current_thread_from_code();
+    thread->ThrowNewExceptionF("Ljava/lang/ClassCastException;",
+                               "%s cannot be cast to %s",
+                               PrettyDescriptor(dest_type).c_str(),
+                               PrettyDescriptor(src_type).c_str());
   }
 }
 
@@ -490,10 +500,11 @@
   Class* component_type = array_class->GetComponentType();
   Class* element_class = element->GetClass();
   if (UNLIKELY(!component_type->IsAssignableFrom(element_class))) {
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
-        "%s cannot be stored in an array of type %s",
-        PrettyDescriptor(element_class).c_str(),
-        PrettyDescriptor(array_class).c_str());
+    Thread* thread = art_get_current_thread_from_code();
+    thread->ThrowNewExceptionF("Ljava/lang/ArrayStoreException;",
+                               "%s cannot be stored in an array of type %s",
+                               PrettyDescriptor(element_class).c_str(),
+                               PrettyDescriptor(array_class).c_str());
   }
   return;
 }
@@ -566,7 +577,7 @@
   //                                               Resolve method.
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   called = linker->ResolveMethod(dex_method_idx, caller, !is_virtual);
-  if (UNLIKELY(Thread::Current()->IsExceptionPending())) {
+  if (UNLIKELY(art_get_current_thread_from_code()->IsExceptionPending())) {
     return NULL;
   }
   if (LIKELY(called->IsDirect() == !is_virtual)) {
@@ -575,10 +586,11 @@
     linker->EnsureInitialized(called_class, true, true);
     return called;
   } else {
+    Thread* thread = art_get_current_thread_from_code();
     // Direct method has been made virtual
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
-                                          "Expected direct method but found virtual: %s",
-                                          PrettyMethod(called, true).c_str());
+    thread->ThrowNewExceptionF("Ljava/lang/IncompatibleClassChangeError;",
+                               "Expected direct method but found virtual: %s",
+                               PrettyMethod(called, true).c_str());
     return NULL;
   }
 }
@@ -609,7 +621,7 @@
     } else if (called_class->IsInitializing()) {
       return linker->GetOatCodeFor(called);
     } else {
-      DCHECK(Thread::Current()->IsExceptionPending());
+      DCHECK(art_get_current_thread_from_code()->IsExceptionPending());
       DCHECK(called_class->IsErroneous());
       return NULL;
     }
@@ -617,8 +629,9 @@
 
   // 2. The code address is AbstractMethodErrorStub. -> AbstractMethodErrorStub
   if (UNLIKELY(code == runtime->GetAbstractMethodErrorStubArray()->GetData())) {
-    Thread::Current()->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
-                                          "abstract method \"%s\"", PrettyMethod(called).c_str());
+    art_get_current_thread_from_code()->ThrowNewExceptionF("Ljava/lang/AbstractMethodError;",
+                                                           "abstract method \"%s\"",
+                                                           PrettyMethod(called).c_str());
     return NULL;
   }
 
@@ -638,7 +651,7 @@
   va_start(ap, proxy_method);
 
   Object* receiver = va_arg(ap, Object*);
-  Thread* thread = Thread::Current();
+  Thread* thread = art_get_current_thread_from_code();
   MethodHelper proxy_mh(proxy_method);
   const size_t num_params = proxy_mh.NumArgs();
 
diff --git a/src/shadow_frame.h b/src/shadow_frame.h
index a12abc8..261875e 100644
--- a/src/shadow_frame.h
+++ b/src/shadow_frame.h
@@ -23,6 +23,7 @@
 namespace art {
 
 class Object;
+class Method;
 
 class ShadowFrame {
  public:
diff --git a/src/thread.h b/src/thread.h
index 2cb59d5..4f43473 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -433,6 +433,10 @@
   void PushShadowFrame(ShadowFrame* frame);
   ShadowFrame* PopShadowFrame();
 
+  static ThreadOffset TopShadowFrameOffset() {
+    return ThreadOffset(OFFSETOF_MEMBER(Thread, top_shadow_frame_));
+  }
+
   void PushSirt(StackIndirectReferenceTable* sirt);
   StackIndirectReferenceTable* PopSirt();