Introduce a new main resolveMethod function.

This CL also introduces resolve variants for known defintions and rewrites such
call sites.

Change-Id: Ie6627e6e12c0a58828c26aa05f0fc4ab6871691f
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 7e83700..648efbe 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -245,12 +245,12 @@
 
   /**
    * Implements resolution of a method descriptor against a target type.
-   * <p>
-   * This method will query the definition of the holder to decide on which resolution to use. If
+   *
+   * <p>This method will query the definition of the holder to decide on which resolution to use. If
    * the holder is an interface, it delegates to {@link #resolveMethodOnInterface(DexType,
    * DexMethod)}, otherwise {@link #resolveMethodOnClass(DexType, DexMethod)} is used.
-   * <p>
-   * This is to overcome the shortcoming of the DEX file format that does not allow to encode the
+   *
+   * <p>This is to overcome the shortcoming of the DEX file format that does not allow to encode the
    * kind of a method reference.
    */
   public ResolutionResult resolveMethod(DexType holder, DexMethod method) {
@@ -263,18 +263,36 @@
       return ResolutionResult.EmptyResult.get();
     }
     return definition.isInterface()
+        ? resolveMethodOnInterface(definition, method)
+        : resolveMethodOnClass(definition, method);
+  }
+
+  /**
+   * Implements resolution of a method descriptor against a target type.
+   *
+   * <p>The boolean isInterface parameter denotes if the method reference is an interface method
+   * reference, and if so method resolution is done according to interface method resolution.
+   *
+   * @param holder Type at which to initiate the resolution.
+   * @param method Method descriptor for resolution (the field method.holder is ignored).
+   * @param isInterface Indicates if resolution is to be done according to class or interface.
+   * @return The result of resolution.
+   */
+  public ResolutionResult resolveMethod(DexType holder, DexMethod method, boolean isInterface) {
+    assert checkIfObsolete();
+    return isInterface
         ? resolveMethodOnInterface(holder, method)
         : resolveMethodOnClass(holder, method);
   }
 
   /**
    * Implements resolution of a method descriptor against an array type.
-   * <p>See <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.7">
-   * Section 10.7 of the Java Language Specification</a>.
-   * </p>
-   * All invokations will have target java.lang.Object except clone which has no target.
+   *
+   * <p>See <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.7">Section
+   * 10.7 of the Java Language Specification</a>. All invokations will have target java.lang.Object
+   * except clone which has no target.
    */
-  public ResolutionResult resolveMethodOnArray(DexType holder, DexMethod method) {
+  private ResolutionResult resolveMethodOnArray(DexType holder, DexMethod method) {
     assert checkIfObsolete();
     assert holder.isArrayType();
     if (method.name == dexItemFactory.cloneMethodName) {
@@ -305,6 +323,12 @@
     if (clazz == null || clazz.isInterface()) {
       return ResolutionResult.EmptyResult.get();
     }
+    return resolveMethodOnClass(clazz, method);
+  }
+
+  public ResolutionResult resolveMethodOnClass(DexClass clazz, DexMethod method) {
+    assert checkIfObsolete();
+    assert !clazz.isInterface();
     // Step 2:
     DexEncodedMethod singleTarget = resolveMethodOnClassStep2(clazz, method);
     if (singleTarget != null) {
@@ -425,6 +449,9 @@
    */
   public ResolutionResult resolveMethodOnInterface(DexType holder, DexMethod desc) {
     assert checkIfObsolete();
+    if (holder.isArrayType()) {
+      return ResolutionResult.EmptyResult.get();
+    }
     // Step 1: Lookup interface.
     DexClass definition = definitionFor(holder);
     // If the definition is not an interface, resolution fails with an ICCE. We just return the
@@ -432,6 +459,12 @@
     if (definition == null || !definition.isInterface()) {
       return ResolutionResult.EmptyResult.get();
     }
+    return resolveMethodOnInterface(definition, desc);
+  }
+
+  public ResolutionResult resolveMethodOnInterface(DexClass definition, DexMethod desc) {
+    assert checkIfObsolete();
+    assert definition.isInterface();
     // Step 2: Look for exact method on interface.
     DexEncodedMethod result = definition.lookupMethod(desc);
     if (result != null) {
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index 23bcc18..4aeae4e 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -33,7 +33,7 @@
     for (DexType type : appInfo.subtypes(method.holder)) {
       DexClass clazz = appInfo.definitionFor(type);
       if (!clazz.isInterface()) {
-        ResolutionResult methods = appInfo.resolveMethodOnClass(type, method);
+        ResolutionResult methods = appInfo.resolveMethodOnClass(clazz, method);
         methods.forEachTarget(
             target -> {
               if (target.isVirtualMethod()) {
@@ -102,10 +102,10 @@
     for (DexType type : set) {
       DexClass clazz = appInfo.definitionFor(type);
       if (clazz.isInterface()) {
-        ResolutionResult targetMethods = appInfo.resolveMethodOnInterface(type, method);
+        ResolutionResult targetMethods = appInfo.resolveMethodOnInterface(clazz, method);
         targetMethods.forEachTarget(addIfNotAbstractAndBridge);
       } else {
-        ResolutionResult targetMethods = appInfo.resolveMethodOnClass(type, method);
+        ResolutionResult targetMethods = appInfo.resolveMethodOnClass(clazz, method);
         targetMethods.forEachTarget(addIfNotAbstract);
       }
     }
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
index 9a68feb..2322b7b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
@@ -184,19 +184,17 @@
         }
       }
 
+      boolean isInterface = type == Type.INTERFACE;
       Set<DexEncodedMethod> possibleTargets =
           possibleTargetsCache.computeIfAbsent(
               target,
-              method ->
-                  type == Type.INTERFACE
-                      ? appView
-                          .appInfo()
-                          .resolveMethodOnInterface(method.holder, method)
-                          .lookupInterfaceTargets(appView.appInfo())
-                      : appView
-                          .appInfo()
-                          .resolveMethodOnClass(method.holder, method)
-                          .lookupVirtualTargets(appView.appInfo()));
+              method -> {
+                ResolutionResult resolution =
+                    appView.appInfo().resolveMethod(method.holder, method, isInterface);
+                return isInterface
+                    ? resolution.lookupInterfaceTargets(appView.appInfo())
+                    : resolution.lookupVirtualTargets(appView.appInfo());
+              });
       if (possibleTargets != null) {
         boolean likelySpuriousCallEdge =
             possibleTargets.size() >= appView.options().callGraphLikelySpuriousCallEdgeThreshold;
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 5a18e61..ee9d779 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
@@ -1477,11 +1477,11 @@
   private boolean hasNonTrivialFinalizeMethod(DexType type) {
     DexClass clazz = appView.definitionFor(type);
     if (clazz != null) {
-      if (clazz.isProgramClass()) {
+      if (clazz.isProgramClass() && !clazz.isInterface()) {
         ResolutionResult resolutionResult =
             appView
                 .appInfo()
-                .resolveMethodOnClass(type, appView.dexItemFactory().objectMethods.finalize);
+                .resolveMethodOnClass(clazz, appView.dexItemFactory().objectMethods.finalize);
         for (DexEncodedMethod target : resolutionResult.asListOfTargets()) {
           if (target.method != appView.dexItemFactory().objectMethods.finalize) {
             return true;
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index dd955ed..03978ed 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1019,7 +1019,7 @@
     }
     // First check that there is a target for this invoke-interface to hit. If there is none,
     // this will fail at runtime.
-    ResolutionResult topTarget = resolveMethodOnInterface(method.holder, method);
+    ResolutionResult topTarget = resolveMethodOnInterface(holder, method);
     if (topTarget.asResultOfResolve() == null) {
       return null;
     }
@@ -1049,7 +1049,7 @@
         // override them, so we ignore interface methods here. Otherwise, we would look up
         // default methods that are factually never used.
       } else if (!clazz.accessFlags.isAbstract()) {
-        ResolutionResult resolutionResult = resolveMethodOnClass(type, method);
+        ResolutionResult resolutionResult = resolveMethodOnClass(clazz, method);
         if (resolutionResult.hasSingleTarget()) {
           if ((result != null) && (result != resolutionResult.asSingleTarget())) {
             return null;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 2c6d4e5..2bf674b 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1716,9 +1716,7 @@
   private DexEncodedMethod findAndMarkResolutionTarget(
       DexMethod method, boolean interfaceInvoke, KeepReason reason) {
     DexEncodedMethod resolutionTarget =
-        interfaceInvoke
-            ? appInfo.resolveMethodOnInterface(method.holder, method).asResultOfResolve()
-            : appInfo.resolveMethodOnClass(method.holder, method).asResultOfResolve();
+        appInfo.resolveMethod(method.holder, method, interfaceInvoke).asResultOfResolve();
     if (resolutionTarget == null) {
       reportMissingMethod(method);
       return null;
@@ -1760,9 +1758,9 @@
       DexClass resolutionTargetClass) {
     while (resolutionTarget.isPrivateMethod() || resolutionTarget.isStatic()) {
       resolutionTarget =
-          (resolutionTargetClass.isInterface()
-                  ? appInfo.resolveMethodOnInterface(resolutionTargetClass.superType, method)
-                  : appInfo.resolveMethodOnClass(resolutionTargetClass.superType, method))
+          appInfo
+              .resolveMethod(
+                  resolutionTargetClass.superType, method, resolutionTargetClass.isInterface())
               .asResultOfResolve();
       if (resolutionTarget == null) {
         return;
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
index e9e836b..c2a5c6a 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -60,17 +60,13 @@
 
     // Check lookup targets with include method.
     Set<DexEncodedMethod> targets =
-        appInfo
-            .resolveMethodOnClass(method.method.holder, method.method)
-            .lookupVirtualTargets(appInfo);
+        appInfo.resolveMethodOnClass(clazz, method.method).lookupVirtualTargets(appInfo);
     assertTrue(targets.contains(method));
   }
 
   private void testInterfaceLookup(DexProgramClass clazz, DexEncodedMethod method) {
     Set<DexEncodedMethod> targets =
-        appInfo
-            .resolveMethodOnInterface(method.method.holder, method.method)
-            .lookupInterfaceTargets(appInfo);
+        appInfo.resolveMethodOnInterface(clazz, method.method).lookupInterfaceTargets(appInfo);
     if (appInfo.subtypes(method.method.holder).stream()
         .allMatch(t -> appInfo.definitionFor(t).isInterface())) {
       assertEquals(