Implement Link-loading and pass 62 tests in JniInternalTest.

The passed tests include the 12 originally ARM-only tests. Now it works
on x86 as well if defined(ART_USE_LLVM_COMPILER).

Change-Id: I03092637fa4f0979ca77e0cac06e5d31a867e465
diff --git a/src/compiler_llvm/compilation_unit.cc b/src/compiler_llvm/compilation_unit.cc
index 45c4bb7..7a2857c 100644
--- a/src/compiler_llvm/compilation_unit.cc
+++ b/src/compiler_llvm/compilation_unit.cc
@@ -143,6 +143,8 @@
 
   target_options.FloatABIType = llvm::FloatABI::Soft;
   target_options.UseSoftFloat = false;
+  target_options.NoFramePointerElim = true;
+  target_options.NoFramePointerElimNonLeaf = true;
 
   // Create the llvm::TargetMachine
   llvm::TargetMachine* target_machine =
diff --git a/src/compiler_llvm/compiler_llvm.cc b/src/compiler_llvm/compiler_llvm.cc
index 56f0b07..0985894 100644
--- a/src/compiler_llvm/compiler_llvm.cc
+++ b/src/compiler_llvm/compiler_llvm.cc
@@ -55,8 +55,8 @@
 
 
 CompilerLLVM::CompilerLLVM(Compiler* compiler, InstructionSet insn_set)
-: compiler_(compiler), compiler_lock_("llvm_compiler_lock"),
-  insn_set_(insn_set), cunit_counter_(0) {
+    : compiler_(compiler), compiler_lock_("llvm_compiler_lock"),
+      insn_set_(insn_set), cunit_counter_(0) {
 
   // Initialize LLVM libraries
   pthread_once(&llvm_initialized, InitializeLLVM);
@@ -69,6 +69,7 @@
 
 
 void CompilerLLVM::EnsureCompilationUnit() {
+  MutexLock GUARD(compiler_lock_);
   DCHECK_NE(llvm_initialized, PTHREAD_ONCE_INIT);
   if (cunit_.get() == NULL) {
     cunit_.reset(new CompilationUnit(insn_set_));
diff --git a/src/compiler_llvm/utils_llvm.cc b/src/compiler_llvm/utils_llvm.cc
index 1a8e8a2..a924793 100644
--- a/src/compiler_llvm/utils_llvm.cc
+++ b/src/compiler_llvm/utils_llvm.cc
@@ -14,6 +14,12 @@
  * limitations under the License.
  */
 
+#include <android/librsloader.h>
+#include <cutils/log.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+
 #include "utils_llvm.h"
 
 #include "class_loader.h"
@@ -86,4 +92,112 @@
   return long_name;
 }
 
+std::string LLVMStubName(const Method* m) {
+  MethodHelper mh(m);
+  std::string stub_name;
+  if (m->IsStatic()) {
+    stub_name += "ArtSUpcall_";
+  } else {
+    stub_name += "ArtUpcall_";
+  }
+  stub_name += mh.GetShorty();
+
+  return stub_name;
+}
+
+// TODO: Remove these when art_llvm.ll runtime support is ready.
+void art_push_shadow_frame_from_code(void* frame) {
+}
+
+void art_pop_shadow_frame_from_code() {
+}
+
+int art_is_exception_pending_from_code() {
+  return 0;
+}
+
+void art_test_suspend_from_code() {
+}
+
+void art_set_current_thread_from_code(void* thread_object_addr) {
+}
+
+// Linker's call back function. Added some for debugging.
+void* find_sym(void* context, char const* name) {
+  struct func_entry_t {
+    char const* name;
+    size_t name_len;
+    void* addr;
+  };
+
+  static struct func_entry_t const tab[] = {
+#define DEF(NAME, ADDR) \
+    { NAME, sizeof(NAME) - 1, (void *)(&(ADDR)) },
+
+    DEF("art_push_shadow_frame_from_code", art_push_shadow_frame_from_code)
+    DEF("art_pop_shadow_frame_from_code", art_pop_shadow_frame_from_code)
+    DEF("art_is_exception_pending_from_code", art_is_exception_pending_from_code)
+    DEF("art_test_suspend_from_code", art_test_suspend_from_code)
+    DEF("art_set_current_thread_from_code", art_set_current_thread_from_code)
+    DEF("printf", printf)
+    DEF("scanf", scanf)
+    DEF("__isoc99_scanf", scanf)
+    DEF("rand", rand)
+    DEF("time", time)
+    DEF("srand", srand)
+#undef DEF
+  };
+
+  static size_t const tab_size = sizeof(tab) / sizeof(struct func_entry_t);
+
+  // Note: Since our table is small, we are using trivial O(n) searching
+  // function.  For bigger table, it will be better to use binary
+  // search or hash function.
+  size_t i;
+  size_t name_len = strlen(name);
+  for (i = 0; i < tab_size; ++i) {
+    if (name_len == tab[i].name_len && strcmp(name, tab[i].name) == 0) {
+      return tab[i].addr;
+    }
+  }
+
+  CHECK(0) << "Error: Can't find symbol " << name;
+  return 0;
+}
+
+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, find_sym, 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::byte*, art::JValue*)>(addr));
+
+  close(fd);
+}
+
 }  // namespace art
diff --git a/src/compiler_llvm/utils_llvm.h b/src/compiler_llvm/utils_llvm.h
index a1624d7..fb4da34 100644
--- a/src/compiler_llvm/utils_llvm.h
+++ b/src/compiler_llvm/utils_llvm.h
@@ -33,6 +33,10 @@
 // Returns the LLVM function name for the overloaded method 'm'.
 std::string LLVMLongName(const Method* m);
 
+// Returns the LLVM stub function name for the overloaded method 'm'.
+std::string LLVMStubName(const Method* m);
+
+void LLVMLinkLoadMethod(const std::string& file_name, Method* method);
 }  // namespace art
 
 #endif  // ART_SRC_UTILS_LLVM_H_