Merge "Revert "Implicitly add necessary rules for Java reflections in any R8 mode.""
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index 4025180..7858ad8 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.3.9-dev";
+ public static final String LABEL = "1.3.11-dev";
private Version() {
}
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/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index 5b908af..c5d366a 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -25,7 +25,10 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -150,7 +153,12 @@
}
public void write(Writer writer) throws IOException {
- for (ClassNamingForNameMapper naming : classNameMappings.values()) {
+ // Sort classes by their original name such that the generated Proguard map is deterministic
+ // (and easy to navigate manually).
+ List<ClassNamingForNameMapper> classNamingForNameMappers =
+ new ArrayList<>(classNameMappings.values());
+ classNamingForNameMappers.sort(Comparator.comparing(x -> x.originalName));
+ for (ClassNamingForNameMapper naming : classNamingForNameMappers) {
naming.write(writer);
}
}
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..ee596f3 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -189,7 +189,7 @@
this.executorService = executorService;
this.graphLense = appView.getGraphLense();
this.methodPoolCollection = new MethodPoolCollection(application);
- this.renamedMembersLense = VerticalClassMergerGraphLense.builder(appInfo);
+ this.renamedMembersLense = new VerticalClassMergerGraphLense.Builder();
this.timing = timing;
Iterable<DexProgramClass> classes = application.classesWithDeterministicOrder();
@@ -651,7 +651,7 @@
if (Log.ENABLED) {
Log.debug(getClass(), "Merged %d classes.", numberOfMerges);
}
- return renamedMembersLense.build(graphLense, mergedClasses, application.dexItemFactory);
+ return renamedMembersLense.build(graphLense, mergedClasses, appInfo);
}
private boolean methodResolutionMayChange(DexClass source, DexClass target) {
@@ -733,7 +733,7 @@
private final DexClass source;
private final DexClass target;
private final VerticalClassMergerGraphLense.Builder deferredRenamings =
- VerticalClassMergerGraphLense.builder(appInfo);
+ new VerticalClassMergerGraphLense.Builder();
private boolean abortMerge = false;
private ClassMerger(DexClass source, DexClass target) {
@@ -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..4e09a9e 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,17 +60,22 @@
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;
}
- public static Builder builder(AppInfo appInfo) {
- return new Builder(appInfo);
- }
-
@Override
public GraphLenseLookupResult lookupMethod(
DexMethod method, DexEncodedMethod context, Type type) {
@@ -136,60 +144,107 @@
}
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 Builder(AppInfo appInfo) {
- this.appInfo = appInfo;
- }
+ private final Map<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
public GraphLense build(
- GraphLense previousLense,
- Map<DexType, DexType> mergedClasses,
- DexItemFactory dexItemFactory) {
+ GraphLense previousLense, Map<DexType, DexType> mergedClasses, AppInfo appInfo) {
if (fieldMap.isEmpty()
&& methodMap.isEmpty()
&& 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, appInfo.dexItemFactory, cache),
contextualVirtualToDirectMethodMaps,
+ getOriginalFieldSignaturesAfterClassMerging(
+ originalFieldSignatures, mergedClasses, appInfo.dexItemFactory),
+ getOriginalMethodSignaturesAfterClassMerging(
+ originalMethodSignatures, mergedClasses, appInfo.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 +266,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 +281,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);
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 127debe..135e961 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -9,6 +9,7 @@
* Android API level description
*/
public enum AndroidApiLevel {
+ Q(29), // Speculative, this can change.
P(28),
O_MR1(27),
O(26),
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 93a80b6..ae99990 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -537,7 +537,7 @@
//
// See b/69364976 and b/77996377.
public boolean canHaveBoundsCheckEliminationBug() {
- return minApiLevel <= AndroidApiLevel.L.getLevel();
+ return minApiLevel < AndroidApiLevel.M.getLevel();
}
// MediaTek JIT compilers for KitKat phones did not implement the not
@@ -631,7 +631,7 @@
//
// See b/78493232 and b/80118070.
public boolean canHaveArtStringNewInitBug() {
- return minApiLevel <= AndroidApiLevel.P.getLevel();
+ return minApiLevel < AndroidApiLevel.Q.getLevel();
}
// Dalvik tracing JIT may perform invalid optimizations when int/float values are converted to
@@ -639,6 +639,6 @@
//
// See b/77496850.
public boolean canHaveNumberConversionRegisterAllocationBug() {
- return minApiLevel <= AndroidApiLevel.K.getLevel();
+ return minApiLevel < AndroidApiLevel.L.getLevel();
}
}