Reland "Interface processing as post processing in D8"

This relands commit 79f75ed44e00bd6d0e5996ff854117939c1f0ed8.

Reland "InterfaceMethodProcessorFacade clean-up"

This relands commit fc459a413afdfe1aacf78d0f7382e3ac4cb67c82.

Reland "Do not process forwarding methods while adding them"

This relands commit 69a1e1774a35e8d7f91ad7a3d5c3f2548706cebf.

Change-Id: I29a8bd70c871bbc7c4cc15aef288b4c69d198f1a
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
index 9508da1..136d452 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/ClassConverter.java
@@ -13,8 +13,6 @@
 import com.android.tools.r8.ir.desugar.CfClassDesugaringEventConsumer.D8CfClassDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
-import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.D8CfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
@@ -112,13 +110,6 @@
 
       classes = deferred;
     }
-
-    D8CfPostProcessingDesugaringEventConsumer eventConsumer =
-        CfPostProcessingDesugaringEventConsumer.createForD8(methodProcessor, appView);
-    methodProcessor.newWave();
-    converter.postProcessDesugaring(eventConsumer);
-    methodProcessor.awaitMethodProcessing();
-    eventConsumer.finalizeDesugaring();
   }
 
   abstract void convertClass(
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 b01f268..3144113 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
@@ -51,11 +51,13 @@
 import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer.D8CfInstructionDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringCollection;
 import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer.D8CfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
 import com.android.tools.r8.ir.desugar.ProgramAdditions;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter.Mode;
 import com.android.tools.r8.ir.desugar.itf.EmulatedInterfaceApplicationRewriter;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 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;
@@ -225,10 +227,7 @@
       assert options.desugarState.isOn();
       this.instructionDesugaring = CfInstructionDesugaringCollection.create(appView);
       this.classDesugaring = instructionDesugaring.createClassDesugaringCollection();
-      this.interfaceMethodRewriter =
-          options.desugaredLibraryConfiguration.getEmulateLibraryInterface().isEmpty()
-              ? null
-              : new InterfaceMethodRewriter(appView, this);
+      this.interfaceMethodRewriter = null;
       this.desugaredLibraryAPIConverter =
           new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS);
       this.covariantReturnTypeAnnotationTransformer = null;
@@ -258,7 +257,7 @@
             : CfInstructionDesugaringCollection.create(appView);
     this.classDesugaring = instructionDesugaring.createClassDesugaringCollection();
     this.interfaceMethodRewriter =
-        options.isInterfaceMethodDesugaringEnabled()
+        options.isInterfaceMethodDesugaringEnabled() && appView.enableWholeProgramOptimizations()
             ? new InterfaceMethodRewriter(appView, this)
             : null;
     this.covariantReturnTypeAnnotationTransformer =
@@ -366,11 +365,6 @@
         D8NestBasedAccessDesugaring::clearNestAttributes);
   }
 
-  void postProcessDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
-    CfPostProcessingDesugaringCollection.create(appView, instructionDesugaring.getRetargetingInfo())
-        .postProcessingDesugaring(eventConsumer);
-  }
-
   private void staticizeClasses(
       OptimizationFeedback feedback, ExecutorService executorService, GraphLens applied)
       throws ExecutionException {
@@ -393,11 +387,11 @@
     }
   }
 
-  private void runInterfaceDesugaringProcessors(
+  private void runInterfaceDesugaringProcessorsForR8(
       Flavor includeAllResources, ExecutorService executorService) throws ExecutionException {
     assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
     if (interfaceMethodRewriter != null) {
-      interfaceMethodRewriter.runInterfaceDesugaringProcessors(
+      interfaceMethodRewriter.runInterfaceDesugaringProcessorsForR8(
           this, includeAllResources, executorService);
     }
   }
@@ -414,25 +408,24 @@
     workaroundAbstractMethodOnNonAbstractClassVerificationBug(
         executor, OptimizationFeedbackIgnore.getInstance());
     DexApplication application = appView.appInfo().app();
+    D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executor);
+
     timing.begin("IR conversion");
 
-    convertClasses(executor);
+    convertClasses(methodProcessor, executor);
 
     reportNestDesugarDependencies();
     clearNestAttributes();
 
-    if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
-      appView.setAppInfo(
-          new AppInfo(
-              appView.appInfo().getSyntheticItems().commit(application),
-              appView.appInfo().getMainDexInfo()));
-      application = appView.appInfo().app();
-    }
+    application = commitPendingSyntheticItems(appView, application);
+
+    postProcessingDesugaringForD8(methodProcessor, executor);
+
+    application = commitPendingSyntheticItems(appView, application);
 
     // Build a new application with jumbo string info,
     Builder<?> builder = application.builder().setHighestSortingString(highestSortingString);
 
-    runInterfaceDesugaringProcessors(ExcludeDexResources, executor);
     if (appView.options().isDesugaredLibraryCompilation()) {
       new EmulatedInterfaceApplicationRewriter(appView).rewriteApplication(builder);
     }
@@ -448,8 +441,34 @@
             appView.appInfo().getMainDexInfo()));
   }
 
-  private void convertClasses(ExecutorService executorService) throws ExecutionException {
-    D8MethodProcessor methodProcessor = new D8MethodProcessor(this, executorService);
+  private DexApplication commitPendingSyntheticItems(
+      AppView<AppInfo> appView, DexApplication application) {
+    if (appView.getSyntheticItems().hasPendingSyntheticClasses()) {
+      appView.setAppInfo(
+          new AppInfo(
+              appView.appInfo().getSyntheticItems().commit(application),
+              appView.appInfo().getMainDexInfo()));
+      application = appView.appInfo().app();
+    }
+    return application;
+  }
+
+  private void postProcessingDesugaringForD8(
+      D8MethodProcessor methodProcessor, ExecutorService executorService)
+      throws ExecutionException {
+    D8CfPostProcessingDesugaringEventConsumer eventConsumer =
+        CfPostProcessingDesugaringEventConsumer.createForD8(methodProcessor, appView);
+    methodProcessor.newWave();
+    InterfaceMethodProcessorFacade interfaceDesugaring =
+        instructionDesugaring.getInterfaceMethodPostProcessingDesugaring(ExcludeDexResources);
+    CfPostProcessingDesugaringCollection.create(
+            appView, interfaceDesugaring, instructionDesugaring.getRetargetingInfo())
+        .postProcessingDesugaring(eventConsumer, executorService);
+    eventConsumer.finalizeDesugaring();
+  }
+
+  private void convertClasses(D8MethodProcessor methodProcessor, ExecutorService executorService)
+      throws ExecutionException {
     ClassConverterResult classConverterResult =
         ClassConverter.create(appView, this, methodProcessor).convertClasses(executorService);
 
@@ -796,7 +815,7 @@
 
     printPhase("Interface method desugaring");
     finalizeInterfaceMethodRewritingThroughIR(executorService);
-    runInterfaceDesugaringProcessors(IncludeAllResources, executorService);
+    runInterfaceDesugaringProcessorsForR8(IncludeAllResources, executorService);
     feedback.updateVisibleOptimizationInfo();
 
     printPhase("Desugared library API Conversion finalization");
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
index 6efa25b..8512734 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringCollection.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.utils.ThrowingConsumer;
 
@@ -58,5 +60,8 @@
   public abstract <T extends Throwable> void withD8NestBasedAccessDesugaring(
       ThrowingConsumer<D8NestBasedAccessDesugaring, T> consumer) throws T;
 
+  public abstract InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(
+      Flavor flavor);
+
   public abstract RetargetingInfo getRetargetingInfo();
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java
index 2a2de5f..38a0413 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaring.java
@@ -3,7 +3,12 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.ir.desugar;
 
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+
 public interface CfPostProcessingDesugaring {
 
-  void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer);
+  void postProcessingDesugaring(
+      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      throws ExecutionException;
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
index f659ad8..986c6ea 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringCollection.java
@@ -6,15 +6,21 @@
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterPostProcessor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
-import java.util.Collections;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
 
 public abstract class CfPostProcessingDesugaringCollection {
 
   public static CfPostProcessingDesugaringCollection create(
-      AppView<?> appView, RetargetingInfo retargetingInfo) {
+      AppView<?> appView,
+      InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
+      RetargetingInfo retargetingInfo) {
     if (appView.options().desugarState.isOn()) {
-      return NonEmptyCfPostProcessingDesugaringCollection.create(appView, retargetingInfo);
+      return NonEmptyCfPostProcessingDesugaringCollection.create(
+          appView, interfaceMethodProcessorFacade, retargetingInfo);
     }
     return empty();
   }
@@ -24,7 +30,8 @@
   }
 
   public abstract void postProcessingDesugaring(
-      CfPostProcessingDesugaringEventConsumer eventConsumer);
+      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      throws ExecutionException;
 
   public static class NonEmptyCfPostProcessingDesugaringCollection
       extends CfPostProcessingDesugaringCollection {
@@ -37,19 +44,29 @@
     }
 
     public static CfPostProcessingDesugaringCollection create(
-        AppView<?> appView, RetargetingInfo retargetingInfo) {
-      if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
+        AppView<?> appView,
+        InterfaceMethodProcessorFacade interfaceMethodProcessorFacade,
+        RetargetingInfo retargetingInfo) {
+      if (appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()
+          && interfaceMethodProcessorFacade == null) {
         return empty();
       }
-      return new NonEmptyCfPostProcessingDesugaringCollection(
-          Collections.singletonList(
-              new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo)));
+      ArrayList<CfPostProcessingDesugaring> desugarings = new ArrayList<>();
+      if (!appView.options().desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()) {
+        desugarings.add(new DesugaredLibraryRetargeterPostProcessor(appView, retargetingInfo));
+      }
+      if (interfaceMethodProcessorFacade != null) {
+        desugarings.add(interfaceMethodProcessorFacade);
+      }
+      return new NonEmptyCfPostProcessingDesugaringCollection(desugarings);
     }
 
     @Override
-    public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
+    public void postProcessingDesugaring(
+        CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+        throws ExecutionException {
       for (CfPostProcessingDesugaring desugaring : desugarings) {
-        desugaring.postProcessingDesugaring(eventConsumer);
+        desugaring.postProcessingDesugaring(eventConsumer, executorService);
       }
     }
   }
@@ -67,7 +84,9 @@
     }
 
     @Override
-    public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
+    public void postProcessingDesugaring(
+        CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+        throws ExecutionException {
       // Intentionally empty.
     }
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
index dc67ee9..5734cab 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfPostProcessingDesugaringEventConsumer.java
@@ -11,7 +11,10 @@
 import com.android.tools.r8.ir.conversion.D8MethodProcessor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryAPIConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeterInstructionEventConsumer.DesugaredLibraryRetargeterPostProcessingEventConsumer;
+import com.android.tools.r8.ir.desugar.itf.InterfaceProcessingDesugaringEventConsumer;
 import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import java.util.concurrent.ExecutionException;
 
 /**
  * Specialized Event consumer for desugaring finalization. During finalization, it is not possible
@@ -19,7 +22,8 @@
  * explicit calls must be done here.
  */
 public abstract class CfPostProcessingDesugaringEventConsumer
-    implements DesugaredLibraryRetargeterPostProcessingEventConsumer {
+    implements DesugaredLibraryRetargeterPostProcessingEventConsumer,
+        InterfaceProcessingDesugaringEventConsumer {
   protected DesugaredLibraryAPIConverter desugaredLibraryAPIConverter;
 
   protected CfPostProcessingDesugaringEventConsumer(AppView<?> appView) {
@@ -36,13 +40,14 @@
     return new R8PostProcessingDesugaringEventConsumer(appView, additions);
   }
 
-  public void finalizeDesugaring() {
-    desugaredLibraryAPIConverter.generateTrackingWarnings();
-  }
+  public abstract void finalizeDesugaring() throws ExecutionException;
 
   public static class D8CfPostProcessingDesugaringEventConsumer
       extends CfPostProcessingDesugaringEventConsumer {
     private final D8MethodProcessor methodProcessor;
+    // Methods cannot be processed directly because we cannot add method to classes while
+    // concurrently processing other methods.
+    private final ProgramMethodSet methodsToReprocess = ProgramMethodSet.createConcurrent();
 
     private D8CfPostProcessingDesugaringEventConsumer(
         D8MethodProcessor methodProcessor, AppView<?> appView) {
@@ -52,7 +57,7 @@
 
     @Override
     public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
-      methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods());
+      methodsToReprocess.addAll(clazz.programMethods());
     }
 
     @Override
@@ -67,9 +72,25 @@
 
     @Override
     public void acceptForwardingMethod(ProgramMethod method) {
-      methodProcessor.scheduleDesugaredMethodForProcessing(method);
-      // TODO(b/189912077): Uncomment when API conversion is performed cf to cf in D8.
-      // desugaredLibraryAPIConverter.generateCallbackIfRequired(method);
+      methodsToReprocess.add(method);
+    }
+
+    @Override
+    public void acceptCompanionClassClinit(ProgramMethod method) {
+      methodsToReprocess.add(method);
+    }
+
+    @Override
+    public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
+      methodsToReprocess.add(method);
+    }
+
+    @Override
+    public void finalizeDesugaring() throws ExecutionException {
+      assert methodProcessor.verifyNoPendingMethodProcessing();
+      methodProcessor.newWave();
+      methodProcessor.scheduleDesugaredMethodsForProcessing(methodsToReprocess);
+      methodProcessor.awaitMethodProcessing();
     }
   }
 
@@ -84,6 +105,11 @@
     }
 
     @Override
+    public void finalizeDesugaring() throws ExecutionException {
+      desugaredLibraryAPIConverter.generateTrackingWarnings();
+    }
+
+    @Override
     public void acceptDesugaredLibraryRetargeterDispatchProgramClass(DexProgramClass clazz) {
       additions.addLiveMethods(clazz.programMethods());
     }
@@ -106,5 +132,15 @@
         additions.addLiveMethod(callback);
       }
     }
+
+    @Override
+    public void acceptCompanionClassClinit(ProgramMethod method) {
+      assert false : "TODO(b/183998768): Support Interface processing in R8";
+    }
+
+    @Override
+    public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
+      assert false : "TODO(b/183998768): Support Interface processing in R8";
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
index 61c9617..7991ac3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/EmptyCfInstructionDesugaringCollection.java
@@ -8,6 +8,8 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.desugar.CfClassDesugaringCollection.EmptyCfClassDesugaringCollection;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.utils.ThrowingConsumer;
 
@@ -63,6 +65,11 @@
   }
 
   @Override
+  public InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(Flavor flavor) {
+    return null;
+  }
+
+  @Override
   public RetargetingInfo getRetargetingInfo() {
     return null;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
index 150fc0a..a7f1a33 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NonEmptyCfInstructionDesugaringCollection.java
@@ -17,7 +17,9 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibraryRetargeter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.RetargetingInfo;
 import com.android.tools.r8.ir.desugar.invokespecial.InvokeSpecialToSelfDesugaring;
+import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
 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.LambdaInstructionDesugaring;
 import com.android.tools.r8.ir.desugar.nest.D8NestBasedAccessDesugaring;
 import com.android.tools.r8.ir.desugar.nest.NestBasedAccessDesugaring;
@@ -42,6 +44,7 @@
   private final NestBasedAccessDesugaring nestBasedAccessDesugaring;
   private final RecordRewriter recordRewriter;
   private final DesugaredLibraryRetargeter desugaredLibraryRetargeter;
+  private final InterfaceMethodRewriter interfaceMethodRewriter;
 
   NonEmptyCfInstructionDesugaringCollection(AppView<?> appView) {
     this.appView = appView;
@@ -49,6 +52,7 @@
       this.nestBasedAccessDesugaring = null;
       this.recordRewriter = null;
       this.desugaredLibraryRetargeter = null;
+      this.interfaceMethodRewriter = null;
       return;
     }
     this.nestBasedAccessDesugaring = NestBasedAccessDesugaring.create(appView);
@@ -68,11 +72,14 @@
       desugarings.add(new TwrInstructionDesugaring(appView));
     }
     // TODO(b/183998768): Enable interface method rewriter cf to cf also in R8.
-    if (appView.options().isInterfaceMethodDesugaringEnabled()
-        && !appView.enableWholeProgramOptimizations()) {
-      desugarings.add(
-          new InterfaceMethodRewriter(
-              appView, backportedMethodRewriter, desugaredLibraryRetargeter));
+    interfaceMethodRewriter =
+        appView.options().isInterfaceMethodDesugaringEnabled()
+                && !appView.enableWholeProgramOptimizations()
+            ? new InterfaceMethodRewriter(
+                appView, backportedMethodRewriter, desugaredLibraryRetargeter)
+            : null;
+    if (interfaceMethodRewriter != null) {
+      desugarings.add(interfaceMethodRewriter);
     }
     desugarings.add(new LambdaInstructionDesugaring(appView));
     desugarings.add(new InvokeSpecialToSelfDesugaring(appView));
@@ -312,6 +319,13 @@
   }
 
   @Override
+  public InterfaceMethodProcessorFacade getInterfaceMethodPostProcessingDesugaring(Flavor flavor) {
+    return interfaceMethodRewriter != null
+        ? interfaceMethodRewriter.getPostProcessingDesugaring(flavor)
+        : null;
+  }
+
+  @Override
   public RetargetingInfo getRetargetingInfo() {
     if (desugaredLibraryRetargeter != null) {
       return desugaredLibraryRetargeter.getRetargetingInfo();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
index 0b0039e..dac3079 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryRetargeterPostProcessor.java
@@ -23,6 +23,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
 
 // The rewrite of virtual calls requires to go through emulate dispatch. This class is responsible
 // for inserting interfaces on library boundaries and forwarding methods in the program, and to
@@ -41,7 +43,9 @@
   }
 
   @Override
-  public void postProcessingDesugaring(CfPostProcessingDesugaringEventConsumer eventConsumer) {
+  public void postProcessingDesugaring(
+      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      throws ExecutionException {
     if (appView.options().isDesugaredLibraryCompilation()) {
       ensureEmulatedDispatchMethodsSynthesized(eventConsumer);
     } else {
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 d86d22c..14e5fea 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
@@ -380,7 +380,8 @@
   }
 
   @Override
-  public void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods) {
+  public void process(
+      DexProgramClass clazz, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     if (!clazz.isInterface()) {
       visitClassInfo(clazz, new ReportingContext(clazz, clazz));
     }
@@ -389,11 +390,11 @@
   // 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(ProgramMethodSet synthesizedMethods) {
+  public final void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     newSyntheticMethods.forEach(
         (clazz, newForwardingMethods) -> {
           clazz.addVirtualMethods(newForwardingMethods.toDefinitionSet());
-          newForwardingMethods.forEach(synthesizedMethods::add);
+          newForwardingMethods.forEach(eventConsumer::acceptForwardingMethod);
         });
   }
 
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
index 46bd871..1c29a09 100644
--- 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
@@ -19,7 +19,6 @@
 import com.android.tools.r8.synthesis.SyntheticNaming;
 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.Iterables;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
@@ -89,7 +88,7 @@
   }
 
   DexProgramClass ensureEmulateInterfaceLibrary(
-      DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
+      DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     assert rewriter.isEmulatedInterface(emulatedInterface.type);
     DexProgramClass emulateInterfaceClass =
         appView
@@ -107,7 +106,7 @@
                                     synthesizeEmulatedInterfaceMethod(
                                         method, emulatedInterface, methodBuilder))),
                 ignored -> {});
-    emulateInterfaceClass.forEachProgramMethod(synthesizedMethods::add);
+    emulateInterfaceClass.forEachProgramMethod(eventConsumer::acceptEmulatedInterfaceMethod);
     assert emulateInterfaceClass.getType()
         == InterfaceMethodRewriter.getEmulateLibraryInterfaceClassType(
             emulatedInterface.type, appView.dexItemFactory());
@@ -212,14 +211,15 @@
   }
 
   @Override
-  public void process(DexProgramClass emulatedInterface, ProgramMethodSet synthesizedMethods) {
+  public void process(
+      DexProgramClass emulatedInterface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     if (!appView.options().isDesugaredLibraryCompilation()
         || !rewriter.isEmulatedInterface(emulatedInterface.type)
         || appView.isAlreadyLibraryDesugared(emulatedInterface)) {
       return;
     }
     if (needsEmulateInterfaceLibrary(emulatedInterface)) {
-      ensureEmulateInterfaceLibrary(emulatedInterface, synthesizedMethods);
+      ensureEmulateInterfaceLibrary(emulatedInterface, eventConsumer);
     }
   }
 
@@ -228,7 +228,7 @@
   }
 
   @Override
-  public void finalizeProcessing(ProgramMethodSet synthesizedMethods) {
+  public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     warnMissingEmulatedInterfaces();
   }
 
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
index 7f3d047..4f4ba32 100644
--- 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
@@ -5,7 +5,6 @@
 package com.android.tools.r8.ir.desugar.itf;
 
 import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
 
 public interface InterfaceDesugaringProcessor {
 
@@ -14,11 +13,11 @@
   // so this phase cannot modify the classes themselves (for example insertion/removal of methods).
   // The phase can insert new classes with new methods, such as emulated interface dispatch classes
   // or companion classes with their methods.
-  void process(DexProgramClass clazz, ProgramMethodSet synthesizedMethods);
+  void process(DexProgramClass clazz, InterfaceProcessingDesugaringEventConsumer eventConsumer);
 
   // The finalization phase is done at a join point, after all code desugaring have been performed.
   // All finalization phases of all desugaring processors are performed sequentially.
   // Complex computations should be avoided if possible here and be moved to the concurrent phase.
   // Classes may be mutated here (new methods can be inserted, etc.).
-  void finalizeProcessing(ProgramMethodSet synthesizedMethods);
+  void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer);
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
index 731316f..71844b0 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodProcessorFacade.java
@@ -6,7 +6,10 @@
 
 import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaring;
+import com.android.tools.r8.ir.desugar.CfPostProcessingDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.itf.InterfaceMethodRewriter.Flavor;
 import com.android.tools.r8.utils.ThreadUtils;
 import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
@@ -16,21 +19,22 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 
-class InterfaceMethodProcessorFacade {
+public class InterfaceMethodProcessorFacade implements CfPostProcessingDesugaring {
 
   private final AppView<?> appView;
+  private final Flavor flavour;
+  private final List<InterfaceDesugaringProcessor> interfaceDesugaringProcessors;
 
-  InterfaceMethodProcessorFacade(AppView<?> appView) {
+  InterfaceMethodProcessorFacade(
+      AppView<?> appView, Flavor flavour, InterfaceMethodRewriter rewriter) {
     this.appView = appView;
+    this.flavour = flavour;
+    interfaceDesugaringProcessors = instantiateInterfaceDesugaringProcessors(appView, rewriter);
   }
 
-  /** Runs the interfaceProcessor, the class processor and the emulated interface processor. */
-  void runInterfaceDesugaringProcessors(
-      InterfaceMethodRewriter rewriter,
-      IRConverter converter,
-      Flavor flavour,
-      ExecutorService executorService)
-      throws ExecutionException {
+  private List<InterfaceDesugaringProcessor> instantiateInterfaceDesugaringProcessors(
+      AppView<?> appView, InterfaceMethodRewriter rewriter) {
+
     // During L8 compilation, emulated interfaces are processed to be renamed, to have
     // their interfaces fixed-up and to generate the emulated dispatch code.
     EmulatedInterfaceProcessor emulatedInterfaceProcessor =
@@ -46,17 +50,47 @@
     // classes if needed.
     InterfaceProcessor interfaceProcessor = new InterfaceProcessor(appView, rewriter);
 
-    // The interface processors must be ordered so that finalization of the processing is performed
-    // in that order. The emulatedInterfaceProcessor has to be last at this point to avoid renaming
-    // emulated interfaces before the other processing.
-    ImmutableList<InterfaceDesugaringProcessor> orderedInterfaceDesugaringProcessors =
-        ImmutableList.of(classProcessor, interfaceProcessor, emulatedInterfaceProcessor);
+    // The processors can be listed in any order.
+    return ImmutableList.of(classProcessor, interfaceProcessor, emulatedInterfaceProcessor);
+  }
+
+  /** Runs the interfaceProcessor, the class processor and the emulated interface processor. */
+  void runInterfaceDesugaringProcessorsForR8(IRConverter converter, ExecutorService executorService)
+      throws ExecutionException {
+
+    CollectingInterfaceDesugaringEventConsumer eventConsumer =
+        new CollectingInterfaceDesugaringEventConsumer();
+    processClassesConcurrently(eventConsumer, executorService);
+    converter.processMethodsConcurrently(
+        eventConsumer.getSortedSynthesizedMethods(), executorService);
+  }
+
+  // This temporary class avoids the duality between collecting with IR processing and
+  // having events with the Cf desugaring.
+  private static class CollectingInterfaceDesugaringEventConsumer
+      implements InterfaceProcessingDesugaringEventConsumer {
 
     SortedProgramMethodSet sortedSynthesizedMethods = SortedProgramMethodSet.createConcurrent();
-    processClassesConcurrently(
-        orderedInterfaceDesugaringProcessors, sortedSynthesizedMethods, flavour, executorService);
-    assert converter != null;
-    converter.processMethodsConcurrently(sortedSynthesizedMethods, executorService);
+
+    @Override
+    public void acceptForwardingMethod(ProgramMethod method) {
+      sortedSynthesizedMethods.add(method);
+    }
+
+    @Override
+    public void acceptCompanionClassClinit(ProgramMethod method) {
+      sortedSynthesizedMethods.add(method);
+    }
+
+    @Override
+    public void acceptEmulatedInterfaceMethod(ProgramMethod method) {
+
+      sortedSynthesizedMethods.add(method);
+    }
+
+    public SortedProgramMethodSet getSortedSynthesizedMethods() {
+      return sortedSynthesizedMethods;
+    }
   }
 
   private boolean shouldProcess(DexProgramClass clazz, Flavor flavour) {
@@ -67,22 +101,28 @@
   }
 
   private void processClassesConcurrently(
-      List<InterfaceDesugaringProcessor> processors,
-      SortedProgramMethodSet sortedSynthesizedMethods,
-      Flavor flavour,
-      ExecutorService executorService)
+      InterfaceProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
       throws ExecutionException {
     ThreadUtils.processItems(
         Iterables.filter(
             appView.appInfo().classes(), (DexProgramClass clazz) -> shouldProcess(clazz, flavour)),
         clazz -> {
-          for (InterfaceDesugaringProcessor processor : processors) {
-            processor.process(clazz, sortedSynthesizedMethods);
+          for (InterfaceDesugaringProcessor processor : interfaceDesugaringProcessors) {
+            processor.process(clazz, eventConsumer);
           }
         },
         executorService);
-    for (InterfaceDesugaringProcessor processor : processors) {
-      processor.finalizeProcessing(sortedSynthesizedMethods);
+    for (InterfaceDesugaringProcessor processor : interfaceDesugaringProcessors) {
+      processor.finalizeProcessing(eventConsumer);
     }
   }
+
+  @Override
+  public void postProcessingDesugaring(
+      CfPostProcessingDesugaringEventConsumer eventConsumer, ExecutorService executorService)
+      throws ExecutionException {
+    // TODO(b/183998768): Would be nice to use the ClassProcessing for the processing of classes,
+    //  and do here only the finalization.
+    processClassesConcurrently(eventConsumer, executorService);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index 6ab6f1f..3e93691 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -1376,11 +1376,15 @@
     this.synthesizedMethods.clear();
   }
 
-  public void runInterfaceDesugaringProcessors(
+  public void runInterfaceDesugaringProcessorsForR8(
       IRConverter converter, Flavor flavour, ExecutorService executorService)
       throws ExecutionException {
-    new InterfaceMethodProcessorFacade(appView)
-        .runInterfaceDesugaringProcessors(this, converter, flavour, executorService);
+    getPostProcessingDesugaring(flavour)
+        .runInterfaceDesugaringProcessorsForR8(converter, executorService);
+  }
+
+  public InterfaceMethodProcessorFacade getPostProcessingDesugaring(Flavor flavour) {
+    return new InterfaceMethodProcessorFacade(appView, flavour, this);
   }
 
   final boolean isDefaultMethod(DexEncodedMethod method) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
new file mode 100644
index 0000000..2581364
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessingDesugaringEventConsumer.java
@@ -0,0 +1,16 @@
+// 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.ProgramMethod;
+
+public interface InterfaceProcessingDesugaringEventConsumer {
+
+  void acceptForwardingMethod(ProgramMethod method);
+
+  void acceptCompanionClassClinit(ProgramMethod method);
+
+  void acceptEmulatedInterfaceMethod(ProgramMethod method);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
index cb752ad..2dd65a9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceProcessor.java
@@ -47,7 +47,6 @@
 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;
@@ -80,12 +79,13 @@
   }
 
   @Override
-  public void process(DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
+  public void process(
+      DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     if (!iface.isInterface()) {
       return;
     }
     analyzeBridges(iface);
-    ensureCompanionClassMethods(iface, synthesizedMethods);
+    ensureCompanionClassMethods(iface, eventConsumer);
   }
 
   private void analyzeBridges(DexProgramClass iface) {
@@ -99,8 +99,8 @@
   }
 
   private void ensureCompanionClassMethods(
-      DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
-    ensureCompanionClassInitializesInterface(iface, synthesizedMethods);
+      DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
+    ensureCompanionClassInitializesInterface(iface, eventConsumer);
     // TODO(b/183998768): Once fixed, the methods should be added for processing.
     // D8 and R8 don't need to optimize the methods since they are just moved from interfaces and
     // don't need to be re-processed.
@@ -134,7 +134,7 @@
   }
 
   private void ensureCompanionClassInitializesInterface(
-      DexProgramClass iface, ProgramMethodSet synthesizedMethods) {
+      DexProgramClass iface, InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     if (!hasStaticMethodThatTriggersNonTrivialClassInitializer(iface)) {
       return;
     }
@@ -146,7 +146,7 @@
             appView.dexItemFactory().createProto(appView.dexItemFactory().voidType),
             appView,
             methodBuilder -> createCompanionClassInitializer(iface, clinitField, methodBuilder));
-    synthesizedMethods.add(clinit);
+    eventConsumer.acceptCompanionClassClinit(clinit);
   }
 
   private DexEncodedField ensureStaticClinitFieldToTriggerInterfaceInitialization(
@@ -441,7 +441,7 @@
   }
 
   @Override
-  public void finalizeProcessing(ProgramMethodSet synthesizedMethods) {
+  public void finalizeProcessing(InterfaceProcessingDesugaringEventConsumer eventConsumer) {
     InterfaceProcessorNestedGraphLens graphLens = postProcessInterfaces();
     if (appView.enableWholeProgramOptimizations() && graphLens != null) {
       appView.setGraphLens(graphLens);
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 20366b4..645d5b9 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3890,14 +3890,14 @@
     }
   }
 
-  private void postProcessingDesugaring() {
+  private void postProcessingDesugaring() throws ExecutionException {
     SyntheticAdditions syntheticAdditions =
         new SyntheticAdditions(appView.createProcessorContext());
 
     R8PostProcessingDesugaringEventConsumer eventConsumer =
         CfPostProcessingDesugaringEventConsumer.createForR8(appView, syntheticAdditions);
-    CfPostProcessingDesugaringCollection.create(appView, desugaring.getRetargetingInfo())
-        .postProcessingDesugaring(eventConsumer);
+    CfPostProcessingDesugaringCollection.create(appView, null, desugaring.getRetargetingInfo())
+        .postProcessingDesugaring(eventConsumer, executorService);
 
     if (syntheticAdditions.isEmpty()) {
       return;