Update optimization info for fields/methods known to return null
Change-Id: I071afd86a5d2e00bb256f5d48f5901a0e72d258f
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 6e60771..34677e0 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -542,6 +542,7 @@
timing.begin("UninstantiatedTypeOptimization");
UninstantiatedTypeOptimizationGraphLense lens =
new UninstantiatedTypeOptimization(appViewWithLiveness)
+ .strenghtenOptimizationInfo()
.run(
new MethodPoolCollection(appViewWithLiveness, subtypingInfo),
executorService,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 8ca93eb..96fd58c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -280,12 +280,7 @@
return;
}
- AbstractValue abstractReturnValue;
- if (singleTarget.returnType().isAlwaysNull(appView)) {
- abstractReturnValue = appView.abstractValueFactory().createSingleNumberValue(0);
- } else {
- abstractReturnValue = singleTarget.getOptimizationInfo().getAbstractReturnValue();
- }
+ AbstractValue abstractReturnValue = singleTarget.getOptimizationInfo().getAbstractReturnValue();
if (abstractReturnValue.isSingleValue()) {
SingleValue singleReturnValue = abstractReturnValue.asSingleValue();
@@ -356,9 +351,7 @@
}
AbstractValue abstractValue;
- if (field.type.isAlwaysNull(appView)) {
- abstractValue = appView.abstractValueFactory().createSingleNumberValue(0);
- } else if (appView.appInfo().isFieldWrittenByFieldPutInstruction(target)) {
+ if (appView.appInfo().isFieldWrittenByFieldPutInstruction(target)) {
abstractValue = target.getOptimizationInfo().getAbstractValue();
if (abstractValue.isUnknown() && !target.isStatic()) {
AbstractValue abstractReceiverValue =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index 11245e7..cb1eec7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -15,6 +15,8 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessInfo;
+import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
@@ -22,6 +24,7 @@
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RemovedArgumentInfo;
import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.FieldInstruction;
import com.android.tools.r8.ir.code.IRCode;
@@ -31,6 +34,8 @@
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.MemberPoolCollection.MemberPool;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.Timing;
@@ -104,6 +109,33 @@
this.appView = appView;
}
+ public UninstantiatedTypeOptimization strenghtenOptimizationInfo() {
+ OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
+ FieldAccessInfoCollection<?> fieldAccessInfoCollection =
+ appView.appInfo().getFieldAccessInfoCollection();
+ AbstractValue nullValue = appView.abstractValueFactory().createSingleNumberValue(0);
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ clazz.forEachField(
+ field -> {
+ if (field.type().isAlwaysNull(appView)) {
+ FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.field);
+ if (fieldAccessInfo != null) {
+ // Clear all writes since each write must write `null` to the field.
+ fieldAccessInfo.asMutable().clearWrites();
+ }
+ feedback.recordFieldHasAbstractValue(field, appView, nullValue);
+ }
+ });
+ clazz.forEachMethod(
+ method -> {
+ if (method.returnType().isAlwaysNull(appView)) {
+ feedback.methodReturnsAbstractValue(method, appView, nullValue);
+ }
+ });
+ }
+ return this;
+ }
+
public UninstantiatedTypeOptimizationGraphLense run(
MethodPoolCollection methodPoolCollection, ExecutorService executorService, Timing timing) {
try {