Revert "Revert "Inline and optimize interface calls.""

This reverts commit 19dc255bf94a4229de8627a2079ee6f0e9005e2d.

Change-Id: Ifc3a92280878d4db1b460d486137497b3456beae
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index c67b2d5..f9e78b0 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -187,12 +187,12 @@
 
 static uint32_t FindMethodIndexIn(ArtMethod* method,
                                   const DexFile& dex_file,
-                                  uint32_t referrer_index)
+                                  uint32_t name_and_signature_index)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   if (IsSameDexFile(*method->GetDexFile(), dex_file)) {
     return method->GetDexMethodIndex();
   } else {
-    return method->FindDexMethodIndexInOtherDexFile(dex_file, referrer_index);
+    return method->FindDexMethodIndexInOtherDexFile(dex_file, name_and_signature_index);
   }
 }
 
@@ -750,7 +750,40 @@
 bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* method, bool do_rtp) {
   HInstruction* return_replacement = nullptr;
   if (!TryBuildAndInline(invoke_instruction, method, &return_replacement)) {
-    return false;
+    if (invoke_instruction->IsInvokeInterface()) {
+      // Turn an invoke-interface into an invoke-virtual. An invoke-virtual is always
+      // better than an invoke-interface because:
+      // 1) In the best case, the interface call has one more indirection (to fetch the IMT).
+      // 2) We will not go to the conflict trampoline with an invoke-virtual.
+      // TODO: Consider sharpening once it is not dependent on the compiler driver.
+      const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
+      uint32_t method_index = FindMethodIndexIn(
+          method, caller_dex_file, invoke_instruction->GetDexMethodIndex());
+      if (method_index == DexFile::kDexNoIndex) {
+        return false;
+      }
+      HInvokeVirtual* new_invoke = new (graph_->GetArena()) HInvokeVirtual(
+          graph_->GetArena(),
+          invoke_instruction->GetNumberOfArguments(),
+          invoke_instruction->GetType(),
+          invoke_instruction->GetDexPc(),
+          method_index,
+          method->GetMethodIndex());
+      HInputsRef inputs = invoke_instruction->GetInputs();
+      for (size_t index = 0; index != inputs.size(); ++index) {
+        new_invoke->SetArgumentAt(index, inputs[index]);
+      }
+      invoke_instruction->GetBlock()->InsertInstructionBefore(new_invoke, invoke_instruction);
+      new_invoke->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
+      if (invoke_instruction->GetType() == Primitive::kPrimNot) {
+        new_invoke->SetReferenceTypeInfo(invoke_instruction->GetReferenceTypeInfo());
+      }
+      return_replacement = new_invoke;
+    } else {
+      // TODO: Consider sharpening an invoke virtual once it is not dependent on the
+      // compiler driver.
+      return false;
+    }
   }
   if (return_replacement != nullptr) {
     invoke_instruction->ReplaceWith(return_replacement);
@@ -1239,14 +1272,6 @@
         return false;
       }
 
-      if (current->IsInvokeInterface()) {
-        // Disable inlining of interface calls. The cost in case of entering the
-        // resolution conflict is currently too high.
-        VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
-                       << " could not be inlined because it has an interface call.";
-        return false;
-      }
-
       if (!same_dex_file && current->NeedsEnvironment()) {
         VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                        << " could not be inlined because " << current->DebugName()