Prune method access info collection
Bug: b/313365881
Change-Id: I35170faee13fd255505b218a822764662b0202c8
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index e61ec53..14c4975 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -558,7 +558,7 @@
@SuppressWarnings("ReferenceEquality")
public DexEncodedMethod lookupSignaturePolymorphicMethod(
DexString methodName, DexItemFactory factory) {
- if (type != factory.methodHandleType && type != factory.varHandleType) {
+ if (!isClassWithSignaturePolymorphicMethods(factory)) {
return null;
}
DexEncodedMethod matchingName = null;
@@ -579,15 +579,17 @@
return signaturePolymorphicMethod;
}
- @SuppressWarnings("ReferenceEquality")
- public static boolean isSignaturePolymorphicMethod(
- DexEncodedMethod method, DexItemFactory factory) {
- assert method.getHolderType() == factory.methodHandleType
- || method.getHolderType() == factory.varHandleType;
- return method.accessFlags.isVarargs()
- && method.accessFlags.isNative()
- && method.getReference().proto.parameters.size() == 1
- && method.getReference().proto.parameters.values[0] == factory.objectArrayType;
+ public boolean isClassWithSignaturePolymorphicMethods(DexItemFactory dexItemFactory) {
+ return type.isIdenticalTo(dexItemFactory.methodHandleType)
+ || type.isIdenticalTo(dexItemFactory.varHandleType);
+ }
+
+ public boolean isSignaturePolymorphicMethod(DexEncodedMethod method, DexItemFactory factory) {
+ assert isClassWithSignaturePolymorphicMethods(factory);
+ return method.isVarargs()
+ && method.isNative()
+ && method.getParameters().size() == 1
+ && method.getParameter(0).isIdenticalTo(factory.objectArrayType);
}
public boolean canBeInstantiatedByNewInstance() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 40bdbe2..7465b0a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -450,6 +450,10 @@
return accessFlags.isSynchronized();
}
+ public boolean isVarargs() {
+ return accessFlags.isVarargs();
+ }
+
public boolean isInitializer() {
checkIfObsolete();
return isInstanceInitializer() || isClassInitializer();
diff --git a/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java b/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
index beb2fb3..2671841 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
@@ -20,6 +20,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
+import java.util.function.Predicate;
import java.util.function.Supplier;
public class MethodAccessInfoCollection {
@@ -334,6 +335,18 @@
}
}
+ public void removeIf(Predicate<DexMethod> predicate) {
+ removeIf(predicate, directInvokes);
+ removeIf(predicate, interfaceInvokes);
+ removeIf(predicate, staticInvokes);
+ removeIf(predicate, superInvokes);
+ removeIf(predicate, virtualInvokes);
+ }
+
+ private static void removeIf(Predicate<DexMethod> predicate, Map<DexMethod, ?> invokes) {
+ invokes.keySet().removeIf(predicate);
+ }
+
public MethodAccessInfoCollection build() {
return new MethodAccessInfoCollection(
directInvokes, interfaceInvokes, staticInvokes, superInvokes, virtualInvokes);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
index 8e04491..ab17919 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -403,22 +403,18 @@
public void replaceAllDirectMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
DexEncodedMethod[] oldMethods = directMethods;
clearDirectMethods();
- DexEncodedMethod[] newMethods = new DexEncodedMethod[oldMethods.length];
- for (int i = 0; i < oldMethods.length; i++) {
- newMethods[i] = replacement.apply(oldMethods[i]);
- }
- directMethods = newMethods;
+ directMethods =
+ ArrayUtils.initialize(
+ new DexEncodedMethod[oldMethods.length], i -> replacement.apply(oldMethods[i]));
}
@Override
public void replaceAllVirtualMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
DexEncodedMethod[] oldMethods = virtualMethods;
clearVirtualMethods();
- DexEncodedMethod[] newMethods = new DexEncodedMethod[oldMethods.length];
- for (int i = 0; i < oldMethods.length; i++) {
- newMethods[i] = replacement.apply(oldMethods[i]);
- }
- virtualMethods = newMethods;
+ virtualMethods =
+ ArrayUtils.initialize(
+ new DexEncodedMethod[oldMethods.length], i -> replacement.apply(oldMethods[i]));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
index 6dbdc35..710666b 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -53,6 +53,15 @@
return this;
}
+ public boolean isSignaturePolymorphicResolution(DexMethod method, DexItemFactory dexItemFactory) {
+ if (isSingleResolution() && !method.match(getResolvedMethod())) {
+ assert getResolvedHolder().isClassWithSignaturePolymorphicMethods(dexItemFactory);
+ assert getResolvedHolder().isSignaturePolymorphicMethod(getResolvedMethod(), dexItemFactory);
+ return true;
+ }
+ return false;
+ }
+
/**
* Returns true if resolution succeeded *and* the resolved method has a known definition.
*
@@ -179,8 +188,8 @@
DexProgramClass context, AppView<? extends AppInfoWithClassHierarchy> appView);
public final DexClassAndMethod lookupInvokeSuperTarget(
- DexProgramClass context, AppView<? extends AppInfoWithClassHierarchy> appView) {
- return lookupInvokeSuperTarget(context, appView, appView.appInfo());
+ ProgramDefinition context, AppView<? extends AppInfoWithClassHierarchy> appView) {
+ return lookupInvokeSuperTarget(context.getContextClass(), appView, appView.appInfo());
}
/** Lookup the single target of an invoke-super on this resolution result if possible. */
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 30d6e81..ea7cbf5 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1509,11 +1509,9 @@
invokeAnalyses.forEach(analysis -> analysis.traceInvokeStatic(invokedMethod, context));
}
- @SuppressWarnings("UnusedVariable")
void traceInvokeSuper(DexMethod invokedMethod, ProgramMethod context) {
// We have to revisit super invokes based on the context they are found in. The same
// method descriptor will hit different targets, depending on the context it is used in.
- DexMethod actualTarget = getInvokeSuperTarget(invokedMethod, context);
if (!registerMethodWithTargetAndContext(
methodAccessInfoCollection::registerInvokeSuperInContext, invokedMethod, context)) {
return;
@@ -1963,20 +1961,6 @@
});
}
- private DexMethod getInvokeSuperTarget(DexMethod method, ProgramMethod currentMethod) {
- DexClass methodHolderClass = appView.definitionFor(method.holder);
- if (methodHolderClass != null && methodHolderClass.isInterface()) {
- return method;
- }
- DexProgramClass holderClass = currentMethod.getHolder();
- if (holderClass.superType == null || holderClass.isInterface()) {
- // We do not know better or this call is made from an interface.
- return method;
- }
- // Return the invoked method on the supertype.
- return appView.dexItemFactory().createMethod(holderClass.superType, method.proto, method.name);
- }
-
//
// Actual actions performed.
//
@@ -4225,6 +4209,15 @@
assert fieldAccessInfoCollection.verifyMappingIsOneToOne();
timing.end();
+ // Remove mappings for methods that don't resolve in the method access info collection.
+ // TODO(b/313365881): Should use non-legacy resolution, but this fails.
+ methodAccessInfoCollection.removeIf(
+ method -> {
+ MethodResolutionResult result = appInfo.unsafeResolveMethodDueToDexFormatLegacy(method);
+ return result.isFailedResolution()
+ || result.isSignaturePolymorphicResolution(method, appView.dexItemFactory());
+ });
+
// Verify all references on the input app before synthesizing definitions.
assert verifyReferences(appInfo.app());
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index f35f32b..8b3a049 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -298,7 +298,7 @@
}
});
if (seenMethod.isFalse()) {
- handleRewrittenMethodReference(rewrittenMethod, (DexClassAndMethod) null);
+ handleRewrittenMethodReference(rewrittenMethod, null);
}
}
}
@@ -368,7 +368,8 @@
.forEachFailureDependency(
type -> addType(type, referencedFrom),
methodCausingFailure ->
- handleRewrittenMethodReference(method, methodCausingFailure));
+ handleRewrittenMethodReference(
+ method, methodCausingFailure.asDexClassAndMethod(appView)));
return;
}
seenSingleResult.set();
@@ -379,33 +380,27 @@
failingResult -> {
assert failingResult.isFailedResolution();
if (!failingResult.asFailedResolution().hasMethodsCausingError()) {
- handleRewrittenMethodReference(method, (DexEncodedMethod) null);
+ handleRewrittenMethodReference(method, null);
}
});
}
}
- private void handleRewrittenMethodReference(
- DexMethod method, DexClassAndMethod resolvedMethod) {
- handleRewrittenMethodReference(
- method, resolvedMethod == null ? null : resolvedMethod.getDefinition());
- }
-
@SuppressWarnings("ReferenceEquality")
private void handleRewrittenMethodReference(
- DexMethod method, DexEncodedMethod resolvedMethod) {
- assert resolvedMethod == null
- || resolvedMethod.getReference().match(method)
- || DexClass.isSignaturePolymorphicMethod(resolvedMethod, factory);
+ DexMethod method, DexClassAndMethod resolvedMethod) {
addType(method.getHolderType(), referencedFrom);
addTypes(method.getParameters(), referencedFrom);
addType(method.getReturnType(), referencedFrom);
if (resolvedMethod != null) {
+ DexEncodedMethod definition = resolvedMethod.getDefinition();
+ assert resolvedMethod.getReference().match(method)
+ || resolvedMethod.getHolder().isSignaturePolymorphicMethod(definition, factory);
if (isTargetType(resolvedMethod.getHolderType())) {
if (resolvedMethod.getHolderType() != method.getHolderType()) {
addType(resolvedMethod.getHolderType(), referencedFrom);
}
- TracedMethodImpl tracedMethod = new TracedMethodImpl(resolvedMethod, referencedFrom);
+ TracedMethodImpl tracedMethod = new TracedMethodImpl(definition, referencedFrom);
consumer.acceptMethod(tracedMethod, diagnostics);
if (resolvedMethod.getAccessFlags().isVisibilityDependingOnPackage()) {
consumer.acceptPackage(