blob: 00c6b1006c5c6583c32a2435d9fe2521c8e96ef1 [file] [log] [blame]
// 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.
return context.getSynthesizingContextType().toBinaryName();
}
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 *input* context type to restrict sharing.
// This restricts sharing to only allow sharing the synthetics with the same *input* context.
// If the synthetic is itself an input from a previous compilation it is restricted to share
// within its own context only. The input context should not be mapped to an equivalence type.
getContext().getSynthesizingInputContext(intermediate).hash(hasher);
}
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.isNotIdenticalTo(thisOrigType) || otherType.isNotIdenticalTo(otherOrigType)) {
map =
t -> {
if (DexType.identical(t, otherType)
|| DexType.identical(t, thisOrigType)
|| DexType.identical(t, otherOrigType)) {
return thisType;
}
return t;
};
}
}
if (map == null) {
map = t -> otherType.isIdenticalTo(t) ? thisType : t;
}
return internalCompareTo(other, map);
}
abstract int internalCompareTo(D other, RepresentativeMap map);
public abstract boolean isValid();
}