Version 1.0.31

Merge: Fix an infinite loop in CodeRewriter#simplifyArrayConstruction.
CL: https://r8-review.googlesource.com/c/r8/+/21880

Bug: 87341268
Change-Id: Ibccf02e65171eec8c4aa1c513fe0f65f11f23311
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index fb1837e..5c7bd78 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 = "v1.0.30";
+  public static final String LABEL = "v1.0.31";
 
   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 61cd3e7..4d745b4 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
@@ -1376,10 +1376,8 @@
           return values;
         }
       }
-      block =
-          block.exit().isGoto() && !visitedBlocks.contains(block.exit().asGoto().getTarget())
-              ? block.exit().asGoto().getTarget()
-              : null;
+      BasicBlock nextBlock = block.exit().isGoto() ? block.exit().asGoto().getTarget() : null;
+      block = nextBlock != null && !visitedBlocks.contains(nextBlock) ? nextBlock : null;
       it = block != null ? block.listIterator() : null;
     } while (it != null);
     return null;
@@ -1470,7 +1468,9 @@
       // Second pass: remove all the array put instructions for the array for which we have
       // inserted a fill array data instruction instead.
       if (!storesToRemoveForArray.isEmpty()) {
+        Set<BasicBlock> visitedBlocks = Sets.newIdentityHashSet();
         do {
+          visitedBlocks.add(block);
           it = block.listIterator();
           while (it.hasNext()) {
             Instruction instruction = it.next();
@@ -1492,7 +1492,8 @@
               }
             }
           }
-          block = block.exit().isGoto() ? block.exit().asGoto().getTarget() : null;
+          BasicBlock nextBlock = block.exit().isGoto() ? block.exit().asGoto().getTarget() : null;
+          block = nextBlock != null && !visitedBlocks.contains(nextBlock) ? nextBlock : null;
         } while (block != null);
       }
     }
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/B87341268.java b/src/test/java/com/android/tools/r8/ir/optimize/B87341268.java
new file mode 100644
index 0000000..f197f46
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/B87341268.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2018, 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 static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.DexInspector.ClassSubject;
+import org.junit.Test;
+
+public class B87341268 extends TestBase {
+  @Test
+  public void test() throws Exception {
+    AndroidApp app = compileWithD8(readClasses(TestClass.class));
+    DexInspector inspector = new DexInspector(app);
+    ClassSubject clazz = inspector.clazz(TestClass.class);
+    assertTrue(clazz.isPresent());
+  }
+}
+
+class TestClass {
+  int loop(String arg) {
+    long[] array = { 0L, 1L, 2L };
+    int length = -1;
+    while (true) {
+      try {
+        length = arg.length();
+      } catch (Exception e) {
+        System.err.println(e.getMessage());
+        break;
+      }
+    }
+    return length;
+  }
+}