COMPILER SHARDING: Make generated artifacts serializable so that they can be passed across processes from Precompile to Link. Review by: bobv git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@3741 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/Artifact.java b/dev/core/src/com/google/gwt/core/ext/linker/Artifact.java index f5fe286..a54eaea 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/Artifact.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/Artifact.java
@@ -17,6 +17,8 @@ import com.google.gwt.core.ext.Linker; +import java.io.Serializable; + /** * A base type for all artifacts relating to the link process. In order to * ensure stable output between runs of the compiler, Artifact types must @@ -27,8 +29,9 @@ * to. */ public abstract class Artifact<C extends Artifact<C>> implements - Comparable<Artifact<?>> { - private final Class<? extends Linker> linker; + Comparable<Artifact<?>>, Serializable { + private final String linkerName; + private transient Class<? extends Linker> linker; /** * Constructor. @@ -37,6 +40,7 @@ */ protected Artifact(Class<? extends Linker> linker) { assert linker != null; + this.linkerName = linker.getName(); this.linker = linker; } @@ -65,6 +69,17 @@ * Returns the Linker that created the Artifact. */ public final Class<? extends Linker> getLinker() { + // linker is null when deserialized. + if (linker == null) { + try { + Class<?> clazz = Class.forName(linkerName, false, + Thread.currentThread().getContextClassLoader()); + linker = clazz.asSubclass(Linker.class); + } catch (ClassNotFoundException e) { + // The class may not be available. + linker = Linker.class; + } + } return linker; }
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/ArtifactSet.java b/dev/core/src/com/google/gwt/core/ext/linker/ArtifactSet.java index c04ad6d..96435bc 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/ArtifactSet.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/ArtifactSet.java
@@ -15,6 +15,7 @@ */ package com.google.gwt.core.ext.linker; +import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -25,7 +26,7 @@ /** * Provides stable ordering and de-duplication of artifacts. */ -public final class ArtifactSet implements SortedSet<Artifact<?>> { +public final class ArtifactSet implements SortedSet<Artifact<?>>, Serializable { private SortedSet<Artifact<?>> treeSet = new TreeSet<Artifact<?>>();
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/GeneratedResource.java b/dev/core/src/com/google/gwt/core/ext/linker/GeneratedResource.java index 28c9400..3bb8000 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/GeneratedResource.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/GeneratedResource.java
@@ -24,11 +24,13 @@ * during the compilation process. */ public abstract class GeneratedResource extends EmittedArtifact { - private final Class<? extends Generator> generatorType; + private final String generatorTypeName; + private transient Class<? extends Generator> generatorType; protected GeneratedResource(Class<? extends Linker> linkerType, Class<? extends Generator> generatorType, String partialPath) { super(linkerType, partialPath); + this.generatorTypeName = generatorType.getName(); this.generatorType = generatorType; } @@ -36,6 +38,17 @@ * The type of Generator that created the resource. */ public final Class<? extends Generator> getGenerator() { + // generatorType is null when deserialized. + if (generatorType == null) { + try { + Class<?> clazz = Class.forName(generatorTypeName, false, + Thread.currentThread().getContextClassLoader()); + generatorType = clazz.asSubclass(Generator.class); + } catch (ClassNotFoundException e) { + // The class may not be available. + generatorType = Generator.class; + } + } return generatorType; } }
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationResult.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationResult.java index 9a99727..89b4492 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationResult.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardCompilationResult.java
@@ -22,6 +22,7 @@ import com.google.gwt.dev.util.Util; import java.io.File; +import java.io.Serializable; import java.lang.ref.SoftReference; import java.util.Collections; import java.util.Comparator; @@ -37,11 +38,8 @@ */ public class StandardCompilationResult extends CompilationResult { - /** - * Smaller maps come before larger maps, then we compare the concatenation of - * every value. - */ - public static final Comparator<SortedMap<SelectionProperty, String>> MAP_COMPARATOR = new Comparator<SortedMap<SelectionProperty, String>>() { + private static final class MapComparator implements + Comparator<SortedMap<SelectionProperty, String>>, Serializable { public int compare(SortedMap<SelectionProperty, String> arg0, SortedMap<SelectionProperty, String> arg1) { int diff = arg0.size() - arg1.size(); @@ -64,10 +62,16 @@ return sb0.toString().compareTo(sb1.toString()); } - }; + } + + /** + * Smaller maps come before larger maps, then we compare the concatenation of + * every value. + */ + public static final Comparator<SortedMap<SelectionProperty, String>> MAP_COMPARATOR = new MapComparator(); private final File cacheFile; - private SoftReference<String> js; + private transient SoftReference<String> js; private final SortedSet<SortedMap<SelectionProperty, String>> propertyValues = new TreeSet<SortedMap<SelectionProperty, String>>( MAP_COMPARATOR); private final String strongName; @@ -93,7 +97,10 @@ } public String getJavaScript() { - String toReturn = js.get(); + String toReturn = null; + if (js != null) { + toReturn = js.get(); + } if (toReturn == null) { toReturn = Util.readFileAsString(cacheFile); js = new SoftReference<String>(toReturn);
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java index 401b1b8..2a1a0bd 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardPublicResource.java
@@ -19,13 +19,37 @@ import com.google.gwt.core.ext.UnableToCompleteException; import com.google.gwt.core.ext.linker.PublicResource; import com.google.gwt.dev.resource.Resource; +import com.google.gwt.dev.util.Util; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; +import java.io.Serializable; /** * The standard implementation of {@link PublicResource}. */ public class StandardPublicResource extends PublicResource { + + /** + * Serializes a public resource via a snapshot of the content. + */ + private static final class SerializedPublicResource extends PublicResource { + private final byte[] data; + + protected SerializedPublicResource(String partialPath, byte[] data) { + super(StandardLinkerContext.class, partialPath); + this.data = data; + } + + @Override + public InputStream getContents(TreeLogger logger) + throws UnableToCompleteException { + return new ByteArrayInputStream(data); + } + } + private final Resource resource; public StandardPublicResource(String partialPath, Resource resource) { @@ -38,4 +62,18 @@ throws UnableToCompleteException { return resource.openContents(); } + + private Object writeReplace() { + if (resource instanceof Serializable) { + return this; + } + // Resource is not serializable, must replace myself. + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Util.copy(resource.openContents(), baos); + return new SerializedPublicResource(getPartialPath(), baos.toByteArray()); + } catch (IOException e) { + throw new RuntimeException(e); + } + } }
diff --git a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSelectionProperty.java b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSelectionProperty.java index 14972c1..5f71786 100644 --- a/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSelectionProperty.java +++ b/dev/core/src/com/google/gwt/core/ext/linker/impl/StandardSelectionProperty.java
@@ -40,8 +40,7 @@ activeValue = null; } name = p.getName(); - provider = p.getProvider() == null ? null - : p.getProvider().getBody().toSource(); + provider = p.getProvider() == null ? null : p.getProvider().getBody(); values = Collections.unmodifiableSortedSet(new TreeSet<String>( Arrays.asList(p.getDefinedValues()))); }
diff --git a/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java b/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java deleted file mode 100644 index b6f0e77..0000000 --- a/dev/core/src/com/google/gwt/dev/cfg/DefaultPropertyProvider.java +++ /dev/null
@@ -1,67 +0,0 @@ -/* - * Copyright 2006 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy of - * the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations under - * the License. - */ -package com.google.gwt.dev.cfg; - -import com.google.gwt.dev.js.JsParser; -import com.google.gwt.dev.js.JsParserException; -import com.google.gwt.dev.js.ast.JsBlock; -import com.google.gwt.dev.js.ast.JsExprStmt; -import com.google.gwt.dev.js.ast.JsFunction; -import com.google.gwt.dev.js.ast.JsProgram; -import com.google.gwt.dev.js.ast.JsStatement; - -import java.io.IOException; -import java.io.StringReader; -import java.util.List; - -/** - * A property provider that reports property values specified literally in a - * host HTML page. - */ -public class DefaultPropertyProvider extends PropertyProvider { - - /* - * TODO: this references 'parent' literally, which could be a problem if you - * were to include the selector script in the host page itself rather than in - * an iframe. - */ - public DefaultPropertyProvider(ModuleDef module, Property property) { - super(module, property); - String src = "function () {"; - src += "return __gwt_getMetaProperty(\""; - src += property.getName(); - src += "\"); }"; - setBody(parseFunction(src)); - } - - private JsBlock parseFunction(String jsniSrc) { - Throwable caught = null; - try { - JsProgram jsPgm = new JsProgram(); - JsParser jsParser = new JsParser(); - StringReader r = new StringReader(jsniSrc); - List<JsStatement> stmts = jsParser.parse(jsPgm.getScope(), r, 1); - JsFunction fn = (JsFunction) ((JsExprStmt) stmts.get(0)).getExpression(); - return fn.getBody(); - } catch (IOException e) { - caught = e; - } catch (JsParserException e) { - caught = e; - } - throw new RuntimeException( - "Internal error parsing source for default property provider", caught); - } -}
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java index 405e93c..3d6efb6 100644 --- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java +++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -408,7 +408,11 @@ * one possible value and no existing provider. */ if (prop.getProvider() == null && prop.getAllowedValues().length > 1) { - prop.setProvider(new DefaultPropertyProvider(this, prop)); + String src = "{"; + src += "return __gwt_getMetaProperty(\""; + src += prop.getName(); + src += "\"); }"; + prop.setProvider(new PropertyProvider(src)); } } }
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java index b7b9a5d..a0c2e94 100644 --- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java +++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefSchema.java
@@ -214,7 +214,6 @@ } protected Schema __property_provider_begin(BindingProperty property) { - property.setProvider(new PropertyProvider(moduleDef, property)); return fChild = new PropertyProviderBodySchema(); } @@ -233,7 +232,7 @@ int lineNumber = childSchema.getStartLineNumber(); JsFunction fn = parseJsBlock(lineNumber, script); - property.getProvider().setBody(fn.getBody()); + property.setProvider(new PropertyProvider(fn.getBody().toSource())); } protected Schema __public_begin(String path, String includes,
diff --git a/dev/core/src/com/google/gwt/dev/cfg/Property.java b/dev/core/src/com/google/gwt/dev/cfg/Property.java index ad30a8b..5615672 100644 --- a/dev/core/src/com/google/gwt/dev/cfg/Property.java +++ b/dev/core/src/com/google/gwt/dev/cfg/Property.java
@@ -15,10 +15,12 @@ */ package com.google.gwt.dev.cfg; +import java.io.Serializable; + /** * Represents an abstract module property. */ -public abstract class Property implements Comparable<Property> { +public abstract class Property implements Comparable<Property>, Serializable { protected final String name;
diff --git a/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java b/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java index 13c44d6..55f5f17 100644 --- a/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java +++ b/dev/core/src/com/google/gwt/dev/cfg/PropertyProvider.java
@@ -1,5 +1,5 @@ /* - * Copyright 2006 Google Inc. + * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -15,36 +15,20 @@ */ package com.google.gwt.dev.cfg; -import com.google.gwt.dev.js.ast.JsBlock; +import java.io.Serializable; /** * Produces a deferred binding property value by executing JavaScript code. */ -public class PropertyProvider { +public class PropertyProvider implements Serializable { - private JsBlock body; + private final String body; - private final ModuleDef module; - private final Property property; - - public PropertyProvider(ModuleDef module, Property property) { - this.module = module; - this.property = property; - } - - public JsBlock getBody() { - return body; - } - - public ModuleDef getModule() { - return module; - } - - public Property getProperty() { - return property; - } - - public void setBody(JsBlock body) { + public PropertyProvider(String body) { this.body = body; } + + public String getBody() { + return body; + } }
diff --git a/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java b/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java index f501fd2..d0cb379 100644 --- a/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java +++ b/dev/core/src/com/google/gwt/dev/cfg/StaticPropertyOracle.java
@@ -19,11 +19,13 @@ import com.google.gwt.core.ext.PropertyOracle; import com.google.gwt.core.ext.TreeLogger; +import java.io.Serializable; + /** * An implementation of {@link PropertyOracle} that contains property values, * rather than computing them. */ -public class StaticPropertyOracle implements PropertyOracle { +public class StaticPropertyOracle implements PropertyOracle, Serializable { private final ConfigurationProperty[] configProps;
diff --git a/dev/core/src/com/google/gwt/dev/util/Util.java b/dev/core/src/com/google/gwt/dev/util/Util.java index 6f3d637..aabd864 100644 --- a/dev/core/src/com/google/gwt/dev/util/Util.java +++ b/dev/core/src/com/google/gwt/dev/util/Util.java
@@ -40,11 +40,14 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.io.Reader; +import java.io.Serializable; import java.io.StringWriter; import java.io.UnsupportedEncodingException; import java.lang.reflect.Array; @@ -140,6 +143,19 @@ return toHexString(md5.digest()); } + public static void copy(InputStream is, OutputStream os) throws IOException { + try { + byte[] buf = new byte[8 * 1024]; + int i; + while ((i = is.read(buf)) != -1) { + os.write(buf, 0, i); + } + } finally { + Utility.close(is); + Utility.close(os); + } + } + public static boolean copy(TreeLogger logger, File in, File out) throws UnableToCompleteException { try { @@ -548,6 +564,43 @@ return null; } + public static <T extends Serializable> T readFileAsObject(File file, + Class<T> type) throws ClassNotFoundException { + FileInputStream fileInputStream = null; + ObjectInputStream objectInputStream = null; + try { + fileInputStream = new FileInputStream(file); + objectInputStream = new ObjectInputStream(fileInputStream); + return type.cast(objectInputStream.readObject()); + } catch (IOException e) { + return null; + } finally { + Utility.close(objectInputStream); + Utility.close(fileInputStream); + } + } + + public static Serializable[] readFileAsObjects(File file, + Class<? extends Serializable>... types) throws ClassNotFoundException { + FileInputStream fileInputStream = null; + ObjectInputStream objectInputStream = null; + try { + fileInputStream = new FileInputStream(file); + objectInputStream = new ObjectInputStream(fileInputStream); + Serializable[] results = new Serializable[types.length]; + for (int i = 0; i < results.length; ++i) { + Object object = objectInputStream.readObject(); + results[i] = types[i].cast(object); + } + return results; + } catch (IOException e) { + return null; + } finally { + Utility.close(objectInputStream); + Utility.close(fileInputStream); + } + } + public static String readFileAsString(File file) { byte[] bytes = readFileAsBytes(file); if (bytes != null) { @@ -974,24 +1027,26 @@ } } - public static void writeStringAsFile(TreeLogger logger, File file, - String string) throws UnableToCompleteException { + /** + * Serializes an object and writes it to a file. + */ + public static void writeObjectAsFile(TreeLogger logger, File file, + Serializable... objects) throws UnableToCompleteException { FileOutputStream stream = null; - OutputStreamWriter writer = null; - BufferedWriter buffered = null; + ObjectOutputStream objectStream = null; try { - stream = new FileOutputStream(file); - writer = new OutputStreamWriter(stream, DEFAULT_ENCODING); - buffered = new BufferedWriter(writer); file.getParentFile().mkdirs(); - buffered.write(string); + stream = new FileOutputStream(file); + objectStream = new ObjectOutputStream(stream); + for (Serializable object : objects) { + objectStream.writeObject(object); + } } catch (IOException e) { logger.log(TreeLogger.ERROR, "Unable to write file: " + file.getAbsolutePath(), e); throw new UnableToCompleteException(); } finally { - Utility.close(buffered); - Utility.close(writer); + Utility.close(objectStream); Utility.close(stream); } } @@ -1016,16 +1071,25 @@ return true; } - private static void copy(InputStream is, OutputStream os) throws IOException { + public static void writeStringAsFile(TreeLogger logger, File file, + String string) throws UnableToCompleteException { + FileOutputStream stream = null; + OutputStreamWriter writer = null; + BufferedWriter buffered = null; try { - byte[] buf = new byte[8 * 1024]; - int i; - while ((i = is.read(buf)) != -1) { - os.write(buf, 0, i); - } + stream = new FileOutputStream(file); + writer = new OutputStreamWriter(stream, DEFAULT_ENCODING); + buffered = new BufferedWriter(writer); + file.getParentFile().mkdirs(); + buffered.write(string); + } catch (IOException e) { + logger.log(TreeLogger.ERROR, "Unable to write file: " + + file.getAbsolutePath(), e); + throw new UnableToCompleteException(); } finally { - Utility.close(is); - Utility.close(os); + Utility.close(buffered); + Utility.close(writer); + Utility.close(stream); } }