| // 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.synthesis; |
| |
| import com.android.tools.r8.features.ClassToFeatureSplitMap; |
| import com.android.tools.r8.graph.AppView; |
| import com.android.tools.r8.graph.DexClass; |
| import com.android.tools.r8.graph.DexType; |
| import com.android.tools.r8.graph.lens.GraphLens; |
| import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind; |
| import com.android.tools.r8.utils.structural.HasherWrapper; |
| import com.android.tools.r8.utils.structural.RepresentativeMap; |
| import com.google.common.hash.HashCode; |
| |
| /** |
| * Base type for the definition of a synthetic item. |
| * |
| * <p>This class is internal to the synthetic items collection, thus package-protected. |
| */ |
| abstract class SyntheticDefinition< |
| R extends SyntheticReference<R, D, C>, |
| D extends SyntheticDefinition<R, D, C>, |
| C extends DexClass> { |
| |
| private final SyntheticKind kind; |
| private final SynthesizingContext context; |
| |
| SyntheticDefinition(SyntheticKind kind, SynthesizingContext context) { |
| assert kind != null; |
| assert context != null; |
| this.kind = kind; |
| this.context = context; |
| } |
| |
| public boolean isClasspathDefinition() { |
| return false; |
| } |
| |
| public SyntheticClasspathDefinition asClasspathDefinition() { |
| return null; |
| } |
| |
| public boolean isProgramDefinition() { |
| return false; |
| } |
| |
| public SyntheticProgramDefinition asProgramDefinition() { |
| return null; |
| } |
| |
| abstract R toReference(); |
| |
| final SyntheticKind getKind() { |
| return kind; |
| } |
| |
| final SynthesizingContext getContext() { |
| return context; |
| } |
| |
| final String getPrefixForExternalSyntheticType(AppView<?> appView) { |
| if (!appView.options().intermediate && context.isSyntheticInputClass() && !kind.isGlobal()) { |
| // If the input class was a synthetic and the build is non-intermediate, unwind the synthetic |
| // name back to the original context (if present in the textual type). |
| return SyntheticNaming.getOuterContextFromExternalSyntheticType( |
| getKind(), getHolder().getType()); |
| } |
| return SyntheticNaming.getPrefixForExternalSyntheticType(getKind(), getHolder().getType()); |
| } |
| |
| public abstract C getHolder(); |
| |
| final HashCode computeHash( |
| RepresentativeMap map, |
| boolean intermediate, |
| ClassToFeatureSplitMap classToFeatureSplitMap, |
| SyntheticItems syntheticItems) { |
| HasherWrapper hasher = HasherWrapper.murmur3128Hasher(); |
| hasher.putInt(kind.getId()); |
| if (!getKind().isShareable()) { |
| // Non-shareable synthetics should use its assumed unique type as the hash. |
| getHolder().getType().hash(hasher); |
| return hasher.hash(); |
| } |
| if (intermediate) { |
| // If in intermediate mode, include the context type as sharing is restricted to within a |
| // single context. |
| getContext().getSynthesizingContextType().hashWithTypeEquivalence(hasher, map); |
| } |
| hasher.putInt(context.getFeatureSplit().hashCode()); |
| internalComputeHash(hasher, map); |
| return hasher.hash(); |
| } |
| |
| abstract void internalComputeHash(HasherWrapper hasher, RepresentativeMap map); |
| |
| final boolean isEquivalentTo( |
| D other, |
| boolean includeContext, |
| GraphLens graphLens, |
| ClassToFeatureSplitMap classToFeatureSplitMap) { |
| return compareTo(other, includeContext, graphLens, classToFeatureSplitMap) == 0; |
| } |
| |
| int compareTo( |
| D other, |
| boolean includeContext, |
| GraphLens graphLens, |
| ClassToFeatureSplitMap classToFeatureSplitMap) { |
| { |
| int order = kind.compareTo(other.getKind()); |
| if (order != 0) { |
| return order; |
| } |
| } |
| DexType thisType = getHolder().getType(); |
| DexType otherType = other.getHolder().getType(); |
| if (!getKind().isShareable()) { |
| return thisType.compareTo(otherType); |
| } |
| if (includeContext) { |
| int order = getContext().compareTo(other.getContext()); |
| if (order != 0) { |
| return order; |
| } |
| } |
| if (getContext().getFeatureSplit() != other.getContext().getFeatureSplit()) { |
| int order = |
| classToFeatureSplitMap.compareFeatureSplits( |
| context.getFeatureSplit(), other.getContext().getFeatureSplit()); |
| assert order != 0; |
| return order; |
| } |
| RepresentativeMap map = null; |
| // If the synthetics have been moved include the original types in the equivalence. |
| if (graphLens.isNonIdentityLens()) { |
| DexType thisOrigType = graphLens.getOriginalType(thisType); |
| DexType otherOrigType = graphLens.getOriginalType(otherType); |
| if (thisType != thisOrigType || otherType != otherOrigType) { |
| map = |
| t -> { |
| if (t == otherType || t == thisOrigType || t == otherOrigType) { |
| return thisType; |
| } |
| return t; |
| }; |
| } |
| } |
| if (map == null) { |
| map = t -> t == otherType ? thisType : t; |
| } |
| return internalCompareTo(other, map); |
| } |
| |
| abstract int internalCompareTo(D other, RepresentativeMap map); |
| |
| public abstract boolean isValid(); |
| } |