Ensure fields marked as dead will be eligible for removal
Bug: 183734568
Change-Id: Ib7c4e1aa763e0ebec6e884600e3c18b9ec1a71e2
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index b11431e..e98e0d2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -93,9 +93,19 @@
timing.end(); // Clear reads from fields of interest
timing.end(); // Trivial field accesses analysis
- constantFields.forEach(OptimizationFeedbackSimple.getInstance()::markFieldAsDead);
- readFields.keySet().forEach(OptimizationFeedbackSimple.getInstance()::markFieldAsDead);
- writtenFields.keySet().forEach(OptimizationFeedbackSimple.getInstance()::markFieldAsDead);
+ constantFields.forEach(this::markFieldAsDead);
+ readFields.keySet().forEach(this::markFieldAsDead);
+ writtenFields.keySet().forEach(this::markFieldAsDead);
+ }
+
+ private void markFieldAsDead(DexEncodedField field) {
+ // Don't mark pinned fields as dead, since they need to remain in the app even if all reads and
+ // writes are removed.
+ if (appView.appInfo().isPinned(field)) {
+ assert field.getType().isAlwaysNull(appView);
+ } else {
+ OptimizationFeedbackSimple.getInstance().markFieldAsDead(field);
+ }
}
private void computeFieldsWithNonTrivialValue() {
@@ -236,7 +246,8 @@
DexEncodedField field,
boolean isWrite,
FieldAccessInfoCollection<?> fieldAccessInfoCollection) {
- assert !appView.appInfo().isPinned(field);
+ assert !appView.appInfo().isPinned(field) || field.getType().isAlwaysNull(appView);
+
FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.getReference());
if (fieldAccessInfo == null) {
assert false
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index 606fbb6..573c0c5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.desugar.itf;
-import static com.android.tools.r8.utils.PredicateUtils.not;
import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -169,7 +168,10 @@
private DexEncodedField findExistingStaticClinitFieldToTriggerInterfaceInitialization(
DexProgramClass iface) {
- for (DexEncodedField field : iface.staticFields(not(DexEncodedField::isPrivate))) {
+ // Don't select a field that has been marked dead, since we'll assert later that these fields
+ // have been dead code eliminated.
+ for (DexEncodedField field :
+ iface.staticFields(field -> !field.isPrivate() && !field.getOptimizationInfo().isDead())) {
return field;
}
return null;
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
index 03611d6..e8d52aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/shaking/ClassInitFieldSynthesizer.java
@@ -48,6 +48,10 @@
// Use an existing static field if there is one.
DexEncodedField encodedClinitField = null;
for (DexEncodedField staticField : clazz.staticFields()) {
+ // Don't consider dead fields.
+ if (staticField.getOptimizationInfo().isDead()) {
+ continue;
+ }
// We need the field to be accessible from the contexts in which it is accessed.
if (!isMinimumRequiredVisibility(staticField, minimumRequiredVisibility)) {
continue;