Do not enable filled-new-array for pre-N minSdkVersion

ART 6.0.1 tests show an odd failure with them, so disable for pre-N.
Many apps now have N as their minSdkVersion, so this won't be a missed
opportunity for most (or at least this will be the case soon).

This still enables String[] for pre-N so as to not regress the status
quo.

Bug: b/246971330
Change-Id: I0a87f6dc8201b487bce0ff2af0abd35f32fd03a8
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 a6da9b7..1d4e435 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
@@ -2220,6 +2220,7 @@
       return;
     }
     InternalOptions.RewriteArrayOptions rewriteOptions = options.rewriteArrayOptions();
+    boolean canUseForStrings = rewriteOptions.canUseFilledNewArrayOfStrings();
     boolean canUseForObjects = rewriteOptions.canUseFilledNewArrayOfObjects();
     boolean canUseForArrays = rewriteOptions.canUseFilledNewArrayOfArrays();
 
@@ -2242,11 +2243,17 @@
         if (size < 1 || size > rewriteOptions.maxFillArrayDataInputs) {
           continue;
         }
-        if (!newArrayEmpty.type.isPrimitiveArrayType() && !canUseForObjects) {
-          continue;
-        }
-        if (newArrayEmpty.type.getNumberOfLeadingSquareBrackets() > 1 && !canUseForArrays) {
-          continue;
+        DexType arrayType = newArrayEmpty.type;
+        if (!arrayType.isPrimitiveArrayType()) {
+          if (arrayType == dexItemFactory.stringArrayType) {
+            if (!canUseForStrings) {
+              continue;
+            }
+          } else if (!canUseForObjects) {
+            continue;
+          } else if (!canUseForArrays && arrayType.getNumberOfLeadingSquareBrackets() > 1) {
+            continue;
+          }
         }
 
         Value[] values =
@@ -2258,8 +2265,8 @@
         // filled-new-array is implemented only for int[] and Object[].
         // For int[], using filled-new-array is usually smaller than filled-array-data.
         // filled-new-array supports up to 5 registers before it's filled-new-array/range.
-        if (!newArrayEmpty.type.isPrimitiveArrayType()
-            || (newArrayEmpty.type == dexItemFactory.intArrayType && size <= 5)) {
+        if (!arrayType.isPrimitiveArrayType()
+            || (arrayType == dexItemFactory.intArrayType && size <= 5)) {
           // Don't replace with filled-new-array if it requires more than 200 consecutive registers.
           if (size > rewriteOptions.maxRangeInputs) {
             continue;
@@ -2270,8 +2277,7 @@
           // positioned).
           Value invokeValue =
               code.createValue(newArrayEmpty.getOutType(), newArrayEmpty.getLocalInfo());
-          InvokeNewArray invoke =
-              new InvokeNewArray(newArrayEmpty.type, invokeValue, Arrays.asList(values));
+          InvokeNewArray invoke = new InvokeNewArray(arrayType, invokeValue, Arrays.asList(values));
           for (Value value : newArrayEmpty.inValues()) {
             value.removeUser(newArrayEmpty);
           }
@@ -2292,7 +2298,7 @@
             // throwing instruction to the same block (the first one being NewArrayEmpty).
             continue;
           }
-          int elementSize = newArrayEmpty.type.elementSizeForPrimitiveArrayType();
+          int elementSize = arrayType.elementSizeForPrimitiveArrayType();
           short[] contents = computeArrayFilledData(values, size, elementSize);
           if (contents == null) {
             continue;
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 5cb7a74..98d5a27 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1403,11 +1403,19 @@
     // Buggy code that accidentally call code that only works on primitives arrays.
     //
     // https://android.googlesource.com/platform/dalvik/+/ics-mr0/vm/mterp/out/InterpAsm-x86-atom.S#25106
-    public boolean canUseFilledNewArrayOfObjects() {
+    public boolean canUseFilledNewArrayOfStrings() {
       assert isGeneratingDex();
       return hasFeaturePresentFrom(AndroidApiLevel.K);
     }
 
+    // When adding support for emitting new-filled-array for non-String types, ART 6.0.1 had issues.
+    // https://ci.chromium.org/ui/p/r8/builders/ci/linux-android-6.0.1/6507/overview
+    // It somehow had a new-array-filled return null.
+    public boolean canUseFilledNewArrayOfObjects() {
+      assert isGeneratingDex();
+      return hasFeaturePresentFrom(AndroidApiLevel.N);
+    }
+
     // Dalvik doesn't handle new-filled-array with arrays as values. It fails with:
     // W(629880) VFY: [Ljava/lang/Integer; is not instance of Ljava/lang/Integer;  (dalvikvm)
     public boolean canUseFilledNewArrayOfArrays() {
diff --git a/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java b/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java
index aad69a0..939753f 100644
--- a/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/arrays/SimplifyArrayConstructionTest.java
@@ -63,11 +63,10 @@
     "[1, null, 2]",
     "[1, null, 2]",
     "[1]",
-    "[a, b]",
+    "[1, 2]",
     "[1, 2, 3, 4, 5]",
     "[1]",
     "[a, 1, null, d, e, f]",
-    "[a, b, c, d, e, f]",
     "[1, null, 3, null, null, 6]",
     "[1, 2, 3, 4, 5, 6]",
     "[true, false]",
@@ -167,6 +166,7 @@
     ClassSubject mainClass = inspector.clazz(Main.class);
     assertTrue(mainClass.isPresent());
 
+    MethodSubject stringArrays = mainClass.uniqueMethodWithOriginalName("stringArrays");
     MethodSubject referenceArraysNoCasts =
         mainClass.uniqueMethodWithOriginalName("referenceArraysNoCasts");
     MethodSubject referenceArraysWithSubclasses =
@@ -210,8 +210,14 @@
       assertArrayTypes(reversedArray, DexFilledNewArray.class);
     }
 
-    // Cannot use filled-new-array of Object before K.
+    // Cannot use filled-new-array of String before K.
     if (parameters.getApiLevel().isLessThan(AndroidApiLevel.K)) {
+      assertArrayTypes(stringArrays, DexNewArray.class);
+    } else {
+      assertArrayTypes(stringArrays, DexFilledNewArray.class);
+    }
+    // Cannot use filled-new-array of Object before L.
+    if (parameters.getApiLevel().isLessThan(AndroidApiLevel.N)) {
       assertArrayTypes(referenceArraysNoCasts, DexNewArray.class);
       assertArrayTypes(referenceArraysWithSubclasses, DexNewArray.class);
       assertArrayTypes(phiFilledNewArray, DexNewArray.class);
@@ -290,6 +296,7 @@
     static final String assumedNullField = null;
 
     public static void main(String[] args) {
+      stringArrays();
       referenceArraysNoCasts();
       referenceArraysWithSubclasses();
       interfaceArrayWithRawObject();
@@ -310,10 +317,14 @@
     }
 
     @NeverInline
-    private static void referenceArraysNoCasts() {
+    private static void stringArrays() {
       // Test exact class, no null.
       String[] stringArr = {"a"};
       System.out.println(Arrays.toString(stringArr));
+    }
+
+    @NeverInline
+    private static void referenceArraysNoCasts() {
       // Tests that no type info is needed when array type is Object[].
       Object[] objectArr = {"a", 1, null};
       System.out.println(Arrays.toString(objectArr));
@@ -454,14 +465,14 @@
 
     @NeverInline
     private static void assumedValues() {
-      String[] arr = {assumedNonNullField, assumedNullField};
+      Object[] arr = {assumedNonNullField, assumedNullField};
       System.out.println(Arrays.toString(arr));
     }
 
     @NeverInline
     private static void phiFilledNewArray() {
       // The presence of ? should not affect use of filled-new-array.
-      String[] phiArray = {"a", System.nanoTime() > 0 ? "b" : "c"};
+      Integer[] phiArray = {1, System.nanoTime() > 0 ? 2 : 3};
       System.out.println(Arrays.toString(phiArray));
     }
 
@@ -483,8 +494,6 @@
       // 6 or more elements use /range variant.
       Object[] objectArr = {"a", 1, null, "d", "e", "f"};
       System.out.println(Arrays.toString(objectArr));
-      String[] stringArr = {"a", "b", "c", "d", "e", "f"};
-      System.out.println(Arrays.toString(stringArr));
       Serializable[] interfaceArr = {
         getSerializable(1), null, getSerializable(3), null, null, getSerializable(6)
       };