Add ELF loader to load the executables.

(cherry picked from commit 8c9ca414a7ed05c3530973c63496e477e9ca5eb7)

Conflicts:

	src/compiler.cc

Change-Id: I950749625d5b266990c617e2d8cea688fbdc11fb
diff --git a/build/Android.libart-compiler-llvm.mk b/build/Android.libart-compiler-llvm.mk
index 1b584d6..134d87e 100644
--- a/build/Android.libart-compiler-llvm.mk
+++ b/build/Android.libart-compiler-llvm.mk
@@ -21,6 +21,7 @@
 	src/compiler_llvm/compilation_unit.cc \
 	src/compiler_llvm/compiler_llvm.cc \
 	src/compiler_llvm/dalvik_reg.cc \
+	src/compiler_llvm/elf_loader.cc \
 	src/compiler_llvm/frontend.cc \
 	src/compiler_llvm/generated/art_module.cc \
 	src/compiler_llvm/inferred_reg_category_map.cc \
diff --git a/src/common_test.h b/src/common_test.h
index 4f65d54..a79b619 100644
--- a/src/common_test.h
+++ b/src/common_test.h
@@ -24,7 +24,6 @@
 #include "class_linker.h"
 #include "class_loader.h"
 #include "compiler.h"
-#include "compiler_llvm/utils_llvm.h"
 #include "constants.h"
 #include "dex_file.h"
 #include "file.h"
@@ -215,10 +214,17 @@
     const CompiledInvokeStub* compiled_invoke_stub =
         compiler_->FindInvokeStub(mh.IsStatic(), mh.GetShorty());
     CHECK(compiled_invoke_stub != NULL) << PrettyMethod(method);
-    const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
-    MakeExecutable(invoke_stub);
-    const Method::InvokeStub* method_invoke_stub
-        = reinterpret_cast<const Method::InvokeStub*>(&invoke_stub[0]);
+
+    const Method::InvokeStub* method_invoke_stub = NULL;
+    if (compiled_invoke_stub->IsExecutableInElf()) {
+      method_invoke_stub =
+          compiler_->GetMethodInvokeStubAddr(compiled_invoke_stub, method);
+    } else {
+      const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
+      MakeExecutable(invoke_stub);
+      method_invoke_stub = reinterpret_cast<const Method::InvokeStub*>(&invoke_stub[0]);
+    }
+
     LOG(INFO) << "MakeExecutable " << PrettyMethod(method)
               << " invoke_stub=" << reinterpret_cast<void*>(method_invoke_stub);
 
@@ -229,11 +235,18 @@
           compiler_->GetCompiledMethod(Compiler::MethodReference(&dex_file,
                                                                  method->GetDexMethodIndex()));
       CHECK(compiled_method != NULL) << PrettyMethod(method);
-      const std::vector<uint8_t>& code = compiled_method->GetCode();
-      MakeExecutable(code);
-      const void* method_code
-          = CompiledMethod::CodePointer(&code[0], compiled_method->GetInstructionSet());
+
+      const void* method_code = NULL;
+      if (compiled_method->IsExecutableInElf()) {
+        method_code = compiler_->GetMethodCodeAddr(compiled_method, method);
+      } else {
+        const std::vector<uint8_t>& code = compiled_method->GetCode();
+        MakeExecutable(code);
+        method_code = CompiledMethod::CodePointer(&code[0], compiled_method->GetInstructionSet());
+      }
+
       LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
+
       OatFile::OatMethod oat_method = CreateOatMethod(method_code,
                                                       compiled_method->GetFrameSizeInBytes(),
                                                       compiled_method->GetCoreSpillMask(),
@@ -242,11 +255,7 @@
                                                       &compiled_method->GetVmapTable()[0],
                                                       NULL,
                                                       method_invoke_stub);
-#if !defined(ART_USE_LLVM_COMPILER)
       oat_method.LinkMethodPointers(method);
-#else
-      LLVMLinkLoadMethod("gtest-0", method);
-#endif
     } else {
       MakeExecutable(runtime_->GetAbstractMethodErrorStubArray());
       const void* method_code = runtime_->GetAbstractMethodErrorStubArray()->GetData();
@@ -361,6 +370,7 @@
                                  true, true));
 #if defined(ART_USE_LLVM_COMPILER)
     compiler_->SetElfFileName("gtest");
+    compiler_->EnableAutoElfLoading();
 #endif
 
     Runtime::Current()->GetHeap()->VerifyHeap();  // Check for heap corruption before the test
diff --git a/src/compiler.cc b/src/compiler.cc
index 0431d74..c5da125 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -322,7 +322,13 @@
       compiler_(NULL),
       compiler_context_(NULL),
       jni_compiler_(NULL),
-      create_invoke_stub_(NULL) {
+      create_invoke_stub_(NULL)
+#if defined(ART_USE_LLVM_COMPILER)
+    , compiler_enable_auto_elf_loading_(NULL),
+      compiler_get_method_code_addr_(NULL),
+      compiler_get_method_invoke_stub_addr_(NULL)
+#endif
+{
   std::string compiler_so_name(MakeCompilerSoName(instruction_set_));
   compiler_library_ = dlopen(compiler_so_name.c_str(), RTLD_LAZY);
   if (compiler_library_ == NULL) {
@@ -346,6 +352,15 @@
   jni_compiler_ = FindFunction<JniCompilerFn>(compiler_so_name, compiler_library_, "ArtJniCompileMethod");
   create_invoke_stub_ = FindFunction<CreateInvokeStubFn>(compiler_so_name, compiler_library_, "ArtCreateInvokeStub");
 
+#if defined(ART_USE_LLVM_COMPILER)
+  compiler_enable_auto_elf_loading_ = FindFunction<CompilerEnableAutoElfLoadingFn>(
+      compiler_so_name, compiler_library_, "compilerLLVMEnableAutoElfLoading");
+  compiler_get_method_code_addr_ = FindFunction<CompilerGetMethodCodeAddrFn>(
+      compiler_so_name, compiler_library_, "compilerLLVMGetMethodCodeAddr");
+  compiler_get_method_invoke_stub_addr_ = FindFunction<CompilerGetMethodInvokeStubAddrFn>(
+      compiler_so_name, compiler_library_, "compilerLLVMGetMethodInvokeStubAddr");
+#endif
+
   CHECK(!Runtime::Current()->IsStarted());
   if (!image_) {
     CHECK(image_classes_ == NULL);
@@ -1429,6 +1444,20 @@
 
   set_bitcode_file_name(*this, filename);
 }
+
+void Compiler::EnableAutoElfLoading() {
+  compiler_enable_auto_elf_loading_(*this);
+}
+
+const void* Compiler::GetMethodCodeAddr(const CompiledMethod* cm,
+                                        const Method* method) const {
+  return compiler_get_method_code_addr_(*this, cm, method);
+}
+
+const Method::InvokeStub* Compiler::GetMethodInvokeStubAddr(const CompiledInvokeStub* cm,
+                                                            const Method* method) const {
+  return compiler_get_method_invoke_stub_addr_(*this, cm, method);
+}
 #endif
 
 }  // namespace art
diff --git a/src/compiler.h b/src/compiler.h
index 4adb447..9834d78 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -137,6 +137,26 @@
 #if defined(ART_USE_LLVM_COMPILER)
   void SetElfFileName(std::string const& filename);
   void SetBitcodeFileName(std::string const& filename);
+
+  void EnableAutoElfLoading();
+
+  const void* GetMethodCodeAddr(const CompiledMethod* cm,
+                                const Method* method) const;
+
+  const Method::InvokeStub* GetMethodInvokeStubAddr(const CompiledInvokeStub* cm,
+                                                    const Method* method) const;
+#else
+  void EnableAutoElfLoader() { }
+
+  const void* GetMethodCodeAddr(const CompiledMethod*,
+                                const Method*) const {
+    return NULL;
+  }
+
+  const Method::InvokeStub* GetMethodInvokeStubAddr(const CompiledInvokeStub*,
+                                                    const Method*) const {
+    return NULL;
+  }
 #endif
 
   void SetCompilerContext(void* compiler_context) {
@@ -285,6 +305,7 @@
   typedef void (*CompilerCallbackFn)(Compiler& compiler);
   typedef MutexLock* (*CompilerMutexLockFn)(Compiler& compiler);
 #endif
+
   void* compiler_library_;
 
   typedef CompiledMethod* (*CompilerFn)(Compiler& compiler,
@@ -305,6 +326,20 @@
                                                     const char* shorty, uint32_t shorty_len);
   CreateInvokeStubFn create_invoke_stub_;
 
+#if defined(ART_USE_LLVM_COMPILER)
+  typedef void (*CompilerEnableAutoElfLoadingFn)(Compiler& compiler);
+  CompilerEnableAutoElfLoadingFn compiler_enable_auto_elf_loading_;
+
+  typedef const void* (*CompilerGetMethodCodeAddrFn)
+      (const Compiler& compiler, const CompiledMethod* cm, const Method* method);
+  CompilerGetMethodCodeAddrFn compiler_get_method_code_addr_;
+
+  typedef const Method::InvokeStub* (*CompilerGetMethodInvokeStubAddrFn)
+      (const Compiler& compiler, const CompiledInvokeStub* cm, const Method* method);
+  CompilerGetMethodInvokeStubAddrFn compiler_get_method_invoke_stub_addr_;
+#endif
+
+
   DISALLOW_COPY_AND_ASSIGN(Compiler);
 };
 
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 84e66de..1d878c9 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -18,8 +18,10 @@
 
 #include "class_linker.h"
 #include "compilation_unit.h"
+#include "compiled_method.h"
 #include "compiler.h"
 #include "dex_cache.h"
+#include "elf_loader.h"
 #include "ir_builder.h"
 #include "jni_compiler.h"
 #include "method_compiler.h"
@@ -166,11 +168,64 @@
   // Materialize the llvm::Module into ELF object file
   curr_cunit_->Materialize();
 
+  // Load ELF image when automatic ELF loading is enabled
+  if (IsAutoElfLoadingEnabled()) {
+    LoadElfFromCompilationUnit(curr_cunit_);
+  }
+
   // Delete the compilation unit
   curr_cunit_ = NULL;
 }
 
 
+void CompilerLLVM::EnableAutoElfLoading() {
+  MutexLock GUARD(compiler_lock_);
+
+  if (IsAutoElfLoadingEnabled()) {
+    // If there is an existing ELF loader, then do nothing.
+    // Because the existing ELF loader may have returned some code address
+    // already.  If we replace the existing ELF loader with
+    // elf_loader_.reset(...), then it is possible to have some dangling
+    // pointer.
+    return;
+  }
+
+  // Create ELF loader and load the materialized CompilationUnit
+  elf_loader_.reset(new ElfLoader());
+
+  for (size_t i = 0; i < cunits_.size(); ++i) {
+    if (cunits_[i]->IsMaterialized()) {
+      LoadElfFromCompilationUnit(cunits_[i]);
+    }
+  }
+}
+
+
+void CompilerLLVM::LoadElfFromCompilationUnit(const CompilationUnit* cunit) {
+  compiler_lock_.AssertHeld();
+  DCHECK(cunit->IsMaterialized()) << cunit->GetElfIndex();
+
+  if (!elf_loader_->LoadElfAt(cunit->GetElfIndex(),
+                              cunit->GetElfImage(),
+                              cunit->GetElfSize())) {
+    LOG(ERROR) << "Failed to load ELF from compilation unit "
+               << cunit->GetElfIndex();
+  }
+}
+
+
+const void* CompilerLLVM::GetMethodCodeAddr(const CompiledMethod* cm,
+                                            const Method* method) const {
+  return elf_loader_->GetMethodCodeAddr(cm->GetElfIndex(), method);
+}
+
+
+const Method::InvokeStub* CompilerLLVM::
+GetMethodInvokeStubAddr(const CompiledInvokeStub* cm, const Method* method) const {
+  return elf_loader_->GetMethodInvokeStubAddr(cm->GetElfIndex(), method);
+}
+
+
 CompiledMethod* CompilerLLVM::
 CompileDexMethod(OatCompilationUnit* oat_compilation_unit) {
   MutexLock GUARD(compiler_lock_);
@@ -286,6 +341,28 @@
   ContextOf(compiler)->MaterializeRemainder();
 }
 
+extern "C" void compilerLLVMEnableAutoElfLoading(art::Compiler& compiler) {
+  art::compiler_llvm::CompilerLLVM* compiler_llvm =
+      reinterpret_cast<art::compiler_llvm::CompilerLLVM*>(compiler.GetCompilerContext());
+  return compiler_llvm->EnableAutoElfLoading();
+}
+
+extern "C" const void* compilerLLVMGetMethodCodeAddr(const art::Compiler& compiler,
+                                                     const art::CompiledMethod* cm,
+                                                     const art::Method* method) {
+  const art::compiler_llvm::CompilerLLVM* compiler_llvm =
+      reinterpret_cast<const art::compiler_llvm::CompilerLLVM*>(compiler.GetCompilerContext());
+  return compiler_llvm->GetMethodCodeAddr(cm, method);
+}
+
+extern "C" const art::Method::InvokeStub* compilerLLVMGetMethodInvokeStubAddr(const art::Compiler& compiler,
+                                                                              const art::CompiledInvokeStub* cm,
+                                                                              const art::Method* method) {
+  const art::compiler_llvm::CompilerLLVM* compiler_llvm =
+      reinterpret_cast<const art::compiler_llvm::CompilerLLVM*>(compiler.GetCompilerContext());
+  return compiler_llvm->GetMethodInvokeStubAddr(cm, method);
+}
+
 // Note: Using this function carefully!!! This is temporary solution, we will remove it.
 extern "C" art::MutexLock* compilerLLVMMutexLock(art::Compiler& compiler) {
   return new art::MutexLock(ContextOf(compiler)->compiler_lock_);
diff --git a/src/compiler_llvm/compiler_llvm.h b/src/compiler_llvm/compiler_llvm.h
index 562a1d2..626c13d 100644
--- a/src/compiler_llvm/compiler_llvm.h
+++ b/src/compiler_llvm/compiler_llvm.h
@@ -20,6 +20,7 @@
 #include "constants.h"
 #include "dex_file.h"
 #include "macros.h"
+#include "object.h"
 
 #include <UniquePtr.h>
 
@@ -31,6 +32,7 @@
   class CompiledMethod;
   class Compiler;
   class OatCompilationUnit;
+  class Method;
 }
 
 
@@ -48,6 +50,7 @@
 namespace compiler_llvm {
 
 class CompilationUnit;
+class ElfLoader;
 class IRBuilder;
 
 class CompilerLLVM {
@@ -84,6 +87,19 @@
     bitcode_filename_ = filename;
   }
 
+  void EnableAutoElfLoading();
+
+  bool IsAutoElfLoadingEnabled() const {
+    return (elf_loader_.get() != NULL);
+  }
+
+  const void* GetMethodCodeAddr(const CompiledMethod* cm,
+                                const Method* method) const;
+
+  const Method::InvokeStub* GetMethodInvokeStubAddr(
+                                const CompiledInvokeStub* cm,
+                                const Method* method) const;
+
   CompiledMethod* CompileDexMethod(OatCompilationUnit* oat_compilation_unit);
 
   CompiledMethod* CompileNativeMethod(OatCompilationUnit* oat_compilation_unit);
@@ -95,6 +111,8 @@
 
   void Materialize();
 
+  void LoadElfFromCompilationUnit(const CompilationUnit* cunit);
+
   bool IsBitcodeFileNameAvailable() const {
     return !bitcode_filename_.empty();
   }
@@ -115,6 +133,8 @@
 
   std::string bitcode_filename_;
 
+  UniquePtr<ElfLoader> elf_loader_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilerLLVM);
 };
 
diff --git a/src/compiler_llvm/elf_loader.cc b/src/compiler_llvm/elf_loader.cc
new file mode 100644
index 0000000..f309b82
--- /dev/null
+++ b/src/compiler_llvm/elf_loader.cc
@@ -0,0 +1,87 @@
+/*
+ * 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 "elf_loader.h"
+
+#include "compiled_method.h"
+#include "logging.h"
+#include "object.h"
+#include "runtime_support_llvm.h"
+#include "utils_llvm.h"
+
+#include <android/librsloader.h>
+
+namespace art {
+namespace compiler_llvm {
+
+
+ElfLoader::~ElfLoader() {
+  // Release every ELF object
+  for (size_t i = 0; i < executables_.size(); ++i) {
+    rsloaderDisposeExec(executables_[i]);
+  }
+}
+
+
+bool ElfLoader::LoadElfAt(size_t elf_idx, const byte* image, size_t size) {
+  if (elf_idx < executables_.size() && executables_[elf_idx] != NULL) {
+    return false;
+  }
+
+  if (elf_idx >= executables_.size()) {
+    executables_.resize(elf_idx + 1);
+  }
+
+  RSExecRef executable =
+    rsloaderCreateExec(reinterpret_cast<const unsigned char*>(image),
+                       size, art_find_runtime_support_func, NULL);
+
+  if (executable == NULL) {
+    LOG(WARNING) << "Failed to load ELF image: " << image << " size: " << size;
+    return false;
+  }
+
+  executables_[elf_idx] = executable;
+  return true;
+}
+
+
+const void* ElfLoader::GetMethodCodeAddr(size_t elf_idx,
+                                         const Method* method) const {
+  CHECK_LT(elf_idx, executables_.size());
+  CHECK(method != NULL);
+  return GetAddr(elf_idx, LLVMLongName(method).c_str());
+}
+
+
+const Method::InvokeStub* ElfLoader::
+GetMethodInvokeStubAddr(size_t elf_idx, const Method* method) const {
+  CHECK_LT(elf_idx, executables_.size());
+  CHECK(method != NULL);
+  return reinterpret_cast<const Method::InvokeStub*>(
+      GetAddr(elf_idx, LLVMStubName(method).c_str()));
+}
+
+
+const void* ElfLoader::GetAddr(size_t elf_idx, const char* sym_name) const {
+  CHECK_LT(elf_idx, executables_.size());
+  CHECK(executables_[elf_idx] != NULL);
+  return rsloaderGetSymbolAddress(executables_[elf_idx], sym_name);
+}
+
+
+} // namespace compiler_llvm
+} // namespace art
diff --git a/src/compiler_llvm/elf_loader.h b/src/compiler_llvm/elf_loader.h
new file mode 100644
index 0000000..5f7ab86
--- /dev/null
+++ b/src/compiler_llvm/elf_loader.h
@@ -0,0 +1,54 @@
+/*
+ * 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_ELF_LOADER_H_
+#define ART_SRC_COMPILER_LLVM_ELF_LOADER_H_
+
+#include "globals.h"
+#include "object.h"
+
+#include <android/librsloader.h>
+#include <vector>
+
+namespace art {
+  class Method;
+}
+
+namespace art {
+namespace compiler_llvm {
+
+class ElfLoader {
+ public:
+  ~ElfLoader();
+
+  bool LoadElfAt(size_t elf_idx, const byte* addr, size_t size);
+
+  const void* GetMethodCodeAddr(size_t elf_idx, const Method* method) const;
+
+  const Method::InvokeStub* GetMethodInvokeStubAddr(size_t elf_idx,
+                                                    const Method* method) const;
+
+ private:
+  const void* GetAddr(size_t elf_idx, const char* sym_name) const;
+
+  std::vector<RSExecRef> executables_;
+};
+
+
+} // namespace compiler_llvm
+} // namespace art
+
+#endif // ART_SRC_COMPILER_LLVM_ELF_LOADER_H_
diff --git a/src/compiler_llvm/utils_llvm.cc b/src/compiler_llvm/utils_llvm.cc
index 0941b3e..98d1c7c 100644
--- a/src/compiler_llvm/utils_llvm.cc
+++ b/src/compiler_llvm/utils_llvm.cc
@@ -108,40 +108,4 @@
   return stub_name;
 }
 
-void LLVMLinkLoadMethod(const std::string& file_name, Method* method) {
-  CHECK(method != NULL);
-
-  int fd = open(file_name.c_str(), O_RDONLY);
-  CHECK(fd >= 0) << "Error: ELF not found: " << file_name;
-
-  struct stat sb;
-  CHECK(fstat(fd, &sb) == 0) << "Error: Unable to stat ELF: " << file_name;
-
-  unsigned char const *image = (unsigned char const *)
-      mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-  CHECK(image != MAP_FAILED) << "Error: Unable to mmap ELF: " << file_name;
-
-  RSExecRef relocatable =
-    rsloaderCreateExec(image, sb.st_size, art_find_runtime_support_func, 0);
-  CHECK(relocatable) << "Error: Unable to load ELF: " << file_name;
-
-  const void *addr = rsloaderGetSymbolAddress(relocatable, LLVMLongName(method).c_str());
-  CHECK(addr) << "Error: ELF (" << file_name << ") has no symbol " << LLVMLongName(method);
-  method->SetCode(reinterpret_cast<const uint32_t*>(addr));
-
-  method->SetFrameSizeInBytes(0);
-  method->SetCoreSpillMask(0);
-  method->SetFpSpillMask(0);
-  method->SetMappingTable(reinterpret_cast<const uint32_t*>(NULL));
-  method->SetVmapTable(reinterpret_cast<const uint16_t*>(NULL));
-  method->SetGcMap(reinterpret_cast<const uint8_t*>(NULL));
-
-  addr = rsloaderGetSymbolAddress(relocatable, LLVMStubName(method).c_str());
-  CHECK(addr) << "Error: ELF (" << file_name << ") has no symbol " << LLVMStubName(method);
-  method->SetInvokeStub(reinterpret_cast<void (*)(const art::Method*, art::Object*, art::Thread*,
-                                                  art::JValue*, art::JValue*)>(addr));
-
-  close(fd);
-}
-
 }  // namespace art