Parallelize preprocessing for argument propagation
Change-Id: I3d0de595f438c6bf32fe1aec31c35628e1708d50
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index a1d1e2a..c00f43c 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -659,7 +659,7 @@
// Setup the argument propagator for the primary optimization pass.
appView.withArgumentPropagator(
- argumentPropagator -> argumentPropagator.initializeCodeScanner(timing));
+ argumentPropagator -> argumentPropagator.initializeCodeScanner(executorService, timing));
appView.withCallSiteOptimizationInfoPropagator(
optimization -> {
optimization.abandonCallSitePropagationForLambdaImplementationMethods(
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index f8edd1e..2173883 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.optimize.argumentpropagation;
+import static com.android.tools.r8.optimize.argumentpropagation.utils.StronglyConnectedProgramClasses.computeStronglyConnectedProgramClasses;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -18,7 +20,10 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.VirtualRootMethodsAnalysis;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import java.util.List;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -50,7 +55,8 @@
* Called by {@link IRConverter} *before* the primary optimization pass to setup the scanner for
* collecting argument information from the code objects.
*/
- public void initializeCodeScanner(Timing timing) {
+ public void initializeCodeScanner(ExecutorService executorService, Timing timing)
+ throws ExecutionException {
assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
timing.begin("Argument propagator");
@@ -58,20 +64,25 @@
codeScanner = new ArgumentPropagatorCodeScanner(appView);
- // Disable argument propagation for methods that should not be optimized.
ImmediateProgramSubtypingInfo immediateSubtypingInfo =
ImmediateProgramSubtypingInfo.create(appView);
+ List<Set<DexProgramClass>> stronglyConnectedProgramClasses =
+ computeStronglyConnectedProgramClasses(appView, immediateSubtypingInfo);
+ ThreadUtils.processItems(
+ stronglyConnectedProgramClasses,
+ classes -> {
+ // Disable argument propagation for methods that should not be optimized by setting their
+ // method state to unknown.
+ new ArgumentPropagatorUnoptimizableMethods(
+ appView, immediateSubtypingInfo, codeScanner.getMethodStates())
+ .disableArgumentPropagationForUnoptimizableMethods(classes);
- // TODO(b/190154391): Consider computing the strongly connected components and running this in
- // parallel for each scc.
- new ArgumentPropagatorUnoptimizableMethods(
- appView, immediateSubtypingInfo, codeScanner.getMethodStates())
- .disableArgumentPropagationForUnoptimizableMethods(appView.appInfo().classes());
-
- // TODO(b/190154391): Consider computing the strongly connected components and running this in
- // parallel for each scc.
- new VirtualRootMethodsAnalysis(appView, immediateSubtypingInfo)
- .extendVirtualRootMethods(appView.appInfo().classes(), codeScanner);
+ // Compute the mapping from virtual methods to their root virtual method and the set of
+ // monomorphic virtual methods.
+ new VirtualRootMethodsAnalysis(appView, immediateSubtypingInfo)
+ .extendVirtualRootMethods(appView.appInfo().classes(), codeScanner);
+ },
+ executorService);
timing.end();
timing.end();
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
index 4548f35..6d4f3b7 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.optimize.argumentpropagation;
+import static com.android.tools.r8.optimize.argumentpropagation.utils.StronglyConnectedProgramClasses.computeStronglyConnectedProgramClasses;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -25,9 +27,6 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.utils.WorkList;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -56,40 +55,7 @@
ImmediateProgramSubtypingInfo.create(appView);
this.immediateSubtypingInfo = immediateSubtypingInfo;
this.stronglyConnectedComponents =
- computeStronglyConnectedComponents(appView, immediateSubtypingInfo);
- }
-
- /**
- * Computes the strongly connected components in the program class hierarchy (where extends and
- * implements edges are treated as bidirectional).
- *
- * <p>All strongly connected components can be processed in parallel.
- */
- private static List<Set<DexProgramClass>> computeStronglyConnectedComponents(
- AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
- Set<DexProgramClass> seen = Sets.newIdentityHashSet();
- List<Set<DexProgramClass>> stronglyConnectedComponents = new ArrayList<>();
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- if (seen.contains(clazz)) {
- continue;
- }
- Set<DexProgramClass> stronglyConnectedComponent =
- computeStronglyConnectedComponent(clazz, immediateSubtypingInfo);
- stronglyConnectedComponents.add(stronglyConnectedComponent);
- seen.addAll(stronglyConnectedComponent);
- }
- return stronglyConnectedComponents;
- }
-
- private static Set<DexProgramClass> computeStronglyConnectedComponent(
- DexProgramClass clazz, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
- WorkList<DexProgramClass> worklist = WorkList.newIdentityWorkList(clazz);
- while (worklist.hasNext()) {
- DexProgramClass current = worklist.next();
- immediateSubtypingInfo.forEachImmediateProgramSuperClass(current, worklist::addIfNotSeen);
- worklist.addIfNotSeen(immediateSubtypingInfo.getSubclasses(current));
- }
- return worklist.getSeenSet();
+ computeStronglyConnectedProgramClasses(appView, immediateSubtypingInfo);
}
/**
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/StronglyConnectedProgramClasses.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/StronglyConnectedProgramClasses.java
new file mode 100644
index 0000000..25d28cb
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/utils/StronglyConnectedProgramClasses.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2021, 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.optimize.argumentpropagation.utils;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.WorkList;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class StronglyConnectedProgramClasses {
+
+ /**
+ * Computes the strongly connected components in the program class hierarchy (where extends and
+ * implements edges are treated as bidirectional).
+ */
+ public static List<Set<DexProgramClass>> computeStronglyConnectedProgramClasses(
+ AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
+ Set<DexProgramClass> seen = Sets.newIdentityHashSet();
+ List<Set<DexProgramClass>> stronglyConnectedComponents = new ArrayList<>();
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ if (seen.contains(clazz)) {
+ continue;
+ }
+ Set<DexProgramClass> stronglyConnectedComponent =
+ internalComputeStronglyConnectedProgramClasses(clazz, immediateSubtypingInfo);
+ stronglyConnectedComponents.add(stronglyConnectedComponent);
+ seen.addAll(stronglyConnectedComponent);
+ }
+ return stronglyConnectedComponents;
+ }
+
+ private static Set<DexProgramClass> internalComputeStronglyConnectedProgramClasses(
+ DexProgramClass clazz, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
+ WorkList<DexProgramClass> worklist = WorkList.newIdentityWorkList(clazz);
+ while (worklist.hasNext()) {
+ DexProgramClass current = worklist.next();
+ immediateSubtypingInfo.forEachImmediateProgramSuperClass(current, worklist::addIfNotSeen);
+ worklist.addIfNotSeen(immediateSubtypingInfo.getSubclasses(current));
+ }
+ return worklist.getSeenSet();
+ }
+}