Compile method one-by-one.

Change-Id: Ic56fb397f3bd6dee32372eb875261a3383eaf30c
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index 38faf61..fdbf575 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -17,6 +17,7 @@
 #include "compilation_unit.h"
 
 #include "compiled_method.h"
+#include "compiler_llvm.h"
 #include "file.h"
 #include "instruction_set.h"
 #include "ir_builder.h"
@@ -47,8 +48,10 @@
 #include <llvm/DerivedTypes.h>
 #include <llvm/LLVMContext.h>
 #include <llvm/Module.h>
+#include <llvm/Object/ObjectFile.h>
 #include <llvm/PassManager.h>
 #include <llvm/Support/Debug.h>
+#include <llvm/Support/ELF.h>
 #include <llvm/Support/FormattedStream.h>
 #include <llvm/Support/ManagedStatic.h>
 #include <llvm/Support/MemoryBuffer.h>
@@ -77,37 +80,6 @@
 
 namespace {
 
-class UpdateFrameSizePass : public llvm::MachineFunctionPass {
- public:
-  static char ID;
-
-  UpdateFrameSizePass() : llvm::MachineFunctionPass(ID), cunit_(NULL) {
-    LOG(FATAL) << "Unexpected instantiation of UpdateFrameSizePass";
-    // NOTE: We have to declare this constructor for llvm::RegisterPass, but
-    // this constructor won't work because we have no information on
-    // CompilationUnit.  Thus, we should place a LOG(FATAL) here.
-  }
-
-  UpdateFrameSizePass(art::compiler_llvm::CompilationUnit* cunit)
-    : llvm::MachineFunctionPass(ID), cunit_(cunit) {
-  }
-
-  virtual bool runOnMachineFunction(llvm::MachineFunction &MF) {
-    cunit_->UpdateFrameSizeInBytes(MF.getFunction(),
-                                   MF.getFrameInfo()->getStackSize());
-    return false;
-  }
-
- private:
-  art::compiler_llvm::CompilationUnit* cunit_;
-};
-
-char UpdateFrameSizePass::ID = 0;
-
-llvm::RegisterPass<UpdateFrameSizePass> reg_update_frame_size_pass_(
-  "update-frame-size", "Update frame size pass", false, false);
-
-
 // TODO: We may need something to manage these passes.
 // TODO: We need high-level IR to analysis and do this at the IRBuilder level.
 class AddSuspendCheckToLoopLatchPass : public llvm::LoopPass {
@@ -167,10 +139,10 @@
 llvm::Module* makeLLVMModuleContents(llvm::Module* module);
 
 
-CompilationUnit::CompilationUnit(InstructionSet insn_set, size_t elf_idx)
-: cunit_lock_("compilation_unit_lock"), insn_set_(insn_set), elf_idx_(elf_idx),
-  context_(new llvm::LLVMContext()), compiled_methods_map_(new CompiledMethodMap()),
-  mem_usage_(0), num_elf_funcs_(0) {
+CompilationUnit::CompilationUnit(const CompilerLLVM* compiler_llvm,
+                                 size_t cunit_idx)
+: compiler_llvm_(compiler_llvm), cunit_idx_(cunit_idx),
+  context_(new llvm::LLVMContext()) {
 
   // Create the module and include the runtime function declaration
   module_ = new llvm::Module("art", *context_);
@@ -180,7 +152,7 @@
   irb_.reset(new IRBuilder(*context_, *module_));
 
   // We always need a switch case, so just use a normal function.
-  switch(insn_set_) {
+  switch(GetInstructionSet()) {
   default:
     runtime_support_.reset(new RuntimeSupportBuilder(*context_, *module_, *irb_));
     break;
@@ -205,57 +177,56 @@
 }
 
 
-bool CompilationUnit::Materialize(size_t thread_count) {
-  MutexLock GUARD(cunit_lock_);
-
-  // Materialize the bitcode to elf_image_
-  llvm::raw_string_ostream str_os(elf_image_);
-  bool success = MaterializeToFile(str_os);
-  LOG(INFO) << "Compilation Unit: " << elf_idx_ << (success ? " (done)" : " (failed)");
-
-  // Free the resources
-  context_.reset(NULL);
-  irb_.reset(NULL);
-  module_ = NULL;
-  runtime_support_.reset(NULL);
-  compiled_methods_map_.reset(NULL);
-
-  return success;
+InstructionSet CompilationUnit::GetInstructionSet() const {
+  return compiler_llvm_->GetInstructionSet();
 }
 
 
-void CompilationUnit::RegisterCompiledMethod(const llvm::Function* func,
-                                             CompiledMethod* compiled_method) {
-  MutexLock GUARD(cunit_lock_);
-  compiled_methods_map_->Put(func, compiled_method);
-}
+bool CompilationUnit::Materialize() {
+  std::string elf_image;
 
-
-void CompilationUnit::UpdateFrameSizeInBytes(const llvm::Function* func,
-                                             size_t frame_size_in_bytes) {
-  MutexLock GUARD(cunit_lock_);
-  SafeMap<const llvm::Function*, CompiledMethod*>::iterator iter =
-    compiled_methods_map_->find(func);
-
-  if (iter != compiled_methods_map_->end()) {
-    CompiledMethod* compiled_method = iter->second;
-    compiled_method->SetFrameSizeInBytes(frame_size_in_bytes);
-
-    if (frame_size_in_bytes > 1728u) {
-      LOG(WARNING) << "Huge frame size: " << frame_size_in_bytes
-                   << " elf_idx=" << compiled_method->GetElfIndex()
-                   << " elf_func_idx=" << compiled_method->GetElfFuncIndex();
-    }
+  // Compile and prelink llvm::Module
+  if (!MaterializeToString(elf_image)) {
+    LOG(ERROR) << "Failed to materialize compilation unit " << cunit_idx_;
+    DeleteResources();
+    return false;
   }
+
+#if 0
+  // Dump the ELF image for debugging
+  std::string filename(StringPrintf("%s/Art%zu.elf",
+                                    GetArtCacheOrDie(GetAndroidData()).c_str(),
+                                    cunit_idx_));
+  UniquePtr<File> output(OS::OpenFile(filename.c_str(), true));
+  output->WriteFully(elf_image.data(), elf_image.size());
+#endif
+
+  // Extract the .text section and prelink the code
+  if (!ExtractCodeAndPrelink(elf_image)) {
+    LOG(ERROR) << "Failed to extract code from compilation unit " << cunit_idx_;
+    DeleteResources();
+    return false;
+  }
+
+  DeleteResources();
+  return true;
 }
 
-bool CompilationUnit::MaterializeToFile(llvm::raw_ostream& out_stream) {
+
+bool CompilationUnit::MaterializeToString(std::string& str_buffer) {
+  llvm::raw_string_ostream str_os(str_buffer);
+  return MaterializeToRawOStream(str_os);
+}
+
+
+bool CompilationUnit::MaterializeToRawOStream(llvm::raw_ostream& out_stream) {
   // Lookup the LLVM target
   char const* target_triple = NULL;
   char const* target_cpu = "";
   char const* target_attr = NULL;
 
-  switch (insn_set_) {
+  InstructionSet insn_set = GetInstructionSet();
+  switch (insn_set) {
   case kThumb2:
     target_triple = "thumb-none-linux-gnueabi";
     target_cpu = "cortex-a9";
@@ -281,7 +252,7 @@
     break;
 
   default:
-    LOG(FATAL) << "Unknown instruction set: " << insn_set_;
+    LOG(FATAL) << "Unknown instruction set: " << insn_set;
   }
 
   std::string errmsg;
@@ -375,11 +346,6 @@
       return false;
     }
 
-    // FIXME: Unable to run the UpdateFrameSizePass pass since it tries to
-    //        update the value reside in the different address space.
-    // Add pass to update the frame_size_in_bytes_
-    //pm.add(new ::UpdateFrameSizePass(this));
-
     // Run the per-function optimization
     fpm.doInitialization();
     for (llvm::Module::iterator F = module_->begin(), E = module_->end();
@@ -395,5 +361,130 @@
   return true;
 }
 
+
+bool CompilationUnit::ExtractCodeAndPrelink(const std::string& elf_image) {
+  llvm::OwningPtr<llvm::MemoryBuffer> elf_image_buff(
+    llvm::MemoryBuffer::getMemBuffer(llvm::StringRef(elf_image.data(),
+                                                     elf_image.size())));
+
+  llvm::OwningPtr<llvm::object::ObjectFile> elf_file(
+    llvm::object::ObjectFile::createELFObjectFile(elf_image_buff.take()));
+
+  llvm::error_code ec;
+
+  const ProcedureLinkageTable& plt = compiler_llvm_->GetProcedureLinkageTable();
+
+  for (llvm::object::section_iterator
+       sec_iter = elf_file->begin_sections(),
+       sec_end = elf_file->end_sections();
+       sec_iter != sec_end; sec_iter.increment(ec)) {
+
+    CHECK(ec == 0) << "Failed to read section because " << ec.message();
+
+    // Read the section information
+    llvm::StringRef name;
+    uint64_t alignment = 0u;
+    uint64_t size = 0u;
+
+    CHECK(sec_iter->getName(name) == 0);
+    CHECK(sec_iter->getSize(size) == 0);
+    CHECK(sec_iter->getAlignment(alignment) == 0);
+
+    if (name == ".data" || name == ".bss" || name == ".rodata") {
+      if (size > 0) {
+        LOG(FATAL) << "Compilation unit " << cunit_idx_ << " has non-empty "
+                   << name.str() << " section";
+      }
+
+    } else if (name == "" || name == ".rel.text" ||
+               name == ".ARM.attributes" || name == ".symtab" ||
+               name == ".strtab" || name == ".shstrtab") {
+      // We can ignore these sections.  We don't have to copy them into
+      // the result Oat file.
+
+    } else if (name == ".text") {
+      // Ensure the alignment requirement is less than or equal to
+      // kArchAlignment
+      CheckCodeAlign(alignment);
+
+      // Copy the compiled code
+      llvm::StringRef contents;
+      CHECK(sec_iter->getContents(contents) == 0);
+
+      copy(contents.data(),
+           contents.data() + contents.size(),
+           back_inserter(compiled_code_));
+
+      // Prelink the compiled code
+      for (llvm::object::relocation_iterator
+           rel_iter = sec_iter->begin_relocations(),
+           rel_end = sec_iter->end_relocations(); rel_iter != rel_end;
+           rel_iter.increment(ec)) {
+
+        CHECK(ec == 0) << "Failed to read relocation because " << ec.message();
+
+        // Read the relocation information
+        llvm::object::SymbolRef sym_ref;
+        uint64_t rel_offset = 0;
+        uint64_t rel_type = 0;
+        int64_t rel_addend = 0;
+
+        CHECK(rel_iter->getSymbol(sym_ref) == 0);
+        CHECK(rel_iter->getOffset(rel_offset) == 0);
+        CHECK(rel_iter->getType(rel_type) == 0);
+        CHECK(rel_iter->getAdditionalInfo(rel_addend) == 0);
+
+        // Read the symbol related to this relocation fixup
+        llvm::StringRef sym_name;
+        CHECK(sym_ref.getName(sym_name) == 0);
+
+        // Relocate the fixup.
+        // TODO: Support more relocation type.
+        CHECK(rel_type == llvm::ELF::R_ARM_ABS32);
+        CHECK_LE(rel_offset + 4, compiled_code_.size());
+
+        uintptr_t dest_addr = plt.GetEntryAddress(sym_name.str().c_str());
+        uintptr_t final_addr = dest_addr + rel_addend;
+        compiled_code_[rel_offset] = final_addr & 0xff;
+        compiled_code_[rel_offset + 1] = (final_addr >> 8) & 0xff;
+        compiled_code_[rel_offset + 2] = (final_addr >> 16) & 0xff;
+        compiled_code_[rel_offset + 3] = (final_addr >> 24) & 0xff;
+      }
+
+    } else {
+      LOG(WARNING) << "Unexpected section: " << name.str();
+    }
+  }
+
+  return true;
+}
+
+
+// Check whether the align is less than or equal to the code alignment of
+// that architecture.  Since the Oat writer only guarantee that the compiled
+// method being aligned to kArchAlignment, we have no way to align the ELf
+// section if the section alignment is greater than kArchAlignment.
+void CompilationUnit::CheckCodeAlign(uint32_t align) const {
+  InstructionSet insn_set = GetInstructionSet();
+  switch (insn_set) {
+  case kThumb2:
+  case kArm:
+    CHECK_LE(align, static_cast<uint32_t>(kArmAlignment));
+    break;
+
+  case kX86:
+    CHECK_LE(align, static_cast<uint32_t>(kX86Alignment));
+    break;
+
+  case kMips:
+    CHECK_LE(align, static_cast<uint32_t>(kMipsAlignment));
+    break;
+
+  default:
+    LOG(FATAL) << "Unknown instruction set: " << insn_set;
+  }
+}
+
+
 } // namespace compiler_llvm
 } // namespace art