Avoid tree shaking of fields that are read or written
Bug: 112290098
Change-Id: I9c238b70dae4d13f2b8b6d8299f29aab084a2fb1
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 962247e..b91c27d 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -7,6 +7,7 @@
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.KeyedDexItem;
@@ -21,6 +22,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.function.Predicate;
public class TreePruner {
@@ -102,9 +104,9 @@
}
private <S extends PresortedComparable<S>, T extends KeyedDexItem<S>> int firstUnreachableIndex(
- T[] items, Set<S> live) {
+ T[] items, Predicate<S> live) {
for (int i = 0; i < items.length; i++) {
- if (!live.contains(items[i].getKey())) {
+ if (!live.test(items[i].getKey())) {
return i;
}
}
@@ -117,7 +119,7 @@
}
private DexEncodedMethod[] reachableMethods(DexEncodedMethod[] methods, DexClass clazz) {
- int firstUnreachable = firstUnreachableIndex(methods, appInfo.liveMethods);
+ int firstUnreachable = firstUnreachableIndex(methods, appInfo.liveMethods::contains);
// Return the original array if all methods are used.
if (firstUnreachable == -1) {
return methods;
@@ -168,7 +170,12 @@
}
private DexEncodedField[] reachableFields(DexEncodedField[] fields) {
- int firstUnreachable = firstUnreachableIndex(fields, appInfo.liveFields);
+ Predicate<DexField> isReachableOrReferencedField =
+ field ->
+ appInfo.liveFields.contains(field)
+ || appInfo.fieldsRead.contains(field)
+ || appInfo.fieldsWritten.contains(field);
+ int firstUnreachable = firstUnreachableIndex(fields, isReachableOrReferencedField);
// Return the original array if all fields are used.
if (firstUnreachable == -1) {
return fields;
@@ -177,14 +184,14 @@
Log.debug(getClass(), "Removing field: " + fields[firstUnreachable]);
}
usagePrinter.printUnusedField(fields[firstUnreachable]);
- ArrayList<DexEncodedField> reachableFields = new ArrayList<>(fields.length);
+ ArrayList<DexEncodedField> reachableOrReferencedFields = new ArrayList<>(fields.length);
for (int i = 0; i < firstUnreachable; i++) {
- reachableFields.add(fields[i]);
+ reachableOrReferencedFields.add(fields[i]);
}
for (int i = firstUnreachable + 1; i < fields.length; i++) {
DexEncodedField field = fields[i];
- if (appInfo.liveFields.contains(field.getKey())) {
- reachableFields.add(field);
+ if (isReachableOrReferencedField.test(field.field)) {
+ reachableOrReferencedFields.add(field);
} else {
if (Log.ENABLED) {
Log.debug(getClass(), "Removing field: " + field);
@@ -192,7 +199,9 @@
usagePrinter.printUnusedField(field);
}
}
- return reachableFields.toArray(new DexEncodedField[reachableFields.size()]);
+ return reachableOrReferencedFields.isEmpty()
+ ? DexEncodedField.EMPTY_ARRAY
+ : reachableOrReferencedFields.toArray(DexEncodedField.EMPTY_ARRAY);
}
public Collection<DexType> getRemovedClasses() {
diff --git a/src/test/java/com/android/tools/r8/shaking/B112290098.java b/src/test/java/com/android/tools/r8/shaking/B112290098.java
index 429853c..502da76 100644
--- a/src/test/java/com/android/tools/r8/shaking/B112290098.java
+++ b/src/test/java/com/android/tools/r8/shaking/B112290098.java
@@ -13,7 +13,6 @@
public class B112290098 extends TestBase {
- @Ignore("b/112290098")
@Test
public void test() throws Exception {
String mainClass = TestClass.class.getName();