Use monomorphic state for abstract methods with single implementation
Change-Id: If284f39a90d1577f8def96f7f54c7919af64cdfd
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
index 8fe8d8c..a61d0b4 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorCodeScanner.java
@@ -121,11 +121,15 @@
}
boolean isMonomorphicVirtualMethod(ProgramMethod method) {
- boolean isMonomorphicVirtualMethod = monomorphicVirtualMethods.contains(method.getReference());
+ boolean isMonomorphicVirtualMethod = isMonomorphicVirtualMethod(method.getReference());
assert method.getDefinition().belongsToVirtualPool() || !isMonomorphicVirtualMethod;
return isMonomorphicVirtualMethod;
}
+ boolean isMonomorphicVirtualMethod(DexMethod method) {
+ return monomorphicVirtualMethods.contains(method);
+ }
+
void scan(ProgramMethod method, IRCode code, Timing timing) {
timing.begin("Argument propagation scanner");
for (Invoke invoke : code.<Invoke>instructions(Instruction::isInvoke)) {
@@ -218,14 +222,11 @@
// possible dispatch targets and propagate the information to these methods (this is expensive).
// Instead we record the information in one place and then later propagate the information to
// all dispatch targets.
- DexMethod representativeMethodReference =
- getRepresentativeForPolymorphicInvokeOrElse(
- invoke, resolvedMethod, resolvedMethod.getReference());
ProgramMethod finalResolvedMethod = resolvedMethod;
timing.begin("Add method state");
methodStates.addTemporaryMethodState(
appView,
- representativeMethodReference,
+ getRepresentative(invoke, resolvedMethod),
existingMethodState ->
computeMethodState(invoke, finalResolvedMethod, context, existingMethodState, timing),
timing);
@@ -245,10 +246,8 @@
// compute a polymorphic method state, which includes information about the receiver's dynamic
// type bounds.
timing.begin("Compute method state for invoke");
- boolean isPolymorphicInvoke =
- getRepresentativeForPolymorphicInvokeOrElse(invoke, resolvedMethod, null) != null;
MethodState result;
- if (isPolymorphicInvoke) {
+ if (shouldUsePolymorphicMethodState(invoke, resolvedMethod)) {
assert existingMethodState.isBottom() || existingMethodState.isPolymorphic();
result =
computePolymorphicMethodState(
@@ -485,10 +484,9 @@
: new ConcretePrimitiveTypeParameterState(abstractValue);
}
- private DexMethod getRepresentativeForPolymorphicInvokeOrElse(
- InvokeMethod invoke, ProgramMethod resolvedMethod, DexMethod defaultValue) {
+ private DexMethod getRepresentative(InvokeMethod invoke, ProgramMethod resolvedMethod) {
if (resolvedMethod.getDefinition().belongsToDirectPool()) {
- return defaultValue;
+ return resolvedMethod.getReference();
}
if (invoke.isInvokeInterface()) {
@@ -499,14 +497,22 @@
assert invoke.isInvokeSuper() || invoke.isInvokeVirtual();
if (isMonomorphicVirtualMethod(resolvedMethod)) {
- return defaultValue;
+ return resolvedMethod.getReference();
}
DexMethod rootMethod = getVirtualRootMethod(resolvedMethod);
assert rootMethod != null;
+ assert !isMonomorphicVirtualMethod(resolvedMethod)
+ || rootMethod == resolvedMethod.getReference();
return rootMethod;
}
+ private boolean shouldUsePolymorphicMethodState(
+ InvokeMethod invoke, ProgramMethod resolvedMethod) {
+ return !resolvedMethod.getDefinition().belongsToDirectPool()
+ && !isMonomorphicVirtualMethod(getRepresentative(invoke, resolvedMethod));
+ }
+
private void scan(InvokeCustom invoke, ProgramMethod context) {
// If the bootstrap method is program declared it will be called. The call is with runtime
// provided arguments so ensure that the argument information is unknown.
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysis.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysis.java
index 5d5399d..75bcbba 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/VirtualRootMethodsAnalysis.java
@@ -45,6 +45,22 @@
return root;
}
+ ProgramMethod getSingleNonAbstractMethod() {
+ ProgramMethod singleNonAbstractMethod = root.getAccessFlags().isAbstract() ? null : root;
+ for (ProgramMethod override : overrides) {
+ if (!override.getAccessFlags().isAbstract()) {
+ if (singleNonAbstractMethod != null) {
+ // Not a single non-abstract method.
+ return null;
+ }
+ singleNonAbstractMethod = override;
+ }
+ }
+ assert singleNonAbstractMethod == null
+ || !singleNonAbstractMethod.getAccessFlags().isAbstract();
+ return singleNonAbstractMethod;
+ }
+
void forEach(Consumer<ProgramMethod> consumer) {
consumer.accept(root);
overrides.forEach(consumer);
@@ -125,9 +141,20 @@
if (isMonomorphicVirtualMethod) {
monomorphicVirtualMethods.add(rootCandidate.getReference());
} else {
- virtualRootMethod.forEach(
- method ->
- virtualRootMethods.put(method.getReference(), rootCandidate.getReference()));
+ ProgramMethod singleNonAbstractMethod = virtualRootMethod.getSingleNonAbstractMethod();
+ if (singleNonAbstractMethod != null) {
+ virtualRootMethod.forEach(
+ method ->
+ virtualRootMethods.put(
+ method.getReference(), singleNonAbstractMethod.getReference()));
+ if (!singleNonAbstractMethod.getHolder().isInterface()) {
+ monomorphicVirtualMethods.add(singleNonAbstractMethod.getReference());
+ }
+ } else {
+ virtualRootMethod.forEach(
+ method ->
+ virtualRootMethods.put(method.getReference(), rootCandidate.getReference()));
+ }
}
});
}