Postpone EmulatedInterfaceProcessor interface modifications

- Processing of interface should be able to be performed
  in any order.

Bug: 183998768
Change-Id: Iaae03d39628c97f4cb860133fc35afd5b9a605d2
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 559172a..0a56ddb 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
@@ -285,12 +285,7 @@
     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);
+    generateEmulateInterfaceLibrary(emulatedInterface);
   }
 
   @Override
@@ -300,6 +295,16 @@
       assert syntheticClasses.isEmpty();
       return;
     }
+    for (DexType interfaceType : emulatedInterfaces.keySet()) {
+      DexClass theInterface = appView.definitionFor(interfaceType);
+      if (theInterface != null && theInterface.isProgramClass()) {
+        DexProgramClass emulatedInterface = theInterface.asProgramClass();
+        if (!appView.isAlreadyLibraryDesugared(emulatedInterface)) {
+          replaceInterfacesInEmulatedInterface(emulatedInterface);
+          renameEmulatedInterface(emulatedInterface);
+        }
+      }
+    }
     syntheticClasses.forEach(
         (interfaceClass, synthesizedClass) -> {
           builder.addSynthesizedClass(synthesizedClass);
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 d85e8a2..821ff44 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
@@ -9,9 +9,19 @@
 import com.android.tools.r8.utils.collections.ProgramMethodSet;
 
 public interface InterfaceDesugaringProcessor {
+
   boolean shouldProcess(DexProgramClass clazz);
 
+  // The process phase can be performed before, concurrently or after code desugaring. It can be
+  // executed concurrently on all classes. Each processing may require to read other classes,
+  // 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);
 
+  // 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(DexApplication.Builder<?> builder, ProgramMethodSet synthesizedMethods);
 }
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 8fd5d23..c45a1e0 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
@@ -84,7 +84,6 @@
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.ExecutorService;
 import java.util.function.BiConsumer;
-import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 //
@@ -963,26 +962,29 @@
   public void desugarInterfaceMethods(
       Builder<?> builder, Flavor flavour, ExecutorService executorService)
       throws ExecutionException {
-    // TODO(b/183998768): Merge the following four sequential loops into a single one.
-
+    // 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 =
         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.
-    process(new ClassProcessor(appView, this), builder, flavour);
+    ClassProcessor classProcessor = new ClassProcessor(appView, this);
 
     // 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.
-    process(new InterfaceProcessor(appView, this), builder, flavour);
+    InterfaceProcessor interfaceProcessor = new InterfaceProcessor(appView, this);
 
-    // During L8 compilation, emulated interfaces are processed to be renamed, to have
-    // their interfaces fixed-up and to generate the emulated dispatch code.
+    // TODO(b/183998768): Merge the following loops into a single one.
     process(emulatedInterfaceProcessor, builder, flavour);
+    process(classProcessor, builder, flavour);
+    process(interfaceProcessor, builder, flavour);
+
+    classProcessor.finalizeProcessing(builder, synthesizedMethods);
+    interfaceProcessor.finalizeProcessing(builder, synthesizedMethods);
+    emulatedInterfaceProcessor.finalizeProcessing(builder, synthesizedMethods);
 
     converter.processMethodsConcurrently(synthesizedMethods, executorService);
 
@@ -990,18 +992,6 @@
     clear();
   }
 
-  private void forEachProgramEmulatedInterface(Consumer<DexProgramClass> consumer) {
-    if (!appView.options().isDesugaredLibraryCompilation()) {
-      return;
-    }
-    for (DexType interfaceType : emulatedInterfaces.keySet()) {
-      DexClass theInterface = appView.definitionFor(interfaceType);
-      if (theInterface != null && theInterface.isProgramClass()) {
-        consumer.accept(theInterface.asProgramClass());
-      }
-    }
-  }
-
   private void clear() {
     this.cache.clear();
     this.synthesizedMethods.clear();
@@ -1020,7 +1010,6 @@
         processor.process(clazz, synthesizedMethods);
       }
     }
-    processor.finalizeProcessing(builder, synthesizedMethods);
   }
 
   final boolean isDefaultMethod(DexEncodedMethod method) {