summaryrefslogtreecommitdiff
path: root/compiler/optimizing
diff options
context:
space:
mode:
author Santiago Aboy Solanes <solanes@google.com> 2022-12-08 15:15:17 +0000
committer Santiago Aboy Solanes <solanes@google.com> 2022-12-12 14:14:57 +0000
commitb9df137d1dbdab1fdca13bb459705b6603e9328b (patch)
tree6aa74b24b130c96cb3216cbf7ff5a5bfba67186b /compiler/optimizing
parent5a454c6ed6bb692f5881a68ea9177d50e735b101 (diff)
Allow to inline invokes that sometimes throw into try blocks
We supported inlining these invokes into regular blocks, and we can extend that support for try blocks too. Bug: 227283224 Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b Change-Id: Id45a009adabc610f4bf7a0457880ad7b9d772178
Diffstat (limited to 'compiler/optimizing')
-rw-r--r--compiler/optimizing/inliner.cc10
-rw-r--r--compiler/optimizing/nodes.cc40
-rw-r--r--compiler/optimizing/optimizing_compiler_stats.h1
3 files changed, 32 insertions, 19 deletions
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 3e3b2d46ca..1f7ef2cf4c 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1883,7 +1883,6 @@ bool HInliner::CanInlineBody(const HGraph* callee_graph,
HInvoke* invoke,
size_t* out_number_of_instructions,
bool is_speculative) const {
- const HBasicBlock* target_block = invoke->GetBlock();
ArtMethod* const resolved_method = callee_graph->GetArtMethod();
HBasicBlock* exit_block = callee_graph->GetExitBlock();
@@ -1905,14 +1904,7 @@ bool HInliner::CanInlineBody(const HGraph* callee_graph,
}
if (last_instruction->IsThrow()) {
- if (target_block->IsTryBlock()) {
- // TODO(ngeoffray): Support adding HTryBoundary in Hgraph::InlineInto.
- LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedTryCatchCaller)
- << "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) {
+ if (graph_->GetExitBlock() == nullptr) {
// TODO(ngeoffray): Support adding HExit in the caller graph.
LOG_FAIL(stats_, MethodCompilationStat::kNotInlinedInfiniteLoop)
<< "Method " << resolved_method->PrettyMethod()
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 270bb4fb86..85d0fe7245 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2919,23 +2919,45 @@ HInstruction* HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) {
DCHECK_IMPLIES(saw_goto, last->IsReturnVoid() || last->IsReturn());
if (last->IsThrow()) {
- DCHECK(!at->IsTryBlock());
// The chain `Throw->TryBoundary` is allowed but not `Throw->TryBoundary->Goto` since that
// would mean a Goto will point to exit after ReplaceSuccessor.
DCHECK(!saw_goto);
- // We either have `Throw->TryBoundary` or `Throw`. We want to point the whole chain to the
- // exit, so we recompute `predecessor`
- predecessor = to->GetPredecessors()[pred];
- predecessor->ReplaceSuccessor(to, outer_graph->GetExitBlock());
+ if (at->IsTryBlock()) {
+ DCHECK(!saw_try_boundary) << "We don't support inlining of try blocks into try blocks.";
+ // Create a TryBoundary of kind:exit and point it to the Exit block.
+ HBasicBlock* new_block = outer_graph->SplitEdge(predecessor, to);
+ new_block->AddInstruction(
+ new (allocator) HTryBoundary(HTryBoundary::BoundaryKind::kExit, last->GetDexPc()));
+ new_block->ReplaceSuccessor(to, outer_graph->GetExitBlock());
+
+ // Copy information from the predecessor.
+ new_block->SetLoopInformation(predecessor->GetLoopInformation());
+ TryCatchInformation* try_catch_info = predecessor->GetTryCatchInformation();
+ new_block->SetTryCatchInformation(try_catch_info);
+ for (HBasicBlock* xhandler :
+ try_catch_info->GetTryEntry().GetBlock()->GetExceptionalSuccessors()) {
+ new_block->AddSuccessor(xhandler);
+ }
+ DCHECK(try_catch_info->GetTryEntry().HasSameExceptionHandlersAs(
+ *new_block->GetLastInstruction()->AsTryBoundary()));
+ } else {
+ // We either have `Throw->TryBoundary` or `Throw`. We want to point the whole chain to the
+ // exit, so we recompute `predecessor`
+ predecessor = to->GetPredecessors()[pred];
+ predecessor->ReplaceSuccessor(to, outer_graph->GetExitBlock());
+ }
+
--pred;
// We need to re-run dominance information, as the exit block now has
- // a new dominator.
+ // a new predecessor and potential new dominator.
+ // TODO(solanes): See if it's worth it to hand-modify the domination chain instead of
+ // rerunning the dominance for the whole graph.
rerun_dominance = true;
if (predecessor->GetLoopInformation() != nullptr) {
- // The exit block and blocks post dominated by the exit block do not belong
- // to any loop. Because we do not compute the post dominators, we need to re-run
- // loop analysis to get the loop information correct.
+ // The loop information might have changed e.g. `predecessor` might not be in a loop
+ // anymore. We only do this if `predecessor` has loop information as it is impossible for
+ // predecessor to end up in a loop if it wasn't in one before.
rerun_loop_analysis = true;
}
} else {
diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h
index 02f1fe9d0d..c741b02751 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -95,7 +95,6 @@ enum class MethodCompilationStat {
kNotInlinedIrreducibleLoop,
kNotInlinedAlwaysThrows,
kNotInlinedInfiniteLoop,
- kNotInlinedTryCatchCaller,
kNotInlinedTryCatchCallee,
kNotInlinedTryCatchDisabled,
kNotInlinedRegisterAllocator,