CompilationState now keeps a Collection of units rather than a Set; this allows us to simply reuse the map's values().

This replaces code that used to construct a new HashSet each time new units were generated, which was super-linear.  It turns out none of the callers rely on the the return type being a Set.

Review by: jat (desk)

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5346 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index 21b5f1e..40bb6e0 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -64,6 +64,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.SortedMap;
@@ -413,7 +414,7 @@
       String[] additionalRootTypes = null;
       if (declEntryPts.length == 0) {
         // No declared entry points, just validate all visible classes.
-        Set<CompilationUnit> compilationUnits = compilationState.getCompilationUnits();
+        Collection<CompilationUnit> compilationUnits = compilationState.getCompilationUnits();
         additionalRootTypes = new String[compilationUnits.size()];
         int i = 0;
         for (CompilationUnit unit : compilationUnits) {
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 67e1dd5..684192e 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
@@ -49,7 +49,7 @@
     return result;
   }
 
-  private static void markSurvivorsChecked(Set<CompilationUnit> units) {
+  private static void markSurvivorsChecked(Collection<CompilationUnit> units) {
     for (CompilationUnit unit : units) {
       if (unit.getState() == State.COMPILED
           || unit.getState() == State.GRAVEYARD) {
@@ -86,7 +86,7 @@
   /**
    * Unmodifiable view of all units.
    */
-  private Set<CompilationUnit> exposedUnits = Collections.emptySet();
+  private final Collection<CompilationUnit> exposedUnits = Collections.unmodifiableCollection(unitMap.values());
 
   private CompilationUnitInvalidator.InvalidatorState invalidatorState = new CompilationUnitInvalidator.InvalidatorState();
 
@@ -144,7 +144,7 @@
       }
     }
     unitMap.clear();
-    updateExposedUnits();
+    invalidateClassFileMaps();
     jdtCompiler = null;
     mediator = new TypeOracleMediator();
     invalidatorState = new CompilationUnitInvalidator.InvalidatorState();
@@ -181,7 +181,7 @@
   /**
    * Returns an unmodifiable view of the set of compilation units.
    */
-  public Set<CompilationUnit> getCompilationUnits() {
+  public Collection<CompilationUnit> getCompilationUnits() {
     return exposedUnits;
   }
 
@@ -220,11 +220,11 @@
     }
 
     refreshFromSourceOracle();
-    updateExposedUnits();
+    invalidateClassFileMaps();
 
     // Don't log about invalidated units via refresh.
-    Set<CompilationUnit> allUnitsPlusGraveyard = concatSet(
-        getCompilationUnits(), graveyardUnits.values());
+    Set<CompilationUnit> allUnitsPlusGraveyard = concatSet(unitMap.values(),
+        graveyardUnits.values());
     CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(TreeLogger.NULL,
         allUnitsPlusGraveyard);
     removeInvalidatedGraveyardUnits(graveyardUnits);
@@ -233,7 +233,8 @@
      * Only retain state for units marked as CHECKED; because CHECKED units
      * won't be revalidated.
      */
-    Set<CompilationUnit> toRetain = new HashSet<CompilationUnit>(exposedUnits);
+    Set<CompilationUnit> toRetain = new HashSet<CompilationUnit>(
+        unitMap.values());
     for (Iterator<CompilationUnit> it = toRetain.iterator(); it.hasNext();) {
       CompilationUnit unit = it.next();
       if (unit.getState() != State.CHECKED) {
@@ -243,10 +244,9 @@
     invalidatorState.retainAll(toRetain);
 
     jdtCompiler = new JdtCompiler();
-    compile(logger, getCompilationUnits(),
-        Collections.<CompilationUnit> emptySet());
-    mediator.refresh(logger, getCompilationUnits());
-    markSurvivorsChecked(getCompilationUnits());
+    compile(logger, unitMap.values(), Collections.<CompilationUnit> emptySet());
+    mediator.refresh(logger, unitMap.values());
+    markSurvivorsChecked(unitMap.values());
   }
 
   /**
@@ -273,9 +273,9 @@
     for (CompilationUnit generatedUnit : usefulGeneratedCups) {
       unitMap.put(generatedUnit.getTypeName(), generatedUnit);
     }
-    updateExposedUnits();
+    invalidateClassFileMaps();
 
-    compile(logger, usefulGeneratedCups, getCompilationUnits());
+    compile(logger, usefulGeneratedCups, unitMap.values());
     mediator.addNewUnits(logger, usefulGeneratedCups);
     markSurvivorsChecked(usefulGeneratedCups);
   }
@@ -320,7 +320,7 @@
       Set<CompilationUnit> allGraveyardUnits = concatSet(
           graveyardUnits.values(), usefulGraveyardUnits.values());
       CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(
-          TreeLogger.NULL, allGraveyardUnits, exposedUnits);
+          TreeLogger.NULL, allGraveyardUnits, unitMap.values());
 
       removeInvalidatedGraveyardUnits(graveyardUnits);
       removeInvalidatedGraveyardUnits(usefulGraveyardUnits);
@@ -332,8 +332,8 @@
    * Compile units and update their internal state. Invalidate any units with
    * compile errors.
    */
-  private void compile(TreeLogger logger, Set<CompilationUnit> newUnits,
-      Set<CompilationUnit> existingUnits) {
+  private void compile(TreeLogger logger, Collection<CompilationUnit> newUnits,
+      Collection<CompilationUnit> existingUnits) {
     PerfLogger.start("CompilationState.compile");
     if (jdtCompiler.doCompile(newUnits)) {
       logger = logger.branch(TreeLogger.DEBUG,
@@ -362,10 +362,16 @@
     PerfLogger.end();
   }
 
+  private void invalidateClassFileMaps() {
+    // TODO: see if we can call this in fewer places.
+    exposedClassFileMap = null;
+    exposedClassFileMapBySource = null;
+  }
+
   private void rebuildClassMaps() {
     HashMap<String, CompiledClass> classFileMap = new HashMap<String, CompiledClass>();
     HashMap<String, CompiledClass> classFileMapBySource = new HashMap<String, CompiledClass>();
-    for (CompilationUnit unit : getCompilationUnits()) {
+    for (CompilationUnit unit : unitMap.values()) {
       if (unit.isCompiled()) {
         for (CompiledClass compiledClass : unit.getCompiledClasses()) {
           classFileMap.put(compiledClass.getBinaryName(), compiledClass);
@@ -426,11 +432,4 @@
       }
     }
   }
-
-  private void updateExposedUnits() {
-    exposedUnits = Collections.unmodifiableSet(new HashSet<CompilationUnit>(
-        unitMap.values()));
-    exposedClassFileMap = null;
-    exposedClassFileMapBySource = null;
-  }
 }
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java
index 6b8d850..101fa4e 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnitInvalidator.java
@@ -60,7 +60,7 @@
    * @return <code>true</code> if any units changed state
    */
   public static boolean invalidateUnitsWithErrors(TreeLogger logger,
-      Set<CompilationUnit> units) {
+      Collection<CompilationUnit> units) {
     logger = logger.branch(TreeLogger.TRACE, "Removing units with errors");
     // Start by removing units with a known problem.
     boolean anyRemoved = false;
@@ -135,7 +135,7 @@
    *          set that reference each other
    */
   public static void invalidateUnitsWithInvalidRefs(TreeLogger logger,
-      Set<CompilationUnit> unitsToCheck) {
+      Collection<CompilationUnit> unitsToCheck) {
     invalidateUnitsWithInvalidRefs(logger, unitsToCheck,
         Collections.<CompilationUnit> emptySet());
   }
@@ -151,7 +151,8 @@
    *          may be empty)
    */
   public static void invalidateUnitsWithInvalidRefs(TreeLogger logger,
-      Set<CompilationUnit> unitsToCheck, Set<CompilationUnit> knownUnits) {
+      Collection<CompilationUnit> unitsToCheck,
+      Collection<CompilationUnit> knownUnits) {
     logger = logger.branch(TreeLogger.TRACE, "Removing invalidated units");
 
     Set<String> knownValidRefs = new HashSet<String>();
@@ -195,7 +196,7 @@
   }
 
   public static void validateCompilationUnits(InvalidatorState state,
-      Set<CompilationUnit> units, Set<String> validBinaryTypeNames) {
+      Collection<CompilationUnit> units, Set<String> validBinaryTypeNames) {
     for (CompilationUnit unit : units) {
       if (unit.getState() == State.COMPILED) {
         CompilationUnitDeclaration jdtCud = unit.getJdtCud();
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
index 92251c7..9555da1 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
@@ -35,8 +35,8 @@
 import java.io.IOException;
 import java.io.StringReader;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Adapts compilation units containing JSNI-accessible code by rewriting the
@@ -156,7 +156,7 @@
   }
 
   public static void collectJsniMethods(TreeLogger logger,
-      Set<CompilationUnit> units, JsProgram program) {
+      Collection<CompilationUnit> units, JsProgram program) {
     for (CompilationUnit unit : units) {
       if (unit.getState() == State.COMPILED) {
         String loc = unit.getDisplayLocation();
diff --git a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
index e735dc5..fb265fe 100644
--- a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
+++ b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
@@ -83,6 +83,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.lang.reflect.Array;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -266,7 +267,7 @@
   /**
    * Adds new units to an existing TypeOracle.
    */
-  public void addNewUnits(TreeLogger logger, Set<CompilationUnit> units) {
+  public void addNewUnits(TreeLogger logger, Collection<CompilationUnit> units) {
     // Perform a shallow pass to establish identity for new and old types.
     for (CompilationUnit unit : units) {
       switch (unit.getState()) {
@@ -328,7 +329,7 @@
   /**
    * Full refresh based on new units.
    */
-  public void refresh(TreeLogger logger, Set<CompilationUnit> units) {
+  public void refresh(TreeLogger logger, Collection<CompilationUnit> units) {
     logger = logger.branch(TreeLogger.DEBUG, "Refreshing TypeOracle");
     binaryMapper.clear();
     typeOracle.reset();
diff --git a/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java b/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
index 52e6cf2..9addb1d 100644
--- a/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
@@ -438,10 +438,11 @@
   private void validateCompilationState(String... generatedTypeNames) {
     // Save off the reflected collections.
     Map<String, CompilationUnit> unitMap = state.getCompilationUnitMap();
-    Set<CompilationUnit> units = state.getCompilationUnits();
+    Collection<CompilationUnit> units = state.getCompilationUnits();
 
     // Validate that the collections are consistent with each other.
-    assertEquals(new HashSet<CompilationUnit>(unitMap.values()), units);
+    assertEquals(new HashSet<CompilationUnit>(unitMap.values()),
+        new HashSet<CompilationUnit>(units));
 
     // Save off a mutable copy of the source map and generated types to compare.
     Map<String, Resource> sourceMap = new HashMap<String, Resource>(