Update threading in distributor and member pool collection
This removes dead code from the member pool to avoid a dead use of
threading.
Bug: b/304992619
Change-Id: I7bcb3ff848a85ae40fb4bdbe658b51742ad6c0c3
diff --git a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
index 4d10674..dc79a46 100644
--- a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
+++ b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
@@ -10,8 +10,8 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.threading.TaskCollection;
import com.android.tools.r8.utils.IntBox;
-import com.android.tools.r8.utils.ThreadUtils;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.BitSet;
@@ -27,7 +27,6 @@
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
/**
* Partition classes among dex files to limit LinearAlloc usage during DexOpt.
@@ -538,12 +537,14 @@
}
private void updateGroupsNumberOfIds(List<ClassGroup> groups) {
- Collection<Future<?>> updateIdsTasks = new ArrayList<>(groups.size());
- for (ClassGroup group : groups) {
- updateIdsTasks.add(executorService.submit(group::updateNumbersOfIds));
- }
+ TaskCollection<?> updateIdsTasks =
+ new TaskCollection<>(
+ appView.options().getThreadingModule(), executorService, groups.size());
try {
- ThreadUtils.awaitFutures(updateIdsTasks);
+ for (ClassGroup group : groups) {
+ updateIdsTasks.submit(group::updateNumbersOfIds);
+ }
+ updateIdsTasks.await();
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberPoolCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberPoolCollection.java
index bd0376b..a4ccb28 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberPoolCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberPoolCollection.java
@@ -6,29 +6,22 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexMember;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.threading.TaskCollection;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.utils.UncheckedExecutionException;
import com.android.tools.r8.utils.WorkList;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Deque;
import java.util.HashSet;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
import java.util.function.BiFunction;
-import java.util.function.Predicate;
// Per-class collection of member signatures.
public abstract class MemberPoolCollection<R extends DexMember<?, R>> {
@@ -49,36 +42,22 @@
public void buildAll(ExecutorService executorService, Timing timing) throws ExecutionException {
timing.begin("Building member pool collection");
+ // Generate a future for each class that will build the member pool collection for the
+ // corresponding class. Note that, we visit the classes using a top-down class hierarchy
+ // traversal, since this ensures that we do not visit library classes that are not
+ // reachable from any program class.
+ TaskCollection<?> tasks = new TaskCollection<>(appView.options(), executorService);
try {
- List<Future<?>> futures = new ArrayList<>();
-
- // Generate a future for each class that will build the member pool collection for the
- // corresponding class. Note that, we visit the classes using a top-down class hierarchy
- // traversal, since this ensures that we do not visit library classes that are not
- // reachable from any program class.
TopDownClassHierarchyTraversal.forAllClasses(appView)
- .visit(appView.appInfo().classes(), clazz -> submit(clazz, futures, executorService));
- ThreadUtils.awaitFutures(futures);
- } finally {
- timing.end();
+ .visit(
+ appView.appInfo().classes(),
+ clazz -> tasks.submitUnchecked(() -> computeMemberPoolForClass(clazz).run()));
+ tasks.await();
+ } catch (UncheckedExecutionException e) {
+ throw e.rethrow();
}
}
- public MemberPool<R> buildForHierarchy(
- DexClass clazz, ExecutorService executorService, Timing timing) throws ExecutionException {
- timing.begin("Building member pool collection");
- try {
- List<Future<?>> futures = new ArrayList<>();
- submitAll(
- getAllSuperTypesInclusive(clazz, memberPools::containsKey), futures, executorService);
- submitAll(getAllSubTypesExclusive(clazz, memberPools::containsKey), futures, executorService);
- ThreadUtils.awaitFutures(futures);
- } finally {
- timing.end();
- }
- return get(clazz);
- }
-
public boolean hasPool(DexClass clazz) {
return memberPools.containsKey(clazz);
}
@@ -98,66 +77,8 @@
return false;
}
- private void submitAll(
- Iterable<? extends DexClass> classes,
- List<Future<?>> futures,
- ExecutorService executorService) {
- for (DexClass clazz : classes) {
- submit(clazz, futures, executorService);
- }
- }
-
- private void submit(DexClass clazz, List<Future<?>> futures, ExecutorService executorService) {
- futures.add(executorService.submit(computeMemberPoolForClass(clazz)));
- }
-
abstract Runnable computeMemberPoolForClass(DexClass clazz);
- private Set<DexClass> getAllSuperTypesInclusive(
- DexClass subject, Predicate<DexClass> stoppingCriterion) {
- Set<DexClass> superTypes = new HashSet<>();
- Deque<DexClass> worklist = new ArrayDeque<>();
- worklist.add(subject);
- while (!worklist.isEmpty()) {
- DexClass clazz = worklist.pop();
- if (stoppingCriterion.test(clazz)) {
- continue;
- }
- if (superTypes.add(clazz)) {
- if (clazz.superType != null) {
- addNonNull(worklist, appView.definitionFor(clazz.superType));
- }
- for (DexType interfaceType : clazz.interfaces.values) {
- addNonNull(worklist, appView.definitionFor(interfaceType));
- }
- }
- }
- return superTypes;
- }
-
- private Set<DexClass> getAllSubTypesExclusive(
- DexClass subject, Predicate<DexClass> stoppingCriterion) {
- Set<DexClass> subTypes = new HashSet<>();
- Deque<DexClass> worklist = new ArrayDeque<>();
- subtypingInfo.forAllImmediateExtendsSubtypes(
- subject.type, type -> addNonNull(worklist, appView.definitionFor(type)));
- subtypingInfo.forAllImmediateImplementsSubtypes(
- subject.type, type -> addNonNull(worklist, appView.definitionFor(type)));
- while (!worklist.isEmpty()) {
- DexClass clazz = worklist.pop();
- if (stoppingCriterion.test(clazz)) {
- continue;
- }
- if (subTypes.add(clazz)) {
- subtypingInfo.forAllImmediateExtendsSubtypes(
- clazz.type, type -> addNonNull(worklist, appView.definitionFor(type)));
- subtypingInfo.forAllImmediateImplementsSubtypes(
- clazz.type, type -> addNonNull(worklist, appView.definitionFor(type)));
- }
- }
- return subTypes;
- }
-
public static class MemberPool<T> {
private final DexClass clazz;
@@ -200,18 +121,6 @@
return fold(member, false, true, (t, ignored) -> true);
}
- public boolean hasSeenDirectly(Wrapper<T> member) {
- return here(member, false, (t, ignored) -> true);
- }
-
- public boolean hasSeenStrictlyAbove(Wrapper<T> member) {
- return above(member, false, false, true, (t, ignored) -> true);
- }
-
- public boolean hasSeenStrictlyBelow(Wrapper<T> member) {
- return below(member, false, true, (t, ignored) -> true);
- }
-
private <S> S above(
Wrapper<T> member,
boolean inclusive,
@@ -267,10 +176,4 @@
return below(member, initialValue, terminator, accumulator);
}
}
-
- private static <T> void addNonNull(Collection<T> collection, T item) {
- if (item != null) {
- collection.add(item);
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
index 78eb343..3b5d81f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MethodPoolCollection.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
-import com.google.common.base.Predicates;
import java.util.function.Predicate;
// Per-class collection of method signatures.
@@ -27,10 +26,6 @@
private final Predicate<DexEncodedMethod> methodTester;
- public MethodPoolCollection(AppView<AppInfoWithLiveness> appView, SubtypingInfo subtypingInfo) {
- this(appView, subtypingInfo, Predicates.alwaysTrue());
- }
-
public MethodPoolCollection(
AppView<AppInfoWithLiveness> appView,
SubtypingInfo subtypingInfo,
diff --git a/src/main/java/com/android/tools/r8/threading/TaskCollection.java b/src/main/java/com/android/tools/r8/threading/TaskCollection.java
index 11a64bb..8ef8168 100644
--- a/src/main/java/com/android/tools/r8/threading/TaskCollection.java
+++ b/src/main/java/com/android/tools/r8/threading/TaskCollection.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThrowingAction;
+import com.android.tools.r8.utils.UncheckedExecutionException;
import com.google.common.util.concurrent.Futures;
import java.util.ArrayList;
import java.util.List;
@@ -20,16 +21,21 @@
private final ThreadingModule threadingModule;
private final ExecutorService executorService;
+ private final List<Future<T>> futures;
- private final List<Future<T>> futures = new ArrayList<>();
-
- public TaskCollection(ThreadingModule threadingModule, ExecutorService executorService) {
+ public TaskCollection(
+ ThreadingModule threadingModule, ExecutorService executorService, int initialCapacity) {
this.threadingModule = threadingModule;
this.executorService = executorService;
+ this.futures = initialCapacity > 0 ? new ArrayList<>(initialCapacity) : new ArrayList<>();
+ }
+
+ public TaskCollection(ThreadingModule threadingModule, ExecutorService executorService) {
+ this(threadingModule, executorService, -1);
}
public TaskCollection(InternalOptions options, ExecutorService executorService) {
- this(options.getThreadingModule(), executorService);
+ this(options.getThreadingModule(), executorService, -1);
}
/**
@@ -99,6 +105,24 @@
});
}
+ /** Derived submit to hide the execution exception */
+ public final void submitUnchecked(Callable<T> task) {
+ try {
+ submit(task);
+ } catch (ExecutionException e) {
+ throw new UncheckedExecutionException(e);
+ }
+ }
+
+ /** Derived submit to hide the execution exception */
+ public final <E extends Exception> void submitUnchecked(ThrowingAction<E> task) {
+ try {
+ submit(task);
+ } catch (ExecutionException e) {
+ throw new UncheckedExecutionException(e);
+ }
+ }
+
/** Derived await when no results are needed. */
public final void await() throws ExecutionException {
await(null);