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);