CompileModule creates a serialized set of compilation units to represent
a GWT module as a <module>.gwt file. This is intended to be run when building
a library to support incremental compilation of a module.
Review at http://gwt-code-reviews.appspot.com/1448808
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@10304 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/CompileModule.java b/dev/core/src/com/google/gwt/dev/CompileModule.java
new file mode 100644
index 0000000..1b870b7
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/CompileModule.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2011 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;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.CompileTaskRunner.CompileTask;
+import com.google.gwt.dev.cfg.ModuleDef;
+import com.google.gwt.dev.cfg.ModuleDefLoader;
+import com.google.gwt.dev.javac.CompilationProblemReporter;
+import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompilationStateBuilder;
+import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.CompilationUnitArchive;
+import com.google.gwt.dev.util.Memory;
+import com.google.gwt.dev.util.arg.ArgHandlerLogLevel;
+import com.google.gwt.dev.util.arg.ArgHandlerModuleName;
+import com.google.gwt.dev.util.arg.ArgHandlerOutDir;
+import com.google.gwt.dev.util.arg.ArgHandlerStrict;
+import com.google.gwt.dev.util.arg.OptionOutDir;
+import com.google.gwt.dev.util.arg.OptionStrict;
+import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
+import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Compiles a GWT module into a form that can be re-used by subsequent builds.
+ *
+ * Takes all compilation units specified on the module source path and write out
+ * CachedCompilationUnits for each one into a file named <module>.gwtar (rhymes
+ * with the musical instrument). This will reduce compile and dev mode startup
+ * time if a .gwtar file is up to date and doesn't need to be re-built.
+ *
+ * Most developers using the GWT SDK won't need to invoke this tool to get
+ * performance improvements. The built-in PersistentUnitCache already saves
+ * compiled modules between builds.
+ *
+ * This tool is of use to library authors for bundling up a pre-compiled gwt
+ * library for distributions. Projects that include the library will never incur
+ * the penalty of recompiling the library.
+ *
+ * It can also be useful in a distributed or multi-process build environment, as
+ * separate instances of CompileModule could be invoked in parallel.
+ *
+ * CompileModule is meant to be used in conjunction with a build tool such as
+ * Apache Ant which can do gross level dependency checking of the inputs and
+ * compute the staleness of a .gwtar file. If the .gwtar file is up to date, the
+ * assumption is that this tool won't be invoked at all.
+ *
+ * If there are dependent modules that already have their own .gwtar files, they
+ * are assumed good and loaded first. CachedCompilationUnits that already exist
+ * will not be re-written into the <module>.gwtar files.
+ *
+ * Note: Currently, the order the modules are passed in is the order in which
+ * they will be compiled. This means you should be careful to pass in modules
+ * that depend on other modules in the same list last.
+ *
+ * TODO(zundel): remove the manual ordering of dependencies.
+ */
+public class CompileModule {
+
+ static class ArgProcessor extends ArgProcessorBase {
+ public ArgProcessor(CompileModuleOptions options) {
+ registerHandler(new ArgHandlerLogLevel(options));
+ registerHandler(new ArgHandlerOutDir(options) {
+ @Override
+ public String[] getDefaultArgs() {
+ return new String[] {getTag(), "bin"};
+ }
+ });
+ registerHandler(new ArgHandlerModuleName(options));
+ registerHandler(new ArgHandlerStrict(options));
+ }
+
+ @Override
+ protected String getName() {
+ return CompileModule.class.getName();
+ }
+ }
+
+ interface CompileModuleOptions extends CompileTaskOptions, OptionOutDir, OptionStrict {
+ }
+
+ static class CompileModuleOptionsImpl extends CompileTaskOptionsImpl implements
+ CompileModuleOptions {
+
+ private File outDir;
+ private boolean strict = false;
+
+ public CompileModuleOptionsImpl() {
+ }
+
+ public CompileModuleOptionsImpl(CompileModuleOptions other) {
+ copyFrom(other);
+ }
+
+ public void copyFrom(CompileModuleOptions other) {
+ super.copyFrom(other);
+ setOutDir(other.getOutDir());
+ setStrict(other.isStrict());
+ }
+
+ @Override
+ public File getOutDir() {
+ return outDir;
+ }
+
+ @Override
+ public boolean isStrict() {
+ return strict;
+ }
+
+ @Override
+ public void setOutDir(File outDir) {
+ this.outDir = outDir;
+ }
+
+ @Override
+ public void setStrict(boolean strict) {
+ this.strict = strict;
+ }
+ }
+
+ // TODO(zundel): Many classes in this package share a similar main()
+ // structure. Refactor to reduce redundancy?
+ public static void main(String[] args) {
+ Memory.initialize();
+ SpeedTracerLogger.init();
+ SpeedTracerLogger.start(CompilerEventType.COMPILE_MODULE);
+ /*
+ * NOTE: main always exits with a call to System.exit to terminate any
+ * non-daemon threads that were started in Generators. Typically, this is to
+ * shutdown AWT related threads, since the contract for their termination is
+ * still implementation-dependent.
+ */
+ final CompileModuleOptions options = new CompileModuleOptionsImpl();
+ if (new ArgProcessor(options).processArgs(args)) {
+ CompileTask task = new CompileTask() {
+ @Override
+ public boolean run(TreeLogger logger) throws UnableToCompleteException {
+ return new CompileModule(options).run(logger);
+ }
+ };
+ if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
+ // Exit w/ success code.
+ System.exit(0);
+ }
+ }
+ // Exit w/ non-success code.
+ System.exit(1);
+ }
+
+ private final CompileModuleOptionsImpl options;
+
+ public CompileModule(CompileModuleOptions options) {
+ this.options = new CompileModuleOptionsImpl(options);
+ }
+
+ /**
+ * Main loop.
+ *
+ * For each module passed on the command line, populates the compilation state
+ * with compilation units from other archives, compiles all resources in this
+ * module, and writes out all the compilation units that are not already
+ * members of another archive into a new {@link CompilationUnitArchive} file.
+ */
+ public boolean run(final TreeLogger logger) throws UnableToCompleteException {
+
+ // TODO(zundel): There is an optimal order to compile these modules in.
+ // Modify ModuleDefLoader to be able to figure that out and sort them for
+ // us.
+
+ for (String moduleToCompile : options.getModuleNames()) {
+ ModuleDef module;
+ try {
+ module = ModuleDefLoader.loadFromClassPath(logger, moduleToCompile, false);
+ } catch (Throwable e) {
+ CompilationProblemReporter.logAndTranslateException(logger, e);
+ return false;
+ }
+
+ Set<String> archivedResourcePaths = new HashSet<String>();
+ SpeedTracerLogger.Event loadAllArchives =
+ SpeedTracerLogger.start(CompilerEventType.LOAD_ARCHIVE, "module", moduleToCompile);
+ try {
+ Collection<URL> archiveURLs = module.getAllCompilationUnitArchiveURLs();
+ if (logger.isLoggable(TreeLogger.TRACE) && archiveURLs != null) {
+ for (URL archiveURL : archiveURLs) {
+ logger.log(TreeLogger.TRACE, "Found archive: " + archiveURL);
+ }
+ }
+
+ for (URL archiveURL : archiveURLs) {
+ SpeedTracerLogger.Event loadArchive =
+ SpeedTracerLogger.start(CompilerEventType.LOAD_ARCHIVE, "dependentModule", archiveURL
+ .toString());
+
+ try {
+ CompilationUnitArchive archive = CompilationUnitArchive.createFromURL(archiveURL);
+ // Pre-populate CompilationStateBuilder with .gwtar files
+ CompilationStateBuilder.addArchive(archive);
+
+ // Remember already archived units - we don't want to add them back.
+ if (!archive.getTopModuleName().equals(moduleToCompile)) {
+ for (CompilationUnit unit : archive.getUnits().values()) {
+ archivedResourcePaths.add(unit.getResourcePath());
+ }
+ }
+ } catch (IOException ex) {
+ logger.log(TreeLogger.WARN, "Unable to read: " + archiveURL + ". Skipping: " + ex);
+ } catch (ClassNotFoundException ex) {
+ logger
+ .log(TreeLogger.WARN, "Incompatible archive: " + archiveURL + ". Skipping: " + ex);
+ } finally {
+ loadArchive.end();
+ }
+ }
+ } finally {
+ loadAllArchives.end();
+ }
+
+ CompilationState compilationState;
+ try {
+ compilationState = module.getCompilationState(logger, !options.isStrict());
+ } catch (Throwable e) {
+ CompilationProblemReporter.logAndTranslateException(logger, e);
+ return false;
+ }
+
+ if (options.isStrict() && compilationState.hasErrors()) {
+ logger.log(TreeLogger.ERROR, "Failed to compile " + moduleToCompile);
+ return false;
+ }
+
+ CompilationUnitArchive outputModule = new CompilationUnitArchive(moduleToCompile);
+ for (CompilationUnit unit : compilationState.getCompilationUnits()) {
+ if (!archivedResourcePaths.contains(unit.getResourcePath())) {
+ outputModule.addUnit(unit);
+ }
+ }
+
+ File outputDir = options.getOutDir();
+ if (!outputDir.isDirectory() && !outputDir.mkdirs()) {
+ logger.log(Type.ERROR, "Error creating directories for ouptut: "
+ + outputDir.getAbsolutePath());
+ throw new UnableToCompleteException();
+ }
+
+ String slashedModuleName =
+ module.getName().replace('.', '/') + ModuleDefLoader.COMPILATION_UNIT_ARCHIVE_SUFFIX;
+ File outputFile = new File(outputDir, slashedModuleName);
+ outputFile.getParentFile().mkdirs();
+ logger.log(TreeLogger.INFO, "Writing " + outputModule.getUnits().size() + " units to "
+ + outputFile.getAbsolutePath());
+
+ try {
+ outputModule.writeToFile(outputFile);
+ } catch (IOException ex) {
+ logger.log(Type.ERROR, "Error writing module file: " + outputFile.getAbsolutePath() + ": "
+ + ex);
+ throw new UnableToCompleteException();
+ }
+ }
+ return true;
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/DevModeBase.java b/dev/core/src/com/google/gwt/dev/DevModeBase.java
index cff1e53..cc8b2ad 100644
--- a/dev/core/src/com/google/gwt/dev/DevModeBase.java
+++ b/dev/core/src/com/google/gwt/dev/DevModeBase.java
@@ -103,6 +103,10 @@
ModuleDef moduleDef = loadModule(logger, moduleName, true);
assert (moduleDef != null);
+ if (Boolean.valueOf(System.getProperty("gwt.usearchives"))) {
+ Precompile.preloadArchives(logger, moduleDef);
+ }
+
CompilationState compilationState =
moduleDef.getCompilationState(logger, !options.isStrict());
ShellModuleSpaceHost host =
diff --git a/dev/core/src/com/google/gwt/dev/GwtAstBuilderUtil.java b/dev/core/src/com/google/gwt/dev/GwtAstBuilderUtil.java
index c9fe43a..18c66cf 100644
--- a/dev/core/src/com/google/gwt/dev/GwtAstBuilderUtil.java
+++ b/dev/core/src/com/google/gwt/dev/GwtAstBuilderUtil.java
@@ -26,10 +26,7 @@
import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
import com.google.gwt.dev.jjs.CorrelationFactory;
import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory;
-import com.google.gwt.dev.jjs.InternalCompilerException;
-import com.google.gwt.dev.jjs.InternalCompilerException.NodeInfo;
import com.google.gwt.dev.jjs.JJSOptionsImpl;
-import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.jjs.ast.JProgram;
import com.google.gwt.dev.jjs.impl.BuildTypeMap;
import com.google.gwt.dev.jjs.impl.GenerateJavaAST;
@@ -119,48 +116,6 @@
}
}
- static UnableToCompleteException logAndTranslateException(TreeLogger logger, Throwable e) {
- if (e instanceof UnableToCompleteException) {
- // just rethrow
- return (UnableToCompleteException) e;
- } else if (e instanceof InternalCompilerException) {
- TreeLogger topBranch =
- logger.branch(TreeLogger.ERROR, "An internal compiler exception occurred", e);
- List<NodeInfo> nodeTrace = ((InternalCompilerException) e).getNodeTrace();
- for (NodeInfo nodeInfo : nodeTrace) {
- SourceInfo info = nodeInfo.getSourceInfo();
- String msg;
- if (info != null) {
- String fileName = info.getFileName();
- fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
- fileName = fileName.substring(fileName.lastIndexOf('\\') + 1);
- msg = "at " + fileName + "(" + info.getStartLine() + "): ";
- } else {
- msg = "<no source info>: ";
- }
-
- String description = nodeInfo.getDescription();
- if (description != null) {
- msg += description;
- } else {
- msg += "<no description available>";
- }
- TreeLogger nodeBranch = topBranch.branch(TreeLogger.ERROR, msg, null);
- String className = nodeInfo.getClassName();
- if (className != null) {
- nodeBranch.log(TreeLogger.INFO, className, null);
- }
- }
- return new UnableToCompleteException();
- } else if (e instanceof VirtualMachineError) {
- // Always rethrow VM errors (an attempt to wrap may fail).
- throw (VirtualMachineError) e;
- } else {
- logger.log(TreeLogger.ERROR, "Unexpected internal compiler error", e);
- return new UnableToCompleteException();
- }
- }
-
private static void checkForErrors(TreeLogger logger, CompilationUnitDeclaration[] goldenCuds)
throws UnableToCompleteException {
for (CompilationUnitDeclaration cud : goldenCuds) {
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index 8d35df5..1c6a67a 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -29,7 +29,9 @@
import com.google.gwt.dev.cfg.ModuleDefLoader;
import com.google.gwt.dev.cfg.PropertyPermutations;
import com.google.gwt.dev.javac.CompilationState;
+import com.google.gwt.dev.javac.CompilationStateBuilder;
import com.google.gwt.dev.javac.CompilationUnit;
+import com.google.gwt.dev.javac.CompilationUnitArchive;
import com.google.gwt.dev.jjs.AbstractCompiler;
import com.google.gwt.dev.jjs.JJSOptions;
import com.google.gwt.dev.jjs.JavaScriptCompiler;
@@ -45,7 +47,9 @@
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import java.io.File;
+import java.io.IOException;
import java.lang.management.ManagementFactory;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -154,7 +158,8 @@
File genDir) {
Event validateEvent = SpeedTracerLogger.start(CompilerEventType.VALIDATE);
try {
- CompilationState compilationState = module.getCompilationState(logger, !jjsOptions.isStrict());
+ CompilationState compilationState =
+ module.getCompilationState(logger, !jjsOptions.isStrict());
if (jjsOptions.isStrict() && compilationState.hasErrors()) {
abortDueToStrictMode(logger);
}
@@ -239,8 +244,13 @@
// doesn't block when the library is accessed for the first time.
new GraphicsInitThread().start();
+ if (Boolean.valueOf(System.getProperty("gwt.usearchives"))) {
+ preloadArchives(logger, module);
+ }
+
try {
- CompilationState compilationState = module.getCompilationState(logger, !jjsOptions.isStrict());
+ CompilationState compilationState =
+ module.getCompilationState(logger, !jjsOptions.isStrict());
if (jjsOptions.isStrict() && compilationState.hasErrors()) {
abortDueToStrictMode(logger);
}
@@ -332,6 +342,36 @@
}
}
+ /**
+ * Load any .gwtar files into the cache before building CompilationState.
+ */
+ static void preloadArchives(TreeLogger logger, ModuleDef module) {
+ SpeedTracerLogger.Event loadArchive = SpeedTracerLogger.start(CompilerEventType.LOAD_ARCHIVE);
+ try {
+ Collection<URL> archiveURLs = module.getAllCompilationUnitArchiveURLs();
+ if (logger.isLoggable(TreeLogger.TRACE) && archiveURLs != null) {
+ for (URL archiveURL : archiveURLs) {
+ logger.log(TreeLogger.TRACE, "Found archived module: " + archiveURL);
+ }
+ }
+
+ for (URL archiveURL : archiveURLs) {
+ try {
+ CompilationUnitArchive archive = CompilationUnitArchive.createFromURL(archiveURL);
+ // Pre-populate CompilationStateBuilder with .gwt files
+ CompilationStateBuilder.addArchive(archive);
+ } catch (IOException ex) {
+ logger.log(TreeLogger.WARN, "Unable to read: " + archiveURL + ". Skipping: " + ex);
+ } catch (ClassNotFoundException ex) {
+ logger.log(TreeLogger.WARN, "Incompatible archived module: " + archiveURL
+ + ". Skipping: " + ex);
+ }
+ }
+ } finally {
+ loadArchive.end();
+ }
+ }
+
private static void abortDueToStrictMode(TreeLogger logger) throws UnableToCompleteException {
logger.log(TreeLogger.ERROR, "Aborting compile due to errors in some input files");
throw new UnableToCompleteException();
@@ -423,8 +463,8 @@
"Precompiling on the start node, because some linkers are not updated");
if (legacyLinkersLogger.isLoggable(TreeLogger.INFO)) {
for (Linker linker : linkerContext.findUnshardableLinkers()) {
- legacyLinkersLogger.log(TreeLogger.INFO, "Linker" + linker.getClass().getCanonicalName()
- + " is not updated");
+ legacyLinkersLogger.log(TreeLogger.INFO, "Linker"
+ + linker.getClass().getCanonicalName() + " is not updated");
}
}
generateOnShards = false;
@@ -447,8 +487,8 @@
Util.writeStringAsFile(logger, new File(compilerWorkDir, PERM_COUNT_FILENAME), String
.valueOf(numPermutations));
if (branch.isLoggable(TreeLogger.INFO)) {
- branch.log(TreeLogger.INFO, "Precompilation (minimal) succeeded, number of permutations: "
- + numPermutations);
+ branch.log(TreeLogger.INFO,
+ "Precompilation (minimal) succeeded, number of permutations: " + numPermutations);
}
} else {
if (options.isValidateOnly()) {
@@ -475,7 +515,7 @@
.valueOf(permsPrecompiled));
if (branch.isLoggable(TreeLogger.INFO)) {
branch.log(TreeLogger.INFO, "Precompilation succeeded, number of permutations: "
- + permsPrecompiled);
+ + permsPrecompiled);
}
}
}
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 3c3cfb3..92d0e7d 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -1,12 +1,12 @@
/*
* 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
* 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
@@ -21,9 +21,9 @@
import com.google.gwt.core.ext.linker.LinkerOrder;
import com.google.gwt.core.ext.linker.LinkerOrder.Order;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
+import com.google.gwt.dev.javac.CompilationProblemReporter;
import com.google.gwt.dev.javac.CompilationState;
import com.google.gwt.dev.javac.CompilationStateBuilder;
-import com.google.gwt.dev.javac.CompilationProblemReporter;
import com.google.gwt.dev.resource.Resource;
import com.google.gwt.dev.resource.ResourceOracle;
import com.google.gwt.dev.resource.impl.DefaultFilters;
@@ -38,8 +38,11 @@
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import java.io.File;
+import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -57,19 +60,22 @@
public class ModuleDef {
private static final ResourceFilter NON_JAVA_RESOURCES = new ResourceFilter() {
+ @Override
public boolean allows(String path) {
return !path.endsWith(".java") && !path.endsWith(".class");
}
};
- private static final Comparator<Map.Entry<String, ?>> REV_NAME_CMP = new Comparator<Map.Entry<String, ?>>() {
- public int compare(Map.Entry<String, ?> entry1, Map.Entry<String, ?> entry2) {
- String key1 = entry1.getKey();
- String key2 = entry2.getKey();
- // intentionally reversed
- return key2.compareTo(key1);
- }
- };
+ private static final Comparator<Map.Entry<String, ?>> REV_NAME_CMP =
+ new Comparator<Map.Entry<String, ?>>() {
+ @Override
+ public int compare(Map.Entry<String, ?> entry1, Map.Entry<String, ?> entry2) {
+ String key1 = entry1.getKey();
+ String key2 = entry2.getKey();
+ // intentionally reversed
+ return key2.compareTo(key1);
+ }
+ };
public static boolean isValidModuleName(String moduleName) {
String[] parts = moduleName.split("\\.");
@@ -86,6 +92,14 @@
private String activePrimaryLinker;
+ /**
+ * A set of URLs for <module>.gwtar files found on the classpath that correspond
+ * to <module>.gwt.xml files loaded as a part of this module's nested load.
+ *
+ * @see com.google.gwt.dev.CompileModule
+ */
+ private final List<URL> archiveURLs = new ArrayList<URL>();
+
private boolean collapseAllProperties;
private final DefaultFilters defaultFilters;
@@ -94,13 +108,26 @@
private final Set<File> gwtXmlFiles = new HashSet<File>();
+ /**
+ * All resources found on the public path, specified by <public> directives in
+ * modules (or the implicit ./public directory). Marked 'lazy' because it does not
+ * start searching for resources until a query is made.
+ */
private ResourceOracleImpl lazyPublicOracle;
+ /**
+ * A subset of lazySourceOracle, contains files other than .java and .class files.
+ */
private ResourceOracleImpl lazyResourcesOracle;
+ /**
+ * Contains all files from the source path, specified by <source> and <super>
+ * directives in modules (or the implicit ./client directory).
+ */
private ResourceOracleImpl lazySourceOracle;
- private final Map<String, Class<? extends Linker>> linkerTypesByName = new LinkedHashMap<String, Class<? extends Linker>>();
+ private final Map<String, Class<? extends Linker>> linkerTypesByName =
+ new LinkedHashMap<String, Class<? extends Linker>>();
private final long moduleDefCreationTime = System.currentTimeMillis();
@@ -156,48 +183,44 @@
activeLinkers.add(name);
}
- public synchronized void addPublicPackage(String publicPackage,
- String[] includeList, String[] excludeList, String[] skipList,
- boolean defaultExcludes, boolean caseSensitive) {
+ public synchronized void addPublicPackage(String publicPackage, String[] includeList,
+ String[] excludeList, String[] skipList, boolean defaultExcludes, boolean caseSensitive) {
if (lazyPublicOracle != null) {
throw new IllegalStateException("Already normalized");
}
- publicPrefixSet.add(new PathPrefix(publicPackage,
- defaultFilters.customResourceFilter(includeList, excludeList,
- skipList, defaultExcludes, caseSensitive), true, excludeList));
+ publicPrefixSet.add(new PathPrefix(publicPackage, defaultFilters.customResourceFilter(
+ includeList, excludeList, skipList, defaultExcludes, caseSensitive), true, excludeList));
}
- public void addSourcePackage(String sourcePackage, String[] includeList,
- String[] excludeList, String[] skipList, boolean defaultExcludes,
- boolean caseSensitive) {
- addSourcePackageImpl(sourcePackage, includeList, excludeList,
- skipList, defaultExcludes, caseSensitive, false);
+ public void addSourcePackage(String sourcePackage, String[] includeList, String[] excludeList,
+ String[] skipList, boolean defaultExcludes, boolean caseSensitive) {
+ addSourcePackageImpl(sourcePackage, includeList, excludeList, skipList, defaultExcludes,
+ caseSensitive, false);
}
public void addSourcePackageImpl(String sourcePackage, String[] includeList,
- String[] excludeList, String[] skipList, boolean defaultExcludes,
- boolean caseSensitive, boolean isSuperSource) {
+ String[] excludeList, String[] skipList, boolean defaultExcludes, boolean caseSensitive,
+ boolean isSuperSource) {
if (lazySourceOracle != null) {
throw new IllegalStateException("Already normalized");
}
- PathPrefix pathPrefix = new PathPrefix(sourcePackage,
- defaultFilters.customJavaFilter(includeList, excludeList, skipList,
- defaultExcludes, caseSensitive), isSuperSource, excludeList);
+ PathPrefix pathPrefix =
+ new PathPrefix(sourcePackage, defaultFilters.customJavaFilter(includeList, excludeList,
+ skipList, defaultExcludes, caseSensitive), isSuperSource, excludeList);
sourcePrefixSet.add(pathPrefix);
}
- public void addSuperSourcePackage(String superSourcePackage,
- String[] includeList, String[] excludeList, String[] skipList,
- boolean defaultExcludes, boolean caseSensitive) {
- addSourcePackageImpl(superSourcePackage, includeList, excludeList,
- skipList, defaultExcludes, caseSensitive, true);
+ public void addSuperSourcePackage(String superSourcePackage, String[] includeList,
+ String[] excludeList, String[] skipList, boolean defaultExcludes, boolean caseSensitive) {
+ addSourcePackageImpl(superSourcePackage, includeList, excludeList, skipList, defaultExcludes,
+ caseSensitive, true);
}
/**
* Free up memory no longer needed in later compile stages. After calling this
- * method, the ResourceOraclewill be empty and unusable. Calling
- * {@link #refresh(TreeLogger)} will restore them.
+ * method, the ResourceOracle will be empty and unusable. Calling
+ * {@link #refresh()} will restore them.
*/
public synchronized void clear() {
if (lazySourceOracle != null) {
@@ -216,15 +239,14 @@
* linker had been previously added to the set of active linkers, the old
* active linker will be replaced with the new linker.
*/
- public void defineLinker(TreeLogger logger, String name,
- Class<? extends Linker> linker) throws UnableToCompleteException {
+ public void defineLinker(TreeLogger logger, String name, Class<? extends Linker> linker)
+ throws UnableToCompleteException {
Class<? extends Linker> old = getLinker(name);
if (old != null) {
// Redefining an existing name
if (activePrimaryLinker.equals(name)) {
// Make sure the new one is also a primary linker
- if (!linker.getAnnotation(LinkerOrder.class).value().equals(
- Order.PRIMARY)) {
+ if (!linker.getAnnotation(LinkerOrder.class).value().equals(Order.PRIMARY)) {
logger.log(TreeLogger.ERROR, "Redefining primary linker " + name
+ " with non-primary implementation " + linker.getName());
throw new UnableToCompleteException();
@@ -232,8 +254,7 @@
} else if (activeLinkers.contains(name)) {
// Make sure it's a not a primary linker
- if (linker.getAnnotation(LinkerOrder.class).value().equals(
- Order.PRIMARY)) {
+ if (linker.getAnnotation(LinkerOrder.class).value().equals(Order.PRIMARY)) {
logger.log(TreeLogger.ERROR, "Redefining non-primary linker " + name
+ " with primary implementation " + linker.getName());
throw new UnableToCompleteException();
@@ -258,7 +279,7 @@
/*
* Ensure that URLs that match the servlet mapping, including those that
* have additional path_info, get routed to the correct servlet.
- *
+ *
* See "Inside Servlets", Second Edition, pg. 208
*/
if (actual.equals(mapping) || actual.startsWith(mapping + "/")) {
@@ -271,7 +292,7 @@
/**
* Returns the Resource for a source file if it is found; <code>null</code>
* otherwise.
- *
+ *
* @param partialPath the partial path of the source file
* @return the resource for the requested source file
*/
@@ -298,13 +319,22 @@
return linkerTypesByName.get(activePrimaryLinker);
}
+ /**
+ * Returns URLs to fetch archives of precompiled compilation units.
+ *
+ * @see com.google.gwt.dev.CompileModule
+ */
+ public Collection<URL> getAllCompilationUnitArchiveURLs() {
+ return Collections.unmodifiableCollection(archiveURLs);
+ }
+
public String[] getAllPublicFiles() {
doRefresh();
return lazyPublicOracle.getPathNames().toArray(Empty.STRINGS);
}
/**
- * Strictly for statistics gathering. There is no guarantee that the source
+ * Strictly for statistics gathering. There is no guarantee that the source
* oracle has been initialized.
*/
public String[] getAllSourceFiles() {
@@ -319,16 +349,17 @@
public String getCanonicalName() {
return name;
}
-
+
public CompilationState getCompilationState(TreeLogger logger) throws UnableToCompleteException {
return getCompilationState(logger, false);
}
-
+
public synchronized CompilationState getCompilationState(TreeLogger logger, boolean suppressErrors)
throws UnableToCompleteException {
doRefresh();
CompilationState compilationState =
- CompilationStateBuilder.buildFrom(logger, lazySourceOracle.getResources(), null, suppressErrors);
+ CompilationStateBuilder.buildFrom(logger, lazySourceOracle.getResources(), null,
+ suppressErrors);
checkForSeedTypes(logger, compilationState);
return compilationState;
}
@@ -367,8 +398,8 @@
PathPrefixSet pathPrefixes = lazySourceOracle.getPathPrefixes();
PathPrefixSet newPathPrefixes = new PathPrefixSet();
for (PathPrefix pathPrefix : pathPrefixes.values()) {
- newPathPrefixes.add(new PathPrefix(pathPrefix.getPrefix(),
- NON_JAVA_RESOURCES, pathPrefix.shouldReroot()));
+ newPathPrefixes.add(new PathPrefix(pathPrefix.getPrefix(), NON_JAVA_RESOURCES, pathPrefix
+ .shouldReroot()));
}
lazyResourcesOracle.setPathPrefixes(newPathPrefixes);
ResourceOracleImpl.refresh(TreeLogger.NULL, lazyResourcesOracle);
@@ -421,7 +452,7 @@
* For convenience in hosted mode, servlets can be automatically loaded and
* delegated to via {@link com.google.gwt.dev.shell.GWTShellServlet}. If a
* servlet is already mapped to the specified path, it is replaced.
- *
+ *
* @param path the url path at which the servlet resides
* @param servletClassName the name of the servlet to publish
*/
@@ -448,11 +479,15 @@
this.nameOverride = nameOverride;
}
+ void addCompilationUnitArchiveURL(URL url) {
+ archiveURLs.add(url);
+ }
+
/**
* The final method to call when everything is setup. Before calling this
* method, several of the getter methods may not be called. After calling this
* method, the add methods may not be called.
- *
+ *
* @param logger Logs the activity.
*/
synchronized void normalize(TreeLogger logger) {
@@ -498,8 +533,8 @@
moduleDefNormalize.end();
}
- private void checkForSeedTypes(TreeLogger logger,
- CompilationState compilationState) throws UnableToCompleteException {
+ private void checkForSeedTypes(TreeLogger logger, CompilationState compilationState)
+ throws UnableToCompleteException {
// Sanity check the seed types and don't even start it they're missing.
boolean seedTypesMissing = false;
TypeOracle typeOracle = compilationState.getTypeOracle();
@@ -508,8 +543,7 @@
compilationState);
seedTypesMissing = true;
} else {
- TreeLogger branch = logger.branch(TreeLogger.TRACE,
- "Finding entry point classes", null);
+ TreeLogger branch = logger.branch(TreeLogger.TRACE, "Finding entry point classes", null);
String[] typeNames = getEntryPointTypeNames();
for (int i = 0; i < typeNames.length; i++) {
String typeName = typeNames[i];
@@ -530,15 +564,15 @@
if (!needsRefresh) {
return;
}
- Event moduleDefEvent = SpeedTracerLogger.start(
- CompilerEventType.MODULE_DEF, "phase", "refresh", "module", getName());
+ Event moduleDefEvent =
+ SpeedTracerLogger.start(CompilerEventType.MODULE_DEF, "phase", "refresh", "module",
+ getName());
// Refresh resource oracles.
if (lazyResourcesOracle == null) {
- ResourceOracleImpl.refresh(TreeLogger.NULL, lazyPublicOracle,
- lazySourceOracle);
+ ResourceOracleImpl.refresh(TreeLogger.NULL, lazyPublicOracle, lazySourceOracle);
} else {
- ResourceOracleImpl.refresh(TreeLogger.NULL, lazyPublicOracle,
- lazySourceOracle, lazyResourcesOracle);
+ ResourceOracleImpl.refresh(TreeLogger.NULL, lazyPublicOracle, lazySourceOracle,
+ lazyResourcesOracle);
}
moduleDefEvent.end();
needsRefresh = false;
diff --git a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
index 9713fb4..c4365a9 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDefLoader.java
@@ -64,6 +64,11 @@
* Filename suffix used for GWT Module XML files.
*/
public static final String GWT_MODULE_XML_SUFFIX = ".gwt.xml";
+
+ /**
+ * Filename suffix used for Precompiled GWT Module files.
+ */
+ public static final String COMPILATION_UNIT_ARCHIVE_SUFFIX = ".gwtar";
/**
* Keep soft references to loaded modules so the VM can gc them when memory is
@@ -111,7 +116,7 @@
/**
* Loads a new module from the class path. Equivalent to
- * {@link #loadFromClassPath(logger, moduleName, false)}.
+ * {@link #loadFromClassPath(TreeLogger, String, boolean)}.
*
* @param logger logs the process
* @param moduleName the module to load
@@ -187,6 +192,7 @@
private ModuleDefLoader() {
this.classLoader = Thread.currentThread().getContextClassLoader();
this.strategy = new LoadStrategy() {
+ @Override
public void load(TreeLogger logger, String moduleName, ModuleDef moduleDef)
throws UnableToCompleteException {
nestedLoad(logger, moduleName, moduleDef);
@@ -202,6 +208,7 @@
private ModuleDefLoader(final String[] inherits) {
this.classLoader = Thread.currentThread().getContextClassLoader();
this.strategy = new LoadStrategy() {
+ @Override
public void load(TreeLogger logger, String moduleName, ModuleDef moduleDef)
throws UnableToCompleteException {
for (String inherit : inherits) {
@@ -257,6 +264,11 @@
logger.log(TreeLogger.ERROR, "Error parsing URI", e);
throw new UnableToCompleteException();
}
+ String compilationUnitArchiveName = slashedModuleName + ModuleDefLoader.COMPILATION_UNIT_ARCHIVE_SUFFIX;
+ URL compiledModuleURL = classLoader.getResource(compilationUnitArchiveName);
+ if (compiledModuleURL != null) {
+ moduleDef.addCompilationUnitArchiveURL(compiledModuleURL);
+ }
}
if (moduleURL == null) {
String msg = "Unable to find '"
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationProblemReporter.java b/dev/core/src/com/google/gwt/dev/javac/CompilationProblemReporter.java
index f1dc0cb..0f7d450 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationProblemReporter.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationProblemReporter.java
@@ -18,6 +18,10 @@
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.TreeLogger.HelpInfo;
import com.google.gwt.core.ext.TreeLogger.Type;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.jjs.InternalCompilerException;
+import com.google.gwt.dev.jjs.InternalCompilerException.NodeInfo;
+import com.google.gwt.dev.jjs.SourceInfo;
import com.google.gwt.dev.util.Messages;
import com.google.gwt.dev.util.Util;
@@ -29,6 +33,7 @@
import java.net.URL;
import java.util.HashSet;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
@@ -47,8 +52,61 @@
}
/**
- * Provides a meaningful error message when a type is missing from the {@link
- * import com.google.gwt.core.ext.typeinfo.TypeOracle} or
+ * Used as a convenience to catch all exceptions thrown by the compiler. For
+ * instances of {@link InternalCompilerException}, extra diagnostics are
+ * printed.
+ *
+ * @param logger logger used to report errors to the console
+ * @param e the exception to analyze and log
+ * @return Always returns an instance of {@link UnableToCompleteException} so
+ * that the calling method can declare a more narrow 'throws
+ * UnableToCompleteException'
+ */
+ public static UnableToCompleteException logAndTranslateException(TreeLogger logger, Throwable e) {
+ if (e instanceof UnableToCompleteException) {
+ // just rethrow
+ return (UnableToCompleteException) e;
+ } else if (e instanceof InternalCompilerException) {
+ TreeLogger topBranch =
+ logger.branch(TreeLogger.ERROR, "An internal compiler exception occurred", e);
+ List<NodeInfo> nodeTrace = ((InternalCompilerException) e).getNodeTrace();
+ for (NodeInfo nodeInfo : nodeTrace) {
+ SourceInfo info = nodeInfo.getSourceInfo();
+ String msg;
+ if (info != null) {
+ String fileName = info.getFileName();
+ fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
+ fileName = fileName.substring(fileName.lastIndexOf('\\') + 1);
+ msg = "at " + fileName + "(" + info.getStartLine() + "): ";
+ } else {
+ msg = "<no source info>: ";
+ }
+
+ String description = nodeInfo.getDescription();
+ if (description != null) {
+ msg += description;
+ } else {
+ msg += "<no description available>";
+ }
+ TreeLogger nodeBranch = topBranch.branch(TreeLogger.ERROR, msg, null);
+ String className = nodeInfo.getClassName();
+ if (className != null) {
+ nodeBranch.log(TreeLogger.INFO, className, null);
+ }
+ }
+ return new UnableToCompleteException();
+ } else if (e instanceof VirtualMachineError) {
+ // Always rethrow VM errors (an attempt to wrap may fail).
+ throw (VirtualMachineError) e;
+ } else {
+ logger.log(TreeLogger.ERROR, "Unexpected internal compiler error", e);
+ return new UnableToCompleteException();
+ }
+ }
+
+ /**
+ * Provides a meaningful error message when a type is missing from the
+ * {@link com.google.gwt.core.ext.typeinfo.TypeOracle} or
* {@link com.google.gwt.dev.shell.CompilingClassLoader}.
*
* @param logger logger for logging errors to the console
@@ -85,6 +143,13 @@
}
}
+ /**
+ * Walk the compilation state and report errors if they exist.
+ *
+ * @param logger logger for reporting errors to the console
+ * @param compilationState contains units that might contain errors
+ * @param suppressErrors See {@link #reportErrors(TreeLogger, CompilationUnit, boolean)}
+ */
public static void reportAllErrors(TreeLogger logger, CompilationState compilationState,
boolean suppressErrors) {
for (CompilationUnit unit : compilationState.getCompilationUnits()) {
@@ -190,6 +255,7 @@
CompilationProblemReporter.reportErrors(logger, unit.getProblems(), unit
.getResourceLocation(), unit.isError(), new SourceFetcher() {
+ @Override
public String getSource() {
return unit.getSource();
}
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java b/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
index 36b7309..02da551 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationStateBuilder.java
@@ -1,12 +1,12 @@
/*
* Copyright 2009 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
@@ -66,6 +66,7 @@
private final class UnitProcessorImpl implements UnitProcessor {
+ @Override
public void process(CompilationUnitBuilder builder, CompilationUnitDeclaration cud,
List<CompiledClass> compiledClasses) {
Event event = SpeedTracerLogger.start(DevModeEventType.CSB_PROCESS);
@@ -80,6 +81,7 @@
final Set<String> jsniDeps = new HashSet<String>();
Map<String, Binding> jsniRefs = new HashMap<String, Binding>();
JsniChecker.check(cud, jsoState, jsniMethods, jsniRefs, new JsniChecker.TypeResolver() {
+ @Override
public ReferenceBinding resolveType(String typeName) {
ReferenceBinding resolveType = compiler.resolveType(typeName);
if (resolveType != null) {
@@ -147,8 +149,6 @@
private final GwtAstBuilder astBuilder = new GwtAstBuilder();
- private final boolean suppressErrors;
-
private transient LinkedBlockingQueue<CompilationUnitBuilder> buildQueue;
/**
@@ -162,6 +162,8 @@
private final JSORestrictionsChecker.CheckerState jsoState =
new JSORestrictionsChecker.CheckerState();
+ private final boolean suppressErrors;
+
public CompileMoreLater(AdditionalTypeProviderDelegate delegate, boolean suppressErrors) {
compiler.setAdditionalTypeProviderDelegate(delegate);
this.suppressErrors = suppressErrors;
@@ -323,7 +325,8 @@
if (suppressErrors && errorCount > 0 && !logger.isLoggable(TreeLogger.TRACE)
&& logger.isLoggable(TreeLogger.INFO)) {
logger.log(TreeLogger.INFO, "Ignored " + errorCount + " unit" + (errorCount > 1 ? "s" : "")
- + " with compilation errors in first pass. Specify -logLevel DEBUG to see all errors");
+ + " with compilation errors in first pass.\n"
+ + "Compile with -strict or with -logLevel set to TRACE or DEBUG to see all errors.");
}
return resultUnits;
}
@@ -331,6 +334,26 @@
private static final CompilationStateBuilder instance = new CompilationStateBuilder();
+ /**
+ * Use previously compiled {@link CompilationUnit}s to pre-populate the unit
+ * cache.
+ */
+ public static void addArchive(CompilationUnitArchive module) {
+ UnitCache unitCache = instance.unitCache;
+ for (CompilationUnit unit : module.getUnits().values()) {
+ CompilationUnit cachedCompilationUnit = unitCache.find(unit.getResourcePath());
+ // A previously cached unit might be from the persistent cache or another
+ // archive
+ if (cachedCompilationUnit == null
+ || cachedCompilationUnit.getLastModified() < unit.getLastModified()) {
+ // TODO(zundel): mark these units as being a part of an archive.
+ // that way, the persistent unit cache won't need to bother to write
+ // them out.
+ unitCache.addArchivedUnit(unit);
+ }
+ }
+ }
+
public static CompilationState buildFrom(TreeLogger logger, Set<Resource> resources) {
return buildFrom(logger, resources, null, false);
}
@@ -355,7 +378,7 @@
}
/**
- * Called to setup the directory where the persistent {@link ComplationUnit}
+ * Called to setup the directory where the persistent {@link CompilationUnit}
* cache should be stored. Only the first call to init() will have an effect.
*/
public static synchronized void init(TreeLogger logger, File cacheDirectory) {
@@ -371,7 +394,7 @@
/**
* Build a new compilation state from a source oracle. Allow the caller to
* specify a compiler delegate that will handle undefined names.
- *
+ *
* TODO: maybe use a finer brush than to synchronize the whole thing.
*/
public synchronized CompilationState doBuildFrom(TreeLogger logger, Set<Resource> resources,
@@ -394,13 +417,13 @@
new ResourceCompilationUnitBuilder(typeName, resource);
CompilationUnit cachedUnit = unitCache.find(resource.getPathPrefix() + resource.getPath());
-
+
// Try to rescue cached units from previous sessions where a jar has been
// recompiled.
if (cachedUnit != null && cachedUnit.getLastModified() != resource.getLastModified()) {
unitCache.remove(cachedUnit);
- if (cachedUnit instanceof CachedCompilationUnit &&
- cachedUnit.getContentId().equals(builder.getContentId())) {
+ if (cachedUnit instanceof CachedCompilationUnit
+ && cachedUnit.getContentId().equals(builder.getContentId())) {
CachedCompilationUnit updatedUnit =
new CachedCompilationUnit((CachedCompilationUnit) cachedUnit, resource
.getLastModified(), resource.getLocation());
@@ -434,7 +457,7 @@
/**
* Compile new generated units into an existing state.
- *
+ *
* TODO: maybe use a finer brush than to synchronize the whole thing.
*/
synchronized Collection<CompilationUnit> doBuildGeneratedTypes(TreeLogger logger,
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
index e9c8881..fd30f4f 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
@@ -175,9 +175,10 @@
protected static final DiskCache diskCache = DiskCache.INSTANCE;
- static final Comparator<CompilationUnit> COMPARATOR = new Comparator<CompilationUnit>() {
+ public static final Comparator<CompilationUnit> COMPARATOR = new Comparator<CompilationUnit>() {
+ @Override
public int compare(CompilationUnit o1, CompilationUnit o2) {
- return o1.getTypeName().compareTo(o2.getTypeName());
+ return o1.getResourcePath().compareTo(o2.getResourcePath());
}
};
@@ -210,8 +211,8 @@
private transient Map<String, String> anonymousClassMap = null;
/**
- * Returns the unit as an instance of {@link CachedCompilationUnit}, making
- * a copy if necessary.
+ * Returns the unit as an instance of {@link CachedCompilationUnit}, making a
+ * copy if necessary.
*/
public abstract CachedCompilationUnit asCachedCompilationUnit();
@@ -293,7 +294,7 @@
* for this unit originated. This should be unique for each unit compiled to
* create a module.
*
- * @see {@link com.google.gwt.dev.resource.Resource#getLocation()}
+ * @see com.google.gwt.dev.resource.Resource#getLocation()
*/
public abstract String getResourceLocation();
@@ -301,8 +302,8 @@
* Returns the full abstract path of the resource. If a resource has been
* re-rooted, this path should include any path prefix that was stripped.
*
- * @see {@link com.google.gwt.dev.resource.Resource#getPath()} and
- * {@link com.google.gwt.dev.resource.Resource#getPathPrefix()}
+ * @see com.google.gwt.dev.resource.Resource#getPath()
+ * @see com.google.gwt.dev.resource.Resource#getPathPrefix()
*/
public abstract String getResourcePath();
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitArchive.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitArchive.java
new file mode 100644
index 0000000..6cf2468
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitArchive.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2011 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.javac;
+
+import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * This class represents a file that contains {@link CachedCompilationUnit}s
+ * that make up a module.
+ *
+ * Intended to work with other CompilationUnitArchives on the class path to
+ * allow a project to be compiled incrementally. Therefore, one file may not
+ * contain all dependent compilation units. To get all dependent compilation
+ * units, the program will need to load all archives, plus any files not
+ * contained in any archive.
+ *
+ * No mater how the archive is created, when serialized, the output file
+ * should be deterministic.
+ */
+public class CompilationUnitArchive implements Serializable {
+
+ public static CompilationUnitArchive createFromFile(File location) throws IOException,
+ ClassNotFoundException {
+ return createFromStream(new FileInputStream(location));
+ }
+
+ public static CompilationUnitArchive createFromStream(InputStream stream) throws IOException,
+ ClassNotFoundException {
+ ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(stream));
+ CompilationUnitArchive result = (CompilationUnitArchive) ois.readObject();
+ ois.close();
+ return result;
+ }
+
+ public static CompilationUnitArchive createFromURL(URL location) throws IOException,
+ ClassNotFoundException {
+ return createFromStream(location.openConnection().getInputStream());
+ }
+
+ private final String topModuleName;
+ private transient Map<String, CompilationUnit> units;
+
+ /**
+ * Create an archive object. Note that data is retained in memory only until
+ * the {@link #writeToFile(File)} method is invoked.
+ *
+ * @param topModuleName The name of the module used to compile this archive.
+ * That is, the original parameter passed to
+ * {@link com.google.gwt.dev.CompileModule}.
+ */
+ public CompilationUnitArchive(String topModuleName) {
+ units = new TreeMap<String, CompilationUnit>();
+ this.topModuleName = topModuleName;
+ }
+
+ /**
+ * Add a compilation unit to the archive.
+ */
+ public void addUnit(CompilationUnit unit) {
+ units.put(unit.getResourcePath(), unit);
+ }
+
+ public CompilationUnit findUnit(String resourcePath) {
+ return units.get(resourcePath);
+ }
+
+ /**
+ * The name of the module used to compile this archive.
+ */
+ public String getTopModuleName() {
+ return topModuleName;
+ }
+
+ /**
+ * Retrieve all units stored in this archive.
+ */
+ public Map<String, CompilationUnit> getUnits() {
+ return ImmutableMap.copyOf(units);
+ }
+
+ /**
+ * Persists the units currently stored in the archive to the specified file. The file
+ * is immediately closed.
+ */
+ public void writeToFile(File location) throws IOException {
+ ObjectOutputStream oos =
+ new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(location)));
+ oos.writeObject(this);
+ oos.close();
+ }
+
+ private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
+ stream.defaultReadObject();
+ units = new TreeMap<String, CompilationUnit>();
+ CompilationUnit unitsIn[] = (CompilationUnit[]) stream.readObject();
+ for (CompilationUnit unit : unitsIn) {
+ assert unit != null;
+ addUnit(unit);
+ }
+ }
+
+ // CompilationUnits are serialized as a sorted array in order to make sure the
+ // output format is deterministic.
+ private void writeObject(ObjectOutputStream stream) throws IOException {
+ stream.defaultWriteObject();
+ CompilationUnit unitsOut[] = units.values().toArray(new CompilationUnit[units.size()]);
+ Arrays.sort(unitsOut, CompilationUnit.COMPARATOR);
+ stream.writeObject(unitsOut);
+ }
+}
diff --git a/dev/core/src/com/google/gwt/dev/javac/MemoryUnitCache.java b/dev/core/src/com/google/gwt/dev/javac/MemoryUnitCache.java
index f7c4bbf..971a1d8 100644
--- a/dev/core/src/com/google/gwt/dev/javac/MemoryUnitCache.java
+++ b/dev/core/src/com/google/gwt/dev/javac/MemoryUnitCache.java
@@ -34,8 +34,8 @@
* Storage for a compilation unit in the map.
*/
protected static class UnitCacheEntry {
- private final CompilationUnit unit;
private final UnitOrigin origin;
+ private final CompilationUnit unit;
protected UnitCacheEntry(CompilationUnit unit, UnitOrigin source) {
this.unit = unit;
@@ -44,11 +44,11 @@
public UnitOrigin getOrigin() {
return origin;
- };
+ }
public CompilationUnit getUnit() {
return unit;
- };
+ }
}
/**
@@ -58,6 +58,11 @@
*/
protected static enum UnitOrigin {
/**
+ * Unit was loaded from an archive.
+ */
+ ARCHIVE,
+
+ /**
* Unit was loaded from persistent store.
*/
PERSISTENT,
@@ -89,24 +94,29 @@
/**
* Adds a new entry into the cache.
*/
+ @Override
public void add(CompilationUnit newUnit) {
- UnitCacheEntry newEntry = new UnitCacheEntry(newUnit, UnitOrigin.RUN_TIME);
- String resourcePath = newUnit.getResourcePath();
- UnitCacheEntry oldEntry = unitMap.get(resourcePath);
- if (oldEntry != null) {
- remove(oldEntry.getUnit());
- }
- unitMap.put(resourcePath, newEntry);
- unitMapByContentId.put(newUnit.getContentId(), newEntry);
+ add(newUnit, UnitOrigin.RUN_TIME);
+ }
+
+ /**
+ * Adds a new entry into the cache, but marks it as already coming from a
+ * persistent archive. This means it doesn't need to be saved out to disk.
+ */
+ @Override
+ public void addArchivedUnit(CompilationUnit newUnit) {
+ add(newUnit, UnitOrigin.ARCHIVE);
}
/**
* This method is a no-op for an in-memory cache.
*/
+ @Override
public synchronized void cleanup(final TreeLogger logger) {
// do nothing.
}
+ @Override
public CompilationUnit find(ContentId contentId) {
UnitCacheEntry entry = unitMapByContentId.get(contentId);
if (entry != null) {
@@ -115,6 +125,7 @@
return null;
}
+ @Override
public CompilationUnit find(String resourcePath) {
UnitCacheEntry entry = unitMap.get(resourcePath);
if (entry != null) {
@@ -123,8 +134,20 @@
return null;
}
+ @Override
public void remove(CompilationUnit unit) {
unitMap.remove(unit.getResourcePath());
unitMapByContentId.remove(unit.getContentId());
}
+
+ private void add(CompilationUnit newUnit, UnitOrigin origin) {
+ UnitCacheEntry newEntry = new UnitCacheEntry(newUnit, origin);
+ String resourcePath = newUnit.getResourcePath();
+ UnitCacheEntry oldEntry = unitMap.get(resourcePath);
+ if (oldEntry != null) {
+ remove(oldEntry.getUnit());
+ }
+ unitMap.put(resourcePath, newEntry);
+ unitMapByContentId.put(newUnit.getContentId(), newEntry);
+ }
}
diff --git a/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java b/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java
index d11de53..17065dd 100644
--- a/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java
+++ b/dev/core/src/com/google/gwt/dev/javac/PersistentUnitCache.java
@@ -219,6 +219,7 @@
assert unitWriteQueue.size() == 0;
break;
} else {
+ assert msg.unitCacheEntry.getOrigin() != UnitOrigin.ARCHIVE;
CompilationUnit unit = msg.unitCacheEntry.getUnit();
assert unit != null;
stream.writeObject(unit);
@@ -346,8 +347,9 @@
public void add(CompilationUnit newUnit) {
unitCacheMapLoader.await();
super.add(newUnit);
+ UnitCacheEntry entry = unitMap.get(newUnit.getResourcePath());
addCount.getAndIncrement();
- unitWriteQueue.add(new UnitWriteMessage(unitMap.get(newUnit.getResourcePath())));
+ unitWriteQueue.add(new UnitWriteMessage(entry));
}
/**
diff --git a/dev/core/src/com/google/gwt/dev/javac/UnitCache.java b/dev/core/src/com/google/gwt/dev/javac/UnitCache.java
index ae5fec2..c32f502 100644
--- a/dev/core/src/com/google/gwt/dev/javac/UnitCache.java
+++ b/dev/core/src/com/google/gwt/dev/javac/UnitCache.java
@@ -28,6 +28,13 @@
void add(CompilationUnit newUnit);
/**
+ * Adds a new entry into the cache, but marks it as already coming from a
+ * persistent archive. This means it doesn't need to be saved out to disk in a
+ * persistent implementation of the cache.
+ */
+ void addArchivedUnit(CompilationUnit newUnit);
+
+ /**
* Each run of the compiler should call {@link #cleanup(TreeLogger)} when
* finished adding units to the cache so that cache files from previous runs
* can be purged from a persistent cache.
@@ -43,7 +50,7 @@
* Lookup a {@link CompilationUnit} by resource path. This should include any
* path prefix that may have been was stripped to reroot the resource.
*
- * @see {@link CompilationUnit#getResourcePath()}
+ * @see CompilationUnit#getResourcePath()
*/
CompilationUnit find(String resourcePath);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
index 819f123..bac3201 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -47,7 +47,6 @@
import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory;
import com.google.gwt.dev.jjs.CorrelationFactory.RealCorrelationFactory;
-import com.google.gwt.dev.jjs.InternalCompilerException.NodeInfo;
import com.google.gwt.dev.jjs.UnifiedAst.AST;
import com.google.gwt.dev.jjs.ast.Context;
import com.google.gwt.dev.jjs.ast.JBinaryOperation;
@@ -462,7 +461,7 @@
}
return toReturn;
} catch (Throwable e) {
- throw logAndTranslateException(logger, e);
+ throw CompilationProblemReporter.logAndTranslateException(logger, e);
} finally {
jjsCompilePermutationEvent.end();
}
@@ -709,7 +708,7 @@
createUnifiedAstEvent.end();
return result;
} catch (Throwable e) {
- throw logAndTranslateException(logger, e);
+ throw CompilationProblemReporter.logAndTranslateException(logger, e);
} finally {
}
}
@@ -1146,48 +1145,6 @@
return v.classNames.toArray(new String[v.classNames.size()]);
}
- private static UnableToCompleteException logAndTranslateException(TreeLogger logger, Throwable e) {
- if (e instanceof UnableToCompleteException) {
- // just rethrow
- return (UnableToCompleteException) e;
- } else if (e instanceof InternalCompilerException) {
- TreeLogger topBranch =
- logger.branch(TreeLogger.ERROR, "An internal compiler exception occurred", e);
- List<NodeInfo> nodeTrace = ((InternalCompilerException) e).getNodeTrace();
- for (NodeInfo nodeInfo : nodeTrace) {
- SourceInfo info = nodeInfo.getSourceInfo();
- String msg;
- if (info != null) {
- String fileName = info.getFileName();
- fileName = fileName.substring(fileName.lastIndexOf('/') + 1);
- fileName = fileName.substring(fileName.lastIndexOf('\\') + 1);
- msg = "at " + fileName + "(" + info.getStartLine() + "): ";
- } else {
- msg = "<no source info>: ";
- }
-
- String description = nodeInfo.getDescription();
- if (description != null) {
- msg += description;
- } else {
- msg += "<no description available>";
- }
- TreeLogger nodeBranch = topBranch.branch(TreeLogger.ERROR, msg, null);
- String className = nodeInfo.getClassName();
- if (className != null && logger.isLoggable(TreeLogger.INFO)) {
- nodeBranch.log(TreeLogger.INFO, className, null);
- }
- }
- return new UnableToCompleteException();
- } else if (e instanceof VirtualMachineError) {
- // Always rethrow VM errors (an attempt to wrap may fail).
- throw (VirtualMachineError) e;
- } else {
- logger.log(TreeLogger.ERROR, "Unexpected internal compiler error", e);
- return new UnableToCompleteException();
- }
- }
-
/*
* This method is intended as a central location for producing optional
* tracking output. This will be called after all optimization/normalization
diff --git a/dev/core/src/com/google/gwt/dev/util/log/speedtracer/CompilerEventType.java b/dev/core/src/com/google/gwt/dev/util/log/speedtracer/CompilerEventType.java
index abaf3c8..0d4c6f9 100644
--- a/dev/core/src/com/google/gwt/dev/util/log/speedtracer/CompilerEventType.java
+++ b/dev/core/src/com/google/gwt/dev/util/log/speedtracer/CompilerEventType.java
@@ -70,7 +70,8 @@
CHECK_FOR_ERRORS("CheckForErrors", "DimGrey"), //
GRAPHICS_INIT("Graphics2D.createGraphics()", "Blue"), //
ANALYZE_MODULE("AnalyzeModule", "LightBlue"), //
- COMPILE_MODULE("CompileModule", "LightBlue"); //
+ COMPILE_MODULE("CompileModule", "LightBlue"),
+ LOAD_ARCHIVE("LoadArchive", "DarkSlateBlue"); //
final String cssColor;
final String name;
diff --git a/dev/core/test/com/google/gwt/dev/javac/CompilationUnitArchiveTest.java b/dev/core/test/com/google/gwt/dev/javac/CompilationUnitArchiveTest.java
new file mode 100644
index 0000000..1ef790d
--- /dev/null
+++ b/dev/core/test/com/google/gwt/dev/javac/CompilationUnitArchiveTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2011 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.javac;
+
+import com.google.gwt.dev.util.Util;
+import com.google.gwt.util.tools.Utility;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.IOException;
+
+public class CompilationUnitArchiveTest extends TestCase {
+ private static final String MOCK_TYPE_1 = "com.example.Foo";
+ private static final String MOCK_TYPE_2 = "com.example.Bar";
+ private static final String MOCK_TYPE_3 = "com.example.Baz";
+
+ /**
+ * Some build systems insist that given the same inputs, the compiler produce
+ * the same output every time.
+ */
+ public void testDeterministicOutput() throws IOException {
+ int numMockTypes = 100;
+ CompilationUnit mockUnits[] = new CompilationUnit[numMockTypes];
+ for (int i = 0; i < numMockTypes; i++) {
+ mockUnits[i] = new MockCompilationUnit("com.example.MockType" + i, "Dummy Source " + i);
+ }
+
+ File tmpDir = Utility.makeTemporaryDirectory(null, "cgmt-");
+ int numLoops = 100;
+ String lastStrongName = null;
+ for (int i = 0; i < numLoops; i++) {
+ File tmpFile = new File(tmpDir, "module" + i + ".ser");
+ tmpFile.deleteOnExit();
+ scrambleArray(mockUnits);
+ CompilationUnitArchive archive = new CompilationUnitArchive("com.example.Module");
+ for (int j = 0; j < numMockTypes; j++) {
+ archive.addUnit(mockUnits[j]);
+ }
+ archive.writeToFile(tmpFile);
+ // grab the md5 signature of the file as a string
+ byte[] bytes = Util.readFileAsBytes(tmpFile);
+ tmpFile.delete();
+ String thisStrongName = Util.computeStrongName(bytes);
+ if (lastStrongName != null) {
+ assertEquals("loop " + i, thisStrongName, lastStrongName);
+ }
+ lastStrongName = thisStrongName;
+ }
+ tmpDir.delete();
+ }
+
+ public void testReadWrite() throws IOException, ClassNotFoundException {
+ CompilationUnitArchive archive1 = new CompilationUnitArchive("com.example.Foo");
+ MockCompilationUnit unit1 = new MockCompilationUnit(MOCK_TYPE_1, "Foo");
+ MockCompilationUnit unit2 = new MockCompilationUnit(MOCK_TYPE_2, "Bar");
+ MockCompilationUnit unit3 = new MockCompilationUnit(MOCK_TYPE_3, "Baz");
+
+ archive1.addUnit(unit1);
+ archive1.addUnit(unit2);
+ archive1.addUnit(unit3);
+
+ assertEquals(3, archive1.getUnits().size());
+ compareUnits(unit1, archive1, MOCK_TYPE_1);
+ compareUnits(unit2, archive1, MOCK_TYPE_2);
+ compareUnits(unit3, archive1, MOCK_TYPE_3);
+
+ File tmp = File.createTempFile("cu-archive-test", ".ser");
+ tmp.deleteOnExit();
+ archive1.writeToFile(tmp);
+ CompilationUnitArchive archive2 = CompilationUnitArchive.createFromFile(tmp);
+
+ assertEquals(3, archive2.getUnits().size());
+ compareUnits(unit1, archive2, MOCK_TYPE_1);
+ compareUnits(unit2, archive2, MOCK_TYPE_2);
+ compareUnits(unit3, archive2, MOCK_TYPE_3);
+ }
+
+ private void compareUnits(MockCompilationUnit unit, CompilationUnitArchive archive, String lookupType) {
+ CompilationUnit found = archive.findUnit(unit.getResourcePath());
+ assertEquals(found.getTypeName(), lookupType);
+ assertEquals(found.getResourceLocation(), unit.getResourceLocation());
+ assertEquals(found.getSource(), unit.getSource());
+ }
+
+ private void scrambleArray(Object[] array) {
+ final int max = array.length;
+ for (int i = 0; i < max; i++) {
+ int randomIdx;
+ do {
+ randomIdx = (int) (Math.random() * (max - 1));
+ } while (i == randomIdx);
+
+ Object tmp = array[randomIdx];
+ array[randomIdx] = array[i % array.length];
+ array[i % array.length] = tmp;
+ }
+ }
+}
diff --git a/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java b/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
index 2b16917..77f9e0a 100644
--- a/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
+++ b/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
@@ -25,9 +25,9 @@
import java.util.concurrent.atomic.AtomicInteger;
/**
- * Used by {@link MemoryUnitTest} and {@link PersistentUnitTest}.
+ * Used by {@link MemoryUnitCacheTest} and {@link PersistentUnitCacheTest}.
*/
-class MockCompilationUnit extends CompilationUnit {
+public class MockCompilationUnit extends CompilationUnit {
private static final AtomicInteger nextTimestamp = new AtomicInteger(1);
private final ContentId contentId;
diff --git a/servlet/build.xml b/servlet/build.xml
index c5cb923..c33229f 100755
--- a/servlet/build.xml
+++ b/servlet/build.xml
@@ -37,6 +37,7 @@
<exclude name="com/google/gwt/junit/remote/**" />
<exclude name="com/google/gwt/junit/server/**" />
<exclude name="com/google/gwt/benchmarks/*" />
+ <exclude name="**/*.gwtar" />
</fileset>
<!-- additional dependencies (used by scripts). -->
diff --git a/user/build.xml b/user/build.xml
index bb1d8dd..579e7a6 100755
--- a/user/build.xml
+++ b/user/build.xml
@@ -141,7 +141,65 @@
</gwt.javac>
</target>
- <target name="build" depends="compile"
+ <!-- Precompile some GWT modules to speed up end-user builds -->
+ <!-- TODO(zundel): Find a way to precompile all modules -->
+ <!-- without tedious manual specification -->
+ <target name="precompile.modules" depends="compile">
+ <outofdate>
+ <sourcefiles>
+ <fileset dir="${gwt.root}/user/src" />
+ <fileset dir="${gwt.root}/user/super" />
+ <fileset dir="${gwt.root}/dev/core/src" />
+ <fileset dir="${gwt.root}/dev/core/super" />
+ <fileset file="${gwt.dev.jar}" />
+ </sourcefiles>
+ <targetfiles>
+ <!-- TODO(zundel): this is a mechanical transform -->
+ <!-- from module name. There must be a better way. -->
+ <pathelement location="${project.build}/bin/com/google/gwt/core/Core.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/json/JSON.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/regexp/RegExp.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/user/User.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/xml/XML.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/rpc/RPC.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/debug/Debug.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/place/Place.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/activity/Activity.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/web/bindery/event/Event.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/web/bindery/autobean/AutoBean.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/web/bindery/requestfactory/RequestFactory.gwtar" />
+ <pathelement location="${project.build}/bin/com/google/gwt/logging/Logging.gwtar" />
+ </targetfiles>
+ <sequential>
+ <compileModule>
+ <module>
+ <!-- Order is important! Modules that inherit from -->
+ <!-- others should come later in the list. -->
+ <!-- All modules depend on Core -->
+ <arg value="com.google.gwt.core.Core" />
+ <arg value="com.google.gwt.json.JSON" />
+ <arg value="com.google.gwt.regexp.RegExp" />
+ <arg value="com.google.gwt.user.User" />
+
+ <!-- Below are modules that depend on User -->
+ <arg value="com.google.gwt.xml.XML" />
+ <arg value="com.google.gwt.rpc.RPC" />
+ <arg value="com.google.gwt.debug.Debug" />
+ <arg value="com.google.gwt.logging.Logging" />
+
+ <arg value="com.google.gwt.place.Place" />
+ <arg value="com.google.gwt.activity.Activity" />
+
+ <arg value="com.google.web.bindery.event.Event" />
+ <arg value="com.google.web.bindery.autobean.AutoBean" />
+ <arg value="com.google.web.bindery.requestfactory.RequestFactory" />
+ </module>
+ </compileModule>
+ </sequential>
+ </outofdate>
+ </target>
+
+ <target name="build" depends="precompile.modules"
description="Build and package this project">
<mkdir dir="${gwt.build.lib}" />
<gwt.jar>
@@ -704,6 +762,31 @@
</sequential>
</macrodef>
+ <macrodef name="compileModule">
+ <element name="module" />
+ <sequential>
+ <gwt.timer name="Pre-compile module">
+ <java classname="com.google.gwt.dev.CompileModule" fork="yes" failonerror="true">
+ <classpath>
+ <pathelement location="${gwt.root}/user/src" />
+ <pathelement location="${gwt.root}/user/super" />
+ <pathelement location="${gwt.root}/dev/core/src" />
+ <pathelement location="${gwt.root}/dev/core/super" />
+ <pathelement location="${gwt.tools.lib}/javax/validation/validation-api-1.0.0.GA.jar" />
+ <pathelement location="${gwt.tools.lib}/javax/validation/validation-api-1.0.0.GA-sources.jar" />
+ <pathelement location="${gwt.root}/build/out/user/bin" />
+ <pathelement location="${gwt.dev.jar}" />
+ </classpath>
+ <jvmarg value="-Xmx512M" />
+ <module />
+ <arg value="-strict" />
+ <arg value="-out" />
+ <arg value="${project.build}/bin" />
+ </java>
+ </gwt.timer>
+ </sequential>
+ </macrodef>
+
<target name="tck.report">
<mkdir dir="${junit.out}/tck-report" />
<mkdir dir="${junit.out}/tck-report/text" />
diff --git a/user/src/com/google/gwt/activity/Activity.gwt.xml b/user/src/com/google/gwt/activity/Activity.gwt.xml
index 78b19d0..dbdd296 100644
--- a/user/src/com/google/gwt/activity/Activity.gwt.xml
+++ b/user/src/com/google/gwt/activity/Activity.gwt.xml
@@ -1,7 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 0.0.999//EN" "http://google-web-toolkit.googlecode.com/svn/tags/0.0.999/distro-source/core/src/gwt-module.dtd">
<module>
- <inherits name='com.google.gwt.user.User'/>
<inherits name='com.google.gwt.place.Place'/>
<source path="shared"/>
diff --git a/user/src/com/google/gwt/debug/Debug.gwt.xml b/user/src/com/google/gwt/debug/Debug.gwt.xml
index 338588a..9d77e6d 100644
--- a/user/src/com/google/gwt/debug/Debug.gwt.xml
+++ b/user/src/com/google/gwt/debug/Debug.gwt.xml
@@ -14,6 +14,8 @@
<!-- Adds debug ID support for UIObjects. -->
<module>
+ <inherits name="com.google.gwt.core.Core" />
+
<!-- Enable or disable the UIObject.ensureDebugID method -->
<define-property name="gwt.enableDebugId" values="true, false"/>
diff --git a/user/src/com/google/gwt/i18n/CldrLocales.gwt.xml b/user/src/com/google/gwt/i18n/CldrLocales.gwt.xml
index 6c80f23..9a109da 100644
--- a/user/src/com/google/gwt/i18n/CldrLocales.gwt.xml
+++ b/user/src/com/google/gwt/i18n/CldrLocales.gwt.xml
@@ -14,6 +14,8 @@
<!-- List of all locales imported into GWT from CLDR, as runtime locales -->
<module>
+ <inherits name="com.google.gwt.user.User"/>
+ <inherits name="com.google.gwt.i18n.I18N"/>
<extend-configuration-property name="runtime.locales" value="aa"/>
<extend-configuration-property name="runtime.locales" value="aa_DJ"/>
<extend-configuration-property name="runtime.locales" value="aa_ER"/>
diff --git a/user/src/com/google/gwt/i18n/I18N.gwt.xml b/user/src/com/google/gwt/i18n/I18N.gwt.xml
index 6473a34..15f35ab 100644
--- a/user/src/com/google/gwt/i18n/I18N.gwt.xml
+++ b/user/src/com/google/gwt/i18n/I18N.gwt.xml
@@ -15,6 +15,7 @@
<!-- Internationalization support. -->
<!-- -->
<module>
+ <inherits name="com.google.gwt.core.Core" />
<inherits name="com.google.gwt.regexp.RegExp"/>
<inherits name="com.google.gwt.safehtml.SafeHtml"/>
<source path="" includes="client/,shared/" />
diff --git a/user/src/com/google/gwt/logging/Logging.gwt.xml b/user/src/com/google/gwt/logging/Logging.gwt.xml
index 4646c37..6989f1b 100644
--- a/user/src/com/google/gwt/logging/Logging.gwt.xml
+++ b/user/src/com/google/gwt/logging/Logging.gwt.xml
@@ -13,7 +13,8 @@
<!-- limitations under the License. -->
<module>
- <inherits name='com.google.gwt.json.JSON'/>
+ <inherits name="com.google.gwt.json.JSON"/>
+ <inherits name="com.google.gwt.user.User" />
<inherits name="com.google.gwt.logging.LogImpl"/>
<source path="client" />
<source path="shared" />
diff --git a/user/src/com/google/gwt/regexp/RegExp.gwt.xml b/user/src/com/google/gwt/regexp/RegExp.gwt.xml
index 285dd66..146103c 100644
--- a/user/src/com/google/gwt/regexp/RegExp.gwt.xml
+++ b/user/src/com/google/gwt/regexp/RegExp.gwt.xml
@@ -14,6 +14,7 @@
<!-- regular expressions support. -->
<module>
+ <inherits name="com.google.gwt.core.Core" />
<source path="shared" />
<super-source path="super" />
</module>
diff --git a/user/src/com/google/gwt/storage/Storage.gwt.xml b/user/src/com/google/gwt/storage/Storage.gwt.xml
index 98c0055..48c79de 100644
--- a/user/src/com/google/gwt/storage/Storage.gwt.xml
+++ b/user/src/com/google/gwt/storage/Storage.gwt.xml
@@ -13,8 +13,7 @@
<!-- limitations under the License. -->
<module>
- <inherits name="com.google.gwt.core.Core" />
- <inherits name="com.google.gwt.user.UserAgent" />
+ <inherits name="com.google.gwt.user.User" />
<!-- Define the storage support property -->
<define-property name="storageSupport" values="maybe,no" />
diff --git a/user/src/com/google/gwt/view/View.gwt.xml b/user/src/com/google/gwt/view/View.gwt.xml
index 06676be..21babcb 100644
--- a/user/src/com/google/gwt/view/View.gwt.xml
+++ b/user/src/com/google/gwt/view/View.gwt.xml
@@ -14,6 +14,6 @@
the License.
-->
<module>
- <inherits name="com.google.gwt.core.Core"/>
+ <inherits name="com.google.gwt.user.User"/>
<source path="client"/>
</module>
diff --git a/user/src/com/google/gwt/xml/XML.gwt.xml b/user/src/com/google/gwt/xml/XML.gwt.xml
index 4eaf0d1..3c75c56 100644
--- a/user/src/com/google/gwt/xml/XML.gwt.xml
+++ b/user/src/com/google/gwt/xml/XML.gwt.xml
@@ -15,9 +15,8 @@
<!-- XML parsing support. -->
<!-- -->
<module>
- <inherits name="com.google.gwt.core.Core"/>
- <inherits name="com.google.gwt.user.UserAgent"/>
-
+ <inherits name="com.google.gwt.user.User"/>
+
<!-- Fall through to this rule for all other browsers -->
<replace-with class="com.google.gwt.xml.client.impl.XMLParserImplStandard">
<when-type-is class="com.google.gwt.xml.client.impl.XMLParserImpl"/>
diff --git a/user/src/com/google/web/bindery/autobean/AutoBean.gwt.xml b/user/src/com/google/web/bindery/autobean/AutoBean.gwt.xml
index 88b8981..fc7fbd8 100644
--- a/user/src/com/google/web/bindery/autobean/AutoBean.gwt.xml
+++ b/user/src/com/google/web/bindery/autobean/AutoBean.gwt.xml
@@ -13,7 +13,6 @@
<!-- AutoBean framework -->
<module>
- <inherits name="com.google.gwt.core.Core" />
<inherits name="com.google.gwt.user.User" />
<source path="gwt/client" />
<source path="shared" />
diff --git a/user/src/com/google/web/bindery/event/Event.gwt.xml b/user/src/com/google/web/bindery/event/Event.gwt.xml
index 8bafd18..bd600e6 100644
--- a/user/src/com/google/web/bindery/event/Event.gwt.xml
+++ b/user/src/com/google/web/bindery/event/Event.gwt.xml
@@ -14,5 +14,7 @@
the License.
-->
<module>
+ <inherits name="com.google.gwt.core.Core" />
+
<source path="shared" />
</module>