Account for other merge groups in deadlock after class merging detection
Bug: 205611444
Change-Id: Ib7fbaebb9319baa3197c05a7167b074a4068e72d
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
index a57a034..d3c2661 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerCycles.java
@@ -131,7 +131,23 @@
}
newGroups.addAll(newGroupsFromPartition);
}
- return removeTrivialGroups(newGroups);
+ removeTrivialGroups(newGroups);
+ commit(group, newGroups);
+ return newGroups;
+ }
+
+ private void commit(MergeGroup oldGroup, List<MergeGroup> newGroups) {
+ for (MergeGroup newGroup : newGroups) {
+ for (DexProgramClass member : newGroup) {
+ allGroups.put(member, newGroup);
+ }
+ }
+ for (DexProgramClass member : oldGroup) {
+ MergeGroup newGroup = allGroups.get(member);
+ if (newGroup == oldGroup) {
+ allGroups.remove(member);
+ }
+ }
}
private MergeGroup getOrCreateGroupFor(
@@ -273,7 +289,10 @@
private class Tracer {
- final Set<DexProgramClass> group;
+ final MergeGroup group;
+
+ // The members of the existing merge group, for efficient membership querying.
+ final Set<DexProgramClass> groupMembers;
private final Set<DexProgramClass> seenClassInitializers = Sets.newIdentityHashSet();
private final ProgramMethodSet seenMethods = ProgramMethodSet.create();
@@ -289,7 +308,8 @@
private Collection<DexProgramClass> tracingRoots;
Tracer(MergeGroup group) {
- this.group = SetUtils.newIdentityHashSet(group);
+ this.group = group;
+ this.groupMembers = SetUtils.newIdentityHashSet(group);
}
void clearSeen() {
@@ -320,7 +340,7 @@
}
void recordClassInitializerReachableFromTracingRoots(DexProgramClass clazz) {
- assert group.contains(clazz);
+ assert groupMembers.contains(clazz);
classInitializerReachableFromClasses
.computeIfAbsent(clazz, ignoreKey(Sets::newIdentityHashSet))
.addAll(tracingRoots);
@@ -428,15 +448,12 @@
}
}
- // TODO(b/205611444): This needs to account for pending merging. If the given class is in a
- // merge group, then this should trigger the class initializers of all of the classes in the
- // merge group.
private void triggerClassInitializer(DexProgramClass clazz) {
if (!markClassInitializerAsSeen(clazz)) {
return;
}
- if (group.contains(clazz)) {
+ if (groupMembers.contains(clazz)) {
if (hasSingleTracingRoot(clazz)) {
// We found an execution path from the class initializer of the given class back to its
// own class initializer. Therefore this class is not eligible for merging.
@@ -457,6 +474,13 @@
}
triggerClassInitializer(clazz.getSuperType());
+
+ MergeGroup other = allGroups.get(clazz);
+ if (other != null && other != group) {
+ for (DexProgramClass member : other) {
+ triggerClassInitializer(member);
+ }
+ }
}
@Override
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingMultipleGroupsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingMultipleGroupsTest.java
index a2b099a..3d07644 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingMultipleGroupsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClinitDeadlockAfterMergingMultipleGroupsTest.java
@@ -33,11 +33,10 @@
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepClassAndMembersRules(Main.class)
- // TODO(b/205611444): Should only allow merging three out of the four merge groups.
.addHorizontallyMergedClassesInspector(
inspector ->
inspector
- .assertIsCompleteMergeGroup(A1.class, A2.class)
+ .assertClassesNotMerged(A1.class, A2.class)
.assertIsCompleteMergeGroup(B1.class, B2.class)
.assertIsCompleteMergeGroup(C1.class, C2.class)
.assertIsCompleteMergeGroup(D1.class, D2.class)