blob: 4803ae22966eb43867646307b0fdece21e4e4024 [file] [log] [blame]
Damien Martin-Guillerezf88f4d82015-09-25 13:56:55 +00001// Copyright 2014 The Bazel Authors. All rights reserved.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +01002//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package com.google.devtools.build.lib.skyframe;
16
tomlua155b532017-11-08 20:12:47 +010017import com.google.common.base.Preconditions;
janakr573807d2018-01-11 14:02:35 -080018import com.google.common.collect.Interner;
jhorvitz3daedc32020-07-22 18:33:55 -070019import com.google.devtools.build.lib.actions.ActionLookupKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010020import com.google.devtools.build.lib.analysis.ConfiguredTarget;
21import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
Lukacs Berki6e91eb92015-09-21 09:12:37 +000022import com.google.devtools.build.lib.cmdline.Label;
janakr573807d2018-01-11 14:02:35 -080023import com.google.devtools.build.lib.concurrent.BlazeInterners;
janakr1b787692018-02-13 12:53:31 -080024import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec;
jcater0985ad72020-07-14 05:22:21 -070025import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec.VisibleForSerialization;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010026import com.google.devtools.build.skyframe.SkyFunctionName;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010027import java.util.Objects;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010028import javax.annotation.Nullable;
29
30/**
janakr3863b532018-01-11 15:49:42 -080031 * A (Label, Configuration key) pair. Note that this pair may be used to look up the generating
32 * action of an artifact.
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010033 */
jhorvitz3daedc32020-07-22 18:33:55 -070034// TODO(janakr): Intern deserialized instances.
35public class ConfiguredTargetKey implements ActionLookupKey {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010036 private final Label label;
janakr192c8902018-01-19 22:29:42 -080037 @Nullable private final BuildConfigurationValue.Key configurationKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010038
janakr573807d2018-01-11 14:02:35 -080039 private transient int hashCode;
40
jcater8e08aa3f2020-05-29 11:27:59 -070041 ConfiguredTargetKey(Label label, @Nullable BuildConfigurationValue.Key configurationKey) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010042 this.label = Preconditions.checkNotNull(label);
janakr3863b532018-01-11 15:49:42 -080043 this.configurationKey = configurationKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010044 }
45
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010046 @Override
jcaterdf1a96e2020-06-03 14:28:46 -070047 public final Label getLabel() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010048 return label;
49 }
50
51 @Override
jcaterdf1a96e2020-06-03 14:28:46 -070052 public final SkyFunctionName functionName() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010053 return SkyFunctions.CONFIGURED_TARGET;
54 }
55
56 @Nullable
jcaterdf1a96e2020-06-03 14:28:46 -070057 final BuildConfigurationValue.Key getConfigurationKey() {
janakr3863b532018-01-11 15:49:42 -080058 return configurationKey;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010059 }
60
jcaterdf1a96e2020-06-03 14:28:46 -070061 @Nullable
62 ToolchainContextKey getToolchainContextKey() {
63 return null;
64 }
65
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010066 @Override
jcaterdf1a96e2020-06-03 14:28:46 -070067 public final int hashCode() {
janakr573807d2018-01-11 14:02:35 -080068 // We use the hash code caching strategy employed by java.lang.String. There are three subtle
69 // things going on here:
70 //
71 // (1) We use a value of 0 to indicate that the hash code hasn't been computed and cached yet.
72 // Yes, this means that if the hash code is really 0 then we will "recompute" it each time. But
73 // this isn't a problem in practice since a hash code of 0 should be rare.
74 //
75 // (2) Since we have no synchronization, multiple threads can race here thinking there are the
76 // first one to compute and cache the hash code.
77 //
78 // (3) Moreover, since 'hashCode' is non-volatile, the cached hash code value written from one
79 // thread may not be visible by another.
80 //
81 // All three of these issues are benign from a correctness perspective; in the end we have no
82 // overhead from synchronization, at the cost of potentially computing the hash code more than
83 // once.
84 int h = hashCode;
85 if (h == 0) {
86 h = computeHashCode();
87 hashCode = h;
88 }
89 return h;
90 }
91
jhorvitz3daedc32020-07-22 18:33:55 -070092 private int computeHashCode() {
janakr3863b532018-01-11 15:49:42 -080093 int configVal = configurationKey == null ? 79 : configurationKey.hashCode();
jcaterdf1a96e2020-06-03 14:28:46 -070094 int toolchainContextVal =
95 getToolchainContextKey() == null ? 47 : getToolchainContextKey().hashCode();
96 return 31 * label.hashCode() + configVal + toolchainContextVal;
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +010097 }
98
99 @Override
jcaterdf1a96e2020-06-03 14:28:46 -0700100 public final boolean equals(Object obj) {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100101 if (this == obj) {
102 return true;
103 }
104 if (obj == null) {
105 return false;
106 }
107 if (!(obj instanceof ConfiguredTargetKey)) {
108 return false;
109 }
110 ConfiguredTargetKey other = (ConfiguredTargetKey) obj;
jcater6be63162020-05-28 09:29:22 -0700111 return Objects.equals(label, other.label)
jcaterdf1a96e2020-06-03 14:28:46 -0700112 && Objects.equals(configurationKey, other.configurationKey)
113 && Objects.equals(getToolchainContextKey(), other.getToolchainContextKey());
janakr3863b532018-01-11 15:49:42 -0800114 }
115
jcaterdf1a96e2020-06-03 14:28:46 -0700116 public final String prettyPrint() {
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100117 if (label == null) {
118 return "null";
119 }
jcater6be63162020-05-28 09:29:22 -0700120 return label.toString();
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100121 }
122
123 @Override
jcaterdf1a96e2020-06-03 14:28:46 -0700124 public final String toString() {
125 if (getToolchainContextKey() != null) {
126 return String.format("%s %s %s", label, configurationKey, getToolchainContextKey());
127 }
jcater6be63162020-05-28 09:29:22 -0700128 return String.format("%s %s", label, configurationKey);
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100129 }
jcater3eb2d252020-05-28 10:39:12 -0700130
jcater0985ad72020-07-14 05:22:21 -0700131 @AutoCodec
jcaterdf1a96e2020-06-03 14:28:46 -0700132 static class ConfiguredTargetKeyWithToolchainContext extends ConfiguredTargetKey {
133 private final ToolchainContextKey toolchainContextKey;
134
jcater0985ad72020-07-14 05:22:21 -0700135 @VisibleForSerialization
136 ConfiguredTargetKeyWithToolchainContext(
jcaterdf1a96e2020-06-03 14:28:46 -0700137 Label label,
138 @Nullable BuildConfigurationValue.Key configurationKey,
139 ToolchainContextKey toolchainContextKey) {
140 super(label, configurationKey);
141 this.toolchainContextKey = toolchainContextKey;
142 }
143
144 @Override
145 @Nullable
146 final ToolchainContextKey getToolchainContextKey() {
147 return toolchainContextKey;
148 }
149 }
150
jcater3eb2d252020-05-28 10:39:12 -0700151 /** Returns a new {@link Builder} to create instances of {@link ConfiguredTargetKey}. */
152 public static Builder builder() {
153 return new Builder();
154 }
155
156 /**
157 * Caches so that the number of ConfiguredTargetKey instances is {@code O(configured targets)} and
158 * not {@code O(edges between configured targets)}.
159 */
160 private static final Interner<ConfiguredTargetKey> interner = BlazeInterners.newWeakInterner();
161
jcaterdf1a96e2020-06-03 14:28:46 -0700162 private static final Interner<ConfiguredTargetKeyWithToolchainContext>
163 withToolchainContextInterner = BlazeInterners.newWeakInterner();
164
jcater3eb2d252020-05-28 10:39:12 -0700165 /** A helper class to create instances of {@link ConfiguredTargetKey}. */
166 public static class Builder {
jcater3eb2d252020-05-28 10:39:12 -0700167 private Label label = null;
168 private BuildConfigurationValue.Key configurationKey = null;
jcaterdf1a96e2020-06-03 14:28:46 -0700169 private ToolchainContextKey toolchainContextKey = null;
jcater3eb2d252020-05-28 10:39:12 -0700170
171 /** Sets the label for the target. */
172 public Builder setLabel(Label label) {
173 this.label = label;
174 return this;
175 }
176
177 /**
178 * Sets the {@link ConfiguredTarget} that we want a key for.
179 *
180 * <p>This sets both the label and configurationKey data.
181 */
182 public Builder setConfiguredTarget(ConfiguredTarget configuredTarget) {
183 setLabel(configuredTarget.getOriginalLabel());
184 if (this.configurationKey == null) {
185 setConfigurationKey(configuredTarget.getConfigurationKey());
186 }
187 return this;
188 }
189
190 /** Sets the {@link BuildConfiguration} for the configured target. */
191 public Builder setConfiguration(@Nullable BuildConfiguration buildConfiguration) {
192 if (buildConfiguration == null) {
193 return setConfigurationKey(null);
194 } else {
195 return setConfigurationKey(BuildConfigurationValue.key(buildConfiguration));
196 }
197 }
198
199 /** Sets the configuration key for the configured target. */
200 public Builder setConfigurationKey(@Nullable BuildConfigurationValue.Key configurationKey) {
201 this.configurationKey = configurationKey;
202 return this;
203 }
204
jcaterdf1a96e2020-06-03 14:28:46 -0700205 /**
206 * Sets the {@link ToolchainContextKey} this configured target should use for toolchain
207 * resolution. When present, this overrides the normally determined toolchain context.
208 */
209 public Builder setToolchainContextKey(ToolchainContextKey toolchainContextKey) {
210 this.toolchainContextKey = toolchainContextKey;
211 return this;
212 }
213
jcater3eb2d252020-05-28 10:39:12 -0700214 /** Builds a new {@link ConfiguredTargetKey} based on the supplied data. */
215 public ConfiguredTargetKey build() {
jcaterdf1a96e2020-06-03 14:28:46 -0700216 if (this.toolchainContextKey != null) {
217 return withToolchainContextInterner.intern(
218 new ConfiguredTargetKeyWithToolchainContext(
219 label, configurationKey, toolchainContextKey));
220 }
jcater3eb2d252020-05-28 10:39:12 -0700221 return interner.intern(new ConfiguredTargetKey(label, configurationKey));
222 }
223 }
Han-Wen Nienhuysd08b27f2015-02-25 16:45:20 +0100224}