Avoid computing parameter states when already unknown
Change-Id: I42ad7d6c7b5b498fda257e5a551318be8489d18a
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 b80f03b..de55357 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
@@ -29,8 +29,10 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteArrayTypeParameterState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteClassTypeParameterState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodState;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodStateOrBottom;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodStateOrUnknown;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcretePolymorphicMethodState;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcretePolymorphicMethodStateOrBottom;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcretePrimitiveTypeParameterState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteReceiverParameterState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
@@ -193,13 +195,20 @@
methodStates.addTemporaryMethodState(
appView,
representativeMethodReference,
- () -> computeMethodState(invoke, finalResolvedMethod, context, timing),
+ existingMethodState ->
+ computeMethodState(invoke, finalResolvedMethod, context, existingMethodState, timing),
timing);
timing.end();
}
private MethodState computeMethodState(
- InvokeMethod invoke, ProgramMethod resolvedMethod, ProgramMethod context, Timing timing) {
+ InvokeMethod invoke,
+ ProgramMethod resolvedMethod,
+ ProgramMethod context,
+ MethodState existingMethodState,
+ Timing timing) {
+ assert !existingMethodState.isUnknown();
+
// If this invoke may target at most one method, then we compute a state that maps each
// parameter to the abstract value and dynamic type provided by this call site. Otherwise, we
// compute a polymorphic method state, which includes information about the receiver's dynamic
@@ -207,11 +216,21 @@
timing.begin("Compute method state for invoke");
boolean isPolymorphicInvoke =
getRepresentativeForPolymorphicInvokeOrElse(invoke, resolvedMethod, null) != null;
- MethodState result =
- isPolymorphicInvoke
- ? computePolymorphicMethodState(
- invoke.asInvokeMethodWithReceiver(), resolvedMethod, context)
- : computeMonomorphicMethodState(invoke, context);
+ MethodState result;
+ if (isPolymorphicInvoke) {
+ assert existingMethodState.isBottom() || existingMethodState.isPolymorphic();
+ result =
+ computePolymorphicMethodState(
+ invoke.asInvokeMethodWithReceiver(),
+ resolvedMethod,
+ context,
+ existingMethodState.asPolymorphicOrBottom());
+ } else {
+ assert existingMethodState.isBottom() || existingMethodState.isMonomorphic();
+ result =
+ computeMonomorphicMethodState(
+ invoke, context, existingMethodState.asMonomorphicOrBottom());
+ }
timing.end();
return result;
}
@@ -220,40 +239,65 @@
// experimenting with the performance/size trade-off between precise/imprecise handling of
// dynamic dispatch.
private MethodState computePolymorphicMethodState(
- InvokeMethodWithReceiver invoke, ProgramMethod resolvedMethod, ProgramMethod context) {
+ InvokeMethodWithReceiver invoke,
+ ProgramMethod resolvedMethod,
+ ProgramMethod context,
+ ConcretePolymorphicMethodStateOrBottom existingMethodState) {
DynamicType dynamicReceiverType = invoke.getReceiver().getDynamicType(appView);
assert !dynamicReceiverType.getDynamicUpperBoundType().nullability().isDefinitelyNull();
- if (invoke.isInvokeSuper()) {
- ClassTypeElement exactClassType =
- resolvedMethod.getHolderType().toTypeElement(appView).asClassType();
- DynamicType exactType = DynamicType.create(appView, exactClassType, exactClassType);
- return new ConcretePolymorphicMethodState(
- exactType, computeMonomorphicMethodState(invoke, context));
+ DynamicType bounds =
+ invoke.isInvokeSuper()
+ ? DynamicType.createExact(
+ resolvedMethod.getHolderType().toTypeElement(appView).asClassType())
+ : dynamicReceiverType;
+
+ MethodState existingMethodStateForBounds =
+ existingMethodState.isPolymorphic()
+ ? existingMethodState.asPolymorphic().getMethodStateForBounds(bounds)
+ : MethodState.bottom();
+
+ if (existingMethodStateForBounds.isPolymorphic()) {
+ assert false;
+ return MethodState.unknown();
}
- ConcretePolymorphicMethodState methodState =
- new ConcretePolymorphicMethodState(
- dynamicReceiverType,
- computeMonomorphicMethodState(invoke, context, dynamicReceiverType));
+ // If we already don't know anything about the parameters for the given type bounds, then don't
+ // compute a method state.
+ if (existingMethodStateForBounds.isUnknown()) {
+ return MethodState.unknown();
+ }
+
// TODO(b/190154391): If the receiver type is effectively unknown, and the computed monomorphic
// method state is also unknown (i.e., we have "unknown receiver type" -> "unknown method
// state"), then return the canonicalized UnknownMethodState instance instead.
- return methodState;
+ return new ConcretePolymorphicMethodState(
+ bounds,
+ computeMonomorphicMethodState(
+ invoke,
+ context,
+ existingMethodStateForBounds.asMonomorphicOrBottom(),
+ dynamicReceiverType));
}
private ConcreteMonomorphicMethodStateOrUnknown computeMonomorphicMethodState(
- InvokeMethod invoke, ProgramMethod context) {
+ InvokeMethod invoke,
+ ProgramMethod context,
+ ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
return computeMonomorphicMethodState(
invoke,
context,
+ existingMethodState,
invoke.isInvokeMethodWithReceiver()
? invoke.getFirstArgument().getDynamicType(appView)
: null);
}
private ConcreteMonomorphicMethodStateOrUnknown computeMonomorphicMethodState(
- InvokeMethod invoke, ProgramMethod context, DynamicType dynamicReceiverType) {
+ InvokeMethod invoke,
+ ProgramMethod context,
+ ConcreteMonomorphicMethodStateOrBottom existingMethodState,
+ DynamicType dynamicReceiverType) {
List<ParameterState> parameterStates = new ArrayList<>(invoke.arguments().size());
int argumentIndex = 0;
@@ -261,14 +305,18 @@
assert dynamicReceiverType != null;
parameterStates.add(
computeParameterStateForReceiver(
- invoke.asInvokeMethodWithReceiver(), dynamicReceiverType));
+ invoke.asInvokeMethodWithReceiver(), dynamicReceiverType, existingMethodState));
argumentIndex++;
}
for (; argumentIndex < invoke.arguments().size(); argumentIndex++) {
parameterStates.add(
computeParameterStateForNonReceiver(
- invoke, argumentIndex, invoke.getArgument(argumentIndex), context));
+ invoke,
+ argumentIndex,
+ invoke.getArgument(argumentIndex),
+ context,
+ existingMethodState));
}
// If all parameter states are unknown, then return a canonicalized unknown method state that
@@ -285,7 +333,15 @@
// TODO(b/190154391): Consider validating the above hypothesis by using
// computeParameterStateForNonReceiver() for receivers.
private ParameterState computeParameterStateForReceiver(
- InvokeMethodWithReceiver invoke, DynamicType dynamicReceiverType) {
+ InvokeMethodWithReceiver invoke,
+ DynamicType dynamicReceiverType,
+ ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
+ // Don't compute a state for this parameter if the stored state is already unknown.
+ if (existingMethodState.isMonomorphic()
+ && existingMethodState.asMonomorphic().getParameterState(0).isUnknown()) {
+ return ParameterState.unknown();
+ }
+
ClassTypeElement staticReceiverType =
invoke
.getInvokedMethod()
@@ -299,7 +355,17 @@
}
private ParameterState computeParameterStateForNonReceiver(
- InvokeMethod invoke, int argumentIndex, Value argument, ProgramMethod context) {
+ InvokeMethod invoke,
+ int argumentIndex,
+ Value argument,
+ ProgramMethod context,
+ ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
+ // Don't compute a state for this parameter if the stored state is already unknown.
+ if (existingMethodState.isMonomorphic()
+ && existingMethodState.asMonomorphic().getParameterState(argumentIndex).isUnknown()) {
+ return ParameterState.unknown();
+ }
+
Value argumentRoot = argument.getAliasedValue(aliasedValueConfiguration);
TypeElement parameterType =
invoke
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/BottomMethodState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/BottomMethodState.java
index 2bd69e9..4487eea 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/BottomMethodState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/BottomMethodState.java
@@ -6,9 +6,10 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.function.Supplier;
+import java.util.function.Function;
-public class BottomMethodState extends MethodStateBase {
+public class BottomMethodState extends MethodStateBase
+ implements ConcreteMonomorphicMethodStateOrBottom, ConcretePolymorphicMethodStateOrBottom {
private static final BottomMethodState INSTANCE = new BottomMethodState();
@@ -24,6 +25,16 @@
}
@Override
+ public ConcreteMonomorphicMethodStateOrBottom asMonomorphicOrBottom() {
+ return this;
+ }
+
+ @Override
+ public ConcretePolymorphicMethodStateOrBottom asPolymorphicOrBottom() {
+ return this;
+ }
+
+ @Override
public MethodState mutableCopy() {
return this;
}
@@ -35,7 +46,8 @@
@Override
public MethodState mutableJoin(
- AppView<AppInfoWithLiveness> appView, Supplier<MethodState> methodStateSupplier) {
- return mutableJoin(appView, methodStateSupplier.get());
+ AppView<AppInfoWithLiveness> appView,
+ Function<MethodState, MethodState> methodStateSupplier) {
+ return mutableJoin(appView, methodStateSupplier.apply(this));
}
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMethodState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMethodState.java
index a4d7070..bfb7a89 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMethodState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMethodState.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.function.Supplier;
+import java.util.function.Function;
public abstract class ConcreteMethodState extends MethodStateBase {
@@ -33,8 +33,9 @@
@Override
public MethodState mutableJoin(
- AppView<AppInfoWithLiveness> appView, Supplier<MethodState> methodStateSupplier) {
- return mutableJoin(appView, methodStateSupplier.get());
+ AppView<AppInfoWithLiveness> appView,
+ Function<MethodState, MethodState> methodStateSupplier) {
+ return mutableJoin(appView, methodStateSupplier.apply(this));
}
private MethodState mutableJoin(
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodState.java
index 0998c52..908d97d 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodState.java
@@ -12,7 +12,7 @@
import java.util.List;
public class ConcreteMonomorphicMethodState extends ConcreteMethodState
- implements ConcreteMonomorphicMethodStateOrUnknown {
+ implements ConcreteMonomorphicMethodStateOrBottom, ConcreteMonomorphicMethodStateOrUnknown {
List<ParameterState> parameterStates;
@@ -73,6 +73,11 @@
return this;
}
+ @Override
+ public ConcreteMonomorphicMethodStateOrBottom asMonomorphicOrBottom() {
+ return this;
+ }
+
public void setParameterState(int index, ParameterState parameterState) {
assert index == 0
|| !parameterState.isConcrete()
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodStateOrBottom.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodStateOrBottom.java
new file mode 100644
index 0000000..9528fd7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteMonomorphicMethodStateOrBottom.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, 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.optimize.argumentpropagation.codescanner;
+
+public interface ConcreteMonomorphicMethodStateOrBottom extends MethodState {}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePolymorphicMethodState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePolymorphicMethodState.java
index 9aa8957..5b3b61e 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePolymorphicMethodState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePolymorphicMethodState.java
@@ -12,7 +12,8 @@
import java.util.function.BiConsumer;
import java.util.function.Function;
-public class ConcretePolymorphicMethodState extends ConcreteMethodState {
+public class ConcretePolymorphicMethodState extends ConcreteMethodState
+ implements ConcretePolymorphicMethodStateOrBottom {
private final Map<DynamicType, ConcreteMonomorphicMethodStateOrUnknown> receiverBoundsToState =
new HashMap<>();
@@ -54,6 +55,15 @@
receiverBoundsToState.forEach(consumer);
}
+ public MethodState getMethodStateForBounds(DynamicType dynamicType) {
+ ConcreteMonomorphicMethodStateOrUnknown methodStateForBounds =
+ receiverBoundsToState.get(dynamicType);
+ if (methodStateForBounds != null) {
+ return methodStateForBounds;
+ }
+ return MethodState.bottom();
+ }
+
public boolean isEmpty() {
return receiverBoundsToState.isEmpty();
}
@@ -99,4 +109,9 @@
public ConcretePolymorphicMethodState asPolymorphic() {
return this;
}
+
+ @Override
+ public ConcretePolymorphicMethodStateOrBottom asPolymorphicOrBottom() {
+ return this;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePolymorphicMethodStateOrBottom.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePolymorphicMethodStateOrBottom.java
new file mode 100644
index 0000000..6577c0e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePolymorphicMethodStateOrBottom.java
@@ -0,0 +1,7 @@
+// Copyright (c) 2021, 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.optimize.argumentpropagation.codescanner;
+
+public interface ConcretePolymorphicMethodStateOrBottom extends MethodState {}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodState.java
index 15bd5cd..97124a8 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodState.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.function.Supplier;
+import java.util.function.Function;
public interface MethodState {
@@ -28,10 +28,14 @@
ConcreteMonomorphicMethodState asMonomorphic();
+ ConcreteMonomorphicMethodStateOrBottom asMonomorphicOrBottom();
+
boolean isPolymorphic();
ConcretePolymorphicMethodState asPolymorphic();
+ ConcretePolymorphicMethodStateOrBottom asPolymorphicOrBottom();
+
boolean isUnknown();
MethodState mutableCopy();
@@ -39,5 +43,5 @@
MethodState mutableJoin(AppView<AppInfoWithLiveness> appView, MethodState methodState);
MethodState mutableJoin(
- AppView<AppInfoWithLiveness> appView, Supplier<MethodState> methodStateSupplier);
+ AppView<AppInfoWithLiveness> appView, Function<MethodState, MethodState> methodStateSupplier);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodStateBase.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodStateBase.java
index 4bdf867..1b1800d 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodStateBase.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodStateBase.java
@@ -40,6 +40,11 @@
}
@Override
+ public ConcreteMonomorphicMethodStateOrBottom asMonomorphicOrBottom() {
+ return null;
+ }
+
+ @Override
public boolean isPolymorphic() {
return false;
}
@@ -50,6 +55,11 @@
}
@Override
+ public ConcretePolymorphicMethodStateOrBottom asPolymorphicOrBottom() {
+ return null;
+ }
+
+ @Override
public boolean isUnknown() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodStateCollection.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodStateCollection.java
index ea8fcd8..cbc73da 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodStateCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodStateCollection.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.utils.Timing;
import java.util.Map;
import java.util.function.BiConsumer;
+import java.util.function.Function;
import java.util.function.Supplier;
abstract class MethodStateCollection<K> {
@@ -55,13 +56,13 @@
public void addTemporaryMethodState(
AppView<AppInfoWithLiveness> appView,
K method,
- Supplier<MethodState> methodStateSupplier,
+ Function<MethodState, MethodState> methodStateSupplier,
Timing timing) {
methodStates.compute(
method,
(ignore, existingMethodState) -> {
if (existingMethodState == null) {
- MethodState newMethodState = methodStateSupplier.get();
+ MethodState newMethodState = methodStateSupplier.apply(MethodState.bottom());
assert !newMethodState.isBottom();
return newMethodState;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownMethodState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownMethodState.java
index 0241446..20ab101 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownMethodState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownMethodState.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.function.Supplier;
+import java.util.function.Function;
// Use this when the nothing is known.
public class UnknownMethodState extends MethodStateBase
@@ -37,7 +37,8 @@
@Override
public MethodState mutableJoin(
- AppView<AppInfoWithLiveness> appView, Supplier<MethodState> methodStateSupplier) {
+ AppView<AppInfoWithLiveness> appView,
+ Function<MethodState, MethodState> methodStateSupplier) {
return this;
}
}