Fix loading of compiler libraries on Mac OS.

Change-Id: I0deecf991f4e45a37221a1348dddf2759144b0a0
diff --git a/src/compiler.cc b/src/compiler.cc
index 26a6919..3f7f637 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -36,6 +36,10 @@
 #include "stl_util.h"
 #include "timing_logger.h"
 
+#if defined(__APPLE__)
+#include <mach-o/dyld.h>
+#endif
+
 #if defined(ART_USE_LLVM_COMPILER)
 #include "compiler_llvm/compiler_llvm.h"
 #endif
@@ -209,19 +213,52 @@
     instruction_set = kArm;
   }
 
+  // Capitalize the instruction set, because that's what we do in the build system.
   std::ostringstream instruction_set_name_os;
   instruction_set_name_os << instruction_set;
   std::string instruction_set_name(instruction_set_name_os.str());
   for (size_t i = 0; i < instruction_set_name.size(); ++i) {
     instruction_set_name[i] = toupper(instruction_set_name[i]);
   }
+
+  // Bad things happen if we pull in the libartd-compiler to a libart dex2oat or vice versa,
+  // because we end up with both libart and libartd in the same address space!
 #ifndef NDEBUG
   const char* suffix = "d";
 #else
   const char* suffix = "";
 #endif
-  std::string name(StringPrintf("art%s-compiler-%s", suffix, instruction_set_name.c_str()));
-  return StringPrintf(OS_SHARED_LIB_FORMAT_STR, name.c_str());
+
+  // Work out the filename for the compiler library.
+  std::string library_name(StringPrintf("art%s-compiler-%s", suffix, instruction_set_name.c_str()));
+  std::string filename(StringPrintf(OS_SHARED_LIB_FORMAT_STR, library_name.c_str()));
+
+#if defined(__APPLE__)
+  // On Linux, dex2oat will have been built with an RPATH of $ORIGIN/../lib, so dlopen(3) will find
+  // the .so by itself. On Mac OS, there isn't really an equivalent, so we have to manually do the
+  // same work.
+  std::vector<char> executable_path(1);
+  uint32_t executable_path_length = 0;
+  _NSGetExecutablePath(&executable_path[0], &executable_path_length);
+  while (_NSGetExecutablePath(&executable_path[0], &executable_path_length) == -1) {
+    executable_path.resize(executable_path_length);
+  }
+
+  executable_path.resize(executable_path.size() - 1); // Strip trailing NUL.
+  std::string path(&executable_path[0]);
+
+  // Strip the "/dex2oat".
+  size_t last_slash = path.find_last_of('/');
+  CHECK_NE(last_slash, std::string::npos) << path;
+  path.resize(last_slash);
+
+  // Strip the "/bin".
+  last_slash = path.find_last_of('/');
+  path.resize(last_slash);
+
+  filename = path + "/lib/" + filename;
+#endif
+  return filename;
 }
 
 template<typename Fn>
@@ -230,7 +267,7 @@
   if (fn == NULL) {
     LOG(FATAL) << "Couldn't find \"" << name << "\" in compiler library " << compiler_so_name << ": " << dlerror();
   }
-  VLOG(compiler) << "Found \"" << name << "\") at " << reinterpret_cast<void*>(fn);
+  VLOG(compiler) << "Found \"" << name << "\" at " << reinterpret_cast<void*>(fn);
   return fn;
 }