Refine instantiated type information when all allocation sites of a class are dead
Change-Id: I197730593b9f42c886490fe94acffd2274e2b597
Bug: 149454532
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
index fa13c74..af2bdd4 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
@@ -33,6 +33,11 @@
return new Builder(trackAllocationSites, reporter);
}
+ public void markNoLongerInstantiated(DexProgramClass clazz) {
+ classesWithAllocationSiteTracking.remove(clazz);
+ classesWithoutAllocationSiteTracking.remove(clazz);
+ }
+
@Override
public void forEachClassWithKnownAllocationSites(
BiConsumer<DexProgramClass, Set<DexEncodedMethod>> consumer) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index 6d91163..62460e5 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -200,7 +200,7 @@
AbstractValue abstractValue =
abstractInstanceFieldValuesForClass.getOrDefault(field, UnknownValue.getInstance());
if (abstractValue.isBottom()) {
- // TODO(b/149454532): Record that the type is not instantiated.
+ feedback.modifyAppInfoWithLiveness().removeInstantiatedType(clazz);
break;
}
if (abstractValue.isUnknown()) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index ed2dea0..a4d036c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -834,6 +834,7 @@
if (options.enableFieldAssignmentTracker) {
fieldAccessAnalysis.fieldAssignmentTracker().waveDone(wave, delayedOptimizationFeedback);
}
+ delayedOptimizationFeedback.refineAppInfoWithLiveness(appView.appInfo().withLiveness());
delayedOptimizationFeedback.updateVisibleOptimizationInfo();
onWaveDoneActions.forEach(com.android.tools.r8.utils.Action::execute);
onWaveDoneActions = null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 0fec1f7..61f5a16 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.AppInfoWithLivenessModifier;
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.StringUtils;
import java.util.BitSet;
@@ -27,6 +28,8 @@
public class OptimizationFeedbackDelayed extends OptimizationFeedback {
// Caching of updated optimization info and processed status.
+ private final AppInfoWithLivenessModifier appInfoWithLivenessModifier =
+ AppInfoWithLiveness.modifier();
private final Map<DexEncodedField, MutableFieldOptimizationInfo> fieldOptimizationInfos =
new IdentityHashMap<>();
private final Map<DexEncodedMethod, UpdatableMethodOptimizationInfo> methodOptimizationInfos =
@@ -55,6 +58,10 @@
return info;
}
+ public AppInfoWithLivenessModifier modifyAppInfoWithLiveness() {
+ return appInfoWithLivenessModifier;
+ }
+
@Override
public void fixupOptimizationInfos(
AppView<?> appView, ExecutorService executorService, OptimizationInfoFixer fixer)
@@ -63,6 +70,10 @@
super.fixupOptimizationInfos(appView, executorService, fixer);
}
+ public void refineAppInfoWithLiveness(AppInfoWithLiveness appInfo) {
+ appInfoWithLivenessModifier.modify(appInfo);
+ }
+
public void updateVisibleOptimizationInfo() {
// Remove methods that have become obsolete. A method may become obsolete, for example, as a
// result of the class staticizer, which aims to transform virtual methods on companion classes
@@ -85,6 +96,7 @@
}
public boolean noUpdatesLeft() {
+ assert appInfoWithLivenessModifier.isEmpty();
assert fieldOptimizationInfos.isEmpty()
: StringUtils.join(fieldOptimizationInfos.keySet(), ", ");
assert methodOptimizationInfos.isEmpty()
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 69ed3b0..0b9cfdf 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -504,6 +504,10 @@
private boolean dontAssertDefinitionFor = true;
+ public static AppInfoWithLivenessModifier modifier() {
+ return new AppInfoWithLivenessModifier();
+ }
+
@Override
public void enableDefinitionForAssert() {
dontAssertDefinitionFor = false;
@@ -720,6 +724,10 @@
return objectAllocationInfoCollection;
}
+ ObjectAllocationInfoCollectionImpl getMutableObjectAllocationInfoCollection() {
+ return objectAllocationInfoCollection;
+ }
+
private boolean assertNoItemRemoved(Collection<DexReference> items, Collection<DexType> types) {
Set<DexType> typeSet = ImmutableSet.copyOf(types);
for (DexReference item : items) {
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLivenessModifier.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLivenessModifier.java
new file mode 100644
index 0000000..bd982f1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLivenessModifier.java
@@ -0,0 +1,37 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.shaking;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ObjectAllocationInfoCollectionImpl;
+import com.google.common.collect.Sets;
+import java.util.Set;
+
+/** Used to mutate AppInfoWithLiveness between waves. */
+public class AppInfoWithLivenessModifier {
+
+ private final Set<DexProgramClass> noLongerInstantiatedClasses = Sets.newIdentityHashSet();
+
+ AppInfoWithLivenessModifier() {}
+
+ public boolean isEmpty() {
+ return noLongerInstantiatedClasses.isEmpty();
+ }
+
+ public void removeInstantiatedType(DexProgramClass clazz) {
+ noLongerInstantiatedClasses.add(clazz);
+ }
+
+ public void modify(AppInfoWithLiveness appInfo) {
+ ObjectAllocationInfoCollectionImpl objectAllocationInfoCollection =
+ appInfo.getMutableObjectAllocationInfoCollection();
+ noLongerInstantiatedClasses.forEach(objectAllocationInfoCollection::markNoLongerInstantiated);
+ clear();
+ }
+
+ private void clear() {
+ noLongerInstantiatedClasses.clear();
+ }
+}