Reapply "Group if rules without members by equivalence for shared class evaluation"

This reverts commit f827811c408a7310c61b331530747d6e65a3bc3f.

Change-Id: I9034e57fffc5aed3e82c4560d8e23f29024bc97a
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 8da99d1..c0c05d4 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -92,23 +92,27 @@
   }
 
   public void processActiveIfRulesWithoutMembers(
-      Set<ProguardIfRule> ifRules, Iterable<DexProgramClass> newlyLiveClasses)
+      Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules,
+      Iterable<DexProgramClass> newlyLiveClasses)
       throws ExecutionException {
-    ifRules.removeIf(
-        ifRule -> {
+    MapUtils.removeIf(
+        ifRules,
+        (ifRuleWrapper, ifRulesInEquivalence) -> {
           // Depending on which types that trigger the -if rule, the application of the subsequent
           // -keep rule may vary (due to back references). So, we need to try all pairs of -if
           // rule and live types.
+          ProguardIfRule ifRuleKey = ifRuleWrapper.get();
           for (DexProgramClass clazz : newlyLiveClasses) {
-            if (evaluateClassForIfRule(ifRule, clazz)) {
-              registerClassCapture(ifRule, clazz, clazz);
-              uncheckedMaterializeIfRule(ifRule, clazz);
-              if (canRemoveSubsequentKeepRule(ifRule)) {
-                return true;
-              }
+            if (evaluateClassForIfRule(ifRuleKey, clazz)) {
+              ifRulesInEquivalence.removeIf(
+                  ifRule -> {
+                    registerClassCapture(ifRule, clazz, clazz);
+                    uncheckedMaterializeIfRule(ifRule, clazz);
+                    return canRemoveSubsequentKeepRule(ifRule);
+                  });
             }
           }
-          return false;
+          return ifRulesInEquivalence.isEmpty();
         });
     tasks.await();
   }
@@ -199,11 +203,7 @@
       throws ExecutionException {
     incrementNumberOfProguardIfRuleMemberEvaluations();
     Collection<ProguardMemberRule> memberKeepRules = rule.getMemberRules();
-    if (memberKeepRules.isEmpty()) {
-      materializeIfRule(rule, clazz);
-      matchedConsumer.accept(rule);
-      return;
-    }
+    assert !memberKeepRules.isEmpty();
 
     List<DexClassAndField> fieldsInlinedByJavaC = new ArrayList<>();
     Set<DexDefinition> filteredMembers = Sets.newIdentityHashSet();
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 d1f15d8c..cc813e2 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluatorFactory.java
@@ -34,7 +34,7 @@
   /** Map of active if rules. This is important for speeding up aapt2 generated keep rules. */
   private final Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> activeIfRulesWithMembers;
 
-  private final Set<ProguardIfRule> activeIfRulesWithoutMembers;
+  private final Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> activeIfRulesWithoutMembers;
 
   private final Set<DexProgramClass> effectivelyFakeLiveClasses;
   private final Set<DexProgramClass> newlyLiveClasses = Sets.newIdentityHashSet();
@@ -49,8 +49,8 @@
       Enqueuer enqueuer,
       ExecutorService executorService) {
     this.appView = appView;
-    this.activeIfRulesWithMembers = createActiveIfRulesWithMembers(appView.rootSet().ifRules);
-    this.activeIfRulesWithoutMembers = createActiveIfRulesWithoutMembers(appView.rootSet().ifRules);
+    this.activeIfRulesWithMembers = createActiveIfRules(appView.rootSet().ifRules, true);
+    this.activeIfRulesWithoutMembers = createActiveIfRules(appView.rootSet().ifRules, false);
     this.effectivelyFakeLiveClasses = createEffectivelyFakeLiveClasses(appView, enqueuer);
     this.tasks = new TaskCollection<>(appView.options(), executorService);
   }
@@ -66,14 +66,15 @@
     }
   }
 
-  private static Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> createActiveIfRulesWithMembers(
-      Set<ProguardIfRule> ifRules) {
+  private static Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> createActiveIfRules(
+      Set<ProguardIfRule> ifRules, boolean withMembers) {
     // 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) {
-      if (!ifRule.getMemberRules().isEmpty()) {
+      boolean hasMembers = !ifRule.getMemberRules().isEmpty();
+      if (hasMembers == withMembers) {
         Wrapper<ProguardIfRule> wrap = equivalence.wrap(ifRule);
         activeIfRules.computeIfAbsent(wrap, ignoreKey(LinkedHashSet::new)).add(ifRule);
       }
@@ -81,19 +82,6 @@
     return activeIfRules;
   }
 
-  private static Set<ProguardIfRule> createActiveIfRulesWithoutMembers(
-      Set<ProguardIfRule> ifRules) {
-    // 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.
-    Set<ProguardIfRule> activeIfRules = new LinkedHashSet<>(ifRules.size());
-    for (ProguardIfRule ifRule : ifRules) {
-      if (ifRule.getMemberRules().isEmpty()) {
-        activeIfRules.add(ifRule);
-      }
-    }
-    return activeIfRules;
-  }
-
   @SuppressWarnings("MixedMutabilityReturnType")
   private static Set<DexProgramClass> createEffectivelyFakeLiveClasses(
       AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {