Desugared library: synthesized classes prefix

Bug:145504313
Change-Id: Icf8d47484823a1c6dc1eae176b73427d093b0920
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 511b971..41995ce 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -59,7 +59,6 @@
 public final class BackportedMethodRewriter {
 
   public static final String UTILITY_CLASS_NAME_PREFIX = "$r8$backportedMethods$utility";
-  private static final String UTILITY_CLASS_DESCRIPTOR_PREFIX = "L" + UTILITY_CLASS_NAME_PREFIX;
 
   private final AppView<?> appView;
   private final IRConverter converter;
@@ -147,7 +146,7 @@
     // On R8 resolution is immediate, on d8 it may look-up.
     DexClass current = appView.definitionFor(method.holder);
     if (current == null) {
-     return null;
+      return null;
     }
     DexEncodedMethod dexEncodedMethod = current.lookupVirtualMethod(method);
     if (dexEncodedMethod != null) {
@@ -177,7 +176,7 @@
   }
 
   public static boolean hasRewrittenMethodPrefix(DexType clazz) {
-    return clazz.descriptor.toString().startsWith(UTILITY_CLASS_DESCRIPTOR_PREFIX);
+    return clazz.descriptor.toString().contains(UTILITY_CLASS_NAME_PREFIX);
   }
 
   public void synthesizeUtilityClasses(Builder<?> builder, ExecutorService executorService)
@@ -1425,15 +1424,19 @@
       DexItemFactory factory = appView.dexItemFactory();
       String unqualifiedName = method.holder.getName();
       // Avoid duplicate class names between core lib dex file and program dex files.
-      String desugaredLibUtilitySuffix =
-          appView.options().isDesugaredLibraryCompilation() ? "$desugaredLib" : "";
+      String desugaredLibPrefix =
+          appView
+              .options()
+              .desugaredLibraryConfiguration
+              .getSynthesizedLibraryClassesPackagePrefix(appView);
       String descriptor =
-          UTILITY_CLASS_DESCRIPTOR_PREFIX
+          "L"
+              + desugaredLibPrefix
+              + UTILITY_CLASS_NAME_PREFIX
               + '$'
               + unqualifiedName
               + '$'
               + method.proto.parameters.size()
-              + desugaredLibUtilitySuffix
               + '$'
               + methodName
               + ';';
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
index dda019e..1c11d78 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
@@ -5,6 +5,7 @@
 package com.android.tools.r8.ir.desugar;
 
 import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexItemFactory;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
@@ -23,9 +24,12 @@
 
 public class DesugaredLibraryConfiguration {
 
+  public static final String FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX = "j$/";
+
   // TODO(b/134732760): should use DexString, DexType, DexMethod or so on when possible.
   private final AndroidApiLevel requiredCompilationAPILevel;
   private final boolean libraryCompilation;
+  private final String synthesizedLibraryClassesPackagePrefix;
   private final Map<String, String> rewritePrefix;
   private final Map<DexType, DexType> emulateLibraryInterface;
   private final Map<DexString, Map<DexType, DexType>> retargetCoreLibMember;
@@ -43,6 +47,7 @@
     return new DesugaredLibraryConfiguration(
         AndroidApiLevel.B,
         false,
+        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
         prefix,
         ImmutableMap.of(),
         ImmutableMap.of(),
@@ -56,6 +61,7 @@
     return new DesugaredLibraryConfiguration(
         AndroidApiLevel.B,
         false,
+        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
         ImmutableMap.of(),
         ImmutableMap.of(),
         ImmutableMap.of(),
@@ -68,6 +74,7 @@
   public DesugaredLibraryConfiguration(
       AndroidApiLevel requiredCompilationAPILevel,
       boolean libraryCompilation,
+      String packagePrefix,
       Map<String, String> rewritePrefix,
       Map<DexType, DexType> emulateLibraryInterface,
       Map<DexString, Map<DexType, DexType>> retargetCoreLibMember,
@@ -77,6 +84,7 @@
       List<String> extraKeepRules) {
     this.requiredCompilationAPILevel = requiredCompilationAPILevel;
     this.libraryCompilation = libraryCompilation;
+    this.synthesizedLibraryClassesPackagePrefix = packagePrefix;
     this.rewritePrefix = rewritePrefix;
     this.emulateLibraryInterface = emulateLibraryInterface;
     this.retargetCoreLibMember = retargetCoreLibMember;
@@ -100,6 +108,12 @@
     return libraryCompilation;
   }
 
+  public String getSynthesizedLibraryClassesPackagePrefix(AppView<?> appView) {
+    return appView.options().isDesugaredLibraryCompilation()
+        ? synthesizedLibraryClassesPackagePrefix
+        : "";
+  }
+
   public Map<String, String> getRewritePrefix() {
     return rewritePrefix;
   }
@@ -134,6 +148,8 @@
 
     private AndroidApiLevel requiredCompilationAPILevel;
     private boolean libraryCompilation = false;
+    private String synthesizedLibraryClassesPackagePrefix =
+        FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX;
     private Map<String, String> rewritePrefix = new HashMap<>();
     private Map<DexType, DexType> emulateLibraryInterface = new HashMap<>();
     private Map<DexString, Map<DexType, DexType>> retargetCoreLibMember = new IdentityHashMap<>();
@@ -146,6 +162,12 @@
       this.factory = dexItemFactory;
     }
 
+    public Builder setSynthesizedLibraryClassesPackagePrefix(String prefix) {
+      String replace = prefix.replace('.', '/');
+      this.synthesizedLibraryClassesPackagePrefix = replace;
+      return this;
+    }
+
     public Builder setRequiredCompilationAPILevel(AndroidApiLevel requiredCompilationAPILevel) {
       this.requiredCompilationAPILevel = requiredCompilationAPILevel;
       return this;
@@ -231,6 +253,7 @@
       return new DesugaredLibraryConfiguration(
           requiredCompilationAPILevel,
           libraryCompilation,
+          synthesizedLibraryClassesPackagePrefix,
           ImmutableMap.copyOf(rewritePrefix),
           ImmutableMap.copyOf(emulateLibraryInterface),
           ImmutableMap.copyOf(retargetCoreLibMember),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
index 4de1fe1..b66432e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
@@ -19,7 +19,7 @@
 
 public class DesugaredLibraryConfigurationParser {
 
-  private static final int MAX_SUPPORTED_VERSION = 2;
+  private static final int MAX_SUPPORTED_VERSION = 3;
 
   private final DesugaredLibraryConfiguration.Builder configurationBuilder;
   private final Reporter reporter;
@@ -67,6 +67,17 @@
                   + "distributed only in the early canary versions. Please update for "
                   + "production releases and to fix this warning."));
     }
+
+    if (jsonConfig.has("synthesized_library_classes_package_prefix")) {
+      configurationBuilder.setSynthesizedLibraryClassesPackagePrefix(
+          jsonConfig.get("synthesized_library_classes_package_prefix").getAsString());
+    } else {
+      reporter.warning(
+          new StringDiagnostic(
+              "Missing package_prefix, falling back to "
+                  + DesugaredLibraryConfiguration.FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX
+                  + " prefix, update desugared library configuration."));
+    }
     int required_compilation_api_level =
         jsonConfig.get("required_compilation_api_level").getAsInt();
     configurationBuilder.setRequiredCompilationAPILevel(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index 5d7c31f..d75b84c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -32,7 +32,6 @@
 import com.android.tools.r8.ir.synthetic.DesugaredLibraryAPIConversionCfCodeProvider.APIConverterWrapperConversionCfCodeProvider;
 import com.android.tools.r8.origin.SynthesizedOrigin;
 import com.android.tools.r8.utils.Box;
-import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.StringDiagnostic;
 import com.google.common.collect.Sets;
@@ -95,7 +94,6 @@
 public class DesugaredLibraryWrapperSynthesizer {
 
   public static final String WRAPPER_PREFIX = "$r8$wrapper$";
-  public static final String WRAPPER_DESCRIPTOR_PREFIX = "L" + WRAPPER_PREFIX;
   public static final String TYPE_WRAPPER_SUFFIX = "$-WRP";
   public static final String VIVIFIED_TYPE_WRAPPER_SUFFIX = "$-V-WRP";
 
@@ -120,7 +118,7 @@
   }
 
   public static boolean isSynthesizedWrapper(DexType clazz) {
-    return clazz.descriptor.toString().startsWith(WRAPPER_DESCRIPTOR_PREFIX);
+    return clazz.descriptor.toString().contains(WRAPPER_PREFIX);
   }
 
   boolean hasSynthesized(DexType type) {
@@ -152,10 +150,18 @@
   }
 
   private DexType createWrapperType(DexType type, String suffix) {
-    String prefix = appView.options().isDesugaredLibraryCompilation() ? "lib$" : "";
+    String desugaredLibPrefix =
+        appView
+            .options()
+            .desugaredLibraryConfiguration
+            .getSynthesizedLibraryClassesPackagePrefix(appView);
     return factory.createType(
-        DescriptorUtils.javaTypeToDescriptor(
-            WRAPPER_PREFIX + prefix + type.toString().replace('.', '$') + suffix));
+        "L"
+            + desugaredLibPrefix
+            + WRAPPER_PREFIX
+            + type.toString().replace('.', '$')
+            + suffix
+            + ";");
   }
 
   private DexType getWrapper(
@@ -260,7 +266,8 @@
         Collections.emptyList());
   }
 
-  private ChecksumSupplier getChecksumSupplier(DesugaredLibraryWrapperSynthesizer synthesizer, DexType keyType) {
+  private ChecksumSupplier getChecksumSupplier(
+      DesugaredLibraryWrapperSynthesizer synthesizer, DexType keyType) {
     return clazz -> {
       // The synthesized type wrappers are constructed lazily, so their lookup must be delayed
       // until the point the checksum is requested (at write time). The presence of a wrapper
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
index 67bf5a5..159aa8d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -16,8 +16,6 @@
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
 import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
-import com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import java.nio.file.Path;
@@ -79,18 +77,7 @@
   }
 
   private void assertCorrect(CodeInspector inspector) {
-    inspector
-        .allClasses()
-        .forEach(
-            clazz ->
-                assertTrue(
-                    clazz.getOriginalName().startsWith("j$.")
-                        || clazz
-                            .getOriginalName()
-                            .startsWith(DesugaredLibraryWrapperSynthesizer.WRAPPER_PREFIX)
-                        || clazz
-                            .getOriginalName()
-                            .contains(BackportedMethodRewriter.UTILITY_CLASS_NAME_PREFIX)));
+    inspector.allClasses().forEach(clazz -> assertTrue(clazz.getOriginalName().startsWith("j$.")));
     assertThat(inspector.clazz("j$.time.Clock"), isPresent());
     // Above N the following classes are removed instead of being desugared.
     if (parameters.getApiLevel().getLevel() >= AndroidApiLevel.N.getLevel()) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/desugar_jdk_libs.json b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/desugar_jdk_libs.json
index a281c3d..3cfd647 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/desugar_jdk_libs.json
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/desugar_jdk_libs.json
@@ -1,7 +1,8 @@
 {
-  "configuration_format_version": 2,
-  "version": "0.8.0",
+  "configuration_format_version": 3,
+  "version": "0.9.0",
   "required_compilation_api_level": 26,
+  "synthesized_library_classes_package_prefix": "j$.",
   "library_flags": [
     {
       "api_level_below_or_equal": 25,