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