Add debug tests for reordering of blocks.
These tests witness current errors in the debug info and are ignored.
R=ager, shertz
Bug: 65618023
Change-Id: Id189ec7d96b27150ce382e993bec85a3927ad2d1
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 77f1a16..f2dfce4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -397,6 +397,10 @@
// Package up the IR code.
IRCode ir = new IRCode(method, blocks, normalExitBlock, valueNumberGenerator);
+ if (options.testing.invertConditionals) {
+ invertConditionalsForTesting(ir);
+ }
+
// Create block order and make sure that all blocks are immediately followed by their
// fallthrough block if any.
ir.traceBlocks();
@@ -2057,41 +2061,6 @@
blocks.addAll(newBlocks);
}
- /**
- * Trace blocks and attempt to put fallthrough blocks immediately after the block that
- * falls through. When we fail to do that we create a new fallthrough block with an explicit
- * goto to the actual fallthrough block.
- */
- private void traceBlocks(IRCode code) {
- BasicBlock[] sorted = code.topologicallySortedBlocks();
- code.clearMarks();
- int nextBlockNumber = blocks.size();
- LinkedList<BasicBlock> tracedBlocks = new LinkedList<>();
- for (BasicBlock block : sorted) {
- if (!block.isMarked()) {
- block.mark();
- tracedBlocks.add(block);
- BasicBlock current = block;
- BasicBlock fallthrough = block.exit().fallthroughBlock();
- while (fallthrough != null && !fallthrough.isMarked()) {
- fallthrough.mark();
- tracedBlocks.add(fallthrough);
- current = fallthrough;
- fallthrough = fallthrough.exit().fallthroughBlock();
- }
- if (fallthrough != null) {
- BasicBlock newFallthrough = BasicBlock.createGotoBlock(fallthrough, nextBlockNumber++);
- current.exit().setFallthroughBlock(newFallthrough);
- newFallthrough.getPredecessors().add(current);
- fallthrough.replacePredecessor(current, newFallthrough);
- newFallthrough.mark();
- tracedBlocks.add(newFallthrough);
- }
- }
- }
- code.blocks = tracedBlocks;
- }
-
// Other stuff.
boolean isIntegerType(NumericType type) {
@@ -2102,6 +2071,14 @@
return type != NumericType.FLOAT && type != NumericType.DOUBLE && type != NumericType.LONG;
}
+ private static void invertConditionalsForTesting(IRCode code) {
+ for (BasicBlock block : code.blocks) {
+ if (block.exit().isIf()) {
+ block.exit().asIf().invert();
+ }
+ }
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
@@ -2113,3 +2090,4 @@
return builder.toString();
}
}
+
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 95762e4..875c2ef 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -204,6 +204,8 @@
public Function<Set<DexEncodedMethod>, Set<DexEncodedMethod>> irOrdering =
Function.identity();
+
+ public boolean invertConditionals = false;
}
public static class AttributeRemovalOptions {
diff --git a/src/test/debugTestResources/BlockReordering.java b/src/test/debugTestResources/BlockReordering.java
new file mode 100644
index 0000000..ebc6610
--- /dev/null
+++ b/src/test/debugTestResources/BlockReordering.java
@@ -0,0 +1,47 @@
+// Copyright (c) 2017, 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.
+
+public class BlockReordering {
+
+ public static int conditionalReturn(boolean test) {
+ if (test) return 1;
+ else return 2;
+ }
+
+ public static int callConditionalReturn(boolean test) {
+ return conditionalReturn(test);
+ }
+
+ public static int invertConditionalReturn(boolean test) {
+ if (!test) return 1;
+ else return 2;
+ }
+
+ public static int callInvertConditionalReturn(boolean test) {
+ return invertConditionalReturn(test);
+ }
+
+ public static int fallthroughReturn(int x) {
+ if (x <= 5) if (x <= 4) if (x <= 3) if (x <= 2) if (x <= 1) return x + 1;
+ else return x + 2;
+ else return x + 3;
+ else return x + 4;
+ else return x + 5;
+ return x;
+ }
+
+ public static int callFallthroughReturn(int x) {
+ return fallthroughReturn(x);
+ }
+
+ public static void main(String[] args) {
+ System.out.println(callConditionalReturn(true));
+ System.out.println(callConditionalReturn(false));
+ System.out.println(callInvertConditionalReturn(true));
+ System.out.println(callInvertConditionalReturn(false));
+ System.out.println(callFallthroughReturn(1));
+ System.out.println(callFallthroughReturn(5));
+ System.out.println(callFallthroughReturn(6));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/BlockReorderingTest.java b/src/test/java/com/android/tools/r8/debug/BlockReorderingTest.java
new file mode 100644
index 0000000..3c40b74
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debug/BlockReorderingTest.java
@@ -0,0 +1,76 @@
+// Copyright (c) 2017, 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.debug;
+
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+/**
+ * Test single stepping behaviour across reordered blocks.
+ */
+public class BlockReorderingTest extends DebugTestBase {
+
+ public static final String CLASS = "BlockReordering";
+ public static final String FILE = "BlockReordering.java";
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ // Force inversion of all conditionals to reliably construct a regression test for incorrect
+ // line information when reording blocks.
+ setUp(options -> options.testing.invertConditionals = true);
+ }
+
+ @Test
+ @Ignore("b/65618023")
+ public void testConditionalReturn() throws Throwable {
+ final String method = "conditionalReturn";
+ runDebugTest(CLASS,
+ breakpoint(CLASS, method),
+ run(),
+ checkLine(FILE, 8), stepOver(),
+ checkLine(FILE, 13),
+ run(),
+ checkLine(FILE, 8), stepOver(),
+ checkLine(FILE, 9), stepOver(),
+ checkLine(FILE, 13),
+ run());
+ }
+
+ @Test
+ @Ignore("b/65618023")
+ public void testInvertConditionalReturn() throws Throwable {
+ final String method = "invertConditionalReturn";
+ runDebugTest(CLASS,
+ breakpoint(CLASS, method),
+ run(),
+ checkLine(FILE, 17), stepOver(),
+ checkLine(FILE, 18), stepOver(),
+ checkLine(FILE, 22),
+ run(),
+ checkLine(FILE, 17), stepOver(),
+ checkLine(FILE, 22),
+ run());
+ }
+
+ @Test
+ @Ignore("b/65618023")
+ public void testFallthroughReturn() throws Throwable {
+ final String method = "fallthroughReturn";
+ runDebugTest(CLASS,
+ breakpoint(CLASS, method),
+ run(),
+ checkLine(FILE, 26), stepOver(),
+ checkLine(FILE, 35),
+ run(),
+ checkLine(FILE, 26), stepOver(),
+ checkLine(FILE, 30), stepOver(),
+ checkLine(FILE, 35),
+ run(),
+ checkLine(FILE, 26), stepOver(),
+ checkLine(FILE, 31), stepOver(),
+ checkLine(FILE, 35),
+ run());
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
index f655dd7..65fe4aa 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -112,14 +112,21 @@
@BeforeClass
public static void setUp() throws Exception {
+ setUp(null);
+ }
+
+ protected static void setUp(Consumer<InternalOptions> optionsConsumer) throws Exception {
// Convert jar to dex with d8 with debug info
jdwpDexD8 = compileToDex(null, JDWP_JAR);
- debuggeeDexD8 = compileToDex(null, DEBUGGEE_JAR);
+ debuggeeDexD8 = compileToDex(optionsConsumer, DEBUGGEE_JAR);
debuggeeJava8DexD8 = compileToDex(options -> {
// Enable desugaring for preN runtimes
options.interfaceMethodDesugaring = OffOrAuto.Auto;
+ if (optionsConsumer != null) {
+ optionsConsumer.accept(options);
+ }
}, DEBUGGEE_JAVA8_JAR);
- debuggeeKotlinDexD8 = compileToDex(null, DEBUGGEE_KOTLIN_JAR);
+ debuggeeKotlinDexD8 = compileToDex(optionsConsumer, DEBUGGEE_KOTLIN_JAR);
}
protected static Path compileToDex(Consumer<InternalOptions> optionsConsumer,