Fix imprecise join in ArrayTypeElement causing nondeterminism
Bug: 227138351
Change-Id: I084d200f776ddd839c2e18ee1f7bfff4a80275fe
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
index bbee604..d05ea55 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/FieldAssignmentTracker.java
@@ -203,12 +203,10 @@
}
assert fieldType.isClassType();
DynamicType dynamicType =
- fieldType.isArrayType()
- ? DynamicType.unknown()
- : WideningUtils.widenDynamicNonReceiverType(
- appView,
- value.getDynamicType(appView).withNullability(Nullability.maybeNull()),
- field.getType());
+ WideningUtils.widenDynamicNonReceiverType(
+ appView,
+ value.getDynamicType(appView).withNullability(Nullability.maybeNull()),
+ field.getType());
return ConcreteClassTypeFieldState.create(abstractValue, dynamicType);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/state/ConcreteClassTypeFieldState.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/state/ConcreteClassTypeFieldState.java
index 7cd6f2e..3f51c25 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/state/ConcreteClassTypeFieldState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/state/ConcreteClassTypeFieldState.java
@@ -46,13 +46,12 @@
AbstractValue abstractValue,
DynamicType dynamicType,
ProgramField field) {
+ assert field.getType().isClassType();
this.abstractValue =
this.abstractValue.joinReference(abstractValue, appView.abstractValueFactory());
this.dynamicType =
- field.getType().isArrayType()
- ? DynamicType.unknown()
- : WideningUtils.widenDynamicNonReceiverType(
- appView, this.dynamicType.join(appView, dynamicType), field.getType());
+ WideningUtils.widenDynamicNonReceiverType(
+ appView, this.dynamicType.join(appView, dynamicType), field.getType());
return isEffectivelyUnknown() ? unknown() : this;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
index 9b5ea8e..72cbe7d 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ArrayTypeElement.java
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.analysis.type;
-import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
-
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
@@ -85,12 +83,10 @@
}
@Override
- public ReferenceTypeElement getOrCreateVariant(Nullability nullability) {
- ArrayTypeElement variant = variants.get(nullability);
- if (variant != null) {
- return variant;
- }
- return variants.getOrCreateElement(nullability, this::createVariant);
+ public ArrayTypeElement getOrCreateVariant(Nullability nullability) {
+ return nullability.equals(nullability())
+ ? this
+ : variants.getOrCreateElement(nullability, this::createVariant);
}
@Override
@@ -151,16 +147,16 @@
ReferenceTypeElement join(ArrayTypeElement other, AppView<?> appView) {
Nullability nullability = nullability().join(other.nullability());
ReferenceTypeElement join =
- joinMember(this.memberTypeLattice, other.memberTypeLattice, appView, nullability);
+ joinMember(getMemberType(), other.getMemberType(), appView, nullability);
if (join == null) {
// Check if other has the right nullability before creating it.
- if (other.nullability == nullability) {
+ if (other.nullability() == nullability) {
return other;
} else {
return getOrCreateVariant(nullability);
}
} else {
- assert join.nullability == nullability;
+ assert join.nullability() == nullability;
return join;
}
}
@@ -188,12 +184,14 @@
return null;
}
if (aMember.isArrayType() && bMember.isArrayType()) {
+ TypeElement aMemberMember = aMember.asArrayType().getMemberType();
+ TypeElement bMemberMember = bMember.asArrayType().getMemberType();
TypeElement join =
joinMember(
- aMember.asArrayType().memberTypeLattice,
- bMember.asArrayType().memberTypeLattice,
+ aMemberMember,
+ bMemberMember,
appView,
- maybeNull());
+ aMemberMember.nullability().join(bMemberMember.nullability()));
return join == null ? null : ArrayTypeElement.create(join, nullability);
}
if (aMember.isClassType() && bMember.isClassType()) {
@@ -201,6 +199,20 @@
return ArrayTypeElement.create(join, nullability);
}
if (aMember.isPrimitiveType() || bMember.isPrimitiveType()) {
+ if (appView.enableWholeProgramOptimizations()) {
+ assert appView.hasClassHierarchy();
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ InterfaceCollection interfaceCollection =
+ InterfaceCollection.builder()
+ .addKnownInterface(dexItemFactory.cloneableType)
+ .addKnownInterface(dexItemFactory.serializableType)
+ .build();
+ return ClassTypeElement.create(
+ dexItemFactory.objectType,
+ nullability,
+ appView.withClassHierarchy(),
+ interfaceCollection);
+ }
return objectClassType(appView, nullability);
}
return objectArrayType(appView, nullability);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
index 5ff246a..3298b8e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ClassTypeElement.java
@@ -111,11 +111,9 @@
@Override
public ClassTypeElement getOrCreateVariant(Nullability nullability) {
- ClassTypeElement variant = variants.get(nullability);
- if (variant != null) {
- return variant;
- }
- return variants.getOrCreateElement(nullability, this::createVariant);
+ return nullability.equals(nullability())
+ ? this
+ : variants.getOrCreateElement(nullability, this::createVariant);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
index 9448ebb..1b1a557 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithLowerBound.java
@@ -65,6 +65,15 @@
}
@Override
+ public String toString() {
+ return "DynamicTypeWithLowerBound(upperBound="
+ + getDynamicUpperBoundType()
+ + ", lowerBound="
+ + getDynamicLowerBoundType()
+ + ")";
+ }
+
+ @Override
public DynamicTypeWithLowerBound withNullability(Nullability nullability) {
if (getDynamicUpperBoundType().nullability() == nullability) {
return this;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
index 754fb43..5784e9e 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/DynamicTypeWithUpperBound.java
@@ -266,6 +266,11 @@
return dynamicUpperBoundType.hashCode();
}
+ @Override
+ public String toString() {
+ return "DynamicTypeWithUpperBound(upperBound=" + getDynamicUpperBoundType() + ")";
+ }
+
private static boolean verifyNotEffectivelyFinalClassType(
AppView<AppInfoWithLiveness> appView, TypeElement type) {
if (type.isClassType()) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
index 8d2db28..0cd29f2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ExactDynamicType.java
@@ -73,4 +73,9 @@
public int hashCode() {
return getExactClassType().hashCode();
}
+
+ @Override
+ public String toString() {
+ return "ExactDynamicType(type=" + getExactClassType() + ")";
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java b/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
index 37ed14a..a9830ff 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/NotNullDynamicType.java
@@ -70,4 +70,9 @@
public int hashCode() {
return System.identityHashCode(this);
}
+
+ @Override
+ public String toString() {
+ return "NotNullDynamicType";
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
index ed144be..4aa2116 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/ReferenceTypeElement.java
@@ -16,7 +16,7 @@
}
@Override
- public ReferenceTypeElement getOrCreateVariant(Nullability nullability) {
+ public NullElement getOrCreateVariant(Nullability nullability) {
return nullability.isNullable() ? NULL_INSTANCE : NULL_BOTTOM_INSTANCE;
}
@@ -60,8 +60,8 @@
}
}
- private static final ReferenceTypeElement NULL_INSTANCE = NullElement.create();
- private static final ReferenceTypeElement NULL_BOTTOM_INSTANCE = NullElement.createBottom();
+ private static final NullElement NULL_INSTANCE = NullElement.create();
+ private static final NullElement NULL_BOTTOM_INSTANCE = NullElement.createBottom();
final Nullability nullability;