Cleanup mapping from invoke-special to IR

Bug: 201984767
Change-Id: I90b4fbcf252f95a1b3b1ab22959bc7a8ad84fe19
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index fa8b01a..e98923a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.cf.CfPrinter;
 import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.CfCode;
@@ -15,7 +14,6 @@
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.GraphLens;
@@ -34,7 +32,6 @@
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.ir.optimize.InliningConstraints;
 import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.structural.CompareToVisitor;
 import com.android.tools.r8.utils.structural.StructuralSpecification;
 import java.util.Arrays;
@@ -248,7 +245,7 @@
           canonicalMethod = method;
           type =
               computeInvokeTypeForInvokeSpecial(
-                  builder.appView, method, code.getOriginalHolder(), code.getOrigin());
+                  builder.appView, method, builder.getProgramMethod(), code.getOriginalHolder());
           break;
         }
       case Opcodes.INVOKESTATIC:
@@ -297,8 +294,7 @@
       case Opcodes.INVOKESPECIAL:
         {
           Type actualInvokeType =
-              computeInvokeTypeForInvokeSpecial(
-                  appView, method, code.getOriginalHolder(), context.getOrigin());
+              computeInvokeTypeForInvokeSpecial(appView, method, context, code.getOriginalHolder());
           type = graphLens.lookupMethod(target, context.getReference(), actualInvokeType).getType();
         }
         break;
@@ -363,55 +359,38 @@
   }
 
   private Type computeInvokeTypeForInvokeSpecial(
-      AppView<?> appView, DexMethod method, DexType originalHolder, Origin origin) {
+      AppView<?> appView, DexMethod method, ProgramMethod context, DexType originalHolder) {
     if (appView.dexItemFactory().isConstructor(method)) {
       return Type.DIRECT;
     }
-    if (originalHolder == method.holder) {
-      return invokeTypeForInvokeSpecialToNonInitMethodOnHolder(appView, origin);
+    if (originalHolder != method.getHolderType()) {
+      return Type.SUPER;
     }
-    return Type.SUPER;
+    return invokeTypeForInvokeSpecialToNonInitMethodOnHolder(context, appView.graphLens());
   }
 
   private Type invokeTypeForInvokeSpecialToNonInitMethodOnHolder(
-      AppView<?> appView, Origin origin) {
-    boolean desugaringEnabled = appView.options().isInterfaceMethodDesugaringEnabled();
-    MethodLookupResult lookupResult = appView.graphLens().lookupMethod(method, method, Type.DIRECT);
-    if (lookupResult.getType() == Type.VIRTUAL) {
-      // The method has been publicized. We can't always expect private methods that have been
-      // publicized to be final. For example, if a private method A.m() is publicized, and A is
-      // subsequently merged with a class B, with declares a public non-final method B.m(), then the
-      // horizontal class merger will merge A.m() and B.m() into a new non-final public method.
-      return Type.VIRTUAL;
-    }
-    DexMethod rewrittenMethod = lookupResult.getReference();
-    DexEncodedMethod definition = lookupMethodOnHolder(appView, rewrittenMethod);
+      ProgramMethod context, GraphLens graphLens) {
+    MethodLookupResult lookupResult =
+        graphLens.lookupMethod(method, context.getReference(), Type.DIRECT);
+    DexEncodedMethod definition = context.getHolder().lookupMethod(lookupResult.getReference());
     if (definition == null) {
-      // The method is not defined on the class, we can use super to target. When desugaring
-      // default interface methods, it is expected they are targeted with invoke-direct.
-      return this.itf && desugaringEnabled ? Type.DIRECT : Type.SUPER;
+      return Type.SUPER;
     }
-    if (definition.isPrivateMethod() || !definition.isVirtualMethod()) {
-      return Type.DIRECT;
-    }
-    if (definition.isFinal()) {
-      // This method is final which indicates no subtype will overwrite it, we can use
-      // invoke-virtual.
-      return Type.VIRTUAL;
-    }
-    if (itf && definition.isDefaultMethod()) {
-      return desugaringEnabled ? Type.DIRECT : Type.SUPER;
-    }
-    // We cannot emulate the semantics of invoke-special in this case and should throw a compilation
-    // error.
-    throw new CompilationError("Failed to compile unsupported use of invokespecial", origin);
-  }
 
-  private DexEncodedMethod lookupMethodOnHolder(AppView<?> appView, DexMethod method) {
-    // Directly lookup the program type for holder. This bypasses lookup order as well as looks
-    // directly on the application data, which bypasses and indirection or validation.
-    DexProgramClass clazz = appView.appInfo().unsafeDirectProgramTypeLookup(method.getHolderType());
-    assert clazz != null;
-    return clazz.lookupMethod(method);
+    if (context.getHolder().isInterface()) {
+      // On interfaces invoke-special should be mapped to invoke-super if the invoke-special
+      // instruction is used to target a default interface method.
+      if (definition.belongsToVirtualPool()) {
+        return Type.SUPER;
+      }
+    } else {
+      // Due to desugaring of invoke-special instructions that target virtual methods, this invoke
+      // should only target a virtual method if the method has been publicized in R8 (in which case
+      // the invoke instruction has a pending rewrite to invoke-virtual).
+      assert definition.isPrivate() || lookupResult.getType().isVirtual();
+    }
+
+    return Type.DIRECT;
   }
 }