Clean up API for the Extension class
RELNOTES: None
PiperOrigin-RevId: 155507750
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
index 52d00e3..5569a64 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/AspectFunction.java
@@ -116,7 +116,7 @@
return null;
}
- Object skylarkValue = skylarkImportLookupValue.getEnvironmentExtension()
+ Object skylarkValue = skylarkImportLookupValue.getEnvironmentExtension().getBindings()
.get(skylarkValueName);
if (!(skylarkValue instanceof SkylarkAspect)) {
throw new ConversionException(
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
index e4801bc..1dc11eb 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
@@ -17,6 +17,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.cmdline.Label;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.events.EventHandler;
import com.google.devtools.build.lib.events.EventKind;
@@ -285,62 +286,56 @@
}
}
- // TODO(bazel-team): Fix this scary failure of serializability.
- // skyframe.SkylarkImportLookupFunction processes a .bzl and returns an Extension,
- // for use by whoever imports the .bzl file. Skyframe may subsequently serialize the results.
- // And it will fail to process these bindings, because they are inherited from a non-serializable
- // class (in previous versions of the code the serializable SkylarkEnvironment was inheriting
- // from the non-serializable Environment and being returned by said Function).
- // If we try to merge this otherwise redundant superclass into Extension, though,
- // skyframe experiences a massive failure to serialize things, and it's unclear how far
- // reaching the need to make things Serializable goes, though clearly we'll need to make
- // a whole lot of things Serializable, and for efficiency, we'll want to implement sharing
- // of imported values rather than a code explosion.
+ // TODO(bazel-team): Eliminate this hack around Java serialization. The bindings are currently
+ // factored out into BaseExtension, which is non-Serializable, and which has a default constructor
+ // that does not initialize any bindings. This means that when Extension is Java-serialized, all
+ // the bindings are simply lost.
private static class BaseExtension {
- final ImmutableMap<String, Object> bindings;
- BaseExtension(Environment env) {
- this.bindings = ImmutableMap.copyOf(env.globalFrame.bindings);
+
+ protected final ImmutableMap<String, Object> bindings;
+
+ BaseExtension(Map<String, Object> bindings) {
+ this.bindings = ImmutableMap.copyOf(bindings);
}
- // Hack to allow serialization.
+ // Hack to "allow" java serialization.
BaseExtension() {
this.bindings = ImmutableMap.of();
}
}
- /**
- * An Extension to be imported with load() into a BUILD or .bzl file.
- */
+ /** An Extension to be imported with load() into a BUILD or .bzl file. */
+ @Immutable
public static final class Extension extends BaseExtension implements Serializable {
+ /**
+ * Cached hash code for the transitive content of this {@code Extension} and its dependencies.
+ */
private final String transitiveContentHashCode;
/**
- * Constructs an Extension by extracting the new global definitions from an Environment.
- * Also caches a hash code for the transitive content of the file and its dependencies.
- * @param env the Environment from which to extract an Extension.
+ * Constructs with the given hash code and bindings.
+ */
+ public Extension(Map<String, Object> bindings, String transitiveContentHashCode) {
+ super(bindings);
+ this.transitiveContentHashCode = transitiveContentHashCode;
+ }
+
+ /**
+ * Constructs using the bindings from the global definitions of the given {@link Environment},
+ * and that {@code Environment}'s transitive hash code.
*/
public Extension(Environment env) {
- super(env);
+ super(env.globalFrame.bindings);
this.transitiveContentHashCode = env.getTransitiveContentHashCode();
}
- String getTransitiveContentHashCode() {
+ public String getTransitiveContentHashCode() {
return transitiveContentHashCode;
}
- /** get the value bound to a variable in this Extension */
- public Object get(String varname) {
- return bindings.get(varname);
- }
-
- /** does this Extension contain a binding for the named variable? */
- public boolean containsKey(String varname) {
- return bindings.containsKey(varname);
- }
-
- public Set<String> allKeys() {
- return bindings.keySet();
+ public ImmutableMap<String, Object> getBindings() {
+ return bindings;
}
}
@@ -866,11 +861,12 @@
Extension ext = importedExtensions.get(importString);
- if (!ext.containsKey(nameInLoadedFile)) {
- throw new LoadFailedException(importString, nameInLoadedFile, ext.allKeys());
+ Map<String, Object> bindings = ext.getBindings();
+ if (!bindings.containsKey(nameInLoadedFile)) {
+ throw new LoadFailedException(importString, nameInLoadedFile, bindings.keySet());
}
- Object value = ext.get(nameInLoadedFile);
+ Object value = bindings.get(nameInLoadedFile);
try {
update(symbol.getName(), value);