Removes unnecessary calls to superclass clinits that occur after a subclass clinit has already run.

Review by: bobv (postmortem)


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@1681 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 1e43e8c..38d9a42 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
@@ -367,6 +367,8 @@
 
     private final JsName prototype = objectScope.declareName("prototype");
 
+    private Map<JClassType, JsFunction> clinitMap = new HashMap<JClassType, JsFunction>();
+
     {
       globalTemp.setObfuscatable(false);
       prototype.setObfuscatable(false);
@@ -487,7 +489,10 @@
       List<JsNode> jsFields = popList(x.fields.size()); // fields
 
       if (typeOracle.hasClinit(x)) {
-        handleClinit(jsFuncs.get(0));
+        JsFunction superClinit = clinitMap.get(x.extnds);
+        JsFunction myClinit = jsFuncs.get(0);
+        handleClinit(myClinit, superClinit);
+        clinitMap.put(x, myClinit);
       } else {
         jsFuncs.set(0, null);
       }
@@ -701,7 +706,7 @@
 
       if (typeOracle.hasClinit(x)) {
         JsFunction clinitFunc = jsFuncs.get(0);
-        handleClinit(clinitFunc);
+        handleClinit(clinitFunc, null);
         globalStmts.add(clinitFunc.makeStmt());
       }
 
@@ -1394,8 +1399,9 @@
       }
     }
 
-    private void handleClinit(JsFunction clinitFunc) {
+    private void handleClinit(JsFunction clinitFunc, JsFunction superClinit) {
       clinitFunc.setExecuteOnce(true);
+      clinitFunc.setImpliedExecute(superClinit);
       List<JsStatement> statements = clinitFunc.getBody().getStatements();
       // self-assign to the null method immediately (to prevent reentrancy)
       JsExpression asg = createAssignment(clinitFunc.getName().makeRef(),
@@ -1561,7 +1567,8 @@
     }
   }
 
-  public static void exec(JProgram program, JsProgram jsProgram, JsOutputOption output) {
+  public static void exec(JProgram program, JsProgram jsProgram,
+      JsOutputOption output) {
     GenerateJavaScriptAST generateJavaScriptAST = new GenerateJavaScriptAST(
         program, jsProgram, output);
     generateJavaScriptAST.execImpl();
diff --git a/dev/core/src/com/google/gwt/dev/js/JsInliner.java b/dev/core/src/com/google/gwt/dev/js/JsInliner.java
index 0f94ec2..c7d237d 100644
--- a/dev/core/src/com/google/gwt/dev/js/JsInliner.java
+++ b/dev/core/src/com/google/gwt/dev/js/JsInliner.java
@@ -257,19 +257,19 @@
      */
 
     /**
-     * Retains the names of the functions that we know have been called.
+     * Retains the the functions that we know have been called.
      */
-    private final Set<JsName> called;
+    private final Set<JsFunction> called;
     private final JsProgram program;
 
     public DuplicateXORemover(JsProgram program) {
       this.program = program;
-      called = new HashSet<JsName>();
+      called = new HashSet<JsFunction>();
     }
 
-    public DuplicateXORemover(JsProgram program, Set<JsName> alreadyCalled) {
+    public DuplicateXORemover(JsProgram program, Set<JsFunction> alreadyCalled) {
       this.program = program;
-      called = new HashSet<JsName>(alreadyCalled);
+      called = new HashSet<JsFunction>(alreadyCalled);
     }
 
     /**
@@ -424,9 +424,10 @@
      */
     @Override
     public boolean visit(JsInvocation x, JsContext<JsExpression> ctx) {
-      JsName name = isExecuteOnce(x);
-      if (name != null) {
-        called.add(name);
+      JsFunction func = isExecuteOnce(x);
+      while (func != null) {
+        called.add(func);
+        func = func.getImpliedExecute();
       }
       return true;
     }
@@ -464,8 +465,8 @@
         return false;
       }
 
-      JsName name = isExecuteOnce((JsInvocation) x);
-      return (name != null && called.contains(name));
+      JsFunction func = isExecuteOnce((JsInvocation) x);
+      return (func != null && called.contains(func));
     }
   }
 
@@ -1339,10 +1340,10 @@
    * Given a JsInvocation, determine if it is invoking a JsFunction that is
    * specified to be executed only once during the program's lifetime.
    */
-  private static JsName isExecuteOnce(JsInvocation invocation) {
+  private static JsFunction isExecuteOnce(JsInvocation invocation) {
     JsFunction f = isFunction(invocation.getQualifier());
     if (f != null && f.getExecuteOnce()) {
-      return f.getName();
+      return f;
     }
     return null;
   }
diff --git a/dev/core/src/com/google/gwt/dev/js/ast/JsFunction.java b/dev/core/src/com/google/gwt/dev/js/ast/JsFunction.java
index a9c93d4..2a37d08 100644
--- a/dev/core/src/com/google/gwt/dev/js/ast/JsFunction.java
+++ b/dev/core/src/com/google/gwt/dev/js/ast/JsFunction.java
@@ -26,9 +26,10 @@
   protected JsBlock body;
   protected final List<JsParameter> params = new ArrayList<JsParameter>();
   protected final JsScope scope;
-  private JsName name;
-  private boolean fromJava;
   private boolean executeOnce;
+  private boolean fromJava;
+  private JsFunction impliedExecute;
+  private JsName name;
 
   /**
    * Creates an anonymous function.
@@ -69,6 +70,10 @@
     return executeOnce;
   }
 
+  public JsFunction getImpliedExecute() {
+    return impliedExecute;
+  }
+
   public JsName getName() {
     return name;
   }
@@ -97,6 +102,10 @@
     this.fromJava = fromJava;
   }
 
+  public void setImpliedExecute(JsFunction impliedExecute) {
+    this.impliedExecute = impliedExecute;
+  }
+
   public void setName(JsName name) {
     this.name = name;
     if (name != null) {