Structural definitions for encoded fields, annotations and dex values.
Bug: 171867022
Change-Id: I4357f6791494cea2bdbc008dccdfc69dd3eec05b
diff --git a/src/main/java/com/android/tools/r8/graph/AccessFlags.java b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
index de254fc..99f8c14 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessFlags.java
@@ -4,12 +4,15 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.utils.structural.StructuralAccept;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.function.BooleanSupplier;
/** Access flags common to classes, methods and fields. */
-public abstract class AccessFlags<T extends AccessFlags<T>> {
+public abstract class AccessFlags<T extends AccessFlags<T>> implements StructuralItem<T> {
protected static final int BASE_FLAGS
= Constants.ACC_PUBLIC
@@ -53,6 +56,15 @@
this.modifiedFlags = modifiedFlags;
}
+ protected static <T extends AccessFlags<T>> void specify(StructuralSpecification<T, ?> spec) {
+ spec.withInt(a -> a.originalFlags).withInt(a -> a.modifiedFlags);
+ }
+
+ @Override
+ public StructuralAccept<T> getStructuralAccept() {
+ return AccessFlags::specify;
+ }
+
public abstract T copy();
public abstract T self();
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
index 237838f..fc764ff 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
@@ -5,18 +5,35 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.utils.structural.StructuralAccept;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
-public class DexAnnotationElement extends DexItem {
+public class DexAnnotationElement extends DexItem implements StructuralItem<DexAnnotationElement> {
public static final DexAnnotationElement[] EMPTY_ARRAY = {};
public final DexString name;
public final DexValue value;
+ private static void specify(StructuralSpecification<DexAnnotationElement, ?> spec) {
+ spec.withItem(e -> e.name).withItem(e -> e.value);
+ }
+
public DexAnnotationElement(DexString name, DexValue value) {
this.name = name;
this.value = value;
}
+ @Override
+ public DexAnnotationElement self() {
+ return this;
+ }
+
+ @Override
+ public StructuralAccept<DexAnnotationElement> getStructuralAccept() {
+ return DexAnnotationElement::specify;
+ }
+
public DexValue getValue() {
return value;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
index 051dd92..bcefcd2 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -6,11 +6,14 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.utils.structural.StructuralAccept;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Function;
-public class DexEncodedAnnotation extends DexItem {
+public class DexEncodedAnnotation extends DexItem implements StructuralItem<DexEncodedAnnotation> {
private static final int UNSORTED = 0;
@@ -19,11 +22,25 @@
private int sorted = UNSORTED;
+ private static void specify(StructuralSpecification<DexEncodedAnnotation, ?> spec) {
+ spec.withItem(a -> a.type).withItemArray(a -> a.elements);
+ }
+
public DexEncodedAnnotation(DexType type, DexAnnotationElement[] elements) {
this.type = type;
this.elements = elements;
}
+ @Override
+ public DexEncodedAnnotation self() {
+ return this;
+ }
+
+ @Override
+ public StructuralAccept<DexEncodedAnnotation> getStructuralAccept() {
+ return DexEncodedAnnotation::specify;
+ }
+
public void collectIndexedItems(IndexedItemCollection indexedItems) {
type.collectIndexedItems(indexedItems);
for (DexAnnotationElement element : elements) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 5f58f30..133ebe5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -20,8 +20,12 @@
import com.android.tools.r8.ir.optimize.info.MutableFieldOptimizationInfo;
import com.android.tools.r8.kotlin.KotlinFieldLevelInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.structural.StructuralAccept;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
-public class DexEncodedField extends DexEncodedMember<DexEncodedField, DexField> {
+public class DexEncodedField extends DexEncodedMember<DexEncodedField, DexField>
+ implements StructuralItem<DexEncodedField> {
public static final DexEncodedField[] EMPTY_ARRAY = {};
public final DexField field;
@@ -34,6 +38,16 @@
private FieldOptimizationInfo optimizationInfo = DefaultFieldOptimizationInfo.getInstance();
private KotlinFieldLevelInfo kotlinMemberInfo = NO_KOTLIN_INFO;
+ private static void specify(StructuralSpecification<DexEncodedField, ?> spec) {
+ spec.withItem(f -> f.field)
+ .withItem(f -> f.accessFlags)
+ .withNullableItem(f -> f.staticValue)
+ .withBool(f -> f.deprecated)
+ // TODO(b/171867022): The generic signature should be part of the definition.
+ .withAssert(f -> f.genericSignature.hasNoSignature());
+ // TODO(b/171867022): Should the optimization info and member info be part of the definition?
+ }
+
public DexEncodedField(
DexField field,
FieldAccessFlags accessFlags,
@@ -60,6 +74,16 @@
this(field, accessFlags, genericSignature, annotations, staticValue, false);
}
+ @Override
+ public StructuralAccept<DexEncodedField> getStructuralAccept() {
+ return DexEncodedField::specify;
+ }
+
+ @Override
+ public DexEncodedField self() {
+ return this;
+ }
+
public DexType type() {
return field.type;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexReference.java b/src/main/java/com/android/tools/r8/graph/DexReference.java
index d32c7ba..8a59614 100644
--- a/src/main/java/com/android/tools/r8/graph/DexReference.java
+++ b/src/main/java/com/android/tools/r8/graph/DexReference.java
@@ -63,7 +63,7 @@
return null;
}
- private int referenceTypeOrder() {
+ public int referenceTypeOrder() {
if (isDexType()) {
return 1;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
index e4462ac..595c5dd 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -7,12 +7,10 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.ArrayUtils;
-import com.android.tools.r8.utils.structural.CompareToVisitor;
-import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralAccept;
import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import com.google.common.collect.Iterators;
import java.util.Arrays;
import java.util.Collection;
@@ -27,6 +25,10 @@
public final DexType[] values;
+ private static void specify(StructuralSpecification<DexTypeList, ?> spec) {
+ spec.withItemArray(ts -> ts.values);
+ }
+
public static DexTypeList empty() {
return theEmptyTypeList;
}
@@ -52,12 +54,6 @@
return values.isEmpty() ? DexTypeList.empty() : new DexTypeList(values);
}
- @Override
- public StructuralAccept<DexTypeList> getStructuralAccept() {
- // Structural accept is never accessed as all accept methods are defined directly.
- throw new Unreachable();
- }
-
public DexTypeList keepIf(Predicate<DexType> predicate) {
DexType[] filtered = ArrayUtils.filter(DexType[].class, values, predicate);
if (filtered != values) {
@@ -76,13 +72,8 @@
}
@Override
- public void acceptCompareTo(DexTypeList other, CompareToVisitor visitor) {
- visitor.visitDexTypeList(this, other);
- }
-
- @Override
- public void acceptHashing(HashingVisitor visitor) {
- visitor.visitDexTypeList(this);
+ public StructuralAccept<DexTypeList> getStructuralAccept() {
+ return DexTypeList::specify;
}
public boolean contains(DexType type) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index 273c69a..a54daf8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -23,12 +23,16 @@
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.EncodedValueUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
+import com.android.tools.r8.utils.structural.StructuralAccept;
+import com.android.tools.r8.utils.structural.StructuralItem;
import java.util.Arrays;
import java.util.function.Consumer;
import org.objectweb.asm.Handle;
import org.objectweb.asm.Type;
-public abstract class DexValue extends DexItem {
+public abstract class DexValue extends DexItem implements StructuralItem<DexValue> {
public enum DexValueKind {
BYTE(0x00),
@@ -104,6 +108,41 @@
}
}
+ @Override
+ public DexValue self() {
+ return this;
+ }
+
+ @Override
+ public final StructuralAccept<DexValue> getStructuralAccept() {
+ // DexValue is not generic at its base type (and can't as we use it as a polymorphic value),
+ // so each concrete value must implement polymorphic accept functions. This base class
+ // implements (most of) the polymorphic checks and concrete types implement the internal
+ // variants for that type.
+ throw new Unreachable();
+ }
+
+ @Override
+ public final void acceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ // Order first on 'kind', only equal kinds then forward to the 'kind' specific internal compare.
+ if (getValueKind() != other.getValueKind()) {
+ visitor.visitInt(getValueKind().toByte(), other.getValueKind().toByte());
+ } else {
+ internalAcceptCompareTo(other, visitor);
+ }
+ }
+
+ @Override
+ public final void acceptHashing(HashingVisitor visitor) {
+ // Always hash the 'kind' which ensures that raw values of different type are distinct.
+ visitor.visitInt(getValueKind().toByte());
+ internalAcceptHashing(visitor);
+ }
+
+ abstract void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor);
+
+ abstract void internalAcceptHashing(HashingVisitor visitor);
+
public static final DexValue[] EMPTY_ARRAY = {};
public abstract DexValueKind getValueKind();
@@ -438,6 +477,16 @@
return value == DEFAULT.value ? DEFAULT : new DexValueByte(value);
}
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitInt(value, other.asDexValueByte().value);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(value);
+ }
+
public byte getValue() {
return value;
}
@@ -521,6 +570,16 @@
return value == DEFAULT.value ? DEFAULT : new DexValueShort(value);
}
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(value);
+ }
+
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitInt(value, other.asDexValueShort().getValue());
+ }
+
public short getValue() {
return value;
}
@@ -603,6 +662,16 @@
return value == DEFAULT.value ? DEFAULT : new DexValueChar(value);
}
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitInt(value, other.asDexValueChar().value);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(value);
+ }
+
public char getValue() {
return value;
}
@@ -689,6 +758,16 @@
return value == DEFAULT.value ? DEFAULT : new DexValueInt(value);
}
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(value);
+ }
+
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitInt(value, other.asDexValueInt().value);
+ }
+
public int getValue() {
return value;
}
@@ -771,6 +850,16 @@
return value == DEFAULT.value ? DEFAULT : new DexValueLong(value);
}
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitLong(value, other.asDexValueLong().value);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitLong(value);
+ }
+
public long getValue() {
return value;
}
@@ -853,6 +942,16 @@
return Float.compare(value, DEFAULT.value) == 0 ? DEFAULT : new DexValueFloat(value);
}
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitFloat(value);
+ }
+
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitFloat(value, other.asDexValueFloat().value);
+ }
+
public float getValue() {
return value;
}
@@ -941,6 +1040,16 @@
return Double.compare(value, DEFAULT.value) == 0 ? DEFAULT : new DexValueDouble(value);
}
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitDouble(value, other.asDexValueDouble().value);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitDouble(value);
+ }
+
public double getValue() {
return value;
}
@@ -1087,6 +1196,18 @@
}
@Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ value.acceptHashing(visitor);
+ }
+
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ if (DexItemBasedValueString.compareAndCheckValueStrings(this, other, visitor)) {
+ value.acceptCompareTo(other.asDexValueString().value, visitor);
+ }
+ }
+
+ @Override
public void collectIndexedItems(IndexedItemCollection indexedItems) {
value.collectIndexedItems(indexedItems);
}
@@ -1143,6 +1264,20 @@
public static class DexItemBasedValueString extends NestedDexValue<DexReference> {
+ // Helper to ensure a consistent order on DexValueString and DexItemBasedValueString which are
+ // both defined to have kind 'string'.
+ static boolean compareAndCheckValueStrings(DexValue v1, DexValue v2, CompareToVisitor visitor) {
+ assert v1.getValueKind() == DexValueKind.STRING;
+ assert v2.getValueKind() == DexValueKind.STRING;
+ int order1 = v1.isDexItemBasedValueString() ? 1 : 0;
+ int order2 = v2.isDexItemBasedValueString() ? 1 : 0;
+ boolean equal = order1 == order2;
+ if (!equal) {
+ visitor.visitInt(order1, order2);
+ }
+ return equal;
+ }
+
private final NameComputationInfo<?> nameComputationInfo;
public DexItemBasedValueString(DexReference value, NameComputationInfo<?> nameComputationInfo) {
@@ -1151,6 +1286,18 @@
}
@Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitDexReference(value);
+ }
+
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ if (compareAndCheckValueStrings(this, other, visitor)) {
+ visitor.visitDexReference(value, other.asDexItemBasedValueString().value);
+ }
+ }
+
+ @Override
public void collectIndexedItems(IndexedItemCollection indexedItems) {
value.collectIndexedItems(indexedItems);
}
@@ -1221,6 +1368,16 @@
}
@Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ value.acceptCompareTo(other.asDexValueType().value, visitor);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ value.acceptHashing(visitor);
+ }
+
+ @Override
public DexValueKind getValueKind() {
return DexValueKind.TYPE;
}
@@ -1253,6 +1410,16 @@
}
@Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ value.acceptCompareTo(other.asDexValueField().value, visitor);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ value.acceptHashing(visitor);
+ }
+
+ @Override
public DexValueKind getValueKind() {
return DexValueKind.FIELD;
}
@@ -1285,6 +1452,16 @@
}
@Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ value.acceptCompareTo(other.asDexValueMethod().value, visitor);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ value.acceptHashing(visitor);
+ }
+
+ @Override
public DexValueKind getValueKind() {
return DexValueKind.METHOD;
}
@@ -1317,6 +1494,16 @@
}
@Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ value.acceptCompareTo(other.asDexValueEnum().value, visitor);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ value.acceptHashing(visitor);
+ }
+
+ @Override
public DexValueKind getValueKind() {
return DexValueKind.ENUM;
}
@@ -1349,6 +1536,16 @@
}
@Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ value.acceptCompareTo(other.asDexValueMethodType().value, visitor);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ value.acceptHashing(visitor);
+ }
+
+ @Override
public boolean isDexValueMethodType() {
return true;
}
@@ -1382,6 +1579,16 @@
this.values = values;
}
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitItemArray(values, other.asDexValueArray().values);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitItemArray(values);
+ }
+
public void forEachElement(Consumer<DexValue> consumer) {
for (DexValue value : values) {
consumer.accept(value);
@@ -1481,6 +1688,16 @@
this.value = value;
}
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ value.acceptCompareTo(other.asDexValueAnnotation().value, visitor);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ value.acceptHashing(visitor);
+ }
+
public DexEncodedAnnotation getValue() {
return value;
}
@@ -1567,6 +1784,17 @@
private DexValueNull() {
}
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ assert this == NULL;
+ }
+
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ assert this == NULL;
+ assert other == NULL;
+ }
+
public Object getValue() {
return null;
}
@@ -1653,6 +1881,16 @@
return value ? TRUE : FALSE;
}
+ @Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ visitor.visitBool(value, other.asDexValueBoolean().value);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitBool(value);
+ }
+
public boolean getValue() {
return value;
}
@@ -1729,6 +1967,16 @@
}
@Override
+ void internalAcceptCompareTo(DexValue other, CompareToVisitor visitor) {
+ value.acceptCompareTo(other.asDexValueMethodHandle().value, visitor);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ value.acceptHashing(visitor);
+ }
+
+ @Override
public boolean isDexValueMethodHandle() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java
index 832d172..47d8669 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitor.java
@@ -5,10 +5,14 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.Comparator;
+import java.util.Iterator;
/** Base class for a visitor implementing compareTo on a structural item. */
public abstract class CompareToVisitor {
@@ -17,13 +21,30 @@
public abstract void visitInt(int value1, int value2);
+ public abstract void visitLong(long value1, long value2);
+
+ public abstract void visitFloat(float value1, float value2);
+
+ public abstract void visitDouble(double value1, double value2);
+
+ /** Base for visiting an enumeration of items. */
+ protected abstract <S> void visitItemIterator(
+ Iterator<S> it1, Iterator<S> it2, CompareToAccept<S> compareToAccept);
+
+ public final <S extends StructuralItem<S>> void visitItemArray(S[] items1, S[] items2) {
+ visitItemCollection(Arrays.asList(items1), Arrays.asList(items2));
+ }
+
+ public final <S extends StructuralItem<S>> void visitItemCollection(
+ Collection<S> items1, Collection<S> items2) {
+ visitItemIterator(items1.iterator(), items2.iterator(), S::acceptCompareTo);
+ }
+
public abstract void visitDexString(
DexString string1, DexString string2, Comparator<DexString> comparator);
public abstract void visitDexType(DexType type1, DexType type2);
- public abstract void visitDexTypeList(DexTypeList types1, DexTypeList types2);
-
public void visitDexField(DexField field1, DexField field2) {
visit(field1, field2, field1.getStructuralAccept());
}
@@ -32,6 +53,8 @@
visit(method1, method2, method1.getStructuralAccept());
}
+ public abstract void visitDexReference(DexReference reference1, DexReference reference2);
+
public abstract <S> void visit(S item1, S item2, StructuralAccept<S> accept);
@Deprecated
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java
index b7d016a..3526dfb 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java
@@ -3,11 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils.structural;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
import java.util.Comparator;
+import java.util.Iterator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
@@ -44,6 +45,38 @@
}
@Override
+ public void visitLong(long value1, long value2) {
+ if (stillEqual()) {
+ setOrder(Long.compare(value1, value2));
+ }
+ }
+
+ @Override
+ public void visitFloat(float value1, float value2) {
+ if (stillEqual()) {
+ setOrder(Float.compare(value1, value2));
+ }
+ }
+
+ @Override
+ public void visitDouble(double value1, double value2) {
+ if (stillEqual()) {
+ setOrder(Double.compare(value1, value2));
+ }
+ }
+
+ @Override
+ protected <S> void visitItemIterator(
+ Iterator<S> it1, Iterator<S> it2, CompareToAccept<S> compareToAccept) {
+ while (stillEqual() && it1.hasNext() && it2.hasNext()) {
+ compareToAccept.accept(it1.next(), it2.next(), this);
+ }
+ if (stillEqual()) {
+ visitBool(it1.hasNext(), it2.hasNext());
+ }
+ }
+
+ @Override
public final void visitDexString(
DexString string1, DexString string2, Comparator<DexString> comparator) {
if (stillEqual()) {
@@ -52,15 +85,18 @@
}
@Override
- public final void visitDexTypeList(DexTypeList types1, DexTypeList types2) {
- // Comparison is lexicographic with comparisons between items prior to the length of the lists.
+ public void visitDexReference(DexReference reference1, DexReference reference2) {
if (stillEqual()) {
- int length = Math.min(types1.size(), types2.size());
- for (int i = 0; i < length && stillEqual(); i++) {
- visitDexType(types1.values[i], types2.values[i]);
- }
+ visitInt(reference1.referenceTypeOrder(), reference2.referenceTypeOrder());
if (stillEqual()) {
- visitInt(types1.size(), types2.size());
+ assert reference1.getClass() == reference2.getClass();
+ if (reference1.isDexType()) {
+ visitDexType(reference1.asDexType(), reference2.asDexType());
+ } else if (reference1.isDexField()) {
+ visitDexField(reference1.asDexField(), reference2.asDexField());
+ } else {
+ visitDexMethod(reference1.asDexMethod(), reference2.asDexMethod());
+ }
}
}
}
@@ -128,5 +164,14 @@
}
return this;
}
+
+ @Override
+ protected <S> ItemSpecification<T> withItemIterator(
+ Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) {
+ if (parent.stillEqual()) {
+ parent.visitItemIterator(getter.apply(item1), getter.apply(item2), compare);
+ }
+ return this;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
index ab75fb4..8038e48 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
+import java.util.Iterator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
@@ -64,9 +65,19 @@
if (predicate.test(item)) {
return amend(getter.apply(item).hashCode());
} else {
- // Use the value 1 for the failing-predicate case such that a different hash is obtained for
+ // Use the value 1 for the failing-predicate case such that a different hash is obtained for,
// eg, {null, null} and {null}.
return amend(1);
}
}
+
+ @Override
+ protected <S> HashCodeVisitor<T> withItemIterator(
+ Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) {
+ Iterator<S> it = getter.apply(item);
+ while (it.hasNext()) {
+ amend(it.next().hashCode());
+ }
+ return this;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitor.java
index bfd5e0d..ed0f61e 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitor.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitor.java
@@ -3,10 +3,16 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils.structural;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
import com.google.common.hash.Hasher;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.function.BiConsumer;
public abstract class HashingVisitor {
@@ -15,11 +21,38 @@
public abstract void visitInt(int value);
+ public abstract void visitFloat(float value);
+
+ public abstract void visitLong(long value);
+
+ public abstract void visitDouble(double value);
+
+ /** Base for visiting an enumeration of items. */
+ protected abstract <S> void visitItemIterator(Iterator<S> it, HashingAccept<S> hashingAccept);
+
+ public final <S extends StructuralItem<S>> void visitItemArray(S[] items) {
+ visitItemCollection(Arrays.asList(items));
+ }
+
+ public final <S extends StructuralItem<S>> void visitItemCollection(Collection<S> items) {
+ visitItemIterator(items.iterator(), S::acceptHashing);
+ }
+
public abstract void visitDexString(DexString string);
public abstract void visitDexType(DexType type);
- public abstract void visitDexTypeList(DexTypeList types);
+ public void visitDexField(DexField field) {
+ visit(field, field.getStructuralAccept());
+ }
+
+ public void visitDexMethod(DexMethod method) {
+ visit(method, method.getStructuralAccept());
+ }
+
+ public void visitDexReference(DexReference reference) {
+ reference.accept(this::visitDexType, this::visitDexField, this::visitDexMethod);
+ }
public abstract <S> void visit(S item, StructuralAccept<S> accept);
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
index 2036b1b..d216cd9 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
@@ -5,10 +5,10 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
import com.google.common.hash.Hasher;
+import java.util.Iterator;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -46,6 +46,21 @@
}
@Override
+ public void visitFloat(float value) {
+ hash.putFloat(value);
+ }
+
+ @Override
+ public void visitLong(long value) {
+ hash.putLong(value);
+ }
+
+ @Override
+ public void visitDouble(double value) {
+ hash.putDouble(value);
+ }
+
+ @Override
public void visitDexString(DexString string) {
visitInt(string.hashCode());
}
@@ -56,13 +71,15 @@
}
@Override
- public void visitDexTypeList(DexTypeList types) {
- types.forEach(this::visitDexType);
+ public <S> void visit(S item, StructuralAccept<S> accept) {
+ accept.accept(new ItemSpecification<>(item, this));
}
@Override
- public <S> void visit(S item, StructuralAccept<S> accept) {
- accept.accept(new ItemSpecification<>(item, this));
+ protected <S> void visitItemIterator(Iterator<S> it, HashingAccept<S> hashingAccept) {
+ while (it.hasNext()) {
+ hashingAccept.accept(it.next(), this);
+ }
}
@Override
@@ -113,5 +130,12 @@
}
return this;
}
+
+ @Override
+ protected <S> ItemSpecification<T> withItemIterator(
+ Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) {
+ parent.visitItemIterator(getter.apply(item), hasher);
+ return this;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java b/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
index bb8f7c7..b80d95a 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
@@ -5,6 +5,9 @@
import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToIntFunction;
@@ -12,12 +15,12 @@
public abstract class StructuralSpecification<T, V extends StructuralSpecification<T, V>> {
/**
- * Basic specification for visiting an item.
+ * Base for accessing and visiting a sub-part on an item.
*
- * <p>This specified the getter for the item as well as all of the methods that are required for
- * visiting. Those coincide with the requirements of Specified.
+ * <p>This specifies the getter for the sub-part as well as all of the methods that are required
+ * for visiting. The required methods coincide with the requirements of StructuralItem.
*
- * <p>It is preferable to use withStructuralItem.
+ * <p>It is preferable to use withItem and make the item itself implement StructuralItem.
*/
@Deprecated
public final <S> V withCustomItem(
@@ -25,12 +28,17 @@
return withConditionalCustomItem(t -> true, getter, compare, hasher);
}
+ /** Base implementation for visiting an item. */
protected abstract <S> V withConditionalCustomItem(
Predicate<T> predicate,
Function<T, S> getter,
CompareToAccept<S> compare,
HashingAccept<S> hasher);
+ /** Base implementation for visiting an enumeration of items. */
+ protected abstract <S> V withItemIterator(
+ Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher);
+
/**
* Specification for a "specified" item.
*
@@ -41,7 +49,7 @@
return withConditionalItem(t -> true, getter);
}
- final <S extends StructuralItem<S>> V withNullableItem(Function<T, S> getter) {
+ public final <S extends StructuralItem<S>> V withNullableItem(Function<T, S> getter) {
return withConditionalItem(s -> getter.apply(s) != null, getter);
}
@@ -50,6 +58,17 @@
return withConditionalCustomItem(predicate, getter, S::acceptCompareTo, S::acceptHashing);
}
+ public final <S extends StructuralItem<S>> V withItemCollection(
+ Function<T, Collection<S>> getter) {
+ return withItemIterator(
+ getter.andThen(Collection::iterator), S::acceptCompareTo, S::acceptHashing);
+ }
+
+ public final <S extends StructuralItem<S>> V withItemArray(Function<T, S[]> getter) {
+ return withItemIterator(
+ getter.andThen(a -> Arrays.asList(a).iterator()), S::acceptCompareTo, S::acceptHashing);
+ }
+
/**
* Helper to declare an assert on the item.
*