Misc. utils for new access modifier

Change-Id: I4dea7ab9efac3c80f72a9f55c0127508c44533cb
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index ee86680..54fecaa 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -236,6 +236,10 @@
     return self();
   }
 
+  public boolean isPromotedFromPrivateToPublic() {
+    return isDemoted(Constants.ACC_PRIVATE) && isPromoted(Constants.ACC_PUBLIC);
+  }
+
   public boolean isPromotedToPublic() {
     return isPromoted(Constants.ACC_PUBLIC);
   }
@@ -277,6 +281,10 @@
     modifiedFlags &= ~flag;
   }
 
+  protected boolean isDemoted(int flag) {
+    return wasSet(flag) && !isSet(flag);
+  }
+
   protected boolean isPromoted(int flag) {
     return !wasSet(flag) && isSet(flag);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index aff2b31..4eff317 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -41,6 +41,7 @@
 import com.android.tools.r8.shaking.AssumeInfoCollection;
 import com.android.tools.r8.shaking.KeepClassInfo;
 import com.android.tools.r8.shaking.KeepFieldInfo;
+import com.android.tools.r8.shaking.KeepInfo;
 import com.android.tools.r8.shaking.KeepInfoCollection;
 import com.android.tools.r8.shaking.KeepMethodInfo;
 import com.android.tools.r8.shaking.LibraryModeledPredicate;
@@ -679,6 +680,15 @@
     return keepInfo;
   }
 
+  public KeepInfo<?, ?> getKeepInfo(ProgramDefinition definition) {
+    return definition
+        .getReference()
+        .apply(
+            clazz -> getKeepInfo(definition.asProgramClass()),
+            field -> getKeepInfo(definition.asProgramField()),
+            method -> getKeepInfo(definition.asProgramMethod()));
+  }
+
   public KeepClassInfo getKeepInfo(DexProgramClass clazz) {
     return getKeepInfo().getClassInfo(clazz);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java b/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
index 521d6c7..8b9a38b 100644
--- a/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/ImmediateProgramSubtypingInfo.java
@@ -9,6 +9,7 @@
 import static com.google.common.base.Predicates.alwaysTrue;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.List;
@@ -32,8 +33,18 @@
 
   public static ImmediateProgramSubtypingInfo create(
       AppView<? extends AppInfoWithClassHierarchy> appView) {
+    return internalCreate(appView, appView.appInfo().classes());
+  }
+
+  public static ImmediateProgramSubtypingInfo createWithDeterministicOrder(
+      AppView<? extends AppInfoWithClassHierarchy> appView) {
+    return internalCreate(appView, appView.appInfo().classesWithDeterministicOrder());
+  }
+
+  private static ImmediateProgramSubtypingInfo internalCreate(
+      AppView<? extends AppInfoWithClassHierarchy> appView, Collection<DexProgramClass> classes) {
     Map<DexProgramClass, List<DexProgramClass>> immediateSubtypes = new IdentityHashMap<>();
-    for (DexProgramClass clazz : appView.appInfo().classes()) {
+    for (DexProgramClass clazz : classes) {
       clazz.forEachImmediateSupertype(
           supertype -> {
             DexProgramClass superclass = asProgramClassOrNull(appView.definitionFor(supertype));
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
index 24c8b0a..77d8fbd 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -372,7 +372,7 @@
       DexEncodedMethod method = directMethods[i];
       DexEncodedMethod newMethod = replacement.apply(method);
       assert newMethod != null;
-      if (method != newMethod) {
+      if (method != newMethod || !method.belongsToDirectPool()) {
         if (belongsToDirectPool(newMethod)) {
           directMethods[i] = newMethod;
         } else {
@@ -404,7 +404,7 @@
     for (int i = 0; i < virtualMethods.length; i++) {
       DexEncodedMethod method = virtualMethods[i];
       DexEncodedMethod newMethod = replacement.apply(method);
-      if (method != newMethod) {
+      if (method != newMethod || !method.belongsToVirtualPool()) {
         if (belongsToVirtualPool(newMethod)) {
           virtualMethods[i] = newMethod;
         } else {
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
index a31e669..47d8a02 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -269,6 +269,13 @@
     backing.replaceMethods(replacement);
   }
 
+  @SuppressWarnings("unchecked")
+  public <T extends DexClassAndMethod> void replaceClassAndMethods(
+      Function<T, DexEncodedMethod> replacement) {
+    assert holder.isProgramClass();
+    replaceMethods(method -> replacement.apply((T) DexClassAndMethod.create(holder, method)));
+  }
+
   public void replaceDirectMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
     resetDirectMethodCaches();
     backing.replaceDirectMethods(replacement);
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index c998cf6..d09475d 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -287,7 +287,7 @@
     void accept(T item, int index);
   }
 
-  public static <T> List<T> sort(List<T> items, Comparator<T> comparator) {
+  public static <T> List<T> sort(Collection<T> items, Comparator<T> comparator) {
     List<T> sorted = new ArrayList<>(items);
     sorted.sort(comparator);
     return sorted;
diff --git a/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureMap.java b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureMap.java
index 5289f92..bbf5afb 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/DexMethodSignatureMap.java
@@ -4,10 +4,12 @@
 
 package com.android.tools.r8.utils.collections;
 
+import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexMethodSignature;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.Map;
@@ -28,10 +30,18 @@
     return new DexMethodSignatureMap<>(new HashMap<>());
   }
 
+  public static <T> DexMethodSignatureMap<T> create(DexMethodSignatureMap<T> map) {
+    return new DexMethodSignatureMap<>(new HashMap<>(map.backing));
+  }
+
   public static <T> DexMethodSignatureMap<T> createLinked() {
     return new DexMethodSignatureMap<>(new LinkedHashMap<>());
   }
 
+  public static <T> DexMethodSignatureMap<T> empty() {
+    return new DexMethodSignatureMap<>(Collections.emptyMap());
+  }
+
   @Override
   public T put(DexMethodSignature signature, T value) {
     return backing.put(signature, value);
@@ -100,6 +110,11 @@
     return backing.replace(key, value);
   }
 
+  public T computeIfAbsent(
+      DexClassAndMethod key, Function<? super DexMethodSignature, ? extends T> mappingFunction) {
+    return computeIfAbsent(key.getMethodSignature(), mappingFunction);
+  }
+
   @Override
   public T computeIfAbsent(
       DexMethodSignature key, Function<? super DexMethodSignature, ? extends T> mappingFunction) {