Reapply "Move if rule evalation logic to own class"

This reverts commit ff10459b2d120cea74d59190ebc3f772ff13bed5.

Change-Id: I0998aa8fd59a53800f81369cf79e2ff0004ad1c1
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 fa22d3a..6b70524 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -147,7 +147,6 @@
 import com.android.tools.r8.shaking.KeepMethodInfo.Joiner;
 import com.android.tools.r8.shaking.KeepReason.ReflectiveUseFromXml;
 import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSet;
-import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSetBuilder;
 import com.android.tools.r8.shaking.RootSetUtils.RootSet;
 import com.android.tools.r8.shaking.RootSetUtils.RootSetBase;
 import com.android.tools.r8.shaking.RootSetUtils.RootSetBuilder;
@@ -172,7 +171,6 @@
 import com.android.tools.r8.utils.collections.ProgramFieldSet;
 import com.android.tools.r8.utils.collections.ProgramMethodMap;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -272,6 +270,7 @@
   // Don't hold a direct pointer to app info (use appView).
   private AppInfoWithClassHierarchy appInfo;
   private final AppView<AppInfoWithClassHierarchy> appView;
+  private final IfRuleEvaluatorFactory ifRuleEvaluatorFactory;
   private final EnqueuerDeferredTracing deferredTracing;
   private final ExecutorService executorService;
   private SubtypingInfo subtypingInfo;
@@ -460,9 +459,6 @@
   private final Map<DexType, Map<DexAnnotation, List<ProgramDefinition>>>
       deferredParameterAnnotations = new IdentityHashMap<>();
 
-  /** Map of active if rules to speed up aapt2 generated keep rules. */
-  private Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> activeIfRules;
-
   /**
    * A cache of ScopedDexMethodSet for each live type used for determining that virtual methods that
    * cannot be removed because they are widening access for another virtual method defined earlier
@@ -504,6 +500,8 @@
     InternalOptions options = appView.options();
     this.appInfo = appView.appInfo();
     this.appView = appView.withClassHierarchy();
+    this.ifRuleEvaluatorFactory =
+        new IfRuleEvaluatorFactory(appView.withClassHierarchy(), this, executorService);
     this.profileCollectionAdditions = profileCollectionAdditions;
     this.deferredTracing = EnqueuerDeferredTracing.create(appView, this, mode);
     this.executorService = executorService;
@@ -4756,28 +4754,7 @@
         long numberOfLiveItemsAfterProcessing = getNumberOfLiveItems();
         if (numberOfLiveItemsAfterProcessing > numberOfLiveItems) {
           timing.time("Conditional rules", () -> applicableRules.evaluateConditionalRules(this));
-
-          // Build the mapping of active if rules. We use a single collection of if-rules to allow
-          // removing if rules that have a constant sequent keep rule when they materialize.
-          if (activeIfRules == null) {
-            activeIfRules = new HashMap<>();
-            IfRuleClassPartEquivalence equivalence = new IfRuleClassPartEquivalence();
-            for (ProguardIfRule ifRule : rootSet.ifRules) {
-              Wrapper<ProguardIfRule> wrap = equivalence.wrap(ifRule);
-              activeIfRules.computeIfAbsent(wrap, ignore -> new LinkedHashSet<>()).add(ifRule);
-            }
-          }
-          ConsequentRootSetBuilder consequentSetBuilder =
-              ConsequentRootSet.builder(appView, this, subtypingInfo);
-          IfRuleEvaluator ifRuleEvaluator =
-              new IfRuleEvaluator(
-                  appView,
-                  subtypingInfo,
-                  this,
-                  executorService,
-                  activeIfRules,
-                  consequentSetBuilder);
-          addConsequentRootSet(ifRuleEvaluator.run());
+          ifRuleEvaluatorFactory.run(subtypingInfo);
           assert getNumberOfLiveItems() == numberOfLiveItemsAfterProcessing;
           if (!worklist.isEmpty()) {
             continue;
@@ -4905,7 +4882,7 @@
     return result;
   }
 
-  private void addConsequentRootSet(ConsequentRootSet consequentRootSet) {
+  void addConsequentRootSet(ConsequentRootSet consequentRootSet) {
     // TODO(b/132600955): This modifies the root set, but the consequent should not be persistent.
     //  Instead, the consequent root set should be added to collections that are owned by the
     //  enqueuer, similar to Enqueuer#dependentMinimumKeepClassInfo.
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 44ba57d..34bf3c1 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -14,7 +14,6 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.shaking.InlineRule.InlineRuleType;
-import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSet;
 import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSetBuilder;
 import com.android.tools.r8.shaking.RootSetUtils.RootSetBuilder;
 import com.android.tools.r8.threading.TaskCollection;
@@ -29,7 +28,6 @@
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
 import java.util.stream.Collectors;
 
 public class IfRuleEvaluator {
@@ -45,21 +43,21 @@
       AppView<? extends AppInfoWithClassHierarchy> appView,
       SubtypingInfo subtypingInfo,
       Enqueuer enqueuer,
-      ExecutorService executorService,
       Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules,
-      ConsequentRootSetBuilder rootSetBuilder) {
+      ConsequentRootSetBuilder rootSetBuilder,
+      TaskCollection<?> tasks) {
+    assert tasks.isEmpty();
     this.appView = appView;
     this.subtypingInfo = subtypingInfo;
     this.enqueuer = enqueuer;
     this.ifRules = ifRules;
     this.rootSetBuilder = rootSetBuilder;
-    this.tasks = new TaskCollection<>(appView.options(), executorService);
+    this.tasks = tasks;
   }
 
-  public ConsequentRootSet run() throws ExecutionException {
+  public void run() throws ExecutionException {
     appView.appInfo().app().timing.begin("Find consequent items for -if rules...");
     try {
-      if (ifRules != null && !ifRules.isEmpty()) {
         Iterator<Map.Entry<Wrapper<ProguardIfRule>, Set<ProguardIfRule>>> it =
             ifRules.entrySet().iterator();
         while (it.hasNext()) {
@@ -107,11 +105,9 @@
           }
         }
         tasks.await();
-      }
     } finally {
       appView.appInfo().app().timing.end();
     }
-    return rootSetBuilder.buildConsequentRootSet();
   }
 
   private boolean canRemoveSubsequentKeepRule(ProguardIfRule rule) {
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
new file mode 100644
index 0000000..b85f182
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
@@ -0,0 +1,73 @@
+// Copyright (c) 2024, 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 static com.android.tools.r8.utils.MapUtils.ignoreKey;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+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.google.common.base.Equivalence.Wrapper;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
+public class IfRuleEvaluatorFactory {
+
+  private final AppView<? extends AppInfoWithClassHierarchy> appView;
+  private final Enqueuer enqueuer;
+
+  /** 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 TaskCollection<?> tasks;
+
+  public IfRuleEvaluatorFactory(
+      AppView<? extends AppInfoWithClassHierarchy> appView,
+      Enqueuer enqueuer,
+      ExecutorService executorService) {
+    this.appView = appView;
+    this.enqueuer = enqueuer;
+    this.activeIfRules =
+        createActiveIfRules(
+            appView.hasRootSet() ? appView.rootSet().ifRules : Collections.emptySet());
+    this.tasks = new TaskCollection<>(appView.options(), executorService);
+  }
+
+  @SuppressWarnings("MixedMutabilityReturnType")
+  private static Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> createActiveIfRules(
+      Set<ProguardIfRule> ifRules) {
+    if (ifRules == null || ifRules.isEmpty()) {
+      return Collections.emptyMap();
+    }
+    // Build the mapping of active if rules. We use a single collection of if-rules to allow
+    // removing if rules that have a constant sequent keep rule when they materialize.
+    Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> activeIfRules = new HashMap<>(ifRules.size());
+    IfRuleClassPartEquivalence equivalence = new IfRuleClassPartEquivalence();
+    for (ProguardIfRule ifRule : ifRules) {
+      Wrapper<ProguardIfRule> wrap = equivalence.wrap(ifRule);
+      activeIfRules.computeIfAbsent(wrap, ignoreKey(LinkedHashSet::new)).add(ifRule);
+    }
+    return activeIfRules;
+  }
+
+  public void run(SubtypingInfo subtypingInfo) throws ExecutionException {
+    if (activeIfRules.isEmpty()) {
+      return;
+    }
+    ConsequentRootSetBuilder consequentRootSetBuilder =
+        ConsequentRootSet.builder(appView, enqueuer, subtypingInfo);
+    new IfRuleEvaluator(
+            appView, subtypingInfo, enqueuer, activeIfRules, consequentRootSetBuilder, tasks)
+        .run();
+    enqueuer.addConsequentRootSet(consequentRootSetBuilder.buildConsequentRootSet());
+  }
+}