Add a test and CHECKs around the combination of CHA and default methods.

Test: 823-cha-inlining
Bug: 182538502
Change-Id: Ie3e0014804216802af0addf13751a8f89adbfdfa
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 96cb605..3e9969d 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1286,11 +1286,14 @@
         return false;
       }
 
-      if (method->IsDefault() && method->IsDefaultConflicting()) {
-        // Changing to invoke-virtual cannot be done on default conflict method
-        // since it's not in any vtable.
-        DCHECK(cha_devirtualize);
-        return false;
+      if (kIsDebugBuild && method->IsDefaultConflicting()) {
+        CHECK(!cha_devirtualize) << "CHA cannot have a default conflict method as target";
+        // Devirtualization by exact type/inline-cache always uses a method in the vtable,
+        // so it's OK to change this invoke into a HInvokeVirtual.
+        ObjPtr<mirror::Class> receiver_class = receiver_type.GetTypeHandle().Get();
+        CHECK(!receiver_class->IsInterface());
+        PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+        CHECK(method == receiver_class->GetVTableEntry(method->GetMethodIndex(), pointer_size));
       }
 
       uint32_t dex_method_index = FindMethodIndexIn(
@@ -1786,14 +1789,12 @@
 bool HInliner::CanInlineBody(const HGraph* callee_graph,
                              const HBasicBlock* target_block,
                              size_t* out_number_of_instructions) const {
-  const DexFile& callee_dex_file = callee_graph->GetDexFile();
   ArtMethod* const resolved_method = callee_graph->GetArtMethod();
-  const uint32_t method_index = resolved_method->GetMethodIndex();
 
   HBasicBlock* exit_block = callee_graph->GetExitBlock();
   if (exit_block == nullptr) {
     LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInfiniteLoop)
-        << "Method " << callee_dex_file.PrettyMethod(method_index)
+        << "Method " << resolved_method->PrettyMethod()
         << " could not be inlined because it has an infinite loop";
     return false;
   }
@@ -1804,21 +1805,21 @@
       if (target_block->IsTryBlock()) {
         // TODO(ngeoffray): Support adding HTryBoundary in Hgraph::InlineInto.
         LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatch)
-            << "Method " << callee_dex_file.PrettyMethod(method_index)
+            << "Method " << resolved_method->PrettyMethod()
             << " could not be inlined because one branch always throws and"
             << " caller is in a try/catch block";
         return false;
       } else if (graph_->GetExitBlock() == nullptr) {
         // TODO(ngeoffray): Support adding HExit in the caller graph.
         LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInfiniteLoop)
-            << "Method " << callee_dex_file.PrettyMethod(method_index)
+            << "Method " << resolved_method->PrettyMethod()
             << " could not be inlined because one branch always throws and"
             << " caller does not have an exit block";
         return false;
       } else if (graph_->HasIrreducibleLoops()) {
         // TODO(ngeoffray): Support re-computing loop information to graphs with
         // irreducible loops?
-        VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index)
+        VLOG(compiler) << "Method " << resolved_method->PrettyMethod()
                        << " could not be inlined because one branch always throws and"
                        << " caller has irreducible loops";
         return false;
@@ -1830,7 +1831,7 @@
 
   if (!has_one_return) {
     LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedAlwaysThrows)
-        << "Method " << callee_dex_file.PrettyMethod(method_index)
+        << "Method " << resolved_method->PrettyMethod()
         << " could not be inlined because it always throws";
     return false;
   }
@@ -1843,7 +1844,7 @@
         // Don't inline methods with irreducible loops, they could prevent some
         // optimizations to run.
         LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedIrreducibleLoop)
-            << "Method " << callee_dex_file.PrettyMethod(method_index)
+            << "Method " << resolved_method->PrettyMethod()
             << " could not be inlined because it contains an irreducible loop";
         return false;
       }
@@ -1852,7 +1853,7 @@
         // loop information to be computed incorrectly when updating after
         // inlining.
         LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedLoopWithoutExit)
-            << "Method " << callee_dex_file.PrettyMethod(method_index)
+            << "Method " << resolved_method->PrettyMethod()
             << " could not be inlined because it contains a loop with no exit";
         return false;
       }
@@ -1863,7 +1864,7 @@
          instr_it.Advance()) {
       if (++number_of_instructions >= inlining_budget_) {
         LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInstructionBudget)
-            << "Method " << callee_dex_file.PrettyMethod(method_index)
+            << "Method " << resolved_method->PrettyMethod()
             << " is not inlined because the outer method has reached"
             << " its instruction budget limit.";
         return false;
@@ -1872,7 +1873,7 @@
       if (current->NeedsEnvironment() &&
           (total_number_of_dex_registers_ >= kMaximumNumberOfCumulatedDexRegisters)) {
         LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedEnvironmentBudget)
-            << "Method " << callee_dex_file.PrettyMethod(method_index)
+            << "Method " << resolved_method->PrettyMethod()
             << " is not inlined because its caller has reached"
             << " its environment budget limit.";
         return false;
@@ -1882,7 +1883,7 @@
           !CanEncodeInlinedMethodInStackMap(*caller_compilation_unit_.GetDexFile(),
                                             resolved_method)) {
         LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedStackMaps)
-            << "Method " << callee_dex_file.PrettyMethod(method_index)
+            << "Method " << resolved_method->PrettyMethod()
             << " could not be inlined because " << current->DebugName()
             << " needs an environment, is in a different dex file"
             << ", and cannot be encoded in the stack maps.";
@@ -1895,7 +1896,7 @@
           current->IsUnresolvedInstanceFieldSet()) {
         // Entrypoint for unresolved fields does not handle inlined frames.
         LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedUnresolvedEntrypoint)
-            << "Method " << callee_dex_file.PrettyMethod(method_index)
+            << "Method " << resolved_method->PrettyMethod()
             << " could not be inlined because it is using an unresolved"
             << " entrypoint";
         return false;