Add seen-check in bridge method analyzer
Bug: b/307761442
Change-Id: If3ba849c073ad0d13e133b15ece7a531f8a82fa5
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/bridge/BridgeAnalyzer.java b/src/main/java/com/android/tools/r8/ir/optimize/info/bridge/BridgeAnalyzer.java
index 853c734..5c76c0f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/bridge/BridgeAnalyzer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/bridge/BridgeAnalyzer.java
@@ -24,6 +24,8 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.SetUtils;
+import java.util.Set;
public class BridgeAnalyzer {
@@ -36,12 +38,11 @@
InvokeMethodWithReceiver uniqueInvoke = null;
CheckCast uniqueReturnCast = null;
InstructionListIterator instructionIterator = code.entryBlock().listIterator(code);
+ Set<BasicBlock> seenBlocks = null;
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
switch (instruction.opcode()) {
case ARGUMENT:
- break;
-
case ASSUME:
break;
@@ -84,6 +85,13 @@
if (targetBlock.hasCatchHandlers()) {
return failure();
}
+ if (seenBlocks == null) {
+ assert gotoInstruction.getBlock().isEntry();
+ seenBlocks = SetUtils.newIdentityHashSet(code.entryBlock());
+ }
+ if (!seenBlocks.add(targetBlock)) {
+ return failure();
+ }
instructionIterator = targetBlock.listIterator(code);
break;
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/InfiniteLoopTest.java b/src/test/java/com/android/tools/r8/ir/optimize/InfiniteLoopTest.java
new file mode 100644
index 0000000..595cb08
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/InfiniteLoopTest.java
@@ -0,0 +1,74 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.optimize;
+
+import com.android.tools.r8.AssumeMayHaveSideEffects;
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class InfiniteLoopTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void testD8Release() throws Exception {
+ parameters.assumeDexRuntime();
+ testForD8().addInnerClasses(getClass()).release().setMinApi(parameters).compile();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .enableSideEffectAnnotations()
+ .setMinApi(parameters)
+ .compile();
+ }
+
+ @NeverClassInline
+ static class Main {
+
+ public static void main(String[] args) {
+ new Main().loopDirect();
+ loopStatic();
+ new Main().loopVirtual();
+ }
+
+ @AssumeMayHaveSideEffects
+ @NeverInline
+ private void loopDirect() {
+ while (true) {}
+ }
+
+ @AssumeMayHaveSideEffects
+ @NeverInline
+ public static void loopStatic() {
+ while (true) {}
+ }
+
+ @AssumeMayHaveSideEffects
+ @NeverInline
+ public void loopVirtual() {
+ while (true) {}
+ }
+ }
+}