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/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,