Finalize LirToLirDesugaredLibraryRetargeter

This implements lir-to-lir rewriting of retargeted methods.

Bug: b/391572031
Change-Id: Ief64b512ad4d4e7438b1f16d2c0699571e95a012
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 909494b..693ff71 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -556,8 +556,8 @@
           "Landroid/support/multidex/instrumentation/BuildConfig;",
           "Landroid/test/runner/MultiDexTestRunner;");
 
-  private List<DexType> createMultiDexTypes() {
-    ImmutableList.Builder<DexType> builder = ImmutableList.builder();
+  private Set<DexType> createMultiDexTypes() {
+    ImmutableSet.Builder<DexType> builder = ImmutableSet.builder();
     for (String prefix : MULTIDEX_PREFIXES) {
       for (String suffix : MULTIDEX_SUFFIXES) {
         builder.add(createType("L" + prefix + suffix));
@@ -569,7 +569,7 @@
     return builder.build();
   }
 
-  public List<DexType> multiDexTypes = createMultiDexTypes();
+  public Set<DexType> multiDexTypes = createMultiDexTypes();
 
   public final DexType doubleConsumer =
       createStaticallyKnownType("Ljava/util/function/DoubleConsumer;");
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
index b3904bf..c7b54f2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/R8LibraryDesugaring.java
@@ -99,7 +99,7 @@
     LirToLirDesugaredLibraryLibRewriter desugaredLibraryLibRewriter =
         DesugaredLibraryLibRewriter.createLirToLir(appView, eventConsumer);
     LirToLirDesugaredLibraryRetargeter desugaredLibraryRetargeter =
-        LirToLirDesugaredLibraryRetargeter.createLirToLir(appView);
+        LirToLirDesugaredLibraryRetargeter.createLirToLir(appView, eventConsumer);
     // TODO(b/391572031): Implement lir-to-lir interface method rewriting.
     InterfaceMethodRewriter interfaceMethodRewriter = null;
     LirToLirDesugaredLibraryApiConverter desugaredLibraryAPIConverter =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryRetargeter.java
index aed15b8..48a29d5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/CfToCfDesugaredLibraryRetargeter.java
@@ -7,20 +7,14 @@
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfInvoke;
 import com.android.tools.r8.cf.code.CfOpcodeUtils;
-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.DexField;
 import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.InvokeType;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
-import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.DesugarDescription;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import java.util.Collections;
-import java.util.function.BiFunction;
 import java.util.function.IntConsumer;
 import org.objectweb.asm.Opcodes;
 
@@ -50,57 +44,40 @@
 
   private DesugarDescription computeInvokeDescription(
       CfInstruction instruction, ProgramMethod context) {
-    if (appView.dexItemFactory().multiDexTypes.contains(context.getContextType())) {
+    if (!isApplicableToContext(context)) {
       return DesugarDescription.nothing();
     }
-    CfInvoke cfInvoke = instruction.asInvoke();
-    DexMethod invokedMethod = cfInvoke.getMethod();
-    AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
-    MethodResolutionResult resolutionResult =
-        appInfo.resolveMethodLegacy(invokedMethod, cfInvoke.isInterface());
-    if (!resolutionResult.isSingleResolution()) {
-      return DesugarDescription.nothing();
-    }
-    assert resolutionResult.getSingleTarget() != null;
-    DexMethod singleTarget = resolutionResult.getSingleTarget().getReference();
-    if (cfInvoke.isInvokeStatic()) {
-      DexMethod retarget = staticRetarget.get(singleTarget);
-      return ensureInvokeRetargetingResult(retarget);
-    }
-    DesugarDescription retarget = computeNonStaticRetarget(singleTarget, false);
-    if (!retarget.needsDesugaring()) {
-      return DesugarDescription.nothing();
-    }
-    if (cfInvoke.isInvokeSuper(context.getHolderType())) {
-      DexClassAndMethod superTarget =
-          appInfo.lookupSuperTarget(invokedMethod, context, appView, appInfo);
-      if (superTarget != null) {
-        assert !superTarget.getDefinition().isStatic();
-        return computeNonStaticRetarget(superTarget.getReference(), true);
-      }
-    }
-    return retarget;
-  }
-
-  private DesugarDescription computeNonStaticRetarget(DexMethod singleTarget, boolean superInvoke) {
-    EmulatedDispatchMethodDescriptor descriptor = emulatedVirtualRetarget.get(singleTarget);
-    if (descriptor != null) {
-      return createWithTarget(
-          (eventConsumer, methodProcessingContext) ->
-              superInvoke
-                  ? syntheticHelper.ensureForwardingMethod(descriptor, eventConsumer)
-                  : syntheticHelper.ensureEmulatedHolderDispatchMethod(descriptor, eventConsumer));
-    }
-    if (covariantRetarget.containsKey(singleTarget)) {
-      return createWithTarget(
-          (eventConsumer, methodProcessingContext) ->
-              syntheticHelper.ensureCovariantRetargetMethod(
-                  singleTarget,
-                  covariantRetarget.get(singleTarget),
+    CfInvoke invoke = instruction.asInvoke();
+    DexMethod invokedMethod = invoke.getMethod();
+    InvokeType invokeType =
+        invoke.getInvokeType(
+            appView, context.getDefinition().getCode().getCodeLens(appView), context);
+    boolean isInterface = invoke.isInterface();
+    RetargetMethodSupplier retargetMethodSupplier =
+        getRetargetMethodSupplier(invokedMethod, invokeType, isInterface, context);
+    if (retargetMethodSupplier != null) {
+      return DesugarDescription.builder()
+          .setDesugarRewrite(
+              (position,
+                  freshLocalProvider,
+                  localStackAllocator,
+                  desugaringInfo,
                   eventConsumer,
-                  methodProcessingContext));
+                  innerContext,
+                  methodProcessingContext,
+                  desugarings,
+                  dexItemFactory) -> {
+                DexMethod retargetMethod =
+                    retargetMethodSupplier.getRetargetMethod(
+                        eventConsumer, methodProcessingContext);
+                assert appView.definitionForHolder(retargetMethod, innerContext) != null;
+                assert !appView.definitionForHolder(retargetMethod, innerContext).isInterface();
+                return Collections.singletonList(
+                    new CfInvoke(Opcodes.INVOKESTATIC, retargetMethod, false));
+              })
+          .build();
     }
-    return ensureInvokeRetargetingResult(nonEmulatedVirtualRetarget.get(singleTarget));
+    return null;
   }
 
   private DesugarDescription computeStaticFieldGetDescription(
@@ -124,37 +101,4 @@
                 Collections.singletonList(fieldInstruction.createWithField(retargetField)))
         .build();
   }
-
-  DesugarDescription ensureInvokeRetargetingResult(DexMethod retarget) {
-    if (retarget == null) {
-      return DesugarDescription.nothing();
-    }
-    return createWithTarget(
-        (eventConsumer, methodProcessingContext) ->
-            syntheticHelper.ensureRetargetMethod(retarget, eventConsumer));
-  }
-
-  private DesugarDescription createWithTarget(
-      BiFunction<CfInstructionDesugaringEventConsumer, MethodProcessingContext, DexMethod>
-          methodProvider) {
-    return DesugarDescription.builder()
-        .setDesugarRewrite(
-            (position,
-                freshLocalProvider,
-                localStackAllocator,
-                desugaringInfo,
-                eventConsumer,
-                context,
-                methodProcessingContext,
-                desugarings,
-                dexItemFactory) -> {
-              DexMethod newInvokeTarget =
-                  methodProvider.apply(eventConsumer, methodProcessingContext);
-              assert appView.definitionFor(newInvokeTarget.getHolderType()) != null;
-              assert !appView.definitionFor(newInvokeTarget.getHolderType()).isInterface();
-              return Collections.singletonList(
-                  new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, false));
-            })
-        .build();
-  }
 }
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 d340582..4c31664 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
@@ -3,19 +3,28 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
+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.DexEncodedField;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.LibraryDesugaringOptions;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import java.util.Map;
+import java.util.Set;
 
 public abstract class DesugaredLibraryRetargeter {
 
   final AppView<?> appView;
+  private final Set<DexType> multiDexTypes;
   final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
 
   private final Map<DexField, DexField> staticFieldRetarget;
@@ -26,6 +35,7 @@
 
   public DesugaredLibraryRetargeter(AppView<?> appView) {
     this.appView = appView;
+    this.multiDexTypes = appView.dexItemFactory().multiDexTypes;
     this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
     MachineDesugaredLibrarySpecification specification =
         appView.options().getLibraryDesugaringOptions().getMachineDesugaredLibrarySpecification();
@@ -46,16 +56,21 @@
     return null;
   }
 
-  public static LirToLirDesugaredLibraryRetargeter createLirToLir(AppView<?> appView) {
+  public static LirToLirDesugaredLibraryRetargeter createLirToLir(
+      AppView<?> appView, CfInstructionDesugaringEventConsumer eventConsumer) {
     LibraryDesugaringOptions libraryDesugaringOptions =
         appView.options().getLibraryDesugaringOptions();
     if (libraryDesugaringOptions.isLirToLirLibraryDesugaringEnabled()
         && libraryDesugaringOptions.getMachineDesugaredLibrarySpecification().hasRetargeting()) {
-      return new LirToLirDesugaredLibraryRetargeter(appView);
+      return new LirToLirDesugaredLibraryRetargeter(appView, eventConsumer);
     }
     return null;
   }
 
+  boolean isApplicableToContext(ProgramMethod context) {
+    return !multiDexTypes.contains(context.getHolderType());
+  }
+
   DexField getRetargetField(DexField field, ProgramMethod context) {
     DexEncodedField resolvedField =
         appView.appInfoForDesugaring().resolveField(field, context).getResolvedField();
@@ -66,4 +81,65 @@
     }
     return null;
   }
+
+  RetargetMethodSupplier getRetargetMethodSupplier(
+      DexMethod invokedMethod, InvokeType invokeType, boolean isInterface, ProgramMethod context) {
+    AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
+    SingleResolutionResult<?> resolutionResult =
+        appInfo.resolveMethodLegacy(invokedMethod, isInterface).asSingleResolution();
+    if (resolutionResult == null) {
+      return null;
+    }
+    DexMethod resolvedMethod = resolutionResult.getResolvedMethod().getReference();
+    if (invokeType.isStatic()) {
+      return ensureRetargetMethod(resolvedMethod, staticRetarget);
+    }
+    RetargetMethodSupplier result = computeNonStaticRetarget(resolvedMethod, false);
+    if (result != null && invokeType.isSuper()) {
+      DexClassAndMethod singleTarget =
+          appInfo.lookupSuperTarget(invokedMethod, context, appView, appInfo);
+      if (singleTarget != null) {
+        assert !singleTarget.getDefinition().isStatic();
+        return computeNonStaticRetarget(singleTarget.getReference(), true);
+      }
+    }
+    return result;
+  }
+
+  private RetargetMethodSupplier computeNonStaticRetarget(
+      DexMethod singleTarget, boolean superInvoke) {
+    EmulatedDispatchMethodDescriptor descriptor = emulatedVirtualRetarget.get(singleTarget);
+    if (descriptor != null) {
+      return (eventConsumer, methodProcessingContext) ->
+          superInvoke
+              ? syntheticHelper.ensureForwardingMethod(descriptor, eventConsumer)
+              : syntheticHelper.ensureEmulatedHolderDispatchMethod(descriptor, eventConsumer);
+    }
+    if (covariantRetarget.containsKey(singleTarget)) {
+      return (eventConsumer, methodProcessingContext) ->
+          syntheticHelper.ensureCovariantRetargetMethod(
+              singleTarget,
+              covariantRetarget.get(singleTarget),
+              eventConsumer,
+              methodProcessingContext);
+    }
+    return ensureRetargetMethod(singleTarget, nonEmulatedVirtualRetarget);
+  }
+
+  private RetargetMethodSupplier ensureRetargetMethod(
+      DexMethod method, Map<DexMethod, DexMethod> retargetMap) {
+    DexMethod retargetMethod = retargetMap.get(method);
+    if (retargetMethod != null) {
+      return (eventConsumer, methodProcessingContext) ->
+          syntheticHelper.ensureRetargetMethod(retargetMethod, eventConsumer);
+    }
+    return null;
+  }
+
+  interface RetargetMethodSupplier {
+
+    DexMethod getRetargetMethod(
+        CfInstructionDesugaringEventConsumer eventConsumer,
+        MethodProcessingContext methodProcessingContext);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryRetargeter.java
index 0d23fbb..5b689d5 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/LirToLirDesugaredLibraryRetargeter.java
@@ -6,15 +6,22 @@
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.lens.FieldLookupResult;
 import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.R8LibraryDesugaringGraphLens;
 
 public class LirToLirDesugaredLibraryRetargeter extends DesugaredLibraryRetargeter {
 
-  LirToLirDesugaredLibraryRetargeter(AppView<?> appView) {
+  private final CfInstructionDesugaringEventConsumer eventConsumer;
+
+  LirToLirDesugaredLibraryRetargeter(
+      AppView<?> appView, CfInstructionDesugaringEventConsumer eventConsumer) {
     super(appView);
+    this.eventConsumer = eventConsumer;
   }
 
   public FieldLookupResult lookupField(
@@ -36,7 +43,24 @@
       ProgramMethod context,
       MethodProcessingContext methodProcessingContext,
       R8LibraryDesugaringGraphLens lens) {
-    // TODO(b/391572031): Implement.
+    if (isApplicableToContext(context)) {
+      RetargetMethodSupplier retargetMethodSupplier =
+          getRetargetMethodSupplier(
+              previous.getReference(),
+              previous.getType(),
+              previous.isInterface().toBoolean(),
+              context);
+      if (retargetMethodSupplier != null) {
+        DexMethod retargetMethod =
+            retargetMethodSupplier.getRetargetMethod(eventConsumer, methodProcessingContext);
+        return MethodLookupResult.builder(lens, lens.getPrevious())
+            .setReference(retargetMethod)
+            .setReboundReference(retargetMethod)
+            .setIsInterface(false)
+            .setType(InvokeType.STATIC)
+            .build();
+      }
+    }
     return previous;
   }
 }