Merge "Support for a set of verifier failures." into ics-mr1-plus-art
diff --git a/Android.mk b/Android.mk
index fa13d8b..6de5eff 100644
--- a/Android.mk
+++ b/Android.mk
@@ -23,6 +23,9 @@
 ART_BUILD_HOST_NDEBUG ?= true
 ART_BUILD_HOST_DEBUG ?= true
 
+ART_HOST_SHLIB_EXTENSION := $(HOST_SHLIB_SUFFIX)
+ART_HOST_SHLIB_EXTENSION ?= .so
+
 build_path := $(LOCAL_PATH)/build
 include $(build_path)/Android.common.mk
 
@@ -38,11 +41,7 @@
 
 # ART_HOST_DEPENDENCIES depends on Android.executable.mk above for ART_HOST_EXECUTABLES
 ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-hostdex.jar
-ifeq ($(HOST_OS),linux)
-  ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore.so
-else
-  ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore.dylib
-endif
+ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
 ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
 
 ########################################################################
@@ -89,7 +88,7 @@
 	@echo test-art-host PASSED
 
 .PHONY: test-art-host-dependencies
-test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_OUT_SHARED_LIBRARIES)/libarttest.so
+test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION)
 
 .PHONY: test-art-host-gtest
 test-art-host-gtest: $(ART_HOST_TEST_TARGETS)
diff --git a/build/Android.common.mk b/build/Android.common.mk
index 6c2041c..e62602c 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -14,7 +14,7 @@
 # limitations under the License.
 #
 
-# TODO: move the LLVM compiler out into a separate .so too...
+# TODO: move the LLVM compiler out into a separate shared library too...
 # Use llvm as the backend
 ifneq ($(wildcard art/USE_LLVM_COMPILER),)
 ART_USE_LLVM_COMPILER := true
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index b976fd2..9c1f8d0 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -17,9 +17,11 @@
 #include "compilation_unit.h"
 
 #include "compiled_method.h"
+#include "file.h"
 #include "instruction_set.h"
 #include "ir_builder.h"
 #include "logging.h"
+#include "os.h"
 
 #include "runtime_support_builder_arm.h"
 #include "runtime_support_builder_x86.h"
@@ -45,6 +47,7 @@
 #include <llvm/Support/Debug.h>
 #include <llvm/Support/FormattedStream.h>
 #include <llvm/Support/ManagedStatic.h>
+#include <llvm/Support/MemoryBuffer.h>
 #include <llvm/Support/PassNameParser.h>
 #include <llvm/Support/PluginLoader.h>
 #include <llvm/Support/PrettyStackTrace.h>
@@ -54,11 +57,17 @@
 #include <llvm/Support/TargetSelect.h>
 #include <llvm/Support/ToolOutputFile.h>
 #include <llvm/Support/raw_ostream.h>
+#include <llvm/Support/system_error.h>
 #include <llvm/Target/TargetData.h>
 #include <llvm/Target/TargetLibraryInfo.h>
 #include <llvm/Target/TargetMachine.h>
+#include <llvm/Transforms/IPO.h>
 #include <llvm/Transforms/IPO/PassManagerBuilder.h>
 
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
 #include <string>
 
 namespace {
@@ -136,11 +145,11 @@
 }
 
 
-bool CompilationUnit::WriteBitcodeToFile() {
+bool CompilationUnit::WriteBitcodeToFile(const std::string& bitcode_filename) {
   std::string errmsg;
 
   llvm::OwningPtr<llvm::tool_output_file> out_file(
-    new llvm::tool_output_file(bitcode_filename_.c_str(), errmsg,
+    new llvm::tool_output_file(bitcode_filename.c_str(), errmsg,
                                llvm::raw_fd_ostream::F_Binary));
 
 
@@ -155,115 +164,113 @@
   return true;
 }
 
-
-bool CompilationUnit::Materialize() {
-  // Lookup the LLVM target
-  char const* target_triple = NULL;
-  char const* target_attr = NULL;
-
-  switch (insn_set_) {
-  case kThumb2:
-    target_triple = "thumb-none-linux-gnueabi";
-    target_attr = "+thumb2,+neon,+neonfp,+vfp3";
-    break;
-
-  case kArm:
-    target_triple = "armv7-none-linux-gnueabi";
-    target_attr = "+v7,+neon,+neonfp,+vfp3";
-    break;
-
-  case kX86:
-    target_triple = "i386-pc-linux-gnu";
-    target_attr = "";
-    break;
-
-  case kMips:
-    target_triple = "mipsel-unknown-linux";
-    target_attr = "mips32r2";
-    break;
-
-  default:
-    LOG(FATAL) << "Unknown instruction set: " << insn_set_;
+// TODO: Move to scoped_temp_file.h
+class ScopedTempFile {
+ public:
+  ScopedTempFile(const std::string& filename_template)
+      : filename_(filename_template), file_(NULL) {
+    int fd = mkstemp(&filename_[0]);
+    CHECK_NE(-1, fd);
+    file_ = OS::FileFromFd(filename_.c_str(), fd);
   }
 
-  std::string errmsg;
-  llvm::Target const* target =
-    llvm::TargetRegistry::lookupTarget(target_triple, errmsg);
+  ~ScopedTempFile() {
+    delete file_;
+    TEMP_FAILURE_RETRY(unlink(filename_.c_str()));
+  }
 
-  CHECK(target != NULL) << errmsg;
+  int GetFd() {
+    return file_->Fd();
+  }
 
-  // Target options
-  llvm::TargetOptions target_options;
-  target_options.FloatABIType = llvm::FloatABI::Soft;
-  target_options.NoFramePointerElim = true;
-  target_options.NoFramePointerElimNonLeaf = true;
-  target_options.UseSoftFloat = false;
-  target_options.EnableFastISel = true;
+  const std::string &GetName() const {
+    return filename_;
+  }
 
-  // Create the llvm::TargetMachine
-  llvm::TargetMachine* target_machine =
-    target->createTargetMachine(target_triple, "", target_attr, target_options,
-                                llvm::Reloc::Static, llvm::CodeModel::Small,
-                                llvm::CodeGenOpt::Less);
+  bool ReadToString(std::string &buffer) {
+    off_t file_size = file_->Length();
+    if (file_size <= 0) {
+      buffer.clear();
+      return true;
+    }
 
-  CHECK(target_machine != NULL) << "Failed to create target machine";
+    buffer.reserve(file_size);
+    buffer.resize(file_size);
+    return file_->ReadFully(&buffer[0], file_size);
+  }
 
+ private:
+  std::string filename_;
+  File *file_;
+};
 
-  // Add target data
-  llvm::TargetData const* target_data = target_machine->getTargetData();
+bool CompilationUnit::Materialize() {
+  const std::string tmp_file = "/tmp/art-llvm-XXXXXX";
 
-  // PassManager for code generation passes
-  llvm::PassManager pm;
-  pm.add(new llvm::TargetData(*target_data));
+  // Prepare the input
+  ScopedTempFile input(tmp_file);
+  if (input.GetFd() < 0) {
+    PLOG(ERROR) << "Failed to save the module to the file " << tmp_file;
+    return false;
+  }
 
-  // FunctionPassManager for optimization pass
-  llvm::FunctionPassManager fpm(module_);
-  fpm.add(new llvm::TargetData(*target_data));
+  // Write the bitcode to the file
+  if (!WriteBitcodeToFile(input.GetName())) {
+    return false;
+  }
 
-  // Add optimization pass
-  llvm::PassManagerBuilder pm_builder;
-  pm_builder.Inliner = NULL; // TODO: add some inline in the future
-  pm_builder.OptLevel = 1;
-  pm_builder.DisableSimplifyLibCalls = 1;
-  pm_builder.populateModulePassManager(pm);
-  pm_builder.populateFunctionPassManager(fpm);
+  // Prepare the output
+  ScopedTempFile output(tmp_file);
+  if (output.GetFd() < 0) {
+    PLOG(ERROR) << "Failed to prepare the output file " << tmp_file;
+    return false;
+  }
 
-  // Add passes to emit ELF image
-  {
-    llvm::formatted_raw_ostream formatted_os(
-      *(new llvm::raw_string_ostream(elf_image_)), true);
+  // Fork a process to do the compilation
+  pid_t pid = fork();
+  if (pid == 0) {
+    // change process groups, so we don't get ripped by ProcessManager
+    setpgid(0, 0);
 
-    // 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";
+    // TODO: Should use exec* family instead of invoking a function.
+    // Forward our compilation request to bcc.
+    exit(static_cast<int>(!MaterializeFile(input.GetFd(), output.GetFd(),
+                                           insn_set_)));
+  } else {
+    if (pid < 0) {
+      LOG(FATAL) << "Failed to fork a process to do the compilation: "
+                 << strerror(errno);
+    }
+
+    // Free the resources
+    context_.reset(NULL);
+    irb_.reset(NULL);
+    module_ = NULL;
+
+    int status;
+
+    // Wait for child to finish
+    pid_t got_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+    if (got_pid != pid) {
+      PLOG(ERROR) << "waitpid failed: wanted " << pid << ", got " << got_pid;
       return false;
     }
 
-    // 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();
-         F != E; ++F) {
-      fpm.run(*F);
+    if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
+      LOG(ERROR) << "Failed to compile the bitcode: " << WEXITSTATUS(status);
+      return false;
     }
-    fpm.doFinalization();
+  }
 
-    // Run the code generation passes
-    pm.run(*module_);
+  // Read the result out from the output file
+  TEMP_FAILURE_RETRY(lseek(output.GetFd(), 0, SEEK_SET));
+  if (!output.ReadToString(elf_image_)) {
+    LOG(ERROR) << "Failed to read the result file";
+    return false;
   }
 
   LOG(INFO) << "Compilation Unit: " << elf_idx_ << " (done)";
 
-  // Free the resources
-  context_.reset(NULL);
-  irb_.reset(NULL);
-  module_ = NULL;
-
   return true;
 }
 
@@ -291,6 +298,141 @@
   }
 }
 
+bool CompilationUnit::MaterializeFile(int input_fd, int output_fd,
+                                      InstructionSet insn_set) {
+  // Initialize the LLVM first
+  llvm::InitializeAllTargets();
+  llvm::InitializeAllTargetMCs();
+  llvm::InitializeAllAsmPrinters();
+  llvm::InitializeAllAsmParsers();
+
+  // Read the LLVM module from input_fd
+  llvm::OwningPtr<llvm::MemoryBuffer> memory_buffer;
+  llvm::error_code load_input_err =
+      llvm::MemoryBuffer::getOpenFile(input_fd, "<art-llvm-module>",
+                                      memory_buffer);
+
+  if (load_input_err) {
+    LOG(ERROR) << "Failed to load input for compiler into memory: "
+               << load_input_err.message();
+    return false;
+  }
+
+  // It's safe to use the global context now
+  std::string load_module_errmsg;
+  llvm::Module *module = ParseBitcodeFile(memory_buffer.get(),
+                                          llvm::getGlobalContext(),
+                                          &load_module_errmsg);
+  if (module == NULL) {
+    LOG(ERROR) << "Failed to load LLVM module to compiler: "
+               << load_module_errmsg;
+    return false;
+  }
+
+  // Lookup the LLVM target
+  char const* target_triple = NULL;
+  char const* target_attr = NULL;
+
+  switch (insn_set) {
+  case kThumb2:
+    target_triple = "thumb-none-linux-gnueabi";
+    target_attr = "+thumb2,+neon,+neonfp,+vfp3";
+    break;
+
+  case kArm:
+    target_triple = "armv7-none-linux-gnueabi";
+    // TODO: Fix for Xoom.
+    target_attr = "+v7,+neon,+neonfp,+vfp3";
+    break;
+
+  case kX86:
+    target_triple = "i386-pc-linux-gnu";
+    target_attr = "";
+    break;
+
+  case kMips:
+    target_triple = "mipsel-unknown-linux";
+    target_attr = "mips32r2";
+    break;
+
+  default:
+    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.NoFramePointerElim = true;
+  target_options.NoFramePointerElimNonLeaf = true;
+  target_options.UseSoftFloat = false;
+  target_options.EnableFastISel = true;
+
+  // Create the llvm::TargetMachine
+  llvm::TargetMachine* target_machine =
+    target->createTargetMachine(target_triple, "", target_attr, target_options,
+                                llvm::Reloc::Static, llvm::CodeModel::Small,
+                                llvm::CodeGenOpt::Less);
+
+  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 = llvm::createAlwaysInlinerPass();
+  pm_builder.OptLevel = 1;
+  pm_builder.DisableSimplifyLibCalls = 1;
+  pm_builder.populateModulePassManager(pm);
+  pm_builder.populateFunctionPassManager(fpm);
+
+  // Add passes to emit ELF image
+  {
+    llvm::formatted_raw_ostream formatted_os(
+      *(new llvm::raw_fd_ostream(output_fd, /* shouldClose */false)), true);
+
+    // 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;
+    }
+
+    // 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();
+         F != E; ++F) {
+      fpm.run(*F);
+    }
+    fpm.doFinalization();
+
+    // Run the code generation passes
+    pm.run(*module);
+  }
+
+  return true;
+}
 
 } // namespace compiler_llvm
 } // namespace art
diff --git a/src/compiler_llvm/compilation_unit.h b/src/compiler_llvm/compilation_unit.h
index 953f4f4..9d87704 100644
--- a/src/compiler_llvm/compilation_unit.h
+++ b/src/compiler_llvm/compilation_unit.h
@@ -69,14 +69,6 @@
     return irb_.get();
   }
 
-  std::string const& GetBitcodeFileName() const {
-    return bitcode_filename_;
-  }
-
-  void SetBitcodeFileName(std::string const& filename) {
-    bitcode_filename_ = filename;
-  }
-
   ElfImage GetElfImage() const {
     return ElfImage(elf_image_);
   }
@@ -86,7 +78,7 @@
     return num_elf_funcs_++;
   }
 
-  bool WriteBitcodeToFile();
+  bool WriteBitcodeToFile(const std::string& bitcode_filename);
 
   bool Materialize();
 
@@ -116,12 +108,13 @@
   llvm::Module* module_;
 
   std::string elf_image_;
-  std::string bitcode_filename_;
 
   SafeMap<const llvm::Function*, CompiledMethod*> compiled_methods_map_;
 
   size_t mem_usage_;
   uint16_t num_elf_funcs_;
+
+  static bool MaterializeFile(int input_fd, int output_fd, InstructionSet insn_set);
 };
 
 } // namespace compiler_llvm
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 8945210..2ebf5f6 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -129,57 +129,66 @@
 
   // Allocate compilation unit
   size_t cunit_idx = cunits_.size();
-
   curr_cunit_ = new CompilationUnit(insn_set_, cunit_idx);
 
-  // Setup bitcode output filename
-  if (IsBitcodeFileNameAvailable()) {
-    curr_cunit_->SetBitcodeFileName(
-      StringPrintf("%s-%zu", bitcode_filename_.c_str(), cunit_idx));
-  }
-
   // Register compilation unit
   cunits_.push_back(curr_cunit_);
 }
 
 
 void CompilerLLVM::MaterializeRemainder() {
-  MutexLock GUARD(compiler_lock_);
-  if (curr_cunit_ != NULL) {
-    Materialize();
+  compiler_lock_.Lock();
+  // Localize
+  CompilationUnit* cunit = curr_cunit_;
+  // Reset the curr_cuit_
+  curr_cunit_ = NULL;
+  compiler_lock_.Unlock();
+
+  if (cunit != NULL) {
+    Materialize(cunit);
   }
 }
 
 
 void CompilerLLVM::MaterializeIfThresholdReached() {
-  MutexLock GUARD(compiler_lock_);
+  compiler_lock_.Lock();
+  // Localize
+  CompilationUnit* cunit = curr_cunit_;
+
   if (curr_cunit_ != NULL && curr_cunit_->IsMaterializeThresholdReached()) {
-    Materialize();
+    // Delete the compilation unit
+    curr_cunit_ = NULL;
+  } else {
+    // Reset cunit such that Materialize() won't be invoked
+    cunit = NULL;
+  }
+
+  compiler_lock_.Unlock();
+
+  if (cunit != NULL) {
+    Materialize(cunit);
   }
 }
 
 
-void CompilerLLVM::Materialize() {
-  compiler_lock_.AssertHeld();
-
-  DCHECK(curr_cunit_ != NULL);
-  DCHECK(!curr_cunit_->IsMaterialized());
+void CompilerLLVM::Materialize(CompilationUnit* cunit) {
+  DCHECK(cunit != NULL);
+  DCHECK(!cunit->IsMaterialized());
 
   // Write bitcode to file when filename is set
   if (IsBitcodeFileNameAvailable()) {
-    curr_cunit_->WriteBitcodeToFile();
+    const size_t cunit_idx = cunits_.size();
+    cunit->WriteBitcodeToFile(
+      StringPrintf("%s-%zu", bitcode_filename_.c_str(), cunit_idx));
   }
 
   // Materialize the llvm::Module into ELF object file
-  curr_cunit_->Materialize();
+  cunit->Materialize();
 
   // Load ELF image when automatic ELF loading is enabled
   if (IsAutoElfLoadingEnabled()) {
-    LoadElfFromCompilationUnit(curr_cunit_);
+    LoadElfFromCompilationUnit(cunit);
   }
-
-  // Delete the compilation unit
-  curr_cunit_ = NULL;
 }
 
 
diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h
index 8bb053e..a6cf966 100644
--- a/src/compiler_llvm/compiler_llvm.h
+++ b/src/compiler_llvm/compiler_llvm.h
@@ -109,7 +109,7 @@
  private:
   void EnsureCompilationUnit();
 
-  void Materialize();
+  void Materialize(CompilationUnit* cunit);
 
   void LoadElfFromCompilationUnit(const CompilationUnit* cunit);