Add an interner for non source artifacts that are deserialized.
PiperOrigin-RevId: 202311773
diff --git a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
index a974646..a27756e 100644
--- a/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
+++ b/src/main/java/com/google/devtools/build/lib/actions/Artifact.java
@@ -22,6 +22,8 @@
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
@@ -53,6 +55,7 @@
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+import java.util.concurrent.ExecutionException;
import javax.annotation.Nullable;
/**
@@ -152,6 +155,9 @@
/** A Predicate that evaluates to true if the Artifact is not a middleman artifact. */
public static final Predicate<Artifact> MIDDLEMAN_FILTER = input -> !input.isMiddlemanArtifact();
+ private static final Cache<InternedArtifact, Artifact> ARTIFACT_INTERNER =
+ CacheBuilder.newBuilder().weakValues().build();
+
private final int hashCode;
private final ArtifactRoot root;
private final PathFragment execPath;
@@ -177,11 +183,24 @@
+ ")");
}
PathFragment rootExecPath = root.getExecPath();
- return new Artifact(
+ Artifact artifact = new Artifact(
root,
rootExecPath.isEmpty() ? rootRelativePath : rootExecPath.getRelative(rootRelativePath),
rootRelativePath,
owner);
+ if (artifact.isSourceArtifact()) {
+ return artifact;
+ } else {
+ return intern(artifact);
+ }
+ }
+
+ private static Artifact intern(Artifact artifact) {
+ try {
+ return ARTIFACT_INTERNER.get(new InternedArtifact(artifact), () -> artifact);
+ } catch (ExecutionException e) {
+ throw new IllegalStateException(e);
+ }
}
/**
@@ -583,6 +602,34 @@
}
/**
+ * Wraps an artifact for interning because we need to check the artifact owner when doing equals.
+ */
+ private static final class InternedArtifact {
+ private final Artifact wrappedArtifact;
+
+ InternedArtifact(Artifact artifact) {
+ this.wrappedArtifact = artifact;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof InternedArtifact)) {
+ return false;
+ }
+ if (!getClass().equals(other.getClass())) {
+ return false;
+ }
+ InternedArtifact that = (InternedArtifact) other;
+ return Artifact.equalWithOwner(wrappedArtifact, that.wrappedArtifact);
+ }
+
+ @Override
+ public final int hashCode() {
+ return wrappedArtifact.hashCode();
+ }
+ }
+
+ /**
* Returns the relative path to this artifact relative to its root. (Useful
* when deriving output filenames from input files, etc.)
*/