Deterministic ordering in presence of if-then-else functions
Change-Id: I4ae52c9842a5273ff0bcf8a6263e4a25e6cd691c
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 1d0edbe..a17aa98 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
@@ -17,6 +17,7 @@
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.conversion.PrimaryR8IRConverter;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldStateCollection;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.VirtualRootMethodsAnalysis;
@@ -249,6 +250,7 @@
assert appView.isAllCodeProcessed();
FieldStateCollection fieldStates = codeScanner.getFieldStates();
MethodStateCollectionByReference methodStates = codeScanner.getMethodStates();
+ InFlowComparator inFlowComparator = codeScanner.getInFlowComparator();
appView.testing().argumentPropagatorEventConsumer.acceptCodeScannerResult(methodStates);
codeScanner = null;
@@ -261,6 +263,7 @@
immediateSubtypingInfo,
fieldStates,
methodStates,
+ inFlowComparator,
stronglyConnectedProgramComponents,
interfaceDispatchOutsideProgram)
.propagateOptimizationInfo(
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 b29eff6..a3961f0 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
@@ -4,7 +4,6 @@
package com.android.tools.r8.optimize.argumentpropagation;
-
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -39,6 +38,7 @@
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.ir.code.Phi;
+import com.android.tools.r8.ir.code.Position.SourcePosition;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.AbstractFunction;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.BaseInFlow;
@@ -58,6 +58,7 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldValueFactory;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.IfThenElseAbstractFunction;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlow;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.InstanceFieldReadAbstractFunction;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameterFactory;
@@ -80,6 +81,8 @@
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.structural.StructuralItem;
import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.objects.Object2IntMap;
+import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
@@ -134,6 +137,8 @@
private final MethodStateCollectionByReference methodStates =
MethodStateCollectionByReference.createConcurrent();
+ private final InFlowComparator.Builder inFlowComparatorBuilder = InFlowComparator.builder();
+
public ArgumentPropagatorCodeScanner(AppView<AppInfoWithLiveness> appView) {
this(appView, new ArgumentPropagatorReprocessingCriteriaCollection(appView));
}
@@ -166,6 +171,10 @@
return virtualRootMethods.get(method.getReference());
}
+ InFlowComparator getInFlowComparator() {
+ return inFlowComparatorBuilder.build();
+ }
+
// TODO(b/296030319): Allow lookups in the FieldStateCollection using DexField keys to avoid the
// need for definitionFor here.
private boolean isFieldValueAlreadyUnknown(DexType staticType, DexField field) {
@@ -231,6 +240,7 @@
private SuccessfulDataflowAnalysisResult<BasicBlock, PathConstraintAnalysisState>
pathConstraintAnalysisResult;
+ private Object2IntMap<Phi> phiNumbering = null;
protected CodeScanner(
AbstractValueSupplier abstractValueSupplier, IRCode code, ProgramMethod method) {
@@ -359,6 +369,9 @@
// If the value is an argument of the enclosing method or defined by a field-get, then clearly
// we have no information about its abstract value (yet). Instead of treating this as having an
// unknown runtime value, we instead record a flow constraint.
+ // TODO(b/302281503): Cache computed in flow so that we do not compute the same in flow for the
+ // same value multiple times.
+ // TODO(b/302281503): Canonicalize computed in flow.
private InFlow computeInFlow(
DexType staticType,
Value value,
@@ -420,10 +433,34 @@
}
NonEmptyValueState leftValue = valueStateSupplier.apply(phi.getOperand(0));
NonEmptyValueState rightValue = valueStateSupplier.apply(phi.getOperand(1));
- if (leftPredecessorPathConstraint.isNegated(condition)) {
- return new IfThenElseAbstractFunction(condition, rightValue, leftValue);
+ IfThenElseAbstractFunction result =
+ leftPredecessorPathConstraint.isNegated(condition)
+ ? new IfThenElseAbstractFunction(condition, rightValue, leftValue)
+ : new IfThenElseAbstractFunction(condition, leftValue, rightValue);
+ recordIfThenElsePosition(result, phi);
+ return result;
+ }
+
+ private void recordIfThenElsePosition(
+ IfThenElseAbstractFunction ifThenElseAbstractFunction, Phi phi) {
+ inFlowComparatorBuilder.addIfThenElsePosition(
+ ifThenElseAbstractFunction,
+ SourcePosition.builder()
+ .setMethod(code.context().getReference())
+ .setLine(getOrCreatePhiNumbering().getInt(phi))
+ .build());
+ }
+
+ private Object2IntMap<Phi> getOrCreatePhiNumbering() {
+ if (phiNumbering == null) {
+ phiNumbering = new Object2IntOpenHashMap<>();
+ for (BasicBlock block : code.getBlocks()) {
+ for (Phi phi : block.getPhis()) {
+ phiNumbering.put(phi, phiNumbering.size());
+ }
+ }
}
- return new IfThenElseAbstractFunction(condition, leftValue, rightValue);
+ return phiNumbering;
}
private InFlow castBaseInFlow(InFlow inFlow, Value value) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPropagator.java
index 99b3640..800b277 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPropagator.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.ImmediateProgramSubtypingInfo;
import com.android.tools.r8.ir.conversion.PrimaryR8IRConverter;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldStateCollection;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
import com.android.tools.r8.optimize.argumentpropagation.propagation.InFlowPropagator;
import com.android.tools.r8.optimize.argumentpropagation.propagation.InterfaceMethodArgumentPropagator;
@@ -34,6 +35,7 @@
private final PrimaryR8IRConverter converter;
private final FieldStateCollection fieldStates;
private final MethodStateCollectionByReference methodStates;
+ private final InFlowComparator inFlowComparator;
private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
private final List<Set<DexProgramClass>> stronglyConnectedProgramComponents;
@@ -47,6 +49,7 @@
ImmediateProgramSubtypingInfo immediateSubtypingInfo,
FieldStateCollection fieldStates,
MethodStateCollectionByReference methodStates,
+ InFlowComparator inFlowComparator,
List<Set<DexProgramClass>> stronglyConnectedProgramComponents,
BiConsumer<Set<DexProgramClass>, DexMethodSignature> interfaceDispatchOutsideProgram) {
this.appView = appView;
@@ -54,6 +57,7 @@
this.immediateSubtypingInfo = immediateSubtypingInfo;
this.fieldStates = fieldStates;
this.methodStates = methodStates;
+ this.inFlowComparator = inFlowComparator;
this.stronglyConnectedProgramComponents = stronglyConnectedProgramComponents;
this.interfaceDispatchOutsideProgram = interfaceDispatchOutsideProgram;
}
@@ -79,7 +83,8 @@
classesWithSingleCallerInlinedInstanceInitializers,
converter,
fieldStates,
- methodStates)
+ methodStates,
+ inFlowComparator)
.run(executorService);
timing.end();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/BottomValueState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/BottomValueState.java
index 609b769..a267042 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/BottomValueState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/BottomValueState.java
@@ -31,4 +31,14 @@
public ValueState mutableCopyWithoutInFlow() {
return this;
}
+
+ @Override
+ public final boolean equals(Object obj) {
+ return this == obj;
+ }
+
+ @Override
+ public final int hashCode() {
+ return System.identityHashCode(this);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/CastAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/CastAbstractFunction.java
index a4eb77e..2586f8d 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/CastAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/CastAbstractFunction.java
@@ -44,10 +44,12 @@
}
@Override
- public int internalCompareToSameKind(InFlow other) {
+ public int internalCompareToSameKind(InFlow other, InFlowComparator comparator) {
CastAbstractFunction fn = other.asCastAbstractFunction();
if (inFlow != fn.inFlow) {
- return inFlow.compareTo(fn.inFlow);
+ int result = inFlow.compareTo(fn.inFlow, comparator);
+ assert result != 0;
+ return result;
}
return type.compareTo(fn.type);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteArrayTypeValueState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteArrayTypeValueState.java
index 26dc74a..ca98915 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteArrayTypeValueState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteArrayTypeValueState.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.SetUtils;
import java.util.Collections;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
@@ -136,6 +137,23 @@
}
@Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof ConcreteArrayTypeValueState)) {
+ return false;
+ }
+ ConcreteArrayTypeValueState state = (ConcreteArrayTypeValueState) obj;
+ return nullability.equals(state.nullability) && getInFlow().equals(state.getInFlow());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getClass(), nullability, getInFlow());
+ }
+
+ @Override
public String toString() {
assert !hasInFlow();
return "ArrayState(" + nullability + ")";
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeValueState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeValueState.java
index f6a608d..96e476b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeValueState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteClassTypeValueState.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.SetUtils;
import java.util.Collections;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
@@ -189,6 +190,25 @@
}
@Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof ConcreteClassTypeValueState)) {
+ return false;
+ }
+ ConcreteClassTypeValueState state = (ConcreteClassTypeValueState) obj;
+ return abstractValue.equals(state.abstractValue)
+ && dynamicType.equals(state.dynamicType)
+ && getInFlow().equals(state.getInFlow());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getClass(), abstractValue, dynamicType, getInFlow());
+ }
+
+ @Override
public String toString() {
assert !hasInFlow();
return "ClassState(type: " + dynamicType + ", value: " + abstractValue + ")";
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeValueState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeValueState.java
index 864c16e..118c05d 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeValueState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcretePrimitiveTypeValueState.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.SetUtils;
import java.util.Collections;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
@@ -129,6 +130,23 @@
}
@Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof ConcretePrimitiveTypeValueState)) {
+ return false;
+ }
+ ConcretePrimitiveTypeValueState state = (ConcretePrimitiveTypeValueState) obj;
+ return abstractValue.equals(state.abstractValue) && getInFlow().equals(state.getInFlow());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getClass(), abstractValue, getInFlow());
+ }
+
+ @Override
public String toString() {
assert !hasInFlow();
return "PrimitiveState(" + abstractValue + ")";
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReceiverValueState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReceiverValueState.java
index 350d7f9..04711fe 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReceiverValueState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ConcreteReceiverValueState.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Action;
import java.util.Collections;
+import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;
@@ -147,6 +148,23 @@
}
@Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof ConcreteReceiverValueState)) {
+ return false;
+ }
+ ConcreteReceiverValueState state = (ConcreteReceiverValueState) obj;
+ return dynamicType.equals(state.dynamicType) && getInFlow().equals(state.getInFlow());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getClass(), dynamicType, getInFlow());
+ }
+
+ @Override
public String toString() {
assert !hasInFlow();
return "ReceiverState(" + dynamicType + ")";
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FieldValue.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FieldValue.java
index 0b9e152..99fcf7b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FieldValue.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/FieldValue.java
@@ -25,7 +25,7 @@
}
@Override
- public int internalCompareToSameKind(InFlow other) {
+ public int internalCompareToSameKind(InFlow other, InFlowComparator comparator) {
return field.compareTo(other.asFieldValue().getField());
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IdentityAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IdentityAbstractFunction.java
index 1b33495b..f31b821 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IdentityAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IdentityAbstractFunction.java
@@ -41,7 +41,7 @@
}
@Override
- public int internalCompareToSameKind(InFlow inFlow) {
+ public int internalCompareToSameKind(InFlow inFlow, InFlowComparator comparator) {
assert this == inFlow;
return 0;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IfThenElseAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IfThenElseAbstractFunction.java
index a6da375..4d21db9 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IfThenElseAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/IfThenElseAbstractFunction.java
@@ -6,10 +6,12 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.code.Position.SourcePosition;
import com.android.tools.r8.optimize.argumentpropagation.computation.ComputationTreeNode;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ListUtils;
import java.util.List;
+import java.util.Objects;
/**
* Represents a ternary expression (exp ? u : v). The {@link #condition} is an expression containing
@@ -133,9 +135,11 @@
}
@Override
- public int internalCompareToSameKind(InFlow inFlow) {
- // TODO(b/302281503): Find a way to make this comparable.
- return hashCode() - inFlow.hashCode();
+ public int internalCompareToSameKind(InFlow inFlow, InFlowComparator comparator) {
+ SourcePosition position = comparator.getIfThenElsePosition(this);
+ SourcePosition otherPosition =
+ comparator.getIfThenElsePosition(inFlow.asIfThenElseAbstractFunction());
+ return position.compareTo(otherPosition);
}
@Override
@@ -152,4 +156,23 @@
public InFlowKind getKind() {
return InFlowKind.ABSTRACT_FUNCTION_IF_THEN_ELSE;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof IfThenElseAbstractFunction)) {
+ return false;
+ }
+ IfThenElseAbstractFunction fn = (IfThenElseAbstractFunction) obj;
+ return condition.equals(fn.condition)
+ && thenState.equals(fn.thenState)
+ && elseState.equals(fn.elseState);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getClass(), condition, thenState, elseState);
+ }
}
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
index 4590558..3c28c20 100644
--- 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
@@ -7,17 +7,16 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.optimize.compose.UpdateChangedFlagsAbstractFunction;
-public interface InFlow extends Comparable<InFlow> {
+public interface InFlow {
- @Override
- default int compareTo(InFlow inFlow) {
+ default int compareTo(InFlow inFlow, InFlowComparator comparator) {
if (getKind() == inFlow.getKind()) {
- return internalCompareToSameKind(inFlow);
+ return internalCompareToSameKind(inFlow, comparator);
}
return getKind().ordinal() - inFlow.getKind().ordinal();
}
- int internalCompareToSameKind(InFlow inFlow);
+ int internalCompareToSameKind(InFlow inFlow, InFlowComparator comparator);
InFlowKind getKind();
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlowComparator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlowComparator.java
new file mode 100644
index 0000000..82a1cc8
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InFlowComparator.java
@@ -0,0 +1,53 @@
+// 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;
+
+import com.android.tools.r8.ir.code.Position.SourcePosition;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Map;
+
+public class InFlowComparator implements Comparator<InFlow> {
+
+ private final Map<IfThenElseAbstractFunction, SourcePosition> ifThenElsePositions;
+
+ private InFlowComparator(Map<IfThenElseAbstractFunction, SourcePosition> ifThenElsePositions) {
+ this.ifThenElsePositions = ifThenElsePositions;
+ }
+
+ public SourcePosition getIfThenElsePosition(IfThenElseAbstractFunction fn) {
+ SourcePosition position = ifThenElsePositions.get(fn);
+ assert position != null;
+ return position;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public void clear() {
+ ifThenElsePositions.clear();
+ }
+
+ @Override
+ public int compare(InFlow inFlow, InFlow other) {
+ return inFlow.compareTo(other, this);
+ }
+
+ public static class Builder {
+
+ private final Map<IfThenElseAbstractFunction, SourcePosition> ifThenElsePositions =
+ new HashMap<>();
+
+ public void addIfThenElsePosition(IfThenElseAbstractFunction fn, SourcePosition position) {
+ synchronized (ifThenElsePositions) {
+ ifThenElsePositions.put(fn, position);
+ }
+ }
+
+ public InFlowComparator build() {
+ return new InFlowComparator(ifThenElsePositions);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
index d9c23c4..382706b 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/InstanceFieldReadAbstractFunction.java
@@ -74,9 +74,9 @@
}
@Override
- public int internalCompareToSameKind(InFlow other) {
+ public int internalCompareToSameKind(InFlow other, InFlowComparator comparator) {
InstanceFieldReadAbstractFunction fn = other.asInstanceFieldReadAbstractFunction();
- int result = receiver.compareTo(fn.receiver);
+ int result = receiver.compareTo(fn.receiver, comparator);
if (result == 0) {
result = field.compareTo(fn.field);
}
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 138725e..ed49cea 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
@@ -63,7 +63,7 @@
}
@Override
- public int internalCompareToSameKind(InFlow other) {
+ public int internalCompareToSameKind(InFlow other, InFlowComparator comparator) {
MethodParameter methodParameter = other.asMethodParameter();
int result = method.compareTo(methodParameter.method);
if (result == 0) {
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/OrAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/OrAbstractFunction.java
index 8e84a76..c8294a4 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/OrAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/OrAbstractFunction.java
@@ -67,9 +67,9 @@
}
@Override
- public int internalCompareToSameKind(InFlow other) {
+ public int internalCompareToSameKind(InFlow other, InFlowComparator comparator) {
OrAbstractFunction fn = other.asOrAbstractFunction();
- int result = inFlow.compareTo(fn.inFlow);
+ int result = inFlow.compareTo(fn.inFlow, comparator);
if (result == 0) {
result = constant.getIntValue() - fn.constant.getIntValue();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownAbstractFunction.java
index dd06a31..726ade5 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownAbstractFunction.java
@@ -41,7 +41,7 @@
}
@Override
- public int internalCompareToSameKind(InFlow inFlow) {
+ public int internalCompareToSameKind(InFlow inFlow, InFlowComparator comparator) {
assert this == inFlow;
return 0;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownValueState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownValueState.java
index 6fdedc4..69c1fc8 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownValueState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/UnknownValueState.java
@@ -53,6 +53,16 @@
}
@Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
public String toString() {
return "⊤";
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ValueState.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ValueState.java
index b88d240..313b340 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ValueState.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/codescanner/ValueState.java
@@ -136,4 +136,10 @@
DexType outStaticType,
StateCloner cloner,
Action onChangedAction);
+
+ @Override
+ public abstract boolean equals(Object obj);
+
+ @Override
+ public abstract int hashCode();
}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraph.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraph.java
index c9649f8..98247c0 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraph.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraph.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldStateCollection;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FlowGraphStateProvider;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodParameter;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
@@ -58,8 +59,9 @@
AppView<AppInfoWithLiveness> appView,
IRConverter converter,
FieldStateCollection fieldStates,
- MethodStateCollectionByReference methodStates) {
- return new FlowGraphBuilder(appView, converter, fieldStates, methodStates);
+ MethodStateCollectionByReference methodStates,
+ InFlowComparator inFlowComparator) {
+ return new FlowGraphBuilder(appView, converter, fieldStates, methodStates, inFlowComparator);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphBuilder.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphBuilder.java
index d564575..4639273 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphBuilder.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/FlowGraphBuilder.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldStateCollection;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldValue;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlow;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
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;
@@ -32,7 +33,6 @@
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMaps;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
-import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
@@ -42,6 +42,7 @@
private final IRConverter converter;
private final FieldStateCollection fieldStates;
private final MethodStateCollectionByReference methodStates;
+ private final InFlowComparator inFlowComparator;
private final LinkedHashMap<DexField, FlowGraphFieldNode> fieldNodes = new LinkedHashMap<>();
private final LinkedHashMap<DexMethod, Int2ReferenceMap<FlowGraphParameterNode>> parameterNodes =
@@ -51,15 +52,18 @@
AppView<AppInfoWithLiveness> appView,
IRConverter converter,
FieldStateCollection fieldStates,
- MethodStateCollectionByReference methodStates) {
+ MethodStateCollectionByReference methodStates,
+ InFlowComparator inFlowComparator) {
this.appView = appView;
this.converter = converter;
this.fieldStates = fieldStates;
this.methodStates = methodStates;
+ this.inFlowComparator = inFlowComparator;
}
public FlowGraphBuilder addClasses() {
appView.appInfo().classesWithDeterministicOrder().forEach(this::add);
+ inFlowComparator.clear();
return this;
}
@@ -96,7 +100,7 @@
FlowGraphFieldNode node = getOrCreateFieldNode(field, concreteFieldState);
List<InFlow> inFlowWithDeterministicOrder =
- ListUtils.sort(concreteFieldState.getInFlow(), Comparator.naturalOrder());
+ ListUtils.sort(concreteFieldState.getInFlow(), inFlowComparator);
for (InFlow inFlow : inFlowWithDeterministicOrder) {
if (addInFlow(inFlow, node).shouldBreak()) {
assert node.isUnknown();
@@ -143,7 +147,9 @@
}
FlowGraphParameterNode node = getOrCreateParameterNode(method, parameterIndex, methodState);
- for (InFlow inFlow : concreteParameterState.getInFlow()) {
+ List<InFlow> inFlowWithDeterministicOrder =
+ ListUtils.sort(concreteParameterState.getInFlow(), inFlowComparator);
+ for (InFlow inFlow : inFlowWithDeterministicOrder) {
if (addInFlow(inFlow, node).shouldBreak()) {
assert node.isUnknown();
break;
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
index 81e3424..a2ee3c9 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/InFlowPropagator.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteValueState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldStateCollection;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FlowGraphStateProvider;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.MethodStateCollectionByReference;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.NonEmptyValueState;
@@ -48,19 +49,22 @@
final IRConverter converter;
protected final FieldStateCollection fieldStates;
final MethodStateCollectionByReference methodStates;
+ final InFlowComparator inFlowComparator;
public InFlowPropagator(
AppView<AppInfoWithLiveness> appView,
Set<DexProgramClass> classesWithSingleCallerInlinedInstanceInitializers,
IRConverter converter,
FieldStateCollection fieldStates,
- MethodStateCollectionByReference methodStates) {
+ MethodStateCollectionByReference methodStates,
+ InFlowComparator inFlowComparator) {
this.appView = appView;
this.classesWithSingleCallerInlinedInstanceInitializers =
classesWithSingleCallerInlinedInstanceInitializers;
this.converter = converter;
this.fieldStates = fieldStates;
this.methodStates = methodStates;
+ this.inFlowComparator = inFlowComparator;
}
public void run(ExecutorService executorService) throws ExecutionException {
@@ -97,7 +101,7 @@
// Build a graph with an edge from parameter p -> parameter p' if all argument information for p
// must be included in the argument information for p'.
FlowGraph flowGraph =
- FlowGraph.builder(appView, converter, fieldStates, methodStates)
+ FlowGraph.builder(appView, converter, fieldStates, methodStates, inFlowComparator)
.addClasses()
.clearInFlow()
.build();
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/ComposeMethodProcessor.java b/src/main/java/com/android/tools/r8/optimize/compose/ComposeMethodProcessor.java
index 22ed377..210a674 100644
--- a/src/main/java/com/android/tools/r8/optimize/compose/ComposeMethodProcessor.java
+++ b/src/main/java/com/android/tools/r8/optimize/compose/ComposeMethodProcessor.java
@@ -30,6 +30,7 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcretePrimitiveTypeValueState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteValueState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FieldStateCollection;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
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;
@@ -95,9 +96,15 @@
throws ExecutionException {
prepareForInFlowPropagator();
+ InFlowComparator emptyComparator = InFlowComparator.builder().build();
InFlowPropagator inFlowPropagator =
new InFlowPropagator(
- appView, null, converter, codeScanner.getFieldStates(), codeScanner.getMethodStates()) {
+ appView,
+ null,
+ converter,
+ codeScanner.getFieldStates(),
+ codeScanner.getMethodStates(),
+ emptyComparator) {
@Override
protected DefaultFieldValueJoiner createDefaultFieldValueJoiner(
diff --git a/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java b/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java
index e57b4fb..91476d3 100644
--- a/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java
+++ b/src/main/java/com/android/tools/r8/optimize/compose/UpdateChangedFlagsAbstractFunction.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ConcreteValueState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.FlowGraphStateProvider;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlow;
+import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowComparator;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.InFlowKind;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.OrAbstractFunction;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
@@ -131,8 +132,8 @@
}
@Override
- public int internalCompareToSameKind(InFlow other) {
- return inFlow.compareTo(other.asUpdateChangedFlagsAbstractFunction().inFlow);
+ public int internalCompareToSameKind(InFlow other, InFlowComparator comparator) {
+ return inFlow.compareTo(other.asUpdateChangedFlagsAbstractFunction().inFlow, comparator);
}
@Override