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>