Reapply "Avoid computing effectively live info in each if rule evaluation"

This reverts commit 6095462ec66eefe9e79f1b3c6e80711910b26fad.

Change-Id: Ic2b02854a9a1e1d7710d0ca32cab8e3a6aee7ac9
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 096b704..46d4c02 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3531,29 +3531,6 @@
     return liveTypes.contains(clazz);
   }
 
-  public boolean isEffectivelyLive(DexProgramClass clazz) {
-    if (isTypeLive(clazz)) {
-      return true;
-    }
-    if (mode.isInitialTreeShaking()) {
-      return false;
-    }
-    // TODO(b/325014359): Replace this by value tracking in instructions (akin to resource values).
-    for (DexEncodedField field : clazz.fields()) {
-      if (field.getOptimizationInfo().valueHasBeenPropagated()) {
-        return true;
-      }
-    }
-    // TODO(b/325014359): Replace this by value or position tracking.
-    //  We need to be careful not to throw away such values/positions.
-    for (DexEncodedMethod method : clazz.methods()) {
-      if (method.getOptimizationInfo().returnValueHasBeenPropagated()) {
-        return true;
-      }
-    }
-    return false;
-  }
-
   public boolean isOriginalReferenceEffectivelyLive(DexReference reference) {
     // The effectively-live original set contains types, fields and methods witnessed by
     // instructions, such as method inlining positions.
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
index 72563e2..4841933 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -52,7 +52,9 @@
     this.tasks = tasks;
   }
 
-  public void run(Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules)
+  public void run(
+      Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules,
+      Set<DexProgramClass> effectivelyFakeLiveClasses)
       throws ExecutionException {
     MapUtils.removeIf(
         ifRules,
@@ -66,7 +68,7 @@
           for (DexProgramClass clazz :
               ifRuleKey.relevantCandidatesForRule(
                   appView, subtypingInfo, appView.appInfo().classes())) {
-            if (!isEffectivelyLive(clazz)) {
+            if (!isEffectivelyLive(clazz, effectivelyFakeLiveClasses)) {
               continue;
             }
             evaluateRuleOnEffectivelyLiveClass(
@@ -88,6 +90,11 @@
     tasks.await();
   }
 
+  private boolean isEffectivelyLive(
+      DexProgramClass clazz, Set<DexProgramClass> effectivelyFakeLiveClasses) {
+    return enqueuer.isTypeLive(clazz) || effectivelyFakeLiveClasses.contains(clazz);
+  }
+
   private void evaluateRuleOnEffectivelyLiveClass(
       ProguardIfRule ifRuleKey,
       Set<ProguardIfRule> ifRulesInEquivalence,
@@ -140,10 +147,6 @@
     }
   }
 
-  private boolean isEffectivelyLive(DexProgramClass clazz) {
-    return enqueuer.isEffectivelyLive(clazz);
-  }
-
   /** Determines if {@param clazz} satisfies the given if-rule class specification. */
   private boolean evaluateClassForIfRule(ProguardIfRule rule, DexProgramClass clazz) {
     incrementNumberOfProguardIfRuleClassEvaluations();
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
index 28a61ff..5857e14 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
@@ -7,12 +7,16 @@
 
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSet;
 import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSetBuilder;
 import com.android.tools.r8.threading.TaskCollection;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.collect.Sets;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashSet;
@@ -29,6 +33,8 @@
   /** Map of active if rules. This is important for speeding up aapt2 generated keep rules. */
   private final Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> activeIfRules;
 
+  private final Set<DexProgramClass> effectivelyFakeLiveClasses;
+
   private final TaskCollection<?> tasks;
 
   public IfRuleEvaluatorFactory(
@@ -38,6 +44,7 @@
     this.appView = appView;
     this.enqueuer = enqueuer;
     this.activeIfRules = createActiveIfRules(appView.rootSet().ifRules);
+    this.effectivelyFakeLiveClasses = createEffectivelyFakeLiveClasses(appView, enqueuer);
     this.tasks = new TaskCollection<>(appView.options(), executorService);
   }
 
@@ -58,6 +65,38 @@
     return activeIfRules;
   }
 
+  @SuppressWarnings("MixedMutabilityReturnType")
+  private static Set<DexProgramClass> createEffectivelyFakeLiveClasses(
+      AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+    if (enqueuer.getMode().isInitialTreeShaking()) {
+      return Collections.emptySet();
+    }
+    Set<DexProgramClass> effectivelyFakeLiveClasses = Sets.newIdentityHashSet();
+    for (DexProgramClass clazz : appView.appInfo().classes()) {
+      if (isFakeEffectiveLive(clazz)) {
+        effectivelyFakeLiveClasses.add(clazz);
+      }
+    }
+    return effectivelyFakeLiveClasses;
+  }
+
+  private static boolean isFakeEffectiveLive(DexProgramClass clazz) {
+    // TODO(b/325014359): Replace this by value tracking in instructions (akin to resource values).
+    for (DexEncodedField field : clazz.fields()) {
+      if (field.getOptimizationInfo().valueHasBeenPropagated()) {
+        return true;
+      }
+    }
+    // TODO(b/325014359): Replace this by value or position tracking.
+    //  We need to be careful not to throw away such values/positions.
+    for (DexEncodedMethod method : clazz.methods()) {
+      if (method.getOptimizationInfo().returnValueHasBeenPropagated()) {
+        return true;
+      }
+    }
+    return false;
+  }
+
   public void run(SubtypingInfo subtypingInfo, Timing timing) throws ExecutionException {
     if (activeIfRules.isEmpty()) {
       return;
@@ -66,7 +105,9 @@
         ConsequentRootSet.builder(appView, enqueuer, subtypingInfo);
     IfRuleEvaluator evaluator =
         new IfRuleEvaluator(appView, subtypingInfo, enqueuer, consequentRootSetBuilder, tasks);
-    timing.time("Find consequent items for -if rules...", () -> evaluator.run(activeIfRules));
+    timing.time(
+        "Find consequent items for -if rules...",
+        () -> evaluator.run(activeIfRules, effectivelyFakeLiveClasses));
     enqueuer.addConsequentRootSet(consequentRootSetBuilder.buildConsequentRootSet());
   }
 }