Compile llvm.Module into ELF object file.

Change-Id: I8faf7427944324c9bac12573d217cde2a2e658f1
diff --git a/build/Android.common.mk b/build/Android.common.mk
index d564735..3f6b84b 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -204,6 +204,7 @@
 
 ifeq ($(ART_USE_LLVM_COMPILER),true)
 LIBART_COMMON_SRC_FILES += \
+	src/compiler_llvm/compilation_unit.cc \
 	src/compiler_llvm/compiler_llvm.cc \
 	src/compiler_llvm/dalvik_reg.cc \
 	src/compiler_llvm/frontend.cc \
diff --git a/build/Android.libart.mk b/build/Android.libart.mk
index d7ebefe..b049ad9 100644
--- a/build/Android.libart.mk
+++ b/build/Android.libart.mk
@@ -71,7 +71,58 @@
   endif
   LOCAL_C_INCLUDES += $(ART_C_INCLUDES)
   ifeq ($(ART_USE_LLVM_COMPILER),true)
-    LOCAL_STATIC_LIBRARIES += libLLVMBitWriter libLLVMCore libLLVMSupport
+    libart_arm_STATIC_LIBRARIES := \
+      libLLVMARMInfo \
+      libLLVMARMDisassembler \
+      libLLVMARMAsmParser \
+      libLLVMARMAsmPrinter \
+      libLLVMARMCodeGen \
+      libLLVMARMDesc
+
+    libart_mips_STATIC_LIBRARIES := \
+      libLLVMMipsInfo \
+      libLLVMMipsCodeGen \
+      libLLVMMipsDesc \
+      libLLVMMipsAsmPrinter \
+
+    libart_x86_STATIC_LIBRARIES := \
+      libLLVMX86Info \
+      libLLVMX86AsmParser \
+      libLLVMX86CodeGen \
+      libLLVMX86Disassembler \
+      libLLVMX86Desc \
+      libLLVMX86AsmPrinter \
+      libLLVMX86Utils
+
+    ifeq ($$(art_target_or_host),target)
+      LOCAL_STATIC_LIBRARIES += \
+        $$(libart_arm_STATIC_LIBRARIES)
+    else
+      LOCAL_STATIC_LIBRARIES += \
+        $$(libart_arm_STATIC_LIBRARIES) \
+        $$(libart_mips_STATIC_LIBRARIES) \
+        $$(libart_x86_STATIC_LIBRARIES)
+    endif
+
+    LOCAL_STATIC_LIBRARIES += \
+      libLLVMLinker \
+      libLLVMipo \
+      libLLVMBitWriter \
+      libLLVMBitReader \
+      libLLVMAsmPrinter \
+      libLLVMSelectionDAG \
+      libLLVMCodeGen \
+      libLLVMScalarOpts \
+      libLLVMInstCombine \
+      libLLVMInstrumentation \
+      libLLVMTransformUtils \
+      libLLVMipa \
+      libLLVMAnalysis \
+      libLLVMTarget \
+      libLLVMMC \
+      libLLVMMCParser \
+      libLLVMCore \
+      libLLVMSupport
   endif
   LOCAL_SHARED_LIBRARIES := liblog libnativehelper
   ifeq ($$(art_target_or_host),target)
diff --git a/src/compiler.cc b/src/compiler.cc
index 4664987..40874f5 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -347,7 +347,7 @@
                            const std::vector<const DexFile*>& dex_files) {
   SetGcMaps(class_loader, dex_files);
 #if defined(ART_USE_LLVM_COMPILER)
-  compiler_llvm_->MaterializeLLVMModule();
+  compiler_llvm_->MaterializeEveryCompilationUnit();
 #endif
 }
 
@@ -1149,4 +1149,14 @@
   compiled_method->SetGcMap(*gc_map);
 }
 
+#if defined(ART_USE_LLVM_COMPILER)
+void Compiler::SetElfFileName(std::string const& filename) {
+  compiler_llvm_->SetElfFileName(filename);
+}
+
+void Compiler::SetBitcodeFileName(std::string const& filename) {
+  compiler_llvm_->SetBitcodeFileName(filename);
+}
+#endif
+
 }  // namespace art
diff --git a/src/compiler.h b/src/compiler.h
index 27de42f..2ff3b90 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -124,6 +124,9 @@
                          int& vtable_idx);
 
 #if defined(ART_USE_LLVM_COMPILER)
+  void SetElfFileName(std::string const& filename);
+  void SetBitcodeFileName(std::string const& filename);
+
   compiler_llvm::CompilerLLVM* GetCompilerLLVM() const {
     return compiler_llvm_.get();
   }
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
new file mode 100644
index 0000000..45c4bb7
--- /dev/null
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -0,0 +1,218 @@
+/*
+ * 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 "compilation_unit.h"
+
+#include "constants.h"
+#include "ir_builder.h"
+#include "logging.h"
+
+#include <llvm/ADT/OwningPtr.h>
+#include <llvm/ADT/StringSet.h>
+#include <llvm/ADT/Triple.h>
+#include <llvm/Analysis/CallGraph.h>
+#include <llvm/Analysis/DebugInfo.h>
+#include <llvm/Analysis/LoopPass.h>
+#include <llvm/Analysis/RegionPass.h>
+#include <llvm/Analysis/Verifier.h>
+#include <llvm/Assembly/PrintModulePass.h>
+#include <llvm/Bitcode/ReaderWriter.h>
+#include <llvm/CallGraphSCCPass.h>
+#include <llvm/DerivedTypes.h>
+#include <llvm/LLVMContext.h>
+#include <llvm/LinkAllPasses.h>
+#include <llvm/LinkAllVMCore.h>
+#include <llvm/Module.h>
+#include <llvm/PassManager.h>
+#include <llvm/Support/Debug.h>
+#include <llvm/Support/FormattedStream.h>
+#include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/PassNameParser.h>
+#include <llvm/Support/PluginLoader.h>
+#include <llvm/Support/PrettyStackTrace.h>
+#include <llvm/Support/Signals.h>
+#include <llvm/Support/SystemUtils.h>
+#include <llvm/Support/TargetRegistry.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Support/ToolOutputFile.h>
+#include <llvm/Support/raw_ostream.h>
+#include <llvm/Target/TargetData.h>
+#include <llvm/Target/TargetLibraryInfo.h>
+#include <llvm/Target/TargetMachine.h>
+#include <llvm/Transforms/IPO/PassManagerBuilder.h>
+
+#include <string>
+
+namespace art {
+namespace compiler_llvm {
+
+llvm::Module* makeLLVMModuleContents(llvm::Module* module);
+
+
+CompilationUnit::CompilationUnit(InstructionSet insn_set)
+: insn_set_(insn_set), context_(new llvm::LLVMContext()), mem_usage_(0) {
+
+  // Create the module and include the runtime function declaration
+  module_ = new llvm::Module("art", *context_);
+  makeLLVMModuleContents(module_);
+
+  // Create IRBuilder
+  irb_.reset(new IRBuilder(*context_, *module_));
+}
+
+
+CompilationUnit::~CompilationUnit() {
+}
+
+
+bool CompilationUnit::WriteBitcodeToFile() {
+  std::string errmsg;
+
+  llvm::OwningPtr<llvm::tool_output_file> out_file(
+    new llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
+                               llvm::raw_fd_ostream::F_Binary));
+
+
+  if (!errmsg.empty()) {
+    LOG(ERROR) << "Failed to create bitcode output file: " << errmsg;
+    return false;
+  }
+
+  llvm::WriteBitcodeToFile(module_, out_file->os());
+  out_file->keep();
+
+  return true;
+}
+
+
+bool CompilationUnit::Materialize() {
+  // Initialize LLVM optimization passes
+  llvm::PassRegistry &Registry = *llvm::PassRegistry::getPassRegistry();
+
+  llvm::initializeCore(Registry);
+  llvm::initializeScalarOpts(Registry);
+  llvm::initializeIPO(Registry);
+  llvm::initializeAnalysis(Registry);
+  llvm::initializeIPA(Registry);
+  llvm::initializeTransformUtils(Registry);
+  llvm::initializeInstCombine(Registry);
+  llvm::initializeInstrumentation(Registry);
+  llvm::initializeTarget(Registry);
+
+  // Lookup the LLVM target
+  char const* target_triple = NULL;
+  char const* target_attr = NULL;
+
+  if (insn_set_ == kThumb2) {
+    target_triple = "thumb-none-linux-gnueabi";
+    target_attr = "+thumb2,+neon,+neonfp,+vfp3";
+  } else if (insn_set_ == kArm) {
+    target_triple = "armv7-none-linux-gnueabi";
+    target_attr = "+v7,+neon,+neonfp,+vfp3";
+  } else if (insn_set_ == kX86) {
+    target_triple = "i386-pc-linux-gnu";
+    target_attr = "";
+  // } else if (insn_set_ == kMips) {
+  //  target_triple = "mipsel-unknown-linux";
+  //  target_attr = "";
+  } else {
+    LOG(FATAL) << "Unknown instruction set: " << insn_set_;
+  }
+
+  std::string errmsg;
+  llvm::Target const* target =
+    llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
+
+  CHECK(target != NULL) << errmsg;
+
+  // Target options
+  llvm::TargetOptions target_options;
+
+  target_options.FloatABIType = llvm::FloatABI::Soft;
+  target_options.UseSoftFloat = false;
+
+  // Create the llvm::TargetMachine
+  llvm::TargetMachine* target_machine =
+    target->createTargetMachine(target_triple, "", target_attr, target_options,
+                                llvm::Reloc::Static, llvm::CodeModel::Small,
+                                llvm::CodeGenOpt::Aggressive);
+
+  CHECK(target_machine != NULL) << "Failed to create target machine";
+
+
+  // Add target data
+  llvm::TargetData const* target_data = target_machine->getTargetData();
+
+  // PassManager for code generation passes
+  llvm::PassManager pm;
+  pm.add(new llvm::TargetData(*target_data));
+
+  // FunctionPassManager for optimization pass
+  llvm::FunctionPassManager fpm(module_);
+  fpm.add(new llvm::TargetData(*target_data));
+
+  // Add optimization pass
+  llvm::PassManagerBuilder pm_builder;
+  pm_builder.Inliner = NULL; // TODO: add some inline in the future
+  pm_builder.OptLevel = 3;
+  pm_builder.DisableSimplifyLibCalls = 1;
+  pm_builder.populateModulePassManager(pm);
+  pm_builder.populateFunctionPassManager(fpm);
+
+  // Add passes to emit file
+  llvm::OwningPtr<llvm::tool_output_file> out_file(
+    new llvm::tool_output_file(elf_filename_.c_str(), errmsg,
+                               llvm::raw_fd_ostream::F_Binary));
+
+  llvm::formatted_raw_ostream formatted_os(out_file->os(), false);
+
+  // Ask the target to add backend passes as necessary.
+  if (target_machine->addPassesToEmitFile(pm,
+                                          formatted_os,
+                                          llvm::TargetMachine::CGFT_ObjectFile,
+                                          true)) {
+    LOG(FATAL) << "Unable to generate ELF for this target";
+    return false;
+  }
+
+  // Run the per-function optimization
+  fpm.doInitialization();
+  for (llvm::Module::iterator F = module_->begin(), E = module_->end();
+       F != E; ++F) {
+    fpm.run(*F);
+  }
+  fpm.doFinalization();
+  LOG(INFO) << "Intraprocedural optimization finished!";
+
+  // Run the code generation passes
+  pm.run(*module_);
+  LOG(INFO) << "Code generation finished!";
+
+  out_file->keep();
+  LOG(DEBUG) << "ELF: " << elf_filename_ << " (done)";
+
+  return true;
+}
+
+
+void CompilationUnit::Finalize() {
+  context_.reset(NULL);
+  irb_.reset(NULL);
+  module_ = NULL;
+}
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
new file mode 100644
index 0000000..a10d977
--- /dev/null
+++ b/src/compiler_llvm/compilation_unit.h
@@ -0,0 +1,110 @@
+/*
+ * 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_COMPILATION_UNIT_H_
+#define ART_SRC_COMPILER_LLVM_COMPILATION_UNIT_H_
+
+#include "constants.h"
+#include "logging.h"
+
+#include <UniquePtr.h>
+#include <string>
+
+namespace llvm {
+  class LLVMContext;
+  class Module;
+}
+
+namespace art {
+namespace compiler_llvm {
+
+class IRBuilder;
+
+class CompilationUnit {
+ public:
+  CompilationUnit(InstructionSet insn_set);
+
+  ~CompilationUnit();
+
+  InstructionSet GetInstructionSet() const {
+    return insn_set_;
+  }
+
+  llvm::LLVMContext* GetLLVMContext() const {
+    return context_.get();
+  }
+
+  llvm::Module* GetModule() const {
+    return module_;
+  }
+
+  IRBuilder* GetIRBuilder() const {
+    return irb_.get();
+  }
+
+  std::string const& GetElfFileName() const {
+    CHECK(IsFinalized());
+    return elf_filename_;
+  }
+
+  std::string const& GetBitcodeFileName() const {
+    CHECK(IsFinalized());
+    return bitcode_filename_;
+  }
+
+  void SetElfFileName(std::string const& filename) {
+    elf_filename_ = filename;
+  }
+
+  void SetBitcodeFileName(std::string const& filename) {
+    bitcode_filename_ = filename;
+  }
+
+  bool WriteBitcodeToFile();
+
+  bool Materialize();
+
+  bool IsFinalized() const {
+    return (context_.get() == NULL);
+  }
+
+  void Finalize();
+
+  bool IsMaterializeThresholdReached() const {
+    return (mem_usage_ > 300000000u); // (threshold: 300 MB)
+  }
+
+  void AddMemUsageApproximation(size_t usage) {
+    mem_usage_ += usage;
+  }
+
+ private:
+  InstructionSet insn_set_;
+
+  UniquePtr<llvm::LLVMContext> context_;
+  UniquePtr<IRBuilder> irb_;
+  llvm::Module* module_;
+
+  std::string elf_filename_;
+  std::string bitcode_filename_;
+
+  size_t mem_usage_;
+};
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_COMPILATION_UNIT_H_
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 1489ec4..56f0b07 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -16,6 +16,7 @@
 
 #include "compiler_llvm.h"
 
+#include "compilation_unit.h"
 #include "compiler.h"
 #include "ir_builder.h"
 #include "jni_compiler.h"
@@ -23,12 +24,28 @@
 #include "oat_compilation_unit.h"
 #include "upcall_compiler.h"
 
-#include <llvm/ADT/OwningPtr.h>
-#include <llvm/Bitcode/ReaderWriter.h>
-#include <llvm/DerivedTypes.h>
-#include <llvm/LLVMContext.h>
-#include <llvm/Module.h>
-#include <llvm/Support/ToolOutputFile.h>
+#include <llvm/Support/TargetSelect.h>
+#include <llvm/Support/Threading.h>
+
+
+namespace {
+
+pthread_once_t llvm_initialized = PTHREAD_ONCE_INIT;
+
+void InitializeLLVM() {
+  // Initialize LLVM target, MC subsystem, asm printer, and asm parser
+  llvm::InitializeAllTargets();
+  llvm::InitializeAllTargetMCs();
+  llvm::InitializeAllAsmPrinters();
+  llvm::InitializeAllAsmParsers();
+  // TODO: Maybe we don't have to initialize "all" targets.
+
+  // Initialize LLVM internal data structure for multithreading
+  llvm::llvm_start_multithreaded();
+}
+
+} // anonymous namespace
+
 
 namespace art {
 namespace compiler_llvm {
@@ -39,67 +56,93 @@
 
 CompilerLLVM::CompilerLLVM(Compiler* compiler, InstructionSet insn_set)
 : compiler_(compiler), compiler_lock_("llvm_compiler_lock"),
-  insn_set_(insn_set), context_(new llvm::LLVMContext()) {
+  insn_set_(insn_set), cunit_counter_(0) {
 
-  // Create the module and include the runtime function declaration
-  module_ = new llvm::Module("art", *context_);
-  makeLLVMModuleContents(module_);
-
-  // Create IRBuilder
-  irb_.reset(new IRBuilder(*context_, *module_));
+  // Initialize LLVM libraries
+  pthread_once(&llvm_initialized, InitializeLLVM);
 }
 
 
 CompilerLLVM::~CompilerLLVM() {
+  DCHECK(cunit_.get() == NULL);
 }
 
 
-void CompilerLLVM::MaterializeLLVMModule() {
-#if !defined(NDEBUG)
-  // TODO: Add options to JNI_CreateJavaVM() and dex2oat, so that we don't
-  // have to hard-code the path.
-  WriteBitcodeToFile("/tmp/art_llvm_module.bc");
-#endif
+void CompilerLLVM::EnsureCompilationUnit() {
+  DCHECK_NE(llvm_initialized, PTHREAD_ONCE_INIT);
+  if (cunit_.get() == NULL) {
+    cunit_.reset(new CompilationUnit(insn_set_));
+  }
 }
 
 
-void CompilerLLVM::WriteBitcodeToFile(std::string const &filepath) {
-  std::string error_msg;
+void CompilerLLVM::MaterializeEveryCompilationUnit() {
+  if (cunit_.get() != NULL) {
+    MaterializeCompilationUnit();
+  }
+}
 
-  // Write the translated bitcode
-  llvm::OwningPtr<llvm::tool_output_file>
-    out(new llvm::tool_output_file(filepath.c_str(), error_msg,
-                                   llvm::raw_fd_ostream::F_Binary));
 
-  if (!error_msg.empty()) {
-    LOG(FATAL) << "Unable to open file: " << error_msg;
-    return;
+void CompilerLLVM::MaterializeCompilationUnitSafePoint() {
+  if (cunit_->IsMaterializeThresholdReached()) {
+    MaterializeCompilationUnit();
+  }
+}
+
+
+void CompilerLLVM::MaterializeCompilationUnit() {
+  MutexLock GUARD(compiler_lock_);
+
+  cunit_->SetElfFileName(StringPrintf("%s-%u", elf_filename_.c_str(),
+                                      cunit_counter_));
+
+  // Write the translated bitcode for debugging
+  if (!bitcode_filename_.empty()) {
+    cunit_->SetBitcodeFileName(StringPrintf("%s-%u", bitcode_filename_.c_str(),
+                                            cunit_counter_));
+    cunit_->WriteBitcodeToFile();
   }
 
-  llvm::WriteBitcodeToFile(module_, out->os());
-  out->keep();
+  // Materialize the llvm::Module into ELF object file
+  cunit_->Materialize();
 
-  LOG(DEBUG) << "Bitcode Written At: " << filepath;
+  // Increase compilation unit counter
+  ++cunit_counter_;
+
+  // Delete the compilation unit
+  cunit_.reset(NULL);
 }
 
 
 CompiledMethod* CompilerLLVM::CompileDexMethod(OatCompilationUnit* oat_compilation_unit) {
   MutexLock GUARD(compiler_lock_);
 
-  UniquePtr<MethodCompiler> method_compiler(
-    new MethodCompiler(insn_set_, compiler_, oat_compilation_unit));
+  EnsureCompilationUnit();
 
-  return method_compiler->Compile();
+  UniquePtr<MethodCompiler> method_compiler(
+      new MethodCompiler(cunit_.get(), compiler_, oat_compilation_unit));
+
+  CompiledMethod* result = method_compiler->Compile();
+
+  MaterializeCompilationUnitSafePoint();
+
+  return result;
 }
 
 
 CompiledMethod* CompilerLLVM::CompileNativeMethod(OatCompilationUnit* oat_compilation_unit) {
   MutexLock GUARD(compiler_lock_);
 
-  UniquePtr<JniCompiler> jni_compiler(
-    new JniCompiler(insn_set_, *compiler_, oat_compilation_unit));
+  EnsureCompilationUnit();
 
-  return jni_compiler->Compile();
+  UniquePtr<JniCompiler> jni_compiler(
+      new JniCompiler(cunit_.get(), *compiler_, oat_compilation_unit));
+
+  CompiledMethod* result = jni_compiler->Compile();
+
+  MaterializeCompilationUnitSafePoint();
+
+  return result;
 }
 
 
@@ -108,10 +151,16 @@
 
   MutexLock GUARD(compiler_lock_);
 
-  UniquePtr<UpcallCompiler> upcall_compiler(
-    new UpcallCompiler(insn_set_, *compiler_));
+  EnsureCompilationUnit();
 
-  return upcall_compiler->CreateStub(is_static, shorty);
+  UniquePtr<UpcallCompiler> upcall_compiler(
+    new UpcallCompiler(cunit_.get(), *compiler_));
+
+  CompiledInvokeStub* result = upcall_compiler->CreateStub(is_static, shorty);
+
+  MaterializeCompilationUnitSafePoint();
+
+  return result;
 }
 
 
diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h
index 29d32a5..208edfc 100644
--- a/src/compiler_llvm/compiler_llvm.h
+++ b/src/compiler_llvm/compiler_llvm.h
@@ -47,6 +47,7 @@
 namespace art {
 namespace compiler_llvm {
 
+class CompilationUnit;
 class IRBuilder;
 
 class CompilerLLVM {
@@ -55,9 +56,7 @@
 
   ~CompilerLLVM();
 
-  void MaterializeLLVMModule();
-
-  void WriteBitcodeToFile(std::string const &filename);
+  void MaterializeEveryCompilationUnit();
 
   Compiler* GetCompiler() const {
     return compiler_;
@@ -67,16 +66,12 @@
     return insn_set_;
   }
 
-  llvm::Module* GetModule() const {
-    return module_;
+  void SetElfFileName(std::string const& filename) {
+    elf_filename_ = filename;
   }
 
-  llvm::LLVMContext* GetLLVMContext() const {
-    return context_.get();
-  }
-
-  IRBuilder* GetIRBuilder() const {
-    return irb_.get();
+  void SetBitcodeFileName(std::string const& filename) {
+    bitcode_filename_ = filename;
   }
 
   CompiledMethod* CompileDexMethod(OatCompilationUnit* oat_compilation_unit);
@@ -86,17 +81,25 @@
   CompiledInvokeStub* CreateInvokeStub(bool is_static, char const *shorty);
 
  private:
+  void EnsureCompilationUnit();
+
+  void MaterializeCompilationUnit();
+
+  void MaterializeCompilationUnitSafePoint();
+
   Compiler* compiler_;
 
   Mutex compiler_lock_;
 
   InstructionSet insn_set_;
 
-  UniquePtr<llvm::LLVMContext> context_;
+  UniquePtr<CompilationUnit> cunit_;
 
-  UniquePtr<IRBuilder> irb_;
+  unsigned cunit_counter_;
 
-  llvm::Module* module_;
+  std::string elf_filename_;
+
+  std::string bitcode_filename_;
 
   DISALLOW_COPY_AND_ASSIGN(CompilerLLVM);
 };
diff --git a/src/compiler_llvm/jni_compiler.cc b/src/compiler_llvm/jni_compiler.cc
index f97e4fe..0e02846 100644
--- a/src/compiler_llvm/jni_compiler.cc
+++ b/src/compiler_llvm/jni_compiler.cc
@@ -17,6 +17,7 @@
 #include "jni_compiler.h"
 
 #include "class_linker.h"
+#include "compilation_unit.h"
 #include "compiled_method.h"
 #include "compiler.h"
 #include "compiler_llvm.h"
@@ -35,14 +36,11 @@
 namespace compiler_llvm {
 
 
-JniCompiler::JniCompiler(InstructionSet insn_set,
+JniCompiler::JniCompiler(CompilationUnit* cunit,
                          Compiler const& compiler,
                          OatCompilationUnit* oat_compilation_unit)
-: insn_set_(insn_set), compiler_(&compiler),
-  compiler_llvm_(compiler_->GetCompilerLLVM()),
-  module_(compiler_llvm_->GetModule()),
-  context_(compiler_llvm_->GetLLVMContext()),
-  irb_(*compiler_llvm_->GetIRBuilder()),
+: cunit_(cunit), compiler_(&compiler), module_(cunit_->GetModule()),
+  context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()),
   oat_compilation_unit_(oat_compilation_unit),
   access_flags_(oat_compilation_unit->access_flags_),
   method_idx_(oat_compilation_unit->method_idx_),
@@ -63,7 +61,7 @@
 CompiledMethod* JniCompiler::Compile() {
   CreateFunction();
 
-  return new CompiledMethod(insn_set_, func_);
+  return new CompiledMethod(cunit_->GetInstructionSet(), func_);
 }
 
 
diff --git a/src/compiler_llvm/jni_compiler.h b/src/compiler_llvm/jni_compiler.h
index 4d7763e..a6cdd9c 100644
--- a/src/compiler_llvm/jni_compiler.h
+++ b/src/compiler_llvm/jni_compiler.h
@@ -42,12 +42,12 @@
 namespace art {
 namespace compiler_llvm {
 
-class CompilerLLVM;
+class CompilationUnit;
 class IRBuilder;
 
 class JniCompiler {
  public:
-  JniCompiler(InstructionSet insn_set,
+  JniCompiler(CompilationUnit* cunit,
               Compiler const& compiler,
               OatCompilationUnit* oat_compilation_unit);
 
@@ -60,9 +60,8 @@
                                       bool is_static);
 
  private:
-  InstructionSet insn_set_;
+  CompilationUnit* cunit_;
   Compiler const* compiler_;
-  CompilerLLVM* compiler_llvm_;
 
   llvm::Module* module_;
   llvm::LLVMContext* context_;
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 8dc81dd..3af60f4 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -17,6 +17,7 @@
 #include "method_compiler.h"
 
 #include "backend_types.h"
+#include "compilation_unit.h"
 #include "compiler.h"
 #include "inferred_reg_category_map.h"
 #include "ir_builder.h"
@@ -43,30 +44,29 @@
 using namespace runtime_support;
 
 
-MethodCompiler::MethodCompiler(InstructionSet insn_set,
+MethodCompiler::MethodCompiler(CompilationUnit* cunit,
                                Compiler* compiler,
                                OatCompilationUnit* oat_compilation_unit)
-: insn_set_(insn_set), compiler_(compiler),
-  compiler_llvm_(compiler->GetCompilerLLVM()),
-  class_linker_(oat_compilation_unit->class_linker_),
-  class_loader_(oat_compilation_unit->class_loader_),
-  dex_file_(oat_compilation_unit->dex_file_),
-  dex_cache_(oat_compilation_unit->dex_cache_),
-  code_item_(oat_compilation_unit->code_item_),
-  oat_compilation_unit_(oat_compilation_unit),
-  method_(dex_cache_->GetResolvedMethod(oat_compilation_unit->method_idx_)),
-  method_helper_(method_),
-  method_idx_(oat_compilation_unit->method_idx_),
-  access_flags_(oat_compilation_unit->access_flags_),
-  module_(compiler_llvm_->GetModule()),
-  context_(compiler_llvm_->GetLLVMContext()),
-  irb_(*compiler_llvm_->GetIRBuilder()), func_(NULL), retval_reg_(NULL),
-  basic_block_reg_alloca_(NULL), basic_block_shadow_frame_alloca_(NULL),
-  basic_block_reg_zero_init_(NULL), basic_block_reg_arg_init_(NULL),
-  basic_blocks_(code_item_->insns_size_in_code_units_),
-  basic_block_landing_pads_(code_item_->tries_size_, NULL),
-  basic_block_unwind_(NULL), basic_block_unreachable_(NULL),
-  shadow_frame_(NULL) {
+  : cunit_(cunit), compiler_(compiler),
+    class_linker_(oat_compilation_unit->class_linker_),
+    class_loader_(oat_compilation_unit->class_loader_),
+    dex_file_(oat_compilation_unit->dex_file_),
+    dex_cache_(oat_compilation_unit->dex_cache_),
+    code_item_(oat_compilation_unit->code_item_),
+    oat_compilation_unit_(oat_compilation_unit),
+    method_(dex_cache_->GetResolvedMethod(oat_compilation_unit->method_idx_)),
+    method_helper_(method_),
+    method_idx_(oat_compilation_unit->method_idx_),
+    access_flags_(oat_compilation_unit->access_flags_),
+    module_(cunit->GetModule()),
+    context_(cunit->GetLLVMContext()),
+    irb_(*cunit->GetIRBuilder()), func_(NULL), retval_reg_(NULL),
+    basic_block_reg_alloca_(NULL), basic_block_shadow_frame_alloca_(NULL),
+    basic_block_reg_zero_init_(NULL), basic_block_reg_arg_init_(NULL),
+    basic_blocks_(code_item_->insns_size_in_code_units_),
+    basic_block_landing_pads_(code_item_->tries_size_, NULL),
+    basic_block_unwind_(NULL), basic_block_unreachable_(NULL),
+    shadow_frame_(NULL) {
 }
 
 
@@ -3529,7 +3529,13 @@
   // Delete the inferred register category map (won't be used anymore)
   method_->ResetInferredRegCategoryMap();
 
-  return new CompiledMethod(insn_set_, func_);
+  // Add the memory usage approximation of the compilation unit
+  cunit_->AddMemUsageApproximation(code_item_->insns_size_in_code_units_ * 900);
+  // NOTE: From statistic, the bitcode size is 4.5 times bigger than the
+  // Dex file.  Besides, we have to convert the code unit into bytes.
+  // Thus, we got our magic number 9.
+
+  return new CompiledMethod(cunit_->GetInstructionSet(), func_);
 }
 
 
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 0359fa2..764d892 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -56,14 +56,14 @@
 namespace art {
 namespace compiler_llvm {
 
+class CompilationUnit;
 class CompilerLLVM;
 class IRBuilder;
 
 class MethodCompiler {
  private:
-  InstructionSet insn_set_;
+  CompilationUnit* cunit_;
   Compiler* compiler_;
-  compiler_llvm::CompilerLLVM* compiler_llvm_;
 
   ClassLinker* class_linker_;
   ClassLoader const* class_loader_;
@@ -101,7 +101,7 @@
 
 
  public:
-  MethodCompiler(InstructionSet insn_set,
+  MethodCompiler(CompilationUnit* cunit,
                  Compiler* compiler,
                  OatCompilationUnit* oat_compilation_unit);
 
diff --git a/src/compiler_llvm/upcall_compiler.cc b/src/compiler_llvm/upcall_compiler.cc
index be4c00d..ec433c2 100644
--- a/src/compiler_llvm/upcall_compiler.cc
+++ b/src/compiler_llvm/upcall_compiler.cc
@@ -16,8 +16,9 @@
 
 #include "upcall_compiler.h"
 
-#include "compiler.h"
+#include "compilation_unit.h"
 #include "compiled_method.h"
+#include "compiler.h"
 #include "compiler_llvm.h"
 #include "ir_builder.h"
 #include "logging.h"
@@ -39,13 +40,9 @@
 using namespace runtime_support;
 
 
-UpcallCompiler::UpcallCompiler(InstructionSet insn_set,
-                               Compiler& compiler)
-: insn_set_(insn_set), compiler_(&compiler),
-  compiler_llvm_(compiler_->GetCompilerLLVM()),
-  module_(compiler_llvm_->GetModule()),
-  context_(compiler_llvm_->GetLLVMContext()),
-  irb_(*compiler_llvm_->GetIRBuilder()) {
+UpcallCompiler::UpcallCompiler(CompilationUnit* cunit, Compiler& compiler)
+: cunit_(cunit), compiler_(&compiler), module_(cunit_->GetModule()),
+  context_(cunit_->GetLLVMContext()), irb_(*cunit_->GetIRBuilder()) {
 }
 
 
@@ -172,8 +169,16 @@
 
   irb_.CreateRetVoid();
 
+  // Verify the generated function
   llvm::verifyFunction(*func, llvm::PrintMessageAction);
 
+  // Add the memory usage approximation of the compilation unit
+  cunit_->AddMemUsageApproximation((shorty_size * 3 + 8) * 500);
+  // NOTE: We will emit 3 LLVM instructions per shorty for the argument,
+  // plus 3 for pointer arithmetic, and 5 for code_addr, retval, ret_addr,
+  // store ret_addr, and ret_void.  Beside, we guess that we have to use
+  // 50 bytes to represent one LLVM instruction.
+
   return new CompiledInvokeStub(func);
 }
 
diff --git a/src/compiler_llvm/upcall_compiler.h b/src/compiler_llvm/upcall_compiler.h
index 426919e..c1e0afc 100644
--- a/src/compiler_llvm/upcall_compiler.h
+++ b/src/compiler_llvm/upcall_compiler.h
@@ -34,19 +34,19 @@
 namespace art {
 namespace compiler_llvm {
 
+class CompilationUnit;
 class CompilerLLVM;
 class IRBuilder;
 
 class UpcallCompiler {
  public:
-  UpcallCompiler(InstructionSet insn_set, Compiler& compiler);
+  UpcallCompiler(CompilationUnit* cunit, Compiler& compiler);
 
   CompiledInvokeStub* CreateStub(bool is_static, char const* shorty);
 
  private:
-  InstructionSet insn_set_;
+  CompilationUnit* cunit_;
   Compiler const* compiler_;
-  CompilerLLVM* compiler_llvm_;
   llvm::Module* module_;
   llvm::LLVMContext* context_;
   IRBuilder& irb_;
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index 9d334ba..d4ed0cc 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -78,6 +78,14 @@
   UsageError("      to the file descriptor specified by --oat-fd.");
   UsageError("      Example: --oat-location=/data/art-cache/system@app@Calculator.apk.oat");
   UsageError("");
+#if defined(ART_USE_LLVM_COMPILER)
+  UsageError("  --elf-file=<file.elf>: specifies the required elf filename.");
+  UsageError("      Example: --elf-file=/system/framework/boot.elf");
+  UsageError("");
+  UsageError("  --bitcode=<file.bc>: specifies the optional bitcode filename.");
+  UsageError("      Example: --bitcode=/system/framework/boot.bc");
+  UsageError("");
+#endif
   UsageError("  --image=<file.art>: specifies the output image filename.");
   UsageError("      Example: --image=/system/framework/boot.art");
   UsageError("");
@@ -187,6 +195,10 @@
   bool CreateOatFile(const std::string& boot_image_option,
                      const std::vector<const DexFile*>& dex_files,
                      File* oat_file,
+#if defined(ART_USE_LLVM_COMPILER)
+                     std::string const& elf_filename,
+                     std::string const& bitcode_filename,
+#endif
                      bool image,
                      const std::set<std::string>* image_classes) {
     // SirtRef and ClassLoader creation needs to come after Runtime::Create
@@ -207,6 +219,12 @@
     }
 
     Compiler compiler(instruction_set_, image, thread_count_, support_debugging_, image_classes);
+
+#if defined(ART_USE_LLVM_COMPILER)
+    compiler.SetElfFileName(elf_filename);
+    compiler.SetBitcodeFileName(bitcode_filename);
+#endif
+
     compiler.CompileAll(class_loader->get(), dex_files);
 
     if (!OatWriter::Create(oat_file, class_loader->get(), dex_files, compiler)) {
@@ -427,6 +445,10 @@
   std::string oat_filename;
   std::string oat_location;
   int oat_fd = -1;
+#if defined(ART_USE_LLVM_COMPILER)
+  std::string elf_filename;
+  std::string bitcode_filename;
+#endif
   const char* image_classes_filename = NULL;
   std::string image_filename;
   std::string boot_image_filename;
@@ -469,6 +491,12 @@
       }
     } else if (option.starts_with("--oat-location=")) {
       oat_location = option.substr(strlen("--oat-location=")).data();
+#if defined(ART_USE_LLVM_COMPILER)
+    } else if (option.starts_with("--elf-file=")) {
+      elf_filename = option.substr(strlen("--elf-file=")).data();
+    } else if (option.starts_with("--bitcode=")) {
+      bitcode_filename = option.substr(strlen("--bitcode=")).data();
+#endif
     } else if (option.starts_with("--image=")) {
       image_filename = option.substr(strlen("--image=")).data();
     } else if (option.starts_with("--image-classes=")) {
@@ -591,6 +619,23 @@
 
   LOG(INFO) << "dex2oat: " << oat_location;
 
+#if defined(ART_USE_LLVM_COMPILER)
+  if (elf_filename.empty()) {
+    if (oat_filename.empty()) {
+      LOG(FATAL) << "Both --oat-file and --elf-file are not specified";
+    }
+
+    StringPiece elf_filename_sp(oat_filename);
+    if (elf_filename_sp.ends_with(".oat")) {
+      elf_filename_sp.remove_suffix(strlen(".oat"));
+    }
+
+    elf_filename = elf_filename_sp.ToString() + ".elf";
+  }
+
+  LOG(INFO) << "ELF output: " << elf_filename;
+#endif
+
   Runtime::Options options;
   options.push_back(std::make_pair("compiler", reinterpret_cast<void*>(NULL)));
   std::vector<const DexFile*> boot_class_path;
@@ -643,6 +688,10 @@
   if (!dex2oat->CreateOatFile(boot_image_option,
                               dex_files,
                               oat_file.get(),
+#if defined(ART_USE_LLVM_COMPILER)
+                              elf_filename,
+                              bitcode_filename,
+#endif
                               image,
                               image_classes.get())) {
     LOG(ERROR) << "Failed to create oat file: " << oat_location;
@@ -664,6 +713,12 @@
 
   // We wrote the oat file successfully, and want to keep it.
   LOG(INFO) << "Oat file written successfully: " << oat_filename;
+#if defined(ART_USE_LLVM_COMPILER)
+  LOG(INFO) << "ELF file written successfully: " << elf_filename;
+  if (!bitcode_filename.empty()) {
+    LOG(INFO) << "Bitcode file written successfully: " << bitcode_filename;
+  }
+#endif
   LOG(INFO) << "Image written successfully: " << image_filename;
   return EXIT_SUCCESS;
 }
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index 99c42f7..a4a4a2c 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -201,6 +201,8 @@
 size_t OatWriter::InitOatCodeMethod(size_t offset, size_t oat_class_index, size_t class_def_index,
                                     size_t class_def_method_index, bool is_native, bool is_static,
                                     bool is_direct, uint32_t method_idx, const DexFile* dex_file) {
+
+#if !defined(ART_USE_LLVM_COMPILER)
   // derived from CompiledMethod if available
   uint32_t code_offset = 0;
   uint32_t frame_size_in_bytes = kStackAlignment;
@@ -351,6 +353,8 @@
     method->SetOatGcMapOffset(gc_map_offset);
     method->SetOatInvokeStubOffset(invoke_stub_offset);
   }
+#endif
+
   return offset;
 }
 
@@ -502,6 +506,7 @@
 size_t OatWriter::WriteCodeMethod(File* file, size_t code_offset, size_t oat_class_index,
                                   size_t class_def_method_index, bool is_static,
                                   uint32_t method_idx, const DexFile& dex_file) {
+#if !defined(ART_USE_LLVM_COMPILER)
   const CompiledMethod* compiled_method =
       compiler_->GetCompiledMethod(Compiler::MethodReference(&dex_file, method_idx));
 
@@ -679,6 +684,8 @@
     }
     DCHECK_CODE_OFFSET();
   }
+#endif
+
   return code_offset;
 }