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();
+  }
+}