diff options
author | 2022-12-07 19:22:43 +0000 | |
---|---|---|
committer | 2022-12-08 16:36:50 +0000 | |
commit | d2d10628dc0f947219c6b63972a53d45e334f8d6 (patch) | |
tree | f407ac1038c708a365f619905c474ca9e9897b2d | |
parent | 849d09a81907f16d8ccc6019b8baf86a304b730c (diff) |
Update loop information correctly in MaybeAddExtraGotoBlocks
There are cases in which we have a
Return->TryBoundary kind:exit->Exit
chain inside of a loop, and that said TryBoundary has loop
information. Set that information in the new goto block.
Bug: 261731237
Fixes: 261731237
Test: dex2oat compiling the apps in the bug
Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I224d6cb449d1a7a1a987f4e9022098f84ae4fba2
5 files changed, 72 insertions, 6 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 897d8b7015..c9609e0bda 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -124,12 +124,9 @@ void HGraphBuilder::MaybeAddExtraGotoBlocks() { if (NeedsExtraGotoBlock(predecessor)) { HBasicBlock* new_goto = graph_->SplitEdgeAndUpdateRPO(predecessor, exit); new_goto->AddInstruction(new (graph_->GetAllocator()) HGoto(predecessor->GetDexPc())); - - // No need to update loop info of the new block. - DCHECK(!predecessor->IsInLoop()) - << " we should only add the extra Goto blocks for Return/ReturnVoid->TryBoundary->Exit " - << "chains. In those chains, the TryBoundary of kind:exit should never be a part of a " - << "loop"; + if (predecessor->IsInLoop()) { + new_goto->SetLoopInformation(predecessor->GetLoopInformation()); + } // Update domination chain if (!predecessor->GetDominatedBlocks().empty()) { diff --git a/test/2249-checker-return-try-boundary-exit-in-loop/expected-stderr.txt b/test/2249-checker-return-try-boundary-exit-in-loop/expected-stderr.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/2249-checker-return-try-boundary-exit-in-loop/expected-stderr.txt diff --git a/test/2249-checker-return-try-boundary-exit-in-loop/expected-stdout.txt b/test/2249-checker-return-try-boundary-exit-in-loop/expected-stdout.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/2249-checker-return-try-boundary-exit-in-loop/expected-stdout.txt diff --git a/test/2249-checker-return-try-boundary-exit-in-loop/info.txt b/test/2249-checker-return-try-boundary-exit-in-loop/info.txt new file mode 100644 index 0000000000..db79b1299b --- /dev/null +++ b/test/2249-checker-return-try-boundary-exit-in-loop/info.txt @@ -0,0 +1,3 @@ +Tests that there is a case in which we have a + Return->TryBoundary kind:exit->Exit +chain inside of a loop, and that said TryBoundary has loop information. diff --git a/test/2249-checker-return-try-boundary-exit-in-loop/src/Main.java b/test/2249-checker-return-try-boundary-exit-in-loop/src/Main.java new file mode 100644 index 0000000000..070cd9f2f9 --- /dev/null +++ b/test/2249-checker-return-try-boundary-exit-in-loop/src/Main.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +public class Main { + public static void main(String[] args) throws Exception { + assertNotNull($noinline$testReturnTryBoundaryExitInLoop(new Object())); + } + + public static void assertNotNull(Object o) { + if (o == null) { + throw new Error("Expected not null!"); + } + } + + // Simple method to have a call inside of the synchronized block. + private static Object $noinline$call() { + return new Object(); + } + + // Consistency check: Three try boundary kind:exit. One for the explicit try catch, and two for + // the synchronized block (normal, and exceptional path). + + /// CHECK-START: java.lang.Object Main.$inline$inner(java.lang.Object) builder (after) + /// CHECK: TryBoundary kind:exit + /// CHECK: TryBoundary kind:exit + /// CHECK: TryBoundary kind:exit + /// CHECK-NOT: TryBoundary kind:exit + + /// CHECK-START: java.lang.Object Main.$inline$inner(java.lang.Object) builder (after) + /// CHECK: Return loop:B2 + + /// CHECK-START: java.lang.Object Main.$inline$inner(java.lang.Object) builder (after) + /// CHECK: TryBoundary kind:exit loop:B2 + /// CHECK: TryBoundary kind:exit loop:B2 + /// CHECK: TryBoundary kind:exit loop:B2 + private static Object $inline$inner(Object o) { + for (int i = 0; i < 4; i++) { + try { + synchronized (o) { + return $noinline$call(); + } + } catch (Error e) { + continue; + } + } + return null; + } + + // Simple outer to inline `inner`. + private static Object $noinline$testReturnTryBoundaryExitInLoop(Object o) { + return $inline$inner(o); + } +} |