Revert "More aggressive redundant field load elimination for static final fields"
This reverts commit e1f9e833203585965d1d216a4122cc4ee2c8a6e2.
Revert "Simplify value-may-depend-on-environment analysis"
This reverts commit 9eed74e0c1279bfa754a94e5f202e8dd77891f65.
Change-Id: I89a16536d61d6e2d275674efc052f90ae152bc98
Reason for revert: Bot failures
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
index f417d65..05416df 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
@@ -20,12 +20,16 @@
import com.android.tools.r8.ir.code.NewArrayEmpty;
import com.android.tools.r8.ir.code.NewArrayFilledData;
import com.android.tools.r8.ir.code.NewInstance;
+import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.StaticPut;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.LongInterval;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -115,6 +119,9 @@
if (isNewInstanceWithoutEnvironmentDependentFields(root, assumedNotToDependOnEnvironment)) {
return false;
}
+ if (isAliasOfValueThatIsIndependentOfEnvironment(root, assumedNotToDependOnEnvironment)) {
+ return false;
+ }
return true;
} finally {
boolean changed = visited.remove(root);
@@ -407,4 +414,49 @@
return false;
}
+
+ private boolean isAliasOfValueThatIsIndependentOfEnvironment(
+ Value value, Set<Value> assumedNotToDependOnEnvironment) {
+ // If we are inside a class initializer, and we are reading a final field of the enclosing
+ // class, then check if there is a single write to that field in the class initializer, and that
+ // the value being written into that field does not depend on the environment.
+ //
+ // The reason why we do not currently treat final fields that are written in multiple places is
+ // that the value of the field could then be dependent on the environment due to the control
+ // flow.
+ if (code.method.isClassInitializer()) {
+ assert !value.hasAliasedValue();
+ if (value.isPhi()) {
+ return false;
+ }
+ Instruction definition = value.definition;
+ if (definition.isStaticGet()) {
+ StaticGet staticGet = definition.asStaticGet();
+ DexEncodedField field = appView.appInfo().resolveField(staticGet.getField());
+ if (field != null && field.holder() == context) {
+ List<StaticPut> finalFieldPuts = computeFinalFieldPuts().get(field);
+ if (finalFieldPuts == null || finalFieldPuts.size() != 1) {
+ return false;
+ }
+ StaticPut staticPut = ListUtils.first(finalFieldPuts);
+ return !valueMayDependOnEnvironment(staticPut.value(), assumedNotToDependOnEnvironment);
+ }
+ }
+ }
+ return false;
+ }
+
+ private Map<DexEncodedField, List<StaticPut>> computeFinalFieldPuts() {
+ assert code.method.isClassInitializer();
+ if (finalFieldPuts == null) {
+ finalFieldPuts = new IdentityHashMap<>();
+ for (StaticPut staticPut : code.<StaticPut>instructions(Instruction::isStaticPut)) {
+ DexEncodedField field = appView.appInfo().resolveField(staticPut.getField());
+ if (field != null && field.holder() == context && field.isFinal()) {
+ finalFieldPuts.computeIfAbsent(field, ignore -> new ArrayList<>()).add(staticPut);
+ }
+ }
+ }
+ return finalFieldPuts;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index 455d733..81b32e8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -206,12 +206,7 @@
// A field get on a different class can cause <clinit> to run and change static
// field values.
killNonFinalActiveFields(staticGet);
- FieldValue value = new ExistingValue(staticGet.value());
- if (definition.isFinal() && definition.isStatic()) {
- activeState.putFinalStaticField(field, value);
- } else {
- activeState.putNonFinalStaticField(field, value);
- }
+ activeState.putNonFinalStaticField(field, new ExistingValue(staticGet.value()));
}
} else if (instruction.isStaticPut()) {
StaticPut staticPut = instruction.asStaticPut();
@@ -492,9 +487,9 @@
if (instruction.isInstanceGet()) {
Value object = instruction.asInstanceGet().object().getAliasedValue();
FieldAndObject fieldAndObject = new FieldAndObject(field, object);
- removeInstanceField(fieldAndObject);
+ removeNonFinalInstanceField(fieldAndObject);
} else if (instruction.isStaticGet()) {
- removeStaticField(field);
+ removeNonFinalStaticField(field);
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/EnumCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/EnumCanonicalizationTest.java
index 589fa3f..1e323fb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/EnumCanonicalizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/EnumCanonicalizationTest.java
@@ -68,7 +68,8 @@
MethodSubject mainMethodSubject = classSubject.mainMethod();
assertThat(mainMethodSubject, isPresent());
assertEquals(
- 1,
+ // No canonicalization when generating class files.
+ parameters.isCfRuntime() ? 3 : 1,
mainMethodSubject
.streamInstructions()
.filter(InstructionSubject::isStaticGet)
@@ -76,7 +77,7 @@
.filter(enumFieldSubject.getField().field::equals)
.count());
assertEquals(
- 1,
+ 3,
mainMethodSubject
.streamInstructions()
.filter(InstructionSubject::isStaticGet)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/StaticFinalLibraryFieldCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/StaticFinalLibraryFieldCanonicalizationTest.java
index 275f0e4..7da9e81 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/StaticFinalLibraryFieldCanonicalizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/StaticFinalLibraryFieldCanonicalizationTest.java
@@ -66,7 +66,8 @@
MethodSubject mainMethodSubject = testClassSubject.mainMethod();
assertThat(mainMethodSubject, isPresent());
assertEquals(
- 1, mainMethodSubject.streamInstructions().filter(InstructionSubject::isStaticGet).count());
+ systemHasClassInitializationSideEffects || parameters.isCfRuntime() ? 2 : 1,
+ mainMethodSubject.streamInstructions().filter(InstructionSubject::isStaticGet).count());
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalStaticFieldLoadAfterStoreTest.java b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalStaticFieldLoadAfterStoreTest.java
index 2b910f5..fe3d79a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalStaticFieldLoadAfterStoreTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/redundantfieldloadelimination/RedundantFinalStaticFieldLoadAfterStoreTest.java
@@ -65,8 +65,9 @@
MethodSubject mMethodSubject = aClassSubject.uniqueMethodWithName("m");
assertThat(mMethodSubject, isPresent());
+ // TODO(b/152196923): Should be 0.
assertEquals(
- 1,
+ 2,
countStaticGetInstructions(
mMethodSubject.asFoundMethodSubject(), fFieldSubject.asFoundFieldSubject()));
}