Merging releases/1.6@4147:4198 into trunk.

svn merge --accept postpone -r4147:4198https://google-web-toolkit.googlecode.com/svn/releases/1.6 .



git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@4202 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/ExternalPermutationWorkerFactory.java b/dev/core/src/com/google/gwt/dev/ExternalPermutationWorkerFactory.java
index 392afea..137144d 100644
--- a/dev/core/src/com/google/gwt/dev/ExternalPermutationWorkerFactory.java
+++ b/dev/core/src/com/google/gwt/dev/ExternalPermutationWorkerFactory.java
@@ -342,6 +342,7 @@
     List<PermutationWorker> toReturn = new ArrayList<PermutationWorker>(
         numWorkers);
 
+    // TODO(spoon): clean up already-launched processes if we get an exception?
     for (int i = 0; i < numWorkers; i++) {
       String cookie = launchExternalWorker(logger, sock.getLocalPort());
       cookies.add(cookie);
diff --git a/dev/core/src/com/google/gwt/dev/PermutationWorkerFactory.java b/dev/core/src/com/google/gwt/dev/PermutationWorkerFactory.java
index 4448c3d..0322072 100644
--- a/dev/core/src/com/google/gwt/dev/PermutationWorkerFactory.java
+++ b/dev/core/src/com/google/gwt/dev/PermutationWorkerFactory.java
@@ -17,7 +17,6 @@
 
 import com.google.gwt.core.ext.TreeLogger;
 import com.google.gwt.core.ext.UnableToCompleteException;
-import com.google.gwt.dev.jjs.InternalCompilerException;
 import com.google.gwt.dev.jjs.UnifiedAst;
 import com.google.gwt.dev.util.Util;
 
@@ -26,16 +25,9 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Queue;
-import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
 
 /**
  * Represents a factory for implementations of an endpoint that will invoke
@@ -46,73 +38,167 @@
 public abstract class PermutationWorkerFactory {
 
   /**
-   * This callable is responsible for compiling one permutation. It waits for an
-   * available worker, uses it, and returns it to the pool when finished.
+   * Coordinates the actions of a set of {@link PermutationWorker}s, running
+   * each in its own thread.
    */
-  private static class CompileOnePermutation implements Callable<ResultStatus> {
-    private final BlockingQueue<PermutationWorker> availableWorkers;
-    private final TreeLogger logger;
-    private final Permutation permutation;
-    private final File resultFile;
+  private static class Manager {
 
-    public CompileOnePermutation(TreeLogger logger, Permutation permutation,
-        File resultFile, BlockingQueue<PermutationWorker> availableWorkers) {
-      this.logger = logger;
-      this.permutation = permutation;
-      this.resultFile = resultFile;
-      this.availableWorkers = availableWorkers;
+    private static final Work POISON_PILL = new Work(null, null, null);
+
+    private static enum Result {
+      SUCCESS, FAIL, WORKER_DEATH
     }
 
-    public ResultStatus call() {
-      // Find a free worker
-      PermutationWorker worker;
+    /**
+     * Runs a {@link PermutationWorker} on its own thread.
+     */
+    private class WorkerThread implements Runnable {
+      private final PermutationWorker worker;
+
+      public WorkerThread(PermutationWorker worker) {
+        this.worker = worker;
+      }
+
+      public void run() {
+        Result threadDeathResult = Result.FAIL;
+        try {
+          while (true) {
+            Work work = workQueue.take();
+            if (work == POISON_PILL) {
+              return;
+            }
+            TreeLogger logger = work.getLogger();
+            try {
+              PermutationResult result = worker.compile(logger, work.getPerm());
+              Util.writeObjectAsFile(logger, work.getResultFile(), result);
+              logger.log(TreeLogger.DEBUG, "Successfully compiled permutation");
+              resultsQueue.put(Result.SUCCESS);
+            } catch (TransientWorkerException e) {
+              logger.log(TreeLogger.DEBUG,
+                  "Worker died, will retry Permutation", e);
+              workQueue.add(work);
+              threadDeathResult = Result.WORKER_DEATH;
+              return;
+            } catch (UnableToCompleteException e) {
+              logger.log(TreeLogger.ERROR,
+                  "Unrecoverable exception, shutting down", e);
+              threadDeathResult = Result.FAIL;
+              return;
+            }
+          }
+        } catch (InterruptedException e) {
+          return;
+        } finally {
+          // Record why I died.
+          try {
+            resultsQueue.put(threadDeathResult);
+          } catch (InterruptedException ignored) {
+          }
+        }
+      }
+    }
+
+    public static void run(TreeLogger logger, List<Work> work,
+        List<PermutationWorker> workers) throws UnableToCompleteException {
+      new Manager().doRun(logger, work, workers);
+    }
+
+    /**
+     * The queue of work to do.
+     */
+    BlockingQueue<Work> workQueue;
+
+    /**
+     * The queue of work to do.
+     */
+    BlockingQueue<Result> resultsQueue;
+
+    private Manager() {
+    }
+
+    private void doRun(TreeLogger logger, List<Work> work,
+        List<PermutationWorker> workers) throws UnableToCompleteException {
+
+      // Initialize state.
+      workQueue = new LinkedBlockingQueue<Work>(work);
+      resultsQueue = new LinkedBlockingQueue<Result>();
+
+      List<Thread> threads = new ArrayList<Thread>(workers.size());
       try {
-        worker = availableWorkers.take();
+        for (PermutationWorker worker : workers) {
+          Thread thread = new Thread(new WorkerThread(worker));
+          threads.add(thread);
+          thread.start();
+        }
+
+        int workToDo = work.size();
+        int aliveWorkers = workers.size();
+        waitForWorkers : while (workToDo > 0 && aliveWorkers > 0) {
+          Result take = resultsQueue.take();
+          switch (take) {
+            case SUCCESS:
+              --workToDo;
+              break;
+            case FAIL:
+              break waitForWorkers;
+            case WORKER_DEATH:
+              --aliveWorkers;
+              break;
+            default:
+              throw new IncompatibleClassChangeError(Result.class.toString());
+          }
+        }
+
+        workQueue.clear();
+        for (int i = 0; i < aliveWorkers; ++i) {
+          workQueue.add(POISON_PILL);
+        }
+
+        if (workToDo > 0) {
+          logger.log(TreeLogger.ERROR,
+              "Not all permutation were compiled , completed ("
+                  + (work.size() - workToDo) + "/" + work.size() + ")");
+          throw new UnableToCompleteException();
+        }
       } catch (InterruptedException e) {
-        logger.log(TreeLogger.DEBUG, "Worker interrupted", e);
-        return ResultStatus.HARD_FAILURE;
-      }
-
-      if (worker == noMoreWorkersWorker) {
-        // Shutting down
-        return ResultStatus.HARD_FAILURE;
-      }
-
-      // Invoke the worker
-      try {
-        PermutationResult result = worker.compile(logger, permutation);
-        Util.writeObjectAsFile(logger, resultFile, result);
-        logger.log(TreeLogger.DEBUG, "Successfully compiled permutation");
-        availableWorkers.add(worker);
-        return ResultStatus.SUCCESS;
-      } catch (TransientWorkerException e) {
-        logger.log(TreeLogger.DEBUG, "Worker died, will retry Permutation", e);
-        return ResultStatus.TRANSIENT_FAILURE;
-      } catch (UnableToCompleteException e) {
-        logger.log(TreeLogger.ERROR, "Unrecoverable exception, shutting down",
-            e);
-        return ResultStatus.HARD_FAILURE;
+        logger.log(TreeLogger.ERROR,
+            "Exiting without results due to interruption", e);
+        throw new UnableToCompleteException();
+      } finally {
+        // Interrupt any outstanding threads.
+        for (Thread thread : threads) {
+          thread.interrupt();
+        }
       }
     }
   }
 
-  private static enum ResultStatus {
-    /**
-     * A failure bad enough to merit shutting down the compilation.
-     */
-    HARD_FAILURE,
+  /**
+   * Represents work to do.
+   */
+  private static class Work {
+    private final TreeLogger logger;
+    private final Permutation perm;
+    private final File resultFile;
 
-    /**
-     * A successful compile.
-     */
-    SUCCESS,
+    public Work(TreeLogger logger, Permutation perm, File resultFile) {
+      this.logger = logger;
+      this.perm = perm;
+      this.resultFile = resultFile;
+    }
 
-    /**
-     * A worker died while processing this permutation, but it is worth trying
-     * to compile it with another worker.
-     */
-    TRANSIENT_FAILURE
-  };
+    public TreeLogger getLogger() {
+      return logger;
+    }
+
+    public Permutation getPerm() {
+      return perm;
+    }
+
+    public File getResultFile() {
+      return resultFile;
+    }
+  }
 
   /**
    * The name of the system property used to define the workers.
@@ -128,21 +214,6 @@
 
   private static List<PermutationWorkerFactory> lazyFactories;
 
-  private static final PermutationWorker noMoreWorkersWorker = new PermutationWorker() {
-
-    public PermutationResult compile(TreeLogger logger, Permutation permutation)
-        throws TransientWorkerException, UnableToCompleteException {
-      throw new UnableToCompleteException();
-    }
-
-    public String getName() {
-      return "Marker worker indicating no more workers";
-    }
-
-    public void shutdown() {
-    }
-  };
-
   /**
    * Compiles all Permutations in a Precompilation and returns an array of Files
    * that can be consumed by Link using the system-default
@@ -175,103 +246,35 @@
     assert Arrays.asList(precompilation.getPermutations()).containsAll(
         Arrays.asList(permutations));
 
-    // We may have a mixed collection of workers from different factories
+    // Create the work.
+    List<Work> work = new ArrayList<Work>(permutations.length);
+    for (int i = 0; i < permutations.length; ++i) {
+      Permutation perm = permutations[i];
+      TreeLogger permLogger = logger.branch(TreeLogger.DEBUG,
+          "Worker permutation " + perm.getId() + " of " + permutations.length);
+      work.add(new Work(permLogger, perm, resultFiles[i]));
+    }
+
+    // Create the workers.
     List<PermutationWorker> workers = new ArrayList<PermutationWorker>();
-
-    /*
-     * We can have errors below this point, there's a finally block to handle
-     * cleanup of workers.
-     */
     try {
-      createWorkers(logger, precompilation.getUnifiedAst(),
-          permutations.length, localWorkers, workers);
-      ExecutorService executor = Executors.newFixedThreadPool(workers.size());
+      createWorkers(logger, precompilation.getUnifiedAst(), work.size(),
+          localWorkers, workers);
 
-      // List of available workers.
-      // The extra space is for inserting nulls at shutdown time
-      BlockingQueue<PermutationWorker> availableWorkers = new ArrayBlockingQueue<PermutationWorker>(
-          2 * workers.size());
-      availableWorkers.addAll(workers);
-
-      try {
-
-        // Submit all tasks to the executor
-
-        // The permutation compiles not yet finished
-        Queue<CompileOnePermutation> tasksOutstanding = new LinkedList<CompileOnePermutation>();
-
-        // The futures for the results of those compiles
-        Queue<Future<ResultStatus>> resultFutures = new LinkedList<Future<ResultStatus>>();
-
-        for (int i = 0; i < permutations.length; ++i) {
-          TreeLogger permLogger = logger.branch(TreeLogger.DEBUG,
-              "Worker permutation " + permutations[i].getId() + " of "
-                  + permutations.length);
-          CompileOnePermutation task = new CompileOnePermutation(permLogger,
-              permutations[i], resultFiles[i], availableWorkers);
-          tasksOutstanding.add(task);
-          resultFutures.add(executor.submit(task));
-        }
-
-        // Count the number of dead workers
-        int numDeadWorkers = 0;
-        int successCount = 0;
-
-        while (!resultFutures.isEmpty() && numDeadWorkers < workers.size()) {
-          assert resultFutures.size() == tasksOutstanding.size();
-
-          CompileOnePermutation task = tasksOutstanding.remove();
-          Future<ResultStatus> future = resultFutures.remove();
-          ResultStatus result;
-          try {
-            result = future.get();
-          } catch (InterruptedException e) {
-            logger.log(TreeLogger.ERROR,
-                "Exiting without results due to interruption", e);
-            throw new UnableToCompleteException();
-          } catch (ExecutionException e) {
-            logger.log(TreeLogger.ERROR, "A compilation failed", e);
-            throw new UnableToCompleteException();
-          }
-
-          if (result == ResultStatus.SUCCESS) {
-            ++successCount;
-          } else if (result == ResultStatus.TRANSIENT_FAILURE) {
-            // A worker died. Resubmit for the remaining workers.
-            ++numDeadWorkers;
-            tasksOutstanding.add(task);
-            resultFutures.add(executor.submit(task));
-          } else if (result == ResultStatus.HARD_FAILURE) {
-            // Shut down.
-            break;
-          } else {
-            throw new InternalCompilerException("Unknown result type");
-          }
-        }
-
-        // Too many permutations is a coding error
-        assert successCount <= permutations.length;
-
-        if (successCount < permutations.length) {
-          // Likely as not, all of the workers died
-          logger.log(TreeLogger.ERROR, "Not all permutation were compiled "
-              + successCount + " of " + permutations.length);
-          throw new UnableToCompleteException();
-        }
-      } finally {
-        // Shut down the executor
-        executor.shutdown();
-
-        // Inform any residual CompileOnePermutation's that there aren't any
-        // more workers
-        for (int i = 0; i < workers.size(); i++) {
-          availableWorkers.add(noMoreWorkersWorker);
+      // Get it done!
+      Manager.run(logger, work, workers);
+    } finally {
+      Throwable caught = null;
+      for (PermutationWorker worker : workers) {
+        try {
+          worker.shutdown();
+        } catch (Throwable e) {
+          caught = e;
         }
       }
-    } finally {
-      // Shut down all workers
-      for (PermutationWorker worker : workers) {
-        worker.shutdown();
+      if (caught != null) {
+        throw new RuntimeException(
+            "One of the workers threw an exception while shutting down", caught);
       }
     }
   }
diff --git a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
index 826184d..210995c 100644
--- a/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/CompilationUnit.java
@@ -189,6 +189,12 @@
   public abstract boolean isGenerated();
 
   /**
+   *
+   * @return true if the Compilation Unit is from a super-source.
+   */
+  public abstract boolean isSuperSource();
+
+  /**
    * Overridden to finalize; always returns {@link #getDisplayLocation()}.
    */
   public final String toString() {
diff --git a/dev/core/src/com/google/gwt/dev/javac/JavaSourceFile.java b/dev/core/src/com/google/gwt/dev/javac/JavaSourceFile.java
index c1bf5f7..571b501 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JavaSourceFile.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JavaSourceFile.java
@@ -63,6 +63,11 @@
   }
 
   /**
+   * @return true if the corresponding source comes from super-source.
+   */
+  public abstract boolean isSuperSource();
+
+  /**
    * Returns the Java code contained in this source file. May return
    * <code>null</code> if this {@link JavaSourceFile} has been invalidated by
    * its containing {@link JavaSourceOracle}. This method may be expensive as
@@ -76,4 +81,5 @@
   public final String toString() {
     return getLocation();
   }
+
 }
diff --git a/dev/core/src/com/google/gwt/dev/javac/impl/FileCompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/impl/FileCompilationUnit.java
index d2fee22..568791a 100644
--- a/dev/core/src/com/google/gwt/dev/javac/impl/FileCompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/impl/FileCompilationUnit.java
@@ -63,4 +63,9 @@
   public boolean isGenerated() {
     return false;
   }
+
+  @Override
+  public boolean isSuperSource() {
+    return false;
+  }
 }
\ No newline at end of file
diff --git a/dev/core/src/com/google/gwt/dev/javac/impl/JavaSourceOracleImpl.java b/dev/core/src/com/google/gwt/dev/javac/impl/JavaSourceOracleImpl.java
index 88e2406..e2d7145 100644
--- a/dev/core/src/com/google/gwt/dev/javac/impl/JavaSourceOracleImpl.java
+++ b/dev/core/src/com/google/gwt/dev/javac/impl/JavaSourceOracleImpl.java
@@ -85,6 +85,11 @@
     }
 
     @Override
+    public boolean isSuperSource() {
+      return resource.wasRerooted();
+    }
+
+    @Override
     public String readSource() {
       if (resource != null) {
         InputStream contents = resource.openContents();
diff --git a/dev/core/src/com/google/gwt/dev/javac/impl/SourceFileCompilationUnit.java b/dev/core/src/com/google/gwt/dev/javac/impl/SourceFileCompilationUnit.java
index 7f543af..c3e7c9e 100644
--- a/dev/core/src/com/google/gwt/dev/javac/impl/SourceFileCompilationUnit.java
+++ b/dev/core/src/com/google/gwt/dev/javac/impl/SourceFileCompilationUnit.java
@@ -63,6 +63,11 @@
   }
 
   @Override
+  public boolean isSuperSource() {
+    return sourceFile.isSuperSource();
+  }
+
+  @Override
   protected void dumpSource() {
     sourceCode = null;
   }
diff --git a/dev/core/src/com/google/gwt/dev/resource/Resource.java b/dev/core/src/com/google/gwt/dev/resource/Resource.java
index 6d61cce..0a49ff6 100644
--- a/dev/core/src/com/google/gwt/dev/resource/Resource.java
+++ b/dev/core/src/com/google/gwt/dev/resource/Resource.java
@@ -64,8 +64,8 @@
   }
 
   /**
-   * Returns the contents of the resource. May return <code>null</code> if
-   * this {@link Resource} has been invalidated by its containing
+   * Returns the contents of the resource. May return <code>null</code> if this
+   * {@link Resource} has been invalidated by its containing
    * {@link ResourceOracle}. The caller is responsible for closing the stream.
    */
   public abstract InputStream openContents();
@@ -77,4 +77,7 @@
   public final String toString() {
     return getLocation();
   }
+
+  public abstract boolean wasRerooted();
+
 }
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/FileResource.java b/dev/core/src/com/google/gwt/dev/resource/impl/FileResource.java
index dab8e71..a3183cc 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/FileResource.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/FileResource.java
@@ -94,6 +94,11 @@
     }
   }
 
+  @Override
+  public boolean wasRerooted() {
+    return false;
+  }
+
   private long lastModifiedSeconds(File file) {
     return file.lastModified() / 1000;
   }
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
index 780c965..6097117 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ResourceOracleImpl.java
@@ -123,6 +123,11 @@
     public InputStream openContents() {
       return resource.openContents();
     }
+
+    @Override
+    public boolean wasRerooted() {
+      return true;
+    }
   }
 
   public static ClassPathEntry createEntryForUrl(TreeLogger logger, URL url)
diff --git a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileResource.java b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileResource.java
index 1920e86..3c15743 100644
--- a/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileResource.java
+++ b/dev/core/src/com/google/gwt/dev/resource/impl/ZipFileResource.java
@@ -90,4 +90,9 @@
       return null;
     }
   }
+
+  @Override
+  public boolean wasRerooted() {
+    return false;
+  }
 }
diff --git a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
index 81022e1..4eb38c1 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -51,8 +51,8 @@
 
 /**
  * An isolated {@link ClassLoader} for running all user code. All user files are
- * compiled from source code byte a {@link ByteCodeCompiler}. After
- * compilation, some byte code rewriting is performed to support
+ * compiled from source code byte a {@link ByteCodeCompiler}. After compilation,
+ * some byte code rewriting is performed to support
  * <code>JavaScriptObject</code> and its subtypes.
  * 
  * TODO: we should refactor this class to move the getClassInfoByDispId,
@@ -64,8 +64,8 @@
     DispatchIdOracle {
 
   /**
-   * Oracle that can answer questions about
-   * {@link DispatchClassInfo DispatchClassInfos}.
+   * Oracle that can answer questions about {@link DispatchClassInfo
+   * DispatchClassInfos}.
    */
   private final class DispatchClassInfoOracle {
 
@@ -564,8 +564,8 @@
    * was previously cached and has not been garbage collected.
    * 
    * @param javaObject the Object being wrapped
-   * @return the mapped wrapper, or <code>null</code> if the Java object
-   *         mapped or if the wrapper has been garbage collected
+   * @return the mapped wrapper, or <code>null</code> if the Java object mapped
+   *         or if the wrapper has been garbage collected
    */
   public Object getWrapperForObject(Object javaObject) {
     return weakJavaWrapperCache.get(javaObject);
@@ -705,8 +705,13 @@
         lookupClassName);
     if (compiledClass != null) {
       byte[] classBytes = compiledClass.getBytes();
-      classBytes = emmaStrategy.getEmmaClassBytes(classBytes, lookupClassName,
-          compiledClass.getUnit().getLastModified());
+      if (!compiledClass.getUnit().isSuperSource()) {
+        classBytes = emmaStrategy.getEmmaClassBytes(classBytes,
+            lookupClassName, compiledClass.getUnit().getLastModified());
+      } else {
+        logger.log(TreeLogger.SPAM, "no emma instrumentation for "
+            + lookupClassName + " because it is from super-source");
+      }
       if (classRewriter != null) {
         byte[] newBytes = classRewriter.rewrite(className, classBytes);
         if (CLASS_DUMP) {
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 06ba50e..6433045 100644
--- a/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
+++ b/dev/core/src/com/google/gwt/dev/shell/StandardGeneratorContext.java
@@ -127,6 +127,11 @@
       return file != null;
     }
 
+    @Override
+    public boolean isSuperSource() {
+      return false;
+    }
+
     public void setFile(File file) {
       assert (file.exists() && file.canRead());
       this.file = file;
diff --git a/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java b/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
index 4014c8d..7a0b99b 100644
--- a/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
+++ b/dev/core/test/com/google/gwt/dev/javac/MockCompilationUnit.java
@@ -52,4 +52,9 @@
   public boolean isGenerated() {
     return true;
   }
+
+  @Override
+  public boolean isSuperSource() {
+    return false;
+  }
 }
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaSourceFile.java b/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaSourceFile.java
index 1018edb..c7d0bbb 100644
--- a/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaSourceFile.java
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/MockJavaSourceFile.java
@@ -70,7 +70,13 @@
   }
 
   @Override
+  public boolean isSuperSource() {
+    return false;
+  }
+
+  @Override
   public String readSource() {
     return source;
   }
+
 }
diff --git a/dev/core/test/com/google/gwt/dev/javac/impl/MockResource.java b/dev/core/test/com/google/gwt/dev/javac/impl/MockResource.java
index b35cfda..bcce637 100644
--- a/dev/core/test/com/google/gwt/dev/javac/impl/MockResource.java
+++ b/dev/core/test/com/google/gwt/dev/javac/impl/MockResource.java
@@ -57,5 +57,10 @@
     return new ByteArrayInputStream(Util.getBytes(getContent().toString()));
   }
 
+  @Override
+  public boolean wasRerooted() {
+    return false;
+  }
+
   protected abstract CharSequence getContent();
 }
diff --git a/dev/core/test/com/google/gwt/dev/resource/impl/MockAbstractResource.java b/dev/core/test/com/google/gwt/dev/resource/impl/MockAbstractResource.java
index 992fdcb..afca6d4 100644
--- a/dev/core/test/com/google/gwt/dev/resource/impl/MockAbstractResource.java
+++ b/dev/core/test/com/google/gwt/dev/resource/impl/MockAbstractResource.java
@@ -69,4 +69,9 @@
   public void setStale(boolean isStale) {
     this.isStale = isStale;
   }
+
+  @Override
+  public boolean wasRerooted() {
+    return false;
+  }
 }
\ No newline at end of file
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 ede0be2..3d71400 100644
--- a/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
+++ b/dev/core/test/com/google/gwt/dev/shell/StandardGeneratorContextTest.java
@@ -123,6 +123,12 @@
           public InputStream openContents() {
             return new ByteArrayInputStream(Util.getBytes("w00t!"));
           }
+          
+          @Override
+          public boolean wasRerooted() {
+            return false;
+          }
+          
         };
       }
       return null;
diff --git a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
index b7c87d2..bf21c88 100644
--- a/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
+++ b/tools/api-checker/test/com/google/gwt/tools/apichecker/ApiContainerTest.java
@@ -68,6 +68,11 @@
     public boolean isGenerated() {
       return false;
     }
+
+    @Override
+    public boolean isSuperSource() {
+      return false;
+    }
   }
 
   @SuppressWarnings("unused")
diff --git a/user/src/com/google/gwt/user/client/Event.java b/user/src/com/google/gwt/user/client/Event.java
index 94b3043..f4dccd6 100644
--- a/user/src/com/google/gwt/user/client/Event.java
+++ b/user/src/com/google/gwt/user/client/Event.java
@@ -283,12 +283,8 @@
    * Gets whether the ALT key was depressed when the given event occurred.
    * 
    * @return <code>true</code> if ALT was depressed when the event occurred
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#KEYEVENTS}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public final boolean getAltKey() throws AssertionError {
+  public final boolean getAltKey() {
     return DOM.eventGetAltKey(this);
   }
 
@@ -297,10 +293,8 @@
    * 
    * @return a bit-field, defined by {@link Event#BUTTON_LEFT},
    *         {@link Event#BUTTON_MIDDLE}, and {@link Event#BUTTON_RIGHT}
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#ONMOUSEDOWN} or {@link Event#ONMOUSEUP}
    */
-  public final int getButton() throws AssertionError {
+  public final int getButton() {
     return DOM.eventGetButton(this);
   }
 
@@ -308,12 +302,8 @@
    * Gets the mouse x-position within the browser window's client area.
    * 
    * @return the mouse x-position
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#ONMOUSEWHEEL}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public final int getClientX() throws AssertionError {
+  public final int getClientX() {
     return DOM.eventGetClientX(this);
   }
 
@@ -321,12 +311,8 @@
    * Gets the mouse y-position within the browser window's client area.
    * 
    * @return the mouse y-position
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#ONMOUSEWHEEL}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public final int getClientY() throws AssertionError {
+  public final int getClientY() {
     return DOM.eventGetClientY(this);
   }
 
@@ -334,12 +320,8 @@
    * Gets whether the CTRL key was depressed when the given event occurred.
    * 
    * @return <code>true</code> if CTRL was depressed when the event occurred
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#KEYEVENTS}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public final boolean getCtrlKey() throws AssertionError {
+  public final boolean getCtrlKey() {
     return DOM.eventGetCtrlKey(this);
   }
 
@@ -358,10 +340,8 @@
    * {@link Event#ONMOUSEOVER}).
    * 
    * @return the element from which the mouse pointer was moved
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#ONMOUSEOVER} or {@link Event#ONMOUSEOUT}
    */
-  public final Element getFromElement() throws AssertionError {
+  public final Element getFromElement() {
     return DOM.eventGetFromElement(this);
   }
 
@@ -375,10 +355,9 @@
    * </p>
    * 
    * @return the Unicode character or key code.
-   * @throws AssertionError if event type is not one of {@link Event#KEYEVENTS}
    * @see com.google.gwt.user.client.ui.KeyboardListener
    */
-  public final int getKeyCode() throws AssertionError {
+  public final int getKeyCode() {
     return DOM.eventGetKeyCode(this);
   }
 
@@ -386,12 +365,8 @@
    * Gets whether the META key was depressed when the given event occurred.
    * 
    * @return <code>true</code> if META was depressed when the event occurred
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#KEYEVENTS}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public final boolean getMetaKey() throws AssertionError {
+  public final boolean getMetaKey() {
     return DOM.eventGetMetaKey(this);
   }
 
@@ -408,9 +383,8 @@
    * </p>
    * 
    * @return The velocity of the mouse wheel.
-   * @throws AssertionError if event type is not {@link Event#ONMOUSEWHEEL}
    */
-  public final int getMouseWheelVelocityY() throws AssertionError {
+  public final int getMouseWheelVelocityY() {
     return DOM.eventGetMouseWheelVelocityY(this);
   }
 
@@ -418,9 +392,8 @@
    * Gets the key-repeat state of this event.
    * 
    * @return <code>true</code> if this key event was an auto-repeat
-   * @throws AssertionError if event type is not {@link Event#ONKEYDOWN}
    */
-  public final boolean getRepeat() throws AssertionError {
+  public final boolean getRepeat() {
     return DOM.eventGetRepeat(this);
   }
 
@@ -433,7 +406,7 @@
    *           {@link Event#ONCLICK}, {@link Event#ONDBLCLICK}, or
    *           {@link Event#ONCONTEXTMENU}
    */
-  public final int getScreenX() throws AssertionError {
+  public final int getScreenX() {
     return DOM.eventGetScreenX(this);
   }
 
@@ -441,12 +414,8 @@
    * Gets the mouse y-position on the user's display.
    * 
    * @return the mouse y-position
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONMOUSEWHEEL},
-   *           {@link Event#ONCLICK}, {@link Event#ONDBLCLICK}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public final int getScreenY() throws AssertionError {
+  public final int getScreenY() {
     return DOM.eventGetScreenY(this);
   }
 
@@ -454,12 +423,8 @@
    * Gets whether the shift key was depressed when the given event occurred.
    * 
    * @return <code>true</code> if shift was depressed when the event occurred
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#MOUSEEVENTS}, {@link Event#ONCLICK},
-   *           {@link Event#ONDBLCLICK}, {@link Event#KEYEVENTS}, or
-   *           {@link Event#ONCONTEXTMENU}
    */
-  public final boolean getShiftKey() throws AssertionError {
+  public final boolean getShiftKey() {
     return DOM.eventGetShiftKey(this);
   }
 
@@ -489,10 +454,8 @@
    * {@link Event#ONMOUSEOUT}).
    * 
    * @return the element to which the mouse pointer was moved
-   * @throws AssertionError if event type is not one of
-   *           {@link Event#ONMOUSEOVER} or {@link Event#ONMOUSEOUT}
    */
-  public final Element getToElement() throws AssertionError {
+  public final Element getToElement() {
     return DOM.eventGetToElement(this);
   }
 
diff --git a/user/src/com/google/gwt/user/client/ui/CheckBox.java b/user/src/com/google/gwt/user/client/ui/CheckBox.java
index 1b1a8f3..a9eba4f 100644
--- a/user/src/com/google/gwt/user/client/ui/CheckBox.java
+++ b/user/src/com/google/gwt/user/client/ui/CheckBox.java
@@ -219,6 +219,7 @@
   }
 
   public void setValue(Boolean value, boolean fireEvents) {
+    assert null != value : "Value must not be null";
     if (isChecked() == value) {
       return;
     }
diff --git a/user/src/com/google/gwt/user/client/ui/DialogBox.java b/user/src/com/google/gwt/user/client/ui/DialogBox.java
index 3522241..f4b328e 100644
--- a/user/src/com/google/gwt/user/client/ui/DialogBox.java
+++ b/user/src/com/google/gwt/user/client/ui/DialogBox.java
@@ -204,8 +204,10 @@
 
   @Override
   public void hide() {
-    resizeHandlerRegistration.removeHandler();
-    resizeHandlerRegistration = null;
+    if (resizeHandlerRegistration != null) {
+      resizeHandlerRegistration.removeHandler();
+      resizeHandlerRegistration = null;
+    }
     super.hide();
   }
 
diff --git a/user/src/com/google/gwt/user/client/ui/HasValue.java b/user/src/com/google/gwt/user/client/ui/HasValue.java
index f3240e9..0c7d36f 100644
--- a/user/src/com/google/gwt/user/client/ui/HasValue.java
+++ b/user/src/com/google/gwt/user/client/ui/HasValue.java
@@ -20,6 +20,11 @@
 /**
  * An object that implements this interface should be a user input widget, where
  * the user and programmer can both set and get the object's value.
+ * <p>
+ * It is a requirement that a value passed to {@link setValue} be
+ * {@link Object#equals} to that returned by an immediately succeeding call to
+ * {@link getValue}, or that both be null. Note that this is not a requirement
+ * that <code>setValue(null)</code> be supported by all implementors.
  * 
  * @param <T> the type of value.
  */
@@ -33,8 +38,11 @@
   T getValue();
 
   /**
-   * Sets this object's value without firing any events. Should call setValue(T
-   * value, false).
+   * Sets this object's value without firing any events. This should be
+   * identical to calling setValue(value, false).
+   * <p>
+   * It is acceptable to fail assertions or throw (documented) unchecked
+   * exceptions in response to bad values.
    * 
    * @param value the object's new value
    */
@@ -44,6 +52,9 @@
    * Sets this object's value. Fires
    * {@link com.google.gwt.event.logical.shared.ValueChangeEvent} when
    * fireEvents is true and the new value does not equal the existing value.
+   * <p>
+   * It is acceptable to fail assertions or throw (documented) unchecked
+   * exceptions in response to bad values.
    * 
    * @param value the object's new value
    * @param fireEvents fire events if true and value is new
diff --git a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
index 3a8554e..3f7660a 100644
--- a/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
+++ b/user/src/com/google/gwt/user/client/ui/TextBoxBase.java
@@ -301,6 +301,7 @@
   }
 
   public void setValue(String value, boolean fireEvents) {
+    assert null != value : "Value must not be null";
     String oldValue = getText();
     setText(value);
     if (fireEvents) {
diff --git a/user/super/com/google/gwt/junit/translatable/junit/framework/Assert.java b/user/super/com/google/gwt/junit/translatable/junit/framework/Assert.java
index 0d0d66e..fd3a5e1 100644
--- a/user/super/com/google/gwt/junit/translatable/junit/framework/Assert.java
+++ b/user/super/com/google/gwt/junit/translatable/junit/framework/Assert.java
@@ -51,6 +51,10 @@
     assertEquals("", obj1, obj2);
   }
 
+  public static void assertEquals(short expected, short actual) {
+    assertEquals("", expected, actual);
+  }
+
   public static void assertEquals(String str, boolean obj1, boolean obj2) {
     assertEquals(str, Boolean.valueOf(obj1), Boolean.valueOf(obj2));
   }
@@ -107,6 +111,18 @@
     fail(msg + " expected=" + obj1 + " actual=" + obj2);
   }
 
+  public static void assertEquals(String str, short obj1, short obj2) {
+    assertEquals(str, new Short(obj1), new Short(obj2));
+  }
+
+  public static void assertEquals(String obj1, String obj2) {
+    assertEquals("", obj1, obj2);
+  }
+
+  public static void assertEquals(String message, String expected, String actual) {
+    assertEquals(message, (Object) expected, (Object) actual);
+  }
+
   public static void assertFalse(boolean condition) {
     assertFalse(null, condition);
   }
@@ -181,6 +197,32 @@
     throw new AssertionFailedError(message);
   }
 
+  public static void failNotEquals(String message, Object expected,
+      Object actual) {
+    String formatted = "";
+    if (message != null) {
+      formatted = message + " ";
+    }
+    fail(formatted + "expected :<" + expected + "> was not:<" + actual + ">");
+  }
+
+  public static void failNotSame(String message, Object expected, Object actual) {
+    String formatted = "";
+    if (message != null) {
+      formatted = message + " ";
+    }
+    fail(formatted + "expected same:<" + expected + "> was not:<" + actual
+        + ">");
+  }
+
+  public static void failSame(String message) {
+    String formatted = "";
+    if (message != null) {
+      formatted = message + " ";
+    }
+    fail(formatted + "expected not same");
+  }
+
   /**
    * Utility class, no public constructor needed.
    */