Move content-based field in Artifact to DerivedArtifact: SourceArtifact has 3 other fields without this one (root, execPath, and hashCode), so this boolean costs 8 bytes per Artifact per[]
Also mark a bunch of Artifact methods final and group them together.
PiperOrigin-RevId: 315810015
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 93a23c1..65265cc 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
@@ -251,8 +251,6 @@
}
}
- public static final ImmutableList<Artifact> NO_ARTIFACTS = ImmutableList.of();
-
/** A Predicate that evaluates to true if the Artifact is not a middleman artifact. */
public static final Predicate<Artifact> MIDDLEMAN_FILTER = input -> !input.isMiddlemanArtifact();
@@ -260,15 +258,7 @@
private final ArtifactRoot root;
private final PathFragment execPath;
- /**
- * Content-based output paths are experimental. Only derived artifacts that are explicitly opted
- * in by their creating rules should use them and only when {@link
- * com.google.devtools.build.lib.analysis.config.BuildConfiguration#useContentBasedOutputPaths} is
- * on.
- */
- private final boolean contentBasedPath;
-
- private Artifact(ArtifactRoot root, PathFragment execPath, boolean contentBasedPath) {
+ private Artifact(ArtifactRoot root, PathFragment execPath) {
Preconditions.checkNotNull(root);
// The ArtifactOwner is not part of this computation because it is very rare that two Artifacts
// have the same execPath and different owners, so a collision is fine there. If this is
@@ -276,7 +266,6 @@
this.hashCode = execPath.hashCode();
this.root = root;
this.execPath = execPath;
- this.contentBasedPath = contentBasedPath;
}
/**
@@ -294,7 +283,7 @@
@Immutable
public static final class NinjaMysteryArtifact extends Artifact {
public NinjaMysteryArtifact(ArtifactRoot root, PathFragment execPath) {
- super(root, execPath, false);
+ super(root, execPath);
}
@Override
@@ -335,6 +324,14 @@
*/
private Object owner;
+ /**
+ * Content-based output paths are experimental. Only derived artifacts that are explicitly opted
+ * in by their creating rules should use them and only when {@link
+ * com.google.devtools.build.lib.analysis.config.BuildConfiguration#useContentBasedOutputPaths}
+ * is on.
+ */
+ private final boolean contentBasedPath;
+
/** Standard constructor for derived artifacts. */
public DerivedArtifact(ArtifactRoot root, PathFragment execPath, ActionLookupKey owner) {
this(root, execPath, owner, /*contentBasedPath=*/ false);
@@ -347,10 +344,11 @@
*/
public DerivedArtifact(
ArtifactRoot root, PathFragment execPath, ActionLookupKey owner, boolean contentBasedPath) {
- super(root, execPath, contentBasedPath);
+ super(root, execPath);
Preconditions.checkState(
!root.getExecPath().isEmpty(), "Derived root has no exec path: %s, %s", root, execPath);
this.owner = owner;
+ this.contentBasedPath = contentBasedPath;
}
/**
@@ -358,7 +356,7 @@
* must have the same owner as this artifact's current {@link #getArtifactOwner}.
*/
@VisibleForTesting
- public void setGeneratingActionKey(ActionLookupData generatingActionKey) {
+ public final void setGeneratingActionKey(ActionLookupData generatingActionKey) {
Preconditions.checkState(
this.owner instanceof ArtifactOwner,
"Already set generating action key: %s (%s %s)",
@@ -375,35 +373,35 @@
}
@VisibleForTesting
- public boolean hasGeneratingActionKey() {
+ public final boolean hasGeneratingActionKey() {
return this.owner instanceof ActionLookupData;
}
/** Can only be called once {@link #setGeneratingActionKey} is called. */
- public ActionLookupData getGeneratingActionKey() {
+ public final ActionLookupData getGeneratingActionKey() {
Preconditions.checkState(owner instanceof ActionLookupData, "Bad owner: %s %s", this, owner);
return (ActionLookupData) owner;
}
@Override
- public ActionLookupValue.ActionLookupKey getArtifactOwner() {
+ public final ActionLookupValue.ActionLookupKey getArtifactOwner() {
return owner instanceof ActionLookupData
? getGeneratingActionKey().getActionLookupKey()
: (ActionLookupKey) owner;
}
@Override
- public Label getOwnerLabel() {
+ public final Label getOwnerLabel() {
return getArtifactOwner().getLabel();
}
@Override
- public PathFragment getRootRelativePath() {
+ public final PathFragment getRootRelativePath() {
return getExecPath().relativeTo(getRoot().getExecPath());
}
@Override
- boolean ownersEqual(Artifact other) {
+ final boolean ownersEqual(Artifact other) {
DerivedArtifact that = (DerivedArtifact) other;
if (!(this.owner instanceof ActionLookupData) || !(that.owner instanceof ActionLookupData)) {
// Happens when at least one of these artifacts hasn't had its generating action key set
@@ -412,6 +410,11 @@
}
return this.owner.equals(that.owner);
}
+
+ @Override
+ public boolean contentBasedPath() {
+ return contentBasedPath;
+ }
}
@SuppressWarnings("unused") // Codec used by reflection.
@@ -523,12 +526,12 @@
}
@Override
- public String filePathForFileTypeMatcher() {
+ public final String filePathForFileTypeMatcher() {
return getExecPath().filePathForFileTypeMatcher();
}
@Override
- public String expandToCommandLine() {
+ public final String expandToCommandLine() {
return getExecPathString();
}
@@ -563,9 +566,25 @@
return execPath;
}
+ /**
+ * Returns the relative path to this artifact relative to its root. (Useful when deriving output
+ * filenames from input files, etc.)
+ */
+ public abstract PathFragment getRootRelativePath();
+
+ /** Returns this.getExecPath().getPathString(). */
+ @Override
+ public final String getExecPathString() {
+ return getExecPath().getPathString();
+ }
+
+ public final String getRootRelativePathString() {
+ return getRootRelativePath().getPathString();
+ }
+
@Override
public boolean contentBasedPath() {
- return contentBasedPath;
+ return false;
}
@Override
@@ -667,6 +686,85 @@
return false;
}
+ /**
+ * For targets in external repositories, this returns the path the artifact live at in the
+ * runfiles tree. For local targets, it returns the rootRelativePath.
+ */
+ public final PathFragment getRunfilesPath() {
+ PathFragment relativePath = getRootRelativePath();
+ if (relativePath.startsWith(LabelConstants.EXTERNAL_PATH_PREFIX)) {
+ // Turn external/repo/foo into ../repo/foo.
+ relativePath = relativePath.relativeTo(LabelConstants.EXTERNAL_PATH_PREFIX);
+ relativePath = PathFragment.create("..").getRelative(relativePath);
+ }
+ return relativePath;
+ }
+
+ @Override
+ public final String getRunfilesPathString() {
+ return getRunfilesPath().getPathString();
+ }
+
+ public final String prettyPrint() {
+ // toDetailString would probably be more useful to users, but lots of tests rely on the
+ // current values.
+ return getRootRelativePath().toString();
+ }
+
+ @SuppressWarnings("EqualsGetClass") // Distinct classes of Artifact are never equal.
+ @Override
+ public final boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof Artifact)) {
+ return false;
+ }
+ if (!getClass().equals(other.getClass())) {
+ return false;
+ }
+ Artifact that = (Artifact) other;
+ return equalsWithoutOwner(that) && ownersEqual(that);
+ }
+
+ final boolean equalsWithoutOwner(Artifact other) {
+ return hashCode == other.hashCode && execPath.equals(other.execPath) && root.equals(other.root);
+ }
+
+ abstract boolean ownersEqual(Artifact other);
+
+ @Override
+ public final int hashCode() {
+ // This is just execPath.hashCode() (along with the class). We cache a copy in the Artifact
+ // object to reduce LLC misses during operations which build a HashSet out of many Artifacts.
+ // This is a slight loss for memory but saves ~1% overall CPU in some real builds.
+ return hashCode;
+ }
+
+ @Override
+ public final String toString() {
+ return "File:" + toDetailString();
+ }
+
+ /** Returns a string representing the complete artifact path information. */
+ public final String toDetailString() {
+ if (isSourceArtifact()) {
+ // Source Artifact: relPath == execPath, & real path is not under execRoot
+ return "[" + root + "]" + getRootRelativePathString();
+ } else {
+ // Derived Artifact: path and root are under execRoot
+ //
+ // TODO(blaze-team): this is misleading because execution_root isn't unique. Dig the
+ // workspace name out and print that also.
+ return "[[<execution_root>]" + root.getExecPath() + "]" + getRootRelativePathString();
+ }
+ }
+
+ @Override
+ public final SkyFunctionName functionName() {
+ return ARTIFACT;
+ }
+
/** {@link Artifact#isSourceArtifact() is true.
*
* <p>Source artifacts have the property that unlike for output artifacts, direct file system
@@ -679,7 +777,7 @@
@VisibleForTesting
public SourceArtifact(ArtifactRoot root, PathFragment execPath, ArtifactOwner owner) {
- super(root, execPath, /*contentBasedPath=*/ false);
+ super(root, execPath);
this.owner = owner;
}
@@ -759,7 +857,7 @@
}
@Override
- public final boolean isFileset() {
+ public boolean isFileset() {
return type == SpecialArtifactType.FILESET;
}
@@ -986,100 +1084,6 @@
}
}
- /**
- * Returns the relative path to this artifact relative to its root. (Useful when deriving output
- * filenames from input files, etc.)
- */
- public abstract PathFragment getRootRelativePath();
-
- /**
- * For targets in external repositories, this returns the path the artifact live at in the
- * runfiles tree. For local targets, it returns the rootRelativePath.
- */
- public final PathFragment getRunfilesPath() {
- PathFragment relativePath = getRootRelativePath();
- if (relativePath.startsWith(LabelConstants.EXTERNAL_PATH_PREFIX)) {
- // Turn external/repo/foo into ../repo/foo.
- relativePath = relativePath.relativeTo(LabelConstants.EXTERNAL_PATH_PREFIX);
- relativePath = PathFragment.create("..").getRelative(relativePath);
- }
- return relativePath;
- }
-
- @Override
- public final String getRunfilesPathString() {
- return getRunfilesPath().getPathString();
- }
-
- /**
- * Returns this.getExecPath().getPathString().
- */
- @Override
- public final String getExecPathString() {
- return getExecPath().getPathString();
- }
-
- public final String getRootRelativePathString() {
- return getRootRelativePath().getPathString();
- }
-
- public final String prettyPrint() {
- // toDetailString would probably be more useful to users, but lots of tests rely on the
- // current values.
- return getRootRelativePath().toString();
- }
-
- @SuppressWarnings("EqualsGetClass") // Distinct classes of Artifact are never equal.
- @Override
- public final boolean equals(Object other) {
- if (this == other) {
- return true;
- }
- if (!(other instanceof Artifact)) {
- return false;
- }
- if (!getClass().equals(other.getClass())) {
- return false;
- }
- Artifact that = (Artifact) other;
- return equalsWithoutOwner(that) && ownersEqual(that);
- }
-
- final boolean equalsWithoutOwner(Artifact other) {
- return hashCode == other.hashCode && execPath.equals(other.execPath) && root.equals(other.root);
- }
-
- abstract boolean ownersEqual(Artifact other);
-
- @Override
- public final int hashCode() {
- // This is just execPath.hashCode() (along with the class). We cache a copy in the Artifact
- // object to reduce LLC misses during operations which build a HashSet out of many Artifacts.
- // This is a slight loss for memory but saves ~1% overall CPU in some real builds.
- return hashCode;
- }
-
- @Override
- public final String toString() {
- return "File:" + toDetailString();
- }
-
- /**
- * Returns a string representing the complete artifact path information.
- */
- public final String toDetailString() {
- if (isSourceArtifact()) {
- // Source Artifact: relPath == execPath, & real path is not under execRoot
- return "[" + root + "]" + getRootRelativePathString();
- } else {
- // Derived Artifact: path and root are under execRoot
- //
- // TODO(blaze-team): this is misleading because execution_root isn't unique. Dig the
- // workspace name out and print that also.
- return "[[<execution_root>]" + root.getExecPath() + "]" + getRootRelativePathString();
- }
- }
-
/** {@link ObjectCodec} for {@link SourceArtifact} */
@SuppressWarnings("unused") // found by CLASSPATH-scanning magic
private static class SourceArtifactCodec implements ObjectCodec<SourceArtifact> {
@@ -1204,11 +1208,13 @@
}
/**
- * Adds a collection of artifacts to a given collection, with
- * {@link MiddlemanType#AGGREGATING_MIDDLEMAN} middleman actions expanded once.
+ * Adds a collection of artifacts to a given collection, with {@link
+ * MiddlemanType#AGGREGATING_MIDDLEMAN} middleman actions expanded once.
*/
- public static void addExpandedArtifacts(Iterable<Artifact> artifacts,
- Collection<? super Artifact> output, ArtifactExpander artifactExpander) {
+ static void addExpandedArtifacts(
+ Iterable<Artifact> artifacts,
+ Collection<? super Artifact> output,
+ ArtifactExpander artifactExpander) {
addExpandedArtifacts(artifacts, output, Functions.<Artifact>identity(), artifactExpander);
}
@@ -1320,9 +1326,4 @@
.toString();
}
}
-
- @Override
- public SkyFunctionName functionName() {
- return ARTIFACT;
- }
}