Update root-set and if-rule evaluation to new threading module

Bug: b/304992619
Change-Id: I483136220189e10aba1bb16d4489185b002f3ed1
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 93268d1..16b3d76 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -22,8 +22,8 @@
 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;
 import com.android.tools.r8.utils.InternalOptions.TestingOptions.ProguardIfRuleEvaluationData;
-import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
@@ -36,7 +36,6 @@
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
 import java.util.stream.Collectors;
 
 public class IfRuleEvaluator {
@@ -44,10 +43,9 @@
   private final AppView<? extends AppInfoWithClassHierarchy> appView;
   private final SubtypingInfo subtypingInfo;
   private final Enqueuer enqueuer;
-  private final ExecutorService executorService;
-  private final List<Future<?>> futures = new ArrayList<>();
   private final Map<Wrapper<ProguardIfRule>, Set<ProguardIfRule>> ifRules;
   private final ConsequentRootSetBuilder rootSetBuilder;
+  private final TaskCollection<?> tasks;
 
   IfRuleEvaluator(
       AppView<? extends AppInfoWithClassHierarchy> appView,
@@ -59,9 +57,9 @@
     this.appView = appView;
     this.subtypingInfo = subtypingInfo;
     this.enqueuer = enqueuer;
-    this.executorService = executorService;
     this.ifRules = ifRules;
     this.rootSetBuilder = rootSetBuilder;
+    this.tasks = new TaskCollection<>(appView.options(), executorService);
   }
 
   public ConsequentRootSet run() throws ExecutionException {
@@ -96,17 +94,16 @@
               // When matching an if rule against a type, the if-rule are filled with the current
               // capture of wildcards. Propagate this down to member rules with same class part
               // equivalence.
-              ifRulesInEquivalence.forEach(
-                  ifRule -> {
-                    registerClassCapture(ifRule, clazz, clazz);
-                    if (appView.options().testing.measureProguardIfRuleEvaluations) {
-                      ifRuleEvaluationData.numberOfProguardIfRuleMemberEvaluations++;
-                    }
-                    boolean matched = evaluateIfRuleMembersAndMaterialize(ifRule, clazz, clazz);
-                    if (matched && canRemoveSubsequentKeepRule(ifRule)) {
-                      toRemove.add(ifRule);
-                    }
-                  });
+              for (ProguardIfRule ifRule : ifRulesInEquivalence) {
+                registerClassCapture(ifRule, clazz, clazz);
+                if (appView.options().testing.measureProguardIfRuleEvaluations) {
+                  ifRuleEvaluationData.numberOfProguardIfRuleMemberEvaluations++;
+                }
+                boolean matched = evaluateIfRuleMembersAndMaterialize(ifRule, clazz, clazz);
+                if (matched && canRemoveSubsequentKeepRule(ifRule)) {
+                  toRemove.add(ifRule);
+                }
+              }
             }
 
             // Check if one of the types that have been merged into `clazz` satisfies the if-rule.
@@ -131,17 +128,16 @@
                   ifRuleEvaluationData.numberOfProguardIfRuleClassEvaluations++;
                 }
                 if (evaluateClassForIfRule(ifRuleKey, sourceClass)) {
-                  ifRulesInEquivalence.forEach(
-                      ifRule -> {
-                        registerClassCapture(ifRule, sourceClass, clazz);
-                        if (appView.options().testing.measureProguardIfRuleEvaluations) {
-                          ifRuleEvaluationData.numberOfProguardIfRuleMemberEvaluations++;
-                        }
-                        if (evaluateIfRuleMembersAndMaterialize(ifRule, sourceClass, clazz)
-                            && canRemoveSubsequentKeepRule(ifRule)) {
-                          toRemove.add(ifRule);
-                        }
-                      });
+                  for (ProguardIfRule ifRule : ifRulesInEquivalence) {
+                    registerClassCapture(ifRule, sourceClass, clazz);
+                    if (appView.options().testing.measureProguardIfRuleEvaluations) {
+                      ifRuleEvaluationData.numberOfProguardIfRuleMemberEvaluations++;
+                    }
+                    if (evaluateIfRuleMembersAndMaterialize(ifRule, sourceClass, clazz)
+                        && canRemoveSubsequentKeepRule(ifRule)) {
+                      toRemove.add(ifRule);
+                    }
+                  }
                 }
               }
             }
@@ -152,7 +148,7 @@
             ifRulesInEquivalence.removeAll(toRemove);
           }
         }
-        ThreadUtils.awaitFutures(futures);
+        tasks.await();
       }
     } finally {
       appView.appInfo().app().timing.end();
@@ -226,7 +222,7 @@
 
   @SuppressWarnings("ReferenceEquality")
   private boolean evaluateIfRuleMembersAndMaterialize(
-      ProguardIfRule rule, DexClass sourceClass, DexClass targetClass) {
+      ProguardIfRule rule, DexClass sourceClass, DexClass targetClass) throws ExecutionException {
     Collection<ProguardMemberRule> memberKeepRules = rule.getMemberRules();
     if (memberKeepRules.isEmpty()) {
       materializeIfRule(rule, ImmutableSet.of(sourceClass.getReference()));
@@ -327,7 +323,8 @@
   }
 
   @SuppressWarnings("BadImport")
-  private void materializeIfRule(ProguardIfRule rule, Set<DexReference> preconditions) {
+  private void materializeIfRule(ProguardIfRule rule, Set<DexReference> preconditions)
+      throws ExecutionException {
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     ProguardIfRule materializedRule = rule.materialize(dexItemFactory, preconditions);
 
@@ -337,14 +334,13 @@
       ClassInlineRule neverClassInlineRuleForCondition =
           materializedRule.neverClassInlineRuleForCondition(dexItemFactory);
       if (neverClassInlineRuleForCondition != null) {
-        rootSetBuilder.runPerRule(executorService, futures, neverClassInlineRuleForCondition, null);
+        rootSetBuilder.runPerRule(tasks, neverClassInlineRuleForCondition, null);
       }
 
       InlineRule neverInlineForClassInliningRuleForCondition =
           materializedRule.neverInlineRuleForCondition(dexItemFactory, Type.NEVER_CLASS_INLINE);
       if (neverInlineForClassInliningRuleForCondition != null) {
-        rootSetBuilder.runPerRule(
-            executorService, futures, neverInlineForClassInliningRuleForCondition, null);
+        rootSetBuilder.runPerRule(tasks, neverInlineForClassInliningRuleForCondition, null);
       }
 
       // If the condition of the -if rule has any members, then we need to keep these members to
@@ -353,20 +349,19 @@
       InlineRule neverInlineRuleForCondition =
           materializedRule.neverInlineRuleForCondition(dexItemFactory, Type.NEVER);
       if (neverInlineRuleForCondition != null) {
-        rootSetBuilder.runPerRule(executorService, futures, neverInlineRuleForCondition, null);
+        rootSetBuilder.runPerRule(tasks, neverInlineRuleForCondition, null);
       }
 
       // Prevent horizontal class merging of any -if rule members.
       NoHorizontalClassMergingRule noHorizontalClassMergingRule =
           materializedRule.noHorizontalClassMergingRuleForCondition(dexItemFactory);
       if (noHorizontalClassMergingRule != null) {
-        rootSetBuilder.runPerRule(executorService, futures, noHorizontalClassMergingRule, null);
+        rootSetBuilder.runPerRule(tasks, noHorizontalClassMergingRule, null);
       }
     }
 
     // Keep whatever is required by the -if rule.
-    rootSetBuilder.runPerRule(
-        executorService, futures, materializedRule.subsequentRule, materializedRule);
+    rootSetBuilder.runPerRule(tasks, materializedRule.subsequentRule, materializedRule);
     rule.markAsUsed();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 74c0ada..1e8f56d 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -62,6 +62,7 @@
 import com.android.tools.r8.shaking.EnqueuerEvent.LiveClassEnqueuerEvent;
 import com.android.tools.r8.shaking.EnqueuerEvent.UnconditionalKeepInfoEvent;
 import com.android.tools.r8.shaking.KeepInfo.Joiner;
+import com.android.tools.r8.threading.TaskCollection;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
@@ -69,7 +70,6 @@
 import com.android.tools.r8.utils.PredicateSet;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
-import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.android.tools.r8.utils.collections.ProgramMethodMap;
@@ -100,7 +100,6 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
@@ -324,11 +323,8 @@
       }
     }
 
-    void runPerRule(
-        ExecutorService executorService,
-        List<Future<?>> futures,
-        ProguardConfigurationRule rule,
-        ProguardIfRule ifRule) {
+    void runPerRule(TaskCollection<?> tasks, ProguardConfigurationRule rule, ProguardIfRule ifRule)
+        throws ExecutionException {
       List<DexType> specifics = rule.getClassNames().asSpecificDexTypes();
       if (specifics != null) {
         // This keep rule only lists specific type matches.
@@ -343,25 +339,24 @@
         return;
       }
 
-      futures.add(
-          executorService.submit(
-              () -> {
-                for (DexProgramClass clazz :
-                    rule.relevantCandidatesForRule(appView, subtypingInfo, application.classes())) {
-                  process(clazz, rule, ifRule);
-                }
-                if (rule.applyToNonProgramClasses()) {
-                  for (DexLibraryClass clazz : application.libraryClasses()) {
-                    process(clazz, rule, ifRule);
-                  }
-                }
-              }));
+      tasks.submit(
+          () -> {
+            for (DexProgramClass clazz :
+                rule.relevantCandidatesForRule(appView, subtypingInfo, application.classes())) {
+              process(clazz, rule, ifRule);
+            }
+            if (rule.applyToNonProgramClasses()) {
+              for (DexLibraryClass clazz : application.libraryClasses()) {
+                process(clazz, rule, ifRule);
+              }
+            }
+          });
     }
 
     public RootSet build(ExecutorService executorService) throws ExecutionException {
       application.timing.begin("Build root set...");
       try {
-        List<Future<?>> futures = new ArrayList<>();
+        TaskCollection<?> tasks = new TaskCollection<>(options, executorService);
         // Mark all the things explicitly listed in keep rules.
         if (rules != null) {
           for (ProguardConfigurationRule rule : rules) {
@@ -369,10 +364,10 @@
               ProguardIfRule ifRule = (ProguardIfRule) rule;
               ifRules.add(ifRule);
             } else {
-              runPerRule(executorService, futures, rule, null);
+              runPerRule(tasks, rule, null);
             }
           }
-          ThreadUtils.awaitFutures(futures);
+          tasks.await();
         }
       } finally {
         application.timing.end();