Code gen optimization: only emit clinit() calls into static methods that can possibly be the target of a cross-class call.

Review by: mmendez


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1560 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index 0e02ec8..ef6877b 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -71,6 +71,7 @@
 import com.google.gwt.dev.jjs.ast.js.JClassSeed;
 import com.google.gwt.dev.jjs.ast.js.JMultiExpression;
 import com.google.gwt.dev.jjs.ast.js.JsniMethodBody;
+import com.google.gwt.dev.jjs.ast.js.JsniMethodRef;
 import com.google.gwt.dev.jjs.ast.js.JsonArray;
 import com.google.gwt.dev.jjs.ast.js.JsonObject;
 import com.google.gwt.dev.jjs.ast.js.JsonObject.JsonPropInit;
@@ -140,8 +141,8 @@
 
   private class CreateNamesAndScopesVisitor extends JVisitor {
 
-    private final Stack<JsScope> scopeStack = new Stack<JsScope>();
     private final JField arrayLengthField = program.getIndexedField("Array.length");
+    private final Stack<JsScope> scopeStack = new Stack<JsScope>();
 
     @Override
     public void endVisit(JClassType x, Context ctx) {
@@ -319,11 +320,11 @@
     public boolean visit(JTryStatement x, Context ctx) {
       accept(x.getTryBlock());
 
-      List catchArgs = x.getCatchArgs();
-      List catchBlocks = x.getCatchBlocks();
+      List<JLocalRef> catchArgs = x.getCatchArgs();
+      List<JBlock> catchBlocks = x.getCatchBlocks();
       for (int i = 0, c = catchArgs.size(); i < c; ++i) {
-        JLocalRef arg = (JLocalRef) catchArgs.get(i);
-        JBlock catchBlock = (JBlock) catchBlocks.get(i);
+        JLocalRef arg = catchArgs.get(i);
+        JBlock catchBlock = catchBlocks.get(i);
         JsCatch jsCatch = new JsCatch(peek(), arg.getTarget().getName());
         JsParameter jsParam = jsCatch.getParameter();
         names.put(arg.getTarget(), jsParam.getName());
@@ -1381,16 +1382,16 @@
     }
 
     private JsInvocation maybeCreateClinitCall(JMethod x) {
-      if (!x.isStatic()) {
+      if (!crossClassTargets.contains(x)) {
+        return null;
+      }
+      if (!x.isStatic() || program.isStaticImpl(x)) {
         return null;
       }
       JReferenceType enclosingType = x.getEnclosingType();
       if (!typeOracle.hasClinit(enclosingType)) {
         return null;
       }
-      if (program.isStaticImpl(x)) {
-        return null;
-      }
       // avoid recursion sickness
       if (x == enclosingType.methods.get(0)) {
         return null;
@@ -1456,6 +1457,36 @@
     }
   }
 
+  private class RecordCrossClassCalls extends JVisitor {
+
+    private JMethod currentMethod;
+
+    @Override
+    public void endVisit(JMethod x, Context ctx) {
+      currentMethod = null;
+    }
+
+    @Override
+    public void endVisit(JMethodCall x, Context ctx) {
+      JReferenceType sourceType = currentMethod.getEnclosingType();
+      JReferenceType targetType = x.getTarget().getEnclosingType();
+      if (typeOracle.checkClinit(sourceType, targetType)) {
+        crossClassTargets.add(x.getTarget());
+      }
+    }
+
+    @Override
+    public void endVisit(JsniMethodRef x, Context ctx) {
+      endVisit((JMethodCall) x, ctx);
+    }
+    
+    @Override
+    public boolean visit(JMethod x, Context ctx) {
+      currentMethod = x;
+      return true;
+    }
+  }
+
   private class SortVisitor extends JVisitor {
 
     private final HasNameSort hasNameSort = new HasNameSort();
@@ -1510,6 +1541,12 @@
   private final Map<JClassType, JsScope> classScopes = new IdentityHashMap<JClassType, JsScope>();
 
   /**
+   * A list of methods that are called from another class (ie might need to
+   * clinit).
+   */
+  private Set<JMethod> crossClassTargets = new HashSet<JMethod>();
+
+  /**
    * Contains JsNames for all interface methods. A special scope is needed so
    * that independent classes will obfuscate their interface implementation
    * methods the same way.
@@ -1536,6 +1573,7 @@
    * String's super types need special handling.
    */
   private final Map<String, String> specialObfuscatedIdents = new HashMap<String, String>();
+
   /**
    * All of the super types of String.
    * 
@@ -1680,6 +1718,8 @@
   private void execImpl() {
     SortVisitor sorter = new SortVisitor();
     sorter.accept(program);
+    RecordCrossClassCalls recorder = new RecordCrossClassCalls();
+    recorder.accept(program);
     CreateNamesAndScopesVisitor creator = new CreateNamesAndScopesVisitor();
     creator.accept(program);
     GenerateJavaScriptVisitor generator = new GenerateJavaScriptVisitor();