Merge through trunk@6239



git-svn-id: https://google-web-toolkit.googlecode.com/svn/branches/farewellSwt@6253 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/branch-info.txt b/branch-info.txt
index 3e01cb9..8ba9e9b 100644
--- a/branch-info.txt
+++ b/branch-info.txt
@@ -11,3 +11,5 @@
 svn merge --ignore-ancestry -r6142:6200 \
     https://google-web-toolkit.googlecode.com/svn/trunk
     (via changes/jat/noswt-merge6200)
+svn merge https://google-web-toolkit.googlecode.com/svn/trunk \
+  -r6200:6239 .
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
index 81f5e9f..1310630 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
@@ -448,7 +448,6 @@
             }
           }
         }
-        jsoSubType.clearImplements();
       }
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
index 3535af3..0760216 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java
@@ -58,7 +58,8 @@
     public void endVisit(JCastOperation x, Context ctx) {
       JType newType = translate(x.getCastType());
       if (newType != x.getCastType()) {
-        ctx.replaceMe(new JCastOperation(x.getSourceInfo(), newType, x.getExpr()));
+        ctx.replaceMe(new JCastOperation(x.getSourceInfo(), newType,
+            x.getExpr()));
       }
     }
 
@@ -135,8 +136,8 @@
           CloneExpressionVisitor cloner = new CloneExpressionVisitor(program);
 
           // instance.jsoMethod(arg, arg)
-          JMethodCall jsoCall = new JMethodCall(info, cloner.cloneExpression(instance),
-              jsoMethod);
+          JMethodCall jsoCall = new JMethodCall(info,
+              cloner.cloneExpression(instance), jsoMethod);
           jsoCall.addArgs(cloner.cloneExpressions(x.getArgs()));
 
           // Cast.isJavaScriptObject() ? instance.jsoMethod() :
@@ -152,7 +153,8 @@
            * ... otherwise, if there's only a JSO implementation, we'll just
            * call that directly.
            */
-          JMethodCall jsoCall = new JMethodCall(info, x.getInstance(), jsoMethod);
+          JMethodCall jsoCall = new JMethodCall(info, x.getInstance(),
+              jsoMethod);
           jsoCall.addArgs(x.getArgs());
           ctx.replaceMe(jsoCall);
         }
@@ -177,13 +179,21 @@
 
     private JMethod findConcreteImplementation(JMethod method,
         JClassType concreteType) {
-      for (JMethod m : concreteType.getMethods()) {
-        if (program.typeOracle.getAllOverrides(m).contains(method)) {
-          if (!m.isAbstract()) {
-            return m;
+      /*
+       * Search supertypes for virtual overrides via subclass. See the javadoc
+       * on JTypeOracle.getAllVirtualOverrides for an example.
+       */
+      while (concreteType != null) {
+        for (JMethod m : concreteType.getMethods()) {
+          if (program.typeOracle.getAllOverrides(m).contains(method)) {
+            if (!m.isAbstract()) {
+              return m;
+            }
           }
         }
+        concreteType = concreteType.getSuperClass();
       }
+
       return null;
     }
 
@@ -205,7 +215,8 @@
         JExpression notJsoExpr) {
       // Cast.isJavaScriptObjectOrString(instance)
       JMethod isJavaScriptObjectMethod = program.getIndexedMethod("Cast.isJavaScriptObjectOrString");
-      JMethodCall isJavaScriptObjectExpr = new JMethodCall(info, null, isJavaScriptObjectMethod);
+      JMethodCall isJavaScriptObjectExpr = new JMethodCall(info, null,
+          isJavaScriptObjectMethod);
       isJavaScriptObjectExpr.addArg(instance);
       return new JConditional(info, conditionalType, isJavaScriptObjectExpr,
           isJsoExpr, notJsoExpr);
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 0815fad..14f1a4c 100644
--- a/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
+++ b/dev/core/src/com/google/gwt/dev/shell/CompilingClassLoader.java
@@ -36,9 +36,9 @@
 import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter;
 import com.google.gwt.dev.shell.rewrite.HostedModeClassRewriter.InstanceMethodOracle;
 import com.google.gwt.dev.util.JsniRef;
-import com.google.gwt.dev.util.Name.SourceOrBinaryName;
-import com.google.gwt.dev.util.Name.InternalName;
 import com.google.gwt.dev.util.Util;
+import com.google.gwt.dev.util.Name.InternalName;
+import com.google.gwt.dev.util.Name.SourceOrBinaryName;
 import com.google.gwt.util.tools.Utility;
 
 import org.apache.commons.collections.map.AbstractReferenceMap;
@@ -911,6 +911,21 @@
         String mangledName = getBinaryName(type).replace('.', '_') + "_"
             + m.getName();
 
+        JType[] parameterTypes = new JType[m.getParameters().length];
+        for (int i = 0; i < parameterTypes.length; i++) {
+          parameterTypes[i] = m.getParameters()[i].getType();
+        }
+
+        /*
+         * Handle virtual overrides by finding the method that we would normally
+         * invoke and using its declaring class as the dispatch target.
+         */
+        while (implementingType.findMethod(m.getName(), parameterTypes) == null) {
+          implementingType = implementingType.getSuperclass();
+        }
+        assert implementingType != null : "Unable to find virtual override for "
+            + m.toString();
+
         /*
          * Cook up the a pseudo-method declaration for the concrete type. This
          * should look something like
@@ -921,9 +936,9 @@
          */
         String decl = getBinaryOrPrimitiveName(m.getReturnType()) + " "
             + m.getName() + "$ (" + getBinaryOrPrimitiveName(implementingType);
-        for (JParameter p : m.getParameters()) {
+        for (JType paramType : parameterTypes) {
           decl += ",";
-          decl += getBinaryOrPrimitiveName(p.getType());
+          decl += getBinaryOrPrimitiveName(paramType);
         }
         decl += ")";
 
diff --git a/distro-source/core/src/release_notes.html b/distro-source/core/src/release_notes.html
index a765f4c..ba04040 100644
--- a/distro-source/core/src/release_notes.html
+++ b/distro-source/core/src/release_notes.html
@@ -28,28 +28,86 @@
    <body>
       <h1>Google Web Toolkit Release Notes</h1>
       <ul>
-		    <li><a href="#Release_Notes_Current">@GWT_VERSION@</a></li>
+        <li><a href="#Release_Notes_Current">@GWT_VERSION@</a></li>
+        <li><a href="#Release_Notes_1_7_0">1.7.0</a></li>
+        <li><a href="#Release_Notes_1_6_4">1.6.4</a></li>
         <li><a href="#Release_Notes_1_6_3">1.6.3</a></li>
-		    <li><a href="#Release_Notes_1_6_2">1.6.2</a></li>
-		    <li><a href="#Release_Notes_1_5_3">1.5.3</a></li>
-		    <li><a href="#Release_Notes_1_5_2">1.5.2</a></li>
-		    <li><a href="#Release_Notes_1_5_1">1.5.1 (RC2)</a></li>
-		    <li><a href="#Release_Notes_1_5_0">1.5.0 (RC)</a></li>
-		    <li><a href="#Release_Notes_1_4_60">1.4.60</a></li>
-		    <li><a href="#Release_Notes_1_4_59">1.4.59 (RC2)</a></li>
-		    <li><a href="#Release_Notes_1_4_10">1.4.10 (RC)</a></li>
-		    <li><a href="#Release_Notes_1_3_3">1.3.3</a></li>
-		    <li><a href="#Release_Notes_1_3_1">1.3.1 (RC)</a></li>
-		    <li><a href="#Release_Notes_1_2_22">1.2.22</a></li>
-		    <li><a href="#Release_Notes_1_2_11">1.2.21 (RC)</a></li>
-		    <li><a href="#Release_Notes_1_1_10">1.1.10</a></li>
-		    <li><a href="#Release_Notes_1_1_0">1.1.0 (RC)</a></li>
-		    <li><a href="#Release_Notes_1_0_21">1.0.21</a></li>
+        <li><a href="#Release_Notes_1_6_2">1.6.2</a></li>
+        <li><a href="#Release_Notes_1_5_3">1.5.3</a></li>
+        <li><a href="#Release_Notes_1_5_2">1.5.2</a></li>
+        <li><a href="#Release_Notes_1_5_1">1.5.1 (RC2)</a></li>
+        <li><a href="#Release_Notes_1_5_0">1.5.0 (RC)</a></li>
+        <li><a href="#Release_Notes_1_4_60">1.4.60</a></li>
+        <li><a href="#Release_Notes_1_4_59">1.4.59 (RC2)</a></li>
+        <li><a href="#Release_Notes_1_4_10">1.4.10 (RC)</a></li>
+        <li><a href="#Release_Notes_1_3_3">1.3.3</a></li>
+        <li><a href="#Release_Notes_1_3_1">1.3.1 (RC)</a></li>
+        <li><a href="#Release_Notes_1_2_22">1.2.22</a></li>
+        <li><a href="#Release_Notes_1_2_11">1.2.21 (RC)</a></li>
+        <li><a href="#Release_Notes_1_1_10">1.1.10</a></li>
+        <li><a href="#Release_Notes_1_1_0">1.1.0 (RC)</a></li>
+        <li><a href="#Release_Notes_1_0_21">1.0.21</a></li>
       </ul>
 
       <hr/>
       <a name="Release_Notes_Current"></a>
       <h2>Release Notes for @GWT_VERSION@</h2>
+      <p>
+        This release adds support for Mac OS X version 10.6 (Snow Leopard) by allowing hosted mode to run with a 1.6 JRE in 32-bit
+        mode (using the -d32 flag).
+      </p>
+      <h3>Fixed Issues</h3>
+      <ul>
+        <li>
+          Allow hosted mode using a 1.6 JRE with the -d32 flag
+          (<a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3843">#3843</a>, 
+          <a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3998">#3998</a>)
+        </li>
+      </ul>
+
+      <hr/>
+      <a name="Release_Notes_1_7_0"></a>
+      <h2>Release Notes for 1.7.0</h2>
+      <p>
+        This release adds explicit support for Internet Explorer 8, Firefox 3.5, and Safari 4 as well as a few high-priority bug fixes.
+        In all other respects, it is very similar to GWT 1.6.
+        Note, however, that this release is version 1.7.0 rather than version 1.6.5 to signify a potentially breaking change for libraries 
+        that use deferred binding to specialize code based on user agent (see the next section for technical details).
+      </p>
+      <h3>Potentially breaking changes and fixes</h3>
+      <ul>
+        <li>
+          This release includes explicit support for IE8, which has some significant behavioral changes from prior versions of IE.
+          These changes are great enough that the new value <code>ie8</code> has been added for the <code>user.agent</code> deferred binding client property.
+          If you have deferred binding rules (i.e. <code>&lt;replace-with&gt;</code> or <code>&lt;generate-with&gt;</code>) or property providers 
+          that are sensitive to <code>user.agent</code>, you may need to update them to account for the <code>ie8</code> value. 
+          For more information, see the <a href="http://code.google.com/p/google-web-toolkit/wiki/IE8Support">technical notes</a>.
+        </li>
+      </ul>
+
+      <h3>Fixed Issues</h3>
+      <ul>
+        <li>
+          Updated GWT libraries to support IE8 
+          (<a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3558">#3558</a>, 
+          <a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3329">#3329</a>)
+        </li>
+        <li>Native exception in Node.is() (<a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3644">#3644</a>)</li>
+        <li>
+          Incorrect firing of two click events from CheckBox and a related issue 
+          (<a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3508">#3508</a>,  
+          <a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3679">#3679</a>)
+        </li>
+        <li>Compiler java.lang.StackOverflowError if you don't use -Xss to set a stack size (<a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3510">#3510</a>)</li>
+        <li>Mouse wheel in FF3 (<a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=2902">#2902</a>)</li>
+        <li>GWT outputs expressions too long for WebKit (<a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3455">#3455</a>)</li>
+        <li>java.sql.Date.valueOf error (<a href="http://code.google.com/p/google-web-toolkit/issues/detail?id=3731">#3731</a>)</li>
+        <li>Added a workaround for Firefox 3.5 regression (<a href="https://bugzilla.mozilla.org/show_bug.cgi?id=497780">bugzilla #497780</a>)</li>
+      </ul>
+
+      <hr/>
+      <a name="Release_Notes_1_6_4"></a>
+      <h2>Release Notes for 1.6.4</h2>
       <h3>Fixed Issues</h3>
       <ul>
         <li>The classpath in the scripts created by junitCreator was updated to refer to <code>/war/WEB-INF/classes</code> rather than <code>/bin</code>.</li>
diff --git a/user/src/com/google/gwt/junit/JUnitMessageQueue.java b/user/src/com/google/gwt/junit/JUnitMessageQueue.java
index 57ccd4a..c5a2d10 100644
--- a/user/src/com/google/gwt/junit/JUnitMessageQueue.java
+++ b/user/src/com/google/gwt/junit/JUnitMessageQueue.java
@@ -306,7 +306,7 @@
           buf.append('\n');
         }
 
-        if (!results.containsKey(clientStatus.clientId)) {
+        if (results == null || !results.containsKey(clientStatus.clientId)) {
           buf.append(" - NO RESPONSE: ");
         } else {
           buf.append(" - (ok): ");
diff --git a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
index 8295ad6..adbf29c 100644
--- a/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
+++ b/user/src/com/google/gwt/resources/rg/CssResourceGenerator.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- *
+ * 
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ * 
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ * 
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -97,7 +97,6 @@
 import java.util.SortedSet;
 import java.util.TreeSet;
 import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 import java.util.zip.Adler32;
 
 /**
@@ -105,21 +104,59 @@
  */
 public final class CssResourceGenerator extends AbstractResourceGenerator {
   static class ClassRenamer extends CssVisitor {
-    private final Map<JMethod, String> actualReplacements = new IdentityHashMap<JMethod, String>();
 
     /**
-     * This is a map of local prefixes to the obfuscated names of imported
-     * methods. If a CssResource makes use of the {@link Import} annotation, the
-     * keys of this map will correspond to the {@link ImportedWithPrefix} value
-     * defined on the imported CssResource. The zero-length string key holds the
-     * obfuscated names for the CssResource that is being generated.
+     * A tag to indicate that an externally-defined CSS class has no JMethod
+     * that is used to access it.
      */
-    private final Map<String, Map<JMethod, String>> classReplacementsWithPrefix;
+    private static final Replacement UNREFERENCED_EXTERNAL = new Replacement(
+        null, null);
+
+    /*
+     * TODO: Replace with Pair<A, B>.
+     */
+    private static class Replacement {
+
+      private JMethod method;
+      private String obfuscatedClassName;
+
+      public Replacement(JMethod method, String obfuscatedClassName) {
+        this.method = method;
+        this.obfuscatedClassName = obfuscatedClassName;
+      }
+
+      public JMethod getMethod() {
+        return method;
+      }
+
+      public String getObfuscatedClassName() {
+        return obfuscatedClassName;
+      }
+
+      /**
+       * For debugging use only.
+       */
+      public String toString() {
+        if (this == UNREFERENCED_EXTERNAL) {
+          return "Unreferenced external class name";
+        } else {
+          return method.getName() + "=" + obfuscatedClassName;
+        }
+      }
+    }
+
+    /**
+     * Records replacements that have actually been performed.
+     */
+    private final Map<JMethod, String> actualReplacements = new IdentityHashMap<JMethod, String>();
     private final Set<String> cssDefs = new HashSet<String>();
-    private final Set<String> externalClasses;
+
+    /**
+     * The task-list of replacements to perform in the stylesheet.
+     */
+    private final Map<String, Replacement> potentialReplacements;
     private final TreeLogger logger;
     private final Set<JMethod> missingClasses;
-    private final Set<String> replacedClasses = new HashSet<String>();
     private final boolean strict;
     private final Set<String> unknownClasses = new HashSet<String>();
 
@@ -127,9 +164,10 @@
         Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
         boolean strict, Set<String> externalClasses) {
       this.logger = logger.branch(TreeLogger.DEBUG, "Replacing CSS class names");
-      this.classReplacementsWithPrefix = classReplacementsWithPrefix;
       this.strict = strict;
-      this.externalClasses = externalClasses;
+
+      potentialReplacements = computeReplacements(classReplacementsWithPrefix,
+          externalClasses);
 
       // Require a definition for all classes in the default namespace
       assert classReplacementsWithPrefix.containsKey("");
@@ -144,56 +182,45 @@
 
     @Override
     public void endVisit(CssSelector x, Context ctx) {
+
       String sel = x.getSelector();
+      int originalLength = sel.length();
 
-      // TODO This would be simplified by having a class hierarchy for selectors
-      for (Map.Entry<String, Map<JMethod, String>> outerEntry : classReplacementsWithPrefix.entrySet()) {
-        String prefix = outerEntry.getKey();
-        for (Map.Entry<JMethod, String> entry : outerEntry.getValue().entrySet()) {
-          JMethod method = entry.getKey();
-          String sourceClassName = method.getName();
-          String obfuscatedClassName = entry.getValue();
+      Matcher ma = CssSelector.CLASS_SELECTOR_PATTERN.matcher(sel);
+      StringBuilder sb = new StringBuilder(originalLength);
+      int start = 0;
 
-          ClassName className = method.getAnnotation(ClassName.class);
-          if (className != null) {
-            sourceClassName = className.value();
-          }
+      while (ma.find()) {
+        String sourceClassName = ma.group(1);
 
-          sourceClassName = prefix + sourceClassName;
+        Replacement entry = potentialReplacements.get(sourceClassName);
 
-          Pattern p = Pattern.compile("(.*)\\.("
-              + Pattern.quote(sourceClassName) + ")([ :>+#.].*|$)");
-          Matcher m = p.matcher(sel);
-          if (m.find()) {
-            if (externalClasses.contains(sourceClassName)) {
-              actualReplacements.put(method, sourceClassName);
-            } else {
-              sel = m.group(1) + "." + obfuscatedClassName + m.group(3);
-              actualReplacements.put(method, obfuscatedClassName);
-            }
+        if (entry == null) {
+          unknownClasses.add(sourceClassName);
+          continue;
 
-            missingClasses.remove(method);
-            if (strict) {
-              replacedClasses.add(obfuscatedClassName);
-            }
-          }
+        } else if (entry == UNREFERENCED_EXTERNAL) {
+          // An @external without an accessor method. This is OK.
+          continue;
         }
+
+        JMethod method = entry.getMethod();
+        String obfuscatedClassName = entry.getObfuscatedClassName();
+
+        // Consume the interstitial portion of the original selector
+        sb.append(sel.subSequence(start, ma.start(1)));
+        sb.append(obfuscatedClassName);
+        start = ma.end(1);
+
+        actualReplacements.put(method, obfuscatedClassName);
+        missingClasses.remove(method);
       }
 
-      sel = sel.trim();
-
-      if (strict) {
-        Matcher m = CssSelector.CLASS_SELECTOR_PATTERN.matcher(sel);
-        while (m.find()) {
-          String classSelector = m.group(1);
-          if (!replacedClasses.contains(classSelector)
-              && !externalClasses.contains(classSelector)) {
-            unknownClasses.add(classSelector);
-          }
-        }
+      if (start != 0) {
+        // Consume the remainder and update the selector
+        sb.append(sel.subSequence(start, originalLength));
+        x.setSelector(sb.toString());
       }
-
-      x.setSelector(sel);
     }
 
     @Override
@@ -245,9 +272,66 @@
       }
     }
 
+    /**
+     * Reports the replacements that were actually performed by this visitor.
+     */
     public Map<JMethod, String> getReplacements() {
       return actualReplacements;
     }
+
+    /**
+     * Flatten class name lookups to speed selector rewriting.
+     * 
+     * @param classReplacementsWithPrefix a map of local prefixes to the
+     *          obfuscated names of imported methods. If a CssResource makes use
+     *          of the {@link Import} annotation, the keys of this map will
+     *          correspond to the {@link ImportedWithPrefix} value defined on
+     *          the imported CssResource. The zero-length string key holds the
+     *          obfuscated names for the CssResource that is being generated.
+     * @return A flattened version of the classReplacementWithPrefix map, where
+     *         the keys are the source class name (with prefix included), and
+     *         values have the obfuscated class name and associated JMethod.
+     */
+    private Map<String, Replacement> computeReplacements(
+        Map<String, Map<JMethod, String>> classReplacementsWithPrefix,
+        Set<String> externalClasses) {
+
+      Map<String, Replacement> toReturn = new HashMap<String, Replacement>();
+
+      for (String externalClass : externalClasses) {
+        toReturn.put(externalClass, UNREFERENCED_EXTERNAL);
+      }
+
+      for (Map.Entry<String, Map<JMethod, String>> outerEntry : classReplacementsWithPrefix.entrySet()) {
+        String prefix = outerEntry.getKey();
+
+        for (Map.Entry<JMethod, String> entry : outerEntry.getValue().entrySet()) {
+          JMethod method = entry.getKey();
+          String sourceClassName = method.getName();
+          String obfuscatedClassName = entry.getValue();
+
+          ClassName className = method.getAnnotation(ClassName.class);
+          if (className != null) {
+            sourceClassName = className.value();
+          }
+
+          sourceClassName = prefix + sourceClassName;
+
+          if (externalClasses.contains(sourceClassName)) {
+            /*
+             * It simplifies the sanity-checking logic to treat external classes
+             * as though they were simply obfuscated to exactly the value the
+             * user wants.
+             */
+            obfuscatedClassName = sourceClassName;
+          }
+
+          toReturn.put(sourceClassName, new Replacement(method,
+              obfuscatedClassName));
+        }
+      }
+      return Collections.unmodifiableMap(toReturn);
+    }
   }
 
   static class DefsCollector extends CssVisitor {
@@ -1086,7 +1170,7 @@
      * Very large concatenation expressions using '+' cause the GWT compiler to
      * overflow the stack due to deep AST nesting. The workaround for now is to
      * force it to be more balanced using intermediate concatenation groupings.
-     *
+     * 
      * This variable is used to track the number of subexpressions within the
      * current parenthetical expression.
      */
@@ -1159,7 +1243,7 @@
   /**
    * Check if number of concat expressions currently exceeds limit and either
    * append '+' if the limit isn't reached or ') + (' if it is.
-   *
+   * 
    * @return numExpressions + 1 or 0 if limit was exceeded.
    */
   private static int concatOp(int numExpressions, StringBuilder b) {
@@ -1439,7 +1523,8 @@
           name = classNameOverride.value();
         }
 
-        String obfuscatedClassName = classPrefix + makeIdent(classCounter.next());
+        String obfuscatedClassName = classPrefix
+            + makeIdent(classCounter.next());
         if (prettyOutput) {
           obfuscatedClassName += "-"
               + type.getQualifiedSourceName().replaceAll("[.$]", "-") + "-"
@@ -1571,7 +1656,7 @@
      * result regardless of the order in which the generators fired. (It no
      * longer behaves that way, as that scheme prevented the generation of new
      * CssResource interfaces, but the complexity lives on.)
-     *
+     * 
      * TODO(rjrjr,bobv) These days scottb tells us we're guaranteed that the
      * recompiling the same code will fire the generators in a consistent order,
      * so the old gymnastics aren't really justified anyway. It would probably
@@ -1657,7 +1742,7 @@
   /**
    * Create a Java expression that evaluates to the string representation of the
    * stylesheet resource.
-   *
+   * 
    * @param actualReplacements An out parameter that will be populated by the
    *          obfuscated class names that should be used for the particular
    *          instance of the CssResource, based on any substitution
diff --git a/user/src/com/google/gwt/uibinder/rebind/GwtResourceEntityResolver.java b/user/src/com/google/gwt/uibinder/rebind/GwtResourceEntityResolver.java
index c93dbd3..8dad0ec 100644
--- a/user/src/com/google/gwt/uibinder/rebind/GwtResourceEntityResolver.java
+++ b/user/src/com/google/gwt/uibinder/rebind/GwtResourceEntityResolver.java
@@ -1,12 +1,12 @@
 /*
  * Copyright 2009 Google Inc.
- * 
+ *
  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- * 
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -25,13 +25,13 @@
 /**
  * Does special handling of external entities encountered by sax xml parser,
  * e.g. the uri in
- * 
+ *
  * <pre>
- * &lt;!DOCTYPE gwt:UiBinder 
-  SYSTEM "http://google-web-toolkit.googlecode.com/svn/resources/xhtml.ent"></pre>
+ * &lt;!DOCTYPE gwt:UiBinder
+  SYSTEM "http://google-web-toolkit.googlecode.com/files/xhtml.ent"></pre>
  * <p>
  * Specifically, if the requested uri starts with
- * <code>http://google-web-toolkit.googlecode.com/svn/resources</code>, provide
+ * <code>http://google-web-toolkit.googlecode.com/files</code>, provide
  * the contents from a built in resource rather than allowing sax to make a
  * network request.
  */
@@ -40,9 +40,9 @@
     InputStream fetch(String name);
   }
 
-  private static final String EXTERNAL_ENTITY_PREFIX = "http://google-web-toolkit.googlecode.com/svn/resources";
+  private static final String EXTERNAL_ENTITY_PREFIX = "http://google-web-toolkit.googlecode.com/files/";
 
-  private static final String RESOURCES = "com/google/gwt/uibinder/resources";
+  private static final String RESOURCES = "com/google/gwt/uibinder/resources/";
 
   private final ResourceLoader resourceLoader;
 
@@ -87,4 +87,4 @@
     inputSource.setSystemId(systemId);
     return inputSource;
   }
-}
\ No newline at end of file
+}
diff --git a/user/src/com/google/gwt/uibinder/resources/xhtml.ent b/user/src/com/google/gwt/uibinder/resources/xhtml.ent
index aa80147..1c5183f 100644
--- a/user/src/com/google/gwt/uibinder/resources/xhtml.ent
+++ b/user/src/com/google/gwt/uibinder/resources/xhtml.ent
@@ -6,12 +6,22 @@
 -->
 
 <!--
-  This is the complete set of named character entites defined in XHTML1.0. It's
-  essentially a union of:
+  This is the complete set of named character entites defined in
+  XHTML1.0.  Though this file was created for the convenience of users
+  of the Google Web Toolkit, it should be useful for any XML
+  document. It's essentially a union of:
 
     http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
     http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent
     http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent
+
+  Sample usage:
+  <!DOCTYPE ui:UiBinder
+    SYSTEM "http://google-web-toolkit.googlecode.com/files/xhtml.ent">
+
+  This file is maintained at
+  <http://google-web-toolkit.googlecode.com/svn/trunk/user/src/com/google/gwt/uibinder/resources/xhtml.ent>. Changes
+  made to it must be propagated to the URL in the sample above.
 -->
 
 <!-- Latin-1 characters -->
@@ -208,7 +218,7 @@
        existing ISO 8879 entity names. ISO 10646 character numbers
        are given for each character, in hex. values are decimal
        conversions of the ISO 10646 values and refer to the document
-       character set. Names are Unicode names. 
+       character set. Names are Unicode names.
   -->
 
   <!-- C0 Controls and Basic Latin -->
@@ -394,7 +404,7 @@
   <!ENTITY uArr     "&#8657;"> <!-- upwards double arrow, U+21D1 ISOamsa -->
   <!ENTITY rArr     "&#8658;"> <!-- rightwards double arrow,
                                        U+21D2 ISOtech -->
-  <!-- Unicode does not say this is the 'implies' character but does not have 
+  <!-- Unicode does not say this is the 'implies' character but does not have
        another character with this function so rArr can be used for 'implies'
        as ISOtech suggests -->
   <!ENTITY dArr     "&#8659;"> <!-- downwards double arrow, U+21D3 ISOamsa -->
@@ -467,11 +477,11 @@
   <!ENTITY rfloor   "&#8971;"> <!-- right floor, U+230B ISOamsc  -->
   <!ENTITY lang     "&#9001;"> <!-- left-pointing angle bracket = bra,
                                        U+2329 ISOtech -->
-  <!-- lang is NOT the same character as U+003C 'less than sign' 
+  <!-- lang is NOT the same character as U+003C 'less than sign'
        or U+2039 'single left-pointing angle quotation mark' -->
   <!ENTITY rang     "&#9002;"> <!-- right-pointing angle bracket = ket,
                                        U+232A ISOtech -->
-  <!-- rang is NOT the same character as U+003E 'greater than sign' 
+  <!-- rang is NOT the same character as U+003E 'greater than sign'
        or U+203A 'single right-pointing angle quotation mark' -->
 
   <!-- Geometric Shapes -->
diff --git a/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml b/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
index d16bb54..7f40dfd 100644
--- a/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
+++ b/user/src/com/google/gwt/uibinder/sample/client/WidgetBasedUi.ui.xml
@@ -14,7 +14,7 @@
 -->
 
 <!DOCTYPE ui:UiBinder 
-  SYSTEM "http://google-web-toolkit.googlecode.com/svn/resources/xhtml.ent"
+  SYSTEM "http://google-web-toolkit.googlecode.com/files/xhtml.ent"
   [
     <!ENTITY % MyEntities SYSTEM "MyEntities.ent">
     %MyEntities;
@@ -26,13 +26,15 @@
   
   First, this bit:
   
-    SYSTEM "http://google-web-toolkit.googlecode.com/svn/trunk/resources/xhtml.ent"
+    SYSTEM "http://google-web-toolkit.googlecode.com/files/xhtml.ent"
  
   allows you to use familiar HTML entities like %nbsp; and &bull;, 
   which are not part of XML.
     
-  Next, the bit in square brackets pulls in additional definitions for
-  &point-left; and &point-right; from local file MyEntities.ent.
+  Next, the bit in square brackets is even more optional. It shows how
+  to add your own entities, in this case pulling in additional
+  definitions for &point-left; and &point-right; from local file
+  MyEntities.ent.
 
   You don't have to be so verbose to include a local file! For
   example, you might instead grab your own copy of xhtml.ent
diff --git a/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java b/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
index b954f3e..80966f5 100644
--- a/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
+++ b/user/test/com/google/gwt/dev/jjs/test/singlejso/TypeHierarchyTest.java
@@ -24,6 +24,16 @@
 public class TypeHierarchyTest extends GWTTestCase {
 
   /**
+   * Used with PlainJso and PlainJsoWithInterface to mix interfaces into
+   * existing base classes.
+   */
+  interface Arrayish {
+    int getLength();
+
+    JavaScriptObject getObject(int i);
+  }
+
+  /**
    * The bottom type for a non-trivial diamond-shaped inheritance pattern.
    */
   static class DiamondImpl extends JavaScriptObject implements IDiamond2A,
@@ -59,6 +69,35 @@
   interface IDiamond2B extends IDiamond1 {
   }
 
+  /**
+   * This is a base class that is used to test adding interfaces to a JSO via a
+   * subclass.
+   */
+  static class PlainJso extends JavaScriptObject {
+    protected PlainJso() {
+    }
+
+    public final native int getLength()/*-{
+      return this.length;
+    }-*/;
+
+    public final native JavaScriptObject getObject(int i) /*-{
+      return this[i];
+    }-*/;
+  }
+
+  /**
+   * We'll mix in an interface into PlainJso.
+   */
+  static class PlainJsoWithInterface extends PlainJso implements Arrayish {
+    public static PlainJsoWithInterface create() {
+      return JavaScriptObject.createArray().cast();
+    }
+
+    protected PlainJsoWithInterface() {
+    }
+  }
+
   @Override
   public String getModuleName() {
     return "com.google.gwt.dev.jjs.CompilerSuite";
@@ -107,4 +146,10 @@
     IDiamond2B d2b = DiamondImpl.create();
     assertEquals(42, d2b.size());
   }
+
+  public void testVirtualOverrides() {
+    Arrayish array = PlainJsoWithInterface.create();
+    assertEquals(0, array.getLength());
+    assertNull(array.getObject(0));
+  }
 }
diff --git a/user/test/com/google/gwt/uibinder/rebind/GwtResourceEntityResolverTest.java b/user/test/com/google/gwt/uibinder/rebind/GwtResourceEntityResolverTest.java
index da630e7..5cf1b55 100644
--- a/user/test/com/google/gwt/uibinder/rebind/GwtResourceEntityResolverTest.java
+++ b/user/test/com/google/gwt/uibinder/rebind/GwtResourceEntityResolverTest.java
@@ -27,7 +27,8 @@
  * Text of GwtResourceEntityResolver.
  */
 public class GwtResourceEntityResolverTest extends TestCase {
-  
+  private static final String SYSTEM_ID = "http://google-web-toolkit.googlecode.com/files/xhtml.ent";
+
   private static class MockResourceLoader implements
       GwtResourceEntityResolver.ResourceLoader {
     String fetched;
@@ -37,7 +38,7 @@
       return stream;
     }
   }
-  
+
   private GwtResourceEntityResolver resolver;
   private MockResourceLoader loader;
 
@@ -46,27 +47,31 @@
     super.setUp();
     loader = new MockResourceLoader();
     resolver = new GwtResourceEntityResolver(loader);
+
+    loader.stream = new InputStream() {
+      @Override
+      public int read() throws IOException {
+        throw new UnsupportedOperationException();
+      }
+    };
   }
 
   public void testNotOurProblem() throws SAXException, IOException {
     assertNull(resolver.resolveEntity(null, "http://arbitrary"));
     assertNull(resolver.resolveEntity("meaningless", "http://arbitrary"));
     assertNull(resolver.resolveEntity(null, "arbitrary/relative"));
+
+    String almostCorrectAndOnceWorked = SYSTEM_ID.replace("files", "filesss");
+    assertNull(resolver.resolveEntity("meaningless", almostCorrectAndOnceWorked));
+    assertNull(resolver.resolveEntity(null, almostCorrectAndOnceWorked));
   }
 
   public void testOursGood() throws SAXException, IOException {
     String publicId = "some old public thing";
-    String systemId = "http://google-web-toolkit.googlecode.com/svn/resources/xhtml.ent";
-    loader.stream = new InputStream() {
-      @Override
-      public int read() throws IOException {
-        throw new UnsupportedOperationException();
-      }      
-    };
-    
-    InputSource s = resolver.resolveEntity(publicId, systemId);
+
+    InputSource s = resolver.resolveEntity(publicId, SYSTEM_ID);
     assertEquals(publicId, s.getPublicId());
-    assertEquals(systemId, s.getSystemId());
+    assertEquals(SYSTEM_ID, s.getSystemId());
     assertEquals(loader.stream, s.getByteStream());
   }
 }