Free up CompilationState and TypeOracle as soon as the golden CUDs are produced.

This allows us to build the Java AST on a clean slate.

Review by: jat

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5164 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/GWTShell.java b/dev/core/src/com/google/gwt/dev/GWTShell.java
index 8b7924d..21ffe84 100644
--- a/dev/core/src/com/google/gwt/dev/GWTShell.java
+++ b/dev/core/src/com/google/gwt/dev/GWTShell.java
@@ -192,6 +192,7 @@
   protected void compile(TreeLogger logger, ModuleDef moduleDef)
       throws UnableToCompleteException {
     LegacyCompilerOptions newOptions = new GWTCompilerOptionsImpl(options);
+    newOptions.setCompilationStateRetained(true);
     if (!new GWTCompiler(newOptions).run(logger, moduleDef)) {
       throw new UnableToCompleteException();
     }
diff --git a/dev/core/src/com/google/gwt/dev/HostedMode.java b/dev/core/src/com/google/gwt/dev/HostedMode.java
index d5064ab..b9dba20 100644
--- a/dev/core/src/com/google/gwt/dev/HostedMode.java
+++ b/dev/core/src/com/google/gwt/dev/HostedMode.java
@@ -294,6 +294,7 @@
   @Override
   protected void compile(TreeLogger logger) throws UnableToCompleteException {
     CompilerOptions newOptions = new CompilerOptionsImpl(options);
+    newOptions.setCompilationStateRetained(true);
     new Compiler(newOptions).run(logger);
   }
 
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index bedf780..ed22cd4 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -30,7 +30,6 @@
 import com.google.gwt.dev.javac.CompilationUnit;
 import com.google.gwt.dev.jdt.RebindOracle;
 import com.google.gwt.dev.jdt.RebindPermutationOracle;
-import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
 import com.google.gwt.dev.jjs.JJSOptions;
 import com.google.gwt.dev.jjs.JJSOptionsImpl;
 import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
@@ -166,6 +165,10 @@
       return jjsOptions.isClassMetadataDisabled();
     }
 
+    public boolean isCompilationStateRetained() {
+      return jjsOptions.isCompilationStateRetained();
+    }
+
     public boolean isDraftCompile() {
       return jjsOptions.isDraftCompile();
     }
@@ -202,6 +205,10 @@
       jjsOptions.setClassMetadataDisabled(disabled);
     }
 
+    public void setCompilationStateRetained(boolean retained) {
+      jjsOptions.setCompilationStateRetained(retained);
+    }
+
     public void setDisableUpdateCheck(boolean disabled) {
       disableUpdateCheck = disabled;
     }
@@ -414,10 +421,9 @@
       FragmentLoaderCreator fragmentLoaderCreator = new FragmentLoaderCreator(
           compilationState, module, genDir, generatorResourcesDir,
           generatorArtifacts);
-      WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
-          compilationState, rpo, fragmentLoaderCreator);
-      JavaToJavaScriptCompiler.precompile(logger, frontEnd, declEntryPts,
-          additionalRootTypes, jjsOptions, true);
+      JavaToJavaScriptCompiler.precompile(logger, compilationState, rpo,
+          fragmentLoaderCreator, declEntryPts, additionalRootTypes, jjsOptions,
+          true);
       return true;
     } catch (UnableToCompleteException e) {
       // Already logged.
@@ -454,12 +460,10 @@
       FragmentLoaderCreator fragmentLoaderCreator = new FragmentLoaderCreator(
           compilationState, module, genDir, generatorResourcesDir,
           generatedArtifacts);
-      WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
-          compilationState, rpo, fragmentLoaderCreator);
       PerfLogger.start("Precompile");
       UnifiedAst unifiedAst = JavaToJavaScriptCompiler.precompile(logger,
-          frontEnd, declEntryPts, null, jjsOptions,
-          rpo.getPermuationCount() == 1);
+          compilationState, rpo, fragmentLoaderCreator, declEntryPts, null,
+          jjsOptions, rpo.getPermuationCount() == 1);
       PerfLogger.end();
 
       // Merge all identical permutations together.
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 599a7dd..2756b87 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -89,8 +89,6 @@
 
   private ResourceOracleImpl lazySourceOracle;
 
-  private TypeOracle lazyTypeOracle;
-
   private final Map<String, Class<? extends Linker>> linkerTypesByName = new LinkedHashMap<String, Class<? extends Linker>>();
 
   private final long moduleDefCreationTime = System.currentTimeMillis();
@@ -232,9 +230,11 @@
     return name;
   }
 
-  public CompilationState getCompilationState(TreeLogger logger) {
+  public CompilationState getCompilationState(TreeLogger logger)
+      throws UnableToCompleteException {
     if (lazyCompilationState == null) {
       lazyCompilationState = new CompilationState(logger, lazyJavaSourceOracle);
+      checkForSeedTypes(logger);
     }
     return lazyCompilationState;
   }
@@ -294,32 +294,7 @@
 
   public synchronized TypeOracle getTypeOracle(TreeLogger logger)
       throws UnableToCompleteException {
-    if (lazyTypeOracle == null) {
-      lazyTypeOracle = getCompilationState(logger).getTypeOracle();
-
-      // Sanity check the seed types and don't even start it they're missing.
-      boolean seedTypesMissing = false;
-      if (lazyTypeOracle.findType("java.lang.Object") == null) {
-        Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
-        seedTypesMissing = true;
-      } else {
-        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];
-          if (lazyTypeOracle.findType(typeName) == null) {
-            Util.logMissingTypeErrorWithHints(branch, typeName);
-            seedTypesMissing = true;
-          }
-        }
-      }
-
-      if (seedTypesMissing) {
-        throw new UnableToCompleteException();
-      }
-    }
-    return lazyTypeOracle;
+    return getCompilationState(logger).getTypeOracle();
   }
 
   public boolean isGwtXmlFileStale() {
@@ -361,11 +336,7 @@
     // Update the compilation state to reflect the resource oracle changes.
     if (lazyCompilationState != null) {
       lazyCompilationState.refresh(logger);
-    }
-
-    // Refresh type oracle if needed.
-    if (lazyTypeOracle != null) {
-      getTypeOracle(logger);
+      checkForSeedTypes(logger);
     }
     PerfLogger.end();
   }
@@ -443,4 +414,30 @@
     PerfLogger.end();
   }
 
+  private void checkForSeedTypes(TreeLogger logger)
+      throws UnableToCompleteException {
+    // Sanity check the seed types and don't even start it they're missing.
+    boolean seedTypesMissing = false;
+    TypeOracle typeOracle = lazyCompilationState.getTypeOracle();
+    if (typeOracle.findType("java.lang.Object") == null) {
+      Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
+      seedTypesMissing = true;
+    } else {
+      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];
+        if (typeOracle.findType(typeName) == null) {
+          Util.logMissingTypeErrorWithHints(branch, typeName);
+          seedTypesMissing = true;
+        }
+      }
+    }
+
+    if (seedTypesMissing) {
+      throw new UnableToCompleteException();
+    }
+  }
+
 }
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
index 9cfa89d..3997826 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
@@ -94,7 +94,7 @@
   /**
    * Controls our type oracle.
    */
-  private final TypeOracleMediator mediator = new TypeOracleMediator();
+  private TypeOracleMediator mediator = new TypeOracleMediator();
 
   /**
    * Our source file inputs.
@@ -127,6 +127,23 @@
   }
 
   /**
+   * Reset all units to FRESH and clear TypeOracle to free up memory.
+   */
+  public void clear() {
+    // Always remove all generated compilation units.
+    for (Iterator<CompilationUnit> it = unitMap.values().iterator(); it.hasNext();) {
+      CompilationUnit unit = it.next();
+      unit.setFresh();
+      if (unit.isGenerated()) {
+        it.remove();
+      }
+    }
+    updateExposedUnits();
+    jdtCompiler = null;
+    mediator = new TypeOracleMediator();
+  }
+
+  /**
    * Returns a map of all compiled classes by binary name.
    */
   public Map<String, CompiledClass> getClassFileMap() {
diff --git a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java b/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
index 9e267ee..8aca693 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
@@ -48,6 +48,17 @@
  */
 public class WebModeCompilerFrontEnd extends AbstractCompiler {
 
+  public static CompilationUnitDeclaration[] getCompilationUnitDeclarations(
+      TreeLogger logger, String[] seedTypeNames,
+      CompilationState compilationState,
+      RebindPermutationOracle rebindPermOracle,
+      FragmentLoaderCreator fragmentLoaderCreator)
+      throws UnableToCompleteException {
+    return new WebModeCompilerFrontEnd(compilationState, rebindPermOracle,
+        fragmentLoaderCreator).getCompilationUnitDeclarations(logger,
+        seedTypeNames);
+  }
+
   private final FragmentLoaderCreator fragmentLoaderCreator;
   private final RebindPermutationOracle rebindPermOracle;
 
@@ -57,7 +68,7 @@
    * generator infrastructure, and therefore needs access to more parts of the
    * compiler than WebModeCompilerFrontEnd currently has.
    */
-  public WebModeCompilerFrontEnd(CompilationState compilationState,
+  private WebModeCompilerFrontEnd(CompilationState compilationState,
       RebindPermutationOracle rebindPermOracle,
       FragmentLoaderCreator fragmentLoaderCreator) {
     super(compilationState, false);
@@ -125,10 +136,6 @@
     return cuds;
   }
 
-  public RebindPermutationOracle getRebindPermutationOracle() {
-    return rebindPermOracle;
-  }
-
   @Override
   protected void doCompilationUnitDeclarationValidation(
       CompilationUnitDeclaration cud, TreeLogger logger) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java b/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
index e9624a0..4e1ae47 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JJSOptions.java
@@ -20,6 +20,7 @@
 import com.google.gwt.dev.util.arg.OptionDisableClassMetadata;
 import com.google.gwt.dev.util.arg.OptionDraftCompile;
 import com.google.gwt.dev.util.arg.OptionEnableAssertions;
+import com.google.gwt.dev.util.arg.OptionCompilationStateRetained;
 import com.google.gwt.dev.util.arg.OptionRunAsyncEnabled;
 import com.google.gwt.dev.util.arg.OptionScriptStyle;
 import com.google.gwt.dev.util.arg.OptionSoycEnabled;
@@ -31,5 +32,5 @@
 public interface JJSOptions extends OptionAggressivelyOptimize,
     OptionDisableClassMetadata, OptionDisableCastChecking, OptionDraftCompile,
     OptionEnableAssertions, OptionRunAsyncEnabled, OptionScriptStyle,
-    OptionSoycEnabled, OptionWorkDir {
+    OptionSoycEnabled, OptionCompilationStateRetained, OptionWorkDir {
 }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java b/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
index 63b29d7..9c92c43 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JJSOptionsImpl.java
@@ -24,6 +24,7 @@
 public class JJSOptionsImpl implements JJSOptions, Serializable {
 
   private boolean aggressivelyOptimize = true;
+  private boolean compilationStateRetained = false;
   private boolean disableCastChecking = false;
   private boolean disableClassMetadata = false;
   private boolean draftCompile = false;
@@ -42,8 +43,9 @@
 
   public void copyFrom(JJSOptions other) {
     setAggressivelyOptimize(other.isAggressivelyOptimize());
-    setClassMetadataDisabled(other.isClassMetadataDisabled());
     setCastCheckingDisabled(other.isCastCheckingDisabled());
+    setClassMetadataDisabled(other.isClassMetadataDisabled());
+    setCompilationStateRetained(other.isCompilationStateRetained());
     setDraftCompile(other.isDraftCompile());
     setEnableAssertions(other.isEnableAssertions());
     setOutput(other.getOutput());
@@ -72,6 +74,10 @@
     return disableClassMetadata;
   }
 
+  public boolean isCompilationStateRetained() {
+    return compilationStateRetained;
+  }
+
   public boolean isDraftCompile() {
     return draftCompile;
   }
@@ -100,6 +106,10 @@
     disableClassMetadata = disabled;
   }
 
+  public void setCompilationStateRetained(boolean retained) {
+    compilationStateRetained = retained;
+  }
+
   public void setDraftCompile(boolean draft) {
     this.draftCompile = draft;
   }
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 0b6f460..cd668cb 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -27,6 +27,7 @@
 import com.google.gwt.core.ext.soyc.impl.SplitPointRecorderImpl;
 import com.google.gwt.core.ext.soyc.impl.StoryRecorderImpl;
 import com.google.gwt.dev.PermutationResult;
+import com.google.gwt.dev.javac.CompilationState;
 import com.google.gwt.dev.jdt.RebindPermutationOracle;
 import com.google.gwt.dev.jdt.WebModeCompilerFrontEnd;
 import com.google.gwt.dev.jjs.InternalCompilerException.NodeInfo;
@@ -315,7 +316,9 @@
    * Performs a precompilation, returning a unified AST.
    * 
    * @param logger the logger to use
-   * @param compilerFrontEnd the compiler front ent
+   * @param compilationState the CompilationState
+   * @param rpo the RebindPermutationOracle
+   * @param fragmentLoaderCreator a FragmentLoaderCreator
    * @param declEntryPts the set of entry classes declared in a GWT module;
    *          these will be automatically rebound
    * @param additionalRootTypes additional classes that should serve as code
@@ -328,7 +331,8 @@
    *           {@link OutOfMemoryError} occurs
    */
   public static UnifiedAst precompile(TreeLogger logger,
-      WebModeCompilerFrontEnd compilerFrontEnd, String[] declEntryPts,
+      CompilationState compilationState, RebindPermutationOracle rpo,
+      FragmentLoaderCreator fragmentLoaderCreator, String[] declEntryPts,
       String[] additionalRootTypes, JJSOptions options,
       boolean singlePermutation) throws UnableToCompleteException {
 
@@ -339,8 +343,6 @@
       throw new IllegalArgumentException("entry point(s) required");
     }
 
-    RebindPermutationOracle rpo = compilerFrontEnd.getRebindPermutationOracle();
-
     Set<String> allRootTypes = new TreeSet<String>();
 
     // Find all the possible rebinds for declared entry point types.
@@ -357,8 +359,14 @@
 
     // Compile the source and get the compiler so we can get the parse tree
     //
-    CompilationUnitDeclaration[] goldenCuds = compilerFrontEnd.getCompilationUnitDeclarations(
-        logger, allRootTypes.toArray(new String[0]));
+    CompilationUnitDeclaration[] goldenCuds = WebModeCompilerFrontEnd.getCompilationUnitDeclarations(
+        logger, allRootTypes.toArray(new String[0]), compilationState, rpo,
+        fragmentLoaderCreator);
+
+    // Free up memory.
+    if (!options.isCompilationStateRetained()) {
+      compilationState.clear();
+    }
 
     // Check for compilation problems. We don't log here because any problems
     // found here will have already been logged by AbstractCompiler.
diff --git a/dev/core/src/com/google/gwt/dev/util/arg/OptionCompilationStateRetained.java b/dev/core/src/com/google/gwt/dev/util/arg/OptionCompilationStateRetained.java
new file mode 100644
index 0000000..3553b96
--- /dev/null
+++ b/dev/core/src/com/google/gwt/dev/util/arg/OptionCompilationStateRetained.java
@@ -0,0 +1,27 @@
+/*
+ * 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
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.gwt.dev.util.arg;
+
+/**
+ * Option for retaining {@link com.google.gwt.dev.javac.CompilationState} during
+ * a compile. Does not correspond to any command line option. This is used by
+ * hosted mode when doing a web mode compile to preserve the compilation state.
+ */
+public interface OptionCompilationStateRetained {
+  boolean isCompilationStateRetained();
+
+  void setCompilationStateRetained(boolean retained);
+}
diff --git a/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java b/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java
index bba102a..93d8604 100644
--- a/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java
+++ b/dev/oophm/overlay/com/google/gwt/dev/GWTShell.java
@@ -229,6 +229,7 @@
   protected void compile(TreeLogger logger, ModuleDef moduleDef)
       throws UnableToCompleteException {
     LegacyCompilerOptions newOptions = new GWTCompilerOptionsImpl(options);
+    newOptions.setCompilationStateRetained(true);
     if (!new GWTCompiler(newOptions).run(logger, moduleDef)) {
       // TODO(jat): error dialog?
     }