Version 1.4.97
Cherry pick: Fix workaround for exceptional edges targeting loop headers.
CL: https://r8-review.googlesource.com/c/r8/+/38545
Bug: 133130870
Change-Id: I447803f18e050d93b7367226b44e8dd77d5dcb16
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 0190082..6fa660a 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.4.96";
+ public static final String LABEL = "1.4.97";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 5075b99..d828483 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -3837,7 +3837,7 @@
// The loop is conditional if it has at least two normal successors.
BasicBlock target = handler.endOfGotoChain();
if (target != null
- && target.getPredecessors().size() > 2
+ && target.getPredecessors().size() > 1
&& target.getNormalPredecessors().size() > 1
&& target.getNormalSuccessors().size() > 1) {
Instruction fixit = new AlwaysMaterializingNop();
diff --git a/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestIdenticalNormalAndExceptionalEdge.java b/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestIdenticalNormalAndExceptionalEdge.java
new file mode 100644
index 0000000..ff6f074
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestIdenticalNormalAndExceptionalEdge.java
@@ -0,0 +1,28 @@
+// Copyright (c) 2019, 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.debuginfo;
+
+import java.util.Arrays;
+
+public class Regress111337896TestIdenticalNormalAndExceptionalEdge {
+
+ public static void regress111337896() {
+ for (Object o : Arrays.asList(new Object())) {
+ try {
+ doThrow();
+ } catch (Exception e) {
+ // Empty handler causes segfault on some ART 5.0 x86 devices.
+ }
+ }
+ }
+
+ public static void doThrow() throws Exception {
+ throw new Exception();
+ }
+
+ public static void main(String[] args) {
+ regress111337896();
+ System.out.print("aok");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestRunner.java
index 1404f35..be25d4a 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/Regress111337896TestRunner.java
@@ -68,4 +68,52 @@
assertEquals(expectedNops, nopsFound);
}
}
+
+ @Test
+ public void testIdenticalNormalAndExceptionalEdge() throws Exception {
+ Class clazz = Regress111337896TestIdenticalNormalAndExceptionalEdge.class;
+
+ // Check the regression test is valid code.
+ String expected = "aok";
+ assertEquals(expected, runOnJava(clazz));
+
+ for (AndroidApiLevel minApi : Arrays.asList(AndroidApiLevel.L, AndroidApiLevel.M)) {
+ for (CompilationMode mode : CompilationMode.values()) {
+ AndroidAppConsumers appSink = new AndroidAppConsumers();
+ D8.run(
+ D8Command.builder()
+ .addProgramFiles(ToolHelper.getClassFileForTestClass(clazz))
+ .setProgramConsumer(appSink.wrapDexIndexedConsumer(null))
+ .setMode(mode)
+ .setMinApiLevel(minApi.getLevel())
+ .build());
+ AndroidApp app = appSink.build();
+ assertEquals(expected, runOnArt(app, clazz.getCanonicalName()));
+
+ // Check that the compiled output contains a nop to workaround the issue.
+ // We can't really check much else as this only reproduces on some physical x86_64 devices.
+ checkIdenticalNormalAndExceptionalEdge(
+ inspectMethod(app, clazz, "void", "regress111337896"), mode, minApi);
+ }
+ }
+ }
+
+ private void checkIdenticalNormalAndExceptionalEdge(
+ DebugInfoInspector info, CompilationMode mode, AndroidApiLevel minApi) {
+ info.checkStartLine(11);
+ assertEquals(1, info.checkLineExists(13));
+ int nopsFound = 0;
+ for (Instruction instruction : info.getMethod().getCode().asDexCode().instructions) {
+ if (instruction instanceof Nop) {
+ nopsFound++;
+ }
+ }
+ if (mode == CompilationMode.DEBUG) {
+ assertEquals(0, nopsFound);
+ } else {
+ // In release mode the workaround will have inserted a nop if below M.
+ int expectedNops = minApi.getLevel() < AndroidApiLevel.M.getLevel() ? 1 : 0;
+ assertEquals(expectedNops, nopsFound);
+ }
+ }
}