Fast path interface dispatch.

Interface dispatch when the method we're dispatching against is known
currently goes slow path. This change makes the load of the interface
method either a load of a constant or from the resolve methods table. It
also makes the null check on the "this" pointer inline.

Change-Id: I69571a062d3d693bee2dec6e46a456e0f74411cd
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index ccc2a83..cf06c80 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -650,38 +650,35 @@
   }
   // Push code and method literals, record offsets for the compiler to patch.
   dataLIR = cUnit->codeLiteralList;
-  if (dataLIR != NULL) {
-    while (dataLIR != NULL) {
-      uint32_t target = dataLIR->operands[0];
-      cUnit->compiler->AddCodePatch(cUnit->dex_file,
+  while (dataLIR != NULL) {
+    uint32_t target = dataLIR->operands[0];
+    cUnit->compiler->AddCodePatch(cUnit->dex_file,
+                                  cUnit->method_idx,
+                                  cUnit->invoke_type,
+                                  target,
+                                  static_cast<InvokeType>(dataLIR->operands[1]),
+                                  cUnit->codeBuffer.size());
+    const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
+    // unique based on target to ensure code deduplication works
+    uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
+    pushWord(cUnit->codeBuffer, unique_patch_value);
+    dataLIR = NEXT_LIR(dataLIR);
+  }
+  dataLIR = cUnit->methodLiteralList;
+  while (dataLIR != NULL) {
+    uint32_t target = dataLIR->operands[0];
+    cUnit->compiler->AddMethodPatch(cUnit->dex_file,
                                     cUnit->method_idx,
                                     cUnit->invoke_type,
                                     target,
                                     static_cast<InvokeType>(dataLIR->operands[1]),
                                     cUnit->codeBuffer.size());
-      const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
-      // unique based on target to ensure code deduplication works
-      uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
-      pushWord(cUnit->codeBuffer, unique_patch_value);
-      dataLIR = NEXT_LIR(dataLIR);
-    }
-    dataLIR = cUnit->methodLiteralList;
-    while (dataLIR != NULL) {
-      uint32_t target = dataLIR->operands[0];
-      cUnit->compiler->AddMethodPatch(cUnit->dex_file,
-                                      cUnit->method_idx,
-                                      cUnit->invoke_type,
-                                      target,
-                                      static_cast<InvokeType>(dataLIR->operands[1]),
-                                      cUnit->codeBuffer.size());
-      const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
-      // unique based on target to ensure code deduplication works
-      uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
-      pushWord(cUnit->codeBuffer, unique_patch_value);
-      dataLIR = NEXT_LIR(dataLIR);
-    }
+    const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
+    // unique based on target to ensure code deduplication works
+    uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
+    pushWord(cUnit->codeBuffer, unique_patch_value);
+    dataLIR = NEXT_LIR(dataLIR);
   }
-
 }
 
 /* Write the switch tables to the output stream */
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index 3cc7c93..0208a4a 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -188,7 +188,7 @@
   } else {
     switch (state) {
     case 0:  // Get the current Method* [sets rARG0]
-      // TUNING: we can save a reg copy if Method* has been promoted
+      // TUNING: we can save a reg copy if Method* has been promoted.
       loadCurrMethodDirect(cUnit, rARG0);
       break;
     case 1:  // Get method->dex_cache_resolved_methods_
@@ -247,16 +247,16 @@
                   int state, uint32_t dexIdx, uint32_t methodIdx,
                   uintptr_t unused, uintptr_t unused2, InvokeType unused3)
 {
-  RegLocation rlArg;
   /*
    * This is the fast path in which the target virtual method is
    * fully resolved at compile time.
    */
   switch (state) {
-    case 0:  // Get "this" [set rARG1]
-      rlArg = info->args[0];
+    case 0: {  // Get "this" [set rARG1]
+      RegLocation  rlArg = info->args[0];
       loadValueDirectFixed(cUnit, rlArg, rARG1);
       break;
+    }
     case 1: // Is "this" null? [use rARG1]
       genNullCheck(cUnit, info->args[0].sRegLow, rARG1, info->optFlags);
       // get this->klass_ [use rARG1, set rINVOKE_TGT]
@@ -283,6 +283,76 @@
   return state + 1;
 }
 
+/*
+ * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
+ * which will locate the target and continue on via a tail call.
+ */
+int nextInterfaceCallInsn(CompilationUnit* cUnit, CallInfo* info, int state,
+                          uint32_t dexIdx, uint32_t unused, uintptr_t unused2,
+                          uintptr_t directMethod, InvokeType unused4)
+{
+#if !defined(TARGET_ARM)
+  directMethod = 0;
+#endif
+#if !defined(TARGET_X86)
+  int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
+#endif
+
+  if (directMethod != 0) {
+    switch (state) {
+      case 0:  // Load the trampoline target [sets rINVOKE_TGT].
+#if !defined(TARGET_X86)
+        loadWordDisp(cUnit, rSELF, trampoline, rINVOKE_TGT);
+#endif
+        // Get the interface Method* [sets rARG0]
+        if (directMethod != (uintptr_t)-1) {
+          loadConstant(cUnit, rARG0, directMethod);
+        } else {
+          LIR* dataTarget = scanLiteralPool(cUnit->methodLiteralList, dexIdx, 0);
+          if (dataTarget == NULL) {
+            dataTarget = addWordData(cUnit, &cUnit->methodLiteralList, dexIdx);
+            dataTarget->operands[1] = kInterface;
+          }
+#if defined(TARGET_ARM)
+          LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
+                                  kThumb2LdrPcRel12, rARG0, 0, 0, 0, 0,
+                                  dataTarget);
+          oatAppendLIR(cUnit, loadPcRel);
+#else
+          UNIMPLEMENTED(FATAL) << (void*)dataTarget;
+#endif
+        }
+        break;
+      default:
+        return -1;
+    }
+  } else {
+    switch (state) {
+      case 0:
+        // Get the current Method* [sets rARG0] - TUNING: remove copy of method if it is promoted.
+        loadCurrMethodDirect(cUnit, rARG0);
+        // Load the trampoline target [sets rINVOKE_TGT].
+#if !defined(TARGET_X86)
+        loadWordDisp(cUnit, rSELF, trampoline, rINVOKE_TGT);
+#endif
+        break;
+    case 1:  // Get method->dex_cache_resolved_methods_ [set/use rARG0]
+      loadWordDisp(cUnit, rARG0,
+                   AbstractMethod::DexCacheResolvedMethodsOffset().Int32Value(),
+                   rARG0);
+      break;
+    case 2:  // Grab target method* [set/use rARG0]
+      loadWordDisp(cUnit, rARG0,
+                   Array::DataOffset(sizeof(Object*)).Int32Value() + dexIdx * 4,
+                   rARG0);
+      break;
+    default:
+      return -1;
+    }
+  }
+  return state + 1;
+}
+
 int nextInvokeInsnSP(CompilationUnit* cUnit, CallInfo* info, int trampoline,
                      int state, uint32_t dexIdx, uint32_t methodIdx)
 {
@@ -335,18 +405,6 @@
   return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
 }
 
-/*
- * All invoke-interface calls bounce off of art_invoke_interface_trampoline,
- * which will locate the target and continue on via a tail call.
- */
-int nextInterfaceCallInsn(CompilationUnit* cUnit, CallInfo* info, int state,
-                          uint32_t dexIdx, uint32_t unused, uintptr_t unused2,
-                          uintptr_t unused3, InvokeType unused4)
-{
-  int trampoline = ENTRYPOINT_OFFSET(pInvokeInterfaceTrampoline);
-  return nextInvokeInsnSP(cUnit, info, trampoline, state, dexIdx, 0);
-}
-
 int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit,
                                          CallInfo* info, int state,
                                          uint32_t dexIdx, uint32_t unused,
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 3a80d10..3321c33 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -83,8 +83,11 @@
                                        directMethod)
     && !SLOW_INVOKE_PATH;
   if (info->type == kInterface) {
+    if (fastPath) {
+      pNullCk = &nullCk;
+    }
     nextCallInsn = fastPath ? nextInterfaceCallInsn
-        : nextInterfaceCallInsnWithAccessCheck;
+                            : nextInterfaceCallInsnWithAccessCheck;
     skipThis = false;
   } else if (info->type == kDirect) {
     if (fastPath) {