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_