Make InvokeInterfaceTrampoline check methods

InvokeInterfaceTrampoline was causing problems by looking into the
ImtConflictTable of non-imt-conflict-methods. This makes it check for
that before doing so.

Bug: 27931085

Change-Id: I993178a371f8f46535a752e5c4d46d74777cefaf
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 35f2102..7375656 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -2166,9 +2166,13 @@
     uint32_t imt_index = interface_method->GetDexMethodIndex();
     ArtMethod* conflict_method = cls->GetEmbeddedImTableEntry(
         imt_index % mirror::Class::kImtSize, sizeof(void*));
-    DCHECK(conflict_method->IsRuntimeMethod()) << PrettyMethod(conflict_method);
-    ImtConflictTable* current_table = conflict_method->GetImtConflictTable(sizeof(void*));
-    method = current_table->Lookup(interface_method);
+    if (LIKELY(conflict_method->IsRuntimeMethod())) {
+      ImtConflictTable* current_table = conflict_method->GetImtConflictTable(sizeof(void*));
+      method = current_table->Lookup(interface_method);
+    } else {
+      // It seems we aren't really a conflict method!
+      method = cls->FindVirtualMethodForInterface(interface_method, sizeof(void*));
+    }
     if (method != nullptr) {
       return GetTwoWordSuccessValue(
           reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode()),
@@ -2214,39 +2218,41 @@
   uint32_t imt_index = interface_method->GetDexMethodIndex();
   ArtMethod* conflict_method = cls->GetEmbeddedImTableEntry(
       imt_index % mirror::Class::kImtSize, sizeof(void*));
-  ImtConflictTable* current_table = conflict_method->GetImtConflictTable(sizeof(void*));
-  Runtime* runtime = Runtime::Current();
-  LinearAlloc* linear_alloc = (cls->GetClassLoader() == nullptr)
-      ? runtime->GetLinearAlloc()
-      : cls->GetClassLoader()->GetAllocator();
-  bool is_new_entry = (conflict_method == runtime->GetImtConflictMethod());
+  if (conflict_method->IsRuntimeMethod()) {
+    ImtConflictTable* current_table = conflict_method->GetImtConflictTable(sizeof(void*));
+    Runtime* runtime = Runtime::Current();
+    LinearAlloc* linear_alloc = (cls->GetClassLoader() == nullptr)
+        ? runtime->GetLinearAlloc()
+        : cls->GetClassLoader()->GetAllocator();
+    bool is_new_entry = (conflict_method == runtime->GetImtConflictMethod());
 
-  // Create a new entry if the existing one is the shared conflict method.
-  ArtMethod* new_conflict_method = is_new_entry
-      ? runtime->CreateImtConflictMethod(linear_alloc)
-      : conflict_method;
+    // Create a new entry if the existing one is the shared conflict method.
+    ArtMethod* new_conflict_method = is_new_entry
+        ? runtime->CreateImtConflictMethod(linear_alloc)
+        : conflict_method;
 
-  // Allocate a new table. Note that we will leak this table at the next conflict,
-  // but that's a tradeoff compared to making the table fixed size.
-  void* data = linear_alloc->Alloc(
-      self, ImtConflictTable::ComputeSizeWithOneMoreEntry(current_table));
-  CHECK(data != nullptr) << "Out of memory";
-  ImtConflictTable* new_table = new (data) ImtConflictTable(
-      current_table, interface_method, method);
+    // Allocate a new table. Note that we will leak this table at the next conflict,
+    // but that's a tradeoff compared to making the table fixed size.
+    void* data = linear_alloc->Alloc(
+        self, ImtConflictTable::ComputeSizeWithOneMoreEntry(current_table));
+    CHECK(data != nullptr) << "Out of memory";
+    ImtConflictTable* new_table = new (data) ImtConflictTable(
+        current_table, interface_method, method);
 
-  // Do a fence to ensure threads see the data in the table before it is assigned
-  // to the conlict method.
-  // Note that there is a race in the presence of multiple threads and we may leak
-  // memory from the LinearAlloc, but that's a tradeoff compared to using
-  // atomic operations.
-  QuasiAtomic::ThreadFenceRelease();
-  new_conflict_method->SetImtConflictTable(new_table);
-  if (is_new_entry) {
-    // Update the IMT if we create a new conflict method. No fence needed here, as the
-    // data is consistent.
-    cls->SetEmbeddedImTableEntry(imt_index % mirror::Class::kImtSize,
-                                 new_conflict_method,
-                                 sizeof(void*));
+    // Do a fence to ensure threads see the data in the table before it is assigned
+    // to the conlict method.
+    // Note that there is a race in the presence of multiple threads and we may leak
+    // memory from the LinearAlloc, but that's a tradeoff compared to using
+    // atomic operations.
+    QuasiAtomic::ThreadFenceRelease();
+    new_conflict_method->SetImtConflictTable(new_table);
+    if (is_new_entry) {
+      // Update the IMT if we create a new conflict method. No fence needed here, as the
+      // data is consistent.
+      cls->SetEmbeddedImTableEntry(imt_index % mirror::Class::kImtSize,
+                                  new_conflict_method,
+                                  sizeof(void*));
+    }
   }
 
   const void* code = method->GetEntryPointFromQuickCompiledCode();