Adapt and simplify emulated dispatch

Bug: 184026720
Change-Id: I475b0004a062504600d02808547ea2d153dd2c99
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 865a536..1977132 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1184,7 +1184,7 @@
   }
 
   public static DexEncodedMethod createDesugaringForwardingMethod(
-      DexClassAndMethod target, DexClass clazz, DexMethod forwardMethod, DexItemFactory factory) {
+      DexEncodedMethod target, DexClass clazz, DexMethod forwardMethod, DexItemFactory factory) {
     DexMethod method = target.getReference();
     assert forwardMethod != null;
     // New method will have the same name, proto, and also all the flags of the
@@ -1206,8 +1206,8 @@
                 .setNonStaticSource(newMethod)
                 .setStaticTarget(forwardMethod, isInterfaceMethodReference)
                 .build())
-        .setApiLevelForDefinition(target.getDefinition().getApiLevelForDefinition())
-        .setApiLevelForCode(target.getDefinition().getApiLevelForCode())
+        .setApiLevelForDefinition(target.getApiLevelForDefinition())
+        .setApiLevelForCode(target.getApiLevelForCode())
         .build();
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
index abe876f..c383dcd 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
@@ -5,6 +5,9 @@
 package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
 
 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.synthesis.SyntheticNaming.SyntheticKind;
 
 /**
@@ -26,4 +29,24 @@
     this.holderKind = holderKind;
     this.method = method;
   }
+
+  public SyntheticKind getHolderKind() {
+    return holderKind;
+  }
+
+  public DexType getHolderContext() {
+    return method.getHolderType();
+  }
+
+  public DexMethod getMethod() {
+    return method;
+  }
+
+  public DexString getName() {
+    return method.getName();
+  }
+
+  public DexProto getProto() {
+    return method.getProto();
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedDispatchMethodDescriptor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedDispatchMethodDescriptor.java
index 7b368fc..c5154cd 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedDispatchMethodDescriptor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/EmulatedDispatchMethodDescriptor.java
@@ -52,4 +52,20 @@
     this.forwardingMethod = forwardingMethod;
     this.dispatchCases = dispatchCases;
   }
+
+  public DerivedMethod getInterfaceMethod() {
+    return interfaceMethod;
+  }
+
+  public DerivedMethod getEmulatedDispatchMethod() {
+    return emulatedDispatchMethod;
+  }
+
+  public DerivedMethod getForwardingMethod() {
+    return forwardingMethod;
+  }
+
+  public LinkedHashMap<DexType, DerivedMethod> getDispatchCases() {
+    return dispatchCases;
+  }
 }
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 950459f..7c5d1c3 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
@@ -15,8 +15,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.DexProto;
-import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodResolutionResult;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaring;
@@ -24,8 +22,8 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.FreshLocalProvider;
 import com.android.tools.r8.ir.desugar.LocalStackAllocator;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
-import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Map;
@@ -41,7 +39,7 @@
   private final RetargetingInfo retargetingInfo;
   private final Map<DexMethod, DexMethod> staticRetarget;
   private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
-  private final DexClassAndMethodSet emulatedDispatchMethods;
+  private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
 
   public DesugaredLibraryRetargeter(AppView<?> appView) {
     this.appView = appView;
@@ -49,13 +47,14 @@
     retargetingInfo = RetargetingInfo.get(appView);
     staticRetarget = retargetingInfo.getStaticRetarget();
     nonEmulatedVirtualRetarget = retargetingInfo.getNonEmulatedVirtualRetarget();
-    emulatedDispatchMethods = retargetingInfo.getEmulatedDispatchMethods();
+    emulatedVirtualRetarget = retargetingInfo.getEmulatedVirtualRetarget();
   }
 
   // Used by the ListOfBackportedMethods utility.
   public void visit(Consumer<DexMethod> consumer) {
     staticRetarget.keySet().forEach(consumer);
     nonEmulatedVirtualRetarget.keySet().forEach(consumer);
+    emulatedVirtualRetarget.keySet().forEach(consumer);
   }
 
   public RetargetingInfo getRetargetingInfo() {
@@ -158,8 +157,7 @@
     if (cfInvoke.isInvokeSuper(context.getHolderType())) {
       DexClassAndMethod superTarget = appInfo.lookupSuperTarget(invokedMethod, context);
       if (superTarget != null) {
-        return InvokeRetargetingResult.createInvokeRetargetingResult(
-            appView.options().desugaredLibrarySpecification.retargetMethod(superTarget, appView));
+        return computeSuperRetarget(superTarget.getDefinition());
       }
     }
     return retarget;
@@ -168,18 +166,24 @@
   private InvokeRetargetingResult computeNonStaticRetarget(DexEncodedMethod singleTarget) {
     assert !singleTarget.isStatic();
     DexMethod reference = singleTarget.getReference();
-    DexClassAndMethod emulatedMethod = emulatedDispatchMethods.get(reference);
-    if (emulatedMethod != null) {
+    EmulatedDispatchMethodDescriptor descriptor = emulatedVirtualRetarget.get(reference);
+    if (descriptor != null) {
       return new InvokeRetargetingResult(
           true,
-          eventConsumer -> {
-            DexType newHolder =
-                syntheticHelper.ensureEmulatedHolderDispatchMethod(emulatedMethod, eventConsumer)
-                    .type;
-            DexItemFactory factory = appView.dexItemFactory();
-            DexProto newProto = factory.prependHolderToProto(reference);
-            return factory.createMethod(newHolder, newProto, reference.getName());
-          });
+          eventConsumer ->
+              syntheticHelper.ensureEmulatedHolderDispatchMethod(descriptor, eventConsumer));
+    }
+    return InvokeRetargetingResult.createInvokeRetargetingResult(
+        nonEmulatedVirtualRetarget.get(reference));
+  }
+
+  private InvokeRetargetingResult computeSuperRetarget(DexEncodedMethod singleTarget) {
+    assert !singleTarget.isStatic();
+    DexMethod reference = singleTarget.getReference();
+    EmulatedDispatchMethodDescriptor descriptor = emulatedVirtualRetarget.get(reference);
+    if (descriptor != null) {
+      return InvokeRetargetingResult.createInvokeRetargetingResult(
+          syntheticHelper.ensureForwardingMethod(descriptor));
     }
     return InvokeRetargetingResult.createInvokeRetargetingResult(
         nonEmulatedVirtualRetarget.get(reference));
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
index d757c94..11fcfb7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterL8Synthesizer.java
@@ -4,21 +4,22 @@
 package com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter;
 
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaring;
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
-import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
+import java.util.Map;
 
 public class DesugaredLibraryRetargeterL8Synthesizer implements CfClassSynthesizerDesugaring {
 
   private final AppView<?> appView;
   private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
-  private final DexClassAndMethodSet emulatedDispatchMethods;
+  private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedDispatchMethods;
 
   public static DesugaredLibraryRetargeterL8Synthesizer create(
       AppView<?> appView, RetargetingInfo retargetingInfo) {
     assert appView.options().isDesugaredLibraryCompilation();
-    if (retargetingInfo == null || retargetingInfo.getEmulatedDispatchMethods().isEmpty()) {
+    if (retargetingInfo == null || retargetingInfo.getEmulatedVirtualRetarget().isEmpty()) {
       assert appView.options().desugaredLibrarySpecification.getRetargetCoreLibMember().isEmpty();
       return null;
     }
@@ -29,13 +30,14 @@
       AppView<?> appView, RetargetingInfo retargetingInfo) {
     this.appView = appView;
     this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
-    emulatedDispatchMethods = retargetingInfo.getEmulatedDispatchMethods();
+    emulatedDispatchMethods = retargetingInfo.getEmulatedVirtualRetarget();
   }
 
   @Override
   public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
     assert !emulatedDispatchMethods.isEmpty();
-    for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) {
+    for (EmulatedDispatchMethodDescriptor emulatedDispatchMethod :
+        emulatedDispatchMethods.values()) {
       syntheticHelper.ensureProgramEmulatedHolderDispatchMethod(
           emulatedDispatchMethod, eventConsumer);
     }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
index aae08a7..43e7baf 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterPostProcessor.java
@@ -5,7 +5,6 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexLibraryClass;
 import com.android.tools.r8.graph.DexMethod;
@@ -15,15 +14,16 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
 import com.android.tools.r8.utils.OptionalBool;
-import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
 import com.google.common.collect.Maps;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 
@@ -34,13 +34,13 @@
 
   private final AppView<?> appView;
   private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
-  private final DexClassAndMethodSet emulatedDispatchMethods;
+  private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedDispatchMethods;
 
   public DesugaredLibraryRetargeterPostProcessor(
       AppView<?> appView, RetargetingInfo retargetingInfo) {
     this.appView = appView;
     this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
-    emulatedDispatchMethods = retargetingInfo.getEmulatedDispatchMethods();
+    emulatedDispatchMethods = retargetingInfo.getEmulatedVirtualRetarget();
   }
 
   @Override
@@ -57,11 +57,11 @@
       Collection<DexProgramClass> programClasses,
       DesugaredLibraryRetargeterPostProcessingEventConsumer eventConsumer) {
     assert !appView.options().isDesugaredLibraryCompilation();
-    Map<DexType, List<DexClassAndMethod>> map = Maps.newIdentityHashMap();
-    for (DexClassAndMethod emulatedDispatchMethod : emulatedDispatchMethods) {
-      map.putIfAbsent(emulatedDispatchMethod.getHolderType(), new ArrayList<>(1));
-      map.get(emulatedDispatchMethod.getHolderType()).add(emulatedDispatchMethod);
-    }
+    Map<DexType, List<DexMethod>> map = Maps.newIdentityHashMap();
+    emulatedDispatchMethods.forEach(
+        (method, descriptor) -> {
+          map.putIfAbsent(method.getHolderType(), new ArrayList<>(1)).add(method);
+        });
     for (DexProgramClass clazz : programClasses) {
       if (clazz.superType == null) {
         assert clazz.type == appView.dexItemFactory().objectType : clazz.type.toSourceString();
@@ -84,7 +84,9 @@
   }
 
   private boolean inherit(
-      DexLibraryClass clazz, DexType typeToInherit, DexClassAndMethodSet retarget) {
+      DexLibraryClass clazz,
+      DexType typeToInherit,
+      Map<DexMethod, EmulatedDispatchMethodDescriptor> retarget) {
     DexLibraryClass current = clazz;
     while (current.type != appView.dexItemFactory().objectType) {
       if (current.type == typeToInherit) {
@@ -92,7 +94,7 @@
       }
       DexClass dexClass = appView.definitionFor(current.superType);
       if (dexClass == null || dexClass.isClasspathClass()) {
-        reportInvalidLibrarySupertype(current, retarget);
+        reportInvalidLibrarySupertype(current, retarget.keySet());
         return false;
       } else if (dexClass.isProgramClass()) {
         // If dexClass is a program class, then it is already correctly desugared.
@@ -106,7 +108,7 @@
   private void ensureInterfacesAndForwardingMethodsSynthesized(
       DesugaredLibraryRetargeterPostProcessingEventConsumer eventConsumer,
       DexProgramClass clazz,
-      List<DexClassAndMethod> methods) {
+      List<DexMethod> methods) {
     // DesugaredLibraryRetargeter emulate dispatch: insertion of a marker interface & forwarding
     // methods.
     // We cannot use the ClassProcessor since this applies up to 26, while the ClassProcessor
@@ -114,9 +116,10 @@
     if (appView.isAlreadyLibraryDesugared(clazz)) {
       return;
     }
-    for (DexClassAndMethod method : methods) {
+    for (DexMethod method : methods) {
+      EmulatedDispatchMethodDescriptor descriptor = emulatedDispatchMethods.get(method);
       DexClass newInterface =
-          syntheticHelper.ensureEmulatedInterfaceDispatchMethod(method, eventConsumer);
+          syntheticHelper.ensureEmulatedInterfaceDispatchMethod(descriptor, eventConsumer);
       if (clazz.interfaces.contains(newInterface.type)) {
         // The class has already been desugared.
         continue;
@@ -131,30 +134,35 @@
       clazz.addExtraInterfaces(
           Collections.singletonList(new ClassTypeSignature(newInterface.type)));
       eventConsumer.acceptInterfaceInjection(clazz, newInterface);
-      if (clazz.lookupVirtualMethod(method.getReference()) == null) {
-        DexEncodedMethod newMethod = createForwardingMethod(method, clazz);
+      DexMethod itfMethod =
+          syntheticHelper.getEmulatedInterfaceDispatchMethod(newInterface, descriptor);
+      if (clazz.lookupVirtualMethod(method) == null) {
+        DexEncodedMethod newMethod = createForwardingMethod(itfMethod, descriptor, clazz);
         clazz.addVirtualMethod(newMethod);
         eventConsumer.acceptForwardingMethod(new ProgramMethod(clazz, newMethod));
       }
     }
   }
 
-  private DexEncodedMethod createForwardingMethod(DexClassAndMethod target, DexClass clazz) {
+  private DexEncodedMethod createForwardingMethod(
+      DexMethod target, EmulatedDispatchMethodDescriptor descriptor, DexClass clazz) {
     // NOTE: Never add a forwarding method to methods of classes unknown or coming from android.jar
     // even if this results in invalid code, these classes are never desugared.
     // In desugared library, emulated interface methods can be overridden by retarget lib members.
-    DexMethod forwardMethod =
-        appView.options().desugaredLibrarySpecification.retargetMethod(target, appView);
-    assert forwardMethod != null && forwardMethod != target.getReference();
+    DexMethod forwardMethod = syntheticHelper.ensureForwardingMethod(descriptor);
+    assert forwardMethod != null && forwardMethod != target;
+    DexEncodedMethod resolvedMethod =
+        appView.appInfoForDesugaring().resolveMethod(target, true).getResolvedMethod();
+    assert resolvedMethod != null;
     DexEncodedMethod desugaringForwardingMethod =
         DexEncodedMethod.createDesugaringForwardingMethod(
-            target, clazz, forwardMethod, appView.dexItemFactory());
+            resolvedMethod, clazz, forwardMethod, appView.dexItemFactory());
     desugaringForwardingMethod.setLibraryMethodOverride(OptionalBool.TRUE);
     return desugaringForwardingMethod;
   }
 
   private void reportInvalidLibrarySupertype(
-      DexLibraryClass libraryClass, DexClassAndMethodSet retarget) {
+      DexLibraryClass libraryClass, Set<DexMethod> retarget) {
     DexClass dexClass = appView.definitionFor(libraryClass.superType);
     String message;
     if (dexClass == null) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
index 1a46480..5a5768f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -5,19 +5,21 @@
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
 import com.android.tools.r8.graph.ClasspathOrLibraryClass;
 import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterL8SynthesizerEventConsumer;
 import com.android.tools.r8.ir.synthetic.EmulateDispatchSyntheticCfCodeProvider;
 import com.android.tools.r8.synthesis.SyntheticClassBuilder;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.DescriptorUtils;
-import java.util.Collections;
+import java.util.LinkedHashMap;
 
 public class DesugaredLibraryRetargeterSyntheticHelper {
 
@@ -27,54 +29,87 @@
     this.appView = appView;
   }
 
-  public DexClass ensureEmulatedHolderDispatchMethod(
-      DexClassAndMethod emulatedDispatchMethod,
+  public DexMethod ensureForwardingMethod(EmulatedDispatchMethodDescriptor descriptor) {
+    // TODO(b/184026720): We may synthesize a stub on the classpath if absent.
+    assert descriptor.getForwardingMethod().getHolderKind() == null;
+    return descriptor.getForwardingMethod().getMethod();
+  }
+
+  private DexMethod emulatedHolderDispatchMethod(DexType holder, DerivedMethod method) {
+    assert method.getHolderKind() == SyntheticKind.RETARGET_CLASS;
+    return appView.dexItemFactory().createMethod(holder, method.getProto(), method.getName());
+  }
+
+  DexMethod emulatedInterfaceDispatchMethod(DexType holder, DerivedMethod method) {
+    assert method.getHolderKind() == SyntheticKind.RETARGET_INTERFACE;
+    return appView.dexItemFactory().createMethod(holder, method.getProto(), method.getName());
+  }
+
+  public DexMethod getEmulatedInterfaceDispatchMethod(
+      DexClass newInterface, EmulatedDispatchMethodDescriptor descriptor) {
+    DexMethod method =
+        emulatedInterfaceDispatchMethod(newInterface.type, descriptor.getInterfaceMethod());
+    assert newInterface.lookupMethod(method) != null;
+    return method;
+  }
+
+  public DexMethod ensureEmulatedHolderDispatchMethod(
+      EmulatedDispatchMethodDescriptor descriptor,
       DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
     assert eventConsumer != null;
+    DerivedMethod emulatedDispatchMethod = descriptor.getEmulatedDispatchMethod();
+    DexClass holderContext =
+        appView.contextIndependentDefinitionFor(emulatedDispatchMethod.getHolderContext());
+    DexClass syntheticClass;
     if (appView.options().isDesugaredLibraryCompilation()) {
-      return appView
-          .getSyntheticItems()
-          .getExistingFixedClass(
-              SyntheticKind.RETARGET_CLASS, emulatedDispatchMethod.getHolder(), appView);
+      syntheticClass =
+          appView
+              .getSyntheticItems()
+              .getExistingFixedClass(
+                  emulatedDispatchMethod.getHolderKind(), holderContext, appView);
+      DexMethod dispatchMethod =
+          emulatedHolderDispatchMethod(syntheticClass.type, emulatedDispatchMethod);
+      assert syntheticClass.lookupMethod(dispatchMethod) != null;
+      return dispatchMethod;
+    } else {
+      DexClass itfClass = ensureEmulatedInterfaceDispatchMethod(descriptor, eventConsumer);
+      ClasspathOrLibraryClass context = holderContext.asClasspathOrLibraryClass();
+      assert context != null;
+      syntheticClass =
+          appView
+              .getSyntheticItems()
+              .ensureFixedClasspathClass(
+                  SyntheticKind.RETARGET_CLASS,
+                  context,
+                  appView,
+                  classBuilder -> buildHolderDispatchMethod(classBuilder, itfClass, descriptor),
+                  clazz -> {
+                    eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
+                    rewriteType(clazz.type);
+                  });
     }
-    DexClass interfaceClass =
-        ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod, eventConsumer);
-    DexMethod itfMethod =
-        interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference();
-    ClasspathOrLibraryClass context =
-        emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
-    assert context != null;
-    return appView
-        .getSyntheticItems()
-        .ensureFixedClasspathClass(
-            SyntheticKind.RETARGET_CLASS,
-            context,
-            appView,
-            classBuilder ->
-                buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod),
-            clazz -> {
-              eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
-              rewriteType(clazz.type);
-            });
+    DexMethod dispatchMethod =
+        emulatedHolderDispatchMethod(syntheticClass.type, emulatedDispatchMethod);
+    assert syntheticClass.lookupMethod(dispatchMethod) != null;
+    return dispatchMethod;
   }
 
   public void ensureProgramEmulatedHolderDispatchMethod(
-      DexClassAndMethod emulatedDispatchMethod,
+      EmulatedDispatchMethodDescriptor descriptor,
       DesugaredLibraryRetargeterL8SynthesizerEventConsumer eventConsumer) {
     assert eventConsumer != null;
     assert appView.options().isDesugaredLibraryCompilation();
-    DexClass interfaceClass =
-        ensureEmulatedInterfaceDispatchMethod(emulatedDispatchMethod, eventConsumer);
-    DexMethod itfMethod =
-        interfaceClass.lookupMethod(emulatedDispatchMethod.getReference()).getReference();
+    DerivedMethod emulatedDispatchMethod = descriptor.getEmulatedDispatchMethod();
+    DexClass holderContext =
+        appView.contextIndependentDefinitionFor(emulatedDispatchMethod.getHolderContext());
+    DexClass itfClass = ensureEmulatedInterfaceDispatchMethod(descriptor, eventConsumer);
     appView
         .getSyntheticItems()
         .ensureFixedClass(
-            SyntheticKind.RETARGET_CLASS,
-            emulatedDispatchMethod.getHolder(),
+            emulatedDispatchMethod.getHolderKind(),
+            holderContext,
             appView,
-            classBuilder ->
-                buildHolderDispatchMethod(classBuilder, emulatedDispatchMethod, itfMethod),
+            classBuilder -> buildHolderDispatchMethod(classBuilder, itfClass, descriptor),
             clazz -> {
               eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
               rewriteType(clazz.type);
@@ -82,17 +117,17 @@
   }
 
   public DexClass ensureEmulatedInterfaceDispatchMethod(
-      DexClassAndMethod emulatedDispatchMethod,
+      EmulatedDispatchMethodDescriptor descriptor,
       DesugaredLibraryRetargeterInstructionEventConsumer eventConsumer) {
     assert eventConsumer != null;
+    DerivedMethod itfMethod = descriptor.getInterfaceMethod();
+    DexClass itfContext = appView.contextIndependentDefinitionFor(itfMethod.getHolderContext());
     if (appView.options().isDesugaredLibraryCompilation()) {
       return appView
           .getSyntheticItems()
-          .getExistingFixedClass(
-              SyntheticKind.RETARGET_INTERFACE, emulatedDispatchMethod.getHolder(), appView);
+          .getExistingFixedClass(itfMethod.getHolderKind(), itfContext, appView);
     }
-    ClasspathOrLibraryClass context =
-        emulatedDispatchMethod.getHolder().asClasspathOrLibraryClass();
+    ClasspathOrLibraryClass context = itfContext.asClasspathOrLibraryClass();
     assert context != null;
     return appView
         .getSyntheticItems()
@@ -100,7 +135,7 @@
             SyntheticKind.RETARGET_INTERFACE,
             context,
             appView,
-            classBuilder -> buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod),
+            classBuilder -> buildInterfaceDispatchMethod(classBuilder, descriptor),
             clazz -> {
               eventConsumer.acceptDesugaredLibraryRetargeterDispatchClasspathClass(clazz);
               rewriteType(clazz.type);
@@ -108,17 +143,19 @@
   }
 
   public DexClass ensureEmulatedInterfaceDispatchMethod(
-      DexClassAndMethod emulatedDispatchMethod,
+      EmulatedDispatchMethodDescriptor descriptor,
       DesugaredLibraryRetargeterL8SynthesizerEventConsumer eventConsumer) {
     assert appView.options().isDesugaredLibraryCompilation();
     assert eventConsumer != null;
+    DerivedMethod itfMethod = descriptor.getInterfaceMethod();
+    DexClass itfContext = appView.contextIndependentDefinitionFor(itfMethod.getHolderContext());
     return appView
         .getSyntheticItems()
         .ensureFixedClass(
-            SyntheticKind.RETARGET_INTERFACE,
-            emulatedDispatchMethod.getHolder(),
+            itfMethod.getHolderKind(),
+            itfContext,
             appView,
-            classBuilder -> buildInterfaceDispatchMethod(classBuilder, emulatedDispatchMethod),
+            classBuilder -> buildInterfaceDispatchMethod(classBuilder, descriptor),
             clazz -> {
               eventConsumer.acceptDesugaredLibraryRetargeterDispatchProgramClass(clazz);
               rewriteType(clazz.type);
@@ -126,18 +163,21 @@
   }
 
   private void buildInterfaceDispatchMethod(
-      SyntheticClassBuilder<?, ?> classBuilder, DexClassAndMethod emulatedDispatchMethod) {
+      SyntheticClassBuilder<?, ?> classBuilder, EmulatedDispatchMethodDescriptor descriptor) {
     classBuilder
         .setInterface()
         .addMethod(
             methodBuilder -> {
+              DexMethod itfMethod =
+                  emulatedInterfaceDispatchMethod(
+                      classBuilder.getType(), descriptor.getInterfaceMethod());
               MethodAccessFlags flags =
                   MethodAccessFlags.fromSharedAccessFlags(
                       Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT | Constants.ACC_SYNTHETIC,
                       false);
               methodBuilder
-                  .setName(emulatedDispatchMethod.getName())
-                  .setProto(emulatedDispatchMethod.getProto())
+                  .setName(itfMethod.getName())
+                  .setProto(itfMethod.getProto())
                   // Will be traced by the enqueuer.
                   .disableAndroidApiLevelCheck()
                   .setAccessFlags(flags);
@@ -145,36 +185,36 @@
   }
 
   private <SCB extends SyntheticClassBuilder<?, ?>> void buildHolderDispatchMethod(
-      SCB classBuilder, DexClassAndMethod emulatedDispatchMethod, DexMethod itfMethod) {
+      SCB classBuilder, DexClass itfClass, EmulatedDispatchMethodDescriptor descriptor) {
     classBuilder.addMethod(
         methodBuilder -> {
-          DexMethod desugarMethod =
-              appView
-                  .options()
-                  .desugaredLibrarySpecification
-                  .retargetMethod(emulatedDispatchMethod, appView);
-          assert desugarMethod
-              != null; // This method is reached only for retarget core lib members.
+          DexMethod dispatchMethod =
+              emulatedHolderDispatchMethod(
+                  classBuilder.getType(), descriptor.getEmulatedDispatchMethod());
           methodBuilder
-              .setName(emulatedDispatchMethod.getName())
-              .setProto(desugarMethod.proto)
+              .setName(dispatchMethod.getName())
+              .setProto(dispatchMethod.getProto())
               .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
               // Will be traced by the enqueuer.
               .disableAndroidApiLevelCheck()
               .setCode(
                   methodSig ->
                       appView.options().isDesugaredLibraryCompilation()
-                          ? new EmulateDispatchSyntheticCfCodeProvider(
-                                  methodSig.getHolderType(),
-                                  desugarMethod,
-                                  itfMethod,
-                                  Collections.emptyList(),
-                                  appView)
-                              .generateCfCode()
+                          ? generateEmulatedDispatchCfCode(descriptor, itfClass, methodSig)
                           : null);
         });
   }
 
+  private CfCode generateEmulatedDispatchCfCode(
+      EmulatedDispatchMethodDescriptor descriptor, DexClass itfClass, DexMethod methodSig) {
+    DexMethod forwardingMethod = ensureForwardingMethod(descriptor);
+    DexMethod itfMethod = getEmulatedInterfaceDispatchMethod(itfClass, descriptor);
+    assert descriptor.getDispatchCases().isEmpty();
+    return new EmulateDispatchSyntheticCfCodeProvider(
+            methodSig.getHolderType(), forwardingMethod, itfMethod, new LinkedHashMap<>(), appView)
+        .generateCfCode();
+  }
+
   private void rewriteType(DexType type) {
     String newName =
         appView.options().desugaredLibrarySpecification.convertJavaNameToDesugaredLibrary(type);
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 79c2b3a..9f4a585 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
@@ -12,11 +12,14 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.WorkList;
-import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
 import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
 import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -24,17 +27,15 @@
 
   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;
+  private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
 
   RetargetingInfo(
       Map<DexMethod, DexMethod> staticRetarget,
       Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
-      DexClassAndMethodSet emulatedDispatchMethods) {
+      Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget) {
     this.staticRetarget = staticRetarget;
     this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
-    this.emulatedDispatchMethods = emulatedDispatchMethods;
+    this.emulatedVirtualRetarget = emulatedVirtualRetarget;
   }
 
   public static synchronized RetargetingInfo get(AppView<?> appView) {
@@ -49,8 +50,8 @@
     return nonEmulatedVirtualRetarget;
   }
 
-  public DexClassAndMethodSet getEmulatedDispatchMethods() {
-    return emulatedDispatchMethods;
+  public Map<DexMethod, EmulatedDispatchMethodDescriptor> getEmulatedVirtualRetarget() {
+    return emulatedVirtualRetarget;
   }
 
   private static class RetargetingInfoBuilder {
@@ -58,7 +59,8 @@
     private final AppView<?> appView;
     private final Map<DexMethod, DexMethod> staticRetarget = new IdentityHashMap<>();
     private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget = new IdentityHashMap<>();
-    private final DexClassAndMethodSet emulatedDispatchMethods = DexClassAndMethodSet.create();
+    private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget =
+        new IdentityHashMap<>();
 
     public RetargetingInfoBuilder(AppView<?> appView) {
       this.appView = appView;
@@ -70,8 +72,7 @@
       Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
           desugaredLibrarySpecification.getRetargetCoreLibMember();
       if (retargetCoreLibMember.isEmpty()) {
-        return new RetargetingInfo(
-            ImmutableMap.of(), ImmutableMap.of(), DexClassAndMethodSet.empty());
+        return new RetargetingInfo(ImmutableMap.of(), ImmutableMap.of(), ImmutableMap.of());
       }
       for (DexString methodName : retargetCoreLibMember.keySet()) {
         for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
@@ -99,7 +100,22 @@
               } else {
                 // Virtual rewrites require emulated dispatch for inheritance.
                 // The call is rewritten to the dispatch holder class instead.
-                emulatedDispatchMethods.add(method);
+                DexProto newProto = appView.dexItemFactory().prependHolderToProto(methodReference);
+                DexMethod forwardingDexMethod =
+                    appView.dexItemFactory().createMethod(newHolder, newProto, methodName);
+                DerivedMethod forwardingMethod = new DerivedMethod(forwardingDexMethod);
+                DerivedMethod interfaceMethod =
+                    new DerivedMethod(methodReference, SyntheticKind.RETARGET_INTERFACE);
+                DexMethod dispatchDexMethod =
+                    appView
+                        .dexItemFactory()
+                        .createMethod(methodReference.getHolderType(), newProto, methodName);
+                DerivedMethod dispatchMethod =
+                    new DerivedMethod(dispatchDexMethod, SyntheticKind.RETARGET_CLASS);
+                emulatedVirtualRetarget.put(
+                    methodReference,
+                    new EmulatedDispatchMethodDescriptor(
+                        interfaceMethod, dispatchMethod, forwardingMethod, new LinkedHashMap<>()));
               }
             }
           }
@@ -137,7 +153,7 @@
       return new RetargetingInfo(
           ImmutableMap.copyOf(staticRetarget),
           ImmutableMap.copyOf(nonEmulatedVirtualRetarget),
-          emulatedDispatchMethods);
+          emulatedVirtualRetarget);
     }
 
     DexMethod computeRetargetMethod(DexMethod method, boolean isStatic, DexType newHolder) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 0d79ac1..3a91fef 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -853,7 +853,7 @@
             : appView.options().desugaredLibrarySpecification.retargetMethod(target, appView);
     DexEncodedMethod desugaringForwardingMethod =
         DexEncodedMethod.createDesugaringForwardingMethod(
-            target, clazz, forwardMethod, dexItemFactory);
+            target.getDefinition(), clazz, forwardMethod, dexItemFactory);
     if (!target.isProgramDefinition()
         || target.getDefinition().isLibraryMethodOverride().isTrue()) {
       desugaringForwardingMethod.setLibraryMethodOverride(OptionalBool.TRUE);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
index 3d91f5c..55cf273 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ProgramEmulatedInterfaceSynthesizer.java
@@ -20,7 +20,6 @@
 import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
 import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.synthesis.SyntheticProgramClassBuilder;
-import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
@@ -28,6 +27,7 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -143,7 +143,7 @@
             .withHolder(helper.getEmulatedInterface(theInterface.type), appView.dexItemFactory());
     DexMethod companionMethod =
         helper.ensureDefaultAsMethodOfProgramCompanionClassStub(method).getReference();
-    List<Pair<DexType, DexMethod>> extraDispatchCases =
+    LinkedHashMap<DexType, DexMethod> extraDispatchCases =
         getDispatchCases(method, theInterface, companionMethod);
     return new EmulateDispatchSyntheticCfCodeProvider(
             emulatedInterfaceMethod.getHolderType(),
@@ -154,14 +154,14 @@
         .generateCfCode();
   }
 
-  private List<Pair<DexType, DexMethod>> getDispatchCases(
+  private LinkedHashMap<DexType, DexMethod> getDispatchCases(
       ProgramMethod method, DexProgramClass theInterface, DexMethod companionMethod) {
     // To properly emulate the library interface call, we need to compute the interfaces
     // inheriting from the interface and manually implement the dispatch with instance of.
     // The list guarantees that an interface is always after interfaces it extends,
     // hence reverse iteration.
     List<DexType> subInterfaces = emulatedInterfacesHierarchy.get(theInterface.type);
-    List<Pair<DexType, DexMethod>> extraDispatchCases = new ArrayList<>();
+    LinkedHashMap<DexType, DexMethod> extraDispatchCases = new LinkedHashMap<>();
     // In practice, there is usually a single case (except for tests),
     // so we do not bother to make the following loop more clever.
     Map<DexString, Map<DexType, DexType>> retargetCoreLibMember =
@@ -171,17 +171,16 @@
         for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
           DexClass inClass = appView.definitionFor(inType);
           if (inClass != null && implementsInterface(inClass, theInterface.type)) {
-            extraDispatchCases.add(
-                new Pair<>(
-                    inType,
-                    appView
-                        .dexItemFactory()
-                        .createMethod(
-                            retargetCoreLibMember.get(methodName).get(inType),
-                            appView
-                                .dexItemFactory()
-                                .protoWithDifferentFirstParameter(companionMethod.proto, inType),
-                            method.getName())));
+            extraDispatchCases.put(
+                inType,
+                appView
+                    .dexItemFactory()
+                    .createMethod(
+                        retargetCoreLibMember.get(methodName).get(inType),
+                        appView
+                            .dexItemFactory()
+                            .protoWithDifferentFirstParameter(companionMethod.proto, inType),
+                        method.getName()));
           }
         }
       }
@@ -196,11 +195,10 @@
         DexEncodedMethod result = subInterfaceClass.lookupVirtualMethod(method.getReference());
         if (result != null && !result.isAbstract()) {
           assert result.isDefaultMethod();
-          extraDispatchCases.add(
-              new Pair<>(
-                  subInterfaceClass.type,
-                  InterfaceDesugaringSyntheticHelper.defaultAsMethodOfCompanionClass(
-                      result.getReference(), appView.dexItemFactory())));
+          extraDispatchCases.put(
+              subInterfaceClass.type,
+              InterfaceDesugaringSyntheticHelper.defaultAsMethodOfCompanionClass(
+                  result.getReference(), appView.dexItemFactory()));
         }
       }
     } else {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
index 4847e78..e356796 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
@@ -21,29 +21,30 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.code.If;
 import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.collections.ImmutableDeque;
 import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
 import java.util.ArrayList;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import org.objectweb.asm.Opcodes;
 
 public class EmulateDispatchSyntheticCfCodeProvider extends SyntheticCfCodeProvider {
 
-  private final DexType receiverType;
   private final DexMethod forwardingMethod;
+  private final DexType receiverType;
   private final DexMethod interfaceMethod;
-  private final List<Pair<DexType, DexMethod>> extraDispatchCases;
+  private final LinkedHashMap<DexType, DexMethod> extraDispatchCases;
 
   public EmulateDispatchSyntheticCfCodeProvider(
       DexType holder,
       DexMethod forwardingMethod,
       DexMethod interfaceMethod,
-      List<Pair<DexType, DexMethod>> extraDispatchCases,
+      LinkedHashMap<DexType, DexMethod> extraDispatchCases,
       AppView<?> appView) {
     super(appView, holder);
-    this.receiverType = forwardingMethod.getParameter(0);
     this.forwardingMethod = forwardingMethod;
+    this.receiverType = forwardingMethod.getParameter(0);
     this.interfaceMethod = interfaceMethod;
     this.extraDispatchCases = extraDispatchCases;
   }
@@ -78,19 +79,19 @@
     addReturn(instructions);
 
     // SubInterface dispatch (subInterfaces are ordered).
-    for (Pair<DexType, DexMethod> dispatch : extraDispatchCases) {
+    for (Map.Entry<DexType, DexMethod> dispatch : extraDispatchCases.entrySet()) {
       // Type check basic block.
       instructions.add(labels[nextLabel++]);
       instructions.add(new CfFrame(locals, ImmutableDeque.of()));
       instructions.add(new CfLoad(ValueType.fromDexType(receiverType), 0));
-      instructions.add(new CfInstanceOf(dispatch.getFirst()));
+      instructions.add(new CfInstanceOf(dispatch.getKey()));
       instructions.add(new CfIf(If.Type.EQ, ValueType.INT, labels[nextLabel]));
 
       // Call basic block.
       instructions.add(new CfLoad(ValueType.fromDexType(receiverType), 0));
-      instructions.add(new CfCheckCast(dispatch.getFirst()));
+      instructions.add(new CfCheckCast(dispatch.getKey()));
       loadExtraParameters(instructions);
-      instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, dispatch.getSecond(), false));
+      instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, dispatch.getValue(), false));
       addReturn(instructions);
     }
 
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index f3dcf92..8daa0a9 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -74,7 +74,6 @@
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.utils.IROrdering.IdentityIROrdering;
 import com.android.tools.r8.utils.IROrdering.NondeterministicIROrdering;
-import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.android.tools.r8.utils.structural.Ordered;
 import com.google.common.annotations.VisibleForTesting;
@@ -1037,7 +1036,7 @@
       DexType libraryType,
       DexType invalidSuperType,
       String message,
-      DexClassAndMethodSet retarget) {
+      Set<DexMethod> retarget) {
     if (invalidLibraryClasses.add(invalidSuperType)) {
       reporter.warning(
           new InvalidLibrarySuperclassDiagnostic(
@@ -1046,8 +1045,7 @@
               Reference.classFromDescriptor(invalidSuperType.toDescriptorString()),
               message,
               Lists.newArrayList(
-                  Iterables.transform(
-                      retarget, method -> method.getReference().asMethodReference()))));
+                  Iterables.transform(retarget, method -> method.asMethodReference()))));
     }
   }