Added the ability to staticify a method call based on the concrete type of the qualifier, even in cases where the target method is not globally final.

Review by: knorton


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2249 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
index 6ae7b88..a02025c 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/ast/JMethodCall.java
@@ -25,6 +25,7 @@
 public class JMethodCall extends JExpression {
 
   private ArrayList<JExpression> args = new ArrayList<JExpression>();
+  private boolean cannotBePolymorphic = false;
   private JExpression instance;
   private final JMethod method;
   private final JType overrideReturnType;
@@ -41,6 +42,15 @@
     this.overrideReturnType = null;
   }
 
+  public JMethodCall(JProgram program, SourceInfo info, JExpression instance,
+      JMethod method, boolean staticDispatchOnly) {
+    super(program, info);
+    this.instance = instance;
+    this.method = method;
+    this.staticDispatchOnly = staticDispatchOnly;
+    this.overrideReturnType = null;
+  }
+
   /**
    * Create a method call whose type is overridden to the specified type,
    * ignoring the return type of the target method. This constructor is used
@@ -61,17 +71,9 @@
     this.overrideReturnType = overrideReturnType;
   }
 
-  public JMethodCall(JProgram program, SourceInfo info, JExpression instance,
-      JMethod method, boolean staticDispatchOnly) {
-    super(program, info);
-    this.instance = instance;
-    this.method = method;
-    this.staticDispatchOnly = staticDispatchOnly;
-    this.overrideReturnType = null;
-  }
-
   public boolean canBePolymorphic() {
-    return !staticDispatchOnly && !method.isFinal() && !method.isStatic();
+    return !cannotBePolymorphic && !staticDispatchOnly && !method.isFinal()
+        && !method.isStatic();
   }
 
   public ArrayList<JExpression> getArgs() {
@@ -104,6 +106,10 @@
     return staticDispatchOnly;
   }
 
+  public void setCannotBePolymorphic() {
+    this.cannotBePolymorphic = true;
+  }
+
   public void setStaticDispatchOnly() {
     this.staticDispatchOnly = true;
   }
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java b/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
index 4d815eb..2f81641 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/CloneExpressionVisitor.java
@@ -182,6 +182,9 @@
   public boolean visit(JMethodCall x, Context ctx) {
     JMethodCall newMethodCall = new JMethodCall(program, x.getSourceInfo(),
         cloneExpression(x.getInstance()), x.getTarget());
+    if (!x.canBePolymorphic()) {
+      newMethodCall.setCannotBePolymorphic();
+    }
 
     for (JExpression arg : x.getArgs()) {
       newMethodCall.getArgs().add(cloneExpression(arg));
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
index b58a5ce..bd60b0d 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
@@ -141,6 +141,9 @@
 
         JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(),
             x.getInstance(), method);
+        if (!x.canBePolymorphic()) {
+          newCall.setCannotBePolymorphic();
+        }
 
         ArrayList<JExpression> args = x.getArgs();
         ArrayList<JParameter> originalParams = methodToOriginalParamsMap.get(method);
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
index ef6f251..7707f0b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/TypeTightener.java
@@ -567,13 +567,33 @@
      */
     @Override
     public void endVisit(JMethodCall x, Context ctx) {
-      JMethod concreteMethod = getSingleConcreteMethod(x.getTarget());
+      JMethod target = x.getTarget();
+      JMethod concreteMethod = getSingleConcreteMethod(target);
       if (concreteMethod != null) {
         JMethodCall newCall = new JMethodCall(program, x.getSourceInfo(),
             x.getInstance(), concreteMethod);
         newCall.getArgs().addAll(x.getArgs());
-
         ctx.replaceMe(newCall);
+        target = concreteMethod;
+        x = newCall;
+      }
+
+      if (x.canBePolymorphic()) {
+        // See if we can remove virtualization from this call.
+        JExpression instance = x.getInstance();
+        assert (instance != null);
+        JReferenceType instanceType = (JReferenceType) instance.getType();
+        Set<JMethod> myOverriders = overriders.get(target);
+        for (JMethod override : myOverriders) {
+          JReferenceType overrideType = override.getEnclosingType();
+          if (program.typeOracle.canTheoreticallyCast(instanceType, overrideType)) {
+            // This call is truly polymorphic.
+            // TODO: composite types! :)
+            return;
+          }
+        }
+        x.setCannotBePolymorphic();
+        didChange = true;
       }
     }