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;