Merge "Mapping from signatures after class merging to before"
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLense.java b/src/main/java/com/android/tools/r8/graph/GraphLense.java
index 8de4a6e..84ceac3 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLense.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLense.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.ir.code.Invoke.Type;
+import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableSet;
import java.util.HashSet;
import java.util.IdentityHashMap;
@@ -78,7 +79,8 @@
if (typeMap.isEmpty() && methodMap.isEmpty() && fieldMap.isEmpty()) {
return previousLense;
}
- return new NestedGraphLense(typeMap, methodMap, fieldMap, previousLense, dexItemFactory);
+ return new NestedGraphLense(
+ typeMap, methodMap, fieldMap, null, null, previousLense, dexItemFactory);
}
}
@@ -87,6 +89,10 @@
return new Builder();
}
+ public abstract DexField getOriginalFieldSignature(DexField field);
+
+ public abstract DexMethod getOriginalMethodSignature(DexMethod method);
+
public abstract DexType lookupType(DexType type);
// This overload can be used when the graph lense is known to be context insensitive.
@@ -156,6 +162,16 @@
private static class IdentityGraphLense extends GraphLense {
@Override
+ public DexField getOriginalFieldSignature(DexField field) {
+ return field;
+ }
+
+ @Override
+ public DexMethod getOriginalMethodSignature(DexMethod method) {
+ return method;
+ }
+
+ @Override
public DexType lookupType(DexType type) {
return type;
}
@@ -197,16 +213,47 @@
protected final Map<DexMethod, DexMethod> methodMap;
protected final Map<DexField, DexField> fieldMap;
- public NestedGraphLense(Map<DexType, DexType> typeMap, Map<DexMethod, DexMethod> methodMap,
- Map<DexField, DexField> fieldMap, GraphLense previousLense, DexItemFactory dexItemFactory) {
+ // Maps that store the original signature of fields and methods that have been affected by
+ // vertical class merging. Needed to generate a correct Proguard map in the end.
+ private final BiMap<DexField, DexField> originalFieldSignatures;
+ private final BiMap<DexMethod, DexMethod> originalMethodSignatures;
+
+ public NestedGraphLense(
+ Map<DexType, DexType> typeMap,
+ Map<DexMethod, DexMethod> methodMap,
+ Map<DexField, DexField> fieldMap,
+ BiMap<DexField, DexField> originalFieldSignatures,
+ BiMap<DexMethod, DexMethod> originalMethodSignatures,
+ GraphLense previousLense,
+ DexItemFactory dexItemFactory) {
this.typeMap = typeMap.isEmpty() ? null : typeMap;
this.methodMap = methodMap;
this.fieldMap = fieldMap;
+ this.originalFieldSignatures = originalFieldSignatures;
+ this.originalMethodSignatures = originalMethodSignatures;
this.previousLense = previousLense;
this.dexItemFactory = dexItemFactory;
}
@Override
+ public DexField getOriginalFieldSignature(DexField field) {
+ DexField originalField =
+ originalFieldSignatures != null
+ ? originalFieldSignatures.getOrDefault(field, field)
+ : field;
+ return previousLense.getOriginalFieldSignature(originalField);
+ }
+
+ @Override
+ public DexMethod getOriginalMethodSignature(DexMethod method) {
+ DexMethod originalMethod =
+ originalMethodSignatures != null
+ ? originalMethodSignatures.getOrDefault(method, method)
+ : method;
+ return previousLense.getOriginalMethodSignature(originalMethod);
+ }
+
+ @Override
public DexType lookupType(DexType type) {
if (type.isArrayType()) {
synchronized (this) {
diff --git a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
index 492bcd0..6ba18ac 100644
--- a/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/BridgeMethodAnalysis.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.optimize;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
@@ -88,6 +89,17 @@
}
@Override
+ public DexField getOriginalFieldSignature(DexField field) {
+ return previousLense.getOriginalFieldSignature(field);
+ }
+
+ @Override
+ public DexMethod getOriginalMethodSignature(DexMethod method) {
+ // TODO(b/79143143): implement this when re-enable bridge analysis.
+ throw new Unimplemented("BridgeLense.getOriginalMethodSignature() not implemented");
+ }
+
+ @Override
public DexType lookupType(DexType type) {
return previousLense.lookupType(type);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java
index 4ee0cee..98a0da4 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingLense.java
@@ -38,7 +38,8 @@
Map<DexMethod, DexMethod> methodMap,
Map<DexField, DexField> fieldMap,
GraphLense previousLense) {
- super(ImmutableMap.of(), methodMap, fieldMap, previousLense, appInfo.dexItemFactory);
+ super(
+ ImmutableMap.of(), methodMap, fieldMap, null, null, previousLense, appInfo.dexItemFactory);
this.appInfo = appInfo;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java b/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
index 7a9c08f..ad7effd 100644
--- a/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
+++ b/src/main/java/com/android/tools/r8/optimize/PublicizerLense.java
@@ -25,6 +25,8 @@
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
+ null,
+ null,
appView.getGraphLense(),
appView.getAppInfo().dexItemFactory);
this.appView = appView;
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index a19c0d5..9973121 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -773,6 +773,7 @@
directMethod.isClassInitializer() ? Rename.NEVER : Rename.IF_NEEDED);
add(directMethods, resultingDirectMethod, MethodSignatureEquivalence.get());
deferredRenamings.map(directMethod.method, resultingDirectMethod.method);
+ deferredRenamings.recordMove(directMethod.method, resultingDirectMethod.method);
if (!directMethod.isStaticMethod()) {
blockRedirectionOfSuperCalls(resultingDirectMethod.method);
@@ -802,6 +803,7 @@
DexEncodedMethod resultingVirtualMethod =
renameMethod(virtualMethod, availableMethodSignatures, Rename.NEVER);
deferredRenamings.map(virtualMethod.method, resultingVirtualMethod.method);
+ deferredRenamings.recordMove(virtualMethod.method, resultingVirtualMethod.method);
add(virtualMethods, resultingVirtualMethod, MethodSignatureEquivalence.get());
continue;
}
@@ -856,6 +858,7 @@
}
deferredRenamings.map(virtualMethod.method, shadowedBy.method);
+ deferredRenamings.recordMove(virtualMethod.method, resultingDirectMethod.method);
}
if (abortMerge) {
@@ -1155,6 +1158,7 @@
DexEncodedMethod result = method.toTypeSubstitutedMethod(newSignature);
result.markForceInline();
deferredRenamings.map(method.method, result.method);
+ deferredRenamings.recordMove(method.method, result.method);
// Renamed constructors turn into ordinary private functions. They can be private, as
// they are only references from their direct subclass, which they were merged into.
result.accessFlags.unsetConstructor();
@@ -1510,6 +1514,16 @@
}
@Override
+ public DexField getOriginalFieldSignature(DexField field) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public DexMethod getOriginalMethodSignature(DexMethod method) {
+ throw new Unreachable();
+ }
+
+ @Override
public DexType lookupType(DexType type) {
return type == source ? target : mergedClasses.getOrDefault(type, type);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
index 5974e60..e074c25 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLense.java
@@ -14,6 +14,9 @@
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.GraphLense.NestedGraphLense;
import com.android.tools.r8.ir.code.Invoke.Type;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.HashMap;
@@ -57,8 +60,17 @@
Map<DexMethod, DexMethod> methodMap,
Set<DexMethod> mergedMethods,
Map<DexType, Map<DexMethod, GraphLenseLookupResult>> contextualVirtualToDirectMethodMaps,
+ BiMap<DexField, DexField> originalFieldSignatures,
+ BiMap<DexMethod, DexMethod> originalMethodSignatures,
GraphLense previousLense) {
- super(ImmutableMap.of(), methodMap, fieldMap, previousLense, appInfo.dexItemFactory);
+ super(
+ ImmutableMap.of(),
+ methodMap,
+ fieldMap,
+ originalFieldSignatures,
+ originalMethodSignatures,
+ previousLense,
+ appInfo.dexItemFactory);
this.appInfo = appInfo;
this.mergedMethods = mergedMethods;
this.contextualVirtualToDirectMethodMaps = contextualVirtualToDirectMethodMaps;
@@ -138,12 +150,14 @@
public static class Builder {
private final AppInfo appInfo;
- protected final Map<DexField, DexField> fieldMap = new HashMap<>();
+ protected final BiMap<DexField, DexField> fieldMap = HashBiMap.create();
protected final Map<DexMethod, DexMethod> methodMap = new HashMap<>();
private final ImmutableSet.Builder<DexMethod> mergedMethodsBuilder = ImmutableSet.builder();
private final Map<DexType, Map<DexMethod, GraphLenseLookupResult>>
contextualVirtualToDirectMethodMaps = new HashMap<>();
+ private final Map<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
+
private Builder(AppInfo appInfo) {
this.appInfo = appInfo;
}
@@ -157,39 +171,91 @@
&& contextualVirtualToDirectMethodMaps.isEmpty()) {
return previousLense;
}
+ Map<DexProto, DexProto> cache = new HashMap<>();
+ BiMap<DexField, DexField> originalFieldSignatures = fieldMap.inverse();
return new VerticalClassMergerGraphLense(
appInfo,
fieldMap,
methodMap,
getMergedMethodSignaturesAfterClassMerging(
- mergedMethodsBuilder.build(), mergedClasses, dexItemFactory),
+ mergedMethodsBuilder.build(), mergedClasses, dexItemFactory, cache),
contextualVirtualToDirectMethodMaps,
+ getOriginalFieldSignaturesAfterClassMerging(
+ originalFieldSignatures, mergedClasses, dexItemFactory),
+ getOriginalMethodSignaturesAfterClassMerging(
+ originalMethodSignatures, mergedClasses, dexItemFactory, cache),
previousLense);
}
// After we have recorded that a method "a.b.c.Foo;->m(A, B, C)V" was merged into another class,
// it could be that the class B was merged into its subclass B'. In that case we update the
// signature to "a.b.c.Foo;->m(A, B', C)V".
- private Set<DexMethod> getMergedMethodSignaturesAfterClassMerging(
+ private static Set<DexMethod> getMergedMethodSignaturesAfterClassMerging(
Set<DexMethod> mergedMethods,
Map<DexType, DexType> mergedClasses,
- DexItemFactory dexItemFactory) {
+ DexItemFactory dexItemFactory,
+ Map<DexProto, DexProto> cache) {
ImmutableSet.Builder<DexMethod> result = ImmutableSet.builder();
- Map<DexProto, DexProto> cache = new HashMap<>();
for (DexMethod signature : mergedMethods) {
- DexType newHolder = mergedClasses.getOrDefault(signature.holder, signature.holder);
- DexProto newProto =
- dexItemFactory.applyClassMappingToProto(
- signature.proto, type -> mergedClasses.getOrDefault(type, type), cache);
- if (signature.holder.equals(newHolder) && signature.proto.equals(newProto)) {
- result.add(signature);
- } else {
- result.add(dexItemFactory.createMethod(newHolder, newProto, signature.name));
- }
+ result.add(
+ getMethodSignatureAfterClassMerging(signature, mergedClasses, dexItemFactory, cache));
}
return result.build();
}
+ private static BiMap<DexField, DexField> getOriginalFieldSignaturesAfterClassMerging(
+ Map<DexField, DexField> originalFieldSignatures,
+ Map<DexType, DexType> mergedClasses,
+ DexItemFactory dexItemFactory) {
+ ImmutableBiMap.Builder<DexField, DexField> result = ImmutableBiMap.builder();
+ for (Map.Entry<DexField, DexField> entry : originalFieldSignatures.entrySet()) {
+ result.put(
+ getFieldSignatureAfterClassMerging(entry.getKey(), mergedClasses, dexItemFactory),
+ entry.getValue());
+ }
+ return result.build();
+ }
+
+ private static BiMap<DexMethod, DexMethod> getOriginalMethodSignaturesAfterClassMerging(
+ Map<DexMethod, DexMethod> originalMethodSignatures,
+ Map<DexType, DexType> mergedClasses,
+ DexItemFactory dexItemFactory,
+ Map<DexProto, DexProto> cache) {
+ ImmutableBiMap.Builder<DexMethod, DexMethod> result = ImmutableBiMap.builder();
+ for (Map.Entry<DexMethod, DexMethod> entry : originalMethodSignatures.entrySet()) {
+ result.put(
+ getMethodSignatureAfterClassMerging(
+ entry.getKey(), mergedClasses, dexItemFactory, cache),
+ entry.getValue());
+ }
+ return result.build();
+ }
+
+ private static DexField getFieldSignatureAfterClassMerging(
+ DexField signature, Map<DexType, DexType> mergedClasses, DexItemFactory dexItemFactory) {
+ DexType newClass = mergedClasses.getOrDefault(signature.clazz, signature.clazz);
+ DexType newType = mergedClasses.getOrDefault(signature.type, signature.type);
+ if (signature.clazz.equals(newClass) && signature.type.equals(newType)) {
+ return signature;
+ }
+ return dexItemFactory.createField(newClass, newType, signature.name);
+ }
+
+ private static DexMethod getMethodSignatureAfterClassMerging(
+ DexMethod signature,
+ Map<DexType, DexType> mergedClasses,
+ DexItemFactory dexItemFactory,
+ Map<DexProto, DexProto> cache) {
+ DexType newHolder = mergedClasses.getOrDefault(signature.holder, signature.holder);
+ DexProto newProto =
+ dexItemFactory.applyClassMappingToProto(
+ signature.proto, type -> mergedClasses.getOrDefault(type, type), cache);
+ if (signature.holder.equals(newHolder) && signature.proto.equals(newProto)) {
+ return signature;
+ }
+ return dexItemFactory.createMethod(newHolder, newProto, signature.name);
+ }
+
public boolean hasMappingForSignatureInContext(DexType context, DexMethod signature) {
Map<DexMethod, GraphLenseLookupResult> virtualToDirectMethodMap =
contextualVirtualToDirectMethodMaps.get(context);
@@ -211,6 +277,10 @@
methodMap.put(from, to);
}
+ public void recordMove(DexMethod from, DexMethod to) {
+ originalMethodSignatures.put(to, from);
+ }
+
public void mapVirtualMethodToDirectInType(
DexMethod from, GraphLenseLookupResult to, DexType type) {
Map<DexMethod, GraphLenseLookupResult> virtualToDirectMethodMap =
@@ -222,6 +292,7 @@
fieldMap.putAll(builder.fieldMap);
methodMap.putAll(builder.methodMap);
mergedMethodsBuilder.addAll(builder.mergedMethodsBuilder.build());
+ originalMethodSignatures.putAll(builder.originalMethodSignatures);
for (DexType context : builder.contextualVirtualToDirectMethodMaps.keySet()) {
Map<DexMethod, GraphLenseLookupResult> current =
contextualVirtualToDirectMethodMaps.get(context);