Revision: 9901
Author: sco...@google.com
Date: Fri Mar 25 16:48:01 2011
Log: Serialize GWT ASTs with CompilationUnits.
When we persist CompilationUnits, persist the GWT AST too.
http://gwt-code-reviews.appspot.com/1384807/
Review by: zun...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=9901
Modified:
/trunk/dev/core/src/com/google/gwt/dev/javac/CachedCompilationUnit.java
/trunk/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
/trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
/trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnitBuilder.java
/trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnitImpl.java
/trunk/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
/trunk/dev/core/src/com/google/gwt/dev/javac/SourceFileCompilationUnit.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java
/trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java
/trunk/dev/core/src/com/google/gwt/dev/util/DiskCacheToken.java
/trunk/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
/trunk/user/test/com/google/gwt/dev/jjs/GwtAstBuilderTest.java
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/CachedCompilationUnit.java
Thu Mar 24 15:47:57 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/javac/CachedCompilationUnit.java
Fri Mar 25 16:48:01 2011
@@ -15,14 +15,10 @@
*/
package com.google.gwt.dev.javac;
-import com.google.gwt.dev.jjs.ast.JDeclaredType;
-import com.google.gwt.dev.util.collect.Lists;
+import com.google.gwt.dev.util.DiskCacheToken;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.util.Collection;
import java.util.List;
@@ -30,6 +26,7 @@
* This class provides a Convenient way to serialize a {@CompilationUnit}.
*/
public class CachedCompilationUnit extends CompilationUnit {
+ private final DiskCacheToken astToken;
private final Collection<CompiledClass> compiledClasses;
private final ContentId contentId;
private final Dependencies dependencies;
@@ -42,18 +39,17 @@
private final boolean isGenerated;
private final boolean isSuperSource;
private final CategorizedProblem[] problems;
- private transient long sourceToken = -1;
+ private final DiskCacheToken sourceToken;
/**
* Create a compilation unit that can be serialized from another {@link
CompilationUnit}.
*
* @param unit A unit to copy
- * @param sourceToken A valid {@DiskCache} token for this unit's source
code. If
- * you don't have a valid disk cache token, use another
constructor
- * to provide the source code.
+ * @param sourceToken A valid {@DiskCache} token for this unit's source
code.
+ * @param astToken A valid {@DiskCache} token for this unit's serialized
AST types.
*/
@SuppressWarnings("deprecation")
- CachedCompilationUnit(CompilationUnit unit, long sourceToken) {
+ CachedCompilationUnit(CompilationUnit unit, long sourceToken, long
astToken) {
assert unit != null;
this.compiledClasses = unit.getCompiledClasses();
this.contentId = unit.getContentId();
@@ -75,8 +71,13 @@
this.problems[i] = new
SerializableCategorizedProblem(problemsIn[i]);
}
}
- assert sourceToken >= 0;
- this.sourceToken = sourceToken;
+ this.astToken = new DiskCacheToken(astToken);
+ this.sourceToken = new DiskCacheToken(sourceToken);
+ }
+
+ @Override
+ public Collection<CompiledClass> getCompiledClasses() {
+ return compiledClasses;
}
@Override
@@ -102,7 +103,7 @@
@Override
@Deprecated
public String getSource() {
- return diskCache.readString(sourceToken);
+ return sourceToken.readString();
}
@Override
@@ -111,9 +112,8 @@
}
@Override
- public List<JDeclaredType> getTypes() {
- // TODO(scottb): implement.
- return Lists.create();
+ public byte[] getTypesSerialized() {
+ return astToken.readByteArray();
}
@Override
@@ -137,11 +137,6 @@
protected Object writeReplace() {
return this;
}
-
- @Override
- Collection<CompiledClass> getCompiledClasses() {
- return compiledClasses;
- }
@Override
ContentId getContentId() {
@@ -157,15 +152,4 @@
CategorizedProblem[] getProblems() {
return problems;
}
-
- private void readObject(ObjectInputStream inputStream)
- throws ClassNotFoundException, IOException {
- inputStream.defaultReadObject();
- sourceToken = diskCache.transferFromStream(inputStream);
- }
-
- private void writeObject(ObjectOutputStream outputStream) throws
IOException {
- outputStream.defaultWriteObject();
- diskCache.transferToStream(sourceToken, outputStream);
- }
-}
+}
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
Fri Mar 25 11:27:04 2011
+++
/trunk/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
Fri Mar 25 16:48:01 2011
@@ -51,6 +51,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.LinkedBlockingQueue;
/**
* Manages a centralized cache for compiled units.
@@ -120,11 +121,14 @@
}
}
- CompilationUnit unit =
- builder.build(compiledClasses, types, dependencies,
jsniMethods.values(), methodArgs,
+ for (CompiledClass cc : compiledClasses) {
+ allValidClasses.put(cc.getSourceName(), cc);
+ }
+
+
builder.setClasses(compiledClasses).setTypes(types).setDependencies(dependencies)
+
.setJsniMethods(jsniMethods.values()).setMethodArgs(methodArgs).setProblems(
cud.compilationResult().getProblems());
- addValidUnit(unit);
- newlyBuiltUnits.add(unit);
+ buildQueue.add(builder);
} finally {
event.end();
}
@@ -140,6 +144,8 @@
private final GwtAstBuilder astBuilder = new GwtAstBuilder();
+ private transient LinkedBlockingQueue<CompilationUnitBuilder>
buildQueue;
+
/**
* The JDT compiler.
*/
@@ -151,8 +157,6 @@
private final JSORestrictionsChecker.CheckerState jsoState =
new JSORestrictionsChecker.CheckerState();
- private transient Collection<CompilationUnit> newlyBuiltUnits;
-
public CompileMoreLater(AdditionalTypeProviderDelegate delegate) {
compiler.setAdditionalTypeProviderDelegate(delegate);
}
@@ -174,8 +178,7 @@
void addValidUnit(CompilationUnit unit) {
compiler.addCompiledUnit(unit);
for (CompiledClass cc : unit.getCompiledClasses()) {
- String sourceName = cc.getSourceName();
- allValidClasses.put(sourceName, cc);
+ allValidClasses.put(cc.getSourceName(), cc);
}
}
@@ -194,20 +197,54 @@
ArrayList<CompilationUnit> resultUnits = new
ArrayList<CompilationUnit>();
do {
// Compile anything that needs to be compiled.
- this.newlyBuiltUnits = new ArrayList<CompilationUnit>();
-
+ buildQueue = new LinkedBlockingQueue<CompilationUnitBuilder>();
+ final ArrayList<CompilationUnit> newlyBuiltUnits = new
ArrayList<CompilationUnit>();
+ final CompilationUnitBuilder sentinel =
CompilationUnitBuilder.create((GeneratedUnit) null);
+ final Throwable[] workerException = new Throwable[1];
+ Thread buildThread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ do {
+ CompilationUnitBuilder builder = buildQueue.take();
+ if (builder == sentinel) {
+ return;
+ }
+ // Expensive, must serialize GWT AST types to bytes.
+ CompilationUnit unit = builder.build();
+ newlyBuiltUnits.add(unit);
+ } while (true);
+ } catch (Throwable e) {
+ workerException[0] = e;
+ }
+ }
+ };
+ buildThread.setName("CompilationUnitBuilder");
+ buildThread.start();
Event jdtCompilerEvent = SpeedTracerLogger.start(eventType);
try {
compiler.doCompile(builders);
} finally {
jdtCompilerEvent.end();
}
-
- resultUnits.addAll(this.newlyBuiltUnits);
+ buildQueue.add(sentinel);
+ try {
+ buildThread.join();
+ if (workerException[0] != null) {
+ throw workerException[0];
+ }
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Throwable e) {
+ throw new RuntimeException("Exception processing units", e);
+ } finally {
+ buildQueue = null;
+ }
+ resultUnits.addAll(newlyBuiltUnits);
builders.clear();
// Resolve all newly built unit deps against the global classes.
- for (CompilationUnit unit : this.newlyBuiltUnits) {
+ for (CompilationUnit unit : newlyBuiltUnits) {
unit.getDependencies().resolve(allValidClasses);
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java Thu
Mar 24 15:47:57 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java Fri
Mar 25 16:48:01 2011
@@ -20,13 +20,16 @@
import com.google.gwt.dev.asm.Opcodes;
import com.google.gwt.dev.asm.commons.EmptyVisitor;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
+import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.util.DiskCache;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.collect.HashMap;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.Serializable;
import java.net.URL;
import java.net.URLConnection;
@@ -254,6 +257,11 @@
}
return anonymousClassMap;
}
+
+ /**
+ * Returns all contained classes.
+ */
+ public abstract Collection<CompiledClass> getCompiledClasses();
public abstract List<JsniMethod> getJsniMethods();
@@ -289,7 +297,25 @@
/**
* Returns the GWT AST types in this unit.
*/
- public abstract List<JDeclaredType> getTypes();
+ public List<JDeclaredType> getTypes() {
+ try {
+ byte[] bytes = getTypesSerialized();
+ ObjectInputStream ois = new ObjectInputStream(new
ByteArrayInputStream(
+ bytes));
+ return JProgram.deserializeTypes(ois);
+ } catch (IOException e) {
+ throw new RuntimeException("Unexpected IOException on in-memory
stream",
+ e);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException("Unexpected error deserializing AST
for '" + getTypeName() + "'",
+ e);
+ }
+ }
+
+ /**
+ * Returns the GWT AST types in this unit in serialized form.
+ */
+ public abstract byte[] getTypesSerialized();
@Deprecated
public final boolean hasAnonymousClasses() {
@@ -342,11 +368,6 @@
*/
protected abstract Object writeReplace();
- /**
- * Returns all contained classes.
- */
- abstract Collection<CompiledClass> getCompiledClasses();
-
/**
* Returns the content ID for the source with which this unit was
compiled.
*/
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnitBuilder.java
Thu Mar 24 15:47:57 2011
+++
/trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnitBuilder.java
Fri Mar 25 16:48:01 2011
@@ -209,7 +209,7 @@
protected Object writeReplace() {
long sourceToken = generatedUnit.getSourceToken();
assert sourceToken >= 0;
- return new CachedCompilationUnit(this, sourceToken);
+ return new CachedCompilationUnit(this, sourceToken, astToken);
}
@Override
@@ -238,21 +238,31 @@
return "generated://" + generatedUnit.getStrongHash() + "/"
+ Shared.toPath(generatedUnit.getTypeName());
}
+
+ private List<CompiledClass> compiledClasses;
+ private Dependencies dependencies;
+ private Collection<? extends JsniMethod> jsniMethods;
+ private MethodArgNamesLookup methodArgs;
+ private CategorizedProblem[] problems;
/**
* Caches source until JSNI methods can be collected.
*/
private transient String source;
+ private List<JDeclaredType> types;
+
protected CompilationUnitBuilder() {
}
- public CompilationUnit build(List<CompiledClass> compiledClasses,
- List<JDeclaredType> types, Dependencies dependencies,
- Collection<? extends JsniMethod> jsniMethods,
- MethodArgNamesLookup methodArgs, CategorizedProblem[] problems) {
+ public CompilationUnit build() {
// Free the source now.
source = null;
+ assert compiledClasses != null;
+ assert types != null;
+ assert dependencies != null;
+ assert jsniMethods != null;
+ assert methodArgs != null;
return makeUnit(compiledClasses, types, dependencies, jsniMethods,
methodArgs, problems);
}
@@ -270,6 +280,48 @@
public abstract String getTypeName();
+ public CompilationUnitBuilder setClasses(List<CompiledClass>
compiledClasses) {
+ this.compiledClasses = compiledClasses;
+ return this;
+ }
+
+ public CompilationUnitBuilder setCompiledClasses(
+ List<CompiledClass> compiledClasses) {
+ this.compiledClasses = compiledClasses;
+ return this;
+ }
+
+ public CompilationUnitBuilder setDependencies(Dependencies dependencies)
{
+ this.dependencies = dependencies;
+ return this;
+ }
+
+ public CompilationUnitBuilder setJsniMethods(
+ Collection<? extends JsniMethod> jsniMethods) {
+ this.jsniMethods = jsniMethods;
+ return this;
+ }
+
+ public CompilationUnitBuilder setMethodArgs(MethodArgNamesLookup
methodArgs) {
+ this.methodArgs = methodArgs;
+ return this;
+ }
+
+ public CompilationUnitBuilder setProblems(CategorizedProblem[] problems)
{
+ this.problems = problems;
+ return this;
+ }
+
+ public CompilationUnitBuilder setSource(String source) {
+ this.source = source;
+ return this;
+ }
+
+ public CompilationUnitBuilder setTypes(List<JDeclaredType> types) {
+ this.types = types;
+ return this;
+ }
+
@Override
public final String toString() {
return getLocation();
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnitImpl.java
Fri Mar 11 09:50:44 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/javac/CompilationUnitImpl.java
Fri Mar 25 16:48:01 2011
@@ -16,18 +16,26 @@
package com.google.gwt.dev.javac;
import com.google.gwt.dev.jjs.ast.JDeclaredType;
+import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.util.collect.Lists;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectOutputStream;
import java.util.Collection;
import java.util.List;
abstract class CompilationUnitImpl extends CompilationUnit {
+ /**
+ * Handle to serialized GWT AST.
+ */
+ protected transient long astToken;
+
private final Dependencies dependencies;
private final List<CompiledClass> exposedCompiledClasses;
- private final List<JDeclaredType> exposedTypes;
private final boolean hasErrors;
private final List<JsniMethod> jsniMethods;
private final MethodArgNamesLookup methodArgs;
@@ -38,7 +46,6 @@
Collection<? extends JsniMethod> jsniMethods,
MethodArgNamesLookup methodArgs, CategorizedProblem[] problems) {
this.exposedCompiledClasses =
Lists.normalizeUnmodifiable(compiledClasses);
- this.exposedTypes = Lists.normalizeUnmodifiable(types);
this.dependencies = dependencies;
this.jsniMethods = Lists.create(jsniMethods.toArray(new
JsniMethod[jsniMethods.size()]));
this.methodArgs = methodArgs;
@@ -55,6 +62,21 @@
for (CompiledClass cc : compiledClasses) {
cc.initUnit(this);
}
+ try {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(baos);
+ JProgram.serializeTypes(types, out);
+ out.close();
+ astToken = diskCache.writeByteArray(baos.toByteArray());
+ } catch (IOException e) {
+ throw new RuntimeException("Unexpected IOException on in-memory
stream",
+ e);
+ }
+ }
+
+ @Override
+ public Collection<CompiledClass> getCompiledClasses() {
+ return exposedCompiledClasses;
}
@Override
@@ -68,22 +90,14 @@
}
@Override
- public List<JDeclaredType> getTypes() {
- return exposedTypes;
+ public byte[] getTypesSerialized() {
+ return diskCache.readByteArray(astToken);
}
@Override
public boolean isError() {
return hasErrors;
}
-
- /**
- * Returns all contained classes.
- */
- @Override
- Collection<CompiledClass> getCompiledClasses() {
- return exposedCompiledClasses;
- }
@Override
Dependencies getDependencies() {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java Fri Mar
11 09:50:44 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java Fri Mar
25 16:48:01 2011
@@ -125,11 +125,11 @@
public void process(CompilationUnitBuilder builder,
CompilationUnitDeclaration cud, List<CompiledClass>
compiledClasses) {
- CompilationUnit unit = builder.build(compiledClasses,
- Collections.<JDeclaredType> emptyList(), new Dependencies(),
- Collections.<JsniMethod> emptyList(), new MethodArgNamesLookup(),
- cud.compilationResult().getProblems());
- results.add(unit);
+
builder.setClasses(compiledClasses).setTypes(Collections.<JDeclaredType>
emptyList())
+ .setDependencies(new
Dependencies()).setJsniMethods(Collections.<JsniMethod> emptyList())
+ .setMethodArgs(new MethodArgNamesLookup()).setProblems(
+ cud.compilationResult().getProblems());
+ results.add(builder.build());
}
}
/**
=======================================
---
/trunk/dev/core/src/com/google/gwt/dev/javac/SourceFileCompilationUnit.java
Thu Mar 24 15:47:57 2011
+++
/trunk/dev/core/src/com/google/gwt/dev/javac/SourceFileCompilationUnit.java
Fri Mar 25 16:48:01 2011
@@ -101,7 +101,7 @@
if (sourceToken < 0) {
sourceToken =
diskCache.transferFromStream(sourceFile.openContents());
}
- return new CachedCompilationUnit(this, sourceToken);
+ return new CachedCompilationUnit(this, sourceToken, astToken);
}
@Override
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java Sat Jan
22 17:19:44 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JClassType.java Fri Mar
25 16:48:01 2011
@@ -16,12 +16,30 @@
package com.google.gwt.dev.jjs.ast;
import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceOrigin;
+
+import java.io.Serializable;
/**
* Java class type reference expression.
*/
public class JClassType extends JDeclaredType implements CanBeSetFinal {
+ private static class ExternalSerializedForm implements Serializable {
+ private final String name;
+
+ public ExternalSerializedForm(JClassType classType) {
+ name = classType.getName();
+ }
+
+ private Object readResolve() {
+ JClassType result = new JClassType(SourceOrigin.UNKNOWN, name, false,
+ false);
+ result.setExternal(true);
+ return result;
+ }
+ }
+
private final boolean isAbstract;
private boolean isFinal;
private JClassType superClass;
@@ -81,4 +99,13 @@
}
visitor.endVisit(this, ctx);
}
-}
+
+ @Override
+ protected Object writeReplace() {
+ if (isExternal()) {
+ return new ExternalSerializedForm(this);
+ } else {
+ return this;
+ }
+ }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java Wed
Jan 26 16:52:13 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JConstructor.java Fri
Mar 25 16:48:01 2011
@@ -16,7 +16,9 @@
package com.google.gwt.dev.jjs.ast;
import com.google.gwt.dev.jjs.SourceInfo;
-
+import com.google.gwt.dev.jjs.SourceOrigin;
+
+import java.io.Serializable;
import java.util.List;
/**
@@ -24,6 +26,24 @@
*/
public class JConstructor extends JMethod {
+ private static class ExternalSerializedForm implements Serializable {
+
+ private final JClassType enclosingType;
+ private final String signature;
+
+ public ExternalSerializedForm(JConstructor ctor) {
+ enclosingType = ctor.getEnclosingType();
+ signature = ctor.getSignature();
+ }
+
+ private Object readResolve() {
+ JConstructor result = new JConstructor(SourceOrigin.UNKNOWN,
+ enclosingType);
+ result.signature = signature;
+ return result;
+ }
+ }
+
/**
* Caches whether or not this constructor does any work. Once true, we
never
* have to recheck, but we keep rechecking as long as it's false.
@@ -106,5 +126,13 @@
visitor.endVisit(this, ctx);
traceAfter(visitor, before);
}
+
+ protected Object writeReplace() {
+ if (getEnclosingType() != null && getEnclosingType().isExternal()) {
+ return new ExternalSerializedForm(this);
+ } else {
+ return this;
+ }
+ }
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java Fri
Mar 11 09:50:44 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JDeclaredType.java Fri
Mar 25 16:48:01 2011
@@ -285,6 +285,12 @@
Arrays.sort(a, 1, a.length, sort);
methods = Lists.create(a);
}
+
+ /**
+ * Subclasses must replace themselves with a shallow reference when
+ * {@link #isExternal()} is <code>true</code>.
+ */
+ protected abstract Object writeReplace();
/**
* Clears all existing implemented interfaces.
@@ -308,7 +314,7 @@
}
/**
- * See {@link #writeMethodBodies(ObjectOutputStream).
+ * See {@link #writeMethodBodies(ObjectOutputStream)}.
*
* @see #writeMethodBodies(ObjectOutputStream)
*/
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java Wed Jan 26
16:52:13 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JField.java Fri Mar 25
16:48:01 2011
@@ -16,6 +16,9 @@
package com.google.gwt.dev.jjs.ast;
import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceOrigin;
+
+import java.io.Serializable;
/**
* Java field definition.
@@ -43,12 +46,32 @@
return this == VOLATILE;
}
}
+
+ private static class ExternalSerializedForm implements Serializable {
+
+ private final JDeclaredType enclosingType;
+ private final String signature;
+
+ public ExternalSerializedForm(JField field) {
+ enclosingType = field.getEnclosingType();
+ signature = field.getSignature();
+ }
+
+ private Object readResolve() {
+ String name = signature.substring(0, signature.indexOf(':'));
+ JField result = new JField(SourceOrigin.UNKNOWN, name, enclosingType,
+ JNullType.INSTANCE, false, Disposition.NONE);
+ result.signature = signature;
+ return result;
+ }
+ }
private final JDeclaredType enclosingType;
private final boolean isCompileTimeConstant;
private final boolean isStatic;
private boolean isThisRef;
private boolean isVolatile;
+ private transient String signature;
public JField(SourceInfo info, String name, JDeclaredType enclosingType,
JType type,
boolean isStatic, Disposition disposition) {
@@ -72,6 +95,17 @@
}
return null;
}
+
+ public String getSignature() {
+ if (signature == null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getName());
+ sb.append(':');
+ sb.append(getType().getJsniSignatureName());
+ signature = sb.toString();
+ }
+ return signature;
+ }
public boolean isCompileTimeConstant() {
return isCompileTimeConstant;
@@ -115,5 +149,13 @@
}
visitor.endVisit(this, ctx);
}
+
+ protected Object writeReplace() {
+ if (enclosingType != null && enclosingType.isExternal()) {
+ return new ExternalSerializedForm(this);
+ } else {
+ return this;
+ }
+ }
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java Wed
Jan 26 16:52:13 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JInterfaceType.java Fri
Mar 25 16:48:01 2011
@@ -16,12 +16,29 @@
package com.google.gwt.dev.jjs.ast;
import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceOrigin;
+
+import java.io.Serializable;
/**
* Java interface type definition.
*/
public class JInterfaceType extends JDeclaredType {
+ private static class ExternalSerializedForm implements Serializable {
+ private final String name;
+
+ public ExternalSerializedForm(JInterfaceType interfaceType) {
+ name = interfaceType.getName();
+ }
+
+ private Object readResolve() {
+ JInterfaceType result = new JInterfaceType(SourceOrigin.UNKNOWN,
name);
+ result.setExternal(true);
+ return result;
+ }
+ }
+
public JInterfaceType(SourceInfo info, String name) {
super(info, name);
}
@@ -52,4 +69,13 @@
}
visitor.endVisit(this, ctx);
}
-}
+
+ @Override
+ protected Object writeReplace() {
+ if (isExternal()) {
+ return new ExternalSerializedForm(this);
+ } else {
+ return this;
+ }
+ }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java Thu Sep 23
06:33:21 2010
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JMethod.java Fri Mar 25
16:48:01 2011
@@ -17,12 +17,14 @@
import com.google.gwt.dev.jjs.InternalCompilerException;
import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.jjs.SourceOrigin;
import com.google.gwt.dev.util.StringInterner;
import com.google.gwt.dev.util.collect.Lists;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -34,6 +36,25 @@
public class JMethod extends JNode implements HasAnnotations,
HasEnclosingType,
HasName, HasType, CanBeAbstract, CanBeSetFinal, CanBeNative,
CanBeStatic {
+ private static class ExternalSerializedForm implements Serializable {
+
+ private final JDeclaredType enclosingType;
+ private final String signature;
+
+ public ExternalSerializedForm(JMethod method) {
+ enclosingType = method.getEnclosingType();
+ signature = method.getSignature();
+ }
+
+ private Object readResolve() {
+ String name = signature.substring(0, signature.indexOf('('));
+ JMethod result = new JMethod(SourceOrigin.UNKNOWN, name,
enclosingType,
+ null, false, false, false, false);
+ result.signature = signature;
+ return result;
+ }
+ }
+
private static final String TRACE_METHOD_WILDCARD = "*";
private static void trace(String title, String code) {
@@ -42,6 +63,8 @@
System.out.println("---------------------------");
System.out.println(code);
}
+
+ protected transient String signature;
private List<JAnnotation> annotations = Lists.create();
@@ -162,9 +185,6 @@
}
public List<JType> getOriginalParamTypes() {
- if (originalParamTypes == null) {
- return null;
- }
return originalParamTypes;
}
@@ -185,6 +205,21 @@
public List<JParameter> getParams() {
return params;
}
+
+ public String getSignature() {
+ if (signature == null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(getName());
+ sb.append('(');
+ for (JType type : getOriginalParamTypes()) {
+ sb.append(type.getJsniSignatureName());
+ }
+ sb.append(')');
+ sb.append(getOriginalReturnType().getJsniSignatureName());
+ signature = sb.toString();
+ }
+ return signature;
+ }
public List<JClassType> getThrownExceptions() {
return thrownExceptions;
@@ -329,6 +364,14 @@
body = (JAbstractMethodBody) visitor.accept(body);
}
}
+
+ protected Object writeReplace() {
+ if (enclosingType != null && enclosingType.isExternal()) {
+ return new ExternalSerializedForm(this);
+ } else {
+ return this;
+ }
+ }
/**
* See {@link #writeBody(ObjectOutputStream)}.
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Thu Mar 3
14:34:14 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JProgram.java Fri Mar 25
16:48:01 2011
@@ -201,6 +201,19 @@
enclosingMethod.addParam(x);
return x;
}
+
+ public static List<JDeclaredType> deserializeTypes(ObjectInputStream
stream)
+ throws IOException, ClassNotFoundException {
+ @SuppressWarnings("unchecked")
+ List<JDeclaredType> types = (List<JDeclaredType>) stream.readObject();
+ for (JDeclaredType type : types) {
+ type.readMembers(stream);
+ }
+ for (JDeclaredType type : types) {
+ type.readMethodBodies(stream);
+ }
+ return types;
+ }
public static String getJsniSig(JMethod method) {
return getJsniSig(method, true);
@@ -255,6 +268,17 @@
}
return latest;
}
+
+ public static void serializeTypes(List<JDeclaredType> types,
+ ObjectOutputStream stream) throws IOException {
+ stream.writeObject(types);
+ for (JDeclaredType type : types) {
+ type.writeMembers(stream);
+ }
+ for (JDeclaredType type : types) {
+ type.writeMethodBodies(stream);
+ }
+ }
/**
* The main logic behind {@link #lastFragmentLoadingBefore(int, int...)}
and
@@ -1153,16 +1177,9 @@
*
* @see #writeObject(ObjectOutputStream)
*/
- @SuppressWarnings("unchecked")
private void readObject(ObjectInputStream stream) throws IOException,
ClassNotFoundException {
- allTypes = (List<JDeclaredType>) stream.readObject();
- for (JDeclaredType type : allTypes) {
- type.readMembers(stream);
- }
- for (JDeclaredType type : allTypes) {
- type.readMethodBodies(stream);
- }
+ allTypes = deserializeTypes(stream);
stream.defaultReadObject();
}
@@ -1188,13 +1205,7 @@
* recursion chains would result.
*/
private void writeObject(ObjectOutputStream stream) throws IOException {
- stream.writeObject(allTypes);
- for (JDeclaredType type : allTypes) {
- type.writeMembers(stream);
- }
- for (JDeclaredType type : allTypes) {
- type.writeMethodBodies(stream);
- }
+ serializeTypes(allTypes, stream);
stream.defaultWriteObject();
}
}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/util/DiskCacheToken.java Fri Mar
25 16:15:23 2011
+++ /trunk/dev/core/src/com/google/gwt/dev/util/DiskCacheToken.java Fri Mar
25 16:48:01 2011
@@ -39,6 +39,7 @@
* Create a wrapper for a token associated with the given diskCache.
*/
DiskCacheToken(DiskCache diskCache, long token) {
+ assert token >= 0;
this.diskCache = diskCache;
this.token = token;
}
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
Thu Mar 24 15:47:57 2011
+++ /trunk/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
Fri Mar 25 16:48:01 2011
@@ -15,8 +15,6 @@
*/
package com.google.gwt.dev.javac;
-import com.google.gwt.dev.jjs.ast.JDeclaredType;
-
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import java.util.Collection;
@@ -30,9 +28,9 @@
private static final AtomicInteger nextTimestamp = new AtomicInteger(1);
private final ContentId contentId;
- private final String typeName;
- private final String source;
private final long lastModified;
+ private final String source;
+ private final String typeName;
public MockCompilationUnit(String typeName, String source) {
this.typeName = typeName;
@@ -40,6 +38,11 @@
contentId = new ContentId(typeName, source);
lastModified = nextTimestamp.getAndIncrement();
}
+
+ @Override
+ public Collection<CompiledClass> getCompiledClasses() {
+ return null;
+ }
@Override
public List<JsniMethod> getJsniMethods() {
@@ -72,7 +75,7 @@
}
@Override
- public List<JDeclaredType> getTypes() {
+ public byte[] getTypesSerialized() {
return null;
}
@@ -94,11 +97,6 @@
protected Object writeReplace() {
return this;
}
-
- @Override
- Collection<CompiledClass> getCompiledClasses() {
- return null;
- }
@Override
ContentId getContentId() {
=======================================
--- /trunk/user/test/com/google/gwt/dev/jjs/GwtAstBuilderTest.java Fri Mar
11 09:50:44 2011
+++ /trunk/user/test/com/google/gwt/dev/jjs/GwtAstBuilderTest.java Fri Mar
25 16:48:01 2011
@@ -28,33 +28,63 @@
import junit.framework.TestCase;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
/**
- * Massive test for {@link com.google.gwt.dev.jjs.impl.GwtAstBuilder}, uses
- * CompilerSuite under the hood to test source compatibility between
- * {@link com.google.gwt.dev.jjs.impl.GwtAstBuilder} and
- * {@link com.google.gwt.dev.jjs.impl.GenerateJavaAST}.
+ * Massive test for {@link com.google.gwt.dev.jjs.impl.GwtAstBuilder}.
*/
public class GwtAstBuilderTest extends TestCase {
-
- private static TreeLogger createLogger() {
- PrintWriterTreeLogger logger = new PrintWriterTreeLogger(new
PrintWriter(System.err, true));
- logger.setMaxDetail(TreeLogger.ERROR);
+ /*
+ * Reuse the module and compilation state between tests, because it
takes a
+ * long time to build them. This is fine as long as we don't mutate them.
+ */
+
+ private static CompilationState compilationState;
+ private static PrintWriterTreeLogger logger;
+ private static ModuleDef module;
+
+ private static synchronized CompilationState getCompilationState()
+ throws UnableToCompleteException {
+ if (compilationState == null) {
+ compilationState = CompileModule.buildGwtAst(getLogger(),
getTestModule());
+ }
+ return compilationState;
+ }
+
+ private static synchronized TreeLogger getLogger() {
+ if (logger == null) {
+ logger = new PrintWriterTreeLogger(new PrintWriter(System.err,
true));
+ logger.setMaxDetail(TreeLogger.ERROR);
+ }
return logger;
}
+ private static synchronized ModuleDef getTestModule() throws
UnableToCompleteException {
+ if (module == null) {
+ module =
+ ModuleDefLoader.createSyntheticModule(getLogger(),
+ "com.google.gwt.dev.jjs.CompilerSuite.GwtAstBuilderTest",
new String[]{
+ "com.google.gwt.junit.JUnit", "com.google.gwt.dev.jjs.CompilerSuite"},
false);
+ }
+ return module;
+ }
+
+ /**
+ * Tests source compatibility between
+ * {@link com.google.gwt.dev.jjs.impl.GwtAstBuilder} and
+ * {@link com.google.gwt.dev.jjs.impl.GenerateJavaAST}.
+ */
public void testGwtAstBuilder() throws UnableToCompleteException {
- TreeLogger logger = createLogger();
- ModuleDef module =
- ModuleDefLoader.createSyntheticModule(logger,
- "com.google.gwt.dev.jjs.CompilerSuite.GwtAstBuilderTest", new
String[]{
- "com.google.gwt.junit.JUnit", "com.google.gwt.dev.jjs.CompilerSuite"},
false);
- CompilationState compilationState = CompileModule.buildGwtAst(logger,
module);
+ CompilationState compilationState = getCompilationState();
assertFalse(compilationState.hasErrors());
- JProgram jprogram = CompileModule.buildGenerateJavaAst(logger, module,
compilationState);
+ JProgram jprogram =
+ CompileModule.buildGenerateJavaAst(getLogger(), getTestModule(),
compilationState);
Map<String, JDeclaredType> compStateTypes = new HashMap<String,
JDeclaredType>();
for (CompilationUnit unit : compilationState.getCompilationUnits()) {
@@ -88,4 +118,32 @@
assertEquals("Mismatched output for '" + typeName + "'", oldSource,
newSource);
}
}
-}
+
+ /**
+ * Test that serialization doesn't crash and produces the same source
tree.
+ */
+ public void testSerialization() throws UnableToCompleteException,
IOException,
+ ClassNotFoundException {
+ CompilationState compilationState = getCompilationState();
+ assertFalse(compilationState.hasErrors());
+ for (CompilationUnit unit : compilationState.getCompilationUnits()) {
+ Map<String, JDeclaredType> compStateTypes = new HashMap<String,
JDeclaredType>();
+ for (JDeclaredType type : unit.getTypes()) {
+ compStateTypes.put(type.getName(), type);
+ }
+ byte[] bytes = unit.getTypesSerialized();
+ ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
+ ObjectInputStream ois = new ObjectInputStream(bais);
+ List<JDeclaredType> deserializedTypes =
JProgram.deserializeTypes(ois);
+ assertEquals(compStateTypes.size(), deserializedTypes.size());
+ for (JDeclaredType deserializedType : deserializedTypes) {
+ String typeName = deserializedType.getName();
+ JDeclaredType compStateType = compStateTypes.get(typeName);
+ assertNotNull("No matching prebuilt type for '" + typeName + "'",
compStateType);
+ String oldSource = compStateType.toSource();
+ String newSource = deserializedType.toSource();
+ assertEquals("Mismatched output for '" + typeName + "'",
oldSource, newSource);
+ }
+ }
+ }
+}
--
http://groups.google.com/group/Google-Web-Toolkit-Contributors