| // Copyright (c) 2020, 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.utils.structural; |
| |
| 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.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; |
| import java.util.function.ToDoubleFunction; |
| import java.util.function.ToIntFunction; |
| import java.util.function.ToLongFunction; |
| |
| /** Visitor for hashing a structural item under some assumed type equivalence. */ |
| public class HashingVisitorWithTypeEquivalence extends HashingVisitor { |
| |
| public static <T> void run( |
| T item, Hasher hasher, RepresentativeMap map, StructuralMapping<T> accept) { |
| run(item, hasher, map, (i, visitor) -> visitor.visit(i, accept)); |
| } |
| |
| public static <T> void run( |
| T item, Hasher hasher, RepresentativeMap map, HashingAccept<T> hashingAccept) { |
| hashingAccept.acceptHashing(item, new HashingVisitorWithTypeEquivalence(hasher, map)); |
| } |
| |
| private final Hasher hash; |
| private final RepresentativeMap representatives; |
| |
| private HashingVisitorWithTypeEquivalence(Hasher hash, RepresentativeMap representatives) { |
| this.hash = hash; |
| this.representatives = representatives; |
| } |
| |
| @Override |
| public void visitBool(boolean value) { |
| hash.putBoolean(value); |
| } |
| |
| @Override |
| public void visitInt(int value) { |
| hash.putInt(value); |
| } |
| |
| @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) { |
| hash.putBytes(string.content); |
| } |
| |
| @Override |
| public void visitDexType(DexType type) { |
| visitDexString(representatives.getRepresentative(type).getDescriptor()); |
| } |
| |
| @Override |
| public <S> void visit(S item, StructuralMapping<S> accept) { |
| accept.apply(new ItemSpecification<>(item, this)); |
| } |
| |
| @Override |
| protected <S> void visitItemIterator(Iterator<S> it, HashingAccept<S> hashingAccept) { |
| while (it.hasNext()) { |
| hashingAccept.acceptHashing(it.next(), this); |
| } |
| } |
| |
| @Override |
| public <S> void visit(S item, BiConsumer<S, Hasher> hasher) { |
| hasher.accept(item, hash); |
| } |
| |
| private static class ItemSpecification<T> |
| extends StructuralSpecification<T, ItemSpecification<T>> { |
| |
| private final HashingVisitorWithTypeEquivalence parent; |
| private final T item; |
| |
| private ItemSpecification(T item, HashingVisitorWithTypeEquivalence parent) { |
| this.item = item; |
| this.parent = parent; |
| } |
| |
| @Override |
| ItemSpecification<T> self() { |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withAssert(Predicate<T> predicate) { |
| assert predicate.test(item); |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withBool(Predicate<T> getter) { |
| parent.visitBool(getter.test(item)); |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withInt(ToIntFunction<T> getter) { |
| parent.visitInt(getter.applyAsInt(item)); |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withLong(ToLongFunction<T> getter) { |
| parent.visitLong(getter.applyAsLong(item)); |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withDouble(ToDoubleFunction<T> getter) { |
| parent.visitDouble(getter.applyAsDouble(item)); |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withIntArray(Function<T, int[]> getter) { |
| int[] ints = getter.apply(item); |
| for (int i = 0; i < ints.length; i++) { |
| parent.visitInt(ints[i]); |
| } |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withShortArray(Function<T, short[]> getter) { |
| short[] ints = getter.apply(item); |
| for (int i = 0; i < ints.length; i++) { |
| parent.visitInt(ints[i]); |
| } |
| return this; |
| } |
| |
| @Override |
| protected <S> ItemSpecification<T> withConditionalCustomItem( |
| Predicate<T> predicate, |
| Function<T, S> getter, |
| CompareToAccept<S> compare, |
| HashingAccept<S> hasher) { |
| boolean test = predicate.test(item); |
| // Always hash the predicate result to distinguish, eg, {null, null} and {null}. |
| parent.visitBool(test); |
| if (test) { |
| hasher.acceptHashing(getter.apply(item), parent); |
| } |
| return this; |
| } |
| |
| @Override |
| protected <S> ItemSpecification<T> withCustomItemIterator( |
| Function<T, Iterator<S>> getter, CompareToAccept<S> compare, HashingAccept<S> hasher) { |
| parent.visitItemIterator(getter.apply(item), hasher); |
| return this; |
| } |
| |
| @Override |
| public ItemSpecification<T> withDexReference(Function<T, DexReference> getter) { |
| parent.visitDexReference(getter.apply(item)); |
| return this; |
| } |
| } |
| } |