Simplify interface method minification
Bug: 123730537
Change-Id: If69ead00ab4ec14e5a007e90e9aae8d7f3eb6824
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 011c026..734e421 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -624,7 +624,6 @@
new Minifier(appView.appInfo().withLiveness(), rootSet, desugaredCallSites, options)
.run(timing);
timing.end();
- assert namingLens.verifyNoCollisions(application.classes(), options.itemFactory);
} else {
namingLens = NamingLens.getIdentityLens();
}
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
index bbb3391..90dbbdb 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import java.util.Map;
import java.util.function.Function;
@@ -33,7 +34,7 @@
}
}
- Map<DexField, DexString> computeRenaming(Timing timing) {
+ FieldRenaming computeRenaming(Timing timing) {
// Reserve names in all classes first. We do this in subtyping order so we do not
// shadow a reserved field in subclasses. While there is no concept of virtual field
// dispatch in Java, field resolution still traverses the super type chain and external
@@ -55,7 +56,20 @@
timing.begin("rename-references");
renameNonReboundReferences();
timing.end();
- return renaming;
+ return new FieldRenaming(renaming);
+ }
+
+ static class FieldRenaming {
+
+ final Map<DexField, DexString> renaming;
+
+ private FieldRenaming(Map<DexField, DexString> renaming) {
+ this.renaming = renaming;
+ }
+
+ public static FieldRenaming empty() {
+ return new FieldRenaming(ImmutableMap.of());
+ }
}
private void reserveNamesInSubtypes(DexType type, NamingState<DexType, ?> state) {
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 5f990ac..21e6bf9 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.utils.Timing;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collections;
@@ -96,6 +97,8 @@
private final Equivalence<DexMethod> equivalence;
private final Map<DexCallSite, DexString> callSiteRenaming = new IdentityHashMap<>();
+ private final Map<DexType, DexType> frontierMap = new IdentityHashMap<>();
+
MethodNameMinifier(
AppInfoWithLiveness appInfo,
RootSet rootSet,
@@ -121,6 +124,7 @@
}
static class MethodRenaming {
+
final Map<DexMethod, DexString> renaming;
final Map<DexCallSite, DexString> callSiteRenaming;
@@ -129,26 +133,27 @@
this.renaming = renaming;
this.callSiteRenaming = callSiteRenaming;
}
+
+ public static MethodRenaming empty() {
+ return new MethodRenaming(ImmutableMap.of(), ImmutableMap.of());
+ }
}
MethodRenaming computeRenaming(Timing timing) {
// Phase 1: Reserve all the names that need to be kept and allocate linked state in the
// library part.
timing.begin("Phase 1");
- Map<DexType, DexType> frontierMap = new IdentityHashMap<>();
- reserveNamesInClasses(appInfo.dexItemFactory.objectType,
- appInfo.dexItemFactory.objectType,
- null, frontierMap);
+ reserveNamesInClasses(
+ appInfo.dexItemFactory.objectType, appInfo.dexItemFactory.objectType, null);
timing.end();
// Phase 2: Reserve all the names that are required for interfaces.
timing.begin("Phase 2");
- DexType.forAllInterfaces(
- appInfo.dexItemFactory, iface -> reserveNamesInInterfaces(iface, frontierMap));
+ DexType.forAllInterfaces(appInfo.dexItemFactory, this::reserveNamesInInterfaces);
timing.end();
// Phase 3: Assign names to interface methods. These are assigned by finding a name that is
// free in all naming states that may hold an implementation.
timing.begin("Phase 3");
- assignNamesToInterfaceMethods(frontierMap, timing);
+ assignNamesToInterfaceMethods(timing);
timing.end();
// Phase 4: Assign names top-down by traversing the subtype hierarchy.
timing.begin("Phase 4");
@@ -201,8 +206,7 @@
}
}
- private Set<NamingState<DexProto, ?>> getReachableStates(DexType type,
- Map<DexType, DexType> frontierMap) {
+ private Set<NamingState<DexProto, ?>> getReachableStates(DexType type) {
Set<DexType> interfaces = Sets.newIdentityHashSet();
interfaces.add(type);
collectSuperInterfaces(type, interfaces);
@@ -221,7 +225,7 @@
return reachableStates;
}
- private void assignNamesToInterfaceMethods(Map<DexType, DexType> frontierMap, Timing timing) {
+ private void assignNamesToInterfaceMethods(Timing timing) {
// First compute a map from method signatures to a set of naming states for interfaces and
// frontier states of classes that implement them. We add the frontier states so that we can
// reserve the names for later method naming.
@@ -232,17 +236,20 @@
Map<Wrapper<DexMethod>, Set<DexMethod>> sourceMethodsMap = new HashMap<>();
// A map from DexMethods to the first interface state it was seen in. Used to pick good names.
Map<Wrapper<DexMethod>, NamingState<DexProto, ?>> originStates = new HashMap<>();
- DexType.forAllInterfaces(appInfo.dexItemFactory, iface -> {
- assert iface.isInterface();
- DexClass clazz = appInfo.definitionFor(iface);
- if (clazz != null) {
- Set<NamingState<DexProto, ?>> collectedStates = getReachableStates(iface, frontierMap);
- for (DexEncodedMethod method : shuffleMethods(clazz.methods())) {
- addStatesToGlobalMapForMethod(
- method, collectedStates, globalStateMap, sourceMethodsMap, originStates, iface);
- }
- }
- });
+ DexType.forAllInterfaces(
+ appInfo.dexItemFactory,
+ iface -> {
+ assert iface.isInterface();
+ DexClass clazz = appInfo.definitionFor(iface);
+ if (clazz != null) {
+ assert clazz.isInterface();
+ Set<NamingState<DexProto, ?>> collectedStates = getReachableStates(iface);
+ for (DexEncodedMethod method : shuffleMethods(clazz.methods())) {
+ addStatesToGlobalMapForMethod(
+ method, collectedStates, globalStateMap, sourceMethodsMap, originStates, iface);
+ }
+ }
+ });
// Collect the live call sites for multi-interface lambda expression renaming. For code with
// desugared lambdas this is a conservative estimate, as we don't track if the generated
// lambda classes survive into the output. As multi-interface lambda expressions are rare
@@ -272,7 +279,7 @@
for (DexEncodedMethod method : implementedMethods) {
DexType iface = method.method.holder;
assert iface.isInterface();
- Set<NamingState<DexProto, ?>> collectedStates = getReachableStates(iface, frontierMap);
+ Set<NamingState<DexProto, ?>> collectedStates = getReachableStates(iface);
addStatesToGlobalMapForMethod(
method, collectedStates, globalStateMap, sourceMethodsMap, originStates, iface);
callSiteMethods.add(equivalence.wrap(method.method));
@@ -434,34 +441,33 @@
return false;
}
- private void reserveNamesInClasses(DexType type, DexType libraryFrontier,
- NamingState<DexProto, ?> parent,
- Map<DexType, DexType> frontierMap) {
+ private void reserveNamesInClasses(
+ DexType type, DexType libraryFrontier, NamingState<DexProto, ?> parent) {
assert !type.isInterface();
DexClass holder = appInfo.definitionFor(type);
- NamingState<DexProto, ?> state = allocateNamingStateAndReserve(holder, type, libraryFrontier,
- parent, frontierMap);
+ NamingState<DexProto, ?> state =
+ allocateNamingStateAndReserve(holder, type, libraryFrontier, parent);
// If this is a library class (or effectively a library class as it is missing) move the
// frontier forward.
- type.forAllExtendsSubtypes(subtype -> {
- assert !subtype.isInterface();
- reserveNamesInClasses(subtype,
- holder == null || holder.isLibraryClass() ? subtype : libraryFrontier,
- state, frontierMap);
- });
+ type.forAllExtendsSubtypes(
+ subtype -> {
+ assert !subtype.isInterface();
+ reserveNamesInClasses(
+ subtype,
+ holder == null || holder.isLibraryClass() ? subtype : libraryFrontier,
+ state);
+ });
}
- private void reserveNamesInInterfaces(DexType type, Map<DexType, DexType> frontierMap) {
+ private void reserveNamesInInterfaces(DexType type) {
assert type.isInterface();
frontierMap.put(type, type);
DexClass holder = appInfo.definitionFor(type);
- allocateNamingStateAndReserve(holder, type, type, null, frontierMap);
+ allocateNamingStateAndReserve(holder, type, type, null);
}
- private NamingState<DexProto, ?> allocateNamingStateAndReserve(DexClass holder, DexType type,
- DexType libraryFrontier,
- NamingState<DexProto, ?> parent,
- Map<DexType, DexType> frontierMap) {
+ private NamingState<DexProto, ?> allocateNamingStateAndReserve(
+ DexClass holder, DexType type, DexType libraryFrontier, NamingState<DexProto, ?> parent) {
frontierMap.put(type, libraryFrontier);
NamingState<DexProto, ?> state =
computeStateIfAbsent(
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index e4ccbcd..becc643 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.naming.ClassNameMinifier.ClassRenaming;
+import com.android.tools.r8.naming.FieldNameMinifier.FieldRenaming;
import com.android.tools.r8.naming.MethodNameMinifier.MethodRenaming;
import com.android.tools.r8.optimize.MemberRebindingAnalysis;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
@@ -56,21 +57,28 @@
ClassNameMinifier classNameMinifier = new ClassNameMinifier(appInfo, rootSet, options);
ClassRenaming classRenaming = classNameMinifier.computeRenaming(timing);
timing.end();
+
+ assert new MinifiedRenaming(
+ classRenaming, MethodRenaming.empty(), FieldRenaming.empty(), appInfo)
+ .verifyNoCollisions(appInfo.classes(), appInfo.dexItemFactory);
+
timing.begin("MinifyMethods");
MethodRenaming methodRenaming =
new MethodNameMinifier(appInfo, rootSet, desugaredCallSites, options)
.computeRenaming(timing);
timing.end();
+
+ assert new MinifiedRenaming(classRenaming, methodRenaming, FieldRenaming.empty(), appInfo)
+ .verifyNoCollisions(appInfo.classes(), appInfo.dexItemFactory);
+
timing.begin("MinifyFields");
- Map<DexField, DexString> fieldRenaming =
+ FieldRenaming fieldRenaming =
new FieldNameMinifier(appInfo, rootSet, options).computeRenaming(timing);
timing.end();
- NamingLens lens =
- new MinifiedRenaming(
- classRenaming,
- methodRenaming,
- fieldRenaming,
- appInfo);
+
+ NamingLens lens = new MinifiedRenaming(classRenaming, methodRenaming, fieldRenaming, appInfo);
+ assert lens.verifyNoCollisions(appInfo.classes(), appInfo.dexItemFactory);
+
timing.begin("MinifyIdentifiers");
new IdentifierMinifier(
appInfo, options.getProguardConfiguration().getAdaptClassStrings(), lens).run();
@@ -87,14 +95,14 @@
private MinifiedRenaming(
ClassRenaming classRenaming,
MethodRenaming methodRenaming,
- Map<DexField, DexString> fieldRenaming,
+ FieldRenaming fieldRenaming,
AppInfo appInfo) {
this.appInfo = appInfo;
this.packageRenaming = classRenaming.packageRenaming;
renaming.putAll(classRenaming.classRenaming);
renaming.putAll(methodRenaming.renaming);
renaming.putAll(methodRenaming.callSiteRenaming);
- renaming.putAll(fieldRenaming);
+ renaming.putAll(fieldRenaming.renaming);
}
@Override