/*
* Copyright 2010 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.UnableToCompleteException;
import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
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.cfg.PropertyPermutations;
import com.google.gwt.dev.shell.CheckForUpdates;
import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
import com.google.gwt.dev.util.Memory;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerPerm;
import com.google.gwt.dev.util.arg.OptionPerm;
import com.google.gwt.dev.util.log.speedtracer.CompilerEventType;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger;
import com.google.gwt.dev.util.log.speedtracer.SpeedTracerLogger.Event;
import java.io.File;
import java.util.List;
import java.util.concurrent.FutureTask;
/**
* Creates a ready-to-compile AST for a single permutation.
*
* Also collapses similar permutations and builds them together.
*/
public class PrecompileOnePerm {
/**
* The set of options for the precompiler.
*/
public interface PrecompileOnePermOptions extends
PrecompileTaskOptions, OptionPerm {
}
static class ArgProcessor extends PrecompileTaskArgProcessor {
public ArgProcessor(PrecompileOnePermOptions options) {
super(options);
registerHandler(new ArgHandlerPerm(options));
}
@Override
protected String getName() {
return PrecompileOnePerm.class.getName();
}
}
@SuppressWarnings("serial")
static class PrecompileOnePermOptionsImpl extends
PrecompileTaskOptionsImpl implements PrecompileOnePermOptions {
int permToCompile = -1;
public PrecompileOnePermOptionsImpl() {
}
public PrecompileOnePermOptionsImpl(PrecompileOnePermOptions other) {
copyFrom(other);
}
public void copyFrom(PrecompileOnePermOptions other) {
super.copyFrom(other);
setPermToCompile(other.getPermToCompile());
}
@Override
public int getPermToCompile() {
return permToCompile;
}
@Override
public void setPermToCompile(int permToCompile) {
this.permToCompile = permToCompile;
}
}
/**
* Performs a command-line precompile.
*/
public static void main(String[] args) {
Memory.initialize();
SpeedTracerLogger.init();
Event precompileEvent = SpeedTracerLogger.start(CompilerEventType.PRECOMPILE);
if (System.getProperty("gwt.jjs.dumpAst") != null) {
System.out.println("Will dump AST to: "
+ System.getProperty("gwt.jjs.dumpAst"));
}
/*
* 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 PrecompileOnePermOptions options = new PrecompileOnePermOptionsImpl();
boolean success = false;
if (new ArgProcessor(options).processArgs(args)) {
CompileTask task = new CompileTask() {
@Override
public boolean run(TreeLogger logger) throws UnableToCompleteException {
FutureTask<UpdateResult> updater = null;
if (!options.isUpdateCheckDisabled()) {
updater = CheckForUpdates.checkForUpdatesInBackgroundThread(logger,
CheckForUpdates.ONE_DAY);
}
boolean success = new PrecompileOnePerm(options).run(logger);
if (success) {
CheckForUpdates.logUpdateAvailable(logger, updater);
}
return success;
}
};
if (CompileTaskRunner.runWithAppropriateLogger(options, task)) {
// Exit w/ success code.
success = true;
}
}
precompileEvent.end();
System.exit(success ? 0 : 1);
}
/**
* Returns a filename for the serialized AST when precompile is performed
* separately on a per-permutation basis.
*/
static String getPrecompileFilename(int permutationBase) {
return Precompile.PRECOMPILE_FILENAME_PREFIX + "-" + permutationBase
+ Precompile.PRECOMPILE_FILENAME_SUFFIX;
}
private static boolean validateOptions(TreeLogger logger, PrecompileOnePermOptions options) {
// Fatal Errors
if (options.getModuleNames().size() != 1) {
logger.log(TreeLogger.ERROR, "Expected a single module name.");
return false;
}
if (options.getPermToCompile() < 0) {
logger.log(TreeLogger.ERROR,
"Expected argument -perm to specify the permutation to compile.");
return false;
}
// Warnings
if (!options.isEnabledGeneratingOnShards()) {
logger.log(TreeLogger.WARN,
"-XdisableGeneratingOnShards has no effect in PrecompileOnePerm");
}
if (options.getMaxPermsPerPrecompile() != -1) {
logger.log(TreeLogger.WARN,
"-XmaxPermsPerPrecompile has no effect in PrecompileOnePerm");
}
return true;
}
private final PrecompileOnePermOptionsImpl options;
private CompilerContext compilerContext;
private final CompilerContext.Builder compilerContextBuilder = new CompilerContext.Builder();
public PrecompileOnePerm(PrecompileOnePermOptions options) {
this.options = new PrecompileOnePermOptionsImpl(options);
compilerContext = compilerContextBuilder.options(options).build();
}
public boolean run(TreeLogger logger) throws UnableToCompleteException {
if (!validateOptions(logger, options)) {
return false;
}
// Avoid early optimizations since permutation compiles will run separately.
options.setOptimizePrecompile(false);
List<String> moduleNames = options.getModuleNames();
int permToRun = options.getPermToCompile();
String moduleName = moduleNames.get(0);
File compilerWorkDir = options.getCompilerWorkDir(moduleName);
ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, compilerContext, moduleName);
compilerContext = compilerContextBuilder.module(module).build();
StandardLinkerContext linkerContext = new StandardLinkerContext(
TreeLogger.NULL, module, compilerContext.getPublicResourceOracle(), options);
if (!linkerContext.allLinkersAreShardable()) {
logger.log(TreeLogger.ERROR,
"This compilation mode requires all linkers to be shardable.");
return false;
}
PrecompileTaskOptions optionsFileData = AnalyzeModule.readAnalyzeModuleOptionsFile(
logger, compilerWorkDir);
if (optionsFileData == null) {
logger.log(TreeLogger.ERROR, "Couldn't find "
+ AnalyzeModule.OPTIONS_FILENAME + " in " + compilerWorkDir);
return false;
}
logger.log(TreeLogger.INFO, "Precompiling only specified permutations");
if (options.isValidateOnly()) {
TreeLogger branch = logger.branch(TreeLogger.INFO,
"Validating compilation " + module.getName());
if (!Precompile.validate(branch, compilerContext)) {
branch.log(TreeLogger.ERROR, "Validation failed");
return false;
}
branch.log(TreeLogger.INFO, "Validation succeeded");
} else {
TreeLogger branch = logger.branch(TreeLogger.INFO, "Precompiling module "
+ module.getName());
if (!precompilePermutation(logger, compilerWorkDir, module, branch,
permToRun)) {
branch.log(TreeLogger.ERROR, "Precompile failed");
return false;
}
}
return true;
}
private boolean precompilePermutation(TreeLogger logger,
File compilerWorkDir, ModuleDef module, TreeLogger branch, int permId)
throws UnableToCompleteException {
// Only precompile specified permutations
List<PropertyPermutations> collapsedPermutations =
Precompile.getCollapsedPermutations(module);
PropertyPermutations onePerm = collapsedPermutations.get(permId);
Precompilation precompilation = Precompile.precompile(branch, compilerContext, permId, onePerm);
if (precompilation == null) {
branch.log(TreeLogger.ERROR, "Precompilation failed");
return false;
}
// TODO: precompile should do this after we get the parameter passing refactored.
if (!options.shouldSaveSource()) {
precompilation.removeSourceArtifacts(logger);
}
File precompilationFile = new File(compilerWorkDir,
getPrecompileFilename(permId));
Util.writeObjectAsFile(logger, precompilationFile, precompilation);
if (branch.isLoggable(TreeLogger.INFO)) {
branch.log(TreeLogger.INFO, "Precompilation succeeded for permutation "
+ permId);
}
return true;
}
}