Package com.google.gwt.dev

Source Code of com.google.gwt.dev.Precompile

/*
* 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
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev;

import com.google.gwt.core.ext.Linker;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.UnableToCompleteException;
import com.google.gwt.core.ext.linker.ArtifactSet;
import com.google.gwt.core.ext.linker.ModuleMetricsArtifact;
import com.google.gwt.core.ext.linker.PrecompilationMetricsArtifact;
import com.google.gwt.core.ext.linker.impl.StandardLinkerContext;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.dev.CompileTaskRunner.CompileTask;
import com.google.gwt.dev.cfg.ConfigurationProperty;
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.javac.CompilationState;
import com.google.gwt.dev.javac.CompilationUnit;
import com.google.gwt.dev.jjs.AbstractCompiler;
import com.google.gwt.dev.jjs.JJSOptions;
import com.google.gwt.dev.jjs.JJSOptionsImpl;
import com.google.gwt.dev.jjs.JavaScriptCompiler;
import com.google.gwt.dev.jjs.JsOutputOption;
import com.google.gwt.dev.jjs.UnifiedAst;
import com.google.gwt.dev.shell.CheckForUpdates;
import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
import com.google.gwt.dev.util.CollapsedPropertyKey;
import com.google.gwt.dev.util.Memory;
import com.google.gwt.dev.util.Util;
import com.google.gwt.dev.util.arg.ArgHandlerCompileReport;
import com.google.gwt.dev.util.arg.ArgHandlerCompilerMetrics;
import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
import com.google.gwt.dev.util.arg.ArgHandlerDisableCastChecking;
import com.google.gwt.dev.util.arg.ArgHandlerDisableClassMetadata;
import com.google.gwt.dev.util.arg.ArgHandlerDisableGeneratingOnShards;
import com.google.gwt.dev.util.arg.ArgHandlerDisableRunAsync;
import com.google.gwt.dev.util.arg.ArgHandlerDisableUpdateCheck;
import com.google.gwt.dev.util.arg.ArgHandlerDraftCompile;
import com.google.gwt.dev.util.arg.ArgHandlerDumpSignatures;
import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
import com.google.gwt.dev.util.arg.ArgHandlerGenDir;
import com.google.gwt.dev.util.arg.ArgHandlerMaxPermsPerPrecompile;
import com.google.gwt.dev.util.arg.ArgHandlerOptimize;
import com.google.gwt.dev.util.arg.ArgHandlerScriptStyle;
import com.google.gwt.dev.util.arg.ArgHandlerSoyc;
import com.google.gwt.dev.util.arg.ArgHandlerSoycDetailed;
import com.google.gwt.dev.util.arg.ArgHandlerStrict;
import com.google.gwt.dev.util.arg.ArgHandlerValidateOnlyFlag;
import com.google.gwt.dev.util.arg.OptionDisableUpdateCheck;
import com.google.gwt.dev.util.arg.OptionEnableGeneratingOnShards;
import com.google.gwt.dev.util.arg.OptionGenDir;
import com.google.gwt.dev.util.arg.OptionMaxPermsPerPrecompile;
import com.google.gwt.dev.util.arg.OptionValidateOnly;
import com.google.gwt.dev.util.collect.Lists;
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.awt.GraphicsEnvironment;
import java.io.File;
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.concurrent.FutureTask;

/**
* Performs the first phase of compilation, generating the set of permutations
* to compile, and a ready-to-compile AST.
*/
public class Precompile {

  /**
   * The set of options for the precompiler.
   */
  public interface PrecompileOptions extends JJSOptions, CompileTaskOptions, OptionGenDir,
      OptionValidateOnly, OptionDisableUpdateCheck, OptionEnableGeneratingOnShards,
      OptionMaxPermsPerPrecompile, PrecompilationResult {
  }

  static class ArgProcessor extends CompileArgProcessor {
    public ArgProcessor(PrecompileOptions options) {
      super(options);
      registerHandler(new ArgHandlerGenDir(options));
      registerHandler(new ArgHandlerScriptStyle(options));
      registerHandler(new ArgHandlerEnableAssertions(options));
      registerHandler(new ArgHandlerDisableGeneratingOnShards(options));
      registerHandler(new ArgHandlerDisableAggressiveOptimization(options));
      registerHandler(new ArgHandlerDisableClassMetadata(options));
      registerHandler(new ArgHandlerDisableCastChecking(options));
      registerHandler(new ArgHandlerValidateOnlyFlag(options));
      registerHandler(new ArgHandlerDisableRunAsync(options));
      registerHandler(new ArgHandlerDraftCompile(options));
      registerHandler(new ArgHandlerDisableUpdateCheck(options));
      registerHandler(new ArgHandlerDumpSignatures());
      registerHandler(new ArgHandlerMaxPermsPerPrecompile(options));
      registerHandler(new ArgHandlerOptimize(options));
      registerHandler(new ArgHandlerCompileReport(options));
      registerHandler(new ArgHandlerSoyc(options));
      registerHandler(new ArgHandlerSoycDetailed(options));
      registerHandler(new ArgHandlerStrict(options));
      registerHandler(new ArgHandlerCompilerMetrics(options));
    }

    @Override
    protected String getName() {
      return Precompile.class.getName();
    }
  }

  static class PrecompileOptionsImpl extends CompileTaskOptionsImpl implements PrecompileOptions,
      Serializable {
    private boolean disableUpdateCheck;
    private boolean enableGeneratingOnShards = true;
    private File genDir;
    private final JJSOptionsImpl jjsOptions = new JJSOptionsImpl();
    private int maxPermsPerPrecompile;
    private boolean validateOnly;

    public PrecompileOptionsImpl() {
    }

    public PrecompileOptionsImpl(PrecompileOptions other) {
      copyFrom(other);
    }

    public void copyFrom(PrecompileOptions other) {
      super.copyFrom(other);

      jjsOptions.copyFrom(other);

      setDisableUpdateCheck(other.isUpdateCheckDisabled());
      setGenDir(other.getGenDir());
      setMaxPermsPerPrecompile(other.getMaxPermsPerPrecompile());
      setValidateOnly(other.isValidateOnly());
      setEnabledGeneratingOnShards(other.isEnabledGeneratingOnShards());
    }

    public File getGenDir() {
      return genDir;
    }

    public int getMaxPermsPerPrecompile() {
      return maxPermsPerPrecompile;
    }

    public int getOptimizationLevel() {
      return jjsOptions.getOptimizationLevel();
    }

    public JsOutputOption getOutput() {
      return jjsOptions.getOutput();
    }

    public boolean isAggressivelyOptimize() {
      return jjsOptions.isAggressivelyOptimize();
    }

    public boolean isCastCheckingDisabled() {
      return jjsOptions.isCastCheckingDisabled();
    }

    public boolean isClassMetadataDisabled() {
      return jjsOptions.isClassMetadataDisabled();
    }

    public boolean isCompilerMetricsEnabled() {
      return jjsOptions.isCompilerMetricsEnabled();
    }

    public boolean isDraftCompile() {
      return jjsOptions.isDraftCompile();
    }

    public boolean isEnableAssertions() {
      return jjsOptions.isEnableAssertions();
    }

    public boolean isEnabledGeneratingOnShards() {
      return enableGeneratingOnShards;
    }

    public boolean isGeneratorResultCachingEnabled() {
      return jjsOptions.isGeneratorResultCachingEnabled();
    }

    public boolean isOptimizePrecompile() {
      return jjsOptions.isOptimizePrecompile();
    }

    public boolean isRunAsyncEnabled() {
      return jjsOptions.isRunAsyncEnabled();
    }

    public boolean isSoycEnabled() {
      return jjsOptions.isSoycEnabled();
    }

    public boolean isSoycExtra() {
      return jjsOptions.isSoycExtra();
    }

    public boolean isStrict() {
      return jjsOptions.isStrict();
    }

    public boolean isUpdateCheckDisabled() {
      return disableUpdateCheck;
    }

    public boolean isValidateOnly() {
      return validateOnly;
    }

    public void setAggressivelyOptimize(boolean aggressivelyOptimize) {
      jjsOptions.setAggressivelyOptimize(aggressivelyOptimize);
    }

    public void setCastCheckingDisabled(boolean disabled) {
      jjsOptions.setCastCheckingDisabled(disabled);
    }

    public void setClassMetadataDisabled(boolean disabled) {
      jjsOptions.setClassMetadataDisabled(disabled);
    }

    public void setCompilerMetricsEnabled(boolean enabled) {
      jjsOptions.setCompilerMetricsEnabled(enabled);
    }

    public void setDisableUpdateCheck(boolean disabled) {
      disableUpdateCheck = disabled;
    }

    public void setEnableAssertions(boolean enableAssertions) {
      jjsOptions.setEnableAssertions(enableAssertions);
    }

    public void setEnabledGeneratingOnShards(boolean enabled) {
      enableGeneratingOnShards = enabled;
    }

    public void setGenDir(File genDir) {
      this.genDir = genDir;
    }

    public void setGeneratorResultCachingEnabled(boolean enabled) {
      jjsOptions.setGeneratorResultCachingEnabled(enabled);
    }

    public void setMaxPermsPerPrecompile(int maxPermsPerPrecompile) {
      this.maxPermsPerPrecompile = maxPermsPerPrecompile;
    }

    public void setOptimizationLevel(int level) {
      jjsOptions.setOptimizationLevel(level);
    }

    public void setOptimizePrecompile(boolean optimize) {
      jjsOptions.setOptimizePrecompile(optimize);
    }

    public void setOutput(JsOutputOption output) {
      jjsOptions.setOutput(output);
    }

    public void setRunAsyncEnabled(boolean enabled) {
      jjsOptions.setRunAsyncEnabled(enabled);
    }

    public void setSoycEnabled(boolean enabled) {
      jjsOptions.setSoycEnabled(enabled);
    }

    public void setSoycExtra(boolean soycExtra) {
      jjsOptions.setSoycExtra(soycExtra);
    }

    public void setStrict(boolean strict) {
      jjsOptions.setStrict(strict);
    }

    public void setValidateOnly(boolean validateOnly) {
      this.validateOnly = validateOnly;
    }
  }

  /**
   * Creates a Graphics2D context in a thread in order to go ahead and get first
   * time initialization out of the way. Delays ranging from 200ms to 6s have
   * been observed when initializing the library.
   */
  private static class GraphicsInitThread extends Thread {
    public GraphicsInitThread() {
      // We don't care if the program finishes before the initialization ends.
      setDaemon(true);
    }

    @Override
    public void run() {
      SpeedTracerLogger.Event createGraphicsEvent =
          SpeedTracerLogger.start(CompilerEventType.GRAPHICS_INIT, "java.awt.headless", System
              .getProperty("java.awt.headless"));
      GraphicsEnvironment.getLocalGraphicsEnvironment();
      createGraphicsEvent.end();
    }
  };

  /**
   * The file name for the max number of permutations output as plain text.
   */
  static final String PERM_COUNT_FILENAME = "permCount.txt";

  static final String PRECOMPILE_FILENAME = Precompile.PRECOMPILE_FILENAME_PREFIX
      + Precompile.PRECOMPILE_FILENAME_SUFFIX;

  /**
   * The file name for the serialized AST artifact from the Precompile step.
   * Sometimes this file is overloaded and only contains a PrecompileOptions
   * object to indicate that precompilation should run inside the CompilePerms
   * step.
   */
  static final String PRECOMPILE_FILENAME_PREFIX = "precompilation";

  static final String PRECOMPILE_FILENAME_SUFFIX = ".ser";

  /**
   * 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 PrecompileOptions options = new PrecompileOptionsImpl();
    boolean success = false;
    if (new ArgProcessor(options).processArgs(args)) {
      CompileTask task = new CompileTask() {
        public boolean run(TreeLogger logger) throws UnableToCompleteException {
          FutureTask<UpdateResult> updater = null;
          if (!options.isUpdateCheckDisabled()) {
            updater =
                CheckForUpdates.checkForUpdatesInBackgroundThread(logger, CheckForUpdates.ONE_DAY);
          }
          boolean success = new Precompile(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);
  }

  /**
   * Precompiles the given module.
   *
   * @param logger a logger to use
   * @param jjsOptions a set of compiler options
   * @param module the module to compile
   * @param genDir optional directory to dump generated source, may be
   *          <code>null</code>
   * @return the precompilation
   */
  public static Precompilation precompile(TreeLogger logger, JJSOptions jjsOptions,
      ModuleDef module, File genDir) {
    PropertyPermutations allPermutations =
        new PropertyPermutations(module.getProperties(), module.getActiveLinkerNames());
    return precompile(logger, jjsOptions, module, 0, allPermutations, genDir);
  }

  /**
   * Validates the given module can be compiled.
   *
   * @param logger a logger to use
   * @param jjsOptions a set of compiler options
   * @param module the module to compile
   * @param genDir optional directory to dump generated source, may be
   *          <code>null</code>
   */
  public static boolean validate(TreeLogger logger, JJSOptions jjsOptions, ModuleDef module,
      File genDir) {
    Event validateEvent = SpeedTracerLogger.start(CompilerEventType.VALIDATE);
    try {
      CompilationState compilationState = module.getCompilationState(logger);
      if (jjsOptions.isStrict() && compilationState.hasErrors()) {
        abortDueToStrictMode(logger);
      }
      String[] declEntryPts = module.getEntryPointTypeNames();
      String[] additionalRootTypes = null;
      if (declEntryPts.length == 0) {
        // No declared entry points, just validate all visible classes.
        Collection<CompilationUnit> compilationUnits = compilationState.getCompilationUnits();
        additionalRootTypes = new String[compilationUnits.size()];
        int i = 0;
        for (CompilationUnit unit : compilationUnits) {
          additionalRootTypes[i++] = unit.getTypeName();
        }
      }

      ArtifactSet generatorArtifacts = new ArtifactSet();
      DistillerRebindPermutationOracle rpo =
          new DistillerRebindPermutationOracle(module, compilationState, generatorArtifacts,
              new PropertyPermutations(module.getProperties(), module.getActiveLinkerNames()),
              genDir);
      // Allow GC later.
      compilationState = null;
      // Never optimize on a validation run.
      jjsOptions.setOptimizePrecompile(false);
      getCompiler(module).precompile(logger, module, rpo, declEntryPts, additionalRootTypes,
          jjsOptions, true, null);
      return true;
    } catch (UnableToCompleteException e) {
      // Already logged.
      return false;
    } finally {
      validateEvent.end();
    }
  }

  /**
   * Create a list of all possible permutations configured for this module after
   * collapsing soft permutations.
   */
  static List<PropertyPermutations> getCollapsedPermutations(ModuleDef module) {
    PropertyPermutations allPermutations =
        new PropertyPermutations(module.getProperties(), module.getActiveLinkerNames());
    List<PropertyPermutations> collapsedPermutations = allPermutations.collapseProperties();
    return collapsedPermutations;
  }

  static AbstractCompiler getCompiler(ModuleDef module) {
    ConfigurationProperty compilerClassProp =
        module.getProperties().createConfiguration("x.compiler.class", false);
    String compilerClassName = compilerClassProp.getValue();
    if (compilerClassName == null || compilerClassName.length() == 0) {
      return new JavaScriptCompiler();
    }
    Throwable caught;
    try {
      Class<?> compilerClass = Class.forName(compilerClassName);
      return (AbstractCompiler) compilerClass.newInstance();
    } catch (ClassNotFoundException e) {
      caught = e;
    } catch (InstantiationException e) {
      caught = e;
    } catch (IllegalAccessException e) {
      caught = e;
    }
    throw new RuntimeException("Unable to instantiate compiler class '" + compilerClassName + "'",
        caught);
  }

  static Precompilation precompile(TreeLogger logger, JJSOptions jjsOptions, ModuleDef module,
      int permutationBase, PropertyPermutations allPermutations, File genDir) {
    return precompile(logger, jjsOptions, module, permutationBase, allPermutations, genDir,
        ManagementFactory.getRuntimeMXBean().getStartTime());
  }

  static Precompilation precompile(TreeLogger logger, JJSOptions jjsOptions, ModuleDef module,
      int permutationBase, PropertyPermutations allPermutations, File genDir,
      long startTimeMilliseconds) {

    Event precompileEvent = SpeedTracerLogger.start(CompilerEventType.PRECOMPILE);

    // This initializes the Java2D library in a thread so that the main program
    // doesn't block when the library is accessed for the first time.
    new GraphicsInitThread().start();

    try {
      CompilationState compilationState = module.getCompilationState(logger);
      if (jjsOptions.isStrict() && compilationState.hasErrors()) {
        abortDueToStrictMode(logger);
      }

      List<String> initialTypeOracleTypes = new ArrayList<String>();
      if (jjsOptions.isCompilerMetricsEnabled()) {
        for (JClassType type : compilationState.getTypeOracle().getTypes()) {
          initialTypeOracleTypes.add(type.getPackage().getName() + "." + type.getName());
        }
      }

      // Track information about the module load including initial type
      // oracle build for diagnostic purposes.
      long moduleLoadFinished = System.currentTimeMillis();

      String[] declEntryPts = module.getEntryPointTypeNames();
      if (declEntryPts.length == 0) {
        logger.log(TreeLogger.ERROR, "Module has no entry points defined", null);
        throw new UnableToCompleteException();
      }

      ArtifactSet generatedArtifacts = new ArtifactSet();
      DistillerRebindPermutationOracle rpo =
          new DistillerRebindPermutationOracle(module, compilationState, generatedArtifacts,
              allPermutations, genDir);
      // Allow GC later.
      compilationState = null;
      PrecompilationMetricsArtifact precompilationMetrics =
          jjsOptions.isCompilerMetricsEnabled()
              ? new PrecompilationMetricsArtifact(permutationBase) : null;
      UnifiedAst unifiedAst =
          getCompiler(module).precompile(logger, module, rpo, declEntryPts, null, jjsOptions,
              rpo.getPermuationCount() == 1, precompilationMetrics);

      if (jjsOptions.isCompilerMetricsEnabled()) {
        ModuleMetricsArtifact moduleMetrics = new ModuleMetricsArtifact();
        moduleMetrics.setSourceFiles(module.getAllSourceFiles());
        // The initial type list has to be gathered before the call to
        // precompile().
        moduleMetrics.setInitialTypes(initialTypeOracleTypes);
        // The elapsed time in ModuleMetricsArtifact represents time
        // which could be done once for all permutations.
        moduleMetrics.setElapsedMilliseconds(moduleLoadFinished - startTimeMilliseconds);
        unifiedAst.setModuleMetrics(moduleMetrics);
      }

      // Merge all identical permutations together.
      List<Permutation> permutations =
          new ArrayList<Permutation>(Arrays.asList(rpo.getPermutations()));

      mergeCollapsedPermutations(permutations);

      // Sort the permutations by an ordered key to ensure determinism.
      SortedMap<RebindAnswersPermutationKey, Permutation> merged =
          new TreeMap<RebindAnswersPermutationKey, Permutation>();
      SortedSet<String> liveRebindRequests = unifiedAst.getRebindRequests();
      for (Permutation permutation : permutations) {
        // Construct a key for the live rebind answers.
        RebindAnswersPermutationKey key =
            new RebindAnswersPermutationKey(permutation, liveRebindRequests);
        if (merged.containsKey(key)) {
          Permutation existing = merged.get(key);
          existing.mergeFrom(permutation, liveRebindRequests);
        } else {
          merged.put(key, permutation);
        }
      }
      if (jjsOptions.isCompilerMetricsEnabled()) {
        int[] ids = new int[allPermutations.size()];
        for (int i = 0; i < allPermutations.size(); i++) {
          ids[i] = permutationBase + i;
        }
        precompilationMetrics.setPermuationIds(ids);
        // TODO(zundel): Right now this double counts module load and
        // precompile time. It correctly counts the amount of time spent
        // in this process. The elapsed time in ModuleMetricsArtifact
        // represents time which could be done once for all permutations.
        precompilationMetrics.setElapsedMilliseconds(System.currentTimeMillis()
            - startTimeMilliseconds);
        unifiedAst.setPrecompilationMetrics(precompilationMetrics);
      }
      return new Precompilation(unifiedAst, merged.values(), permutationBase, generatedArtifacts);
    } catch (UnableToCompleteException e) {
      // We intentionally don't pass in the exception here since the real
      // cause has been logged.
      return null;
    } finally {
      precompileEvent.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();
  }

  /**
   * This merges Permutations that can be considered equivalent by considering
   * their collapsed properties. The list passed into this method may have
   * elements removed from it.
   */
  private static void mergeCollapsedPermutations(List<Permutation> permutations) {
    if (permutations.size() < 2) {
      return;
    }

    // See the doc for CollapsedPropertyKey
    SortedMap<CollapsedPropertyKey, List<Permutation>> mergedByCollapsedProperties =
        new TreeMap<CollapsedPropertyKey, List<Permutation>>();

    // This loop creates the equivalence sets
    for (Iterator<Permutation> it = permutations.iterator(); it.hasNext();) {
      Permutation entry = it.next();
      CollapsedPropertyKey key = new CollapsedPropertyKey(entry);

      List<Permutation> equivalenceSet = mergedByCollapsedProperties.get(key);
      if (equivalenceSet == null) {
        equivalenceSet = Lists.create();
      } else {
        // Mutate list
        it.remove();
        equivalenceSet = Lists.add(equivalenceSet, entry);
      }
      mergedByCollapsedProperties.put(key, equivalenceSet);
    }

    // This loop merges the Permutations together
    for (Map.Entry<CollapsedPropertyKey, List<Permutation>> entry : mergedByCollapsedProperties
        .entrySet()) {
      Permutation mergeInto = entry.getKey().getPermutation();

      /*
       * Merge the deferred-binding properties once we no longer need the
       * PropertyOracle data from the extra permutations.
       */
      for (Permutation mergeFrom : entry.getValue()) {
        mergeInto.mergeRebindsFromCollapsed(mergeFrom);
      }
    }

    // Renumber the Permutations
    for (int i = 0, j = permutations.size(); i < j; i++) {
      permutations.set(i, new Permutation(i, permutations.get(i)));
    }
  }

  private final PrecompileOptionsImpl options;

  public Precompile(PrecompileOptions options) {
    this.options = new PrecompileOptionsImpl(options);
  }

  public boolean run(TreeLogger logger) throws UnableToCompleteException {
    // Avoid early optimizations since permutation compiles will run
    // separately.
    options.setOptimizePrecompile(false);

    for (String moduleName : options.getModuleNames()) {
      File compilerWorkDir = options.getCompilerWorkDir(moduleName);
      Util.recursiveDelete(compilerWorkDir, true);
      // No need to check mkdirs result because an IOException will occur
      // anyway.
      compilerWorkDir.mkdirs();

      File precompilationFile = new File(compilerWorkDir, PRECOMPILE_FILENAME);

      ModuleDef module = ModuleDefLoader.loadFromClassPath(logger, moduleName);

      StandardLinkerContext linkerContext =
          new StandardLinkerContext(TreeLogger.NULL, module, options);

      boolean generateOnShards = true;

      if (!options.isEnabledGeneratingOnShards()) {
        logger.log(TreeLogger.INFO, "Precompiling on the start node");
        generateOnShards = false;
      } else if (!linkerContext.allLinkersAreShardable()) {
        TreeLogger legacyLinkersLogger =
            logger.branch(TreeLogger.INFO,
                "Precompiling on the start node, because some linkers are not updated");
        for (Linker linker : linkerContext.findUnshardableLinkers()) {
          legacyLinkersLogger.log(TreeLogger.INFO, "Linker" + linker.getClass().getCanonicalName()
              + " is not updated");
        }
        generateOnShards = false;
      } else if (options.isValidateOnly()) {
        // Don't bother running on shards for just a validation run
        generateOnShards = false;
      }

      if (generateOnShards) {
        /*
         * Pre-precompile. Count the permutations and plan to do a real
         * precompile in the CompilePerms shards.
         */
        TreeLogger branch =
            logger.branch(TreeLogger.INFO, "Precompiling (minimal) module " + module.getName());
        Util.writeObjectAsFile(logger, precompilationFile, options);
        int numPermutations =
            new PropertyPermutations(module.getProperties(), module.getActiveLinkerNames())
                .collapseProperties().size();
        Util.writeStringAsFile(logger, new File(compilerWorkDir, PERM_COUNT_FILENAME), String
            .valueOf(numPermutations));
        branch.log(TreeLogger.INFO, "Precompilation (minimal) succeeded, number of permutations: "
            + numPermutations);
      } else {
        if (options.isValidateOnly()) {
          TreeLogger branch =
              logger.branch(TreeLogger.INFO, "Validating compilation " + module.getName());
          if (!validate(branch, options, module, options.getGenDir())) {
            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());

          Precompilation precompilation = precompile(branch, options, module, options.getGenDir());
          if (precompilation == null) {
            branch.log(TreeLogger.ERROR, "Precompilation failed");
            return false;
          }
          Util.writeObjectAsFile(logger, precompilationFile, precompilation);

          int permsPrecompiled = precompilation.getPermutations().length;
          Util.writeStringAsFile(logger, new File(compilerWorkDir, PERM_COUNT_FILENAME), String
              .valueOf(permsPrecompiled));
          branch.log(TreeLogger.INFO, "Precompilation succeeded, number of permutations: "
              + permsPrecompiled);
        }
      }
    }
    return true;
  }
}
TOP

Related Classes of com.google.gwt.dev.Precompile

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.