Enable and remove InternalOptions' experimentalNewFilledArraySupport
Plus fix 2 bugs with it and fixup one test.
Bugs:
* Not checking that array is the destination of aput-object users
* Not checking whether value type is an array for isSubtype()
Bug: 246971330
Change-Id: I4a75e439eb46ad9a295fa3ec6821aa132a80a88d
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
index b010a58..8a6298c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
@@ -320,8 +320,7 @@
Value newObjectsValue = code.createValue(objectArrayType);
// Populate the `objects` array.
- if (appView.options().rewriteArrayOptions().experimentalNewFilledArraySupport
- && appView.options().rewriteArrayOptions().canUseFilledNewArrayOfObjects()) {
+ if (appView.options().rewriteArrayOptions().canUseFilledNewArrayOfObjects()) {
List<Value> arrayValues = new ArrayList<>(objects.size());
for (int i = 0; i < objects.size(); i++) {
Instruction materializingInstruction = objects.get(i).buildIR(appView, code);
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 cade4ce..5406e16 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
@@ -2134,6 +2134,7 @@
private Value[] computeArrayValues(LinearFlowInstructionListIterator it, int size) {
NewArrayEmpty newArrayEmpty = it.next().asNewArrayEmpty();
assert newArrayEmpty != null;
+ Value arrayValue = newArrayEmpty.outValue();
// aput-object allows any object for arrays of interfaces, but new-filled-array fails to verify
// if types require a cast.
@@ -2165,7 +2166,7 @@
ArrayPut arrayPut = instruction.asArrayPut();
// If the initialization sequence is broken by another use we cannot use a fill-array-data
// instruction.
- if (arrayPut == null) {
+ if (arrayPut == null || arrayPut.array() != arrayValue) {
return null;
}
if (!arrayPut.index().isConstNumber()) {
@@ -2185,6 +2186,9 @@
if (!elementType.equals(valueDexType)) {
return null;
}
+ } else if (valueDexType.isArrayType()) {
+ // isSubtype asserts for this case.
+ return null;
} else {
// TODO(b/246971330): When in d8 mode, we might still be able to see if this is true for
// library types (which this helper does not do).
@@ -2246,18 +2250,11 @@
if (values == null) {
continue;
}
- if (!rewriteOptions.experimentalNewFilledArraySupport
- && !newArrayEmpty.type.isPrimitiveArrayType()
- && newArrayEmpty.type != dexItemFactory.stringArrayType) {
- continue;
- }
// 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()
- || (rewriteOptions.experimentalNewFilledArraySupport
- && newArrayEmpty.type == dexItemFactory.intArrayType
- && size <= 5)) {
+ || (newArrayEmpty.type == dexItemFactory.intArrayType && size <= 5)) {
// Don't replace with filled-new-array if it requires more than 200 consecutive registers.
if (size > rewriteOptions.maxRangeInputs) {
continue;
@@ -2309,6 +2306,7 @@
// inserted a fill array data instruction instead.
if (!storesToRemoveForArray.isEmpty()) {
Set<BasicBlock> visitedBlocks = Sets.newIdentityHashSet();
+ int numInstructionsInserted = 0;
do {
visitedBlocks.add(block);
it = block.listIterator(code);
@@ -2330,6 +2328,7 @@
// last removed put at which point we are now adding the construction.
construction.setPosition(instruction.getPosition());
it.add(construction);
+ numInstructionsInserted += 1;
}
}
}
@@ -2338,6 +2337,7 @@
BasicBlock nextBlock = block.exit().isGoto() ? block.exit().asGoto().getTarget() : null;
block = nextBlock != null && !visitedBlocks.contains(nextBlock) ? nextBlock : null;
} while (block != null);
+ assert numInstructionsInserted == instructionToInsertForArray.size();
}
}
assert code.isConsistentSSA(appView);
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 acf5ac1..a0c146a 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1394,8 +1394,6 @@
// Arbitrary limit of number of inputs to fill-array-data.
public int maxFillArrayDataInputs = 8 * 1024;
- // TODO(b/246971330): Remove when feature is complete.
- public boolean experimentalNewFilledArraySupport = false;
// Dalvik x86-atom backend had a bug that made it crash on filled-new-array instructions for
// arrays of objects. This is unfortunate, since this never hits arm devices, but we have
// to disallow filled-new-array of objects for dalvik until kitkat. The buggy code was
diff --git a/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java b/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
index 812eb63..80e3c1e 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/GetMembersTest.java
@@ -6,12 +6,11 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.dex.code.DexAputObject;
-import com.android.tools.r8.dex.code.DexConst4;
import com.android.tools.r8.dex.code.DexConstClass;
import com.android.tools.r8.dex.code.DexConstString;
+import com.android.tools.r8.dex.code.DexFilledNewArray;
import com.android.tools.r8.dex.code.DexInvokeVirtual;
-import com.android.tools.r8.dex.code.DexNewArray;
+import com.android.tools.r8.dex.code.DexMoveResultObject;
import com.android.tools.r8.dex.code.DexReturnVoid;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.smali.SmaliBuilder;
@@ -93,16 +92,14 @@
assertTrue(method.isPresent());
DexCode code = method.getMethod().getCode().asDexCode();
- assertTrue(code.instructions[0] instanceof DexConst4);
- assertTrue(code.instructions[1] instanceof DexNewArray);
- assertTrue(code.instructions[2] instanceof DexConst4);
+ assertTrue(code.instructions[0] instanceof DexConstClass);
+ assertTrue(code.instructions[1] instanceof DexFilledNewArray);
+ assertTrue(code.instructions[2] instanceof DexMoveResultObject);
assertTrue(code.instructions[3] instanceof DexConstClass);
- assertTrue(code.instructions[4] instanceof DexAputObject);
- assertTrue(code.instructions[5] instanceof DexConstClass);
- assertTrue(code.instructions[6] instanceof DexConstString);
- assertNotEquals("foo", code.instructions[6].asConstString().getString().toString());
- assertTrue(code.instructions[7] instanceof DexInvokeVirtual);
- assertTrue(code.instructions[8] instanceof DexReturnVoid);
+ assertTrue(code.instructions[4] instanceof DexConstString);
+ assertNotEquals("foo", code.instructions[4].asConstString().getString().toString());
+ assertTrue(code.instructions[5] instanceof DexInvokeVirtual);
+ assertTrue(code.instructions[6] instanceof DexReturnVoid);
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
index fd3ba45..2ccc111 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierNameStringMarkerTest.java
@@ -639,16 +639,7 @@
"-keep class " + CLASS_NAME,
"-keep class R { *; }");
CodeInspector inspector =
- compileWithR8(
- builder,
- testBuilder ->
- testBuilder
- .addKeepRules(pgConfigs)
- .addOptionsModification(
- options ->
- options.rewriteArrayOptions().experimentalNewFilledArraySupport =
- true))
- .inspector();
+ compileWithR8(builder, testBuilder -> testBuilder.addKeepRules(pgConfigs)).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
assertTrue(clazz.isPresent());
@@ -708,16 +699,7 @@
"-keep class " + CLASS_NAME,
"-keep,allowobfuscation class R { *; }");
CodeInspector inspector =
- compileWithR8(
- builder,
- testBuilder ->
- testBuilder
- .addKeepRules(pgConfigs)
- .addOptionsModification(
- (options) ->
- options.rewriteArrayOptions().experimentalNewFilledArraySupport =
- true))
- .inspector();
+ compileWithR8(builder, testBuilder -> testBuilder.addKeepRules(pgConfigs)).inspector();
ClassSubject clazz = inspector.clazz(CLASS_NAME);
assertTrue(clazz.isPresent());
diff --git a/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayWithDataLengthRewriteTest.java b/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayWithDataLengthRewriteTest.java
index 73e39e1..513dc73 100644
--- a/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayWithDataLengthRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/arrays/ArrayWithDataLengthRewriteTest.java
@@ -43,8 +43,6 @@
.setMinApi(parameters.getApiLevel())
.setMode(CompilationMode.RELEASE)
.addProgramClasses(Main.class)
- .addOptionsModification(
- opt -> opt.rewriteArrayOptions().experimentalNewFilledArraySupport = true)
.addOptionsModification(opt -> opt.testing.irModifier = this::transformArray)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(expectedOutput)
@@ -56,8 +54,6 @@
testForR8(parameters.getBackend())
.setMinApi(parameters.getRuntime())
.addProgramClasses(Main.class)
- .addOptionsModification(
- opt -> opt.rewriteArrayOptions().experimentalNewFilledArraySupport = true)
.addOptionsModification(opt -> opt.testing.irModifier = this::transformArray)
.addKeepMainRule(Main.class)
.enableInliningAnnotations()
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 4fe27d8..6c6e076 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
@@ -97,6 +97,7 @@
"[0, 1, 2]",
"[1, 2, 3]",
"[1, 2, 3, 4, 5, 6]",
+ "[0]",
};
private static final byte[] TRANSFORMED_MAIN = transformedMain();
@@ -109,9 +110,6 @@
d8TestBuilder ->
d8TestBuilder
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(
- options ->
- options.rewriteArrayOptions().experimentalNewFilledArraySupport = true)
.setMode(compilationMode))
.addProgramClassFileData(TRANSFORMED_MAIN)
.run(parameters.getRuntime(), Main.class)
@@ -124,12 +122,10 @@
testForR8(parameters.getBackend())
.setMinApi(parameters.getApiLevel())
.addOptionsModification(
- options -> {
- options.rewriteArrayOptions().experimentalNewFilledArraySupport = true;
- options
- .getOpenClosedInterfacesOptions()
- .suppressSingleOpenInterface(Reference.classFromClass(Serializable.class));
- })
+ options ->
+ options
+ .getOpenClosedInterfacesOptions()
+ .suppressSingleOpenInterface(Reference.classFromClass(Serializable.class)))
.setMode(compilationMode)
.addProgramClassFileData(TRANSFORMED_MAIN)
.addKeepMainRule(Main.class)
@@ -296,6 +292,7 @@
catchHandlerThrowing();
catchHandlerNonThrowingFilledNewArray();
catchHandlerNonThrowingFillArrayData();
+ arrayIntoAnotherArray();
}
@NeverInline
@@ -432,6 +429,16 @@
}
@NeverInline
+ private static void arrayIntoAnotherArray() {
+ // Tests that our computeValues() method does not assume all array-put-object users have
+ // the array as the target.
+ int[] intArr = new int[1];
+ Object[] objArr = new Object[2];
+ objArr[0] = intArr;
+ System.out.println(Arrays.toString((int[]) objArr[0]));
+ }
+
+ @NeverInline
private static void phiFilledNewArray() {
// The presence of ? should not affect use of filled-new-array.
String[] phiArray = {"a", System.nanoTime() > 0 ? "b" : "c"};