Machine desugared library flags for wrappers

Bug: 184026720
Change-Id: Iebf6761f1c9d7364899a43291cafe375dff65a93
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index 71442ac..cec5153 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -13,7 +13,6 @@
 import com.android.tools.r8.graph.DexClass;
 import com.android.tools.r8.graph.DexClasspathClass;
 import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexEncodedMember;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
 import com.android.tools.r8.graph.DexItemFactory;
@@ -29,7 +28,7 @@
 import com.android.tools.r8.ir.desugar.CfClassSynthesizerDesugaringEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecification;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterConstructorCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterVivifiedWrapperCfCodeProvider;
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperCfCodeProvider;
@@ -42,13 +41,12 @@
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.StringDiagnostic;
-import com.google.common.collect.Iterables;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedList;
+import java.util.IdentityHashMap;
 import java.util.List;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Map;
 import java.util.function.Function;
 
 // I am responsible for the generation of wrappers used to call library APIs when desugaring
@@ -98,8 +96,6 @@
 
   private final AppView<?> appView;
   private final DexItemFactory factory;
-  private final ConcurrentHashMap<DexType, List<DexEncodedMethod>> allImplementedMethodsCache =
-      new ConcurrentHashMap<>();
   private final DesugaredLibraryEnumConversionSynthesizer enumConverter;
 
   public DesugaredLibraryWrapperSynthesizer(AppView<?> appView) {
@@ -264,6 +260,9 @@
       return getExistingProgramWrapperConversions(context);
     }
     assert context.isNotProgramClass();
+    Iterable<DexMethod> methods =
+        appView.options().machineDesugaredLibrarySpecification.getWrappers().get(context.type);
+    assert methods != null;
     ClasspathOrLibraryClass classpathOrLibraryContext = context.asClasspathOrLibraryClass();
     DexType type = context.type;
     DexType vivifiedType = vivifiedTypeFor(type);
@@ -274,7 +273,7 @@
             type,
             classpathOrLibraryContext,
             eventConsumer,
-            wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, wrapperField));
+            wrapperField -> synthesizeVirtualMethodsForTypeWrapper(context, methods, wrapperField));
     DexClass vivifiedWrapper =
         ensureClasspathWrapper(
             SyntheticKind.VIVIFIED_WRAPPER,
@@ -282,7 +281,8 @@
             vivifiedType,
             classpathOrLibraryContext,
             eventConsumer,
-            wrapperField -> synthesizeVirtualMethodsForVivifiedTypeWrapper(context, wrapperField));
+            wrapperField ->
+                synthesizeVirtualMethodsForVivifiedTypeWrapper(context, methods, wrapperField));
     return new WrapperConversions(
         getConversion(wrapper, vivifiedType, type),
         getConversion(vivifiedWrapper, type, vivifiedType));
@@ -447,8 +447,7 @@
   }
 
   private Collection<DexEncodedMethod> synthesizeVirtualMethodsForVivifiedTypeWrapper(
-      DexClass dexClass, DexEncodedField wrapperField) {
-    Iterable<DexMethod> allImplementedMethods = allImplementedMethods(dexClass);
+      DexClass dexClass, Iterable<DexMethod> allImplementedMethods, DexEncodedField wrapperField) {
     List<DexEncodedMethod> generatedMethods = new ArrayList<>();
     // Each method should use only types in their signature, but each method the wrapper forwards
     // to should used only vivified types.
@@ -489,8 +488,7 @@
   }
 
   private Collection<DexEncodedMethod> synthesizeVirtualMethodsForTypeWrapper(
-      DexClass dexClass, DexEncodedField wrapperField) {
-    Iterable<DexMethod> dexMethods = allImplementedMethods(dexClass);
+      DexClass dexClass, Iterable<DexMethod> dexMethods, DexEncodedField wrapperField) {
     List<DexEncodedMethod> generatedMethods = new ArrayList<>();
     // Each method should use only vivified types in their signature, but each method the wrapper
     // forwards
@@ -546,60 +544,6 @@
         .build();
   }
 
-  private Iterable<DexMethod> allImplementedMethods(DexClass clazz) {
-    if (appView.options().machineDesugaredLibrarySpecification != null) {
-      return appView
-          .options()
-          .machineDesugaredLibrarySpecification
-          .getWrappers()
-          .get(clazz.type);
-    }
-    List<DexEncodedMethod> dexEncodedMethods =
-        allImplementedMethodsCache.computeIfAbsent(
-            clazz.type, type -> internalAllImplementedMethods(clazz));
-    return Iterables.transform(dexEncodedMethods, DexEncodedMember::getReference);
-  }
-
-  private List<DexEncodedMethod> internalAllImplementedMethods(DexClass libraryClass) {
-    LinkedList<DexClass> workList = new LinkedList<>();
-    List<DexEncodedMethod> implementedMethods = new ArrayList<>();
-    workList.add(libraryClass);
-    while (!workList.isEmpty()) {
-      DexClass dexClass = workList.removeFirst();
-      for (DexEncodedMethod virtualMethod : dexClass.virtualMethods()) {
-        if (!virtualMethod.isPrivateMethod()) {
-          boolean alreadyAdded = false;
-          // This looks quadratic but given the size of the collections met in practice for
-          // desugared libraries (Max ~15) it does not matter.
-          for (DexEncodedMethod alreadyImplementedMethod : implementedMethods) {
-            if (alreadyImplementedMethod.getReference().match(virtualMethod.getReference())) {
-              alreadyAdded = true;
-              break;
-            }
-          }
-          if (!alreadyAdded) {
-            implementedMethods.add(virtualMethod);
-          }
-        }
-      }
-      for (DexType itf : dexClass.interfaces.values) {
-        DexClass itfClass = appView.definitionFor(itf);
-        // Cannot be null in program since we started from a LibraryClass.
-        assert itfClass != null || appView.options().isDesugaredLibraryCompilation();
-        if (itfClass != null) {
-          workList.add(itfClass);
-        }
-      }
-      if (dexClass.superType != factory.objectType) {
-        DexClass superClass = appView.definitionFor(dexClass.superType);
-        assert superClass != null; // Cannot be null since we started from a LibraryClass.
-        workList.add(superClass);
-      }
-    }
-    assert !Iterables.any(implementedMethods, DexEncodedMethod::isFinal);
-    return implementedMethods;
-  }
-
   private DexField wrappedValueField(DexType holder, DexType fieldType) {
     return factory.createField(holder, fieldType, factory.wrapperFieldName);
   }
@@ -623,25 +567,28 @@
   // conversion methods are present.
   @Override
   public void synthesizeClasses(CfClassSynthesizerDesugaringEventConsumer eventConsumer) {
-    LegacyDesugaredLibrarySpecification spec = appView.options().desugaredLibrarySpecification;
-    List<DexProgramClass> validClassesToWrap = new ArrayList<>();
-    for (DexType type : spec.getWrapperConversions()) {
-      assert !spec.getCustomConversions().containsKey(type);
-      DexClass validClassToWrap = getValidClassToWrap(type);
-      // In broken set-ups we can end up having a json files containing wrappers of non desugared
-      // classes. Such wrappers are not required since the class won't be rewritten.
-      if (validClassToWrap.isProgramClass()) {
-        if (validClassToWrap.isEnum()) {
-          enumConverter.ensureProgramEnumConversionClass(validClassToWrap, eventConsumer);
-        } else {
-          validClassesToWrap.add(validClassToWrap.asProgramClass());
-          ensureProgramWrappersWithoutVirtualMethods(validClassToWrap, eventConsumer);
-        }
-      }
-    }
-    for (DexProgramClass validClassToWrap : validClassesToWrap) {
-      ensureProgramWrappersVirtualMethods(validClassToWrap);
-    }
+    MachineDesugaredLibrarySpecification librarySpecification =
+        appView.options().machineDesugaredLibrarySpecification;
+    Map<DexProgramClass, Iterable<DexMethod>> validClassesToWrap = new IdentityHashMap<>();
+    librarySpecification
+        .getWrappers()
+        .forEach(
+            (type, methods) -> {
+              assert !librarySpecification.getCustomConversions().containsKey(type);
+              DexClass validClassToWrap = getValidClassToWrap(type);
+              // In broken set-ups we can end up having a json files containing wrappers of non
+              // desugared classes. Such wrappers are not required since the class won't be
+              // rewritten.
+              if (validClassToWrap.isProgramClass()) {
+                if (validClassToWrap.isEnum()) {
+                  enumConverter.ensureProgramEnumConversionClass(validClassToWrap, eventConsumer);
+                } else {
+                  validClassesToWrap.put(validClassToWrap.asProgramClass(), methods);
+                  ensureProgramWrappersWithoutVirtualMethods(validClassToWrap, eventConsumer);
+                }
+              }
+            });
+    validClassesToWrap.forEach(this::ensureProgramWrappersVirtualMethods);
   }
 
   // We generate first the two wrappers with the constructor method and the fields, then we
@@ -669,15 +616,16 @@
         SyntheticKind.VIVIFIED_WRAPPER, programContext, vivifiedWrapper, wrapper);
   }
 
-  private void ensureProgramWrappersVirtualMethods(DexClass context) {
+  private void ensureProgramWrappersVirtualMethods(DexClass context, Iterable<DexMethod> methods) {
     assert context.isProgramClass();
     DexProgramClass wrapper = getExistingProgramWrapper(context, SyntheticKind.WRAPPER);
     wrapper.addVirtualMethods(
-        synthesizeVirtualMethodsForTypeWrapper(context, getWrapperUniqueEncodedField(wrapper)));
+        synthesizeVirtualMethodsForTypeWrapper(
+            context, methods, getWrapperUniqueEncodedField(wrapper)));
     DexProgramClass vivifiedWrapper =
         getExistingProgramWrapper(context, SyntheticKind.VIVIFIED_WRAPPER);
     vivifiedWrapper.addVirtualMethods(
         synthesizeVirtualMethodsForVivifiedTypeWrapper(
-            context, getWrapperUniqueEncodedField(vivifiedWrapper)));
+            context, methods, getWrapperUniqueEncodedField(vivifiedWrapper)));
   }
 }