Bound number of interface methods after interface merging
Bug: 205166439
Change-Id: Ia22209b4ec08ef26af9e3401d0edbce842f59d06
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index fbbe362..5e76e2d 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.horizontalclassmerging.policies.CheckSyntheticClasses;
import com.android.tools.r8.horizontalclassmerging.policies.FinalizeMergeGroup;
import com.android.tools.r8.horizontalclassmerging.policies.LimitClassGroups;
+import com.android.tools.r8.horizontalclassmerging.policies.LimitInterfaceGroups;
import com.android.tools.r8.horizontalclassmerging.policies.MinimizeInstanceFieldCasts;
import com.android.tools.r8.horizontalclassmerging.policies.NoAnnotationClasses;
import com.android.tools.r8.horizontalclassmerging.policies.NoCheckDiscard;
@@ -229,6 +230,7 @@
builder.add(
new NoDefaultInterfaceMethodMerging(appView, mode),
new NoDefaultInterfaceMethodCollisions(appView, mode),
+ new LimitInterfaceGroups(appView),
new OnlyDirectlyConnectedOrUnrelatedInterfaces(appView, mode));
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitClassGroups.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitClassGroups.java
index 210f21d..2752544 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitClassGroups.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitClassGroups.java
@@ -18,7 +18,7 @@
private final int maxGroupSize;
public LimitClassGroups(AppView<? extends AppInfoWithClassHierarchy> appView) {
- maxGroupSize = appView.options().horizontalClassMergerOptions().getMaxGroupSize();
+ maxGroupSize = appView.options().horizontalClassMergerOptions().getMaxClassGroupSize();
assert maxGroupSize >= 2;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitInterfaceGroups.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitInterfaceGroups.java
new file mode 100644
index 0000000..adee1f4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitInterfaceGroups.java
@@ -0,0 +1,63 @@
+// Copyright (c) 2021, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.MergeGroup;
+import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+public class LimitInterfaceGroups extends MultiClassPolicy {
+
+ private final int maxGroupSize;
+
+ public LimitInterfaceGroups(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ maxGroupSize = appView.options().horizontalClassMergerOptions().getMaxInterfaceGroupSize();
+ assert maxGroupSize >= 0;
+ }
+
+ @Override
+ public Collection<MergeGroup> apply(MergeGroup group) {
+ if (group.isClassGroup()) {
+ return Collections.singletonList(group);
+ }
+ // Mapping from new merge groups to their size.
+ Map<MergeGroup, Integer> newGroups = new LinkedHashMap<>();
+ for (DexProgramClass clazz : group) {
+ processClass(clazz, newGroups);
+ }
+ return removeTrivialGroups(newGroups.keySet());
+ }
+
+ private void processClass(DexProgramClass clazz, Map<MergeGroup, Integer> newGroups) {
+ int increment = clazz.getMethodCollection().size();
+
+ // Find an existing group.
+ for (Entry<MergeGroup, Integer> entry : newGroups.entrySet()) {
+ MergeGroup candidateGroup = entry.getKey();
+ int candidateGroupSize = entry.getValue();
+ int newCandidateGroupSize = candidateGroupSize + increment;
+ if (newCandidateGroupSize <= maxGroupSize) {
+ candidateGroup.add(clazz);
+ entry.setValue(newCandidateGroupSize);
+ return;
+ }
+ }
+
+ // Failed to find an existing group.
+ newGroups.put(new MergeGroup(clazz), increment);
+ }
+
+ @Override
+ public String getName() {
+ return "LimitInterfaceGroups";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 727f9c9..ea7c922 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1381,8 +1381,6 @@
private boolean ignoreRuntimeTypeChecksForTesting = false;
private boolean restrictToSynthetics = false;
- public int maxGroupSize = 30;
-
public void disable() {
enable = false;
}
@@ -1399,8 +1397,12 @@
this.enable = enable;
}
- public int getMaxGroupSize() {
- return maxGroupSize;
+ public int getMaxClassGroupSize() {
+ return 30;
+ }
+
+ public int getMaxInterfaceGroupSize() {
+ return 100;
}
public boolean isConstructorMergingEnabled() {
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
index c1da822..89f57c8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
@@ -73,7 +73,8 @@
.allMatch(
mergeGroup ->
mergeGroup.size()
- <= defaultHorizontalClassMergerOptions.getMaxGroupSize()));
+ <= defaultHorizontalClassMergerOptions
+ .getMaxClassGroupSize()));
})
.allowDiagnosticWarningMessages()
.compile()