Add a test for not computing object state in parameter propagation
Bug: b/296030319
Change-Id: Iac232c4a2bc4e1636605658497b2231d96bc75db
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
index e6ac132..b9f074c 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAccessAnalysis.java
@@ -35,7 +35,8 @@
this.appView = appView;
this.fieldBitAccessAnalysis =
options.enableFieldBitAccessAnalysis ? new FieldBitAccessAnalysis() : null;
- this.fieldAssignmentTracker = new FieldAssignmentTracker(appView);
+ this.fieldAssignmentTracker =
+ options.enableFieldAssignmentTracker ? new FieldAssignmentTracker(appView) : null;
this.fieldReadForInvokeReceiverAnalysis = new FieldReadForInvokeReceiverAnalysis(appView);
this.fieldReadForWriteAnalysis = new FieldReadForWriteAnalysis(appView);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index c1a2b62..1a64882 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueNull;
+import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues.EmptyStaticValues;
import com.android.tools.r8.ir.analysis.type.DynamicTypeWithUpperBound;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
@@ -64,6 +65,9 @@
assert appView.appInfo().hasLiveness();
assert appView.enableWholeProgramOptimizations();
assert code.context().getDefinition().isClassInitializer();
+ if (!appView.options().enableFieldValueAnalysis) {
+ return EmptyStaticValues.getInstance();
+ }
timing.begin("Analyze class initializer");
StaticFieldValues result =
new StaticFieldValueAnalysis(appView.withLiveness(), code, feedback)
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
index 7de5536..035690f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
@@ -73,7 +73,7 @@
numberUnboxer.prepareForPrimaryOptimizationPass(timing, executorService);
outliner.prepareForPrimaryOptimizationPass(graphLensForPrimaryOptimizationPass);
- if (fieldAccessAnalysis != null) {
+ if (fieldAccessAnalysis != null && fieldAccessAnalysis.fieldAssignmentTracker() != null) {
fieldAccessAnalysis.fieldAssignmentTracker().initialize();
}
@@ -252,11 +252,12 @@
onWaveDoneActions = Collections.synchronizedList(new ArrayList<>());
}
- public void waveDone(ProgramMethodSet wave, ExecutorService executorService)
- throws ExecutionException {
+ public void waveDone(ProgramMethodSet wave, ExecutorService executorService) {
delayedOptimizationFeedback.refineAppInfoWithLiveness(appView.appInfo().withLiveness());
delayedOptimizationFeedback.updateVisibleOptimizationInfo();
- fieldAccessAnalysis.fieldAssignmentTracker().waveDone(wave, delayedOptimizationFeedback);
+ if (fieldAccessAnalysis.fieldAssignmentTracker() != null) {
+ fieldAccessAnalysis.fieldAssignmentTracker().waveDone(wave, delayedOptimizationFeedback);
+ }
appView.withArgumentPropagator(ArgumentPropagator::publishDelayedReprocessingCriteria);
if (appView.options().protoShrinking().enableRemoveProtoEnumSwitchMap()) {
appView.protoShrinker().protoEnumSwitchMapRemover.updateVisibleStaticFieldValues();
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 b8b3ddf..7b83b69 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -401,6 +401,8 @@
// Optimization-related flags. These should conform to -dontoptimize and disableAllOptimizations.
public boolean enableFieldBitAccessAnalysis =
System.getProperty("com.android.tools.r8.fieldBitAccessAnalysis") != null;
+ public boolean enableFieldAssignmentTracker = true;
+ public boolean enableFieldValueAnalysis = true;
public boolean enableUnusedInterfaceRemoval = true;
public boolean enableDevirtualization = true;
public boolean enableEnumUnboxing = true;
diff --git a/src/test/java/com/android/tools/r8/optimize/argumentpropagation/FieldStateArgumentPropagationTest.java b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/FieldStateArgumentPropagationTest.java
new file mode 100644
index 0000000..728cd78
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/optimize/argumentpropagation/FieldStateArgumentPropagationTest.java
@@ -0,0 +1,101 @@
+// 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.optimize.argumentpropagation;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class FieldStateArgumentPropagationTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> {
+ options.enableFieldAssignmentTracker = false;
+ options.enableFieldValueAnalysis = false;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters)
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
+
+ MethodSubject printMethodSubject =
+ mainClassSubject.uniqueMethodWithOriginalName("print");
+ assertThat(printMethodSubject, isPresent());
+ // TODO(b/296030319): Should be 0.
+ assertEquals(1, printMethodSubject.getProgramMethod().getArity());
+
+ MethodSubject printlnMethodSubject =
+ mainClassSubject.uniqueMethodWithOriginalName("println");
+ assertThat(printlnMethodSubject, isPresent());
+ // TODO(b/296030319): Should be 0.
+ assertEquals(1, printlnMethodSubject.getProgramMethod().getArity());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello, world!");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ print(Greetings.HELLO.f);
+ println(Greetings.WORLD.f);
+ }
+
+ @NeverInline
+ static void print(String message) {
+ System.out.print(message);
+ }
+
+ @NeverInline
+ static void println(String message) {
+ System.out.println(message);
+ }
+ }
+
+ static class Greetings {
+
+ static final Greetings HELLO;
+ static final Greetings WORLD;
+
+ static {
+ HELLO = new Greetings("Hello");
+ WORLD = new Greetings(", world!");
+ }
+
+ final String f;
+
+ Greetings(String f) {
+ this.f = f;
+ }
+ }
+}