Super Dev Mode: remove -Xincremental and add new JobEvent properties Removed -Xincremental which was the old incremental mode. (We are going to use -XcompilePerFile in Super Dev Mode.) New Job Event properties: - getArguments() returns the command-line arguments. - getCompileStrategy() returns an enum indicating if the compile was full, incremental, or skipped. Change-Id: I0606db5374faab778a46f3a90e6904f00917e6ce Review-Link: https://gwt-review.googlesource.com/#/c/9100/
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Job.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Job.java index 845215e..b94c0c5 100644 --- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Job.java +++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Job.java
@@ -18,8 +18,10 @@ import com.google.gwt.core.ext.TreeLogger; import com.google.gwt.core.ext.TreeLogger.Type; import com.google.gwt.dev.cfg.ModuleDef; +import com.google.gwt.dev.codeserver.JobEvent.CompileStrategy; import com.google.gwt.dev.codeserver.JobEvent.Status; import com.google.gwt.thirdparty.guava.common.base.Preconditions; +import com.google.gwt.thirdparty.guava.common.collect.ImmutableList; import com.google.gwt.thirdparty.guava.common.collect.ImmutableSortedMap; import com.google.gwt.thirdparty.guava.common.util.concurrent.Futures; import com.google.gwt.thirdparty.guava.common.util.concurrent.ListenableFuture; @@ -67,12 +69,15 @@ // Miscellaneous + private final ImmutableList<String> args; + /** * The id to report to the recompile listener. */ private int compileId = -1; // non-negative after the compile has started private CompileDir compileDir; // non-null after the compile has started + private CompileStrategy compileStrategy; // non-null after the compile has started private Exception listenerFailure; @@ -83,16 +88,16 @@ * @param parentLogger The parent of the logger that will be used for this job. */ Job(Outbox box, Map<String, String> bindingProperties, - TreeLogger parentLogger, RecompileListener recompileListener, - JobChangeListener jobChangeListener) { + TreeLogger parentLogger, Options options) { this.id = chooseNextId(box); this.outbox = box; this.inputModuleName = box.getInputModuleName(); // TODO: we will use the binding properties to find or create the outbox, // then take binding properties from the outbox here. this.bindingProperties = ImmutableSortedMap.copyOf(bindingProperties); - this.recompileListener = Preconditions.checkNotNull(recompileListener); - this.jobChangeListener = Preconditions.checkNotNull(jobChangeListener); + this.recompileListener = Preconditions.checkNotNull(options.getRecompileListener()); + this.jobChangeListener = Preconditions.checkNotNull(options.getJobChangeListener()); + this.args = Preconditions.checkNotNull(options.getArgs()); this.logSupplier = new LogSupplier(parentLogger, id); } @@ -214,12 +219,20 @@ * @throws IllegalStateException if the job is not running. */ synchronized void onProgress(String stepMessage) { - if (table == null || table.getPublishedEvent(this).getStatus() != Status.COMPILING) { - throw new IllegalStateException("onProgress called for a job that isn't compiling: " + id); - } + checkIsCompiling("onProgress"); publish(makeEvent(Status.COMPILING, stepMessage)); } + synchronized void setCompileStrategy(CompileStrategy strategy) { + checkIsCompiling("setCompileStrategy"); + if (compileStrategy != null) { + throw new IllegalStateException("setCompileStrategy can only be set once per job"); + } + this.compileStrategy = strategy; + // Not bothering to send an event just for this change, so it will be included + // in the next event. + } + /** * Reports that this job has finished. * @throws IllegalStateException if the job is not running. @@ -269,6 +282,8 @@ out.setStatus(status); out.setMessage(message); out.setCompileDir(compileDir); + out.setCompileStrategy(compileStrategy); + out.setArguments(args); return out.build(); } @@ -287,6 +302,12 @@ table.publish(event, getLogger()); } + private void checkIsCompiling(String methodName) { + if (table == null || table.getPublishedEvent(this).getStatus() != Status.COMPILING) { + throw new IllegalStateException(methodName + " called for a job that isn't compiling: " + id); + } + } + /** * Creates a child logger on first use. */
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/JobEvent.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/JobEvent.java index 915b248..ee26865 100644 --- a/dev/codeserver/java/com/google/gwt/dev/codeserver/JobEvent.java +++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/JobEvent.java
@@ -18,9 +18,11 @@ import com.google.gwt.dev.cfg.ModuleDef; import com.google.gwt.dev.cfg.ModuleDefSchema; import com.google.gwt.thirdparty.guava.common.base.Preconditions; +import com.google.gwt.thirdparty.guava.common.collect.ImmutableList; import com.google.gwt.thirdparty.guava.common.collect.ImmutableMap; import com.google.gwt.thirdparty.guava.common.collect.ImmutableSortedMap; +import java.util.List; import java.util.Map; import java.util.SortedMap; @@ -39,6 +41,8 @@ private final String message; private final CompileDir compileDir; + private final CompileStrategy compileStrategy; + private final ImmutableList<String> arguments; private JobEvent(Builder builder) { this.jobId = Preconditions.checkNotNull(builder.jobId); @@ -49,6 +53,8 @@ // The following fields may be null. this.compileDir = builder.compileDir; + this.compileStrategy = builder.compileStrategy; + this.arguments = ImmutableList.copyOf(builder.args); // Any new fields added should allow nulls for backward compatibility. } @@ -99,9 +105,24 @@ } /** + * Returns the strategy used to perform the compile or null if not available. + * (Normally available for finished compiles.) + */ + public CompileStrategy getCompileStrategy() { + return compileStrategy; + } + + /** + * The arguments passed to Super Dev Mode at startup, or null if not available. + */ + public ImmutableList<String> getArguments() { + return arguments; + } + + /** * Defines the lifecycle of a job. */ - public static enum Status { + public enum Status { WAITING("waiting", "Waiting for the compiler to start"), COMPILING("compiling", "Compiling"), SERVING("serving", "Compiled output is ready"), @@ -118,6 +139,28 @@ } /** + * The approach taken to do the compile. + */ + public enum CompileStrategy { + FULL("full"), // Compiled all the source. + INCREMENTAL("incremental"), // Only recompiled the source files that changed. + SKIPPED("skipped"); // Did not compile anything since nothing changed + + final String jsonName; + + CompileStrategy(String jsonName) { + this.jsonName = jsonName; + } + + /** + * The string to use for serialization. + */ + String getJsonName() { + return jsonName; + } + } + + /** * Creates a JobEvent. * This is public to allow external tests of code that implements {@link JobChangeListener}. * Normally all JobEvents are created in the code server. @@ -130,6 +173,8 @@ private Status status; private String message; private CompileDir compileDir; + private CompileStrategy compileStrategy; + private List<String> args = ImmutableList.of(); /** * A unique id for this job. Required. @@ -189,6 +234,22 @@ this.compileDir = compileDir; } + /** + * The strategy used to perform the compile. + * Optional. + */ + public void setCompileStrategy(CompileStrategy compileStrategy) { + this.compileStrategy = compileStrategy; + } + + /** + * The arguments passed to {@link Options#parseArgs} at startup. + * Optional but may not be null. If not set, defaults to the empty list. + */ + public void setArguments(List<String> args) { + this.args = Preconditions.checkNotNull(args); + } + public JobEvent build() { return new JobEvent(this); }
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Options.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Options.java index 3d4f6c5..b7454d1 100644 --- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Options.java +++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Options.java
@@ -27,6 +27,7 @@ import com.google.gwt.dev.util.arg.OptionLogLevel; import com.google.gwt.dev.util.arg.OptionSourceLevel; import com.google.gwt.dev.util.arg.SourceLevel; +import com.google.gwt.thirdparty.guava.common.collect.ImmutableList; import com.google.gwt.util.tools.ArgHandler; import com.google.gwt.util.tools.ArgHandlerDir; import com.google.gwt.util.tools.ArgHandlerExtra; @@ -38,6 +39,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; /** @@ -46,7 +48,8 @@ * <p>These flags are EXPERIMENTAL and subject to change.</p> */ public class Options { - private boolean compileIncremental = false; + private ImmutableList<String> args; + private boolean compilePerFile = false; private boolean noPrecompile = false; private boolean isCompileTest = false; @@ -75,6 +78,11 @@ * @return true if the arguments were parsed successfully. */ public boolean parseArgs(String[] args) { + if (this.args != null) { + throw new IllegalStateException("parseArgs may only be called once"); + } + this.args = ImmutableList.copyOf(Arrays.asList(args)); + boolean ok = new ArgProcessor().processArgs(args); if (!ok) { return false; @@ -85,11 +93,6 @@ return false; } - if (compilePerFile && compileIncremental) { - System.err.println("Usage: -XcompilePerFile and -Xincremental are incompatible"); - return false; - } - if (moduleNames.isEmpty()) { System.err.println("Usage: at least one module must be supplied"); return false; @@ -104,14 +107,21 @@ } /** + * Returns the arguments passed to {@link #parseArgs}. + */ + ImmutableList<String> getArgs() { + return args; + } + + /** * A Java application that embeds Super Dev Mode can use this hook to find out * when compiles start and end. * * @deprecated replaced by {@link #setJobChangeListener} */ @Deprecated - public void setRecompileListener(RecompileListener recompileListener) { - this.recompileListener = recompileListener; + public void setRecompileListener(RecompileListener listener) { + this.recompileListener = listener == null ? RecompileListener.NONE : listener; } RecompileListener getRecompileListener() { @@ -124,8 +134,8 @@ * * <p>Replaces {@link #setRecompileListener} */ - public void setJobChangeListener(JobChangeListener jobChangeListener) { - this.jobChangeListener = jobChangeListener; + public void setJobChangeListener(JobChangeListener listener) { + this.jobChangeListener = listener == null ? JobChangeListener.NONE : listener; } JobChangeListener getJobChangeListener() { @@ -154,13 +164,6 @@ } /** - * Whether to compile a series of reusable libraries that are linked at the end. - */ - boolean shouldCompileIncremental() { - return compileIncremental; - } - - /** * Compiles faster by creating a JavaScript file per class. Can't be turned on at the same time as * shouldCompileIncremental(). */ @@ -258,7 +261,6 @@ registerHandler(new ModuleNameArgument()); registerHandler(new FailOnErrorFlag()); registerHandler(new StrictResourcesFlag()); - registerHandler(new CompileIncrementalFlag()); registerHandler(new CompilePerFileFlag()); registerHandler(new ArgHandlerSourceLevel(new OptionSourceLevel() { @Override @@ -354,35 +356,6 @@ } } - private class CompileIncrementalFlag extends ArgHandlerFlag { - - @Override - public String getLabel() { - return "incremental"; - } - - @Override - public String getPurposeSnippet() { - return "Compile and link the application as a set of separate libraries."; - } - - @Override - public boolean setFlag(boolean value) { - compileIncremental = value; - return true; - } - - @Override - public boolean getDefaultValue() { - return false; - } - - @Override - public boolean isExperimental() { - return true; - } - } - private class CompileTestFlag extends ArgHandlerFlag { @Override
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Outbox.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Outbox.java index be501e6..08171ca 100644 --- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Outbox.java +++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Outbox.java
@@ -111,8 +111,7 @@ * Creates a Job whose output will be saved in this outbox. */ Job makeJob(Map<String, String> bindingProperties, TreeLogger parentLogger) { - return new Job(this, bindingProperties, parentLogger, - options.getRecompileListener(), options.getJobChangeListener()); + return new Job(this, bindingProperties, parentLogger, options); } /**
diff --git a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java index 789fb81..14f547e 100644 --- a/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java +++ b/dev/codeserver/java/com/google/gwt/dev/codeserver/Recompiler.java
@@ -24,8 +24,6 @@ import com.google.gwt.dev.Compiler; import com.google.gwt.dev.CompilerContext; import com.google.gwt.dev.CompilerOptions; -import com.google.gwt.dev.IncrementalBuilder; -import com.google.gwt.dev.IncrementalBuilder.BuildResultStatus; import com.google.gwt.dev.MinimalRebuildCache; import com.google.gwt.dev.NullRebuildCache; import com.google.gwt.dev.cfg.BindingProperty; @@ -36,6 +34,7 @@ import com.google.gwt.dev.cfg.ResourceLoader; import com.google.gwt.dev.cfg.ResourceLoaders; import com.google.gwt.dev.codeserver.Job.Result; +import com.google.gwt.dev.codeserver.JobEvent.CompileStrategy; import com.google.gwt.dev.javac.UnitCacheSingleton; import com.google.gwt.dev.resource.impl.ResourceOracleImpl; import com.google.gwt.dev.resource.impl.ZipFileClassPathEntry; @@ -59,7 +58,6 @@ private final AppSpace appSpace; private final String inputModuleName; - private IncrementalBuilder incrementalBuilder; private String serverPrefix; private int compilesDone = 0; private Map<Map<String, String>, MinimalRebuildCache> minimalRebuildCacheForProperties = @@ -155,14 +153,7 @@ job.onStarted(compileId, compileDir); - boolean success; - if (options.shouldCompileIncremental()) { - job.onProgress("Compiling (incrementally)"); - success = compileIncremental(compileLogger, compileDir); - } else { - success = compileMonolithic(compileLogger, compileDir, job); - } - + boolean success = doCompile(compileLogger, compileDir, job); if (!success) { compileLogger.log(TreeLogger.Type.ERROR, "Compiler returned false"); throw new UnableToCompleteException(); @@ -224,40 +215,7 @@ return new Result(compileDir, null); } - private boolean compileIncremental(TreeLogger compileLogger, CompileDir compileDir) { - BuildResultStatus buildResultStatus; - // Perform a compile. - if (incrementalBuilder == null) { - // If it's the first compile. - ResourceLoader resources = ResourceLoaders.forClassLoader(Thread.currentThread()); - resources = ResourceLoaders.forPathAndFallback(options.getSourcePath(), resources); - this.resourceLoader.set(resources); - - incrementalBuilder = new IncrementalBuilder(inputModuleName, - compileDir.getWarDir().getPath(), compileDir.getWorkDir().getPath(), - compileDir.getGenDir().getPath(), resourceLoader.get()); - buildResultStatus = incrementalBuilder.build(compileLogger); - } else { - // If it's a rebuild. - incrementalBuilder.setWarDir(compileDir.getWarDir().getPath()); - buildResultStatus = incrementalBuilder.rebuild(compileLogger); - } - - if (incrementalBuilder.isRootModuleKnown()) { - outputModuleName.set(incrementalBuilder.getRootModuleName()); - } - // Unlike a monolithic compile, the incremental builder can successfully build but have no new - // output (for example when no files have changed). So it's important to only publish the new - // compileDir if it actually contains output. - if (buildResultStatus.isSuccess() && buildResultStatus.outputChanged()) { - publishedCompileDir = compileDir; - } - lastBuild.set(compileDir); // makes compile log available over HTTP - - return buildResultStatus.isSuccess(); - } - - private boolean compileMonolithic(TreeLogger compileLogger, CompileDir compileDir, Job job) + private boolean doCompile(TreeLogger compileLogger, CompileDir compileDir, Job job) throws UnableToCompleteException { job.onProgress("Loading modules"); @@ -277,9 +235,11 @@ InputSummary input = new InputSummary(bindingProperties, module); if (input.equals(lastBuildInput)) { compileLogger.log(Type.INFO, "skipped compile because no input files have changed"); + job.setCompileStrategy(CompileStrategy.SKIPPED); return true; } + job.onProgress("Compiling"); // TODO: use speed tracer to get more compiler events? @@ -288,6 +248,10 @@ // Looks up the matching rebuild cache using the final set of overridden binding properties. MinimalRebuildCache minimalRebuildCache = getOrCreateMinimalRebuildCache(bindingProperties); + + job.setCompileStrategy(minimalRebuildCache.isPopulated() ? CompileStrategy.INCREMENTAL : + CompileStrategy.FULL); + boolean success = new Compiler(runOptions, minimalRebuildCache).run(compileLogger, module); if (success) { publishedCompileDir = compileDir;
diff --git a/dev/core/src/com/google/gwt/dev/MinimalRebuildCache.java b/dev/core/src/com/google/gwt/dev/MinimalRebuildCache.java index 7a2bad8..21c5da0 100644 --- a/dev/core/src/com/google/gwt/dev/MinimalRebuildCache.java +++ b/dev/core/src/com/google/gwt/dev/MinimalRebuildCache.java
@@ -373,6 +373,13 @@ return immediateTypeRelations; } + /** + * Returns true if there is cached data to reuse in the next recompile. + */ + public boolean isPopulated() { + return !immediateTypeRelations.isEmpty(); + } + public IntTypeIdGenerator getIntTypeIdGenerator() { return intTypeIdGenerator; }