Unify type-may-have-finalizer checks
Change-Id: If7e74a4f0315c657749476f00a7bcee97d594602
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 e8130e4..b06a015 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
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.analysis.fieldaccess;
-import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
@@ -20,8 +19,6 @@
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.UseRegistry;
-import com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement;
-import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
import com.android.tools.r8.ir.analysis.value.SingleValue;
@@ -165,16 +162,8 @@
if (singleValue.isSingleFieldValue()) {
SingleFieldValue singleFieldValue = singleValue.asSingleFieldValue();
DexField singleField = singleFieldValue.getField();
- if (singleField == field.field) {
- return false;
- }
- if (singleField.type.isClassType()) {
- ClassTypeLatticeElement fieldType =
- TypeLatticeElement.fromDexType(singleFieldValue.getField().type, maybeNull(), appView)
- .asClassTypeLatticeElement();
- return !appView.appInfo().mayHaveFinalizeMethodDirectlyOrIndirectly(fieldType);
- }
- return true;
+ return singleField != field.field
+ && !singleFieldValue.mayHaveFinalizeMethodDirectlyOrIndirectly(appView);
}
}
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index 8e48aad..dffd9e0 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
+import com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -35,6 +36,18 @@
return field;
}
+ public boolean mayHaveFinalizeMethodDirectlyOrIndirectly(AppView<AppInfoWithLiveness> appView) {
+ DexType fieldType = field.type;
+ if (fieldType.isClassType()) {
+ ClassTypeLatticeElement fieldClassType =
+ TypeLatticeElement.fromDexType(fieldType, maybeNull(), appView)
+ .asClassTypeLatticeElement();
+ return appView.appInfo().mayHaveFinalizeMethodDirectlyOrIndirectly(fieldClassType);
+ }
+ assert fieldType.isArrayType() || fieldType.isPrimitiveType();
+ return false;
+ }
+
@Override
public boolean isSingleFieldValue() {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
index 42e8e4a..366f0cf 100644
--- a/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/FieldInstruction.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.UnknownFieldSet;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.Sets;
@@ -198,7 +199,8 @@
* default finalize() method in a field. In that case, it is not safe to remove this instruction,
* since that could change the lifetime of the value.
*/
- boolean isStoringObjectWithFinalizer(AppInfoWithLiveness appInfo, DexEncodedField field) {
+ boolean isStoringObjectWithFinalizer(
+ AppView<AppInfoWithLiveness> appView, DexEncodedField field) {
assert isFieldPut();
TypeLatticeElement type = value().getTypeLattice();
@@ -208,25 +210,33 @@
return false;
}
- if (field.getOptimizationInfo().getAbstractValue().isZero()) {
- return false;
+ AbstractValue abstractValue = field.getOptimizationInfo().getAbstractValue();
+ if (abstractValue.isSingleValue()) {
+ if (abstractValue.isZero()) {
+ return false;
+ }
+ if (abstractValue.isSingleFieldValue()) {
+ SingleFieldValue singleFieldValue = abstractValue.asSingleFieldValue();
+ return singleFieldValue.mayHaveFinalizeMethodDirectlyOrIndirectly(appView);
+ }
}
+ AppInfoWithLiveness appInfo = appView.appInfo();
Value root = value().getAliasedValue();
if (!root.isPhi() && root.definition.isNewInstance()) {
- DexClass clazz = appInfo.definitionFor(root.definition.asNewInstance().clazz);
+ DexClass clazz = appView.definitionFor(root.definition.asNewInstance().clazz);
if (clazz == null) {
return true;
}
if (clazz.superType == null) {
return false;
}
- DexItemFactory dexItemFactory = appInfo.dexItemFactory();
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
DexEncodedMethod resolutionResult =
appInfo
.resolveMethod(clazz.type, dexItemFactory.objectMembers.finalize)
.getSingleTarget();
- return resolutionResult != null && resolutionResult.isProgramMethod(appInfo);
+ return resolutionResult != null && resolutionResult.isProgramMethod(appView);
}
return appInfo.mayHaveFinalizeMethodDirectlyOrIndirectly(baseType.asClassTypeLatticeElement());
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 12f3d93..d073a90 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
@@ -123,7 +123,8 @@
public boolean instructionMayHaveSideEffects(
AppView<?> appView, DexType context, Assumption assumption) {
if (appView.appInfo().hasLiveness()) {
- AppInfoWithLiveness appInfoWithLiveness = appView.appInfo().withLiveness();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo();
if (instructionInstanceCanThrow(appView, context, assumption).isThrowing()) {
return true;
@@ -132,7 +133,7 @@
DexEncodedField encodedField = appInfoWithLiveness.resolveField(getField());
assert encodedField != null : "NoSuchFieldError (resolution failure) should be caught.";
return appInfoWithLiveness.isFieldRead(encodedField)
- || isStoringObjectWithFinalizer(appInfoWithLiveness, encodedField);
+ || isStoringObjectWithFinalizer(appViewWithLiveness, 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 721a7bc..9d25691 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
@@ -102,7 +102,8 @@
public boolean instructionMayHaveSideEffects(
AppView<?> appView, DexType context, Assumption assumption) {
if (appView.appInfo().hasLiveness()) {
- AppInfoWithLiveness appInfoWithLiveness = appView.appInfo().withLiveness();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo();
// MemberValuePropagation will replace the field read only if the target field has bound
// -assumevalues rule whose return value is *single*.
//
@@ -128,7 +129,7 @@
}
return appInfoWithLiveness.isFieldRead(encodedField)
- || isStoringObjectWithFinalizer(appInfoWithLiveness, encodedField);
+ || isStoringObjectWithFinalizer(appViewWithLiveness, 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/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index da42de6..1fb713e 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -18,13 +18,11 @@
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
-import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.Sets;
-import com.google.common.collect.Streams;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -177,9 +175,7 @@
clazz.removeEnclosingMethod(this::isAttributeReferencingPrunedItem);
rewriteNestAttributes(clazz);
usagePrinter.visited();
- assert Streams.stream(clazz.fields())
- .map(DexEncodedField::getOptimizationInfo)
- .noneMatch(FieldOptimizationInfo::isDead);
+ assert verifyNoDeadFields(clazz);
}
private void rewriteNestAttributes(DexProgramClass clazz) {
@@ -360,4 +356,12 @@
public Collection<DexReference> getMethodsToKeepForConfigurationDebugging() {
return Collections.unmodifiableCollection(methodsToKeepForConfigurationDebugging);
}
+
+ private boolean verifyNoDeadFields(DexProgramClass clazz) {
+ for (DexEncodedField field : clazz.fields()) {
+ assert !field.getOptimizationInfo().isDead()
+ : "Expected field `" + field.field.toSourceString() + "` to be absent";
+ }
+ return true;
+ }
}