Greatly improve efficiency of generating additional types for really large projects.

- CompilationState is now "always up to date"
- Adding additional types is now divorced from a full "refresh" that starts over.

Suggested by: jat
Review by: spoon


git-svn-id: https://google-web-toolkit.googlecode.com/svn/releases/1.6@4025 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JPackage.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JPackage.java
index 23ea00f..5db5a59 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JPackage.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JPackage.java
@@ -28,7 +28,7 @@
 
   private final Annotations annotations = new Annotations();
 
-  private final Map<String, JClassType> types = new HashMap<String, JClassType>();
+  private final Map<String, JRealClassType> types = new HashMap<String, JRealClassType>();
 
   JPackage(String name) {
     this.name = name;
@@ -81,7 +81,7 @@
     return "package " + name;
   }
 
-  void addType(JClassType type) {
+  void addType(JRealClassType type) {
     types.put(type.getSimpleSourceName(), type);
   }
 
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
index 955146f..e326756 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/JRealClassType.java
@@ -87,6 +87,7 @@
       } while (enclosing != null);
       nestedName = nn;
     }
+    oracle.addNewType(this);
   }
 
   public void addAnnotations(
diff --git a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
index e217ce2..75e8e2e 100644
--- a/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
+++ b/dev/core/src/com/google/gwt/core/ext/typeinfo/TypeOracle.java
@@ -167,10 +167,14 @@
     }
   }
 
-  private Set<JClassType> allTypes = null;
+  private final Set<JRealClassType> allTypes = new HashSet<JRealClassType>();
 
   private final Map<JType, JArrayType> arrayTypes = new IdentityHashMap<JType, JArrayType>();
 
+  /**
+   * A set of invalidated types queued up to be removed on the next
+   * {@link #reset()}.
+   */
   private final Set<JRealClassType> invalidatedTypes = new HashSet<JRealClassType>();
 
   private JClassType javaLangObject;
@@ -179,6 +183,12 @@
 
   private final Map<String, List<JParameterizedType>> parameterizedTypes = new HashMap<String, List<JParameterizedType>>();
 
+  /**
+   * A list of recently-added types that will be fully initialized on the next
+   * call to {@link #finish(TreeLogger)}.
+   */
+  private final List<JRealClassType> recentTypes = new ArrayList<JRealClassType>();
+
   private int reloadCount = 0;
 
   private final Map<String, List<JWildcardType>> wildcardTypes = new HashMap<String, List<JWildcardType>>();
@@ -248,6 +258,18 @@
   }
 
   /**
+   * Called after a block of new types are added.
+   * 
+   * TODO: make not public?
+   */
+  public void finish(TreeLogger logger) {
+    JClassType[] newTypes = recentTypes.toArray(NO_JCLASSES);
+    computeHierarchyRelationships(newTypes);
+    consumeTypeArgMetaData(logger, newTypes);
+    recentTypes.clear();
+  }
+
+  /**
    * Gets the type object that represents an array of the specified type. The
    * returned type always has a stable identity so as to guarantee that all
    * calls to this method with the same argument return the same object.
@@ -270,7 +292,10 @@
    * <code>java.lang.Object</code>.
    */
   public JClassType getJavaLangObject() {
-    assert javaLangObject != null;
+    if (javaLangObject == null) {
+      javaLangObject = findType("java.lang.Object");
+      assert javaLangObject != null;
+    }
     return javaLangObject;
   }
 
@@ -457,18 +482,6 @@
    * @return an array of types, possibly of zero length
    */
   public JClassType[] getTypes() {
-    if (allTypes == null) {
-      allTypes = new HashSet<JClassType>();
-      JPackage[] pkgs = getPackages();
-      for (int i = 0; i < pkgs.length; i++) {
-        JPackage pkg = pkgs[i];
-        JClassType[] types = pkg.getTypes();
-        for (int j = 0; j < types.length; j++) {
-          JRealClassType type = (JRealClassType) types[j];
-          buildAllTypesImpl(allTypes, type);
-        }
-      }
-    }
     return allTypes.toArray(NO_JCLASSES);
   }
 
@@ -525,35 +538,12 @@
   }
 
   /**
-   * Updates relationships within this type oracle. Should be called after any
-   * changes are made.
-   * 
-   * <p>
-   * Throws <code>TypeOracleException</code> thrown if fundamental baseline
-   * correctness criteria are violated, most notably the absence of
-   * "java.lang.Object"
-   * </p>
+   * Reset this type oracle for rebuild.
    * 
    * TODO: make this not public.
    */
-  public void refresh(TreeLogger logger) throws NotFoundException {
-    allTypes = null;
-    if (javaLangObject == null) {
-      javaLangObject = findType("java.lang.Object");
-      if (javaLangObject == null) {
-        throw new NotFoundException("java.lang.Object");
-      }
-    }
-    computeHierarchyRelationships();
-    consumeTypeArgMetaData(logger);
-  }
-
-  /**
-   * Removes all types that are no longer valid.
-   * 
-   * TODO: make not public?
-   */
-  public void removeInvalidatedTypes() {
+  public void reset() {
+    recentTypes.clear();
     if (!invalidatedTypes.isEmpty()) {
       invalidateTypes(invalidatedTypes);
       invalidatedTypes.clear();
@@ -620,32 +610,25 @@
     });
   }
 
+  void addNewType(JRealClassType newType) {
+    allTypes.add(newType);
+    recentTypes.add(newType);
+  }
+
   void invalidate(JRealClassType realClassType) {
     invalidatedTypes.add(realClassType);
   }
 
-  private void buildAllTypesImpl(Set<JClassType> allTypes, JRealClassType type) {
-    boolean didAdd = allTypes.add(type);
-    assert (didAdd);
-    JClassType[] nestedTypes = type.getNestedTypes();
-    for (int i = 0; i < nestedTypes.length; i++) {
-      JRealClassType nestedType = (JRealClassType) nestedTypes[i];
-      buildAllTypesImpl(allTypes, nestedType);
-    }
-  }
-
-  private void computeHierarchyRelationships() {
+  private void computeHierarchyRelationships(JClassType[] types) {
     // For each type, walk up its hierarchy chain and tell each supertype
     // about its subtype.
-    //
-    JClassType[] types = getTypes();
     for (int i = 0; i < types.length; i++) {
       JClassType type = types[i];
       type.notifySuperTypes();
     }
   }
 
-  private void consumeTypeArgMetaData(TreeLogger logger) {
+  private void consumeTypeArgMetaData(TreeLogger logger, JClassType[] types) {
     if (GenUtil.warnAboutMetadata()) {
       logger = logger.branch(
           TreeLogger.DEBUG,
@@ -654,10 +637,6 @@
               + " javadoc annotation; please use Java parameterized types instead",
           null);
     }
-    consumeTypeArgMetaData(logger, getTypes());
-  }
-
-  private void consumeTypeArgMetaData(TreeLogger logger, JClassType[] types) {
     for (int i = 0; i < types.length; i++) {
       JClassType type = types[i];
       // CTORS not supported yet
@@ -1012,12 +991,16 @@
   private void removeTypes(Set<JRealClassType> invalidTypes) {
     for (Iterator<JRealClassType> iter = invalidTypes.iterator(); iter.hasNext();) {
       JClassType classType = iter.next();
+
+      allTypes.remove(classType);
+
       JPackage pkg = classType.getPackage();
       if (pkg != null) {
         pkg.remove(classType);
       }
 
       classType.removeFromSupertypes();
+
       iter.remove();
     }
   }
diff --git a/dev/core/src/com/google/gwt/dev/Precompile.java b/dev/core/src/com/google/gwt/dev/Precompile.java
index 0dd403a..a5aa4ed 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -26,6 +26,7 @@
 import com.google.gwt.dev.cfg.PropertyPermutations;
 import com.google.gwt.dev.cfg.Rules;
 import com.google.gwt.dev.cfg.StaticPropertyOracle;
+import com.google.gwt.dev.javac.CompilationState;
 import com.google.gwt.dev.javac.CompilationUnit;
 import com.google.gwt.dev.jdt.RebindOracle;
 import com.google.gwt.dev.jdt.RebindPermutationOracle;
@@ -36,6 +37,7 @@
 import com.google.gwt.dev.jjs.JsOutputOption;
 import com.google.gwt.dev.jjs.UnifiedAst;
 import com.google.gwt.dev.shell.StandardRebindOracle;
+import com.google.gwt.dev.util.PerfLogger;
 import com.google.gwt.dev.util.Util;
 import com.google.gwt.dev.util.arg.ArgHandlerDisableAggressiveOptimization;
 import com.google.gwt.dev.util.arg.ArgHandlerEnableAssertions;
@@ -152,8 +154,8 @@
     private RebindOracle[] rebindOracles;
 
     public DistillerRebindPermutationOracle(ModuleDef module,
-        ArtifactSet generatorArtifacts, PropertyPermutations perms,
-        File genDir, File generatorResourcesDir) {
+        CompilationState compilationState, ArtifactSet generatorArtifacts,
+        PropertyPermutations perms, File genDir, File generatorResourcesDir) {
       permutations = new Permutation[perms.size()];
       propertyOracles = new StaticPropertyOracle[perms.size()];
       rebindOracles = new RebindOracle[perms.size()];
@@ -165,9 +167,9 @@
         String[] orderedPropValues = perms.getOrderedPropertyValues(i);
         propertyOracles[i] = new StaticPropertyOracle(orderedProps,
             orderedPropValues, configProps);
-        rebindOracles[i] = new StandardRebindOracle(
-            module.getCompilationState(), propertyOracles[i], module, rules,
-            genDir, generatorResourcesDir, generatorArtifacts);
+        rebindOracles[i] = new StandardRebindOracle(compilationState,
+            propertyOracles[i], module, rules, genDir, generatorResourcesDir,
+            generatorArtifacts);
         permutations[i] = new Permutation(propertyOracles[i]);
       }
     }
@@ -252,6 +254,8 @@
       JJSOptions jjsOptions, ModuleDef module, File genDir,
       File generatorResourcesDir) {
     try {
+      CompilationState compilationState = module.getCompilationState(logger);
+
       String[] declEntryPts = module.getEntryPointTypeNames();
       if (declEntryPts.length == 0) {
         logger.log(TreeLogger.ERROR, "Module has no entry points defined", null);
@@ -260,13 +264,16 @@
 
       ArtifactSet generatedArtifacts = new ArtifactSet();
       DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
-          module, generatedArtifacts, new PropertyPermutations(
-              module.getProperties()), genDir, generatorResourcesDir);
+          module, compilationState, generatedArtifacts,
+          new PropertyPermutations(module.getProperties()), genDir,
+          generatorResourcesDir);
 
       WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
-          module.getCompilationState(), rpo);
+          compilationState, rpo);
+      PerfLogger.start("Precompile");
       UnifiedAst unifiedAst = JavaToJavaScriptCompiler.precompile(logger,
           frontEnd, declEntryPts, jjsOptions, rpo.getPermuationCount() == 1);
+      PerfLogger.end();
 
       // Merge all identical permutations together.
       Permutation[] permutations = rpo.getPermutations();
@@ -305,10 +312,12 @@
   public static boolean validate(TreeLogger logger, JJSOptions jjsOptions,
       ModuleDef module, File genDir, File generatorResourcesDir) {
     try {
+      CompilationState compilationState = module.getCompilationState(logger);
+
       String[] declEntryPts = module.getEntryPointTypeNames();
       if (declEntryPts.length == 0) {
         // Pretend that every single compilation unit is an entry point.
-        Set<CompilationUnit> compilationUnits = module.getCompilationState().getCompilationUnits();
+        Set<CompilationUnit> compilationUnits = compilationState.getCompilationUnits();
         declEntryPts = new String[compilationUnits.size()];
         int i = 0;
         for (CompilationUnit unit : compilationUnits) {
@@ -318,11 +327,12 @@
 
       ArtifactSet generatorArtifacts = new ArtifactSet();
       DistillerRebindPermutationOracle rpo = new DistillerRebindPermutationOracle(
-          module, generatorArtifacts, new PropertyPermutations(
-              module.getProperties()), genDir, generatorResourcesDir);
+          module, compilationState, generatorArtifacts,
+          new PropertyPermutations(module.getProperties()), genDir,
+          generatorResourcesDir);
 
       WebModeCompilerFrontEnd frontEnd = new WebModeCompilerFrontEnd(
-          module.getCompilationState(), rpo);
+          compilationState, rpo);
       JavaToJavaScriptCompiler.precompile(logger, frontEnd, declEntryPts,
           jjsOptions, true);
       return true;
@@ -385,6 +395,6 @@
         options.getModuleName());
 
     // TODO: All JDT checks now before even building TypeOracle?
-    module.getCompilationState().compile(logger);
+    module.getCompilationState(logger);
   }
 }
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 b4e4b1e..cbc3e39 100644
--- a/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
+++ b/dev/core/src/com/google/gwt/dev/cfg/ModuleDef.java
@@ -85,14 +85,14 @@
 
   private Class<? extends Linker> activePrimaryLinker;
 
-  private CompilationState compilationState;
-
   private String deployTo;
 
   private final List<String> entryPointTypeNames = new ArrayList<String>();
 
   private final Set<File> gwtXmlFiles = new HashSet<File>();
 
+  private CompilationState lazyCompilationState;
+
   private JavaSourceOracle lazyJavaSourceOracle;
 
   private ResourceOracleImpl lazyPublicOracle;
@@ -262,8 +262,11 @@
     return name;
   }
 
-  public CompilationState getCompilationState() {
-    return compilationState;
+  public CompilationState getCompilationState(TreeLogger logger) {
+    if (lazyCompilationState == null) {
+      lazyCompilationState = new CompilationState(logger, lazyJavaSourceOracle);
+    }
+    return lazyCompilationState;
   }
 
   /**
@@ -333,8 +336,29 @@
   public synchronized TypeOracle getTypeOracle(TreeLogger logger)
       throws UnableToCompleteException {
     if (lazyTypeOracle == null) {
-      lazyTypeOracle = compilationState.getTypeOracle();
-      updateTypeOracle(logger);
+      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;
   }
@@ -371,11 +395,13 @@
     lazySourceOracle.refresh(logger);
 
     // Update the compilation state to reflect the resource oracle changes.
-    compilationState.refresh();
+    if (lazyCompilationState != null) {
+      lazyCompilationState.refresh(logger);
+    }
 
     // Refresh type oracle if needed.
     if (lazyTypeOracle != null) {
-      updateTypeOracle(logger);
+      getTypeOracle(logger);
     }
     PerfLogger.end();
   }
@@ -470,9 +496,6 @@
     }
     lazyJavaSourceOracle = new JavaSourceOracleImpl(lazySourceOracle);
 
-    // Create the compilation state.
-    compilationState = new CompilationState(lazyJavaSourceOracle);
-
     PerfLogger.end();
   }
 
@@ -499,37 +522,4 @@
     return scanner;
   }
 
-  private void updateTypeOracle(TreeLogger logger)
-      throws UnableToCompleteException {
-    PerfLogger.start("ModuleDef.updateTypeOracle");
-    TreeLogger branch = logger.branch(TreeLogger.TRACE,
-        "Compiling Java source files in module '" + getName() + "'");
-    compilationState.compile(branch);
-    PerfLogger.end();
-
-    TypeOracle typeOracle = compilationState.getTypeOracle();
-
-    // Sanity check the seed types and don't even start it they're missing.
-    boolean seedTypesMissing = false;
-    if (typeOracle.findType("java.lang.Object") == null) {
-      Util.logMissingTypeErrorWithHints(logger, "java.lang.Object");
-      seedTypesMissing = true;
-    } else {
-      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 1af9a10..a63ae7b 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationState.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.dev.javac.CompilationUnit.State;
 import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
@@ -40,34 +39,17 @@
  */
 public class CompilationState {
 
-  /**
-   * Compute the set of all valid binary type names (for
-   * {@link BinaryTypeReferenceRestrictionsChecker}.
-   */
-  private static Set<String> getValidBinaryTypeNames(Set<CompilationUnit> units) {
-    Set<String> validBinaryTypeNames = new HashSet<String>();
+  private static void markSurvivorsChecked(Set<CompilationUnit> units) {
     for (CompilationUnit unit : units) {
-      switch (unit.getState()) {
-        case COMPILED:
-          for (ClassFile classFile : unit.getJdtCud().compilationResult().getClassFiles()) {
-            char[] binaryName = CharOperation.concatWith(
-                classFile.getCompoundName(), '/');
-            validBinaryTypeNames.add(String.valueOf(binaryName));
-          }
-          break;
-        case CHECKED:
-          for (CompiledClass compiledClass : unit.getCompiledClasses()) {
-            validBinaryTypeNames.add(compiledClass.getBinaryName());
-          }
-          break;
+      if (unit.getState() == State.COMPILED) {
+        unit.setState(State.CHECKED);
       }
     }
-    return validBinaryTypeNames;
   }
 
   protected final Map<String, CompilationUnit> unitMap = new HashMap<String, CompilationUnit>();
-  private Set<JavaSourceFile> cachedSourceFiles = Collections.emptySet();
 
+  private Set<JavaSourceFile> cachedSourceFiles = Collections.emptySet();
   /**
    * Classes mapped by binary name.
    */
@@ -83,68 +65,55 @@
    */
   private final Map<String, CompilationUnit> exposedUnitMap = Collections.unmodifiableMap(unitMap);
 
+  /**
+   * Unmodifiable view of all units.
+   */
   private Set<CompilationUnit> exposedUnits = Collections.emptySet();
+
+  /**
+   * Recreated on refresh, allows incremental compiles.
+   */
+  private JdtCompiler jdtCompiler;
+
+  /**
+   * Controls our type oracle.
+   */
   private final TypeOracleMediator mediator = new TypeOracleMediator();
+
+  /**
+   * Our source file inputs.
+   */
   private final JavaSourceOracle sourceOracle;
 
   /**
+   * Tracks the set of valid binary type names for
+   * {@link BinaryTypeReferenceRestrictionsChecker}.
+   */
+  private final Set<String> validBinaryTypeNames = new HashSet<String>();
+
+  /**
    * Construct a new {@link CompilationState}.
    * 
    * @param sourceOracle an oracle used to retrieve source code and check for
    *          changes in the underlying source code base
    */
-  public CompilationState(JavaSourceOracle sourceOracle) {
+  public CompilationState(TreeLogger logger, JavaSourceOracle sourceOracle) {
     this.sourceOracle = sourceOracle;
-    refresh();
+    refresh(logger);
   }
 
-  public void addGeneratedCompilationUnit(CompilationUnit unit) {
-    String typeName = unit.getTypeName();
-    assert (!unitMap.containsKey(typeName));
-    unitMap.put(typeName, unit);
-    updateExposedUnits();
-  }
-
-  /**
-   * Compile all units and updates all internal state. Invalidate any units with
-   * compile errors.
-   */
-  public void compile(TreeLogger logger) throws UnableToCompleteException {
-    PerfLogger.start("CompilationState.compile");
-    Set<CompilationUnit> units = getCompilationUnits();
-    if (JdtCompiler.compile(units)) {
-      Set<String> validBinaryTypeNames = getValidBinaryTypeNames(units);
-
-      // Dump all units with direct errors; we cannot safely check them.
-      boolean anyErrors = CompilationUnitInvalidator.invalidateUnitsWithErrors(
-          logger, units);
-
-      // Check all units using our custom checks.
-      CompilationUnitInvalidator.validateCompilationUnits(units,
-          validBinaryTypeNames);
-
-      // More units may have errors now.
-      anyErrors |= CompilationUnitInvalidator.invalidateUnitsWithErrors(logger,
-          units);
-
-      if (anyErrors) {
-        CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(logger, units);
-      }
-
-      JsniCollector.collectJsniMethods(logger, units, new JsProgram());
+  @SuppressWarnings("unchecked")
+  public void addGeneratedCompilationUnits(TreeLogger logger,
+      Set<? extends CompilationUnit> generatedCups) {
+    for (CompilationUnit unit : generatedCups) {
+      String typeName = unit.getTypeName();
+      assert (!unitMap.containsKey(typeName));
+      unitMap.put(typeName, unit);
     }
-
-    mediator.refresh(logger, units);
-
-    // Any surviving units are now considered CHECKED.
-    for (CompilationUnit unit : units) {
-      if (unit.getState() == State.COMPILED) {
-        unit.setState(State.CHECKED);
-      }
-    }
-
     updateExposedUnits();
-    PerfLogger.end();
+    compile(logger, (Set<CompilationUnit>) generatedCups);
+    mediator.addNewUnits(logger, (Set<CompilationUnit>) generatedCups);
+    markSurvivorsChecked((Set<CompilationUnit>) generatedCups);
   }
 
   /**
@@ -193,7 +162,7 @@
    * 
    * TODO: something more optimal with generated files?
    */
-  public void refresh() {
+  public void refresh(TreeLogger logger) {
     // Always remove all generated compilation units.
     for (Iterator<CompilationUnit> it = unitMap.values().iterator(); it.hasNext();) {
       CompilationUnit unit = it.next();
@@ -204,10 +173,49 @@
     }
 
     refreshFromSourceOracle();
+    updateExposedUnits();
+
     // Don't log about invalidated units via refresh.
     CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(TreeLogger.NULL,
         getCompilationUnits());
-    updateExposedUnits();
+
+    jdtCompiler = new JdtCompiler();
+    validBinaryTypeNames.clear();
+    compile(logger, getCompilationUnits());
+    mediator.refresh(logger, getCompilationUnits());
+    markSurvivorsChecked(getCompilationUnits());
+  }
+
+  /**
+   * Compile units and update their internal state. Invalidate any units with
+   * compile errors.
+   */
+  private void compile(TreeLogger logger, Set<CompilationUnit> newUnits) {
+    PerfLogger.start("CompilationState.compile");
+    if (jdtCompiler.doCompile(newUnits)) {
+      // Dump all units with direct errors; we cannot safely check them.
+      boolean anyErrors = CompilationUnitInvalidator.invalidateUnitsWithErrors(
+          logger, newUnits);
+
+      // Check all units using our custom checks.
+      CompilationUnitInvalidator.validateCompilationUnits(newUnits,
+          validBinaryTypeNames);
+
+      // More units may have errors now.
+      anyErrors |= CompilationUnitInvalidator.invalidateUnitsWithErrors(logger,
+          newUnits);
+
+      if (anyErrors) {
+        CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(logger,
+            newUnits);
+      }
+
+      recordValidBinaryTypeNames(newUnits);
+
+      JsniCollector.collectJsniMethods(logger, newUnits, new JsProgram());
+    }
+
+    PerfLogger.end();
   }
 
   private void rebuildClassMaps() {
@@ -225,6 +233,18 @@
     exposedClassFileMapBySource = Collections.unmodifiableMap(classFileMapBySource);
   }
 
+  private void recordValidBinaryTypeNames(Set<CompilationUnit> units) {
+    for (CompilationUnit unit : units) {
+      if (unit.getState() == State.COMPILED) {
+        for (ClassFile classFile : unit.getJdtCud().compilationResult().getClassFiles()) {
+          char[] binaryName = CharOperation.concatWith(
+              classFile.getCompoundName(), '/');
+          validBinaryTypeNames.add(String.valueOf(binaryName));
+        }
+      }
+    }
+  }
+
   private void refreshFromSourceOracle() {
     // See if the source oracle has changed.
     Set<JavaSourceFile> newSourceFiles = sourceOracle.getSourceFiles();
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
index f9e19a7..b02a342 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
@@ -98,11 +98,12 @@
 
     @Override
     public void process(CompilationUnitDeclaration cud, int i) {
-      // TODO: not always generate bytecode eagerly?
       super.process(cud, i);
       ICompilationUnit icu = cud.compilationResult().compilationUnit;
       CompilationUnitAdapter adapter = (CompilationUnitAdapter) icu;
-      adapter.getUnit().setJdtCud(cud);
+      CompilationUnit unit = adapter.getUnit();
+      unit.setJdtCud(cud);
+      recordBinaryTypes(unit.getCompiledClasses());
     }
   }
 
@@ -228,8 +229,6 @@
     return new CompilerOptions(settings);
   }
 
-  private final List<CompilationUnit> activeUnits = new ArrayList<CompilationUnit>();
-
   /**
    * Maps dotted binary names to compiled classes.
    */
@@ -244,7 +243,29 @@
   /**
    * Not externally instantiable.
    */
-  private JdtCompiler() {
+  public JdtCompiler() {
+  }
+
+  public boolean doCompile(Collection<CompilationUnit> units) {
+    List<ICompilationUnit> icus = new ArrayList<ICompilationUnit>();
+    for (CompilationUnit unit : units) {
+      String packageName = Shared.getPackageName(unit.getTypeName());
+      addPackages(packageName);
+      Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
+      if (compiledClasses == null) {
+        icus.add(new CompilationUnitAdapter(unit));
+      } else {
+        recordBinaryTypes(compiledClasses);
+      }
+    }
+    if (icus.isEmpty()) {
+      return false;
+    }
+
+    PerfLogger.start("JdtCompiler.compile");
+    compiler.compile(icus.toArray(new ICompilationUnit[icus.size()]));
+    PerfLogger.end();
+    return true;
   }
 
   private void addPackages(String packageName) {
@@ -260,30 +281,11 @@
     }
   }
 
-  private boolean doCompile(Collection<CompilationUnit> units) {
-    List<ICompilationUnit> icus = new ArrayList<ICompilationUnit>();
-    for (CompilationUnit unit : units) {
-      String packageName = Shared.getPackageName(unit.getTypeName());
-      addPackages(packageName);
-      Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
-      if (compiledClasses == null) {
-        icus.add(new CompilationUnitAdapter(unit));
-        activeUnits.add(unit);
-      } else {
-        for (CompiledClass compiledClass : compiledClasses) {
-          binaryTypes.put(compiledClass.getBinaryName().replace('/', '.'),
-              compiledClass);
-        }
-      }
+  private void recordBinaryTypes(Set<CompiledClass> compiledClasses) {
+    for (CompiledClass compiledClass : compiledClasses) {
+      binaryTypes.put(compiledClass.getBinaryName().replace('/', '.'),
+          compiledClass);
     }
-    if (icus.isEmpty()) {
-      return false;
-    }
-
-    PerfLogger.start("JdtCompiler.compile");
-    compiler.compile(icus.toArray(new ICompilationUnit[icus.size()]));
-    PerfLogger.end();
-    return true;
   }
 
 }
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 885f0d4..63e4a4e 100644
--- a/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
+++ b/dev/core/src/com/google/gwt/dev/javac/TypeOracleMediator.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.HasMetaData;
 import com.google.gwt.core.ext.typeinfo.HasTypeParameters;
 import com.google.gwt.core.ext.typeinfo.JAbstractMethod;
@@ -37,12 +36,10 @@
 import com.google.gwt.core.ext.typeinfo.JRealClassType;
 import com.google.gwt.core.ext.typeinfo.JType;
 import com.google.gwt.core.ext.typeinfo.JTypeParameter;
-import com.google.gwt.core.ext.typeinfo.NotFoundException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.core.ext.typeinfo.JWildcardType.BoundType;
 import com.google.gwt.dev.javac.impl.Shared;
 import com.google.gwt.dev.util.Empty;
-import com.google.gwt.dev.util.PerfLogger;
 
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
@@ -336,22 +333,28 @@
 
   private final Map<String, JRealClassType> binaryMapper = new HashMap<String, JRealClassType>();
   private final Map<SourceTypeBinding, JRealClassType> sourceMapper = new IdentityHashMap<SourceTypeBinding, JRealClassType>();
-  private final Map<TypeVariableBinding, JTypeParameter> tvMapper = new IdentityHashMap<TypeVariableBinding, JTypeParameter>();
+
+  /**
+   * Mapping of type variable bindings; transient because compilation units are
+   * processed monolithically, and a tv binding is only valid within a single
+   * unit.
+   */
+  private final transient Map<TypeVariableBinding, JTypeParameter> tvMapper = new IdentityHashMap<TypeVariableBinding, JTypeParameter>();
+
   private final TypeOracle typeOracle = new TypeOracle();
-  private final Set<JRealClassType> unresolvedTypes = new HashSet<JRealClassType>();
 
-  public TypeOracle getTypeOracle() {
-    return typeOracle;
-  }
+  /**
+   * Set of unresolved types to process, generated from the first phase of type
+   * oracle resolution. Transient because they all get resolved in the second
+   * phase.
+   */
+  private final transient Set<JRealClassType> unresolvedTypes = new HashSet<JRealClassType>();
 
-  public void refresh(TreeLogger logger, Set<CompilationUnit> units)
-      throws UnableToCompleteException {
-    PerfLogger.start("TypeOracleMediator.refresh");
-    typeOracle.removeInvalidatedTypes();
-    clear();
-
+  /**
+   * Adds new units to an existing TypeOracle.
+   */
+  public void addNewUnits(TreeLogger logger, Set<CompilationUnit> units) {
     // Perform a shallow pass to establish identity for new and old types.
-    PerfLogger.start("TypeOracleMediator.refresh (shallow)");
     for (CompilationUnit unit : units) {
       if (!unit.isCompiled()) {
         continue;
@@ -365,10 +368,8 @@
         binaryMapper.put(compiledClass.getBinaryName(), type);
       }
     }
-    PerfLogger.end();
 
     // Perform a deep pass to resolve all new types in terms of our types.
-    PerfLogger.start("TypeOracleMediator.refresh (deep)");
     for (CompilationUnit unit : units) {
       if (!unit.isCompiled()) {
         continue;
@@ -377,9 +378,10 @@
           "Processing types in compilation unit: " + unit.getDisplayLocation());
       Set<CompiledClass> compiledClasses = unit.getCompiledClasses();
       for (CompiledClass compiledClass : compiledClasses) {
-        if (unresolvedTypes.contains(compiledClass.getRealClassType())) {
+        if (unresolvedTypes.remove(compiledClass.getRealClassType())) {
           TypeDeclaration typeDeclaration = compiledClass.getTypeDeclaration();
-          if (!resolveTypeDeclaration(cudLogger, unit.getSource(), typeDeclaration)) {
+          if (!resolveTypeDeclaration(cudLogger, unit.getSource(),
+              typeDeclaration)) {
             logger.log(TreeLogger.WARN,
                 "Unexpectedly unable to fully resolve type "
                     + compiledClass.getSourceName());
@@ -387,24 +389,25 @@
         }
       }
     }
-    clear();
-    PerfLogger.end();
+    // Clean transient state.
+    assert unresolvedTypes.size() == 0;
+    tvMapper.clear();
 
-    try {
-      typeOracle.refresh(logger);
-    } catch (NotFoundException e) {
-      // TODO
-      e.printStackTrace();
-    }
-
-    PerfLogger.end();
+    typeOracle.finish(logger);
   }
 
-  private void clear() {
+  public TypeOracle getTypeOracle() {
+    return typeOracle;
+  }
+
+  /**
+   * Full refresh based on new units.
+   */
+  public void refresh(TreeLogger logger, Set<CompilationUnit> units) {
     binaryMapper.clear();
     sourceMapper.clear();
-    tvMapper.clear();
-    unresolvedTypes.clear();
+    typeOracle.reset();
+    addNewUnits(logger, units);
   }
 
   private Object createAnnotationInstance(TreeLogger logger,
diff --git a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
index 38f106f..0a526c3 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
@@ -90,7 +90,7 @@
     // It has to wait until now because we need to inject javascript.
     //
     Rules rules = module.getRules();
-    rebindOracle = new StandardRebindOracle(module.getCompilationState(),
+    rebindOracle = new StandardRebindOracle(module.getCompilationState(logger),
         propOracle, module, rules, genDir, shellDir, new ArtifactSet());
 
     // Create a completely isolated class loader which owns all classes
@@ -105,7 +105,7 @@
     // class loader (the one that loaded the shell itself).
     //
     classLoader = new CompilingClassLoader(logger,
-        module.getCompilationState(), readySpace);
+        module.getCompilationState(logger), readySpace);
   }
 
   public String rebind(TreeLogger logger, String sourceTypeName)
diff --git a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
index 64687f5..06ba50e 100644
--- a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
+++ b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
@@ -308,14 +308,14 @@
           String qualifiedTypeName = gcup.getTypeName();
           genTypeNames.add(qualifiedTypeName);
           maybeWriteSource(gcup, qualifiedTypeName);
-          compilationState.addGeneratedCompilationUnit(gcup);
 
           if (subBranch != null) {
             subBranch.log(TreeLogger.DEBUG, gcup.getDisplayLocation(), null);
           }
         }
 
-        compilationState.compile(logger);
+        compilationState.addGeneratedCompilationUnits(logger,
+            committedGeneratedCups);
       }
 
       // Make sure all generated types can be found in TypeOracle.
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 23cdb49..6c1a9ad 100644
--- a/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/CompilationStateTest.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.dev.javac.CompilationUnit.State;
 import com.google.gwt.dev.javac.impl.MockJavaSourceFile;
 import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
@@ -38,23 +37,6 @@
  */
 public class CompilationStateTest extends TestCase {
 
-  private MockJavaSourceOracle oracle = new MockJavaSourceOracle(
-      JavaSourceCodeBase.getStandardResources());
-
-  private CompilationState state = new CompilationState(oracle);
-
-  public void testAddGeneratedCompilationUnit() {
-    validateCompilationState();
-
-    // Add a unit and ensure it shows up.
-    addGeneratedUnit(JavaSourceCodeBase.FOO);
-    validateCompilationState(JavaSourceCodeBase.FOO.getTypeName());
-
-    // Ensure it disappears after a refresh.
-    state.refresh();
-    validateCompilationState();
-  }
-
   static void assertUnitsChecked(Collection<CompilationUnit> units) {
     for (CompilationUnit unit : units) {
       assertSame(State.CHECKED, unit.getState());
@@ -63,17 +45,41 @@
     }
   }
 
-  public void testCompile() throws UnableToCompleteException {
-    validateUncompiled();
-    state.compile(createTreeLogger());
-    assertUnitsChecked(state.getCompilationUnits());
+  /**
+   * Tweak this if you want to see the log output.
+   */
+  private static TreeLogger createTreeLogger() {
+    boolean reallyLog = false;
+    if (reallyLog) {
+      AbstractTreeLogger logger = new PrintWriterTreeLogger();
+      logger.setMaxDetail(TreeLogger.ALL);
+      return logger;
+    } else {
+      return TreeLogger.NULL;
+    }
   }
 
-  public void testCompileError() throws UnableToCompleteException {
+  private MockJavaSourceOracle oracle = new MockJavaSourceOracle(
+      JavaSourceCodeBase.getStandardResources());
+
+  private CompilationState state = new CompilationState(createTreeLogger(),
+      oracle);
+
+  public void testAddGeneratedCompilationUnit() {
+    validateCompilationState();
+
+    // Add a unit and ensure it shows up.
+    addGeneratedUnits(JavaSourceCodeBase.FOO);
+    validateCompilationState(JavaSourceCodeBase.FOO.getTypeName());
+
+    // Ensure it disappears after a refresh.
+    state.refresh(createTreeLogger());
+    validateCompilationState();
+  }
+
+  public void testCompileError() {
     oracle.add(JavaSourceCodeBase.BAR);
-    state.refresh();
-    validateUncompiled();
-    state.compile(createTreeLogger());
+    state.refresh(createTreeLogger());
 
     CompilationUnit badUnit = state.getCompilationUnitMap().get(
         JavaSourceCodeBase.BAR.getTypeName());
@@ -85,22 +91,15 @@
     assertUnitsChecked(goodUnits);
   }
 
-  public void testCompileWithGeneratedUnits() throws UnableToCompleteException {
-    validateUncompiled();
-    state.compile(createTreeLogger());
+  public void testCompileWithGeneratedUnits() {
     assertUnitsChecked(state.getCompilationUnits());
-    addGeneratedUnit(JavaSourceCodeBase.FOO);
-    state.compile(createTreeLogger());
+    addGeneratedUnits(JavaSourceCodeBase.FOO);
     assertUnitsChecked(state.getCompilationUnits());
   }
 
-  public void testCompileWithGeneratedUnitsError()
-      throws UnableToCompleteException {
-    validateUncompiled();
-    state.compile(createTreeLogger());
+  public void testCompileWithGeneratedUnitsError() {
     assertUnitsChecked(state.getCompilationUnits());
-    addGeneratedUnit(JavaSourceCodeBase.BAR);
-    state.compile(createTreeLogger());
+    addGeneratedUnits(JavaSourceCodeBase.BAR);
 
     CompilationUnit badUnit = state.getCompilationUnitMap().get(
         JavaSourceCodeBase.BAR.getTypeName());
@@ -112,12 +111,16 @@
     assertUnitsChecked(goodUnits);
   }
 
+  public void testInitialization() {
+    assertUnitsChecked(state.getCompilationUnits());
+  }
+
   public void testSourceOracleAdd() {
     validateCompilationState();
 
     int size = state.getCompilationUnits().size();
     oracle.add(JavaSourceCodeBase.FOO);
-    state.refresh();
+    state.refresh(createTreeLogger());
     assertEquals(size + 1, state.getCompilationUnits().size());
     validateCompilationState();
   }
@@ -128,7 +131,7 @@
 
   public void testSourceOracleEmpty() {
     oracle = new MockJavaSourceOracle();
-    state = new CompilationState(oracle);
+    state = new CompilationState(createTreeLogger(), oracle);
     validateCompilationState();
   }
 
@@ -137,7 +140,7 @@
 
     int size = state.getCompilationUnits().size();
     oracle.remove(JavaSourceCodeBase.OBJECT.getTypeName());
-    state.refresh();
+    state.refresh(createTreeLogger());
     assertEquals(size - 1, state.getCompilationUnits().size());
     validateCompilationState();
   }
@@ -147,7 +150,7 @@
 
     int size = state.getCompilationUnits().size();
     oracle.replace(new MockJavaSourceFile(JavaSourceCodeBase.OBJECT));
-    state.refresh();
+    state.refresh(createTreeLogger());
     assertEquals(size, state.getCompilationUnits().size());
     validateCompilationState();
   }
@@ -157,18 +160,22 @@
 
     int size = state.getCompilationUnits().size();
     oracle.replace(JavaSourceCodeBase.OBJECT);
-    state.refresh();
+    state.refresh(createTreeLogger());
     assertEquals(size, state.getCompilationUnits().size());
     validateCompilationState();
   }
 
-  private void addGeneratedUnit(JavaSourceFile sourceFile) {
-    state.addGeneratedCompilationUnit(new SourceFileCompilationUnit(sourceFile) {
-      @Override
-      public boolean isGenerated() {
-        return true;
-      }
-    });
+  private void addGeneratedUnits(JavaSourceFile... sourceFiles) {
+    Set<CompilationUnit> units = new HashSet<CompilationUnit>();
+    for (JavaSourceFile sourceFile : sourceFiles) {
+      units.add(new SourceFileCompilationUnit(sourceFile) {
+        @Override
+        public boolean isGenerated() {
+          return true;
+        }
+      });
+    }
+    state.addGeneratedCompilationUnits(createTreeLogger(), units);
   }
 
   private void validateCompilationState(String... generatedTypeNames) {
@@ -205,24 +212,4 @@
     assertEquals(0, sourceMap.size());
     assertEquals(0, generatedTypes.size());
   }
-
-  private void validateUncompiled() {
-    for (CompilationUnit unit : state.getCompilationUnits()) {
-      assertNull(unit.getJdtCud());
-    }
-  }
-
-  /**
-   * Tweak this if you want to see the log output.
-   */
-  private TreeLogger createTreeLogger() {
-    boolean reallyLog = false;
-    if (reallyLog) {
-      AbstractTreeLogger logger = new PrintWriterTreeLogger();
-      logger.setMaxDetail(TreeLogger.ALL);
-      return logger;
-    } else {
-      return TreeLogger.NULL;
-    }
-  }
 }
diff --git a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
index ce0305d..b8eb521 100644
--- a/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/JSORestrictionsTest.java
@@ -16,14 +16,13 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.dev.util.UnitTestTreeLogger;
 
 import junit.framework.TestCase;
 
 public class JSORestrictionsTest extends TestCase {
 
-  public void testFinalClass() throws UnableToCompleteException {
+  public void testFinalClass() {
     StringBuffer code = new StringBuffer();
     code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     code.append("final public class Buggy extends JavaScriptObject {\n");
@@ -34,7 +33,7 @@
     shouldGenerateNoError(code);
   }
 
-  public void testInstanceField() throws UnableToCompleteException {
+  public void testInstanceField() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -46,7 +45,7 @@
         + JSORestrictionsChecker.ERR_INSTANCE_FIELD);
   }
 
-  public void testMultiArgConstructor() throws UnableToCompleteException {
+  public void testMultiArgConstructor() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public final class Buggy extends JavaScriptObject {\n");
@@ -57,7 +56,7 @@
         + JSORestrictionsChecker.ERR_CONSTRUCTOR_WITH_PARAMETERS);
   }
 
-  public void testNew() throws UnableToCompleteException {
+  public void testNew() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy {\n");
@@ -71,7 +70,7 @@
         + JSORestrictionsChecker.ERR_NEW_JSO);
   }
 
-  public void testNoConstructor() throws UnableToCompleteException {
+  public void testNoConstructor() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -82,7 +81,7 @@
         + JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR);
   }
 
-  public void testNoInterfaces() throws UnableToCompleteException {
+  public void testNoInterfaces() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy {\n");
@@ -99,7 +98,7 @@
         + JSORestrictionsChecker.errInterfaceWithMethods("Buggy.Squeaks"));
   }
 
-  public void testNonEmptyConstructor() throws UnableToCompleteException {
+  public void testNonEmptyConstructor() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -110,7 +109,7 @@
         + JSORestrictionsChecker.ERR_NONEMPTY_CONSTRUCTOR);
   }
 
-  public void testNonFinalMethod() throws UnableToCompleteException {
+  public void testNonFinalMethod() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -122,7 +121,7 @@
         + JSORestrictionsChecker.ERR_INSTANCE_METHOD_NONFINAL);
   }
 
-  public void testNonProtectedConstructor() throws UnableToCompleteException {
+  public void testNonProtectedConstructor() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -133,7 +132,7 @@
         + JSORestrictionsChecker.ERR_NONPROTECTED_CONSTRUCTOR);
   }
 
-  public void testNonStaticInner() throws UnableToCompleteException {
+  public void testNonStaticInner() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy {\n");
@@ -146,7 +145,7 @@
         + JSORestrictionsChecker.ERR_IS_NONSTATIC_NESTED);
   }
 
-  public void testNoOverride() throws UnableToCompleteException {
+  public void testNoOverride() {
     StringBuffer buggyCode = new StringBuffer();
     buggyCode.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     buggyCode.append("public class Buggy extends JavaScriptObject {\n");
@@ -158,7 +157,7 @@
         + JSORestrictionsChecker.ERR_OVERRIDDEN_METHOD);
   }
 
-  public void testPrivateMethod() throws UnableToCompleteException {
+  public void testPrivateMethod() {
     StringBuffer code = new StringBuffer();
     code.append("import com.google.gwt.core.client.JavaScriptObject;\n");
     code.append("public class Buggy extends JavaScriptObject {\n");
@@ -175,7 +174,7 @@
    * Buggy.
    */
   private void shouldGenerateError(CharSequence buggyCode,
-      final String expectedError) throws UnableToCompleteException {
+      final String expectedError) {
     UnitTestTreeLogger.Builder builder = new UnitTestTreeLogger.Builder();
     builder.setLowestLogLevel(TreeLogger.ERROR);
     if (expectedError != null) {
@@ -189,8 +188,7 @@
     logger.assertCorrectLogEntries();
   }
 
-  private void shouldGenerateNoError(StringBuffer buggyCode)
-      throws UnableToCompleteException {
+  private void shouldGenerateNoError(StringBuffer buggyCode) {
     shouldGenerateError(buggyCode, null);
   }
 }
diff --git a/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java b/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
index 0269e7b..7528d2a 100644
--- a/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/LongFromJSNITest.java
@@ -16,9 +16,7 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
-import com.google.gwt.dev.javac.CompilationUnit;
 import com.google.gwt.dev.util.UnitTestTreeLogger;
 
 import junit.framework.TestCase;
@@ -30,7 +28,7 @@
  * Test access to longs from JSNI.
  */
 public class LongFromJSNITest extends TestCase {
-  public void testCyclicReferences() throws UnableToCompleteException {
+  public void testCyclicReferences() {
     {
       StringBuffer buggy = new StringBuffer();
       buggy.append("class Buggy {\n");
@@ -76,7 +74,7 @@
     }
   }
 
-  public void testFieldAccess() throws UnableToCompleteException {
+  public void testFieldAccess() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("volatile long x = -1;\n");
@@ -88,7 +86,7 @@
         "Referencing field 'Buggy.x': type 'long' is not safe to access in JSNI code");
   }
 
-  public void testInnerClass() throws UnableToCompleteException {
+  public void testInnerClass() {
     StringBuffer code = new StringBuffer();
     code.append("public class Buggy {\n");
     code.append("  static class Inner {\n");
@@ -108,7 +106,7 @@
    * completely unusable in JavaScript, so the current reasoning is to allow
    * them.
    */
-  public void testLongArray() throws UnableToCompleteException {
+  public void testLongArray() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  long[] m() { return new long[] { -1 }; }\n");
@@ -119,7 +117,7 @@
     shouldGenerateNoError(code);
   }
 
-  public void testLongParameter() throws UnableToCompleteException {
+  public void testLongParameter() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  native void jsniMeth(long x) /*-{ return; }-*/;\n");
@@ -129,7 +127,7 @@
         "Parameter 'x': type 'long' is not safe to access in JSNI code");
   }
 
-  public void testLongReturn() throws UnableToCompleteException {
+  public void testLongReturn() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  native long jsniMeth() /*-{ return 0; }-*/;\n");
@@ -139,7 +137,7 @@
         "Type 'long' may not be returned from a JSNI method");
   }
 
-  public void testMethodArgument() throws UnableToCompleteException {
+  public void testMethodArgument() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  void print(long x) { }\n");
@@ -152,7 +150,7 @@
         "Parameter 1 of method \'Buggy.print\': type 'long' may not be passed out of JSNI code");
   }
 
-  public void testMethodReturn() throws UnableToCompleteException {
+  public void testMethodReturn() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  long m() { return -1; }\n");
@@ -166,8 +164,7 @@
         "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code");
   }
 
-  public void testOverloadedMethodWithNoWarning()
-      throws UnableToCompleteException {
+  public void testOverloadedMethodWithNoWarning() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  long m(int x) { return -1; }\n");
@@ -179,8 +176,7 @@
     shouldGenerateNoError(code);
   }
 
-  public void testOverloadedMethodWithWarning()
-      throws UnableToCompleteException {
+  public void testOverloadedMethodWithWarning() {
     StringBuffer code = new StringBuffer();
     code.append("class Buggy {\n");
     code.append("  long m(int x) { return -1; }\n");
@@ -195,7 +191,20 @@
         "Referencing method 'Buggy.m': return type 'long' is not safe to access in JSNI code");
   }
 
-  public void testUnsafeAnnotation() throws UnableToCompleteException {
+  public void testRefInString() {
+    {
+      StringBuffer code = new StringBuffer();
+      code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
+      code.append("class Buggy {\n");
+      code.append("  void print(long x) { }\n");
+      code.append("  native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;\n");
+      code.append("}\n");
+
+      shouldGenerateNoError(code);
+    }
+  }
+
+  public void testUnsafeAnnotation() {
     {
       StringBuffer code = new StringBuffer();
       code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
@@ -209,20 +218,7 @@
     }
   }
 
-  public void testRefInString() throws UnableToCompleteException {
-    {
-      StringBuffer code = new StringBuffer();
-      code.append("import com.google.gwt.core.client.UnsafeNativeLong;");
-      code.append("class Buggy {\n");
-      code.append("  void print(long x) { }\n");
-      code.append("  native void jsniMeth() /*-{ 'this.@Buggy::print(J)(0)'; }-*/;\n");
-      code.append("}\n");
-
-      shouldGenerateNoError(code);
-    }
-  }
-
-  public void testViolator() throws UnableToCompleteException {
+  public void testViolator() {
     {
       StringBuffer okay = new StringBuffer();
       okay.append("class Buggy {\n");
@@ -274,8 +270,7 @@
   }
 
   private TypeOracle buildOracle(CharSequence buggyCode,
-      CharSequence extraCode, UnitTestTreeLogger logger)
-      throws UnableToCompleteException {
+      CharSequence extraCode, UnitTestTreeLogger logger) {
     Set<CompilationUnit> units = new HashSet<CompilationUnit>();
     addLongCheckingCups(units);
     units.add(new MockCompilationUnit("Buggy", buggyCode.toString()));
@@ -287,8 +282,7 @@
   }
 
   private void shouldGenerateError(CharSequence buggyCode,
-      CharSequence extraCode, int line, String message)
-      throws UnableToCompleteException {
+      CharSequence extraCode, int line, String message) {
     UnitTestTreeLogger.Builder b = new UnitTestTreeLogger.Builder();
     b.setLowestLogLevel(TreeLogger.ERROR);
     if (message != null) {
@@ -306,17 +300,15 @@
   }
 
   private void shouldGenerateError(CharSequence buggyCode, int line,
-      String message) throws UnableToCompleteException {
+      String message) {
     shouldGenerateError(buggyCode, null, line, message);
   }
 
-  private void shouldGenerateNoError(CharSequence code)
-      throws UnableToCompleteException {
+  private void shouldGenerateNoError(CharSequence code) {
     shouldGenerateNoError(code, null);
   }
 
-  private void shouldGenerateNoError(CharSequence code, CharSequence extraCode)
-      throws UnableToCompleteException {
+  private void shouldGenerateNoError(CharSequence code, CharSequence extraCode) {
     shouldGenerateError(code, extraCode, -1, null);
   }
 }
diff --git a/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
index 2516e15..fee4d53 100644
--- a/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleMediatorTest.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.JArrayType;
 import com.google.gwt.core.ext.typeinfo.JClassType;
 import com.google.gwt.core.ext.typeinfo.JField;
@@ -59,10 +58,10 @@
   private static void assertEqualArraysUnordered(Object[] expected,
       Object[] actual) {
     assertEquals(expected.length, actual.length);
-    for (int i = 0; i < expected.length; i++) {
+    for (Object element : expected) {
       boolean matched = false;
-      for (int j = 0; j < actual.length; j++) {
-        if (expected[i].equals(actual[j])) {
+      for (Object element2 : actual) {
+        if (element.equals(element2)) {
           matched = true;
           break;
         }
@@ -79,8 +78,10 @@
   }
 
   private static void assertIsNotAssignable(JClassType from, JClassType to) {
-    assertFalse(from.isAssignableTo(to));
-    assertFalse(to.isAssignableFrom(from));
+    assertFalse(from + " should not be assignable to " + to,
+        from.isAssignableTo(to));
+    assertFalse(to + " should not be assignable to " + from,
+        to.isAssignableFrom(from));
   }
 
   private static void recordAssignability(
@@ -101,11 +102,13 @@
 
   protected CheckedMockCompilationUnit CU_AfterAssimilate = new CheckedMockCompilationUnit(
       "test.assim", "AfterAssimilate") {
+    @Override
     public void check(JClassType type) {
       assertEquals("test.assim.BeforeAssimilate",
           type.getSuperclass().getQualifiedSourceName());
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test.assim;\n");
@@ -117,13 +120,16 @@
   protected CheckedMockCompilationUnit CU_Assignable = new CheckedMockCompilationUnit(
       "test.sub", "Derived", "BaseInterface", "DerivedInterface",
       "Derived.Nested") {
+    @Override
     public void check(JClassType type) {
-      if ("Derived".equals(type.getSimpleSourceName()))
+      if ("Derived".equals(type.getSimpleSourceName())) {
         checkDerived(type);
-      else if ("Nested".equals(type.getSimpleSourceName()))
+      } else if ("Nested".equals(type.getSimpleSourceName())) {
         checkNested(type);
+      }
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test.sub;\n");
@@ -148,10 +154,12 @@
 
   protected CheckedMockCompilationUnit CU_BeforeAssimilate = new CheckedMockCompilationUnit(
       "test.assim", "BeforeAssimilate") {
+    @Override
     public void check(JClassType type) {
       assertEquals("test.assim.BeforeAssimilate", type.getQualifiedSourceName());
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test.assim;\n");
@@ -164,13 +172,15 @@
       "test", "BindToTypeScope", "BindToTypeScope.Object",
       "BindToTypeScope.DerivedObject") {
 
+    @Override
     public void check(JClassType type) throws NotFoundException {
-      if ("BindToTypeScope".equals(type.getSimpleSourceName()))
+      if ("BindToTypeScope".equals(type.getSimpleSourceName())) {
         checkBindToTypeScope(type);
-      else if ("Object".equals(type.getSimpleSourceName()))
+      } else if ("Object".equals(type.getSimpleSourceName())) {
         checkObject(type);
-      else
+      } else {
         checkDerivedObject(type);
+      }
     }
 
     public void checkBindToTypeScope(JClassType type) throws NotFoundException {
@@ -187,6 +197,7 @@
       assertEquals("test.BindToTypeScope.Object", type.getQualifiedSourceName());
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test;\n");
@@ -218,6 +229,7 @@
       assertNotNull(type.isGenericType());
     }
 
+    @Override
     public String getSource() {
       StringBuilder sb = new StringBuilder();
       sb.append("package parameterized.type.build.dependency;\n");
@@ -230,6 +242,7 @@
 
   protected CheckedMockCompilationUnit CU_DefaultClass = new CheckedMockCompilationUnit(
       "test", "DefaultClass") {
+    @Override
     public void check(JClassType type) {
       assertEquals("DefaultClass", type.getSimpleSourceName());
       assertEquals("test.DefaultClass", type.getQualifiedSourceName());
@@ -241,6 +254,7 @@
       assertEquals(0, type.getFields().length);
     }
 
+    @Override
     public String getSource() {
       StringBuffer sb = new StringBuffer();
       sb.append("package test;\n");
@@ -257,6 +271,7 @@
       assertNotNull(type.getSuperclass().isParameterized());
     }
 
+    @Override
     public String getSource() {
       StringBuilder sb = new StringBuilder();
       sb.append("package test.refresh;\n");
@@ -272,6 +287,7 @@
       assertNotNull(type.getSuperclass().isParameterized());
     }
 
+    @Override
     public String getSource() {
       StringBuilder sb = new StringBuilder();
       sb.append("package parameterized.type.build.dependency;\n");
@@ -282,6 +298,7 @@
 
   protected CheckedMockCompilationUnit CU_FieldsAndTypes = new CheckedMockCompilationUnit(
       "test", "Fields", "SomeType") {
+    @Override
     public void check(JClassType type) throws NotFoundException {
       if ("Fields".equals(type.getSimpleSourceName())) {
         assertEquals("test.Fields", type.getQualifiedSourceName());
@@ -445,10 +462,11 @@
 
     public void check(JClassType type) {
       final String name = type.getSimpleSourceName();
-      if ("Enclosing".equals(name))
+      if ("Enclosing".equals(name)) {
         checkEnclosing(type);
-      else
+      } else {
         checkLocal(type);
+      }
     }
 
     public void checkEnclosing(JClassType type) {
@@ -603,8 +621,9 @@
 
       methods = type.getOverloads("overloaded");
       assertEquals(2, methods.length);
-      for (int i = 0; i < methods.length; i++)
-        assertEquals("overloaded", methods[i].getName());
+      for (JMethod element : methods) {
+        assertEquals("overloaded", element.getName());
+      }
 
       method = type.getMethod("overloaded", new JType[] {
           JPrimitiveType.INT, javaLangObject});
@@ -655,10 +674,11 @@
 
     public void check(JClassType type) {
       final String name = type.getSimpleSourceName();
-      if ("Outer".equals(name))
+      if ("Outer".equals(name)) {
         checkOuter(type);
-      else
+      } else {
         checkInner(type);
+      }
     }
 
     public void checkInner(JClassType type) {
@@ -759,8 +779,7 @@
   private final Set<CompilationUnit> units = new HashSet<CompilationUnit>();
 
   public void checkTypes(JClassType[] types) throws NotFoundException {
-    for (int i = 0; i < types.length; i++) {
-      JClassType type = types[i];
+    for (JClassType type : types) {
       check(type);
 
       JClassType[] nestedTypes = type.getNestedTypes();
@@ -768,8 +787,7 @@
     }
   }
 
-  public void testAssignable() throws UnableToCompleteException,
-      TypeOracleException {
+  public void testAssignable() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_Assignable);
     units.add(CU_OuterInner);
@@ -806,8 +824,7 @@
     }
   }
 
-  public void testAssimilation() throws UnableToCompleteException,
-      TypeOracleException {
+  public void testAssimilation() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_BeforeAssimilate);
     compileAndRefresh();
@@ -824,8 +841,7 @@
     assertSame(before, after.getSuperclass());
   }
 
-  public void testBindToTypeScope() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testBindToTypeScope() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_BindToTypeScope);
     compileAndRefresh();
@@ -833,8 +849,7 @@
     assertEquals(4, types.length);
   }
 
-  public void testDefaultClass() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testDefaultClass() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_DefaultClass);
     compileAndRefresh();
@@ -842,8 +857,7 @@
     assertEquals(2, types.length);
   }
 
-  public void testFieldsAndTypes() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testFieldsAndTypes() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_FieldsAndTypes);
     compileAndRefresh();
@@ -851,7 +865,7 @@
     assertEquals(3, types.length);
   }
 
-  public void testLocal() throws TypeOracleException, UnableToCompleteException {
+  public void testLocal() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_LocalClass);
     compileAndRefresh();
@@ -859,8 +873,7 @@
     assertEquals(3, types.length);
   }
 
-  public void testMetaData() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testMetaData() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_MetaData);
     compileAndRefresh();
@@ -868,8 +881,7 @@
     assertEquals(2, types.length);
   }
 
-  public void testMethodsAndParams() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testMethodsAndParams() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_Throwable);
     units.add(CU_MethodsAndParams);
@@ -878,8 +890,7 @@
     assertEquals(3, types.length);
   }
 
-  public void testOuterInner() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testOuterInner() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_OuterInner);
     compileAndRefresh();
@@ -896,7 +907,7 @@
    * CU_DeclaresInnerGenericType.
    */
   public void testParameterizedTypeBuildDependencies()
-      throws UnableToCompleteException, TypeOracleException {
+      throws TypeOracleException {
     units.add(CU_ReferencesParameterizedTypeBeforeItsGenericFormHasBeenProcessed);
     units.add(CU_ExtendsParameterizedType);
     units.add(CU_DeclaresInnerGenericType);
@@ -914,8 +925,7 @@
    * @throws NotFoundException
    * @throws IOException
    */
-  public void testRefresh() throws UnableToCompleteException,
-      TypeOracleException {
+  public void testRefresh() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_ExtendsGenericList);
     units.add(CU_GenericList);
@@ -965,8 +975,7 @@
    * @throws UnableToCompleteException
    * @throws IOException
    */
-  public void testRefreshWithErrors() throws UnableToCompleteException,
-      TypeOracleException {
+  public void testRefreshWithErrors() throws TypeOracleException {
     // Add Object
     StringBuffer sb = new StringBuffer();
     sb.append("package java.lang;");
@@ -1042,8 +1051,7 @@
     assertNull(typeOracle.findType("test.refresh.with.errors.GoodClass"));
   }
 
-  public void testSyntaxErrors() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testSyntaxErrors() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_HasSyntaxErrors);
     compileAndRefresh();
@@ -1054,8 +1062,7 @@
     assertEquals("java.lang.Object", types[0].getQualifiedSourceName());
   }
 
-  public void testUnresolvedSymbls() throws TypeOracleException,
-      UnableToCompleteException {
+  public void testUnresolvedSymbls() throws TypeOracleException {
     units.add(CU_Object);
     units.add(CU_HasUnresolvedSymbols);
     units.add(CU_RefsInfectedCompilationUnit);
@@ -1084,8 +1091,7 @@
     }
   }
 
-  private void compileAndRefresh() throws UnableToCompleteException,
-      TypeOracleException {
+  private void compileAndRefresh() throws TypeOracleException {
     TreeLogger logger = createTreeLogger();
     CompilationUnitInvalidator.invalidateUnitsWithInvalidRefs(logger, units);
     JdtCompiler.compile(units);
diff --git a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
index d657d36..48c34b3 100644
--- a/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
+++ b/dev/core/test/com/google/gwt/dev/javac/TypeOracleTestingUtils.java
@@ -16,7 +16,6 @@
 package com.google.gwt.dev.javac;
 
 import com.google.gwt.core.ext.TreeLogger;
-import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.typeinfo.TypeOracle;
 import com.google.gwt.dev.javac.impl.SourceFileCompilationUnit;
 
@@ -31,14 +30,14 @@
 public class TypeOracleTestingUtils {
 
   public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
-      CompilationUnit... extraUnits) throws UnableToCompleteException {
+      CompilationUnit... extraUnits) {
     Set<CompilationUnit> extraUnitSet = new HashSet<CompilationUnit>();
     Collections.addAll(extraUnitSet, extraUnits);
     return buildStandardTypeOracleWith(logger, extraUnitSet);
   }
 
   public static TypeOracle buildStandardTypeOracleWith(TreeLogger logger,
-      Set<CompilationUnit> extraUnits) throws UnableToCompleteException {
+      Set<CompilationUnit> extraUnits) {
     Set<CompilationUnit> unitSet = new HashSet<CompilationUnit>();
     addStandardCups(unitSet);
     for (CompilationUnit extraUnit : extraUnits) {
@@ -48,7 +47,7 @@
   }
 
   public static TypeOracle buildTypeOracle(TreeLogger logger,
-      Set<CompilationUnit> units) throws UnableToCompleteException {
+      Set<CompilationUnit> units) {
     JdtCompiler.compile(units);
     Set<String> validBinaryTypeNames = new HashSet<String>();
     for (CompilationUnit unit : units) {
diff --git a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
index ea2625c..ede0be2 100644
--- a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
@@ -56,7 +56,7 @@
   public static class MockCompilationState extends CompilationState {
 
     public MockCompilationState() {
-      super(new JavaSourceOracle() {
+      super(TreeLogger.NULL, new JavaSourceOracle() {
         public Set<String> getClassNames() {
           return Collections.emptySet();
         }
diff --git a/user/src/com/google/gwt/junit/JUnitShell.java b/user/src/com/google/gwt/junit/JUnitShell.java
index 6587897..cd21132 100644
--- a/user/src/com/google/gwt/junit/JUnitShell.java
+++ b/user/src/com/google/gwt/junit/JUnitShell.java
@@ -173,7 +173,8 @@
     if (foundType != null) {
       return null;
     }
-    Map<String, CompilationUnit> unitMap = currentModule.getCompilationState().getCompilationUnitMap();
+    Map<String, CompilationUnit> unitMap = currentModule.getCompilationState(
+        logger).getCompilationUnitMap();
     CompilationUnit unit = unitMap.get(typeName);
     String errMsg;
     if (unit == null) {