Ensure all methods in method access info collection resolve
Change-Id: Ia29424888766c0ed626dada49b0258c6515d35a9
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 3e0bc95..532abbd 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -1099,6 +1099,17 @@
@Override
public void onJoin() {
appView.withClassHierarchy().setAppInfo(result);
+ assert verifyLensRewriting();
+ }
+
+ private boolean verifyLensRewriting() {
+ if (appView.hasLiveness()) {
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ MethodAccessInfoCollection methodAccessInfoCollection =
+ appViewWithLiveness.appInfo().getMethodAccessInfoCollection();
+ methodAccessInfoCollection.modifier().commit(appViewWithLiveness);
+ }
+ return true;
}
},
new ThreadTask() {
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 2671841..542a558 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodAccessInfoCollection.java
@@ -9,6 +9,8 @@
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.lens.MethodLookupResult;
import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
@@ -347,6 +349,54 @@
invokes.keySet().removeIf(predicate);
}
+ public void removeNonResolving(
+ AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
+ // TODO(b/313365881): Should use non-legacy resolution, but this fails.
+ removeIf(
+ method -> {
+ MethodResolutionResult result =
+ appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(method);
+ if (result.isFailedResolution()
+ || result.isSignaturePolymorphicResolution(method, appView.dexItemFactory())) {
+ return true;
+ }
+ if (result.hasProgramResult()) {
+ ProgramMethod resolvedMethod = result.getResolvedProgramMethod();
+ // Guard against an unusual case where the invoke resolves to a program method but the
+ // invoke is invalid (e.g., invoke-interface to a non-interface), such that the
+ // resolved method is not retained after all.
+ if (!enqueuer.isMethodLive(resolvedMethod)
+ && !enqueuer.isMethodTargeted(resolvedMethod)) {
+ return true;
+ }
+ }
+ return false;
+ });
+ }
+
+ public boolean verifyNoNonResolving(AppView<AppInfoWithLiveness> appView) {
+ verifyNoNonResolving(appView, directInvokes);
+ verifyNoNonResolving(appView, interfaceInvokes);
+ verifyNoNonResolving(appView, staticInvokes);
+ verifyNoNonResolving(appView, superInvokes);
+ verifyNoNonResolving(appView, virtualInvokes);
+ return true;
+ }
+
+ private void verifyNoNonResolving(
+ AppView<AppInfoWithLiveness> appView, Map<DexMethod, ?> invokes) {
+ if (!isThrowingMap(invokes)) {
+ for (DexMethod method : invokes.keySet()) {
+ MethodResolutionResult result =
+ appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(method);
+ assert !result.isFailedResolution()
+ : "Unexpected method that does not resolve: " + method.toSourceString();
+ assert !result.isSignaturePolymorphicResolution(method, appView.dexItemFactory())
+ : "Unexpected signature polymorphic resolution: " + method.toSourceString();
+ }
+ }
+ }
+
public MethodAccessInfoCollection build() {
return new MethodAccessInfoCollection(
directInvokes, interfaceInvokes, staticInvokes, superInvokes, virtualInvokes);
@@ -387,5 +437,9 @@
collection.forEachSuperInvoke(this::registerInvokeSuperInContexts);
collection.forEachVirtualInvoke(this::registerInvokeVirtualInContexts);
}
+
+ public void commit(AppView<AppInfoWithLiveness> appView) {
+ assert verifyNoNonResolving(appView);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
index b0292c6..d0f23ae 100644
--- a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
@@ -36,6 +36,7 @@
import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.android.tools.r8.verticalclassmerging.VerticalClassMergerGraphLens;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -458,6 +459,10 @@
return false;
}
+ public VerticalClassMergerGraphLens asVerticalClassMergerLens() {
+ return null;
+ }
+
@SuppressWarnings("ReferenceEquality")
public boolean assertFieldsNotModified(Iterable<DexEncodedField> fields) {
for (DexEncodedField field : fields) {
diff --git a/src/main/java/com/android/tools/r8/graph/lens/GraphLensUtils.java b/src/main/java/com/android/tools/r8/graph/lens/GraphLensUtils.java
new file mode 100644
index 0000000..b7175d3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/lens/GraphLensUtils.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2023, 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.graph.lens;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+
+public class GraphLensUtils {
+
+ public static Deque<NonIdentityGraphLens> extractNonIdentityLenses(GraphLens lens) {
+ Deque<NonIdentityGraphLens> lenses = new ArrayDeque<>();
+ if (lens.isNonIdentityLens()) {
+ lenses.addFirst(lens.asNonIdentityLens());
+ while (true) {
+ GraphLens previous = lenses.getFirst().getPrevious();
+ if (previous.isNonIdentityLens()) {
+ lenses.addFirst(previous.asNonIdentityLens());
+ } else {
+ break;
+ }
+ }
+ }
+ return lenses;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
index 234b353..0ea0a9a 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingIdentityLens.java
@@ -15,8 +15,10 @@
import com.android.tools.r8.graph.lens.DefaultNonIdentityGraphLens;
import com.android.tools.r8.graph.lens.FieldLookupResult;
import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.GraphLensUtils;
import com.android.tools.r8.graph.lens.MethodLookupResult;
import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
+import java.util.Deque;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -134,10 +136,25 @@
rewrittenNonReboundFieldReference, rewrittenReboundFieldReference);
}
});
+
+ Deque<NonIdentityGraphLens> lenses = GraphLensUtils.extractNonIdentityLenses(lens);
nonReboundMethodReferenceToDefinitionMap.forEach(
(nonReboundMethodReference, reboundMethodReference) -> {
- DexMethod rewrittenReboundMethodReference =
- lens.getRenamedMethodSignature(reboundMethodReference, appliedMemberRebindingLens);
+ DexMethod rewrittenReboundMethodReference = reboundMethodReference;
+ for (NonIdentityGraphLens currentLens : lenses) {
+ if (currentLens.isVerticalClassMergerLens()) {
+ // The vertical class merger lens maps merged virtual methods to private methods in
+ // the subclass. Invokes to such virtual methods are mapped to the corresponding
+ // virtual method in the subclass.
+ rewrittenReboundMethodReference =
+ currentLens
+ .asVerticalClassMergerLens()
+ .getNextBridgeMethodSignature(rewrittenReboundMethodReference);
+ } else {
+ rewrittenReboundMethodReference =
+ currentLens.getNextMethodSignature(rewrittenReboundMethodReference);
+ }
+ }
DexMethod rewrittenNonReboundMethodReference =
rewrittenReboundMethodReference.withHolder(
lens.lookupType(
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
index 5a8e0de..4b4b611 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoisting.java
@@ -114,6 +114,7 @@
assert false;
}
});
+ methodAccessInfoCollectionModifier.commit(appView);
}
}
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 b4f643a..4cdfc22 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -4257,13 +4257,7 @@
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());
- });
+ methodAccessInfoCollection.removeNonResolving(appView, this);
// Verify all references on the input app before synthesizing definitions.
assert verifyReferences(appInfo.app());
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
index 08ca4be..ad653bd 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
@@ -108,6 +108,11 @@
}
@Override
+ public VerticalClassMergerGraphLens asVerticalClassMergerLens() {
+ return this;
+ }
+
+ @Override
public DexType getPreviousClassType(DexType type) {
return type;
}