Version 1.2.41
Merge: Detect the naming loop due to -useuniqueclassmembernames.
CL: https://r8-review.googlesource.com/c/r8/+/25400
Merge: Reproduce b/112701848.
CL: https://r8-review.googlesource.com/c/r8/+/25340
Bug: 112701848
Change-Id: I9c668f5c9f625396010f6d322dda0e7fdb3ed78e
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 7fdd393..3ad2ac7 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.2.40";
+ public static final String LABEL = "1.2.41";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
index 97f1228..c7b73b3 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -370,11 +370,22 @@
// We use the origin state to allocate a name here so that we can reuse names between different
// unrelated interfaces. This saves some space. The alternative would be to use a global state
// for allocating names, which would save the work to search here.
+ DexString previousCandidate = null;
DexString candidate = null;
do {
candidate = originState.assignNewNameFor(false);
+ // If the state returns the same candidate for two consecutive trials, it should be this case:
+ // 1) an interface method with the same signature (name, param) but different return type
+ // has been already renamed; and 2) -useuniqueclassmembernames is set.
+ // The option forces the naming state to return the same renamed name for the same signature.
+ // So, here we break the loop in an ad-hoc manner.
+ if (candidate != null && candidate == previousCandidate) {
+ assert useUniqueMemberNames;
+ break;
+ }
for (MethodNamingState state : collectedStates) {
if (!state.isAvailable(candidate)) {
+ previousCandidate = candidate;
candidate = null;
break;
}
diff --git a/src/main/java/com/android/tools/r8/naming/NamingState.java b/src/main/java/com/android/tools/r8/naming/NamingState.java
index abfa3c1..fc00d91 100644
--- a/src/main/java/com/android/tools/r8/naming/NamingState.java
+++ b/src/main/java/com/android/tools/r8/naming/NamingState.java
@@ -113,7 +113,7 @@
if (state == null) {
return true;
}
- assert state.getAssignedNameFor(original, proto) != candidate;
+ assert state.getAssignedNameFor(original, proto) != candidate || useUniqueMemberNames;
return state.isAvailable(candidate);
}
@@ -182,8 +182,9 @@
if (row != null) {
// Either not renamed yet (0) or renamed (1). If renamed, return the same renamed name
// so that other members with the same name can be renamed to the same renamed name.
- assert row.values().size() <= 1;
- result = Iterables.getOnlyElement(row.values(), null);
+ Set<DexString> renamedNames = Sets.newHashSet(row.values());
+ assert renamedNames.size() <= 1;
+ result = Iterables.getOnlyElement(renamedNames, null);
}
} else {
result = renamings.get(original, proto);
diff --git a/src/test/java/com/android/tools/r8/naming/InterfaceRenamingTestRunner.java b/src/test/java/com/android/tools/r8/naming/InterfaceRenamingTestRunner.java
index ef6e0c8..715de97 100644
--- a/src/test/java/com/android/tools/r8/naming/InterfaceRenamingTestRunner.java
+++ b/src/test/java/com/android/tools/r8/naming/InterfaceRenamingTestRunner.java
@@ -29,57 +29,80 @@
@Test
public void testCfNoMinify() throws Exception {
- testCf(MinifyMode.NONE);
+ testCf(MinifyMode.NONE, false);
}
@Test
public void testCfMinify() throws Exception {
- testCf(MinifyMode.JAVA);
+ testCf(MinifyMode.JAVA, false);
+ }
+
+ @Test
+ public void testCfMinify_useUniqueClassMemberNames() throws Exception {
+ testCf(MinifyMode.JAVA, true);
}
@Test
public void testCfMinifyAggressive() throws Exception {
- testCf(MinifyMode.AGGRESSIVE);
+ testCf(MinifyMode.AGGRESSIVE, false);
+ }
+
+ @Test
+ public void testCfMinifyAggressive_useUniqueClassMemberNames() throws Exception {
+ testCf(MinifyMode.AGGRESSIVE, true);
}
@Test
public void testDexNoMinify() throws Exception {
- testDex(MinifyMode.NONE);
+ testDex(MinifyMode.NONE, false);
}
@Test
public void testDexMinify() throws Exception {
- testDex(MinifyMode.JAVA);
+ testDex(MinifyMode.JAVA, false);
+ }
+
+ @Test
+ public void testDexMinify_useUniqueClassMemberNames() throws Exception {
+ testDex(MinifyMode.JAVA, true);
}
@Test
public void testDexMinifyAggressive() throws Exception {
- testDex(MinifyMode.AGGRESSIVE);
+ testDex(MinifyMode.AGGRESSIVE, false);
}
- private void testCf(MinifyMode minify) throws Exception {
+ @Test
+ public void testDexMinifyAggressive_useUniqueClassMemberNames() throws Exception {
+ testDex(MinifyMode.AGGRESSIVE, true);
+ }
+
+ private void testCf(MinifyMode minify, boolean useUniqueClassMemberNames) throws Exception {
ProcessResult runInput =
ToolHelper.runJava(ToolHelper.getClassPathForTests(), CLASS.getCanonicalName());
assertEquals(0, runInput.exitCode);
Path outCf = temp.getRoot().toPath().resolve("cf.zip");
- build(new ClassFileConsumer.ArchiveConsumer(outCf), minify);
+ build(new ClassFileConsumer.ArchiveConsumer(outCf), minify, useUniqueClassMemberNames);
ProcessResult runCf = ToolHelper.runJava(outCf, CLASS.getCanonicalName());
assertEquals(runInput.toString(), runCf.toString());
}
- private void testDex(MinifyMode minify) throws Exception {
+ private void testDex(MinifyMode minify, boolean useUniqueClassMemberNames) throws Exception {
ProcessResult runInput =
ToolHelper.runJava(ToolHelper.getClassPathForTests(), CLASS.getCanonicalName());
assertEquals(0, runInput.exitCode);
Path outDex = temp.getRoot().toPath().resolve("dex.zip");
- build(new DexIndexedConsumer.ArchiveConsumer(outDex), minify);
+ build(new DexIndexedConsumer.ArchiveConsumer(outDex), minify, useUniqueClassMemberNames);
ProcessResult runDex =
ToolHelper.runArtNoVerificationErrorsRaw(outDex.toString(), CLASS.getCanonicalName());
assertEquals(runInput.stdout, runDex.stdout);
assertEquals(runInput.exitCode, runDex.exitCode);
}
- private void build(ProgramConsumer consumer, MinifyMode minify) throws Exception {
+ private void build(
+ ProgramConsumer consumer,
+ MinifyMode minify,
+ boolean useUniqueClassMemberNames) throws Exception {
List<String> config =
Arrays.asList(
"-keep public class " + CLASS.getCanonicalName() + " {",
@@ -92,6 +115,7 @@
pgConfig -> {
pgConfig.setPrintMapping(true);
pgConfig.setOverloadAggressively(minify == MinifyMode.AGGRESSIVE);
+ pgConfig.setUseUniqueClassMemberNames(useUniqueClassMemberNames);
if (!minify.isMinify()) {
pgConfig.disableObfuscation();
}