Remove use of subtyping info in bridge hoisting

Change-Id: I101c9c44cfb2c3fe11b8ab25c4e125da34b7de1e
diff --git a/src/main/java/com/android/tools/r8/graph/BottomUpClassHierarchyTraversal.java b/src/main/java/com/android/tools/r8/graph/BottomUpClassHierarchyTraversal.java
index b2ecd15..4205abc 100644
--- a/src/main/java/com/android/tools/r8/graph/BottomUpClassHierarchyTraversal.java
+++ b/src/main/java/com/android/tools/r8/graph/BottomUpClassHierarchyTraversal.java
@@ -4,16 +4,18 @@
 
 package com.android.tools.r8.graph;
 
+import com.google.common.collect.Iterables;
+import java.util.Objects;
 import java.util.function.Function;
 
 public class BottomUpClassHierarchyTraversal<T extends DexClass>
     extends ClassHierarchyTraversal<T, BottomUpClassHierarchyTraversal<T>> {
 
-  private final Function<DexType, Iterable<DexType>> immediateSubtypesProvider;
+  private final Function<T, Iterable<T>> immediateSubtypesProvider;
 
   private BottomUpClassHierarchyTraversal(
       AppView<? extends AppInfoWithClassHierarchy> appView,
-      Function<DexType, Iterable<DexType>> immediateSubtypesProvider,
+      Function<T, Iterable<T>> immediateSubtypesProvider,
       Scope scope) {
     super(appView, scope);
     this.immediateSubtypesProvider = immediateSubtypesProvider;
@@ -26,16 +28,14 @@
   public static BottomUpClassHierarchyTraversal<DexClass> forAllClasses(
       AppView<? extends AppInfoWithClassHierarchy> appView, SubtypingInfo subtypingInfo) {
     return new BottomUpClassHierarchyTraversal<>(
-        appView, subtypingInfo::allImmediateSubtypes, 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 AppInfoWithClassHierarchy> appView, SubtypingInfo subtypingInfo) {
-    return forProgramClasses(appView, subtypingInfo::allImmediateSubtypes);
+        appView,
+        clazz ->
+            Iterables.filter(
+                Iterables.transform(
+                    subtypingInfo.allImmediateSubtypes(clazz.getType()),
+                    appView::contextIndependentDefinitionFor),
+                Objects::nonNull),
+        Scope.ALL_CLASSES);
   }
 
   /**
@@ -44,7 +44,17 @@
    */
   public static BottomUpClassHierarchyTraversal<DexProgramClass> forProgramClasses(
       AppView<? extends AppInfoWithClassHierarchy> appView,
-      Function<DexType, Iterable<DexType>> immediateSubtypesProvider) {
+      ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
+    return forProgramClasses(appView, immediateSubtypingInfo::getSubclasses);
+  }
+
+  /**
+   * 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 AppInfoWithClassHierarchy> appView,
+      Function<DexProgramClass, Iterable<DexProgramClass>> immediateSubtypesProvider) {
     return new BottomUpClassHierarchyTraversal<>(
         appView, immediateSubtypesProvider, Scope.ONLY_PROGRAM_CLASSES);
   }
@@ -70,12 +80,9 @@
     worklist.addFirst(clazzWithTypeT);
 
     // Add subtypes to worklist.
-    for (DexType subtype : immediateSubtypesProvider.apply(clazz.getType())) {
-      DexClass definition = definitionSupplier.contextIndependentDefinitionFor(subtype);
-      if (definition != null) {
-        if (scope != Scope.ONLY_PROGRAM_CLASSES || definition.isProgramClass()) {
-          addDependentsToWorklist(definition);
-        }
+    for (DexClass subclass : immediateSubtypesProvider.apply(clazzWithTypeT)) {
+      if (scope != Scope.ONLY_PROGRAM_CLASSES || subclass.isProgramClass()) {
+        addDependentsToWorklist(subclass);
       }
     }
   }
diff --git a/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java
index dace46c..1d27755 100644
--- a/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/SubtypingInfo.java
@@ -6,7 +6,6 @@
 import static com.android.tools.r8.graph.DexApplication.classesWithDeterministicOrder;
 
 import com.android.tools.r8.utils.structural.StructuralItem;
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -189,16 +188,6 @@
     return subtypes == null ? ImmutableSet.of() : subtypes;
   }
 
-  public DexType getSingleDirectSubtype(DexType type) {
-    TypeInfo info = getTypeInfo(type);
-    assert info.hierarchyLevel != SubtypingInfo.UNKNOWN_LEVEL;
-    if (info.directSubtypes.size() == 1) {
-      return Iterables.getFirst(info.directSubtypes, null);
-    } else {
-      return null;
-    }
-  }
-
   /**
    * Apply the given function to all classes that directly extend this class.
    *
@@ -223,25 +212,6 @@
     }
   }
 
-  /**
-   * Apply the given function to all classes that directly implement this interface.
-   *
-   * <p>The implementation does not consider how the hierarchy is encoded in the dex file, where
-   * interfaces "implement" their super interfaces. Instead it takes the view of the source
-   * language, where interfaces "extend" their superinterface.
-   */
-  public void forAllImmediateImplementsSubtypes(DexType type, Consumer<DexType> f) {
-    allImmediateImplementsSubtypes(type).forEach(f);
-  }
-
-  public Iterable<DexType> allImmediateImplementsSubtypes(DexType type) {
-    TypeInfo info = getTypeInfo(type);
-    if (info.hierarchyLevel == SubtypingInfo.INTERFACE_LEVEL) {
-      return Iterables.filter(info.directSubtypes, subtype -> !getTypeInfo(subtype).isInterface());
-    }
-    return ImmutableList.of();
-  }
-
   public Set<DexType> allImmediateSubtypes(DexType type) {
     return getTypeInfo(type).directSubtypes;
   }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 80b6dc7..9307f89 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -106,7 +106,13 @@
       Timing timing)
       throws ExecutionException {
     // Run the policies on all program classes to produce a final grouping.
-    List<Policy> policies = PolicyScheduler.getPolicies(appView, runtimeTypeCheckInfo);
+    ImmediateProgramSubtypingInfo immediateSubtypingInfo =
+        appView.enableWholeProgramOptimizations()
+            ? ImmediateProgramSubtypingInfo.createWithDeterministicOrder(
+                appView.withClassHierarchy())
+            : null;
+    List<Policy> policies =
+        PolicyScheduler.getPolicies(appView, immediateSubtypingInfo, runtimeTypeCheckInfo);
     Collection<HorizontalMergeGroup> groups =
         new HorizontalClassMergerPolicyExecutor()
             .run(getInitialGroups(), policies, executorService, timing);
@@ -127,11 +133,6 @@
 
     // Ensure that all allocations of classes that end up needing a class id use a constructor on
     // the class itself.
-    ImmediateProgramSubtypingInfo immediateSubtypingInfo =
-        appView.enableWholeProgramOptimizations()
-            ? ImmediateProgramSubtypingInfo.createWithDeterministicOrder(
-                appView.withClassHierarchy())
-            : null;
     new UndoConstructorInlining(appView, classMergerSharedData, immediateSubtypingInfo)
         .runIfNecessary(groups, executorService, timing);
 
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index 9e1a36e..cb7bda1 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -66,9 +66,12 @@
 public class PolicyScheduler {
 
   public static List<Policy> getPolicies(
-      AppView<?> appView, RuntimeTypeCheckInfo runtimeTypeCheckInfo) {
+      AppView<?> appView,
+      ImmediateProgramSubtypingInfo immediateSubtypingInfo,
+      RuntimeTypeCheckInfo runtimeTypeCheckInfo) {
     if (appView.hasClassHierarchy()) {
-      return getPoliciesForR8(appView.withClassHierarchy(), runtimeTypeCheckInfo);
+      return getPoliciesForR8(
+          appView.withClassHierarchy(), immediateSubtypingInfo, runtimeTypeCheckInfo);
     } else {
       return getPoliciesForD8(appView.withoutClassHierarchy());
     }
@@ -87,11 +90,12 @@
 
   private static List<Policy> getPoliciesForR8(
       AppView<? extends AppInfoWithClassHierarchy> appView,
+      ImmediateProgramSubtypingInfo immediateSubtypingInfo,
       RuntimeTypeCheckInfo runtimeTypeCheckInfo) {
     List<Policy> policies =
         ImmutableList.<Policy>builder()
             .addAll(getSingleClassPolicies(appView, runtimeTypeCheckInfo))
-            .addAll(getMultiClassPolicies(appView, runtimeTypeCheckInfo))
+            .addAll(getMultiClassPolicies(appView, immediateSubtypingInfo, runtimeTypeCheckInfo))
             .build();
     policies = appView.options().testing.horizontalClassMergingPolicyRewriter.apply(policies);
     assert verifyPolicyOrderingConstraints(policies);
@@ -195,6 +199,7 @@
 
   private static List<Policy> getMultiClassPolicies(
       AppView<? extends AppInfoWithClassHierarchy> appView,
+      ImmediateProgramSubtypingInfo immediateSubtypingInfo,
       RuntimeTypeCheckInfo runtimeTypeCheckInfo) {
     ImmutableList.Builder<Policy> builder = ImmutableList.builder();
     addRequiredMultiClassPolicies(appView, runtimeTypeCheckInfo, builder);
@@ -206,7 +211,7 @@
       builder.add(new PreserveMethodCharacteristics(appView.withLiveness()));
     }
     builder.add(new MinimizeInstanceFieldCasts());
-    addMultiClassPoliciesForInterfaceMerging(appView, builder);
+    addMultiClassPoliciesForInterfaceMerging(appView, immediateSubtypingInfo, builder);
     return builder.add(new LimitClassGroups(appView), new FinalizeMergeGroup(appView)).build();
   }
 
@@ -260,10 +265,11 @@
 
   private static void addMultiClassPoliciesForInterfaceMerging(
       AppView<? extends AppInfoWithClassHierarchy> appView,
+      ImmediateProgramSubtypingInfo immediateSubtypingInfo,
       ImmutableList.Builder<Policy> builder) {
     builder.add(
         new NoDefaultInterfaceMethodMerging(appView),
-        new NoDefaultInterfaceMethodCollisions(appView),
+        new NoDefaultInterfaceMethodCollisions(appView, immediateSubtypingInfo),
         new LimitInterfaceGroups(appView),
         new OnlyDirectlyConnectedOrUnrelatedInterfaces(appView));
   }
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDefaultInterfaceMethodCollisions.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDefaultInterfaceMethodCollisions.java
index 801db59..f66d516 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDefaultInterfaceMethodCollisions.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoDefaultInterfaceMethodCollisions.java
@@ -16,7 +16,7 @@
 import com.android.tools.r8.graph.DexMethodSignature;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.SubtypingInfo;
+import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
 import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
 import com.android.tools.r8.horizontalclassmerging.HorizontalMergeGroup;
 import com.android.tools.r8.horizontalclassmerging.MultiClassPolicyWithPreprocessing;
@@ -72,9 +72,13 @@
     extends MultiClassPolicyWithPreprocessing<Map<DexType, InterfaceInfo>> {
 
   private final AppView<? extends AppInfoWithClassHierarchy> appView;
+  private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
 
-  public NoDefaultInterfaceMethodCollisions(AppView<? extends AppInfoWithClassHierarchy> appView) {
+  public NoDefaultInterfaceMethodCollisions(
+      AppView<? extends AppInfoWithClassHierarchy> appView,
+      ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
     this.appView = appView;
+    this.immediateSubtypingInfo = immediateSubtypingInfo;
   }
 
   @Override
@@ -144,8 +148,7 @@
   @Override
   public Map<DexType, InterfaceInfo> preprocess(
       Collection<HorizontalMergeGroup> groups, ExecutorService executorService) {
-    SubtypingInfo subtypingInfo = SubtypingInfo.create(appView);
-    Collection<DexProgramClass> classesOfInterest = computeClassesOfInterest(subtypingInfo);
+    Collection<DexProgramClass> classesOfInterest = computeClassesOfInterest();
     Map<DexType, DexMethodSignatureSet> inheritedClassMethodsPerClass =
         computeInheritedClassMethodsPerProgramClass(classesOfInterest);
     Map<DexType, Map<DexMethodSignature, Set<DexMethod>>> inheritedDefaultMethodsPerClass =
@@ -156,7 +159,7 @@
     Map<DexType, Map<DexMethodSignature, Set<DexMethod>>>
         defaultMethodsInheritedBySubclassesPerClass =
             computeDefaultMethodsInheritedBySubclassesPerProgramClass(
-                classesOfInterest, inheritedDefaultMethodsPerClass, groups, subtypingInfo);
+                classesOfInterest, inheritedDefaultMethodsPerClass, groups, immediateSubtypingInfo);
 
     // Store the computed information for each interface that is subject to merging.
     Map<DexType, InterfaceInfo> infos = new IdentityHashMap<>();
@@ -176,8 +179,7 @@
   }
 
   /** Returns the set of program classes that must be considered during preprocessing. */
-  @SuppressWarnings("UnusedVariable")
-  private Collection<DexProgramClass> computeClassesOfInterest(SubtypingInfo subtypingInfo) {
+  private Collection<DexProgramClass> computeClassesOfInterest() {
     // TODO(b/173990042): Limit result to the set of classes that are in the same as one of
     //  the interfaces that is subject to merging.
     return appView.appInfo().classes();
@@ -275,13 +277,13 @@
           Collection<DexProgramClass> classesOfInterest,
           Map<DexType, Map<DexMethodSignature, Set<DexMethod>>> inheritedDefaultMethodsPerClass,
           Collection<HorizontalMergeGroup> groups,
-          SubtypingInfo subtypingInfo) {
+          ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
     // Build a mapping from class types to their merge group.
-    Map<DexType, Iterable<DexProgramClass>> classGroupsByType =
+    Map<DexProgramClass, Iterable<DexProgramClass>> classGroupsByClass =
         MapUtils.newIdentityHashMap(
             builder ->
                 Iterables.filter(groups, HorizontalMergeGroup::isClassGroup)
-                    .forEach(group -> group.forEach(clazz -> builder.put(clazz.getType(), group))));
+                    .forEach(group -> group.forEach(clazz -> builder.put(clazz, group))));
 
     // Copy the map from classes to their inherited default methods.
     Map<DexType, Map<DexMethodSignature, Set<DexMethod>>>
@@ -298,15 +300,15 @@
     // Therefore, it is important that we don't process any of A's supertypes until B has been
     // processed, since that would lead to inadequate upwards propagation. To achieve this, we
     // simulate that both A and B are subtypes of A's and B's supertypes.
-    Function<DexType, Iterable<DexType>> immediateSubtypesProvider =
-        type -> {
-          Set<DexType> immediateSubtypesAfterClassMerging = Sets.newIdentityHashSet();
-          for (DexType immediateSubtype : subtypingInfo.allImmediateSubtypes(type)) {
-            Iterable<DexProgramClass> group = classGroupsByType.get(immediateSubtype);
+    Function<DexProgramClass, Iterable<DexProgramClass>> immediateSubtypesProvider =
+        clazz -> {
+          Set<DexProgramClass> immediateSubtypesAfterClassMerging = Sets.newIdentityHashSet();
+          for (DexProgramClass immediateSubclass : immediateSubtypingInfo.getSubclasses(clazz)) {
+            Iterable<DexProgramClass> group = classGroupsByClass.get(immediateSubclass);
             if (group != null) {
-              group.forEach(member -> immediateSubtypesAfterClassMerging.add(member.getType()));
+              group.forEach(immediateSubtypesAfterClassMerging::add);
             } else {
-              immediateSubtypesAfterClassMerging.add(immediateSubtype);
+              immediateSubtypesAfterClassMerging.add(immediateSubclass);
             }
           }
           return immediateSubtypesAfterClassMerging;
@@ -321,7 +323,7 @@
                   defaultMethodsInheritedBySubclassesPerClass.getOrDefault(
                       clazz.getType(), emptyMap());
               Iterable<DexProgramClass> group =
-                  classGroupsByType.getOrDefault(clazz.getType(), IterableUtils.singleton(clazz));
+                  classGroupsByClass.getOrDefault(clazz, IterableUtils.singleton(clazz));
               for (DexProgramClass member : group) {
                 for (DexType supertype : member.allImmediateSupertypes()) {
                   Map<DexMethodSignature, Set<DexMethod>>
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
index 8e8fd00..185b0af 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -3,7 +3,6 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.optimize.bridgehoisting;
 
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.BottomUpClassHierarchyTraversal;
@@ -12,16 +11,16 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
 import com.android.tools.r8.graph.MethodAccessInfoCollection;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.SubtypingInfo;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
 import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
 import com.android.tools.r8.ir.optimize.info.bridge.VirtualBridgeInfo;
 import com.android.tools.r8.lightir.LirCode;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.base.Equivalence;
@@ -35,7 +34,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-import java.util.TreeSet;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 
@@ -80,10 +78,11 @@
 
   public void run(ExecutorService executorService, Timing timing) throws ExecutionException {
     timing.begin("Bridge hoisting");
-    SubtypingInfo subtypingInfo = appView.appInfo().computeSubtypingInfo();
-    BottomUpClassHierarchyTraversal.forProgramClasses(appView, subtypingInfo)
+    ImmediateProgramSubtypingInfo immediateSubtypingInfo =
+        ImmediateProgramSubtypingInfo.create(appView);
+    BottomUpClassHierarchyTraversal.forProgramClasses(appView, immediateSubtypingInfo)
         .excludeInterfaces()
-        .visit(appView.appInfo().classes(), clazz -> processClass(clazz, subtypingInfo));
+        .visit(appView.appInfo().classes(), clazz -> processClass(clazz, immediateSubtypingInfo));
     if (!result.isEmpty()) {
       BridgeHoistingLens lens = result.buildLens();
       appView.rewriteWithLens(lens, executorService, timing);
@@ -113,22 +112,23 @@
     timing.end();
   }
 
-  private void processClass(DexProgramClass clazz, SubtypingInfo subtypingInfo) {
-    Set<DexType> subtypes = subtypingInfo.allImmediateSubtypes(clazz.type);
-    Set<DexProgramClass> subclasses = new TreeSet<>(Comparator.comparing(DexClass::getType));
-    for (DexType subtype : subtypes) {
-      DexProgramClass subclass = asProgramClassOrNull(appView.definitionFor(subtype));
-      if (subclass == null || !appView.testing().isEligibleForBridgeHoisting.test(subclass)) {
-        continue;
+  private void processClass(
+      DexProgramClass clazz, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
+    List<DexProgramClass> subclasses =
+        ListUtils.sort(
+            immediateSubtypingInfo.getSubclasses(clazz), Comparator.comparing(DexClass::getType));
+    List<DexProgramClass> eligibleSubclasses = new ArrayList<>(subclasses.size());
+    for (DexProgramClass subclass : subclasses) {
+      if (appView.testing().isEligibleForBridgeHoisting.test(subclass)) {
+        eligibleSubclasses.add(subclass);
       }
-      subclasses.add(subclass);
     }
-    for (Wrapper<DexMethod> candidate : getCandidatesForHoisting(subclasses)) {
-      hoistBridgeIfPossible(candidate.get(), clazz, subclasses);
+    for (Wrapper<DexMethod> candidate : getCandidatesForHoisting(eligibleSubclasses)) {
+      hoistBridgeIfPossible(candidate.get(), clazz, eligibleSubclasses);
     }
   }
 
-  private Set<Wrapper<DexMethod>> getCandidatesForHoisting(Set<DexProgramClass> subclasses) {
+  private Set<Wrapper<DexMethod>> getCandidatesForHoisting(List<DexProgramClass> subclasses) {
     Equivalence<DexMethod> equivalence = MethodSignatureEquivalence.get();
     Set<Wrapper<DexMethod>> candidates = new HashSet<>();
     for (DexProgramClass subclass : subclasses) {
@@ -143,7 +143,7 @@
   }
 
   private void hoistBridgeIfPossible(
-      DexMethod method, DexProgramClass clazz, Set<DexProgramClass> subclasses) {
+      DexMethod method, DexProgramClass clazz, List<DexProgramClass> subclasses) {
     // If the method is defined on the parent class, we cannot hoist the bridge.
     // TODO(b/153147967): If the declared method is abstract, we could replace it by the bridge.
     //  Add a test.