Move implementedInterfaces to AppInfoWithClassHierarchy.

Change-Id: I8daf953f9cf5699ca967e9cc14ead23d01824d7e
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index 96fee36..6630f9c 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -5,8 +5,11 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
+import com.google.common.collect.Sets;
 import java.util.ArrayDeque;
+import java.util.Collections;
 import java.util.Deque;
+import java.util.Set;
 
 /* Specific subclass of AppInfo designed to support desugaring in D8. Desugaring requires a
  * minimal amount of knowledge in the overall program, provided through classpath. Basic
@@ -89,6 +92,57 @@
     return isSubtype(type, other) || isSubtype(other, type);
   }
 
+  /** Collect all interfaces that this type directly or indirectly implements. */
+  public Set<DexType> implementedInterfaces(DexType type) {
+    assert type.isClassType();
+    DexClass clazz = definitionFor(type);
+    if (clazz == null) {
+      return Collections.emptySet();
+    }
+
+    // Fast path for a type below object with no interfaces.
+    if (clazz.superType == dexItemFactory().objectType && clazz.interfaces.isEmpty()) {
+      return clazz.isInterface() ? Collections.singleton(type) : Collections.emptySet();
+    }
+
+    // Slow path traverses the full hierarchy.
+    Set<DexType> interfaces = Sets.newIdentityHashSet();
+    if (clazz.isInterface()) {
+      interfaces.add(type);
+    }
+    Deque<DexType> workList = new ArrayDeque<>();
+    if (clazz.superType != null && clazz.superType != dexItemFactory().objectType) {
+      workList.add(clazz.superType);
+    }
+    Collections.addAll(interfaces, clazz.interfaces.values);
+    Collections.addAll(workList, clazz.interfaces.values);
+    while (!workList.isEmpty()) {
+      DexType item = workList.pollFirst();
+      DexClass definition = definitionFor(item);
+      if (definition == null) {
+        // Collect missing types for future reporting?
+        continue;
+      }
+      if (definition.superType != null && definition.superType != dexItemFactory().objectType) {
+        workList.add(definition.superType);
+      }
+      for (DexType iface : definition.interfaces.values) {
+        if (interfaces.add(iface)) {
+          workList.add(iface);
+        }
+      }
+    }
+    return interfaces;
+  }
+
+  public boolean isExternalizable(DexType type) {
+    return isSubtype(type, dexItemFactory().externalizableType);
+  }
+
+  public boolean isSerializable(DexType type) {
+    return isSubtype(type, dexItemFactory().serializableType);
+  }
+
   /**
    * Helper method used for emulated interface resolution (not in JVM specifications). The result
    * may be abstract.
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
index 17e63e6..f04ba61 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithSubtyping.java
@@ -511,47 +511,6 @@
     return clazz == null || clazz.hasMissingSuperType(this);
   }
 
-  public boolean isExternalizable(DexType type) {
-    return implementedInterfaces(type).contains(dexItemFactory().externalizableType);
-  }
-
-  public boolean isSerializable(DexType type) {
-    return implementedInterfaces(type).contains(dexItemFactory().serializableType);
-  }
-
-  /** Collect all interfaces that this type directly or indirectly implements. */
-  public Set<DexType> implementedInterfaces(DexType type) {
-    TypeInfo info = getTypeInfo(type);
-    if (info.implementedInterfaces != null) {
-      return info.implementedInterfaces;
-    }
-    synchronized (this) {
-      if (info.implementedInterfaces == null) {
-        Set<DexType> interfaces = Sets.newIdentityHashSet();
-        implementedInterfaces(type, interfaces);
-        info.implementedInterfaces = interfaces;
-      }
-    }
-    return info.implementedInterfaces;
-  }
-
-  private void implementedInterfaces(DexType type, Set<DexType> interfaces) {
-    DexClass dexClass = definitionFor(type);
-    // Loop to traverse the super type hierarchy of the current type.
-    while (dexClass != null) {
-      if (dexClass.isInterface()) {
-        interfaces.add(dexClass.type);
-      }
-      for (DexType itf : dexClass.interfaces.values) {
-        implementedInterfaces(itf, interfaces);
-      }
-      if (dexClass.superType == null) {
-        break;
-      }
-      dexClass = definitionFor(dexClass.superType);
-    }
-  }
-
   public DexType getSingleSubtype(DexType type) {
     TypeInfo info = getTypeInfo(type);
     assert info.hierarchyLevel != UNKNOWN_LEVEL;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index d540b18..321b5c7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -779,11 +779,11 @@
     return isResolvable.isTrue();
   }
 
-  public boolean isSerializable(AppView<? extends AppInfoWithSubtyping> appView) {
+  public boolean isSerializable(AppView<? extends AppInfoWithClassHierarchy> appView) {
     return appView.appInfo().isSerializable(type);
   }
 
-  public boolean isExternalizable(AppView<? extends AppInfoWithSubtyping> appView) {
+  public boolean isExternalizable(AppView<? extends AppInfoWithClassHierarchy> appView) {
     return appView.appInfo().isExternalizable(type);
   }