Revision: 5767
Author: [email protected]
Date: Tue Jul 21 18:30:12 2009
Log: Fixes internal type hierarchy for overlay types.

All interfaces implemented by any overlay types are now directly  
implemented by JSO itself.  This resolves a subtle bug where things could  
get tightened to subclasses of JSO, which is never correct.

Review by: bobv
http://code.google.com/p/google-web-toolkit/source/detail?r=5767

Modified:
  /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java
  /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
   
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java     Mon Jul 
 
20 14:25:19 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/ast/JTypeOracle.java     Tue Jul 
 
21 18:30:12 2009
@@ -23,7 +23,6 @@
  import java.io.Serializable;
  import java.util.ArrayList;
  import java.util.Collections;
-import java.util.LinkedList;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
@@ -210,7 +209,7 @@

    private final Map<JClassType, Set<JInterfaceType>> couldImplementMap =  
new IdentityHashMap<JClassType, Set<JInterfaceType>>();

-  private final Set<JInterfaceType> dualImpl = new  
IdentityHashSet<JInterfaceType>();
+  private final Set<JInterfaceType> dualImpls = new  
IdentityHashSet<JInterfaceType>();

    private final Map<JClassType, Set<JInterfaceType>> implementsMap = new  
IdentityHashMap<JClassType, Set<JInterfaceType>>();

@@ -364,6 +363,8 @@
      couldImplementMap.clear();
      isImplementedMap.clear();
      couldBeImplementedMap.clear();
+    jsoSingleImpls.clear();
+    dualImpls.clear();

      for (int i = 0; i < program.getDeclaredTypes().size(); ++i) {
        JReferenceType type = program.getDeclaredTypes().get(i);
@@ -373,6 +374,31 @@
          recordSuperSubInfo((JInterfaceType) type);
        }
      }
+
+    /*
+     * Now that the basic type hierarchy is computed, move all interfaces  
that
+     * are implemented by overlay types onto JavaScriptObject itself before
+     * building the full maps.
+     */
+    JClassType jsoType = program.getJavaScriptObject();
+    Set<JClassType> jsoSubTypes = Collections.emptySet();
+    if (jsoType != null) {
+      assert jsoType.getImplements().size() == 0;
+      jsoSubTypes = get(subClassMap, jsoType);
+      for (JClassType jsoSubType : jsoSubTypes) {
+        for (JInterfaceType intf : jsoSubType.getImplements()) {
+          jsoType.addImplements(intf);
+          jsoSingleImpls.put(intf, jsoSubType);
+          for (JInterfaceType superIntf : get(superInterfaceMap, intf)) {
+            if (!jsoSingleImpls.containsKey(superIntf)) {
+              jsoSingleImpls.put(superIntf, jsoSubType);
+            }
+          }
+        }
+        jsoSubType.clearImplements();
+      }
+    }
+
      for (int i = 0; i < program.getDeclaredTypes().size(); ++i) {
        JReferenceType type = program.getDeclaredTypes().get(i);
        if (type instanceof JClassType) {
@@ -392,26 +418,17 @@
        }
      }

-    computeSingleJsoImplData();
-  }
-
-  /**
-   * Returns true if qType is a superinterface of type, directly or  
indirectly.
-   */
-  public boolean extendsInterface(JInterfaceType type, JInterfaceType  
qType) {
-    return get(superInterfaceMap, type).contains(qType);
-  }
-
-  public JMethod findConcreteImplementation(JMethod method,
-      JClassType concreteType) {
-    for (JMethod m : concreteType.getMethods()) {
-      if (getAllOverrides(m).contains(method)) {
-        if (!m.isAbstract()) {
-          return m;
-        }
+    // Create dual mappings for any jso interface with a Java implementor.
+    int totalJsoTypes = jsoSubTypes.size() + 1;
+    for (JInterfaceType jsoIntf : jsoSingleImpls.keySet()) {
+      Set<JClassType> implementors = get(isImplementedMap, jsoIntf);
+      if (implementors.size() == totalJsoTypes) {
+        assert implementors.contains(jsoType);
+      } else {
+        assert implementors.size() > totalJsoTypes;
+        dualImpls.add(jsoIntf);
        }
      }
-    return null;
    }

    public Set<JMethod> getAllOverrides(JMethod method) {
@@ -454,20 +471,12 @@
    }

    public Set<JInterfaceType> getInterfacesWithJavaAndJsoImpls() {
-    return Collections.unmodifiableSet(dualImpl);
+    return Collections.unmodifiableSet(dualImpls);
    }

    public Map<JInterfaceType, JClassType> getSingleJsoImpls() {
      return Collections.unmodifiableMap(jsoSingleImpls);
    }
-
-  /**
-   * Returns true if qType is an implemented interface of type, directly or
-   * indirectly.
-   */
-  public boolean implementsInterface(JClassType type, JInterfaceType  
qType) {
-    return get(implementsMap, type).contains(qType);
-  }

    public boolean isInstantiatedType(JReferenceType type) {
      return isInstantiatedType(type, instantiatedTypes);
@@ -486,36 +495,6 @@
    public boolean isSuperClass(JClassType type, JClassType qType) {
      return get(superClassMap, type).contains(qType);
    }
-
-  /**
-   * Returns true if the given type and it's super-interfaces define no  
methods.
-   */
-  public boolean isTagInterface(JInterfaceType type) {
-    Set<JInterfaceType> seen = new IdentityHashSet<JInterfaceType>();
-    List<JInterfaceType> q = new LinkedList<JInterfaceType>();
-    seen.add(type);
-    q.add(type);
-
-    while (!q.isEmpty()) {
-      JInterfaceType intf = q.remove(0);
-
-      List<JMethod> methods = intf.getMethods();
-      int size = methods.size();
-      if (size == 0
-          || (size == 1 && methods.get(0).getName().equals("$clinit"))) {
-        // OK, add any super-interfaces;
-        for (JInterfaceType superIntf : intf.getImplements()) {
-          if (seen.add(superIntf)) {
-            q.add(superIntf);
-          }
-        }
-      } else {
-        return false;
-      }
-    }
-
-    return true;
-  }

    /**
     * This method should be called after altering the types that are live  
in the
@@ -529,8 +508,6 @@
          computeHasClinit(type, computed);
        }
      }
-
-    computeSingleJsoImplData();
    }

    public void setInstantiatedTypes(Set<JReferenceType> instantiatedTypes) {
@@ -541,48 +518,6 @@
    private <K, V> void add(Map<K, Set<V>> map, K key, V value) {
      getOrCreate(map, key).add(value);
    }
-
-  /**
-   * Collect all supertypes and superinterfaces for a type.
-   */
-  private Set<JDeclaredType> allAssignableFrom(JDeclaredType type) {
-    Set<JDeclaredType> toReturn = new IdentityHashSet<JDeclaredType>();
-    List<JDeclaredType> q = new LinkedList<JDeclaredType>();
-    q.add(type);
-
-    while (!q.isEmpty()) {
-      JDeclaredType t = q.remove(0);
-
-      if (toReturn.add(t)) {
-        if (t.getSuperClass() != null) {
-          q.add(t.getSuperClass());
-        }
-
-        q.addAll(t.getImplements());
-      }
-    }
-
-    return toReturn;
-  }
-
-  /**
-   * Computes the set of all interfaces implemented by a type.
-   */
-  private Set<JInterfaceType> allSuperInterfaces(JDeclaredType type) {
-    Set<JInterfaceType> toReturn = new IdentityHashSet<JInterfaceType>();
-    List<JInterfaceType> q = new LinkedList<JInterfaceType>();
-    q.addAll(type.getImplements());
-
-    while (!q.isEmpty()) {
-      JInterfaceType t = q.remove(0);
-
-      if (toReturn.add(t)) {
-        q.addAll(t.getImplements());
-      }
-    }
-
-    return toReturn;
-  }

    /**
     * Compute all of the things I might conceivably implement, either  
through
@@ -687,73 +622,6 @@
        }
      }
    }
-
-  private void computeSingleJsoImplData() {
-    dualImpl.clear();
-    jsoSingleImpls.clear();
-
-    JClassType jsoType = program.getJavaScriptObject();
-    if (jsoType == null) {
-      return;
-    }
-
-    jsoType.clearImplements();
-
-    for (JDeclaredType type : program.getDeclaredTypes()) {
-      if (!program.isJavaScriptObject(type)) {
-        if (type instanceof JClassType) {
-          dualImpl.addAll(allSuperInterfaces(type));
-        }
-        continue;
-      }
-
-      for (JReferenceType refType : allAssignableFrom(type)) {
-        if (!(refType instanceof JInterfaceType)) {
-          continue;
-        }
-        JInterfaceType intr = (JInterfaceType) refType;
-
-        if (isTagInterface(intr)) {
-          /*
-           * Record a tag interface as being implemented by JSO, since they
-           * don't actually have any methods and we want to avoid spurious
-           * messages about multiple JSO types implementing a common  
interface.
-           */
-          jsoSingleImpls.put(intr, program.getJavaScriptObject());
-
-          /*
-           * Pretend JSO had always implemented the tag interface. This  
helps
-           * simplify cast operations.
-           */
-          jsoType.addImplements(intr);
-          add(couldBeImplementedMap, intr, jsoType);
-          add(isImplementedMap, intr, jsoType);
-          add(implementsMap, jsoType, intr);
-          continue;
-        }
-
-        if (jsoSingleImpls.containsKey(intr)) {
-          // See if we're looking at a supertype
-          JClassType alreadySeen = jsoSingleImpls.get(intr);
-
-          if (allAssignableFrom(alreadySeen).contains(type)) {
-            jsoSingleImpls.put(intr, (JClassType) type);
-
-          } else {
-            assert  
allAssignableFrom(type).contains(alreadySeen) : "Already recorded "
-                + alreadySeen.getName()
-                + " as single impl for "
-                + intr.getName()
-                + " while looking at unrelated type "
-                + type.getName();
-          }
-        } else {
-          jsoSingleImpls.put(intr, (JClassType) type);
-        }
-      }
-    }
-    dualImpl.retainAll(jsoSingleImpls.keySet());
-  }

    /**
     * WEIRD: Suppose class Foo declares void f(){} and unrelated interface  
I also
@@ -817,6 +685,13 @@
        }
      }
    }
+
+  /**
+   * Returns true if qType is a superinterface of type, directly or  
indirectly.
+   */
+  private boolean extendsInterface(JInterfaceType type, JInterfaceType  
qType) {
+    return get(superInterfaceMap, type).contains(qType);
+  }

    private <K, V> Set<V> get(Map<K, Set<V>> map, K key) {
      Set<V> set = map.get(key);
@@ -862,6 +737,14 @@
      }
      return map2;
    }
+
+  /**
+   * Returns true if qType is an implemented interface of type, directly or
+   * indirectly.
+   */
+  private boolean implementsInterface(JClassType type, JInterfaceType  
qType) {
+    return get(implementsMap, type).contains(qType);
+  }

    private boolean isSameOrSuper(JClassType type, JClassType qType) {
      return (type == qType || isSuperClass(type, qType));
=======================================
---  
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java        
 
Thu Jul 16 16:35:08 2009
+++  
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java        
 
Tue Jul 21 18:30:12 2009
@@ -174,21 +174,6 @@
        JType targetType = x.getCastType();
        if (program.isJavaScriptObject(targetType)) {
          rescue((JReferenceType) targetType, true, true);
-      } else {
-        /*
-         * If there's a cast to a SingleJso interface, rescue the  
implementing
-         * JSO type. If the JSO type isn't rescued (and there's no other  
regular
-         * Java type implementing the interface), then the cast operation  
will
-         * be replaced with a throwCCEUnlessNull() call, since there's no  
type
-         * left in the type system that implements the interface. If there  
is an
-         * implementing Java type, then a dynamicCast() will be emitted  
which
-         * will throw a CCE if it hits a JSO type.
-         */
-        JClassType maybeSingleJso =  
program.typeOracle.getSingleJsoImpls().get(
-            targetType);
-        if (maybeSingleJso != null) {
-          rescue(maybeSingleJso, true, true);
-        }
        }

        return true;
=======================================
---  
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java 
 
Thu Apr  9 08:41:34 2009
+++  
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/JavaScriptObjectNormalizer.java 
 
Tue Jul 21 18:30:12 2009
@@ -120,7 +120,7 @@
          JMethod jsoMethod = findJsoMethod(x.getTarget());
          assert jsoMethod != null;

-        if (dualImpl.contains(targetClass)) {
+        if (dualImpls.contains(targetClass)) {
            /*
             * This is the special-case code to handle interfaces.
             */
@@ -174,14 +174,25 @@
        currentMethodBody.push(x);
        return true;
      }
+
+    private JMethod findConcreteImplementation(JMethod method,
+        JClassType concreteType) {
+      for (JMethod m : concreteType.getMethods()) {
+        if (program.typeOracle.getAllOverrides(m).contains(method)) {
+          if (!m.isAbstract()) {
+            return m;
+          }
+        }
+      }
+      return null;
+    }

      private JMethod findJsoMethod(JMethod interfaceMethod) {
        JClassType jsoClass =  
jsoSingleImpls.get(interfaceMethod.getEnclosingType());
        assert program.isJavaScriptObject(jsoClass);
        assert jsoClass != null;

-      JMethod toReturn = program.typeOracle.findConcreteImplementation(
-          interfaceMethod, jsoClass);
+      JMethod toReturn = findConcreteImplementation(interfaceMethod,  
jsoClass);
        assert toReturn != null;
        assert !toReturn.isAbstract();
        assert jsoClass.isFinal() || toReturn.isFinal();
@@ -226,8 +237,8 @@
        if (program.isJavaScriptObject(type)) {
          return program.getJavaScriptObject();

-      } else if (jsoSingleImpls.containsKey(type)  
&& !dualImpl.contains(type)) {
-        // Narrow to JSO when possible
+      } else if (jsoSingleImpls.containsKey(type)  
&& !dualImpls.contains(type)) {
+        // Optimization: narrow to JSO if it's not a dual impl.
          return program.getJavaScriptObject();

        } else if (type instanceof JArrayType) {
@@ -249,7 +260,7 @@
    /**
     * Interfaces implemented both by a JSO type and a regular Java type.
     */
-  private final Set<JInterfaceType> dualImpl;
+  private final Set<JInterfaceType> dualImpls;

    /**
     * Maps SingleJsoImpl interfaces onto the single JSO implementation.
@@ -260,7 +271,7 @@

    private JavaScriptObjectNormalizer(JProgram program) {
      this.program = program;
-    dualImpl = program.typeOracle.getInterfacesWithJavaAndJsoImpls();
+    dualImpls = program.typeOracle.getInterfacesWithJavaAndJsoImpls();
      jsoSingleImpls = program.typeOracle.getSingleJsoImpls();
    }



--~--~---------~--~----~------------~-------~--~----~
http://groups.google.com/group/Google-Web-Toolkit-Contributors
-~----------~----~----~----~------~----~------~--~---

Reply via email to