Introduce a new main resolveMethod function.
This CL also introduces resolve variants for known defintions and rewrites such
call sites.
Change-Id: Ie6627e6e12c0a58828c26aa05f0fc4ab6871691f
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 7e83700..648efbe 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -245,12 +245,12 @@
/**
* Implements resolution of a method descriptor against a target type.
- * <p>
- * This method will query the definition of the holder to decide on which resolution to use. If
+ *
+ * <p>This method will query the definition of the holder to decide on which resolution to use. If
* the holder is an interface, it delegates to {@link #resolveMethodOnInterface(DexType,
* DexMethod)}, otherwise {@link #resolveMethodOnClass(DexType, DexMethod)} is used.
- * <p>
- * This is to overcome the shortcoming of the DEX file format that does not allow to encode the
+ *
+ * <p>This is to overcome the shortcoming of the DEX file format that does not allow to encode the
* kind of a method reference.
*/
public ResolutionResult resolveMethod(DexType holder, DexMethod method) {
@@ -263,18 +263,36 @@
return ResolutionResult.EmptyResult.get();
}
return definition.isInterface()
+ ? resolveMethodOnInterface(definition, method)
+ : resolveMethodOnClass(definition, method);
+ }
+
+ /**
+ * Implements resolution of a method descriptor against a target type.
+ *
+ * <p>The boolean isInterface parameter denotes if the method reference is an interface method
+ * reference, and if so method resolution is done according to interface method resolution.
+ *
+ * @param holder Type at which to initiate the resolution.
+ * @param method Method descriptor for resolution (the field method.holder is ignored).
+ * @param isInterface Indicates if resolution is to be done according to class or interface.
+ * @return The result of resolution.
+ */
+ public ResolutionResult resolveMethod(DexType holder, DexMethod method, boolean isInterface) {
+ assert checkIfObsolete();
+ return isInterface
? resolveMethodOnInterface(holder, method)
: resolveMethodOnClass(holder, method);
}
/**
* Implements resolution of a method descriptor against an array type.
- * <p>See <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.7">
- * Section 10.7 of the Java Language Specification</a>.
- * </p>
- * All invokations will have target java.lang.Object except clone which has no target.
+ *
+ * <p>See <a href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html#jls-10.7">Section
+ * 10.7 of the Java Language Specification</a>. All invokations will have target java.lang.Object
+ * except clone which has no target.
*/
- public ResolutionResult resolveMethodOnArray(DexType holder, DexMethod method) {
+ private ResolutionResult resolveMethodOnArray(DexType holder, DexMethod method) {
assert checkIfObsolete();
assert holder.isArrayType();
if (method.name == dexItemFactory.cloneMethodName) {
@@ -305,6 +323,12 @@
if (clazz == null || clazz.isInterface()) {
return ResolutionResult.EmptyResult.get();
}
+ return resolveMethodOnClass(clazz, method);
+ }
+
+ public ResolutionResult resolveMethodOnClass(DexClass clazz, DexMethod method) {
+ assert checkIfObsolete();
+ assert !clazz.isInterface();
// Step 2:
DexEncodedMethod singleTarget = resolveMethodOnClassStep2(clazz, method);
if (singleTarget != null) {
@@ -425,6 +449,9 @@
*/
public ResolutionResult resolveMethodOnInterface(DexType holder, DexMethod desc) {
assert checkIfObsolete();
+ if (holder.isArrayType()) {
+ return ResolutionResult.EmptyResult.get();
+ }
// Step 1: Lookup interface.
DexClass definition = definitionFor(holder);
// If the definition is not an interface, resolution fails with an ICCE. We just return the
@@ -432,6 +459,12 @@
if (definition == null || !definition.isInterface()) {
return ResolutionResult.EmptyResult.get();
}
+ return resolveMethodOnInterface(definition, desc);
+ }
+
+ public ResolutionResult resolveMethodOnInterface(DexClass definition, DexMethod desc) {
+ assert checkIfObsolete();
+ assert definition.isInterface();
// Step 2: Look for exact method on interface.
DexEncodedMethod result = definition.lookupMethod(desc);
if (result != null) {
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index 23bcc18..4aeae4e 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -33,7 +33,7 @@
for (DexType type : appInfo.subtypes(method.holder)) {
DexClass clazz = appInfo.definitionFor(type);
if (!clazz.isInterface()) {
- ResolutionResult methods = appInfo.resolveMethodOnClass(type, method);
+ ResolutionResult methods = appInfo.resolveMethodOnClass(clazz, method);
methods.forEachTarget(
target -> {
if (target.isVirtualMethod()) {
@@ -102,10 +102,10 @@
for (DexType type : set) {
DexClass clazz = appInfo.definitionFor(type);
if (clazz.isInterface()) {
- ResolutionResult targetMethods = appInfo.resolveMethodOnInterface(type, method);
+ ResolutionResult targetMethods = appInfo.resolveMethodOnInterface(clazz, method);
targetMethods.forEachTarget(addIfNotAbstractAndBridge);
} else {
- ResolutionResult targetMethods = appInfo.resolveMethodOnClass(type, method);
+ ResolutionResult targetMethods = appInfo.resolveMethodOnClass(clazz, method);
targetMethods.forEachTarget(addIfNotAbstract);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
index 9a68feb..2322b7b 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilder.java
@@ -184,19 +184,17 @@
}
}
+ boolean isInterface = type == Type.INTERFACE;
Set<DexEncodedMethod> possibleTargets =
possibleTargetsCache.computeIfAbsent(
target,
- method ->
- type == Type.INTERFACE
- ? appView
- .appInfo()
- .resolveMethodOnInterface(method.holder, method)
- .lookupInterfaceTargets(appView.appInfo())
- : appView
- .appInfo()
- .resolveMethodOnClass(method.holder, method)
- .lookupVirtualTargets(appView.appInfo()));
+ method -> {
+ ResolutionResult resolution =
+ appView.appInfo().resolveMethod(method.holder, method, isInterface);
+ return isInterface
+ ? resolution.lookupInterfaceTargets(appView.appInfo())
+ : resolution.lookupVirtualTargets(appView.appInfo());
+ });
if (possibleTargets != null) {
boolean likelySpuriousCallEdge =
possibleTargets.size() >= appView.options().callGraphLikelySpuriousCallEdgeThreshold;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 5a18e61..ee9d779 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -1477,11 +1477,11 @@
private boolean hasNonTrivialFinalizeMethod(DexType type) {
DexClass clazz = appView.definitionFor(type);
if (clazz != null) {
- if (clazz.isProgramClass()) {
+ if (clazz.isProgramClass() && !clazz.isInterface()) {
ResolutionResult resolutionResult =
appView
.appInfo()
- .resolveMethodOnClass(type, appView.dexItemFactory().objectMethods.finalize);
+ .resolveMethodOnClass(clazz, appView.dexItemFactory().objectMethods.finalize);
for (DexEncodedMethod target : resolutionResult.asListOfTargets()) {
if (target.method != appView.dexItemFactory().objectMethods.finalize) {
return true;
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index dd955ed..03978ed 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -1019,7 +1019,7 @@
}
// First check that there is a target for this invoke-interface to hit. If there is none,
// this will fail at runtime.
- ResolutionResult topTarget = resolveMethodOnInterface(method.holder, method);
+ ResolutionResult topTarget = resolveMethodOnInterface(holder, method);
if (topTarget.asResultOfResolve() == null) {
return null;
}
@@ -1049,7 +1049,7 @@
// override them, so we ignore interface methods here. Otherwise, we would look up
// default methods that are factually never used.
} else if (!clazz.accessFlags.isAbstract()) {
- ResolutionResult resolutionResult = resolveMethodOnClass(type, method);
+ ResolutionResult resolutionResult = resolveMethodOnClass(clazz, method);
if (resolutionResult.hasSingleTarget()) {
if ((result != null) && (result != resolutionResult.asSingleTarget())) {
return null;
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 2c6d4e5..2bf674b 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1716,9 +1716,7 @@
private DexEncodedMethod findAndMarkResolutionTarget(
DexMethod method, boolean interfaceInvoke, KeepReason reason) {
DexEncodedMethod resolutionTarget =
- interfaceInvoke
- ? appInfo.resolveMethodOnInterface(method.holder, method).asResultOfResolve()
- : appInfo.resolveMethodOnClass(method.holder, method).asResultOfResolve();
+ appInfo.resolveMethod(method.holder, method, interfaceInvoke).asResultOfResolve();
if (resolutionTarget == null) {
reportMissingMethod(method);
return null;
@@ -1760,9 +1758,9 @@
DexClass resolutionTargetClass) {
while (resolutionTarget.isPrivateMethod() || resolutionTarget.isStatic()) {
resolutionTarget =
- (resolutionTargetClass.isInterface()
- ? appInfo.resolveMethodOnInterface(resolutionTargetClass.superType, method)
- : appInfo.resolveMethodOnClass(resolutionTargetClass.superType, method))
+ appInfo
+ .resolveMethod(
+ resolutionTargetClass.superType, method, resolutionTargetClass.isInterface())
.asResultOfResolve();
if (resolutionTarget == null) {
return;
diff --git a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
index e9e836b..c2a5c6a 100644
--- a/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
+++ b/src/test/java/com/android/tools/r8/internal/R8GMSCoreLookupTest.java
@@ -60,17 +60,13 @@
// Check lookup targets with include method.
Set<DexEncodedMethod> targets =
- appInfo
- .resolveMethodOnClass(method.method.holder, method.method)
- .lookupVirtualTargets(appInfo);
+ appInfo.resolveMethodOnClass(clazz, method.method).lookupVirtualTargets(appInfo);
assertTrue(targets.contains(method));
}
private void testInterfaceLookup(DexProgramClass clazz, DexEncodedMethod method) {
Set<DexEncodedMethod> targets =
- appInfo
- .resolveMethodOnInterface(method.method.holder, method.method)
- .lookupInterfaceTargets(appInfo);
+ appInfo.resolveMethodOnInterface(clazz, method.method).lookupInterfaceTargets(appInfo);
if (appInfo.subtypes(method.method.holder).stream()
.allMatch(t -> appInfo.definitionFor(t).isInterface())) {
assertEquals(