Introduce bottom up class hierarchy traversal
Change-Id: I48069d622131cd2bf4b43c998015af74cfbd003c
diff --git a/src/main/java/com/android/tools/r8/graph/BottomUpClassHierarchyTraversal.java b/src/main/java/com/android/tools/r8/graph/BottomUpClassHierarchyTraversal.java
new file mode 100644
index 0000000..80f3d93
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/BottomUpClassHierarchyTraversal.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2019, 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.graph;
+
+public class BottomUpClassHierarchyTraversal<T extends DexClass>
+ extends ClassHierarchyTraversal<T> {
+
+ private BottomUpClassHierarchyTraversal(
+ AppView<? extends AppInfoWithSubtyping> appView, Scope scope) {
+ super(appView, scope);
+ }
+
+ /**
+ * Returns a visitor that can be used to visit all the classes (including class path and library
+ * classes) that are reachable from a given set of sources.
+ */
+ public static BottomUpClassHierarchyTraversal<DexClass> forAllClasses(
+ AppView<? extends AppInfoWithSubtyping> appView) {
+ return new BottomUpClassHierarchyTraversal<>(appView, Scope.ALL_CLASSES);
+ }
+
+ /**
+ * Returns a visitor that can be used to visit all the program classes that are reachable from a
+ * given set of sources.
+ */
+ public static BottomUpClassHierarchyTraversal<DexProgramClass> forProgramClasses(
+ AppView<? extends AppInfoWithSubtyping> appView) {
+ return new BottomUpClassHierarchyTraversal<>(appView, Scope.ONLY_PROGRAM_CLASSES);
+ }
+
+ @Override
+ void addDependentsToWorklist(DexClass clazz) {
+ @SuppressWarnings("unchecked")
+ T clazzWithTypeT = (T) clazz;
+
+ if (visited.contains(clazzWithTypeT)) {
+ return;
+ }
+
+ worklist.addFirst(clazzWithTypeT);
+
+ // Add subtypes to worklist.
+ for (DexType subtype : appView.appInfo().allImmediateSubtypes(clazz.type)) {
+ DexClass definition = appView.definitionFor(subtype);
+ if (definition != null) {
+ if (scope != Scope.ONLY_PROGRAM_CLASSES || definition.isProgramClass()) {
+ addDependentsToWorklist(definition);
+ }
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ClassHierarchyTraversal.java b/src/main/java/com/android/tools/r8/graph/ClassHierarchyTraversal.java
new file mode 100644
index 0000000..eb21910
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ClassHierarchyTraversal.java
@@ -0,0 +1,62 @@
+// Copyright (c) 2019, 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.graph;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.function.Consumer;
+
+abstract class ClassHierarchyTraversal<T extends DexClass> {
+
+ enum Scope {
+ ALL_CLASSES,
+ ONLY_PROGRAM_CLASSES
+ }
+
+ final AppView<? extends AppInfoWithSubtyping> appView;
+ final Scope scope;
+
+ final Set<T> visited = new HashSet<>();
+ final Deque<T> worklist = new ArrayDeque<>();
+
+ ClassHierarchyTraversal(AppView<? extends AppInfoWithSubtyping> appView, Scope scope) {
+ this.appView = appView;
+ this.scope = scope;
+ }
+
+ public void visit(Iterable<DexProgramClass> sources, Consumer<T> visitor) {
+ Iterator<DexProgramClass> sourceIterator = sources.iterator();
+
+ // Visit the program classes in the order that is implemented by addDependentsToWorklist().
+ while (sourceIterator.hasNext() || !worklist.isEmpty()) {
+ if (worklist.isEmpty()) {
+ // Add the dependents of the next source (including the source itself) to the worklist.
+ // The order in which the dependents are added to the worklist is used to determine the
+ // traversal order (e.g., top-down, bottom-up).
+ addDependentsToWorklist(sourceIterator.next());
+ if (worklist.isEmpty()) {
+ continue;
+ }
+ }
+
+ T clazz = worklist.removeFirst();
+ if (visited.add(clazz)) {
+ assert scope != Scope.ONLY_PROGRAM_CLASSES || clazz.isProgramClass();
+ visitor.accept(clazz);
+ }
+ }
+
+ visited.clear();
+ }
+
+ // The traversal order is dependent on the order in which addDependentsToWorklist() enqueues
+ // classes into the worklist. For example, to implement a top-down class hierarchy, this method
+ // should add all super types of `clazz` to the worklist before adding `clazz` itself to the
+ // worklist.
+ abstract void addDependentsToWorklist(DexClass clazz);
+}
diff --git a/src/main/java/com/android/tools/r8/graph/TopDownClassHierarchyTraversal.java b/src/main/java/com/android/tools/r8/graph/TopDownClassHierarchyTraversal.java
index 14c98e4..9e7fbe4 100644
--- a/src/main/java/com/android/tools/r8/graph/TopDownClassHierarchyTraversal.java
+++ b/src/main/java/com/android/tools/r8/graph/TopDownClassHierarchyTraversal.java
@@ -4,29 +4,11 @@
package com.android.tools.r8.graph;
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.function.Consumer;
+public class TopDownClassHierarchyTraversal<T extends DexClass> extends ClassHierarchyTraversal<T> {
-public class TopDownClassHierarchyTraversal<T extends DexClass> {
-
- private enum Scope {
- ALL_CLASSES,
- ONLY_PROGRAM_CLASSES
- }
-
- private final DexDefinitionSupplier definitions;
- private final Scope scope;
-
- private final Set<T> visited = new HashSet<>();
- private final Deque<T> worklist = new ArrayDeque<>();
-
- private TopDownClassHierarchyTraversal(DexDefinitionSupplier definitions, Scope scope) {
- this.definitions = definitions;
- this.scope = scope;
+ private TopDownClassHierarchyTraversal(
+ AppView<? extends AppInfoWithSubtyping> appView, Scope scope) {
+ super(appView, scope);
}
/**
@@ -34,8 +16,8 @@
* classes) that are reachable from a given set of sources.
*/
public static TopDownClassHierarchyTraversal<DexClass> forAllClasses(
- DexDefinitionSupplier definitions) {
- return new TopDownClassHierarchyTraversal<>(definitions, Scope.ALL_CLASSES);
+ AppView<? extends AppInfoWithSubtyping> appView) {
+ return new TopDownClassHierarchyTraversal<>(appView, Scope.ALL_CLASSES);
}
/**
@@ -43,35 +25,12 @@
* given set of sources.
*/
public static TopDownClassHierarchyTraversal<DexProgramClass> forProgramClasses(
- DexDefinitionSupplier definitions) {
- return new TopDownClassHierarchyTraversal<>(definitions, Scope.ONLY_PROGRAM_CLASSES);
+ AppView<? extends AppInfoWithSubtyping> appView) {
+ return new TopDownClassHierarchyTraversal<>(appView, Scope.ONLY_PROGRAM_CLASSES);
}
- public void visit(Iterable<DexProgramClass> sources, Consumer<T> visitor) {
- Iterator<DexProgramClass> sourceIterator = sources.iterator();
-
- // Visit the program classes in a top-down order according to the class hierarchy.
- while (sourceIterator.hasNext() || !worklist.isEmpty()) {
- if (worklist.isEmpty()) {
- // Add the ancestors of the next source (including the source itself) to the worklist in
- // such a way that all super types of the source class come before the class itself.
- addAncestorsToWorklist(sourceIterator.next());
- if (worklist.isEmpty()) {
- continue;
- }
- }
-
- T clazz = worklist.removeFirst();
- if (visited.add(clazz)) {
- assert scope != Scope.ONLY_PROGRAM_CLASSES || clazz.isProgramClass();
- visitor.accept(clazz);
- }
- }
-
- visited.clear();
- }
-
- private void addAncestorsToWorklist(DexClass clazz) {
+ @Override
+ void addDependentsToWorklist(DexClass clazz) {
@SuppressWarnings("unchecked")
T clazzWithTypeT = (T) clazz;
@@ -83,20 +42,20 @@
// Add super classes to worklist.
if (clazz.superType != null) {
- DexClass definition = definitions.definitionFor(clazz.superType);
+ DexClass definition = appView.definitionFor(clazz.superType);
if (definition != null) {
if (scope != Scope.ONLY_PROGRAM_CLASSES || definition.isProgramClass()) {
- addAncestorsToWorklist(definition);
+ addDependentsToWorklist(definition);
}
}
}
// Add super interfaces to worklist.
for (DexType interfaceType : clazz.interfaces.values) {
- DexClass definition = definitions.definitionFor(interfaceType);
+ DexClass definition = appView.definitionFor(interfaceType);
if (definition != null) {
if (scope != Scope.ONLY_PROGRAM_CLASSES || definition.isProgramClass()) {
- addAncestorsToWorklist(definition);
+ addDependentsToWorklist(definition);
}
}
}