Implement partial sharpening for LLVM.

Change-Id: I0c6953d6428edda71230c0088b9e0c9decada3b7
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 8e592fe..8d6b251 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -36,9 +36,12 @@
 #include <iomanip>
 
 #include <llvm/BasicBlock.h>
+#include <llvm/DerivedTypes.h>
 #include <llvm/Function.h>
 #include <llvm/GlobalVariable.h>
 #include <llvm/Intrinsics.h>
+#include <llvm/Module.h>
+#include <llvm/Type.h>
 
 namespace art {
 namespace compiler_llvm {
@@ -2806,7 +2809,7 @@
   // Compute invoke related information for compiler decision
   int vtable_idx = -1;
   uintptr_t direct_code = 0; // Currently unused
-  uintptr_t direct_method = 0; // Currently unused
+  uintptr_t direct_method = 0;
   bool is_fast_path = compiler_->
     ComputeInvokeInfo(callee_method_idx, oat_compilation_unit_,
                       invoke_type, vtable_idx, direct_code, direct_method);
@@ -2834,8 +2837,15 @@
     switch (invoke_type) {
     case kStatic:
     case kDirect:
-      callee_method_object_addr =
-        EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
+      if (direct_method != 0u &&
+          direct_method != static_cast<uintptr_t>(-1)) {
+        callee_method_object_addr =
+          EmitLoadSDCalleeDirectMethodObjectAddr(callee_method_idx,
+                                                 direct_method);
+      } else {
+        callee_method_object_addr =
+          EmitLoadSDCalleeMethodObjectAddr(callee_method_idx);
+      }
       break;
 
     case kVirtual:
@@ -2982,6 +2992,27 @@
 
 
 llvm::Value* MethodCompiler::
+EmitLoadSDCalleeDirectMethodObjectAddr(uint32_t callee_method_idx,
+                                       uintptr_t direct_method) {
+  std::string direct_method_name(
+    StringPrintf("ArtMethodObject_%08lx",
+                 static_cast<unsigned long>(direct_method)));
+
+  llvm::GlobalVariable* direct_method_addr =
+    module_->getGlobalVariable(direct_method_name);
+
+  if (direct_method_addr == NULL) {
+    direct_method_addr =
+      new llvm::GlobalVariable(*module_, irb_.getJObjectTy()->getElementType(),
+                               false, llvm::GlobalVariable::ExternalLinkage,
+                               NULL, direct_method_name);
+  }
+
+  return direct_method_addr;
+}
+
+
+llvm::Value* MethodCompiler::
 EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx) {
   llvm::Value* callee_method_object_field_addr =
     EmitLoadDexCacheResolvedMethodFieldAddr(callee_method_idx);
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 7dded33..84c55d6 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -215,6 +215,9 @@
 
   llvm::Value* EmitLoadSDCalleeMethodObjectAddr(uint32_t callee_method_idx);
 
+  llvm::Value* EmitLoadSDCalleeDirectMethodObjectAddr(uint32_t callee_method_idx,
+                                                      uintptr_t direct_method);
+
   llvm::Value* EmitLoadVirtualCalleeMethodObjectAddr(int vtable_idx,
                                                      llvm::Value* this_addr);
 
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index fce0f41..1ebbef9 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -797,6 +797,15 @@
     }
   }
 
+  // Fixed method object address
+  const char method_object_prefix[] = "ArtMethodObject_";
+  const size_t method_object_prefix_len = sizeof(method_object_prefix) - 1;
+  if (strncmp(name, method_object_prefix, method_object_prefix_len) == 0) {
+    const char* addr_str = name + method_object_prefix_len;
+    unsigned long addr_int = strtoul(addr_str, NULL, 16);
+    return reinterpret_cast<void*>(addr_int);
+  }
+
   LOG(FATAL) << "Error: Can't find symbol " << name;
   return 0;
 }