Always pop unused multianewarray return value
Bug: b/335663479
Change-Id: I86aa3e5b3bf49a228c842bcb2e7bb5d39ef5b85b
diff --git a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
index c7c4cc7..d7dbde7 100644
--- a/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/LoadStoreHelper.java
@@ -167,10 +167,18 @@
it.next();
}
- public void storeOutValue(Instruction instruction, InstructionListIterator it) {
- if (!instruction.hasOutValue()) {
- return;
+ public void storeOrPopOutValue(
+ DexType type, Instruction instruction, InstructionListIterator it) {
+ if (instruction.hasOutValue()) {
+ assert instruction.outValue().isUsed();
+ storeOutValue(instruction, it);
+ } else {
+ popOutType(type, instruction, it);
}
+ }
+
+ public void storeOutValue(Instruction instruction, InstructionListIterator it) {
+ assert instruction.hasOutValue();
assert !(instruction.outValue() instanceof StackValue);
if (instruction.isConstInstruction()) {
ConstInstruction constInstruction = instruction.asConstInstruction();
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index a2bb674..890516f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.cf.LoadStoreHelper;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.code.DexInstruction;
import com.android.tools.r8.dex.code.DexMoveResult;
@@ -294,4 +295,10 @@
public boolean outTypeKnownToBeBoolean(Set<Phi> seen) {
return getReturnType().isBooleanType();
}
+
+ /**
+ * Subclasses must implement load and store handling and make sure to deal with a null out-value
+ */
+ @Override
+ public abstract void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
index 710fb47..0b24f8b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeCustom.java
@@ -194,12 +194,7 @@
if (getCallSite().methodProto.returnType.isVoidType()) {
return;
}
- if (outValue == null) {
- helper.popOutType(getCallSite().methodProto.returnType, this, it);
- } else {
- assert outValue.isUsed();
- helper.storeOutValue(this, it);
- }
+ helper.storeOrPopOutValue(getCallSite().methodProto.returnType, this, it);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 4a9b217..c1a5688 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -270,12 +270,7 @@
if (getReturnType().isVoidType()) {
return;
}
- if (outValue == null) {
- helper.popOutType(getReturnType(), this, it);
- } else {
- assert outValue.isUsed();
- helper.storeOutValue(this, it);
- }
+ helper.storeOrPopOutValue(getReturnType(), this, it);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
index 9b5eb96..b4256d2 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
@@ -103,7 +103,7 @@
@Override
public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {
helper.loadInValues(this, it);
- helper.storeOutValue(this, it);
+ helper.storeOrPopOutValue(type, this, it);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/cf/UnusedMultiNewArrayTest.java b/src/test/java/com/android/tools/r8/cf/UnusedMultiNewArrayTest.java
index 2ec3d66..986256a 100644
--- a/src/test/java/com/android/tools/r8/cf/UnusedMultiNewArrayTest.java
+++ b/src/test/java/com/android/tools/r8/cf/UnusedMultiNewArrayTest.java
@@ -34,7 +34,10 @@
.addKeepMainRule(TestClass.class)
.addDontWarn(A.class)
.setMinApi(parameters)
- .compile();
+ .compile()
+ .addRunClasspathClasses(A.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput("");
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/cf/UnusedMultiNewArrayWithOnStackValueTest.java b/src/test/java/com/android/tools/r8/cf/UnusedMultiNewArrayWithOnStackValueTest.java
new file mode 100644
index 0000000..1d8c60e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/UnusedMultiNewArrayWithOnStackValueTest.java
@@ -0,0 +1,55 @@
+// Copyright (c) 2024, 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.cf;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+/** Regression test for b/335663479. */
+@RunWith(Parameterized.class)
+public class UnusedMultiNewArrayWithOnStackValueTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public UnusedMultiNewArrayWithOnStackValueTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .addKeepMainRule(TestClass.class)
+ .addDontWarn(A.class)
+ .setMinApi(parameters)
+ .compile()
+ .addRunClasspathClasses(A.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("42");
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ // The array instructions cannot be removed because A is not provided as a program class.
+ int dim = 42;
+ A[][] local = new A[dim][dim];
+ local = new A[dim][dim];
+ System.out.println(local.length);
+ }
+ }
+
+ static class A {}
+}