Adapt and simplify RetargetingInfo

Bug: 184026720
Change-Id: Ic283f0b2ad217097a0985c870c8c64f277f47d4d
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index c4a01f6..950459f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -9,13 +9,13 @@
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClassAndMethod;
 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.DexProto;
-import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
@@ -28,7 +28,6 @@
 import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.List;
 import java.util.Map;
 import java.util.function.Consumer;
 import java.util.function.Function;
@@ -40,22 +39,23 @@
   private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
 
   private final RetargetingInfo retargetingInfo;
-  private final Map<DexMethod, DexMethod> retargetLibraryMember;
-  private final Map<DexString, List<DexMethod>> nonFinalHolderRewrites;
+  private final Map<DexMethod, DexMethod> staticRetarget;
+  private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
   private final DexClassAndMethodSet emulatedDispatchMethods;
 
   public DesugaredLibraryRetargeter(AppView<?> appView) {
     this.appView = appView;
     this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
     retargetingInfo = RetargetingInfo.get(appView);
-    retargetLibraryMember = retargetingInfo.getRetargetLibraryMember();
-    nonFinalHolderRewrites = retargetingInfo.getNonFinalHolderRewrites();
+    staticRetarget = retargetingInfo.getStaticRetarget();
+    nonEmulatedVirtualRetarget = retargetingInfo.getNonEmulatedVirtualRetarget();
     emulatedDispatchMethods = retargetingInfo.getEmulatedDispatchMethods();
   }
 
   // Used by the ListOfBackportedMethods utility.
   public void visit(Consumer<DexMethod> consumer) {
-    retargetLibraryMember.keySet().forEach(consumer);
+    staticRetarget.keySet().forEach(consumer);
+    nonEmulatedVirtualRetarget.keySet().forEach(consumer);
   }
 
   public RetargetingInfo getRetargetingInfo() {
@@ -125,7 +125,7 @@
 
   private InvokeRetargetingResult computeNewInvokeTarget(
       CfInstruction instruction, ProgramMethod context) {
-    if (retargetLibraryMember.isEmpty() || !instruction.isInvoke()) {
+    if (!instruction.isInvoke()) {
       return NO_REWRITING;
     }
     if (appView
@@ -137,17 +137,27 @@
     }
     CfInvoke cfInvoke = instruction.asInvoke();
     DexMethod invokedMethod = cfInvoke.getMethod();
-    InvokeRetargetingResult retarget =
-        computeRetargetedMethod(invokedMethod, cfInvoke.isInterface());
+    AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
+    MethodResolutionResult resolutionResult =
+        appInfo.resolveMethod(invokedMethod, cfInvoke.isInterface());
+    if (!resolutionResult.isSingleResolution()) {
+      return NO_REWRITING;
+    }
+    DexEncodedMethod singleTarget = resolutionResult.getSingleTarget();
+    assert singleTarget != null;
+    if (cfInvoke.isInvokeStatic()) {
+      DexMethod retarget = staticRetarget.get(singleTarget.getReference());
+      return retarget == null
+          ? NO_REWRITING
+          : InvokeRetargetingResult.createInvokeRetargetingResult(retarget);
+    }
+    InvokeRetargetingResult retarget = computeNonStaticRetarget(singleTarget);
     if (!retarget.hasNewInvokeTarget()) {
       return NO_REWRITING;
     }
-    if (cfInvoke.isInvokeSuper(context.getHolderType())
-        && matchesNonFinalHolderRewrite(invokedMethod)) {
-      DexClassAndMethod superTarget =
-          appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
-      // Final methods can be rewritten as a normal invoke.
-      if (superTarget != null && !superTarget.getAccessFlags().isFinal()) {
+    if (cfInvoke.isInvokeSuper(context.getHolderType())) {
+      DexClassAndMethod superTarget = appInfo.lookupSuperTarget(invokedMethod, context);
+      if (superTarget != null) {
         return InvokeRetargetingResult.createInvokeRetargetingResult(
             appView.options().desugaredLibrarySpecification.retargetMethod(superTarget, appView));
       }
@@ -155,59 +165,23 @@
     return retarget;
   }
 
-  private InvokeRetargetingResult computeRetargetedMethod(
-      DexMethod invokedMethod, boolean isInterface) {
-    InvokeRetargetingResult invokeRetargetingResult = computeRetargetLibraryMember(invokedMethod);
-    if (!invokeRetargetingResult.hasNewInvokeTarget()) {
-      if (!matchesNonFinalHolderRewrite(invokedMethod)) {
-        return NO_REWRITING;
-      }
-      // We need to force resolution, even on d8, to know if the invoke has to be rewritten.
-      MethodResolutionResult resolutionResult =
-          appView.appInfoForDesugaring().resolveMethod(invokedMethod, isInterface);
-      if (resolutionResult.isFailedResolution()) {
-        return NO_REWRITING;
-      }
-      DexEncodedMethod singleTarget = resolutionResult.getSingleTarget();
-      assert singleTarget != null;
-      invokeRetargetingResult = computeRetargetLibraryMember(singleTarget.getReference());
-    }
-    return invokeRetargetingResult;
-  }
-
-  private InvokeRetargetingResult computeRetargetLibraryMember(DexMethod method) {
-    DexClassAndMethod emulatedMethod = emulatedDispatchMethods.get(method);
+  private InvokeRetargetingResult computeNonStaticRetarget(DexEncodedMethod singleTarget) {
+    assert !singleTarget.isStatic();
+    DexMethod reference = singleTarget.getReference();
+    DexClassAndMethod emulatedMethod = emulatedDispatchMethods.get(reference);
     if (emulatedMethod != null) {
-      assert !emulatedMethod.getAccessFlags().isStatic();
       return new InvokeRetargetingResult(
           true,
           eventConsumer -> {
             DexType newHolder =
                 syntheticHelper.ensureEmulatedHolderDispatchMethod(emulatedMethod, eventConsumer)
                     .type;
-            return computeRetargetMethod(
-                method, emulatedMethod.getAccessFlags().isStatic(), newHolder);
+            DexItemFactory factory = appView.dexItemFactory();
+            DexProto newProto = factory.prependHolderToProto(reference);
+            return factory.createMethod(newHolder, newProto, reference.getName());
           });
     }
-    return InvokeRetargetingResult.createInvokeRetargetingResult(retargetLibraryMember.get(method));
-  }
-
-  private boolean matchesNonFinalHolderRewrite(DexMethod method) {
-    List<DexMethod> dexMethods = nonFinalHolderRewrites.get(method.name);
-    if (dexMethods == null) {
-      return false;
-    }
-    for (DexMethod dexMethod : dexMethods) {
-      if (method.match(dexMethod)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  DexMethod computeRetargetMethod(DexMethod method, boolean isStatic, DexType newHolder) {
-    DexItemFactory factory = appView.dexItemFactory();
-    DexProto newProto = isStatic ? method.getProto() : factory.prependHolderToProto(method);
-    return factory.createMethod(newHolder, newProto, method.getName());
+    return InvokeRetargetingResult.createInvokeRetargetingResult(
+        nonEmulatedVirtualRetarget.get(reference));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
index d9656fe..79c2b3a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/RetargetingInfo.java
@@ -22,20 +22,18 @@
 
 public class RetargetingInfo {
 
-  private final Map<DexMethod, DexMethod> retargetLibraryMember;
-  // Map nonFinalRewrite hold a methodName -> method mapping for methods which are rewritten while
-  // the holder is non final. In this case d8 needs to force resolution of given methods to see if
-  // the invoke needs to be rewritten.
-  private final Map<DexString, List<DexMethod>> nonFinalHolderRewrites;
+  private final Map<DexMethod, DexMethod> staticRetarget;
+  private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
+
   // Non final virtual library methods requiring generation of emulated dispatch.
   private final DexClassAndMethodSet emulatedDispatchMethods;
 
   RetargetingInfo(
-      Map<DexMethod, DexMethod> retargetLibraryMember,
-      Map<DexString, List<DexMethod>> nonFinalHolderRewrites,
+      Map<DexMethod, DexMethod> staticRetarget,
+      Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
       DexClassAndMethodSet emulatedDispatchMethods) {
-    this.retargetLibraryMember = retargetLibraryMember;
-    this.nonFinalHolderRewrites = nonFinalHolderRewrites;
+    this.staticRetarget = staticRetarget;
+    this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
     this.emulatedDispatchMethods = emulatedDispatchMethods;
   }
 
@@ -43,12 +41,12 @@
     return new RetargetingInfoBuilder(appView).computeRetargetingInfo();
   }
 
-  public Map<DexMethod, DexMethod> getRetargetLibraryMember() {
-    return retargetLibraryMember;
+  public Map<DexMethod, DexMethod> getStaticRetarget() {
+    return staticRetarget;
   }
 
-  public Map<DexString, List<DexMethod>> getNonFinalHolderRewrites() {
-    return nonFinalHolderRewrites;
+  public Map<DexMethod, DexMethod> getNonEmulatedVirtualRetarget() {
+    return nonEmulatedVirtualRetarget;
   }
 
   public DexClassAndMethodSet getEmulatedDispatchMethods() {
@@ -58,8 +56,8 @@
   private static class RetargetingInfoBuilder {
 
     private final AppView<?> appView;
-    private final Map<DexMethod, DexMethod> retargetLibraryMember = new IdentityHashMap<>();
-    private final Map<DexString, List<DexMethod>> nonFinalHolderRewrites = new IdentityHashMap<>();
+    private final Map<DexMethod, DexMethod> staticRetarget = new IdentityHashMap<>();
+    private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget = new IdentityHashMap<>();
     private final DexClassAndMethodSet emulatedDispatchMethods = DexClassAndMethodSet.create();
 
     public RetargetingInfoBuilder(AppView<?> appView) {
@@ -82,28 +80,26 @@
             DexType newHolder = retargetCoreLibMember.get(methodName).get(inType);
             List<DexClassAndMethod> found = findMethodsWithName(methodName, typeClass);
             for (DexClassAndMethod method : found) {
-              boolean emulatedDispatch = false;
               DexMethod methodReference = method.getReference();
-              if (!typeClass.isFinal()) {
-                nonFinalHolderRewrites.putIfAbsent(method.getName(), new ArrayList<>());
-                nonFinalHolderRewrites.get(method.getName()).add(methodReference);
-                if (!method.getAccessFlags().isStatic()) {
-                  if (isEmulatedInterfaceDispatch(method)) {
-                    // In this case interface method rewriter takes care of it.
-                    continue;
-                  } else if (!method.getAccessFlags().isFinal()) {
-                    // Virtual rewrites require emulated dispatch for inheritance.
-                    // The call is rewritten to the dispatch holder class instead.
-                    emulatedDispatchMethods.add(method);
-                    emulatedDispatch = true;
-                  }
-                }
-              }
-              if (!emulatedDispatch) {
-                retargetLibraryMember.put(
+              if (method.getAccessFlags().isStatic()) {
+                staticRetarget.put(
                     methodReference,
                     computeRetargetMethod(
                         methodReference, method.getAccessFlags().isStatic(), newHolder));
+                continue;
+              }
+              if (isEmulatedInterfaceDispatch(method)) {
+                continue;
+              }
+              if (typeClass.isFinal() || method.getAccessFlags().isFinal()) {
+                nonEmulatedVirtualRetarget.put(
+                    methodReference,
+                    computeRetargetMethod(
+                        methodReference, method.getAccessFlags().isStatic(), newHolder));
+              } else {
+                // Virtual rewrites require emulated dispatch for inheritance.
+                // The call is rewritten to the dispatch holder class instead.
+                emulatedDispatchMethods.add(method);
               }
             }
           }
@@ -123,7 +119,7 @@
         DexMethod target =
             computeRetargetMethod(
                 source, true, itemFactory.createType("Ljava/util/DesugarArrays;"));
-        retargetLibraryMember.put(source, target);
+        staticRetarget.put(source, target);
         // TODO(b/181629049): This is only a workaround rewriting invokes of
         //  j.u.TimeZone.getTimeZone taking a java.time.ZoneId.
         name = itemFactory.createString("getTimeZone");
@@ -136,11 +132,11 @@
         target =
             computeRetargetMethod(
                 source, true, itemFactory.createType("Ljava/util/DesugarTimeZone;"));
-        retargetLibraryMember.put(source, target);
+        staticRetarget.put(source, target);
       }
       return new RetargetingInfo(
-          ImmutableMap.copyOf(retargetLibraryMember),
-          ImmutableMap.copyOf(nonFinalHolderRewrites),
+          ImmutableMap.copyOf(staticRetarget),
+          ImmutableMap.copyOf(nonEmulatedVirtualRetarget),
           emulatedDispatchMethods);
     }