Reapply "Cleanup if rule evaluator by removing ifRules field and timing"

This reverts commit 37641c085e0b65e6acd536327f492919f56ecdc9.

Change-Id: Id6ad19d6902540c26b7bc75ff3d81fae851a708c
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 6b70524..0552373 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -4754,7 +4754,7 @@
         long numberOfLiveItemsAfterProcessing = getNumberOfLiveItems();
         if (numberOfLiveItemsAfterProcessing > numberOfLiveItems) {
           timing.time("Conditional rules", () -> applicableRules.evaluateConditionalRules(this));
-          ifRuleEvaluatorFactory.run(subtypingInfo);
+          ifRuleEvaluatorFactory.run(subtypingInfo, timing);
           assert getNumberOfLiveItems() == numberOfLiveItemsAfterProcessing;
           if (!worklist.isEmpty()) {
             continue;
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 cce2733..72563e2 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -17,12 +17,12 @@
 import com.android.tools.r8.shaking.RootSetUtils.ConsequentRootSetBuilder;
 import com.android.tools.r8.shaking.RootSetUtils.RootSetBuilder;
 import com.android.tools.r8.threading.TaskCollection;
+import com.android.tools.r8.utils.MapUtils;
 import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -35,7 +35,6 @@
   private final AppView<? extends AppInfoWithClassHierarchy> appView;
   private final SubtypingInfo subtypingInfo;
   private final Enqueuer enqueuer;
-  private final Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules;
   private final ConsequentRootSetBuilder rootSetBuilder;
   private final TaskCollection<?> tasks;
 
@@ -43,27 +42,22 @@
       AppView<? extends AppInfoWithClassHierarchy> appView,
       SubtypingInfo subtypingInfo,
       Enqueuer enqueuer,
-      Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules,
       ConsequentRootSetBuilder rootSetBuilder,
       TaskCollection<?> tasks) {
     assert tasks.isEmpty();
     this.appView = appView;
     this.subtypingInfo = subtypingInfo;
     this.enqueuer = enqueuer;
-    this.ifRules = ifRules;
     this.rootSetBuilder = rootSetBuilder;
     this.tasks = tasks;
   }
 
-  public void run() throws ExecutionException {
-    appView.appInfo().app().timing.begin("Find consequent items for -if rules...");
-    try {
-        Iterator<Map.Entry<Wrapper<ProguardIfRule>, Set<ProguardIfRule>>> it =
-            ifRules.entrySet().iterator();
-        while (it.hasNext()) {
-          Map.Entry<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRuleEntry = it.next();
-          ProguardIfRule ifRuleKey = ifRuleEntry.getKey().get();
-          Set<ProguardIfRule> ifRulesInEquivalence = ifRuleEntry.getValue();
+  public void run(Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules)
+      throws ExecutionException {
+    MapUtils.removeIf(
+        ifRules,
+        (ifRuleWrapper, ifRulesInEquivalence) -> {
+          ProguardIfRule ifRuleKey = ifRuleWrapper.get();
           List<ProguardIfRule> toRemove = new ArrayList<>();
 
           // Depending on which types that trigger the -if rule, the application of the subsequent
@@ -86,15 +80,12 @@
                 });
           }
           if (ifRulesInEquivalence.size() == toRemove.size()) {
-            it.remove();
-          } else if (!toRemove.isEmpty()) {
-            ifRulesInEquivalence.removeAll(toRemove);
+            return true;
           }
-        }
-        tasks.await();
-    } finally {
-      appView.appInfo().app().timing.end();
-    }
+          toRemove.forEach(ifRulesInEquivalence::remove);
+          return false;
+        });
+    tasks.await();
   }
 
   private void evaluateRuleOnEffectivelyLiveClass(
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 b85f182..551a8c6 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
@@ -11,6 +11,7 @@
 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 java.util.Collections;
 import java.util.HashMap;
@@ -59,15 +60,15 @@
     return activeIfRules;
   }
 
-  public void run(SubtypingInfo subtypingInfo) throws ExecutionException {
+  public void run(SubtypingInfo subtypingInfo, Timing timing) throws ExecutionException {
     if (activeIfRules.isEmpty()) {
       return;
     }
     ConsequentRootSetBuilder consequentRootSetBuilder =
         ConsequentRootSet.builder(appView, enqueuer, subtypingInfo);
-    new IfRuleEvaluator(
-            appView, subtypingInfo, enqueuer, activeIfRules, consequentRootSetBuilder, tasks)
-        .run();
+    IfRuleEvaluator evaluator =
+        new IfRuleEvaluator(appView, subtypingInfo, enqueuer, consequentRootSetBuilder, tasks);
+    timing.time("Find consequent items for -if rules...", () -> evaluator.run(activeIfRules));
     enqueuer.addConsequentRootSet(consequentRootSetBuilder.buildConsequentRootSet());
   }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/MapUtils.java b/src/main/java/com/android/tools/r8/utils/MapUtils.java
index c991a7d..ac5d7f6 100644
--- a/src/main/java/com/android/tools/r8/utils/MapUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/MapUtils.java
@@ -10,11 +10,11 @@
 import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
 import java.util.Collections;
 import java.util.IdentityHashMap;
+import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.function.BiConsumer;
 import java.util.function.BiFunction;
-import java.util.function.BiPredicate;
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.IntFunction;
@@ -80,8 +80,15 @@
     map.entrySet().removeIf(entry -> entry.getKey() == entry.getValue());
   }
 
-  public static <K, V> void removeIf(Map<K, V> map, BiPredicate<K, V> predicate) {
-    map.entrySet().removeIf(entry -> predicate.test(entry.getKey(), entry.getValue()));
+  public static <K, V, E extends Throwable> void removeIf(
+      Map<K, V> map, ThrowingBiPredicate<K, V, E> predicate) throws E {
+    Iterator<Entry<K, V>> iterator = map.entrySet().iterator();
+    while (iterator.hasNext()) {
+      Entry<K, V> entry = iterator.next();
+      if (predicate.test(entry.getKey(), entry.getValue())) {
+        iterator.remove();
+      }
+    }
   }
 
   public static <K, V> V removeOrDefault(Map<K, V> map, K key, V defaultValue) {
diff --git a/src/main/java/com/android/tools/r8/utils/ThrowingBiPredicate.java b/src/main/java/com/android/tools/r8/utils/ThrowingBiPredicate.java
new file mode 100644
index 0000000..7e6fa66
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/ThrowingBiPredicate.java
@@ -0,0 +1,9 @@
+// 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.utils;
+
+public interface ThrowingBiPredicate<S, T, E extends Throwable> {
+
+  boolean test(S s, T t) throws E;
+}