Update threading in AppInfoWithLiveness
This is the last usage of futures outside the threading module
structures.
Bug: b/304992619
Change-Id: Ie9e16321461c9a07a69ab3009b9a37936cd822d3
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 56c1ea4..43ce750 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -64,11 +64,11 @@
import com.android.tools.r8.repackaging.RepackagingUtils;
import com.android.tools.r8.shaking.KeepInfo.Joiner;
import com.android.tools.r8.synthesis.CommittedItems;
+import com.android.tools.r8.threading.TaskCollection;
import com.android.tools.r8.utils.CollectionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.PredicateSet;
-import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Visibility;
import com.android.tools.r8.utils.WorkList;
@@ -80,7 +80,6 @@
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import java.util.ArrayDeque;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
@@ -89,7 +88,6 @@
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.stream.Collectors;
@@ -322,49 +320,46 @@
}
private AppInfoWithLiveness(
- AppInfoWithLiveness previous,
- PrunedItems prunedItems,
- ExecutorService executorService,
- List<Future<?>> futures) {
+ AppInfoWithLiveness previous, PrunedItems prunedItems, TaskCollection<?> tasks)
+ throws ExecutionException {
this(
previous.getSyntheticItems().commitPrunedItems(prunedItems),
previous.getClassToFeatureSplitMap().withoutPrunedItems(prunedItems),
previous.getMainDexInfo().withoutPrunedItems(prunedItems),
previous.getMissingClasses(),
previous.deadProtoTypes,
- pruneClasses(previous.liveTypes, prunedItems, executorService, futures),
- pruneMethods(previous.targetedMethods, prunedItems, executorService, futures),
- pruneClasses(previous.failedClassResolutionTargets, prunedItems, executorService, futures),
- pruneMethods(previous.failedMethodResolutionTargets, prunedItems, executorService, futures),
- pruneFields(previous.failedFieldResolutionTargets, prunedItems, executorService, futures),
- pruneMethods(previous.bootstrapMethods, prunedItems, executorService, futures),
- pruneMethods(
- previous.virtualMethodsTargetedByInvokeDirect, prunedItems, executorService, futures),
- pruneMethods(previous.liveMethods, prunedItems, executorService, futures),
+ pruneClasses(previous.liveTypes, prunedItems, tasks),
+ pruneMethods(previous.targetedMethods, prunedItems, tasks),
+ pruneClasses(previous.failedClassResolutionTargets, prunedItems, tasks),
+ pruneMethods(previous.failedMethodResolutionTargets, prunedItems, tasks),
+ pruneFields(previous.failedFieldResolutionTargets, prunedItems, tasks),
+ pruneMethods(previous.bootstrapMethods, prunedItems, tasks),
+ pruneMethods(previous.virtualMethodsTargetedByInvokeDirect, prunedItems, tasks),
+ pruneMethods(previous.liveMethods, prunedItems, tasks),
previous.fieldAccessInfoCollection,
previous.methodAccessInfoCollection.withoutPrunedItems(prunedItems),
previous.objectAllocationInfoCollection.withoutPrunedItems(prunedItems),
pruneCallSites(previous.callSites, prunedItems),
extendPinnedItems(previous, prunedItems.getAdditionalPinnedItems()),
previous.mayHaveSideEffects,
- pruneMethods(previous.alwaysInline, prunedItems, executorService, futures),
- pruneMethods(previous.neverInlineDueToSingleCaller, prunedItems, executorService, futures),
- pruneMethods(previous.whyAreYouNotInlining, prunedItems, executorService, futures),
- pruneMethods(previous.reprocess, prunedItems, executorService, futures),
- pruneMethods(previous.neverReprocess, prunedItems, executorService, futures),
+ pruneMethods(previous.alwaysInline, prunedItems, tasks),
+ pruneMethods(previous.neverInlineDueToSingleCaller, prunedItems, tasks),
+ pruneMethods(previous.whyAreYouNotInlining, prunedItems, tasks),
+ pruneMethods(previous.reprocess, prunedItems, tasks),
+ pruneMethods(previous.neverReprocess, prunedItems, tasks),
previous.alwaysClassInline,
- pruneClasses(previous.neverClassInline, prunedItems, executorService, futures),
- pruneClasses(previous.noClassMerging, prunedItems, executorService, futures),
- pruneClasses(previous.noVerticalClassMerging, prunedItems, executorService, futures),
- pruneClasses(previous.noHorizontalClassMerging, prunedItems, executorService, futures),
- pruneMembers(previous.neverPropagateValue, prunedItems, executorService, futures),
- pruneMapFromMembers(previous.identifierNameStrings, prunedItems, executorService, futures),
+ pruneClasses(previous.neverClassInline, prunedItems, tasks),
+ pruneClasses(previous.noClassMerging, prunedItems, tasks),
+ pruneClasses(previous.noVerticalClassMerging, prunedItems, tasks),
+ pruneClasses(previous.noHorizontalClassMerging, prunedItems, tasks),
+ pruneMembers(previous.neverPropagateValue, prunedItems, tasks),
+ pruneMapFromMembers(previous.identifierNameStrings, prunedItems, tasks),
prunedItems.hasRemovedClasses()
? CollectionUtils.mergeSets(previous.prunedTypes, prunedItems.getRemovedClasses())
: previous.prunedTypes,
previous.switchMaps,
- pruneClasses(previous.lockCandidates, prunedItems, executorService, futures),
- pruneMapFromClasses(previous.initClassReferences, prunedItems, executorService, futures),
+ pruneClasses(previous.lockCandidates, prunedItems, tasks),
+ pruneMapFromClasses(previous.initClassReferences, prunedItems, tasks),
previous.recordFieldValuesReferences);
}
@@ -386,114 +381,91 @@
}
private static Set<DexType> pruneClasses(
- Set<DexType> methods,
- PrunedItems prunedItems,
- ExecutorService executorService,
- List<Future<?>> futures) {
- return pruneItems(methods, prunedItems.getRemovedClasses(), executorService, futures);
+ Set<DexType> methods, PrunedItems prunedItems, TaskCollection<?> tasks)
+ throws ExecutionException {
+ return pruneItems(methods, prunedItems.getRemovedClasses(), tasks);
}
private static Set<DexField> pruneFields(
- Set<DexField> fields,
- PrunedItems prunedItems,
- ExecutorService executorService,
- List<Future<?>> futures) {
- return pruneItems(fields, prunedItems.getRemovedFields(), executorService, futures);
+ Set<DexField> fields, PrunedItems prunedItems, TaskCollection<?> tasks)
+ throws ExecutionException {
+ return pruneItems(fields, prunedItems.getRemovedFields(), tasks);
}
private static Set<DexMember<?, ?>> pruneMembers(
- Set<DexMember<?, ?>> members,
- PrunedItems prunedItems,
- ExecutorService executorService,
- List<Future<?>> futures) {
+ Set<DexMember<?, ?>> members, PrunedItems prunedItems, TaskCollection<?> tasks)
+ throws ExecutionException {
if (prunedItems.hasRemovedMembers()) {
- futures.add(
- ThreadUtils.processAsynchronously(
- () -> {
- Set<DexField> removedFields = prunedItems.getRemovedFields();
- Set<DexMethod> removedMethods = prunedItems.getRemovedMethods();
- if (members.size() <= removedFields.size() + removedMethods.size()) {
- members.removeIf(
- member ->
- member.isDexField()
- ? removedFields.contains(member.asDexField())
- : removedMethods.contains(member.asDexMethod()));
- } else {
- removedFields.forEach(members::remove);
- removedMethods.forEach(members::remove);
- }
- },
- executorService));
+ tasks.submit(
+ () -> {
+ Set<DexField> removedFields = prunedItems.getRemovedFields();
+ Set<DexMethod> removedMethods = prunedItems.getRemovedMethods();
+ if (members.size() <= removedFields.size() + removedMethods.size()) {
+ members.removeIf(
+ member ->
+ member.isDexField()
+ ? removedFields.contains(member.asDexField())
+ : removedMethods.contains(member.asDexMethod()));
+ } else {
+ removedFields.forEach(members::remove);
+ removedMethods.forEach(members::remove);
+ }
+ });
}
return members;
}
private static Set<DexMethod> pruneMethods(
- Set<DexMethod> methods,
- PrunedItems prunedItems,
- ExecutorService executorService,
- List<Future<?>> futures) {
- return pruneItems(methods, prunedItems.getRemovedMethods(), executorService, futures);
+ Set<DexMethod> methods, PrunedItems prunedItems, TaskCollection<?> tasks)
+ throws ExecutionException {
+ return pruneItems(methods, prunedItems.getRemovedMethods(), tasks);
}
- private static <T> Set<T> pruneItems(
- Set<T> items, Set<T> removedItems, ExecutorService executorService, List<Future<?>> futures) {
+ private static <T> Set<T> pruneItems(Set<T> items, Set<T> removedItems, TaskCollection<?> tasks)
+ throws ExecutionException {
if (!isThrowingSet(items) && !removedItems.isEmpty()) {
- futures.add(
- ThreadUtils.processAsynchronously(
- () -> {
- if (items.size() <= removedItems.size()) {
- items.removeAll(removedItems);
- } else {
- removedItems.forEach(items::remove);
- }
- },
- executorService));
+ tasks.submit(
+ () -> {
+ if (items.size() <= removedItems.size()) {
+ items.removeAll(removedItems);
+ } else {
+ removedItems.forEach(items::remove);
+ }
+ });
}
return items;
}
private static <V> Map<DexType, V> pruneMapFromClasses(
- Map<DexType, V> map,
- PrunedItems prunedItems,
- ExecutorService executorService,
- List<Future<?>> futures) {
- return pruneMap(map, prunedItems.getRemovedClasses(), executorService, futures);
+ Map<DexType, V> map, PrunedItems prunedItems, TaskCollection<?> tasks)
+ throws ExecutionException {
+ return pruneMap(map, prunedItems.getRemovedClasses(), tasks);
}
private static Object2BooleanMap<DexMember<?, ?>> pruneMapFromMembers(
- Object2BooleanMap<DexMember<?, ?>> map,
- PrunedItems prunedItems,
- ExecutorService executorService,
- List<Future<?>> futures) {
+ Object2BooleanMap<DexMember<?, ?>> map, PrunedItems prunedItems, TaskCollection<?> tasks)
+ throws ExecutionException {
if (prunedItems.hasRemovedMembers()) {
- futures.add(
- ThreadUtils.processAsynchronously(
- () -> {
- prunedItems.getRemovedFields().forEach(map::removeBoolean);
- prunedItems.getRemovedMethods().forEach(map::removeBoolean);
- },
- executorService));
+ tasks.submit(
+ () -> {
+ prunedItems.getRemovedFields().forEach(map::removeBoolean);
+ prunedItems.getRemovedMethods().forEach(map::removeBoolean);
+ });
}
return map;
}
private static <K, V> Map<K, V> pruneMap(
- Map<K, V> map,
- Set<K> removedItems,
- ExecutorService executorService,
- List<Future<?>> futures) {
+ Map<K, V> map, Set<K> removedItems, TaskCollection<?> tasks) throws ExecutionException {
if (!removedItems.isEmpty()) {
- futures.add(
- ThreadUtils.processAsynchronously(
- () -> {
- if (map.size() <= removedItems.size()) {
- map.keySet().removeAll(removedItems);
- } else {
- removedItems.forEach(map::remove);
- }
- },
- executorService));
+ tasks.submit(
+ () -> {
+ if (map.size() <= removedItems.size()) {
+ map.keySet().removeAll(removedItems);
+ } else {
+ removedItems.forEach(map::remove);
+ }
+ });
}
return map;
}
@@ -1183,10 +1155,9 @@
} else if (prunedItems.hasRemovedMembers()) {
keepInfo.mutate(keepInfo -> keepInfo.removeKeepInfoForPrunedItems(prunedItems));
}
- List<Future<?>> futures = new ArrayList<>();
- AppInfoWithLiveness appInfoWithLiveness =
- new AppInfoWithLiveness(this, prunedItems, executorService, futures);
- ThreadUtils.awaitFutures(futures);
+ TaskCollection<?> tasks = new TaskCollection<>(options(), executorService);
+ AppInfoWithLiveness appInfoWithLiveness = new AppInfoWithLiveness(this, prunedItems, tasks);
+ tasks.await();
timing.end();
return appInfoWithLiveness;
}
diff --git a/src/main/java/com/android/tools/r8/utils/ThreadUtils.java b/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
index 9c8f6e7..8a28293 100644
--- a/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ThreadUtils.java
@@ -9,14 +9,11 @@
import com.android.tools.r8.threading.ThreadingModule;
import com.android.tools.r8.utils.ListUtils.ReferenceAndIntConsumer;
import java.util.Collection;
-import java.util.Iterator;
import java.util.Map;
-import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ForkJoinPool;
-import java.util.concurrent.Future;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -51,26 +48,6 @@
public static final int NOT_SPECIFIED = -1;
- public static <T> Future<T> processAsynchronously(
- Action action, ExecutorService executorService) {
- return processAsynchronously(
- () -> {
- action.execute();
- return null;
- },
- executorService);
- }
-
- public static <T> void processAsynchronously(
- Action action, ExecutorService executorService, Collection<Future<T>> futures) {
- futures.add(processAsynchronously(action, executorService));
- }
-
- public static <T> Future<T> processAsynchronously(
- Callable<T> callable, ExecutorService executorService) {
- return executorService.submit(callable);
- }
-
public static <T, R, E extends Exception> Collection<R> processItemsWithResults(
Iterable<T> items,
ThrowingFunction<T, R, E> consumer,
@@ -237,29 +214,6 @@
executorService);
}
- public static void awaitFutures(Iterable<? extends Future<?>> futures)
- throws ExecutionException {
- Iterator<? extends Future<?>> futureIterator = futures.iterator();
- try {
- while (futureIterator.hasNext()) {
- futureIterator.next().get();
- }
- } catch (InterruptedException e) {
- throw new RuntimeException("Interrupted while waiting for future.", e);
- } finally {
- // In case we get interrupted or one of the threads throws an exception, still wait for all
- // further work to make sure synchronization guarantees are met. Calling cancel unfortunately
- // does not guarantee that the task at hand actually terminates before cancel returns.
- while (futureIterator.hasNext()) {
- try {
- futureIterator.next().get();
- } catch (Throwable t) {
- // Ignore any new Exception.
- }
- }
- }
- }
-
static ExecutorService getExecutorServiceForProcessors(int processors) {
// This heuristic is based on measurements on a 32 core (hyper-threaded) machine.
int threads = processors <= 2 ? processors : (int) Math.ceil(Integer.min(processors, 16) / 2.0);
diff --git a/src/main/java/com/android/tools/r8/utils/threads/FutureBox.java b/src/main/java/com/android/tools/r8/utils/threads/FutureBox.java
deleted file mode 100644
index c69c7fa..0000000
--- a/src/main/java/com/android/tools/r8/utils/threads/FutureBox.java
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2023, 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.threads;
-
-import com.android.tools.r8.errors.Unimplemented;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-
-public class FutureBox<T> implements Future<T> {
-
- private final T value;
-
- public FutureBox(T value) {
- this.value = value;
- }
-
- @Override
- public boolean cancel(boolean mayInterruptIfRunning) {
- throw new Unimplemented();
- }
-
- @Override
- public boolean isCancelled() {
- throw new Unimplemented();
- }
-
- @Override
- public boolean isDone() {
- throw new Unimplemented();
- }
-
- @Override
- public T get() {
- return value;
- }
-
- @Override
- public T get(long timeout, TimeUnit unit) {
- return value;
- }
-}