Big refactoring of StandardGeneratorContext so that only one instance is created during a compile.

Many things now share the same StandardGeneratorContext, which allows .finish() calls to be chunked, which is somewhat faster in some cases.  Also, a lot of plumbing gets cleaner because we avoid situations where we had to pass around all the components needed to create a new StandardGeneratorContext on the fly.

Review by: spoon

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5340 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 6736b30..21b5f1e 100644
--- a/dev/core/src/com/google/gwt/dev/Precompile.java
+++ b/dev/core/src/com/google/gwt/dev/Precompile.java
@@ -35,8 +35,8 @@
 import com.google.gwt.dev.jjs.JavaToJavaScriptCompiler;
 import com.google.gwt.dev.jjs.JsOutputOption;
 import com.google.gwt.dev.jjs.UnifiedAst;
-import com.google.gwt.dev.jjs.impl.FragmentLoaderCreator;
 import com.google.gwt.dev.shell.CheckForUpdates;
+import com.google.gwt.dev.shell.StandardGeneratorContext;
 import com.google.gwt.dev.shell.StandardRebindOracle;
 import com.google.gwt.dev.shell.CheckForUpdates.UpdateResult;
 import com.google.gwt.dev.util.Memory;
@@ -255,6 +255,7 @@
   private static class DistillerRebindPermutationOracle implements
       RebindPermutationOracle {
 
+    private StandardGeneratorContext generatorContext;
     private Permutation[] permutations;
     private StaticPropertyOracle[] propertyOracles;
     private RebindOracle[] rebindOracles;
@@ -265,6 +266,8 @@
       permutations = new Permutation[perms.size()];
       propertyOracles = new StaticPropertyOracle[perms.size()];
       rebindOracles = new RebindOracle[perms.size()];
+      generatorContext = new StandardGeneratorContext(compilationState, module,
+          genDir, generatorResourcesDir, generatorArtifacts);
       BindingProperty[] orderedProps = perms.getOrderedProperties();
       SortedSet<ConfigurationProperty> configPropSet = module.getProperties().getConfigurationProperties();
       ConfigurationProperty[] configProps = configPropSet.toArray(new ConfigurationProperty[configPropSet.size()]);
@@ -273,9 +276,8 @@
         String[] orderedPropValues = perms.getOrderedPropertyValues(i);
         propertyOracles[i] = new StaticPropertyOracle(orderedProps,
             orderedPropValues, configProps);
-        rebindOracles[i] = new StandardRebindOracle(compilationState,
-            propertyOracles[i], module, rules, genDir, generatorResourcesDir,
-            generatorArtifacts);
+        rebindOracles[i] = new StandardRebindOracle(propertyOracles[i], rules,
+            generatorContext);
         permutations[i] = new Permutation(i, propertyOracles[i]);
       }
     }
@@ -298,6 +300,10 @@
       return Util.toArray(String.class, answers);
     }
 
+    public StandardGeneratorContext getGeneratorContext() {
+      return generatorContext;
+    }
+
     public int getPermuationCount() {
       return rebindOracles.length;
     }
@@ -420,12 +426,8 @@
           module, compilationState, generatorArtifacts,
           new PropertyPermutations(module.getProperties()), genDir,
           generatorResourcesDir);
-      FragmentLoaderCreator fragmentLoaderCreator = new FragmentLoaderCreator(
-          compilationState, module, genDir, generatorResourcesDir,
-          generatorArtifacts);
-      JavaToJavaScriptCompiler.precompile(logger, module, rpo,
-          fragmentLoaderCreator, declEntryPts, additionalRootTypes, jjsOptions,
-          true);
+      JavaToJavaScriptCompiler.precompile(logger, module, rpo, declEntryPts,
+          additionalRootTypes, jjsOptions, true);
       return true;
     } catch (UnableToCompleteException e) {
       // Already logged.
@@ -459,12 +461,9 @@
           generatedArtifacts,
           new PropertyPermutations(module.getProperties(), firstPerm, numPerms),
           genDir, generatorResourcesDir);
-      FragmentLoaderCreator fragmentLoaderCreator = new FragmentLoaderCreator(
-          compilationState, module, genDir, generatorResourcesDir,
-          generatedArtifacts);
       PerfLogger.start("Precompile");
       UnifiedAst unifiedAst = JavaToJavaScriptCompiler.precompile(logger,
-          module, rpo, fragmentLoaderCreator, declEntryPts, null, jjsOptions,
+          module, rpo, declEntryPts, null, jjsOptions,
           rpo.getPermuationCount() == 1);
       PerfLogger.end();
 
diff --git a/dev/core/src/com/google/gwt/dev/jdt/RebindPermutationOracle.java b/dev/core/src/com/google/gwt/dev/jdt/RebindPermutationOracle.java
index a8b010c..c1c9baf 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/RebindPermutationOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/RebindPermutationOracle.java
@@ -17,6 +17,7 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.shell.StandardGeneratorContext;
 
 /**
  * Abstract the process of determining all of the possible deferred binding
@@ -29,4 +30,9 @@
    */
   String[] getAllPossibleRebindAnswers(TreeLogger logger, String sourceTypeName)
       throws UnableToCompleteException;
+
+  /**
+   * Returns the global StandardGeneratorContext.
+   */
+  StandardGeneratorContext getGeneratorContext();
 }
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 8aca693..e98eaf2 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/WebModeCompilerFrontEnd.java
@@ -37,6 +37,7 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -51,12 +52,10 @@
   public static CompilationUnitDeclaration[] getCompilationUnitDeclarations(
       TreeLogger logger, String[] seedTypeNames,
       CompilationState compilationState,
-      RebindPermutationOracle rebindPermOracle,
-      FragmentLoaderCreator fragmentLoaderCreator)
+      RebindPermutationOracle rebindPermOracle)
       throws UnableToCompleteException {
-    return new WebModeCompilerFrontEnd(compilationState, rebindPermOracle,
-        fragmentLoaderCreator).getCompilationUnitDeclarations(logger,
-        seedTypeNames);
+    return new WebModeCompilerFrontEnd(compilationState, rebindPermOracle).getCompilationUnitDeclarations(
+        logger, seedTypeNames);
   }
 
   private final FragmentLoaderCreator fragmentLoaderCreator;
@@ -69,11 +68,11 @@
    * compiler than WebModeCompilerFrontEnd currently has.
    */
   private WebModeCompilerFrontEnd(CompilationState compilationState,
-      RebindPermutationOracle rebindPermOracle,
-      FragmentLoaderCreator fragmentLoaderCreator) {
+      RebindPermutationOracle rebindPermOracle) {
     super(compilationState, false);
     this.rebindPermOracle = rebindPermOracle;
-    this.fragmentLoaderCreator = fragmentLoaderCreator;
+    this.fragmentLoaderCreator = new FragmentLoaderCreator(
+        rebindPermOracle.getGeneratorContext());
   }
 
   /**
@@ -177,61 +176,18 @@
     FindDeferredBindingSitesVisitor v = new FindDeferredBindingSitesVisitor();
     cud.traverse(v, cud.scope);
     Map<String, MessageSendSite> requestedTypes = v.getSites();
+    Map<String, String[]> rebindAnswers = new HashMap<String, String[]>();
+    boolean doFinish = false;
 
     // For each, ask the host for every possible deferred binding answer.
     for (String reqType : requestedTypes.keySet()) {
       MessageSendSite site = requestedTypes.get(reqType);
-
       try {
         String[] resultTypes = rebindPermOracle.getAllPossibleRebindAnswers(
             logger, reqType);
-        // Check that each result is instantiable.
-        for (int i = 0; i < resultTypes.length; ++i) {
-          String typeName = resultTypes[i];
-
-          // This causes the compiler to find the additional type, possibly
-          // winding its back to ask for the compilation unit from the source
-          // oracle.
-          ReferenceBinding type = resolvePossiblyNestedType(typeName);
-
-          // Sanity check rebind results.
-          if (type == null) {
-            FindDeferredBindingSitesVisitor.reportRebindProblem(site,
-                "Rebind result '" + typeName + "' could not be found");
-            continue;
-          }
-          if (!type.isClass()) {
-            FindDeferredBindingSitesVisitor.reportRebindProblem(site,
-                "Rebind result '" + typeName + "' must be a class");
-            continue;
-          }
-          if (type.isAbstract()) {
-            FindDeferredBindingSitesVisitor.reportRebindProblem(site,
-                "Rebind result '" + typeName + "' cannot be abstract");
-            continue;
-          }
-          if (type.isNestedType() && !type.isStatic()) {
-            FindDeferredBindingSitesVisitor.reportRebindProblem(site,
-                "Rebind result '" + typeName
-                    + "' cannot be a non-static nested class");
-            continue;
-          }
-          if (type.isLocalType()) {
-            FindDeferredBindingSitesVisitor.reportRebindProblem(site,
-                "Rebind result '" + typeName + "' cannot be a local class");
-            continue;
-          }
-          // Look for a noArg ctor.
-          MethodBinding noArgCtor = type.getExactConstructor(TypeBinding.NO_PARAMETERS);
-          if (noArgCtor == null) {
-            FindDeferredBindingSitesVisitor.reportRebindProblem(site,
-                "Rebind result '" + typeName
-                    + "' has no default (zero argument) constructors");
-            continue;
-          }
-          dependentTypeNames.add(typeName);
-        }
+        rebindAnswers.put(reqType, resultTypes);
         Collections.addAll(dependentTypeNames, resultTypes);
+        doFinish = true;
       } catch (UnableToCompleteException e) {
         FindDeferredBindingSitesVisitor.reportRebindProblem(site,
             "Failed to resolve '" + reqType + "' via deferred binding");
@@ -247,20 +203,83 @@
      * between loaders and runAsync sites will be made in ReplaceRunAsyncs.
      */
     for (MessageSendSite site : v.getRunAsyncSites()) {
-      FragmentLoaderCreator loaderCreator = fragmentLoaderCreator;
       String resultType;
       try {
-        resultType = loaderCreator.create(logger);
+        resultType = fragmentLoaderCreator.create(logger);
         dependentTypeNames.add(resultType);
+        doFinish = true;
       } catch (UnableToCompleteException e) {
         FindDeferredBindingSitesVisitor.reportRebindProblem(site,
             "Failed to create a runAsync fragment loader");
       }
     }
 
+    if (doFinish) {
+      try {
+        rebindPermOracle.getGeneratorContext().finish(logger);
+      } catch (UnableToCompleteException e) {
+        throw new RuntimeException("Unable to commit generated files", e);
+      }
+    }
+
+    // Sanity check all rebind answers.
+    for (String reqType : requestedTypes.keySet()) {
+      MessageSendSite site = requestedTypes.get(reqType);
+      String[] resultTypes = rebindAnswers.get(reqType);
+      // Check that each result is instantiable.
+      for (String typeName : resultTypes) {
+        checkRebindResultInstantiable(site, typeName);
+      }
+    }
+
     return dependentTypeNames.toArray(Empty.STRINGS);
   }
 
+  private void checkRebindResultInstantiable(MessageSendSite site,
+      String typeName) {
+    /*
+     * This causes the compiler to find the additional type, possibly winding
+     * its back to ask for the compilation unit from the source oracle.
+     */
+    ReferenceBinding type = resolvePossiblyNestedType(typeName);
+
+    // Sanity check rebind results.
+    if (type == null) {
+      FindDeferredBindingSitesVisitor.reportRebindProblem(site,
+          "Rebind result '" + typeName + "' could not be found");
+      return;
+    }
+    if (!type.isClass()) {
+      FindDeferredBindingSitesVisitor.reportRebindProblem(site,
+          "Rebind result '" + typeName + "' must be a class");
+      return;
+    }
+    if (type.isAbstract()) {
+      FindDeferredBindingSitesVisitor.reportRebindProblem(site,
+          "Rebind result '" + typeName + "' cannot be abstract");
+      return;
+    }
+    if (type.isNestedType() && !type.isStatic()) {
+      FindDeferredBindingSitesVisitor.reportRebindProblem(site,
+          "Rebind result '" + typeName
+              + "' cannot be a non-static nested class");
+      return;
+    }
+    if (type.isLocalType()) {
+      FindDeferredBindingSitesVisitor.reportRebindProblem(site,
+          "Rebind result '" + typeName + "' cannot be a local class");
+      return;
+    }
+    // Look for a noArg ctor.
+    MethodBinding noArgCtor = type.getExactConstructor(TypeBinding.NO_PARAMETERS);
+    if (noArgCtor == null) {
+      FindDeferredBindingSitesVisitor.reportRebindProblem(site,
+          "Rebind result '" + typeName
+              + "' has no default (zero argument) constructors");
+      return;
+    }
+  }
+
   /**
    * Get the CompilationUnit for a named type or throw an
    * UnableToCompleteException.
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 b35872b..e8347c4 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
@@ -339,7 +339,6 @@
    * @param logger the logger to use
    * @param module the module to compile
    * @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
@@ -352,8 +351,8 @@
    *           {@link OutOfMemoryError} occurs
    */
   public static UnifiedAst precompile(TreeLogger logger, ModuleDef module,
-      RebindPermutationOracle rpo, FragmentLoaderCreator fragmentLoaderCreator,
-      String[] declEntryPts, String[] additionalRootTypes, JJSOptions options,
+      RebindPermutationOracle rpo, String[] declEntryPts,
+      String[] additionalRootTypes, JJSOptions options,
       boolean singlePermutation) throws UnableToCompleteException {
 
     if (additionalRootTypes == null) {
@@ -381,7 +380,7 @@
     //
     CompilationUnitDeclaration[] goldenCuds = WebModeCompilerFrontEnd.getCompilationUnitDeclarations(
         logger, allRootTypes.toArray(new String[0]),
-        module.getCompilationState(logger), rpo, fragmentLoaderCreator);
+        module.getCompilationState(logger), rpo);
 
     // Free up memory.
     if (!options.isCompilationStateRetained()) {
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
index a650e28..85b74c1 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
@@ -19,16 +19,12 @@
 import com.google.gwt.core.ext.PropertyOracle;
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.core.ext.linker.ArtifactSet;
 import com.google.gwt.dev.cfg.BindingProperty;
 import com.google.gwt.dev.cfg.ConfigurationProperty;
-import com.google.gwt.dev.cfg.PublicOracle;
 import com.google.gwt.dev.cfg.StaticPropertyOracle;
-import com.google.gwt.dev.javac.CompilationState;
 import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor;
 import com.google.gwt.dev.shell.StandardGeneratorContext;
 
-import java.io.File;
 import java.io.PrintWriter;
 import java.util.List;
 
@@ -51,31 +47,26 @@
   private static final String UNCAUGHT_EXCEPTION_HANDLER_CLASS = GWT_CLASS
       + ".UncaughtExceptionHandler";
 
-  private final ArtifactSet artifactSet;
-  private final CompilationState compilationState;
-  private int entryNumber;
-  private final File genDir;
-  private final File outDir;
-  private final PublicOracle publicOracle;
+  private final StandardGeneratorContext context;
+  private int entryNumber = 0;
+  private final PropertyOracle propOracle;
 
   /**
    * Construct a FragmentLoaderCreator. The reason it needs so many parameters
    * is that it uses generator infrastructure.
    */
-  public FragmentLoaderCreator(CompilationState compilationState,
-      PublicOracle publicOracle, File genDir, File moduleOutDir,
-      ArtifactSet artifactSet) {
-    this.compilationState = compilationState;
-    this.publicOracle = publicOracle;
-    this.genDir = genDir;
-    this.outDir = moduleOutDir;
-    this.artifactSet = artifactSet;
+  public FragmentLoaderCreator(StandardGeneratorContext context) {
+    // An empty property oracle is fine, because fragment loaders aren't
+    // affected by properties anyway
+    this.propOracle = new StaticPropertyOracle(new BindingProperty[0],
+        new String[0], new ConfigurationProperty[0]);
+    this.context = context;
   }
 
   public String create(TreeLogger logger) throws UnableToCompleteException {
-    chooseEntryNumber();
-    StandardGeneratorContext context = makeGeneratorContext();
-
+    // First entry is 1.
+    ++entryNumber;
+    context.setPropertyOracle(propOracle);
     PrintWriter loaderWriter = getSourceWriterForLoader(logger, context);
     if (loaderWriter == null) {
       logger.log(TreeLogger.ERROR, "Failed to create island loader named "
@@ -97,22 +88,9 @@
     writeCallbackListClass(logger, context);
     writeLoaderSuperclass(logger, context);
 
-    context.finish(logger);
-
     return getLoaderQualifiedName();
   }
 
-  /**
-   * Pick the lowest-numbered entry number that has not yet had loaders
-   * generated.
-   */
-  private void chooseEntryNumber() {
-    entryNumber = 1;
-    while (compilationState.getTypeOracle().findType(getLoaderQualifiedName()) != null) {
-      entryNumber++;
-    }
-  }
-
   private void generateLoaderFields(PrintWriter srcWriter) {
     srcWriter.println("// Whether the code for this entry point has loaded");
     srcWriter.println("private static boolean loaded = false;");
@@ -212,7 +190,8 @@
         + FindDeferredBindingSitesVisitor.MAGIC_CLASS
         + ".getUncaughtExceptionHandler();");
 
-    srcWriter.println("  " + getCallbackListSimpleName() + " next = callbacksHead;");
+    srcWriter.println("  " + getCallbackListSimpleName()
+        + " next = callbacksHead;");
     srcWriter.println("  callbacksHead = callbacksHead.next;");
     srcWriter.println("  if (callbacksHead == null) {");
     srcWriter.println("    callbacksTail = null;");
@@ -286,16 +265,6 @@
     return printWriter;
   }
 
-  private StandardGeneratorContext makeGeneratorContext() {
-    // An empty property oracle is fine, because fragment loaders aren't
-    // affected by properties anyway
-    PropertyOracle propOracle = new StaticPropertyOracle(
-        new BindingProperty[0], new String[0], new ConfigurationProperty[0]);
-    StandardGeneratorContext context = new StandardGeneratorContext(
-        compilationState, propOracle, publicOracle, genDir, outDir, artifactSet);
-    return context;
-  }
-
   private void writeCallbackListClass(TreeLogger logger, GeneratorContext ctx)
       throws UnableToCompleteException {
     PrintWriter printWriter = ctx.tryCreate(logger, getPackage(),
@@ -318,10 +287,10 @@
 
   /**
    * Create a stand-in superclass of the actual loader. This is used to keep the
-   * liveness analyzer from thinking the real <code>runCallbacks()</code> method
-   * is available until <code>onLoad</code> has been called and the real loader
-   * instantiated. A little work on TypeTightener could prevent the need for
-   * this class.
+   * liveness analyzer from thinking the real <code>runCallbacks()</code>
+   * method is available until <code>onLoad</code> has been called and the
+   * real loader instantiated. A little work on TypeTightener could prevent the
+   * need for this class.
    */
   private void writeLoaderSuperclass(TreeLogger logger, GeneratorContext ctx)
       throws UnableToCompleteException {
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 0a526c3..04d6967 100644
--- a/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
+++ b/dev/core/src/com/google/gwt/dev/shell/ShellModuleSpaceHost.java
@@ -90,8 +90,10 @@
     // It has to wait until now because we need to inject javascript.
     //
     Rules rules = module.getRules();
-    rebindOracle = new StandardRebindOracle(module.getCompilationState(logger),
-        propOracle, module, rules, genDir, shellDir, new ArtifactSet());
+    StandardGeneratorContext genCtx = new StandardGeneratorContext(
+        module.getCompilationState(logger), module, genDir, shellDir,
+        new ArtifactSet());
+    rebindOracle = new StandardRebindOracle(propOracle, rules, genCtx);
 
     // Create a completely isolated class loader which owns all classes
     // associated with a particular module. This effectively builds a
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 ec88f90..5309c38 100644
--- a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
+++ b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
@@ -263,7 +263,7 @@
 
   private final Map<OutputStream, PendingResource> pendingResourcesByOutputStream = new IdentityHashMap<OutputStream, PendingResource>();
 
-  private final PropertyOracle propOracle;
+  private transient PropertyOracle propOracle;
 
   private final PublicOracle publicOracle;
 
@@ -274,10 +274,9 @@
    * available in the supplied type oracle although it isn't strictly required.
    */
   public StandardGeneratorContext(CompilationState compilationState,
-      PropertyOracle propOracle, PublicOracle publicOracle, File genDir,
-      File generatorResourcesDir, ArtifactSet allGeneratedArtifacts) {
+      PublicOracle publicOracle, File genDir, File generatorResourcesDir,
+      ArtifactSet allGeneratedArtifacts) {
     this.compilationState = compilationState;
-    this.propOracle = propOracle;
     this.publicOracle = publicOracle;
     this.genDir = genDir;
     this.generatorResourcesDir = generatorResourcesDir;
@@ -425,6 +424,14 @@
     this.currentGenerator = currentGenerator;
   }
 
+  /**
+   * Sets the current transient property oracle to answer current property
+   * questions.
+   */
+  public void setPropertyOracle(PropertyOracle propOracle) {
+    this.propOracle = propOracle;
+  }
+
   public final PrintWriter tryCreate(TreeLogger logger, String packageName,
       String simpleTypeName) {
     String typeName;
@@ -442,12 +449,8 @@
       return null;
     }
 
-    // Has anybody tried to create this type during this iteration?
+    // Type recently generated?
     if (newlyGeneratedTypeNames.contains(typeName)) {
-      final String msg = "A request to create type '"
-          + typeName
-          + "' was received while the type itself was being created; this might be a generator or configuration bug";
-      logger.log(TreeLogger.WARN, msg, null);
       return null;
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
index 3d27016..d466458 100644
--- a/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
+++ b/dev/core/src/com/google/gwt/dev/shell/StandardRebindOracle.java
@@ -19,14 +19,11 @@
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
 import com.google.gwt.core.ext.linker.ArtifactSet;
-import com.google.gwt.dev.cfg.PublicOracle;
 import com.google.gwt.dev.cfg.Rule;
 import com.google.gwt.dev.cfg.Rules;
-import com.google.gwt.dev.javac.CompilationState;
 import com.google.gwt.dev.jdt.RebindOracle;
 import com.google.gwt.dev.util.Util;
 
-import java.io.File;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -45,24 +42,21 @@
    */
   private final class Rebinder {
 
-    private final StandardGeneratorContext genCtx;
-
     private final Set<Rule> usedRules = new HashSet<Rule>();
 
     private final List<String> usedTypeNames = new ArrayList<String>();
 
-    public Rebinder() {
-      genCtx = new StandardGeneratorContext(compilationState, propOracle,
-          publicOracle, genDir, generatorResourcesDir, allGeneratedArtifacts);
-    }
-
     public String rebind(TreeLogger logger, String typeName,
         ArtifactAcceptor artifactAcceptor) throws UnableToCompleteException {
 
+      genCtx.setPropertyOracle(propOracle);
       String result = tryRebind(logger, typeName);
-      ArtifactSet newlyGeneratedArtifacts = genCtx.finish(logger);
-      if (!newlyGeneratedArtifacts.isEmpty() && artifactAcceptor != null) {
-        artifactAcceptor.accept(logger, newlyGeneratedArtifacts);
+      if (artifactAcceptor != null) {
+        // Go ahead and call finish() to accept new artifacts.
+        ArtifactSet newlyGeneratedArtifacts = genCtx.finish(logger);
+        if (!newlyGeneratedArtifacts.isEmpty()) {
+          artifactAcceptor.accept(logger, newlyGeneratedArtifacts);
+        }
       }
       if (result == null) {
         result = typeName;
@@ -128,32 +122,19 @@
     }
   }
 
-  private final ArtifactSet allGeneratedArtifacts;
-
   private final Map<String, String> cache = new HashMap<String, String>();
 
-  private final CompilationState compilationState;
-
-  private final File genDir;
-
-  private final File generatorResourcesDir;
+  private final StandardGeneratorContext genCtx;
 
   private final PropertyOracle propOracle;
 
-  private final PublicOracle publicOracle;
-
   private final Rules rules;
 
-  public StandardRebindOracle(CompilationState compilationState,
-      PropertyOracle propOracle, PublicOracle publicOracle, Rules rules,
-      File genDir, File generatorResourcesDir, ArtifactSet allGeneratedArtifacts) {
-    this.compilationState = compilationState;
+  public StandardRebindOracle(PropertyOracle propOracle, Rules rules,
+      StandardGeneratorContext genCtx) {
     this.propOracle = propOracle;
-    this.publicOracle = publicOracle;
     this.rules = rules;
-    this.genDir = genDir;
-    this.generatorResourcesDir = generatorResourcesDir;
-    this.allGeneratedArtifacts = allGeneratedArtifacts;
+    this.genCtx = genCtx;
   }
 
   public String rebind(TreeLogger logger, String typeName)
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 05fc32a..18d7685 100644
--- a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
@@ -154,8 +154,9 @@
   public StandardGeneratorContextTest() {
     tempGenDir = createTempDir("gwt-gen-");
     tempOutDir = createTempDir("gwt-out-");
-    genCtx = new StandardGeneratorContext(mockCompilationState, mockPropOracle,
+    genCtx = new StandardGeneratorContext(mockCompilationState,
         mockPublicOracle, tempGenDir, tempOutDir, artifactSet);
+    genCtx.setPropertyOracle(mockPropOracle);
     genCtx.setCurrentGenerator(Generator.class);
   }