Reland "Make merging more resilient to backported names from old versions of R8""
Bug: 146419367
Change-Id: I0e09897fa01efd368cb965f32123eaa9d9af1970
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index cc39610..bbed9bc 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -24,13 +24,19 @@
import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.android.tools.r8.utils.Pair;
import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
public class DexType extends DexReference implements PresortedComparable<DexType> {
public static final DexType[] EMPTY_ARRAY = {};
+ // Bundletool is merging classes that may originate from a build with an old version of R8.
+ // Allow merging of classes that use names from older versions of R8.
+ private static List<String> OLD_SYNTHESIZED_NAMES = ImmutableList.of("$r8$java8methods$utility");
+
public final DexString descriptor;
private String toStringCache = null;
@@ -264,7 +270,17 @@
|| name.contains(TwrCloseResourceRewriter.UTILITY_CLASS_NAME)
|| name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME)
|| name.contains(BackportedMethodRewriter.UTILITY_CLASS_NAME_PREFIX)
- || name.contains(ServiceLoaderRewriter.SERVICE_LOADER_CLASS_NAME);
+ || name.contains(ServiceLoaderRewriter.SERVICE_LOADER_CLASS_NAME)
+ || oldSynthesizedName(name);
+ }
+
+ private boolean oldSynthesizedName(String name) {
+ for (String synthesizedPrefix : OLD_SYNTHESIZED_NAMES) {
+ if (name.contains(synthesizedPrefix)) {
+ return true;
+ }
+ }
+ return false;
}
public boolean isProgramType(DexDefinitionSupplier definitions) {
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 fa68de4..8f33a5e 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
@@ -62,6 +62,8 @@
public final class BackportedMethodRewriter {
+ // Don't change this name, at least not without adding special-casing in DexType to support
+ // merging old dex code in Bundletool.
public static final String UTILITY_CLASS_NAME_PREFIX = "$r8$backportedMethods$utility";
private final AppView<?> appView;
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index 44da91c..d602a51 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -10,12 +10,7 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.desugar.BackportedMethodRewriter;
import com.android.tools.r8.ir.desugar.DesugaredLibraryWrapperSynthesizer;
-import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
-import com.android.tools.r8.ir.desugar.LambdaRewriter;
-import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
-import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
import com.android.tools.r8.references.Reference;
import com.google.common.collect.ImmutableList;
import java.util.List;
@@ -90,17 +85,13 @@
private static DexProgramClass mergeClasses(
Reporter reporter, DexProgramClass a, DexProgramClass b) {
- if (LambdaRewriter.hasLambdaClassPrefix(a.type)
- || BackportedMethodRewriter.hasRewrittenMethodPrefix(a.type)
- || InterfaceMethodRewriter.hasDispatchClassSuffix(a.type)
- || NestBasedAccessDesugaring.isNestConstructor(a.type)
- || TwrCloseResourceRewriter.isUtilityClassDescriptor(a.type)) {
- assert assertEqualClasses(a, b);
- return a;
- }
if (DesugaredLibraryWrapperSynthesizer.isSynthesizedWrapper(a.type)) {
return mergeWrappers(a, b);
}
+ if (a.type.isD8R8SynthesizedClassType()) {
+ assert assertEqualClasses(a, b);
+ return a;
+ }
throw reportDuplicateTypes(reporter, a, b);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java b/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
index 44f32ee..f71139f 100644
--- a/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/BackportedMethodMergeTest.java
@@ -4,9 +4,14 @@
package com.android.tools.r8.desugar;
+import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.transformers.ClassTransformer;
import com.android.tools.r8.utils.AndroidApiLevel;
+import java.io.IOException;
import java.nio.file.Path;
+import java.util.concurrent.ExecutionException;
import org.junit.Test;
public class BackportedMethodMergeTest extends TestBase {
@@ -40,6 +45,61 @@
.assertSuccessWithOutput(jvmOutput);
}
+ @Test
+ public void testMergeOldPrefix()
+ throws IOException, CompilationFailedException, ExecutionException {
+ byte[] transform = transformer($r8$java8methods$utility_MergeInputWithOldBackportedPrefix.class)
+ .addClassTransformer(new ClassTransformer() {
+ @Override
+ public void visit(int version, int access, String name, String signature,
+ String superName, String[] interfaces) {
+ ClassAccessFlags accessFlags = ClassAccessFlags.fromCfAccessFlags(access);
+ accessFlags.setSynthetic();
+ super.visit(version, accessFlags.getAsCfAccessFlags(),
+ name, signature, superName, interfaces);
+ }
+ }).transform();
+
+ Path zip1 = temp.newFile("first.zip").toPath();
+ Path zip2 = temp.newFile("second.zip").toPath();
+ testForD8()
+ .setMinApi(AndroidApiLevel.L)
+ .addProgramClasses(MergeRunWithOldBackportedPrefix.class)
+ .addProgramClassFileData(transform)
+ .compile()
+ .assertNoMessages()
+ .writeToZip(zip1);
+ testForD8()
+ .setMinApi(AndroidApiLevel.L)
+ .addProgramClassFileData(transform)
+ .compile()
+ .assertNoMessages()
+ .writeToZip(zip2);
+ testForD8()
+ .addProgramFiles(zip1, zip2)
+ .setMinApi(AndroidApiLevel.L)
+ .compile()
+ .assertNoMessages()
+ .run(MergeRunWithOldBackportedPrefix.class)
+ .assertSuccessWithOutputLines("foobar");
+ }
+
+
+ static class $r8$java8methods$utility_MergeInputWithOldBackportedPrefix {
+ public void foo() {
+ System.out.println("foobar");
+ }
+
+ }
+
+ static class MergeRunWithOldBackportedPrefix {
+ public static void main(String[] args) {
+ $r8$java8methods$utility_MergeInputWithOldBackportedPrefix a =
+ new $r8$java8methods$utility_MergeInputWithOldBackportedPrefix();
+ a.foo();
+ }
+ }
+
static class MergeInputA {
public void foo() {
System.out.println(Integer.hashCode(42));