Redesign constant abstraction.
Bug: 69963623
Change-Id: I79506a9fdf1bf05352424c8e66fec98b175583f6
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
index e7a1e8b..32e2621 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -11,7 +11,7 @@
* concretization of this abstract value has size 1).
*/
public boolean isSingleValue() {
- return false;
+ return isSingleEnumValue() || isSingleNumberValue() || isSingleStringValue();
}
public boolean isSingleEnumValue() {
@@ -22,6 +22,22 @@
return null;
}
+ public boolean isSingleNumberValue() {
+ return false;
+ }
+
+ public SingleNumberValue asSingleNumberValue() {
+ return null;
+ }
+
+ public boolean isSingleStringValue() {
+ return false;
+ }
+
+ public SingleStringValue asSingleStringValue() {
+ return null;
+ }
+
public boolean isUnknown() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
index c58addb..7e34815 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
@@ -5,13 +5,25 @@
package com.android.tools.r8.ir.analysis.value;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexString;
import java.util.concurrent.ConcurrentHashMap;
public class AbstractValueFactory {
private ConcurrentHashMap<DexField, SingleEnumValue> singleEnumValues = new ConcurrentHashMap<>();
+ private ConcurrentHashMap<Long, SingleNumberValue> singleNumberValues = new ConcurrentHashMap<>();
+ private ConcurrentHashMap<DexString, SingleStringValue> singleStringValues =
+ new ConcurrentHashMap<>();
public SingleEnumValue createSingleEnumValue(DexField field) {
return singleEnumValues.computeIfAbsent(field, SingleEnumValue::new);
}
+
+ public SingleNumberValue createSingleNumberValue(long value) {
+ return singleNumberValues.computeIfAbsent(value, SingleNumberValue::new);
+ }
+
+ public SingleStringValue createSingleStringValue(DexString string) {
+ return singleStringValues.computeIfAbsent(string, SingleStringValue::new);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleEnumValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleEnumValue.java
index 6a3d96b..a9050ef 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleEnumValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleEnumValue.java
@@ -16,11 +16,6 @@
}
@Override
- public boolean isSingleValue() {
- return true;
- }
-
- @Override
public boolean isSingleEnumValue() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
new file mode 100644
index 0000000..914516a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -0,0 +1,39 @@
+// Copyright (c) 2019, 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.ir.analysis.value;
+
+public class SingleNumberValue extends AbstractValue {
+
+ private final long value;
+
+ /** Intentionally package private, use {@link AbstractValueFactory} instead. */
+ SingleNumberValue(long value) {
+ this.value = value;
+ }
+
+ @Override
+ public boolean isSingleNumberValue() {
+ return true;
+ }
+
+ @Override
+ public SingleNumberValue asSingleNumberValue() {
+ return this;
+ }
+
+ public long getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
new file mode 100644
index 0000000..acb2f69
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleStringValue.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2019, 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.ir.analysis.value;
+
+import com.android.tools.r8.graph.DexString;
+
+public class SingleStringValue extends AbstractValue {
+
+ private final DexString string;
+
+ /** Intentionally package private, use {@link AbstractValueFactory} instead. */
+ SingleStringValue(DexString string) {
+ this.string = string;
+ }
+
+ @Override
+ public boolean isSingleStringValue() {
+ return true;
+ }
+
+ @Override
+ public SingleStringValue asSingleStringValue() {
+ return this;
+ }
+
+ public DexString getDexString() {
+ return string;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o;
+ }
+
+ @Override
+ public int hashCode() {
+ return string.hashCode();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index 2f70beb..1ffe1ad 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -30,9 +30,11 @@
void methodReturnsArgument(DexEncodedMethod method, int argument);
- void methodReturnsConstantNumber(DexEncodedMethod method, long value);
+ void methodReturnsConstantNumber(
+ DexEncodedMethod method, AppView<?> appView, long value);
- void methodReturnsConstantString(DexEncodedMethod method, DexString value);
+ void methodReturnsConstantString(
+ DexEncodedMethod method, AppView<?> appView, DexString value);
void methodReturnsObjectWithUpperBoundType(
DexEncodedMethod method, AppView<?> appView, TypeLatticeElement type);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/ConstantData.java b/src/main/java/com/android/tools/r8/ir/optimize/info/ConstantData.java
deleted file mode 100644
index 6c10d58..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/ConstantData.java
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2019, 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.ir.optimize.info;
-
-import com.android.tools.r8.graph.DexString;
-import java.util.Optional;
-import java.util.OptionalLong;
-
-// Simple data class that encapsulates constant values. Usages are:
-// * return value in a method summary when the method returns a constant.
-// * call-site optimization info if a certain method is always invoked with a constant.
-//
-// Note that this data class mimics C-like union. That is, a constant content that a value can hold
-// should be *one* of constant kinds, not multiple things at the same time. E.g., a value cannot
-// have ConstNumber and ConstString simultaneously. Content's orthogonality will be checked at
-// {@link #hasConstant()}.
-class ConstantData {
- private static final ConstantData INSTANCE = new ConstantData();
-
- static ConstantData getDefaultInstance() {
- return INSTANCE;
- }
-
- private final OptionalLong constantNumber;
- // TODO(b/69963623): item-based string?
- private final Optional<DexString> constantString;
- // TODO(b/69963623): constantClass?
-
- private ConstantData() {
- this.constantNumber = OptionalLong.empty();
- this.constantString = Optional.empty();
- }
-
- private ConstantData(long constantNumber) {
- this.constantNumber = OptionalLong.of(constantNumber);
- this.constantString = Optional.empty();
- }
-
- private ConstantData(DexString constantString) {
- this.constantNumber = OptionalLong.empty();
- this.constantString = Optional.of(constantString);
- }
-
- static ConstantData fromConstantNumber(long constantNumber) {
- return new ConstantData(constantNumber);
- }
-
- static ConstantData fromConstantString(DexString constantString) {
- return new ConstantData(constantString);
- }
-
- boolean hasConstant() {
- assert !(hasConstantNumber() && hasConstantString());
- return hasConstantNumber() || hasConstantString();
- }
-
- boolean hasConstantNumber() {
- return constantNumber.isPresent();
- }
-
- boolean hasConstantString() {
- return constantString.isPresent();
- }
-
- long getConstantNumber() {
- assert hasConstantNumber() && !hasConstantString();
- return constantNumber.getAsLong();
- }
-
- DexString getConstantString() {
- assert !hasConstantNumber() && hasConstantString();
- return constantString.get();
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index fd641f3..3b64d1c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -9,6 +9,8 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.initializer.ClassInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
@@ -25,10 +27,10 @@
static int UNKNOWN_RETURNED_ARGUMENT = -1;
static boolean UNKNOWN_NEVER_RETURNS_NULL = false;
static boolean UNKNOWN_NEVER_RETURNS_NORMALLY = false;
- static ConstantData UNKNOWN_CONSTANT_DATA = ConstantData.getDefaultInstance();
+ static AbstractValue UNKNOWN_CONSTANT_VALUE = UnknownValue.getInstance();
static TypeLatticeElement UNKNOWN_TYPE = null;
static ClassTypeLatticeElement UNKNOWN_CLASS_TYPE = null;
- static boolean DOES_NOT_USE_IDNETIFIER_NAME_STRING = false;
+ static boolean DOES_NOT_USE_IDENTIFIER_NAME_STRING = false;
static boolean UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT = false;
static boolean UNKNOWN_TRIGGERS_CLASS_INIT_BEFORE_ANY_SIDE_EFFECT = false;
static ClassInlinerEligibility UNKNOWN_CLASS_INLINER_ELIGIBILITY = null;
@@ -139,18 +141,13 @@
}
@Override
- public boolean returnsConstant() {
- return UNKNOWN_CONSTANT_DATA.hasConstant();
- }
-
- @Override
public boolean returnsConstantNumber() {
- return UNKNOWN_CONSTANT_DATA.hasConstantNumber();
+ return UNKNOWN_CONSTANT_VALUE.isSingleNumberValue();
}
@Override
public boolean returnsConstantString() {
- return UNKNOWN_CONSTANT_DATA.hasConstantString();
+ return UNKNOWN_CONSTANT_VALUE.isSingleStringValue();
}
@Override
@@ -161,13 +158,13 @@
@Override
public long getReturnedConstantNumber() {
assert returnsConstantNumber();
- return UNKNOWN_CONSTANT_DATA.getConstantNumber();
+ return UNKNOWN_CONSTANT_VALUE.asSingleNumberValue().getValue();
}
@Override
public DexString getReturnedConstantString() {
assert returnsConstantString();
- return UNKNOWN_CONSTANT_DATA.getConstantString();
+ return UNKNOWN_CONSTANT_VALUE.asSingleStringValue().getDexString();
}
@Override
@@ -177,7 +174,7 @@
@Override
public boolean useIdentifierNameString() {
- return DOES_NOT_USE_IDNETIFIER_NAME_STRING;
+ return DOES_NOT_USE_IDENTIFIER_NAME_STRING;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index 9ea0777..93cdc1b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -55,7 +55,9 @@
boolean neverReturnsNormally();
- boolean returnsConstant();
+ default boolean returnsConstant() {
+ return returnsConstantNumber() || returnsConstantString();
+ }
boolean returnsConstantNumber();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 371850d..7f8cfc4 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -251,11 +251,12 @@
if (aliasedValue.isConstant()) {
if (aliasedValue.definition.isConstNumber()) {
long value = aliasedValue.definition.asConstNumber().getRawValue();
- feedback.methodReturnsConstantNumber(method, value);
+ feedback.methodReturnsConstantNumber(method, appView, value);
} else if (aliasedValue.definition.isConstString()) {
ConstString constStringInstruction = aliasedValue.definition.asConstString();
if (!constStringInstruction.instructionInstanceCanThrow()) {
- feedback.methodReturnsConstantString(method, constStringInstruction.getValue());
+ feedback.methodReturnsConstantString(
+ method, appView, constStringInstruction.getValue());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 3f5c226..4c3578e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -157,13 +157,15 @@
}
@Override
- public synchronized void methodReturnsConstantNumber(DexEncodedMethod method, long value) {
- getMethodOptimizationInfoForUpdating(method).markReturnsConstantNumber(value);
+ public synchronized void methodReturnsConstantNumber(
+ DexEncodedMethod method, AppView<?> appView, long value) {
+ getMethodOptimizationInfoForUpdating(method).markReturnsConstantNumber(appView, value);
}
@Override
- public synchronized void methodReturnsConstantString(DexEncodedMethod method, DexString value) {
- getMethodOptimizationInfoForUpdating(method).markReturnsConstantString(value);
+ public synchronized void methodReturnsConstantString(
+ DexEncodedMethod method, AppView<?> appView, DexString value) {
+ getMethodOptimizationInfoForUpdating(method).markReturnsConstantString(appView, value);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index 2803998..1b3e982 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -68,10 +68,12 @@
public void methodReturnsArgument(DexEncodedMethod method, int argument) {}
@Override
- public void methodReturnsConstantNumber(DexEncodedMethod method, long value) {}
+ public void methodReturnsConstantNumber(
+ DexEncodedMethod method, AppView<?> appView, long value) {}
@Override
- public void methodReturnsConstantString(DexEncodedMethod method, DexString value) {}
+ public void methodReturnsConstantString(
+ DexEncodedMethod method, AppView<?> appView, DexString value) {}
@Override
public void methodReturnsObjectWithUpperBoundType(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index 122b6bb..ade0e2d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -90,12 +90,14 @@
}
@Override
- public void methodReturnsConstantNumber(DexEncodedMethod method, long value) {
+ public void methodReturnsConstantNumber(
+ DexEncodedMethod method, AppView<?> appView, long value) {
// Ignored.
}
@Override
- public void methodReturnsConstantString(DexEncodedMethod method, DexString value) {
+ public void methodReturnsConstantString(
+ DexEncodedMethod method, AppView<?> appView, DexString value) {
// Ignored.
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
index c9faaa5..d553a4c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement;
import com.android.tools.r8.ir.analysis.type.TypeLatticeElement;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.initializer.ClassInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
@@ -34,14 +35,14 @@
private boolean neverReturnsNull = DefaultMethodOptimizationInfo.UNKNOWN_NEVER_RETURNS_NULL;
private boolean neverReturnsNormally =
DefaultMethodOptimizationInfo.UNKNOWN_NEVER_RETURNS_NORMALLY;
- private ConstantData constantData = DefaultMethodOptimizationInfo.UNKNOWN_CONSTANT_DATA;
+ private AbstractValue constantValue = DefaultMethodOptimizationInfo.UNKNOWN_CONSTANT_VALUE;
private TypeLatticeElement returnsObjectWithUpperBoundType =
DefaultMethodOptimizationInfo.UNKNOWN_TYPE;
private ClassTypeLatticeElement returnsObjectWithLowerBoundType =
DefaultMethodOptimizationInfo.UNKNOWN_CLASS_TYPE;
private InlinePreference inlining = InlinePreference.Default;
private boolean useIdentifierNameString =
- DefaultMethodOptimizationInfo.DOES_NOT_USE_IDNETIFIER_NAME_STRING;
+ DefaultMethodOptimizationInfo.DOES_NOT_USE_IDENTIFIER_NAME_STRING;
private boolean checksNullReceiverBeforeAnySideEffect =
DefaultMethodOptimizationInfo.UNKNOWN_CHECKS_NULL_RECEIVER_BEFORE_ANY_SIDE_EFFECT;
private boolean triggersClassInitBeforeAnySideEffect =
@@ -92,7 +93,7 @@
returnValueOnlyDependsOnArguments = template.returnValueOnlyDependsOnArguments;
neverReturnsNull = template.neverReturnsNull;
neverReturnsNormally = template.neverReturnsNormally;
- constantData = template.constantData;
+ constantValue = template.constantValue;
returnsObjectWithUpperBoundType = template.returnsObjectWithUpperBoundType;
returnsObjectWithLowerBoundType = template.returnsObjectWithLowerBoundType;
inlining = template.inlining;
@@ -234,18 +235,13 @@
}
@Override
- public boolean returnsConstant() {
- return constantData.hasConstant();
- }
-
- @Override
public boolean returnsConstantNumber() {
- return constantData.hasConstantNumber();
+ return constantValue.isSingleNumberValue();
}
@Override
public boolean returnsConstantString() {
- return constantData.hasConstantString();
+ return constantValue.isSingleStringValue();
}
@Override
@@ -256,13 +252,13 @@
@Override
public long getReturnedConstantNumber() {
assert returnsConstantNumber();
- return constantData.getConstantNumber();
+ return constantValue.asSingleNumberValue().getValue();
}
@Override
public DexString getReturnedConstantString() {
assert returnsConstantString();
- return constantData.getConstantString();
+ return constantValue.asSingleStringValue().getDexString();
}
@Override
@@ -359,20 +355,22 @@
neverReturnsNormally = true;
}
- void markReturnsConstantNumber(long value) {
- assert !constantData.hasConstantString();
- assert !constantData.hasConstantNumber() || constantData.getConstantNumber() == value
+ void markReturnsConstantNumber(AppView<?> appView, long value) {
+ assert !constantValue.isSingleStringValue();
+ assert !constantValue.isSingleNumberValue()
+ || constantValue.asSingleNumberValue().getValue() == value
: "return constant number changed from "
- + constantData.getConstantNumber() + " to " + value;
- constantData = ConstantData.fromConstantNumber(value);
+ + constantValue.asSingleNumberValue().getValue() + " to " + value;
+ constantValue = appView.abstractValueFactory().createSingleNumberValue(value);
}
- void markReturnsConstantString(DexString value) {
- assert !constantData.hasConstantNumber();
- assert !constantData.hasConstantString() || constantData.getConstantString() == value
+ void markReturnsConstantString(AppView<?> appView, DexString value) {
+ assert !constantValue.isSingleNumberValue();
+ assert !constantValue.isSingleStringValue()
+ || constantValue.asSingleStringValue().getDexString() == value
: "return constant string changed from "
- + constantData.getConstantString() + " to " + value;
- constantData = ConstantData.fromConstantString(value);
+ + constantValue.asSingleStringValue().getDexString() + " to " + value;
+ constantValue = appView.abstractValueFactory().createSingleStringValue(value);
}
void markReturnsObjectWithUpperBoundType(AppView<?> appView, TypeLatticeElement type) {
@@ -474,7 +472,7 @@
// code is not changed, and thus the following *return* info is not changed either.
// * neverReturnsNull
// * neverReturnsNormally
- // * constantData
+ // * constantValue
// * returnsObjectWithUpperBoundType
// * returnsObjectWithLowerBoundType
// inlining: it is not inlined, and thus staticized. No more chance of inlining, though.