Version 1.0.23

Merge: Always rematerialize single-width numeric constants.
CL: https://r8-review.googlesource.com/c/r8/+/19884
Change-Id: I778c3cfa86f57d4034dca79272b6d23431ffa1c5
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index ab1f699..76e9fbf 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.22";
+  public static final String LABEL = "v1.0.23";
 
   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 54efe87..61cd3e7 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
@@ -1294,8 +1294,7 @@
     insertAt.nextUntil(i ->
         i.inValues().contains(instruction.outValue())
         || i.isJumpInstruction()
-        || (hasCatchHandlers && i.instructionTypeCanThrow())
-        || (options.canHaveBoundsCheckEliminationBug() && i.isArrayLength()));
+        || (hasCatchHandlers && i.instructionTypeCanThrow()));
     Instruction next = insertAt.previous();
     instruction.forceSetPosition(
         next.isGoto() ? next.asGoto().getTarget().getPosition() : next.getPosition());
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
index 2dbc015..3dc151d 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/SpillMoveSet.java
@@ -296,8 +296,18 @@
         scheduler.addMove(
             new RegisterMove(move.to.getRegister(), move.type, move.from.getValue().definition));
       } else if (move.to.getRegister() != move.from.getRegister()) {
-        scheduler.addMove(
-            new RegisterMove(move.to.getRegister(), move.from.getRegister(), move.type));
+        // In case the runtime might have a bound-check elimination bug we make sure to define all
+        // indexing constants with an actual const instruction rather than a move. This appears to
+        // avoid a bug where the index variable could end up being uninitialized.
+        if (code.options.canHaveBoundsCheckEliminationBug()
+            && move.from.getValue().isConstNumber()
+            && move.type == MoveType.SINGLE) {
+          scheduler.addMove(
+              new RegisterMove(move.to.getRegister(), move.type, move.from.getValue().definition));
+        } else {
+          scheduler.addMove(
+              new RegisterMove(move.to.getRegister(), move.from.getRegister(), move.type));
+        }
       }
     }
     scheduler.schedule();
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 45834d7..6a92af6 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -451,18 +451,16 @@
   // Some Lollipop versions of Art found in the wild perform invalid bounds
   // check elimination. There is a fast path of loops and a slow path.
   // The bailout to the slow path is performed too early and therefore
-  // the loop variable might not be defined in the slow path code leading
+  // the array-index variable might not be defined in the slow path code leading
   // to use of undefined registers as indices into arrays. The result
   // is ArrayIndexOutOfBounds exceptions.
   //
-  // In an attempt to help these Art VMs get the loop variable initialized
-  // early, we do not lower constants past array-length instructions when
-  // building for Lollipop or below.
+  // In an attempt to help these Art VMs, all single-width constants are initialized and not moved.
   //
   // There is no guarantee that this works, but it does make the problem
   // disappear on the one known instance of this problem.
   //
-  // See b/69364976.
+  // See b/69364976 and b/77996377.
   public boolean canHaveBoundsCheckEliminationBug() {
     return minApiLevel <= AndroidApiLevel.L.getLevel();
   }