Generalize in flow to allow non-parameters
Change-Id: I5c7ff901ccd701f96e80edeaa59838339b095685
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteArrayTypeParameterState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteArrayTypeParameterState.java
index 97803d0..5f53e18 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteArrayTypeParameterState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteArrayTypeParameterState.java
@@ -19,15 +19,15 @@
private Nullability nullability;
- public ConcreteArrayTypeParameterState(MethodParameter inParameter) {
- this(Nullability.bottom(), SetUtils.newHashSet(inParameter));
+ public ConcreteArrayTypeParameterState(InFlow inFlow) {
+ this(Nullability.bottom(), SetUtils.newHashSet(inFlow));
}
public ConcreteArrayTypeParameterState(Nullability nullability) {
this(nullability, Collections.emptySet());
}
- public ConcreteArrayTypeParameterState(Nullability nullability, Set<MethodParameter> inFlow) {
+ public ConcreteArrayTypeParameterState(Nullability nullability, Set<InFlow> inFlow) {
super(inFlow);
this.nullability = nullability;
assert !isEffectivelyBottom() : "Must use BottomArrayTypeParameterState instead";
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeParameterState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeParameterState.java
index 5c6d7a4..82b371b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeParameterState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeParameterState.java
@@ -21,8 +21,8 @@
private AbstractValue abstractValue;
private DynamicType dynamicType;
- public ConcreteClassTypeParameterState(MethodParameter inParameter) {
- this(AbstractValue.bottom(), DynamicType.bottom(), SetUtils.newHashSet(inParameter));
+ public ConcreteClassTypeParameterState(InFlow inFlow) {
+ this(AbstractValue.bottom(), DynamicType.bottom(), SetUtils.newHashSet(inFlow));
}
public ConcreteClassTypeParameterState(AbstractValue abstractValue, DynamicType dynamicType) {
@@ -30,7 +30,7 @@
}
public ConcreteClassTypeParameterState(
- AbstractValue abstractValue, DynamicType dynamicType, Set<MethodParameter> inFlow) {
+ AbstractValue abstractValue, DynamicType dynamicType, Set<InFlow> inFlow) {
super(inFlow);
this.abstractValue = abstractValue;
this.dynamicType = dynamicType;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteParameterState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteParameterState.java
index 4e95fed..5f94c04 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteParameterState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteParameterState.java
@@ -21,9 +21,9 @@
RECEIVER
}
- private Set<MethodParameter> inFlow;
+ private Set<InFlow> inFlow;
- ConcreteParameterState(Set<MethodParameter> inFlow) {
+ ConcreteParameterState(Set<InFlow> inFlow) {
this.inFlow = inFlow;
}
@@ -33,9 +33,9 @@
inFlow = Collections.emptySet();
}
- public Set<MethodParameter> copyInFlow() {
+ public Set<InFlow> copyInFlow() {
if (inFlow.isEmpty()) {
- assert inFlow == Collections.<MethodParameter>emptySet();
+ assert inFlow == Collections.<InFlow>emptySet();
return inFlow;
}
return new HashSet<>(inFlow);
@@ -45,7 +45,7 @@
return !inFlow.isEmpty();
}
- public Set<MethodParameter> getInFlow() {
+ public Set<InFlow> getInFlow() {
assert inFlow.isEmpty() || inFlow instanceof HashSet<?>;
return inFlow;
}
@@ -135,7 +135,7 @@
return false;
}
if (inFlow.isEmpty()) {
- assert inFlow == Collections.<MethodParameter>emptySet();
+ assert inFlow == Collections.<InFlow>emptySet();
inFlow = new HashSet<>();
}
return inFlow.addAll(parameterState.inFlow);
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeParameterState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeParameterState.java
index 6a90616..5057f0f 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeParameterState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeParameterState.java
@@ -21,16 +21,15 @@
this(abstractValue, Collections.emptySet());
}
- public ConcretePrimitiveTypeParameterState(
- AbstractValue abstractValue, Set<MethodParameter> inFlow) {
+ public ConcretePrimitiveTypeParameterState(AbstractValue abstractValue, Set<InFlow> inFlow) {
super(inFlow);
this.abstractValue = abstractValue;
assert !isEffectivelyBottom() : "Must use BottomPrimitiveTypeParameterState instead";
assert !isEffectivelyUnknown() : "Must use UnknownParameterState instead";
}
- public ConcretePrimitiveTypeParameterState(MethodParameter inParameter) {
- this(AbstractValue.bottom(), SetUtils.newHashSet(inParameter));
+ public ConcretePrimitiveTypeParameterState(InFlow inFlow) {
+ this(AbstractValue.bottom(), SetUtils.newHashSet(inFlow));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReceiverParameterState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReceiverParameterState.java
index 5a321a3..442c6ed 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReceiverParameterState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReceiverParameterState.java
@@ -22,7 +22,7 @@
this(dynamicType, Collections.emptySet());
}
- public ConcreteReceiverParameterState(DynamicType dynamicType, Set<MethodParameter> inFlow) {
+ public ConcreteReceiverParameterState(DynamicType dynamicType, Set<InFlow> inFlow) {
super(inFlow);
this.dynamicType = dynamicType;
assert !isEffectivelyBottom() : "Must use BottomReceiverParameterState instead";
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReferenceTypeParameterState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReferenceTypeParameterState.java
index da2056a..6e94838 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReferenceTypeParameterState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReferenceTypeParameterState.java
@@ -14,7 +14,7 @@
public abstract class ConcreteReferenceTypeParameterState extends ConcreteParameterState {
- ConcreteReferenceTypeParameterState(Set<MethodParameter> inFlow) {
+ ConcreteReferenceTypeParameterState(Set<InFlow> inFlow) {
super(inFlow);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlow.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlow.java
new file mode 100644
index 0000000..b651045
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlow.java
@@ -0,0 +1,15 @@
+// Copyright (c) 2024, 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 InFlow {
+
+ default boolean isMethodParameter() {
+ return false;
+ }
+
+ default MethodParameter asMethodParameter() {
+ return null;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
index d2ba546..9bfeab7 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/MethodParameter.java
@@ -7,7 +7,7 @@
import com.android.tools.r8.graph.DexMethod;
import java.util.Objects;
-public class MethodParameter {
+public class MethodParameter implements InFlow {
private final DexMethod method;
private final int index;
@@ -26,6 +26,16 @@
}
@Override
+ public boolean isMethodParameter() {
+ return true;
+ }
+
+ @Override
+ public MethodParameter asMethodParameter() {
+ return this;
+ }
+
+ @Override
@SuppressWarnings({"EqualsGetClass", "ReferenceEquality"})
public boolean equals(Object obj) {
if (obj == null || getClass() != obj.getClass()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InParameterFlowPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InParameterFlowPropagator.java
index ff0bd01..deae78e 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InParameterFlowPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InParameterFlowPropagator.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.utils.MapUtils.ignoreKey;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -16,6 +17,7 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMethodState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteMonomorphicMethodState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteParameterState;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlow;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
@@ -26,6 +28,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
@@ -208,41 +211,14 @@
}
ParameterNode node = getOrCreateParameterNode(method, parameterIndex, methodState);
- for (MethodParameter inParameter : concreteParameterState.getInFlow()) {
- ProgramMethod enclosingMethod = getEnclosingMethod(inParameter);
- if (enclosingMethod == null) {
- // This is a parameter of a single caller inlined method. Since this method has been
- // pruned, the call from inside the method no longer exists, and we can therefore safely
- // skip it.
- assert converter
- .getInliner()
- .verifyIsPrunedDueToSingleCallerInlining(inParameter.getMethod());
- continue;
+ for (InFlow inFlow : concreteParameterState.getInFlow()) {
+ if (inFlow.isMethodParameter()) {
+ if (addInFlow(inFlow.asMethodParameter(), node).shouldBreak()) {
+ break;
+ }
+ } else {
+ throw new Unreachable();
}
-
- MethodState enclosingMethodState = getMethodState(enclosingMethod);
- if (enclosingMethodState.isBottom()) {
- // The current method is called from a dead method; no need to propagate any information
- // from the dead call site.
- continue;
- }
-
- if (enclosingMethodState.isUnknown()) {
- // The parameter depends on another parameter for which we don't know anything.
- node.clearPredecessors();
- node.setState(ParameterState.unknown());
- break;
- }
-
- assert enclosingMethodState.isConcrete();
- assert enclosingMethodState.asConcrete().isMonomorphic();
-
- ParameterNode predecessor =
- getOrCreateParameterNode(
- enclosingMethod,
- inParameter.getIndex(),
- enclosingMethodState.asConcrete().asMonomorphic());
- node.addPredecessor(predecessor);
}
if (!node.getState().isUnknown()) {
@@ -251,6 +227,42 @@
}
}
+ private TraversalContinuation<?, ?> addInFlow(MethodParameter inFlow, ParameterNode node) {
+ ProgramMethod enclosingMethod = getEnclosingMethod(inFlow);
+ if (enclosingMethod == null) {
+ // This is a parameter of a single caller inlined method. Since this method has been
+ // pruned, the call from inside the method no longer exists, and we can therefore safely
+ // skip it.
+ assert converter.getInliner().verifyIsPrunedDueToSingleCallerInlining(inFlow.getMethod());
+ return TraversalContinuation.doContinue();
+ }
+
+ MethodState enclosingMethodState = getMethodState(enclosingMethod);
+ if (enclosingMethodState.isBottom()) {
+ // The current method is called from a dead method; no need to propagate any information
+ // from the dead call site.
+ return TraversalContinuation.doContinue();
+ }
+
+ if (enclosingMethodState.isUnknown()) {
+ // The parameter depends on another parameter for which we don't know anything.
+ node.clearPredecessors();
+ node.setState(ParameterState.unknown());
+ return TraversalContinuation.doBreak();
+ }
+
+ assert enclosingMethodState.isConcrete();
+ assert enclosingMethodState.asConcrete().isMonomorphic();
+
+ ParameterNode predecessor =
+ getOrCreateParameterNode(
+ enclosingMethod,
+ inFlow.getIndex(),
+ enclosingMethodState.asConcrete().asMonomorphic());
+ node.addPredecessor(predecessor);
+ return TraversalContinuation.doContinue();
+ }
+
private ParameterNode getOrCreateParameterNode(
ProgramMethod method, int parameterIndex, ConcreteMonomorphicMethodState methodState) {
Int2ReferenceMap<ParameterNode> parameterNodesForMethod =