Widen dynamic types to unknown when they are not useful
Change-Id: I3cc64c92febb26a60f75d09de07b7f13ea1f95b8
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 a165209..77c7af7 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
@@ -94,6 +94,7 @@
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.IdentifierNameStringMarker;
+import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.LibraryMethodOverrideAnalysis;
@@ -835,6 +836,7 @@
if (options.enableFieldAssignmentTracker) {
fieldAccessAnalysis.fieldAssignmentTracker().waveDone(wave, delayedOptimizationFeedback);
}
+ appView.withArgumentPropagator(ArgumentPropagator::publishDelayedReprocessingCriteria);
if (appView.options().protoShrinking().enableRemoveProtoEnumSwitchMap()) {
appView.protoShrinker().protoEnumSwitchMapRemover.updateVisibleStaticFieldValues();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
index cabc28f..645bac0 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagator.java
@@ -67,8 +67,8 @@
timing.begin("Argument propagator");
timing.begin("Initialize code scanner");
- codeScanner = new ArgumentPropagatorCodeScanner(appView);
reprocessingCriteriaCollection = new ArgumentPropagatorReprocessingCriteriaCollection(appView);
+ codeScanner = new ArgumentPropagatorCodeScanner(appView, reprocessingCriteriaCollection);
ImmediateProgramSubtypingInfo immediateSubtypingInfo =
ImmediateProgramSubtypingInfo.create(appView);
@@ -110,6 +110,11 @@
}
}
+ public void publishDelayedReprocessingCriteria() {
+ assert reprocessingCriteriaCollection != null;
+ reprocessingCriteriaCollection.publishDelayedReprocessingCriteria();
+ }
+
public void transferArgumentInformation(ProgramMethod from, ProgramMethod to) {
assert codeScanner != null;
MethodStateCollectionByReference methodStates = codeScanner.getMethodStates();
@@ -125,6 +130,8 @@
Timing timing)
throws ExecutionException {
assert !appView.getSyntheticItems().hasPendingSyntheticClasses();
+ assert reprocessingCriteriaCollection.verifyNoDelayedReprocessingCriteria();
+
timing.begin("Argument propagator");
// Compute the strongly connected program components for parallel execution.
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 a61d0b4..4d19a71 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
@@ -40,6 +40,9 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ParameterState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.UnknownMethodState;
+import com.android.tools.r8.optimize.argumentpropagation.reprocessingcriteria.ArgumentPropagatorReprocessingCriteriaCollection;
+import com.android.tools.r8.optimize.argumentpropagation.reprocessingcriteria.MethodReprocessingCriteria;
+import com.android.tools.r8.optimize.argumentpropagation.reprocessingcriteria.ParameterReprocessingCriteria;
import com.android.tools.r8.optimize.argumentpropagation.utils.WideningUtils;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Timing;
@@ -68,6 +71,8 @@
private final Set<DexMethod> monomorphicVirtualMethods = Sets.newIdentityHashSet();
+ private final ArgumentPropagatorReprocessingCriteriaCollection reprocessingCriteriaCollection;
+
/**
* Maps each non-private virtual method to the upper most method in the class hierarchy with the
* same method signature. Virtual methods that do not override other virtual methods are mapped to
@@ -82,8 +87,11 @@
private final MethodStateCollectionByReference methodStates =
MethodStateCollectionByReference.createConcurrent();
- ArgumentPropagatorCodeScanner(AppView<AppInfoWithLiveness> appView) {
+ ArgumentPropagatorCodeScanner(
+ AppView<AppInfoWithLiveness> appView,
+ ArgumentPropagatorReprocessingCriteriaCollection reprocessingCriteriaCollection) {
this.appView = appView;
+ this.reprocessingCriteriaCollection = reprocessingCriteriaCollection;
}
public synchronized void addMonomorphicVirtualMethods(Set<DexMethod> extension) {
@@ -259,7 +267,11 @@
assert existingMethodState.isBottom() || existingMethodState.isMonomorphic();
result =
computeMonomorphicMethodState(
- invoke, resolvedMethod, context, existingMethodState.asMonomorphicOrBottom());
+ invoke,
+ resolvedMethod,
+ invoke.lookupSingleProgramTarget(appView, context),
+ context,
+ existingMethodState.asMonomorphicOrBottom());
}
timing.end();
return result;
@@ -276,9 +288,10 @@
DynamicType dynamicReceiverType = invoke.getReceiver().getDynamicType(appView);
assert !dynamicReceiverType.getDynamicUpperBoundType().nullability().isDefinitelyNull();
+ ProgramMethod singleTarget = invoke.lookupSingleProgramTarget(appView, context);
DynamicType bounds =
computeBoundsForPolymorphicMethodState(
- invoke, resolvedMethod, context, dynamicReceiverType);
+ invoke, resolvedMethod, singleTarget, context, dynamicReceiverType);
MethodState existingMethodStateForBounds =
existingMethodState.isPolymorphic()
? existingMethodState.asPolymorphic().getMethodStateForBounds(bounds)
@@ -299,6 +312,7 @@
computeMonomorphicMethodState(
invoke,
resolvedMethod,
+ singleTarget,
context,
existingMethodStateForBounds.asMonomorphicOrBottom(),
dynamicReceiverType);
@@ -308,9 +322,9 @@
private DynamicType computeBoundsForPolymorphicMethodState(
InvokeMethodWithReceiver invoke,
ProgramMethod resolvedMethod,
+ ProgramMethod singleTarget,
ProgramMethod context,
DynamicType dynamicReceiverType) {
- ProgramMethod singleTarget = invoke.lookupSingleProgramTarget(appView, context);
DynamicType bounds =
singleTarget != null
? DynamicType.createExact(
@@ -343,11 +357,13 @@
private ConcreteMonomorphicMethodStateOrUnknown computeMonomorphicMethodState(
InvokeMethod invoke,
ProgramMethod resolvedMethod,
+ ProgramMethod singleTarget,
ProgramMethod context,
ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
return computeMonomorphicMethodState(
invoke,
resolvedMethod,
+ singleTarget,
context,
existingMethodState,
invoke.isInvokeMethodWithReceiver()
@@ -358,11 +374,17 @@
private ConcreteMonomorphicMethodStateOrUnknown computeMonomorphicMethodState(
InvokeMethod invoke,
ProgramMethod resolvedMethod,
+ ProgramMethod singleTarget,
ProgramMethod context,
ConcreteMonomorphicMethodStateOrBottom existingMethodState,
DynamicType dynamicReceiverType) {
List<ParameterState> parameterStates = new ArrayList<>(invoke.arguments().size());
+ MethodReprocessingCriteria methodReprocessingCriteria =
+ singleTarget != null
+ ? reprocessingCriteriaCollection.getReprocessingCriteria(singleTarget)
+ : MethodReprocessingCriteria.alwaysReprocess();
+
int argumentIndex = 0;
if (invoke.isInvokeMethodWithReceiver()) {
assert dynamicReceiverType != null;
@@ -371,7 +393,8 @@
invoke.asInvokeMethodWithReceiver(),
resolvedMethod,
dynamicReceiverType,
- existingMethodState));
+ existingMethodState,
+ methodReprocessingCriteria.getParameterReprocessingCriteria(0)));
argumentIndex++;
}
@@ -382,7 +405,8 @@
argumentIndex,
invoke.getArgument(argumentIndex),
context,
- existingMethodState));
+ existingMethodState,
+ methodReprocessingCriteria.getParameterReprocessingCriteria(argumentIndex)));
}
// If all parameter states are unknown, then return a canonicalized unknown method state that
@@ -402,13 +426,20 @@
InvokeMethodWithReceiver invoke,
ProgramMethod resolvedMethod,
DynamicType dynamicReceiverType,
- ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
+ ConcreteMonomorphicMethodStateOrBottom existingMethodState,
+ ParameterReprocessingCriteria parameterReprocessingCriteria) {
// 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();
}
+ // For receivers we only track the dynamic type. Therefore, if there is no need to track the
+ // dynamic type of the receiver of the targeted method, then just return unknown.
+ if (!parameterReprocessingCriteria.shouldReprocessDueToDynamicType()) {
+ return ParameterState.unknown();
+ }
+
DynamicType widenedDynamicReceiverType =
WideningUtils.widenDynamicReceiverType(appView, resolvedMethod, dynamicReceiverType);
return widenedDynamicReceiverType.isUnknown()
@@ -421,7 +452,8 @@
int argumentIndex,
Value argument,
ProgramMethod context,
- ConcreteMonomorphicMethodStateOrBottom existingMethodState) {
+ ConcreteMonomorphicMethodStateOrBottom existingMethodState,
+ ParameterReprocessingCriteria parameterReprocessingCriteria) {
// Don't compute a state for this parameter if the stored state is already unknown.
if (existingMethodState.isMonomorphic()
&& existingMethodState.asMonomorphic().getParameterState(argumentIndex).isUnknown()) {
@@ -469,6 +501,12 @@
// then use UnknownParameterState.
if (parameterTypeElement.isClassType()) {
DynamicType dynamicType = argument.getDynamicType(appView);
+ if (!parameterReprocessingCriteria.shouldReprocessDueToDynamicType()) {
+ dynamicType =
+ parameterReprocessingCriteria.widenDynamicClassType(
+ appView, dynamicType, parameterTypeElement.asClassType());
+ }
+
DynamicType widenedDynamicType =
WideningUtils.widenDynamicNonReceiverType(appView, dynamicType, parameterType);
return abstractValue.isUnknown() && widenedDynamicType.isUnknown()
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/AlwaysFalseParameterReprocessingCriteria.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/AlwaysFalseParameterReprocessingCriteria.java
index 90d7e4a..fd343f9 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/AlwaysFalseParameterReprocessingCriteria.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/AlwaysFalseParameterReprocessingCriteria.java
@@ -6,6 +6,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
+import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteParameterState;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -53,4 +55,10 @@
public boolean shouldReprocessDueToNullability() {
return false;
}
+
+ @Override
+ public DynamicType widenDynamicClassType(
+ AppView<AppInfoWithLiveness> appView, DynamicType dynamicType, ClassTypeElement staticType) {
+ return null;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
index 68191f9..90e9ead 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ArgumentPropagatorReprocessingCriteriaCollection.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
+import java.util.IdentityHashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -35,6 +36,9 @@
private final AppView<AppInfoWithLiveness> appView;
private final Map<DexMethod, MethodReprocessingCriteria> reproccessingCriteria =
+ new IdentityHashMap<>();
+
+ private final Map<DexMethod, MethodReprocessingCriteria> delayedReproccessingCriteria =
new ConcurrentHashMap<>();
public ArgumentPropagatorReprocessingCriteriaCollection(AppView<AppInfoWithLiveness> appView) {
@@ -43,7 +47,12 @@
public MethodReprocessingCriteria getReprocessingCriteria(ProgramMethod method) {
return reproccessingCriteria.getOrDefault(
- method.getReference(), MethodReprocessingCriteria.empty());
+ method.getReference(), MethodReprocessingCriteria.alwaysReprocess());
+ }
+
+ public void publishDelayedReprocessingCriteria() {
+ reproccessingCriteria.putAll(delayedReproccessingCriteria);
+ delayedReproccessingCriteria.clear();
}
/**
@@ -69,7 +78,7 @@
// optimization info, then record this information. If the map is empty, then the method should
// always be reprocessed if we find non-trivial optimization info for some of the parameters.
if (!methodReprocessingCriteria.isEmpty()) {
- reproccessingCriteria.put(
+ delayedReproccessingCriteria.put(
method.getReference(), new MethodReprocessingCriteria(methodReprocessingCriteria));
}
}
@@ -142,4 +151,9 @@
return builder.build();
}
+
+ public boolean verifyNoDelayedReprocessingCriteria() {
+ assert delayedReproccessingCriteria.isEmpty();
+ return true;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/MethodReprocessingCriteria.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/MethodReprocessingCriteria.java
index 527ee9e..0afc8ca 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/MethodReprocessingCriteria.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/MethodReprocessingCriteria.java
@@ -15,7 +15,8 @@
public class MethodReprocessingCriteria {
- public static final MethodReprocessingCriteria EMPTY = new MethodReprocessingCriteria();
+ public static final MethodReprocessingCriteria ALWAYS_REPROCESS =
+ new MethodReprocessingCriteria();
private final Int2ReferenceMap<ParameterReprocessingCriteria> reproccesingCriteria;
@@ -29,8 +30,8 @@
this.reproccesingCriteria = reproccesingCriteria;
}
- public static MethodReprocessingCriteria empty() {
- return EMPTY;
+ public static MethodReprocessingCriteria alwaysReprocess() {
+ return ALWAYS_REPROCESS;
}
public ParameterReprocessingCriteria getParameterReprocessingCriteria(int parameterIndex) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ParameterReprocessingCriteria.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ParameterReprocessingCriteria.java
index 9022f81..d7c8890 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ParameterReprocessingCriteria.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/reprocessingcriteria/ParameterReprocessingCriteria.java
@@ -6,6 +6,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
+import com.android.tools.r8.ir.analysis.type.DynamicType;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteParameterState;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -42,6 +44,14 @@
public abstract boolean shouldReprocessDueToNullability();
+ public final DynamicType widenDynamicClassType(
+ AppView<AppInfoWithLiveness> appView, DynamicType dynamicType, ClassTypeElement staticType) {
+ if (dynamicType.getNullability().isMaybeNull()) {
+ return DynamicType.unknown();
+ }
+ return DynamicType.create(appView, staticType.getOrCreateVariant(dynamicType.getNullability()));
+ }
+
public static class Builder {
private boolean reprocessDueToAbstractValue;