Merge commit '7adcff87c841d7b0c5df48a4a75180d3b9631666' into dev-release
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index e6cc1f5..a6f1b9c 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -45,8 +45,8 @@
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.RecordRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.optimize.AssertionsRewriter;
 import com.android.tools.r8.ir.optimize.MethodPoolCollection;
 import com.android.tools.r8.ir.optimize.NestReducer;
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 5d62aae..ab55c16 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -4,7 +4,7 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import com.android.tools.r8.shaking.MainDexInfo;
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index 610208f..88c0bc7 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
+import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
 import com.android.tools.r8.shaking.KeepInfoCollection;
 import com.android.tools.r8.utils.Action;
 import com.android.tools.r8.utils.IterableUtils;
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 0530046..5a9ee16 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
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.conversion;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor.IncludeAllResources;
 import static com.android.tools.r8.ir.desugar.lambda.D8LambdaDesugaring.rewriteEnclosingLambdaMethodAttributes;
 
 import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
@@ -51,8 +51,8 @@
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter.Mode;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.lambda.LambdaDeserializationMethodRemover;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.optimize.AssertionsRewriter;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
index 9877f8d..750ffb4 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/NeedsIRDesugarUseRegistry.java
@@ -19,7 +19,7 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 
 class NeedsIRDesugarUseRegistry extends UseRegistry {
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index 6ef420d..9d9a502 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -1,13 +1,14 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
 
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClassAndMember;
 import com.android.tools.r8.graph.DexClassAndMethod;
@@ -22,7 +23,6 @@
 import com.android.tools.r8.graph.LibraryMethod;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
-import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.graph.ResolutionResult;
 import com.android.tools.r8.ir.synthetic.ExceptionThrowingSourceCode;
 import com.android.tools.r8.ir.synthetic.SynthesizedCode;
@@ -55,7 +55,7 @@
  * In other words, the traversal is in top-down (edges from type to its subtypes) topological order.
  * The traversal is lazy, starting from the unordered set of program classes.
  */
-final class ClassProcessor {
+final class ClassProcessor implements InterfaceDesugaringProcessor {
 
   // Collection for method signatures that may cause forwarding methods to be created.
   private static class MethodSignatures {
@@ -336,7 +336,6 @@
   private final AppView<?> appView;
   private final DexItemFactory dexItemFactory;
   private final InterfaceMethodRewriter rewriter;
-  private final Consumer<ProgramMethod> newSynthesizedMethodConsumer;
   private final MethodSignatureEquivalence equivalence = MethodSignatureEquivalence.get();
   private final boolean needsLibraryInfo;
 
@@ -353,14 +352,10 @@
   private final Map<DexProgramClass, ProgramMethodSet> newSyntheticMethods =
       new IdentityHashMap<>();
 
-  ClassProcessor(
-      AppView<?> appView,
-      InterfaceMethodRewriter rewriter,
-      Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
+  ClassProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
     this.appView = appView;
     this.dexItemFactory = appView.dexItemFactory();
     this.rewriter = rewriter;
-    this.newSynthesizedMethodConsumer = newSynthesizedMethodConsumer;
     needsLibraryInfo =
         !appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()
             || !appView
@@ -378,15 +373,25 @@
     return !needsLibraryInfo;
   }
 
-  public void processClass(DexProgramClass clazz) {
+  @Override
+  public void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods) {
     visitClassInfo(clazz, new ReportingContext(clazz, clazz));
   }
 
-  final void addSyntheticMethods() {
+  @Override
+  public boolean shouldProcess(DexProgramClass clazz) {
+    return !clazz.isInterface();
+  }
+
+  // We introduce forwarding methods only once all desugaring has been performed to avoid
+  // confusing the look-up with inserted forwarding methods.
+  @Override
+  public final void finalizeProcessing(
+      DexApplication.Builder<?> builder, ProgramMethodSet synthesizedMethods) {
     newSyntheticMethods.forEach(
         (clazz, newForwardingMethods) -> {
           clazz.addVirtualMethods(newForwardingMethods.toDefinitionSet());
-          newForwardingMethods.forEach(newSynthesizedMethodConsumer);
+          newForwardingMethods.forEach(synthesizedMethods::add);
         });
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/DefaultMethodsHelper.java
similarity index 92%
rename from src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/DefaultMethodsHelper.java
index 838374d..717f235 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DefaultMethodsHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/DefaultMethodsHelper.java
@@ -1,8 +1,8 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
 
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexMethod;
@@ -25,7 +25,7 @@
   // and hidden default interface methods in this interface's hierarchy.
   //
   // Note that it is assumes that these lists should never be big.
-  final static class Collection {
+  static final class Collection {
     static final Collection EMPTY =
         new Collection(Collections.emptyList(), Collections.emptyList());
 
@@ -79,7 +79,8 @@
   // Create default interface collection based on collected information.
   final Collection wrapInCollection() {
     candidates.removeAll(hidden);
-    return (candidates.isEmpty() && hidden.isEmpty()) ? Collection.EMPTY
+    return (candidates.isEmpty() && hidden.isEmpty())
+        ? Collection.EMPTY
         : new Collection(Lists.newArrayList(candidates), Lists.newArrayList(hidden));
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
new file mode 100644
index 0000000..559172a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/EmulatedInterfaceProcessor.java
@@ -0,0 +1,375 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.ir.desugar.itf;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication.Builder;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.GenericSignature;
+import com.android.tools.r8.graph.GenericSignature.ClassSignature;
+import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.IterableUtils;
+import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public final class EmulatedInterfaceProcessor implements InterfaceDesugaringProcessor {
+  private final AppView<?> appView;
+  private final InterfaceMethodRewriter rewriter;
+  private final Map<DexType, DexType> emulatedInterfaces;
+  private final Map<DexType, List<DexType>> emulatedInterfacesHierarchy;
+  // All created emulated interface classes indexed by emulated interface type.
+  final Map<DexProgramClass, DexProgramClass> syntheticClasses = new IdentityHashMap<>();
+
+  EmulatedInterfaceProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
+    this.appView = appView;
+    this.rewriter = rewriter;
+    emulatedInterfaces =
+        appView.options().desugaredLibraryConfiguration.getEmulateLibraryInterface();
+    // Avoid the computation outside L8 since it is not needed.
+    emulatedInterfacesHierarchy =
+        appView.options().isDesugaredLibraryCompilation()
+            ? processEmulatedInterfaceHierarchy()
+            : Collections.emptyMap();
+  }
+
+  private Map<DexType, List<DexType>> processEmulatedInterfaceHierarchy() {
+    Map<DexType, List<DexType>> emulatedInterfacesHierarchy = new IdentityHashMap<>();
+    Set<DexType> processed = Sets.newIdentityHashSet();
+    ArrayList<DexType> emulatedInterfacesSorted = new ArrayList<>(emulatedInterfaces.keySet());
+    emulatedInterfacesSorted.sort(DexType::compareTo);
+    for (DexType interfaceType : emulatedInterfacesSorted) {
+      processEmulatedInterfaceHierarchy(interfaceType, processed, emulatedInterfacesHierarchy);
+    }
+    return emulatedInterfacesHierarchy;
+  }
+
+  private void processEmulatedInterfaceHierarchy(
+      DexType interfaceType,
+      Set<DexType> processed,
+      Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
+    if (processed.contains(interfaceType)) {
+      return;
+    }
+    emulatedInterfacesHierarchy.put(interfaceType, new ArrayList<>());
+    processed.add(interfaceType);
+    DexClass theInterface = appView.definitionFor(interfaceType);
+    if (theInterface == null) {
+      return;
+    }
+    LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(theInterface.interfaces.values));
+    while (!workList.isEmpty()) {
+      DexType next = workList.removeLast();
+      if (emulatedInterfaces.containsKey(next)) {
+        processEmulatedInterfaceHierarchy(next, processed, emulatedInterfacesHierarchy);
+        emulatedInterfacesHierarchy.get(next).add(interfaceType);
+        DexClass nextClass = appView.definitionFor(next);
+        if (nextClass != null) {
+          workList.addAll(Arrays.asList(nextClass.interfaces.values));
+        }
+      }
+    }
+  }
+
+  // The method transforms emulated interface such as they implement the rewritten version
+  // of each emulated interface they implement. Such change should have no effect on the look-up
+  // results, since each class implementing an emulated interface should also implement the
+  // rewritten one.
+  private void replaceInterfacesInEmulatedInterface(DexProgramClass emulatedInterface) {
+    List<GenericSignature.ClassTypeSignature> newInterfaces = new ArrayList<>();
+    ClassSignature classSignature = emulatedInterface.getClassSignature();
+    for (int i = 0; i < emulatedInterface.interfaces.size(); i++) {
+      DexType itf = emulatedInterface.interfaces.values[i];
+      if (emulatedInterfaces.containsKey(itf)) {
+        List<GenericSignature.FieldTypeSignature> typeArguments;
+        if (classSignature == null) {
+          typeArguments = Collections.emptyList();
+        } else {
+          GenericSignature.ClassTypeSignature classTypeSignature =
+              classSignature.superInterfaceSignatures().get(i);
+          assert itf == classTypeSignature.type();
+          typeArguments = classTypeSignature.typeArguments();
+        }
+        newInterfaces.add(
+            new GenericSignature.ClassTypeSignature(emulatedInterfaces.get(itf), typeArguments));
+      }
+    }
+    emulatedInterface.replaceInterfaces(newInterfaces);
+  }
+
+  private void renameEmulatedInterface(DexProgramClass emulatedInterface) {
+    DexType newType = emulatedInterfaces.get(emulatedInterface.type);
+    assert newType != null;
+    emulatedInterface.type = newType;
+    emulatedInterface.setVirtualMethods(renameHolder(emulatedInterface.virtualMethods(), newType));
+    emulatedInterface.setDirectMethods(renameHolder(emulatedInterface.directMethods(), newType));
+  }
+
+  private DexEncodedMethod[] renameHolder(Iterable<DexEncodedMethod> methods, DexType newName) {
+    List<DexEncodedMethod> methods1 = IterableUtils.toNewArrayList(methods);
+    DexEncodedMethod[] newMethods = new DexEncodedMethod[methods1.size()];
+    for (int i = 0; i < newMethods.length; i++) {
+      newMethods[i] = methods1.get(i).toRenamedHolderMethod(newName, appView.dexItemFactory());
+    }
+    return newMethods;
+  }
+
+  void generateEmulateInterfaceLibrary(DexProgramClass emulatedInterface) {
+    assert rewriter.isEmulatedInterface(emulatedInterface.type);
+    DexProgramClass theProgramInterface = emulatedInterface.asProgramClass();
+    DexProgramClass synthesizedClass = synthesizeEmulateInterfaceLibraryClass(theProgramInterface);
+    if (synthesizedClass != null) {
+      syntheticClasses.put(emulatedInterface, synthesizedClass);
+    }
+  }
+
+  private DexProgramClass synthesizeEmulateInterfaceLibraryClass(DexProgramClass theInterface) {
+    List<DexEncodedMethod> emulationMethods = new ArrayList<>();
+    theInterface.forEachProgramMethodMatching(
+        DexEncodedMethod::isDefaultMethod,
+        method -> {
+          DexMethod libraryMethod =
+              method
+                  .getReference()
+                  .withHolder(emulatedInterfaces.get(theInterface.type), appView.dexItemFactory());
+          DexMethod companionMethod =
+              method.getAccessFlags().isStatic()
+                  ? rewriter.staticAsMethodOfCompanionClass(method)
+                  : rewriter.defaultAsMethodOfCompanionClass(method);
+          // 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<>();
+          // 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 =
+              appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember();
+          for (DexString methodName : retargetCoreLibMember.keySet()) {
+            if (method.getName() == methodName) {
+              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())));
+                }
+              }
+            }
+          }
+          if (subInterfaces != null) {
+            for (int i = subInterfaces.size() - 1; i >= 0; i--) {
+              DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
+              assert subInterfaceClass != null;
+              // Else computation of subInterface would have failed.
+              // if the method is implemented, extra dispatch is required.
+              DexEncodedMethod result =
+                  subInterfaceClass.lookupVirtualMethod(method.getReference());
+              if (result != null && !result.isAbstract()) {
+                extraDispatchCases.add(
+                    new Pair<>(
+                        subInterfaceClass.type,
+                        appView
+                            .dexItemFactory()
+                            .createMethod(
+                                rewriter.getCompanionClassType(subInterfaceClass.type),
+                                appView
+                                    .dexItemFactory()
+                                    .protoWithDifferentFirstParameter(
+                                        companionMethod.proto, subInterfaceClass.type),
+                                companionMethod.name)));
+              }
+            }
+          }
+          emulationMethods.add(
+              DexEncodedMethod.toEmulateDispatchLibraryMethod(
+                  method.getHolderType(),
+                  rewriter.emulateInterfaceLibraryMethod(method),
+                  companionMethod,
+                  libraryMethod,
+                  extraDispatchCases,
+                  appView));
+        });
+    if (emulationMethods.isEmpty()) {
+      return null;
+    }
+    DexType emulateLibraryClassType =
+        InterfaceMethodRewriter.getEmulateLibraryInterfaceClassType(
+            theInterface.type, appView.dexItemFactory());
+    ClassAccessFlags emulateLibraryClassFlags = theInterface.accessFlags.copy();
+    emulateLibraryClassFlags.unsetAbstract();
+    emulateLibraryClassFlags.unsetInterface();
+    emulateLibraryClassFlags.unsetAnnotation();
+    emulateLibraryClassFlags.setFinal();
+    emulateLibraryClassFlags.setSynthetic();
+    emulateLibraryClassFlags.setPublic();
+    DexProgramClass clazz =
+        new DexProgramClass(
+            emulateLibraryClassType,
+            null,
+            new SynthesizedOrigin("interface desugaring (libs)", getClass()),
+            emulateLibraryClassFlags,
+            appView.dexItemFactory().objectType,
+            DexTypeList.empty(),
+            theInterface.sourceFile,
+            null,
+            Collections.emptyList(),
+            null,
+            Collections.emptyList(),
+            ClassSignature.noSignature(),
+            DexAnnotationSet.empty(),
+            DexEncodedField.EMPTY_ARRAY,
+            DexEncodedField.EMPTY_ARRAY,
+            // All synthesized methods are static in this case.
+            emulationMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
+            DexEncodedMethod.EMPTY_ARRAY,
+            appView.dexItemFactory().getSkipNameValidationForTesting(),
+            DexProgramClass::checksumFromType);
+    return clazz;
+  }
+
+  private boolean implementsInterface(DexClass clazz, DexType interfaceType) {
+    LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(clazz.interfaces.values));
+    while (!workList.isEmpty()) {
+      DexType next = workList.removeLast();
+      if (interfaceType == next) {
+        return true;
+      }
+      DexClass nextClass = appView.definitionFor(next);
+      if (nextClass != null) {
+        workList.addAll(Arrays.asList(nextClass.interfaces.values));
+      }
+    }
+    return false;
+  }
+
+  @Override
+  public boolean shouldProcess(DexProgramClass clazz) {
+    return appView.options().isDesugaredLibraryCompilation()
+        && rewriter.isEmulatedInterface(clazz.type);
+  }
+
+  @Override
+  public void process(DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
+    assert rewriter.isEmulatedInterface(emulatedInterface.type);
+    if (appView.isAlreadyLibraryDesugared(emulatedInterface)) {
+      return;
+    }
+    // TODO(b/183998768): Due to sequential dependencies we cannot generateEmulateInterfaceLibrary.
+    //  We need to merge this into a single loop. Uncomment the following line instead of running
+    //  it separately.
+    //  generateEmulateInterfaceLibrary(emulatedInterface);
+    replaceInterfacesInEmulatedInterface(emulatedInterface);
+    renameEmulatedInterface(emulatedInterface);
+  }
+
+  @Override
+  public void finalizeProcessing(Builder<?> builder, ProgramMethodSet synthesizedMethods) {
+    warnMissingEmulatedInterfaces();
+    if (!appView.options().isDesugaredLibraryCompilation()) {
+      assert syntheticClasses.isEmpty();
+      return;
+    }
+    syntheticClasses.forEach(
+        (interfaceClass, synthesizedClass) -> {
+          builder.addSynthesizedClass(synthesizedClass);
+          appView.appInfo().addSynthesizedClass(synthesizedClass, interfaceClass);
+          synthesizedClass.forEachProgramMethod(synthesizedMethods::add);
+        });
+    // TODO(b/183918843): Investigate what to do for the filtering, the minimum would be to make
+    // the rewriting rule explicit instead of using the synthesized class prefix.
+    filterEmulatedInterfaceSubInterfaces(builder);
+  }
+
+  private void filterEmulatedInterfaceSubInterfaces(Builder<?> builder) {
+    ArrayList<DexProgramClass> filteredProgramClasses = new ArrayList<>();
+    for (DexProgramClass clazz : builder.getProgramClasses()) {
+      if (clazz.isInterface()
+          && !rewriter.isEmulatedInterface(clazz.type)
+          && !appView.rewritePrefix.hasRewrittenType(clazz.type, appView)
+          && isEmulatedInterfaceSubInterface(clazz)) {
+        String prefix =
+            DescriptorUtils.getJavaTypeFromBinaryName(
+                appView
+                    .options()
+                    .desugaredLibraryConfiguration
+                    .getSynthesizedLibraryClassesPackagePrefix());
+        String interfaceType = clazz.type.toString();
+        // TODO(b/183918843): We are currently computing a new name for the companion class
+        // by replacing the initial package prefix by the synthesized library class package
+        // prefix, it would be better to make the rewriting explicit in the desugared library
+        // json file.
+        int firstPackage = interfaceType.indexOf('.');
+        String newName = prefix + interfaceType.substring(firstPackage + 1);
+        rewriter.addCompanionClassRewriteRule(clazz.type, newName);
+      } else {
+        filteredProgramClasses.add(clazz);
+      }
+    }
+    builder.replaceProgramClasses(filteredProgramClasses);
+  }
+
+  private boolean isEmulatedInterfaceSubInterface(DexClass subInterface) {
+    assert !rewriter.isEmulatedInterface(subInterface.type);
+    LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(subInterface.interfaces.values));
+    while (!workList.isEmpty()) {
+      DexType next = workList.removeFirst();
+      if (rewriter.isEmulatedInterface(next)) {
+        return true;
+      }
+      DexClass nextClass = appView.definitionFor(next);
+      if (nextClass != null) {
+        workList.addAll(Arrays.asList(nextClass.interfaces.values));
+      }
+    }
+    return false;
+  }
+
+  private void warnMissingEmulatedInterfaces() {
+    for (DexType interfaceType : emulatedInterfaces.keySet()) {
+      DexClass theInterface = appView.definitionFor(interfaceType);
+      if (theInterface == null) {
+        warnMissingEmulatedInterface(interfaceType);
+      }
+    }
+  }
+
+  private void warnMissingEmulatedInterface(DexType interfaceType) {
+    StringDiagnostic warning =
+        new StringDiagnostic(
+            "Cannot emulate interface "
+                + interfaceType.getName()
+                + " because the interface is missing.");
+    appView.options().reporter.warning(warning);
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java
new file mode 100644
index 0000000..d85e8a2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringProcessor.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.itf;
+
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+
+public interface InterfaceDesugaringProcessor {
+  boolean shouldProcess(DexProgramClass clazz);
+
+  void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods);
+
+  void finalizeProcessing(DexApplication.Builder<?> builder, ProgramMethodSet synthesizedMethods);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
similarity index 72%
rename from src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index f6a653b..8fd5d23 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -1,8 +1,8 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
 
 import static com.android.tools.r8.ir.code.Invoke.Type.DIRECT;
 import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
@@ -25,14 +25,12 @@
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.graph.AppInfo;
 import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.DexAnnotationSet;
 import com.android.tools.r8.graph.DexApplication.Builder;
 import com.android.tools.r8.graph.DexCallSite;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClassAndMethod;
 import com.android.tools.r8.graph.DexClasspathClass;
-import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexMethod;
@@ -40,10 +38,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
 import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.GenericSignature;
-import com.android.tools.r8.graph.GenericSignature.ClassSignature;
 import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.MethodCollection;
@@ -65,32 +60,23 @@
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.ir.conversion.IRConverter;
 import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.ir.desugar.DefaultMethodsHelper.Collection;
-import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
+import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
+import com.android.tools.r8.ir.desugar.itf.DefaultMethodsHelper.Collection;
 import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
 import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.MethodSynthesizerConsumer;
 import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.UtilityMethodForCodeOptimizations;
 import com.android.tools.r8.ir.synthetic.ForwardMethodBuilder;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.origin.SynthesizedOrigin;
 import com.android.tools.r8.position.MethodPosition;
 import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.IteratorUtils;
 import com.android.tools.r8.utils.Pair;
-import com.android.tools.r8.utils.StringDiagnostic;
 import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
 import com.android.tools.r8.utils.structural.Ordered;
 import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.ListIterator;
 import java.util.Map;
 import java.util.Set;
@@ -151,17 +137,11 @@
   private final Map<DexType, DefaultMethodsHelper.Collection> cache = new ConcurrentHashMap<>();
 
   private final Predicate<DexType> shouldIgnoreFromReportsPredicate;
-  /**
-   * Defines a minor variation in desugaring.
-   */
+  /** Defines a minor variation in desugaring. */
   public enum Flavor {
-    /**
-     * Process all application resources.
-     */
+    /** Process all application resources. */
     IncludeAllResources,
-    /**
-     * Process all but DEX application resources.
-     */
+    /** Process all but DEX application resources. */
     ExcludeDexResources
   }
 
@@ -213,7 +193,8 @@
     Map<DexType, DexType> emulateLibraryInterface =
         options.desugaredLibraryConfiguration.getEmulateLibraryInterface();
     for (DexType interfaceType : emulateLibraryInterface.keySet()) {
-      addRewritePrefix(interfaceType, emulateLibraryInterface.get(interfaceType).toSourceString());
+      addRewriteRulesForEmulatedInterface(
+          interfaceType, emulateLibraryInterface.get(interfaceType).toSourceString());
       DexClass emulatedInterfaceClass = appView.definitionFor(interfaceType);
       if (emulatedInterfaceClass != null) {
         for (DexEncodedMethod encodedMethod :
@@ -224,16 +205,21 @@
     }
   }
 
-  private void addRewritePrefix(DexType interfaceType, String rewrittenType) {
+  void addRewriteRulesForEmulatedInterface(
+      DexType emulatedInterface, String rewrittenEmulatedInterface) {
+    addCompanionClassRewriteRule(emulatedInterface, rewrittenEmulatedInterface);
+    appView.rewritePrefix.rewriteType(
+        getEmulateLibraryInterfaceClassType(emulatedInterface, factory),
+        factory.createType(
+            DescriptorUtils.javaTypeToDescriptor(
+                rewrittenEmulatedInterface + EMULATE_LIBRARY_CLASS_NAME_SUFFIX)));
+  }
+
+  void addCompanionClassRewriteRule(DexType interfaceType, String rewrittenType) {
     appView.rewritePrefix.rewriteType(
         getCompanionClassType(interfaceType),
         factory.createType(
             DescriptorUtils.javaTypeToDescriptor(rewrittenType + COMPANION_CLASS_NAME_SUFFIX)));
-    appView.rewritePrefix.rewriteType(
-        getEmulateLibraryInterfaceClassType(interfaceType, factory),
-        factory.createType(
-            DescriptorUtils.javaTypeToDescriptor(
-                rewrittenType + EMULATE_LIBRARY_CLASS_NAME_SUFFIX)));
   }
 
   boolean isEmulatedInterface(DexType itf) {
@@ -788,204 +774,13 @@
     return false;
   }
 
-  private void warnMissingEmulatedInterface(DexType interfaceType) {
-    StringDiagnostic warning =
-        new StringDiagnostic(
-            "Cannot emulate interface "
-                + interfaceType.getName()
-                + " because the interface is missing.");
-    options.reporter.warning(warning);
-  }
-
-  private void generateEmulateInterfaceLibrary(Builder<?> builder) {
-    // Emulated library interfaces should generate the Emulated Library EL dispatch class.
-    Map<DexType, List<DexType>> emulatedInterfacesHierarchy = processEmulatedInterfaceHierarchy();
-    AppInfo appInfo = appView.appInfo();
-    for (DexType interfaceType : emulatedInterfaces.keySet()) {
-      DexClass theInterface = appInfo.definitionFor(interfaceType);
-      if (theInterface == null) {
-        warnMissingEmulatedInterface(interfaceType);
-      } else if (theInterface.isProgramClass()) {
-        DexProgramClass theProgramInterface = theInterface.asProgramClass();
-        DexProgramClass synthesizedClass =
-            synthesizeEmulateInterfaceLibraryClass(
-                theProgramInterface, emulatedInterfacesHierarchy);
-        if (synthesizedClass != null) {
-          builder.addSynthesizedClass(synthesizedClass);
-          appInfo.addSynthesizedClass(synthesizedClass, theProgramInterface);
-        }
-      }
-    }
-  }
-
-  private Map<DexType, List<DexType>> processEmulatedInterfaceHierarchy() {
-    Map<DexType, List<DexType>> emulatedInterfacesHierarchy = new IdentityHashMap<>();
-    Set<DexType> processed = Sets.newIdentityHashSet();
-    ArrayList<DexType> emulatedInterfacesSorted = new ArrayList<>(emulatedInterfaces.keySet());
-    emulatedInterfacesSorted.sort(DexType::compareTo);
-    for (DexType interfaceType : emulatedInterfacesSorted) {
-      processEmulatedInterfaceHierarchy(interfaceType, processed, emulatedInterfacesHierarchy);
-    }
-    return emulatedInterfacesHierarchy;
-  }
-
-  private void processEmulatedInterfaceHierarchy(
-      DexType interfaceType,
-      Set<DexType> processed,
-      Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
-    if (processed.contains(interfaceType)) {
-      return;
-    }
-    emulatedInterfacesHierarchy.put(interfaceType, new ArrayList<>());
-    processed.add(interfaceType);
-    DexClass theInterface = appView.definitionFor(interfaceType);
-    if (theInterface == null) {
-      warnMissingEmulatedInterface(interfaceType);
-      return;
-    }
-    LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(theInterface.interfaces.values));
-    while (!workList.isEmpty()) {
-      DexType next = workList.removeLast();
-      if (emulatedInterfaces.containsKey(next)) {
-        processEmulatedInterfaceHierarchy(next, processed, emulatedInterfacesHierarchy);
-        emulatedInterfacesHierarchy.get(next).add(interfaceType);
-        DexClass nextClass = appView.definitionFor(next);
-        if (nextClass != null) {
-          workList.addAll(Arrays.asList(nextClass.interfaces.values));
-        }
-      }
-    }
-  }
-
-  private boolean implementsInterface(DexClass clazz, DexType interfaceType) {
-    LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(clazz.interfaces.values));
-    while (!workList.isEmpty()) {
-      DexType next = workList.removeLast();
-      if (interfaceType == next) {
-        return true;
-      }
-      DexClass nextClass = appView.definitionFor(next);
-      if (nextClass != null) {
-        workList.addAll(Arrays.asList(nextClass.interfaces.values));
-      }
-    }
-    return false;
-  }
-
-  private DexMethod emulateInterfaceLibraryMethod(DexClassAndMethod method) {
+  DexMethod emulateInterfaceLibraryMethod(DexClassAndMethod method) {
     return factory.createMethod(
         getEmulateLibraryInterfaceClassType(method.getHolderType(), factory),
         factory.prependTypeToProto(method.getHolderType(), method.getProto()),
         method.getName());
   }
 
-  private DexProgramClass synthesizeEmulateInterfaceLibraryClass(
-      DexProgramClass theInterface, Map<DexType, List<DexType>> emulatedInterfacesHierarchy) {
-    List<DexEncodedMethod> emulationMethods = new ArrayList<>();
-    theInterface.forEachProgramMethodMatching(
-        DexEncodedMethod::isDefaultMethod,
-        method -> {
-          DexMethod libraryMethod =
-              method.getReference().withHolder(emulatedInterfaces.get(theInterface.type), factory);
-          DexMethod companionMethod =
-              method.getAccessFlags().isStatic()
-                  ? staticAsMethodOfCompanionClass(method)
-                  : defaultAsMethodOfCompanionClass(method);
-
-          // 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<>();
-          // 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 =
-              options.desugaredLibraryConfiguration.getRetargetCoreLibMember();
-          for (DexString methodName : retargetCoreLibMember.keySet()) {
-            if (method.getName() == methodName) {
-              for (DexType inType : retargetCoreLibMember.get(methodName).keySet()) {
-                DexClass inClass = appView.definitionFor(inType);
-                if (inClass != null && implementsInterface(inClass, theInterface.type)) {
-                  extraDispatchCases.add(
-                      new Pair<>(
-                          inType,
-                          factory.createMethod(
-                              retargetCoreLibMember.get(methodName).get(inType),
-                              factory.protoWithDifferentFirstParameter(
-                                  companionMethod.proto, inType),
-                              method.getName())));
-                }
-              }
-            }
-          }
-          if (subInterfaces != null) {
-            for (int i = subInterfaces.size() - 1; i >= 0; i--) {
-              DexClass subInterfaceClass = appView.definitionFor(subInterfaces.get(i));
-              assert subInterfaceClass
-                  != null; // Else computation of subInterface would have failed.
-              // if the method is implemented, extra dispatch is required.
-              DexEncodedMethod result =
-                  subInterfaceClass.lookupVirtualMethod(method.getReference());
-              if (result != null && !result.isAbstract()) {
-                extraDispatchCases.add(
-                    new Pair<>(
-                        subInterfaceClass.type,
-                        factory.createMethod(
-                            getCompanionClassType(subInterfaceClass.type),
-                            factory.protoWithDifferentFirstParameter(
-                                companionMethod.proto, subInterfaceClass.type),
-                            companionMethod.name)));
-              }
-            }
-          }
-          emulationMethods.add(
-              DexEncodedMethod.toEmulateDispatchLibraryMethod(
-                  method.getHolderType(),
-                  emulateInterfaceLibraryMethod(method),
-                  companionMethod,
-                  libraryMethod,
-                  extraDispatchCases,
-                  appView));
-        });
-    if (emulationMethods.isEmpty()) {
-      return null;
-    }
-    DexType emulateLibraryClassType =
-        getEmulateLibraryInterfaceClassType(theInterface.type, factory);
-    ClassAccessFlags emulateLibraryClassFlags = theInterface.accessFlags.copy();
-    emulateLibraryClassFlags.unsetAbstract();
-    emulateLibraryClassFlags.unsetInterface();
-    emulateLibraryClassFlags.unsetAnnotation();
-    emulateLibraryClassFlags.setFinal();
-    emulateLibraryClassFlags.setSynthetic();
-    emulateLibraryClassFlags.setPublic();
-    DexProgramClass clazz =
-        new DexProgramClass(
-            emulateLibraryClassType,
-            null,
-            new SynthesizedOrigin("interface desugaring (libs)", getClass()),
-            emulateLibraryClassFlags,
-            factory.objectType,
-            DexTypeList.empty(),
-            theInterface.sourceFile,
-            null,
-            Collections.emptyList(),
-            null,
-            Collections.emptyList(),
-            ClassSignature.noSignature(),
-            DexAnnotationSet.empty(),
-            DexEncodedField.EMPTY_ARRAY,
-            DexEncodedField.EMPTY_ARRAY,
-            // All synthesized methods are static in this case.
-            emulationMethods.toArray(DexEncodedMethod.EMPTY_ARRAY),
-            DexEncodedMethod.EMPTY_ARRAY,
-            factory.getSkipNameValidationForTesting(),
-            DexProgramClass::checksumFromType);
-    clazz.forEachProgramMethod(synthesizedMethods::add);
-    return clazz;
-  }
-
   private static String getEmulateLibraryInterfaceClassDescriptor(String descriptor) {
     return descriptor.substring(0, descriptor.length() - 1)
         + EMULATE_LIBRARY_CLASS_NAME_SUFFIX
@@ -1027,7 +822,7 @@
     return factory.createSynthesizedType(ccTypeDescriptor);
   }
 
-  DexType getCompanionClassType(DexType type) {
+  public DexType getCompanionClassType(DexType type) {
     return getCompanionClassType(type, factory);
   }
 
@@ -1049,8 +844,9 @@
   public static DexType getInterfaceClassType(DexType type, DexItemFactory factory) {
     assert isCompanionClassType(type);
     String descriptor = type.descriptor.toString();
-    String interfaceTypeDescriptor = descriptor.substring(0,
-        descriptor.length() - 1 - COMPANION_CLASS_NAME_SUFFIX.length()) + ";";
+    String interfaceTypeDescriptor =
+        descriptor.substring(0, descriptor.length() - 1 - COMPANION_CLASS_NAME_SUFFIX.length())
+            + ";";
     return factory.createType(interfaceTypeDescriptor);
   }
 
@@ -1082,8 +878,9 @@
   // not define this default methods, but inherits it. We are making our best effort
   // to find an appropriate method, but still use the original one in case we fail.
   private DexMethod amendDefaultMethod(DexClass classToDesugar, DexMethod method) {
-    DexMethod singleCandidate = getOrCreateInterfaceInfo(
-        classToDesugar, classToDesugar, method.holder).getSingleCandidate(method);
+    DexMethod singleCandidate =
+        getOrCreateInterfaceInfo(classToDesugar, classToDesugar, method.holder)
+            .getSingleCandidate(method);
     return singleCandidate != null ? singleCandidate : method;
   }
 
@@ -1093,7 +890,7 @@
     return instanceAsMethodOfCompanionClass(method, DEFAULT_METHOD_PREFIX, factory);
   }
 
-  final DexMethod defaultAsMethodOfCompanionClass(DexClassAndMethod method) {
+  public final DexMethod defaultAsMethodOfCompanionClass(DexClassAndMethod method) {
     DexItemFactory dexItemFactory = appView.dexItemFactory();
     DexMethod rewritten = defaultAsMethodOfCompanionClass(method.getReference(), dexItemFactory);
     recordCompanionClassReference(appView, method, rewritten);
@@ -1159,107 +956,33 @@
     }
   }
 
-  private void renameEmulatedInterfaces() {
-    // Rename manually the emulated interfaces, we do not use the PrefixRenamingLens
-    // because both the normal and emulated interfaces are used.
-    for (DexClass clazz : appView.appInfo().classes()) {
-      if (clazz.isInterface()) {
-        DexType newType = inferEmulatedInterfaceName(clazz);
-        if (newType != null && !appView.rewritePrefix.hasRewrittenType(clazz.type, appView)) {
-          // We do not rewrite if it is already going to be rewritten using the a rewritingPrefix.
-          addRewritePrefix(clazz.type, newType.toString());
-          renameEmulatedInterfaces(clazz, newType);
-        }
-      }
-    }
-  }
-
-  private DexType inferEmulatedInterfaceName(DexClass subInterface) {
-    DexType newType = emulatedInterfaces.get(subInterface.type);
-    if (newType != null) {
-      return newType;
-    }
-    LinkedList<DexType> workList = new LinkedList<>(Arrays.asList(subInterface.interfaces.values));
-    while (!workList.isEmpty()) {
-      DexType next = workList.removeFirst();
-      if (emulatedInterfaces.get(next) != null) {
-        return inferEmulatedInterfaceName(subInterface.type, next);
-      }
-      DexClass nextClass = appView.definitionFor(next);
-      if (nextClass != null) {
-        workList.addAll(Arrays.asList(nextClass.interfaces.values));
-      }
-    }
-    return null;
-  }
-
-  private DexType inferEmulatedInterfaceName(DexType subInterfaceType, DexType interfaceType) {
-    String initialPrefix = interfaceType.getPackageName();
-    String rewrittenPrefix = emulatedInterfaces.get(interfaceType).getPackageName();
-    String suffix = subInterfaceType.toString().substring(initialPrefix.length());
-    return factory.createType(DescriptorUtils.javaTypeToDescriptor(rewrittenPrefix + suffix));
-  }
-
-  private void renameEmulatedInterfaces(DexClass theInterface, DexType renamedInterface) {
-    theInterface.type = renamedInterface;
-    theInterface.setVirtualMethods(renameHolder(theInterface.virtualMethods(), renamedInterface));
-    theInterface.setDirectMethods(renameHolder(theInterface.directMethods(), renamedInterface));
-  }
-
-  private DexEncodedMethod[] renameHolder(Iterable<DexEncodedMethod> methods, DexType newName) {
-    return renameHolder(IterableUtils.toNewArrayList(methods), newName);
-  }
-
-  private DexEncodedMethod[] renameHolder(List<DexEncodedMethod> methods, DexType newName) {
-    DexEncodedMethod[] newMethods = new DexEncodedMethod[methods.size()];
-    for (int i = 0; i < newMethods.length; i++) {
-      newMethods[i] = methods.get(i).toRenamedHolderMethod(newName, factory);
-    }
-    return newMethods;
-  }
-
   /**
    * Move static and default interface methods to companion classes, add missing methods to forward
    * to moved default methods implementation.
    */
   public void desugarInterfaceMethods(
-      Builder<?> builder,
-      Flavor flavour,
-      ExecutorService executorService)
+      Builder<?> builder, Flavor flavour, ExecutorService executorService)
       throws ExecutionException {
-    if (appView.options().isDesugaredLibraryCompilation()) {
-      generateEmulateInterfaceLibrary(builder);
-    }
+    // TODO(b/183998768): Merge the following four sequential loops into a single one.
+
+    EmulatedInterfaceProcessor emulatedInterfaceProcessor =
+        new EmulatedInterfaceProcessor(appView, this);
+    // TODO(b/183998768): Move this to emulatedInterfaceProcessor#process
+    forEachProgramEmulatedInterface(emulatedInterfaceProcessor::generateEmulateInterfaceLibrary);
 
     // Process all classes first. Add missing forwarding methods to
     // replace desugared default interface methods.
-    processClasses(builder, flavour, synthesizedMethods::add);
-    transformEmulatedInterfaces();
+    process(new ClassProcessor(appView, this), builder, flavour);
 
     // Process interfaces, create companion or dispatch class if needed, move static
     // methods to companion class, copy default interface methods to companion classes,
     // make original default methods abstract, remove bridge methods, create dispatch
     // classes if needed.
-    AppInfo appInfo = appView.appInfo();
-    InterfaceProcessorNestedGraphLens.Builder graphLensBuilder =
-        InterfaceProcessorNestedGraphLens.builder();
-    Map<DexClass, DexProgramClass> classMapping =
-        processInterfaces(builder, flavour, graphLensBuilder, synthesizedMethods::add);
-    InterfaceProcessorNestedGraphLens graphLens = graphLensBuilder.build(appView);
-    if (appView.enableWholeProgramOptimizations() && graphLens != null) {
-      appView.setGraphLens(graphLens);
-    }
-    classMapping.forEach(
-        (interfaceClass, synthesizedClass) -> {
-          // Don't need to optimize synthesized class since all of its methods
-          // are just moved from interfaces and don't need to be re-processed.
-          builder.addSynthesizedClass(synthesizedClass);
-          appInfo.addSynthesizedClass(synthesizedClass, interfaceClass.asProgramClass());
-        });
-    new InterfaceMethodRewriterFixup(appView, graphLens).run();
-    if (appView.options().isDesugaredLibraryCompilation()) {
-      renameEmulatedInterfaces();
-    }
+    process(new InterfaceProcessor(appView, this), builder, flavour);
+
+    // During L8 compilation, emulated interfaces are processed to be renamed, to have
+    // their interfaces fixed-up and to generate the emulated dispatch code.
+    process(emulatedInterfaceProcessor, builder, flavour);
 
     converter.processMethodsConcurrently(synthesizedMethods, executorService);
 
@@ -1267,42 +990,16 @@
     clear();
   }
 
-  private void transformEmulatedInterfaces() {
-    for (DexType dexType : emulatedInterfaces.keySet()) {
-      DexClass dexClass = appView.definitionFor(dexType);
-      if (dexClass != null && dexClass.isProgramClass()) {
-        transformEmulatedInterfaces(dexClass.asProgramClass());
-      }
-    }
-  }
-
-  // The method transforms emulated interface such as they implement the rewritten version
-  // of each emulated interface they implement. Such change should have no effect on the look-up
-  // results, since each class implementing an emulated interface should also implement the
-  // rewritten one.
-  private void transformEmulatedInterfaces(DexProgramClass clazz) {
-    if (appView.isAlreadyLibraryDesugared(clazz)) {
+  private void forEachProgramEmulatedInterface(Consumer<DexProgramClass> consumer) {
+    if (!appView.options().isDesugaredLibraryCompilation()) {
       return;
     }
-    List<GenericSignature.ClassTypeSignature> newInterfaces = new ArrayList<>();
-    GenericSignature.ClassSignature classSignature = clazz.getClassSignature();
-    for (int i = 0; i < clazz.interfaces.size(); i++) {
-      DexType itf = clazz.interfaces.values[i];
-      if (emulatedInterfaces.containsKey(itf)) {
-        List<GenericSignature.FieldTypeSignature> typeArguments;
-        if (classSignature == null) {
-          typeArguments = Collections.emptyList();
-        } else {
-          GenericSignature.ClassTypeSignature classTypeSignature =
-              classSignature.superInterfaceSignatures().get(i);
-          assert itf == classTypeSignature.type();
-          typeArguments = classTypeSignature.typeArguments();
-        }
-        newInterfaces.add(
-            new GenericSignature.ClassTypeSignature(emulatedInterfaces.get(itf), typeArguments));
+    for (DexType interfaceType : emulatedInterfaces.keySet()) {
+      DexClass theInterface = appView.definitionFor(interfaceType);
+      if (theInterface != null && theInterface.isProgramClass()) {
+        consumer.accept(theInterface.asProgramClass());
       }
     }
-    clazz.replaceInterfaces(newInterfaces);
   }
 
   private void clear() {
@@ -1310,41 +1007,20 @@
     this.synthesizedMethods.clear();
   }
 
-  private static boolean shouldProcess(
-      DexProgramClass clazz, Flavor flavour, boolean mustBeInterface) {
-    return (!clazz.originatesFromDexResource() || flavour == Flavor.IncludeAllResources)
-        && clazz.isInterface() == mustBeInterface;
+  private boolean shouldProcess(DexProgramClass clazz, Flavor flavour) {
+    if (appView.isAlreadyLibraryDesugared(clazz)) {
+      return false;
+    }
+    return (!clazz.originatesFromDexResource() || flavour == Flavor.IncludeAllResources);
   }
 
-  private Map<DexClass, DexProgramClass> processInterfaces(
-      Builder<?> builder,
-      Flavor flavour,
-      InterfaceProcessorNestedGraphLens.Builder graphLensBuilder,
-      Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
-    InterfaceProcessor processor = new InterfaceProcessor(appView, this);
+  private void process(InterfaceDesugaringProcessor processor, Builder<?> builder, Flavor flavour) {
     for (DexProgramClass clazz : builder.getProgramClasses()) {
-      if (shouldProcess(clazz, flavour, true)) {
-        processor.process(clazz, graphLensBuilder, newSynthesizedMethodConsumer);
+      if (shouldProcess(clazz, flavour) && processor.shouldProcess(clazz)) {
+        processor.process(clazz, synthesizedMethods);
       }
     }
-    return processor.syntheticClasses;
-  }
-
-  private void processClasses(
-      Builder<?> builder, Flavor flavour, Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
-    ClassProcessor processor = new ClassProcessor(appView, this, newSynthesizedMethodConsumer);
-    // First we compute all desugaring *without* introducing forwarding methods.
-    assert appView.getSyntheticItems().verifyNonLegacySyntheticsAreCommitted();
-    for (DexProgramClass clazz : builder.getProgramClasses()) {
-      if (shouldProcess(clazz, flavour, false)) {
-        if (appView.isAlreadyLibraryDesugared(clazz)) {
-          continue;
-        }
-        processor.processClass(clazz);
-      }
-    }
-    // Then we introduce forwarding methods.
-    processor.addSyntheticMethods();
+    processor.finalizeProcessing(builder, synthesizedMethods);
   }
 
   final boolean isDefaultMethod(DexEncodedMethod method) {
@@ -1428,9 +1104,7 @@
   }
 
   final DefaultMethodsHelper.Collection getOrCreateInterfaceInfo(
-      DexClass classToDesugar,
-      DexClass implementing,
-      DexType iface) {
+      DexClass classToDesugar, DexClass implementing, DexType iface) {
     DefaultMethodsHelper.Collection collection = cache.get(iface);
     if (collection != null) {
       return collection;
@@ -1441,9 +1115,7 @@
   }
 
   private DefaultMethodsHelper.Collection createInterfaceInfo(
-      DexClass classToDesugar,
-      DexClass implementing,
-      DexType iface) {
+      DexClass classToDesugar, DexClass implementing, DexType iface) {
     DefaultMethodsHelper helper = new DefaultMethodsHelper();
     DexClass definedInterface = appView.definitionFor(iface);
     if (definedInterface == null) {
@@ -1452,8 +1124,11 @@
     }
     if (!definedInterface.isInterface()) {
       throw new CompilationError(
-          "Type " + iface.toSourceString() + " is referenced as an interface from `"
-              + implementing.toString() + "`.");
+          "Type "
+              + iface.toSourceString()
+              + " is referenced as an interface from `"
+              + implementing.toString()
+              + "`.");
     }
 
     if (isNonDesugaredLibraryClass(definedInterface)) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriterFixup.java
similarity index 92%
rename from src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriterFixup.java
index bb0de67..b3d5f1b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriterFixup.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriterFixup.java
@@ -1,14 +1,14 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.graph.EnclosingMethodAttribute;
 import com.android.tools.r8.graph.InnerClassAttribute;
-import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
+import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
 
 class InterfaceMethodRewriterFixup {
   private final AppView<?> appView;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
similarity index 92%
rename from src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
rename to src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index 0199730..32c8c64 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -1,8 +1,8 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
-package com.android.tools.r8.ir.desugar;
+package com.android.tools.r8.ir.desugar.itf;
 
 import static com.android.tools.r8.utils.PredicateUtils.not;
 
@@ -21,6 +21,7 @@
 import com.android.tools.r8.graph.ClassAccessFlags;
 import com.android.tools.r8.graph.Code;
 import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication.Builder;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
@@ -50,6 +51,7 @@
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
 import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
 import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
@@ -60,7 +62,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.function.Consumer;
 import org.objectweb.asm.Opcodes;
 
 // Default and static method interface desugaring processor for interfaces.
@@ -69,24 +70,28 @@
 // a companion class. Removes bridge default methods.
 //
 // Also moves static interface methods into a companion class.
-public final class InterfaceProcessor {
+public final class InterfaceProcessor implements InterfaceDesugaringProcessor {
 
   private final AppView<?> appView;
   private final InterfaceMethodRewriter rewriter;
+  private final InterfaceProcessorNestedGraphLens.Builder graphLensBuilder;
 
-  // All created companion and dispatch classes indexed by interface type.
+  // All created companion classes indexed by interface type.
   final Map<DexClass, DexProgramClass> syntheticClasses = new IdentityHashMap<>();
 
-  InterfaceProcessor(
-      AppView<?> appView, InterfaceMethodRewriter rewriter) {
+  InterfaceProcessor(AppView<?> appView, InterfaceMethodRewriter rewriter) {
     this.appView = appView;
     this.rewriter = rewriter;
+    graphLensBuilder = InterfaceProcessorNestedGraphLens.builder();
   }
 
-  void process(
-      DexProgramClass iface,
-      InterfaceProcessorNestedGraphLens.Builder graphLensBuilder,
-      Consumer<ProgramMethod> newSynthesizedMethodConsumer) {
+  @Override
+  public boolean shouldProcess(DexProgramClass clazz) {
+    return clazz.isInterface();
+  }
+
+  @Override
+  public void process(DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
     assert iface.isInterface();
     // The list of methods to be created in companion class.
     List<DexEncodedMethod> companionMethods = new ArrayList<>();
@@ -138,7 +143,7 @@
             getChecksumSupplier(iface));
     syntheticClasses.put(iface, companionClass);
     if (companionClass.hasClassInitializer()) {
-      newSynthesizedMethodConsumer.accept(companionClass.getProgramClassInitializer());
+      synthesizedMethods.add(companionClass.getProgramClassInitializer());
     }
   }
 
@@ -439,6 +444,22 @@
         && !rewriter.factory.isClassConstructor(method.getReference());
   }
 
+  @Override
+  public void finalizeProcessing(Builder<?> builder, ProgramMethodSet synthesizedMethods) {
+    InterfaceProcessorNestedGraphLens graphLens = graphLensBuilder.build(appView);
+    if (appView.enableWholeProgramOptimizations() && graphLens != null) {
+      appView.setGraphLens(graphLens);
+    }
+    syntheticClasses.forEach(
+        (interfaceClass, synthesizedClass) -> {
+          // Don't need to optimize synthesized class since all of its methods
+          // are just moved from interfaces and don't need to be re-processed.
+          builder.addSynthesizedClass(synthesizedClass);
+          appView.appInfo().addSynthesizedClass(synthesizedClass, interfaceClass.asProgramClass());
+        });
+    new InterfaceMethodRewriterFixup(appView, graphLens).run();
+  }
+
   // Specific lens which remaps invocation types to static since all rewrites performed here
   // are to static companion methods.
   public static class InterfaceProcessorNestedGraphLens extends NestedGraphLens {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
index 44a37b0..b622057 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/nest/D8NestBasedAccessDesugaring.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.ir.desugar.nest;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.reportDependencyEdge;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.reportDependencyEdge;
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ClasspathMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index 0f12d78..2f32c5c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -54,7 +54,7 @@
 import com.android.tools.r8.ir.code.ValueTypeConstraint;
 import com.android.tools.r8.ir.conversion.IRBuilder;
 import com.android.tools.r8.ir.conversion.SourceCode;
-import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
+import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
 import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.origin.Origin;
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index 3b2c0d5..92a507b 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -21,7 +21,7 @@
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
 import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
 import com.android.tools.r8.naming.MemberNaming.FieldSignature;
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 4622786..69c27c5 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -47,8 +47,8 @@
 import com.android.tools.r8.ir.code.Invoke.Type;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
 import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.synthesis.CommittedItems;
 import com.android.tools.r8.utils.CollectionUtils;
 import com.android.tools.r8.utils.InternalOptions;
diff --git a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
index ac0d153..963e036 100644
--- a/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
+++ b/src/main/java/com/android/tools/r8/shaking/GraphReporter.java
@@ -29,7 +29,7 @@
 import com.android.tools.r8.graph.ProgramDefinition;
 import com.android.tools.r8.graph.ProgramField;
 import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.references.TypeReference;
 import com.android.tools.r8.utils.DequeUtils;
diff --git a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
index 2cce6ff..317a4cd 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -6,7 +6,7 @@
 
 import static com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter.DESCRIPTOR_VIVIFIED_PREFIX;
 import static com.android.tools.r8.ir.desugar.DesugaredLibraryRetargeter.getRetargetPackageAndClassPrefixDescriptor;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
 import static com.android.tools.r8.utils.collections.IdentityHashSetFromMap.newProgramDerivedContextSet;
 
 import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index c5ce290..dfca4e2 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.errors.InternalCompilerError;
 import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
diff --git a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
index 7f1940e..fd7a3bd 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesJava9Test.java
@@ -13,7 +13,7 @@
 import static org.junit.Assume.assumeFalse;
 
 import com.android.tools.r8.ToolHelper.DexVm;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.TestDescriptionWatcher;
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
index e542559..210967c 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerDebugTestRunner.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.classmerging.vertical;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.hamcrest.CoreMatchers.not;
 import static org.hamcrest.MatcherAssert.assertThat;
diff --git a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
index e72cf0a..5f4be39 100644
--- a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
@@ -7,7 +7,7 @@
 import static org.junit.Assert.assertEquals;
 
 import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Collection;
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java b/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
index 9a7802f..d65470d 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarInnerClassesInInterfaces.java
@@ -8,7 +8,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.google.common.collect.ImmutableList;
 import java.util.List;
 import java.util.concurrent.Callable;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
index d767975..4e96f57 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmulatedInterfacesTest.java
@@ -14,7 +14,7 @@
 import com.android.tools.r8.code.Instruction;
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.BooleanUtils;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
diff --git a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
index 3e60058..c61b1fd 100644
--- a/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/enclosingmethod/EnclosingMethodRewriteTest.java
@@ -3,8 +3,8 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.desugar.enclosingmethod;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertEquals;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
index c0267f2..a86ee63 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlineFromStaticInterfaceMethodTest.java
@@ -12,7 +12,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.android.tools.r8.utils.codeinspector.InstructionSubject;
diff --git a/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java b/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
index 2d0d180..2875a43 100644
--- a/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
+++ b/src/test/java/com/android/tools/r8/jasmin/AnnotationCompanionClassTest.java
@@ -7,7 +7,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.junit.Assert.assertFalse;
 
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
index ad3b7eb..cae1185 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/desugar/DefaultInterfaceMethodTest.java
@@ -10,7 +10,7 @@
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.StringUtils;
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
index a969d1b..961d400 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.shaking.ifrule.interfacemethoddesugaring;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic;
 import static com.android.tools.r8.utils.codeinspector.Matchers.isStatic;
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index 46924fd..fe06c06 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -5,7 +5,7 @@
 
 import static org.hamcrest.CoreMatchers.containsString;
 
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.references.ClassReference;
 import com.android.tools.r8.references.MethodReference;
 import com.android.tools.r8.references.Reference;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index ee96d6b..a794e67 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX;
 
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProgramClass;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index c20ccd6..c830cf6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -24,7 +24,7 @@
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexType;
 import com.android.tools.r8.ir.conversion.SwitchPayloadResolver;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter;
 import com.android.tools.r8.naming.ClassNameMapper;
 import com.android.tools.r8.naming.ClassNamingForNameMapper;
 import com.android.tools.r8.naming.MemberNaming.MethodSignature;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 0eb0de1..f215cca 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -4,7 +4,7 @@
 
 package com.android.tools.r8.utils.codeinspector;
 
-import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
+import static com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.DEFAULT_METHOD_PREFIX;
 
 import com.android.tools.r8.cf.code.CfInstruction;
 import com.android.tools.r8.cf.code.CfPosition;