Change isRead/isWritten to take DexEncodedField
This implicitly guarantees that no indirect field accesses are being passed to isRead() and isWritten().
Change-Id: If3a9c13414ce67de859ef22df94b756d31ab40c7
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 7da40d0..7b57fa2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -147,8 +147,7 @@
// The only way to figure out whether the DexValue contains the final value
// is ensure the value is not the default or check <clinit> is not present.
boolean isEffectivelyFinal =
- (accessFlags.isFinal() || !appInfo.isFieldWritten(field))
- && !appInfo.isPinned(field);
+ (accessFlags.isFinal() || !appInfo.isFieldWritten(this)) && !appInfo.isPinned(field);
if (!isEffectivelyFinal) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
index fca35ba..ee563bc 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstancePut.java
@@ -103,13 +103,9 @@
return true;
}
- DexEncodedField resolveField = appInfoWithLiveness.resolveField(getField());
- assert resolveField != null : "NoSuchFieldError (resolution failure) should be caught.";
- if (appInfoWithLiveness.isFieldRead(resolveField.field)) {
- return true;
- }
-
- return false;
+ DexEncodedField encodedField = appInfoWithLiveness.resolveField(getField());
+ assert encodedField != null : "NoSuchFieldError (resolution failure) should be caught.";
+ return appInfoWithLiveness.isFieldRead(encodedField);
}
// In D8, we always have to assume that the field can be read, and thus have side effects.
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index a609206..13eb959 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -105,13 +105,9 @@
return true;
}
- DexEncodedField resolveField = appInfoWithLiveness.resolveField(getField());
- assert resolveField != null : "NoSuchFieldError (resolution failure) should be caught.";
- if (appInfoWithLiveness.isFieldRead(resolveField.field)) {
- return true;
- }
-
- return false;
+ DexEncodedField encodedField = appInfoWithLiveness.resolveField(getField());
+ assert encodedField != null : "NoSuchFieldError (resolution failure) should be caught.";
+ return appInfoWithLiveness.isFieldRead(encodedField);
}
// In D8, we always have to assume that the field can be read, and thus have side effects.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
index 45ca27a..1e839d7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -210,8 +210,9 @@
Set<DexField> candidates =
finalFieldPuts.stream()
.map(FieldInstruction::getField)
- .map(field -> appInfoWithLiveness.resolveField(field).field)
+ .map(appInfoWithLiveness::resolveField)
.filter(appInfoWithLiveness::isStaticFieldWrittenOnlyInEnclosingStaticInitializer)
+ .map(field -> field.field)
.collect(Collectors.toSet());
// Then retain only these fields that are actually no longer being written to.
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 5fdc8f5..92783d2 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
@@ -622,8 +623,9 @@
return isInstantiatedDirectly(type) || isInstantiatedIndirectly(type);
}
- public boolean isFieldRead(DexField field) {
+ public boolean isFieldRead(DexEncodedField encodedField) {
assert checkIfObsolete();
+ DexField field = encodedField.field;
FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field);
if (info != null && info.isRead()) {
return true;
@@ -632,11 +634,12 @@
// Fields in the class that is synthesized by D8/R8 would be used soon.
|| field.holder.isD8R8SynthesizedClassType()
// For library classes we don't know whether a field is read.
- || isLibraryOrClasspathField(field);
+ || isLibraryOrClasspathField(encodedField);
}
- public boolean isFieldWritten(DexField field) {
+ public boolean isFieldWritten(DexEncodedField encodedField) {
assert checkIfObsolete();
+ DexField field = encodedField.field;
FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field);
if (info != null && info.isWritten()) {
return true;
@@ -645,13 +648,13 @@
// Fields in the class that is synthesized by D8/R8 would be used soon.
|| field.holder.isD8R8SynthesizedClassType()
// For library classes we don't know whether a field is rewritten.
- || isLibraryOrClasspathField(field);
+ || isLibraryOrClasspathField(encodedField);
}
- public boolean isStaticFieldWrittenOnlyInEnclosingStaticInitializer(DexField field) {
+ public boolean isStaticFieldWrittenOnlyInEnclosingStaticInitializer(DexEncodedField field) {
assert checkIfObsolete();
assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written";
- return staticFieldsWrittenOnlyInEnclosingStaticInitializer.contains(field);
+ return staticFieldsWrittenOnlyInEnclosingStaticInitializer.contains(field.field);
}
public boolean mayPropagateValueFor(DexReference reference) {
@@ -659,8 +662,8 @@
return !isPinned(reference) && !neverPropagateValue.contains(reference);
}
- private boolean isLibraryOrClasspathField(DexField field) {
- DexClass holder = definitionFor(field.holder);
+ private boolean isLibraryOrClasspathField(DexEncodedField field) {
+ DexClass holder = definitionFor(field.field.holder);
return holder == null || holder.isLibraryClass() || holder.isClasspathClass();
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 23e4503..19c297c 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -1347,9 +1347,9 @@
DexEncodedField encodedField = appInfo.definitionFor(field);
if (encodedField != null
&& (encodedField.isStatic() || isKeptDirectlyOrIndirectly(field.holder, appInfo))) {
- assert appInfo.isFieldRead(field)
+ assert appInfo.isFieldRead(encodedField)
: "Expected kept field `" + field.toSourceString() + "` to be read";
- assert appInfo.isFieldWritten(field)
+ assert appInfo.isFieldWritten(encodedField)
: "Expected kept field `" + field.toSourceString() + "` to be written";
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 97b440d..c291f9c 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
@@ -194,9 +193,9 @@
}
private <S extends PresortedComparable<S>, T extends KeyedDexItem<S>> int firstUnreachableIndex(
- List<T> items, Predicate<S> live) {
+ List<T> items, Predicate<T> live) {
for (int i = 0; i < items.size(); i++) {
- if (!live.test(items.get(i).getKey())) {
+ if (!live.test(items.get(i))) {
return i;
}
}
@@ -206,7 +205,8 @@
private DexEncodedMethod[] reachableMethods(List<DexEncodedMethod> methods, DexClass clazz) {
AppInfoWithLiveness appInfo = appView.appInfo();
InternalOptions options = appView.options();
- int firstUnreachable = firstUnreachableIndex(methods, appInfo.liveMethods::contains);
+ int firstUnreachable =
+ firstUnreachableIndex(methods, method -> appInfo.liveMethods.contains(method.method));
// Return the original array if all methods are used.
if (firstUnreachable == -1) {
return null;
@@ -266,7 +266,7 @@
private DexEncodedField[] reachableFields(List<DexEncodedField> fields) {
AppInfoWithLiveness appInfo = appView.appInfo();
- Predicate<DexField> isReachableOrReferencedField =
+ Predicate<DexEncodedField> isReachableOrReferencedField =
field -> appInfo.isFieldRead(field) || appInfo.isFieldWritten(field);
int firstUnreachable = firstUnreachableIndex(fields, isReachableOrReferencedField);
// Return the original array if all fields are used.
@@ -283,7 +283,7 @@
}
for (int i = firstUnreachable + 1; i < fields.size(); i++) {
DexEncodedField field = fields.get(i);
- if (isReachableOrReferencedField.test(field.field)) {
+ if (isReachableOrReferencedField.test(field)) {
reachableOrReferencedFields.add(field);
} else {
if (Log.ENABLED) {