Author: [EMAIL PROTECTED]
Date: Tue Nov 11 07:29:02 2008
New Revision: 4015

Modified:
    trunk/dev/core/src/com/google/gwt/dev/GWTCompiler.java
    trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
    trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
    trunk/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java

Log:
Removes UpRefVisitor from ControlFlowAnalyzer, which scans the whole
program to find extra methods that need rescuing due to virtual
method calls.  Instead, such methods are now checked at the
time a new method or type becomes instantiable.

Also, adds PerfLogger calls to GWTCompiler, to make it easy to time
an entire compile.

Review by: scottb


Modified: trunk/dev/core/src/com/google/gwt/dev/GWTCompiler.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/GWTCompiler.java      (original)
+++ trunk/dev/core/src/com/google/gwt/dev/GWTCompiler.java      Tue Nov 11  
07:29:02 2008
@@ -20,6 +20,7 @@
  import com.google.gwt.dev.CompilePerms.CompilePermsOptionsImpl;
  import com.google.gwt.dev.CompileTaskRunner.CompileTask;
  import com.google.gwt.dev.Precompile.PrecompileOptionsImpl;
+import com.google.gwt.dev.util.PerfLogger;
  import com.google.gwt.dev.util.arg.ArgHandlerExtraDir;

  import java.io.File;
@@ -100,6 +101,7 @@
      if (options.isValidateOnly()) {
        return new Precompile(options).run(logger);
      } else {
+      PerfLogger.start("compile");
        logger = logger.branch(TreeLogger.INFO, "Compiling module "
            + options.getModuleName());
        if (new Precompile(options).run(logger)) {
@@ -112,11 +114,13 @@
          if (new CompilePerms(permsOptions).run(logger)) {
            if (new Link(options).run(logger)) {
              logger.log(TreeLogger.INFO, "Compilation succeeded");
+            PerfLogger.end();
              return true;
            }
          }
        }
        logger.log(TreeLogger.ERROR, "Compilation failed");
+      PerfLogger.end();
        return false;
      }
    }

Modified: trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java     
(original)
+++ trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java    Tue  
Nov 11 07:29:02 2008
@@ -267,7 +267,6 @@

      initiallyLive = new ControlFlowAnalyzer(jprogram);
      traverseEntry(initiallyLive, 0);
-    initiallyLive.finishTraversal();

      methodsInJavaScript = fragmentExtractor.findAllMethodsInJavaScript();
    }
@@ -310,7 +309,6 @@
        // Traverse leftoversFragmentHasLoaded, because it should not
        // go into any of the exclusive fragments.
        cfa.traverseFromLeftoversFragmentHasLoaded();
-      cfa.finishTraversal();
        allButOnes.add(cfa);
      }

@@ -326,7 +324,6 @@
        traverseEntry(everything, entry);
      }
      everything.traverseFromLeftoversFragmentHasLoaded();
-    everything.finishTraversal();
      return everything;
    }

@@ -368,7 +365,6 @@
      for (int base = 1; base < numEntries; base++) {
        ControlFlowAnalyzer baseCfa = new ControlFlowAnalyzer(initiallyLive);
        traverseEntry(baseCfa, base);
-      baseCfa.finishTraversal();
        LivenessPredicate baseLive = new CfaLivenessPredicate(baseCfa);

        // secondary base

Modified:  
trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java     
 
(original)
+++ trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java     
 
Tue Nov 11 07:29:02 2008
@@ -57,15 +57,15 @@
  import com.google.gwt.dev.js.ast.JsVisitor;

  import java.util.ArrayList;
+import java.util.HashMap;
  import java.util.HashSet;
  import java.util.List;
+import java.util.Map;
  import java.util.Set;

  /**
   * This class finds out what code in a program is live based on starting
- * execution at a specified location. Note that the client must call
- * [EMAIL PROTECTED] #finishTraversal()} after the other traversal methods 
have been
- * called, or the results will be incomplete.
+ * execution at a specified location.
   */
  public class ControlFlowAnalyzer {

@@ -182,7 +182,7 @@
        // Rescue my super type
        rescue(type.extnds, true, isInstantiated);

-      // Rescue my clinit (it won't ever be explicitly referenced
+      // Rescue my clinit (it won't ever be explicitly referenced)
        rescue(type.methods.get(0));

        // JLS 12.4.1: don't rescue my super interfaces just because I'm  
rescued.
@@ -192,6 +192,8 @@
          rescue(intfType, false, isInstantiated);
        }

+      rescueMethodsIfInstantiable(type);
+
        return false;
      }

@@ -256,6 +258,8 @@
          accept(it);
        }

+      rescueMethodsIfInstantiable(type);
+
        return false;
      }

@@ -305,7 +309,18 @@

      @Override
      public boolean visit(JMethodCall call, Context ctx) {
-      rescue(call.getTarget());
+      JMethod method = call.getTarget();
+      if (method.isStatic()
+          || program.isJavaScriptObject(method.getEnclosingType())
+          || instantiatedTypes.contains(method.getEnclosingType())) {
+        rescue(method);
+      } else {
+        // It's a virtual method whose class is not instantiable
+        if (!liveFieldsAndMethods.contains(method)) {
+          methodsLiveExceptForInstantiability.add(method);
+        }
+      }
+
        return true;
      }

@@ -448,7 +463,10 @@
        if (method != null) {
          if (!liveFieldsAndMethods.contains(method)) {
            liveFieldsAndMethods.add(method);
+          methodsLiveExceptForInstantiability.remove(method);
+
            accept(method);
+
            if (method.isNative()) {
              /*
               * SPECIAL: returning from this method passes a value from
@@ -456,6 +474,9 @@
               */
              maybeRescueJavaScriptObjectPassingIntoJava(method.getType());
            }
+
+          rescueOverridingMethods(method);
+
            return true;
          }
        }
@@ -528,57 +549,72 @@
          rescue(stringValueOfChar);
        }
      }
-  }
-
-  /**
-   * Traverse methods that are reachable via virtual method calls.  
Specifically,
-   * traverse methods whose classes are instantiable and which override a  
method
-   * that is live.
-   */
-  private class UpRefVisitor extends JVisitor {
-
-    private boolean didRescue = false;
-
-    public boolean didRescue() {
-      return didRescue;
-    }

-    @Override
-    public boolean visit(JClassType x, Context ctx) {
-      return instantiatedTypes.contains(x);
+    /**
+     * If the type is instantiable, rescue any of its virtual methods that  
a
+     * previously seen method call could call.
+     */
+    private void rescueMethodsIfInstantiable(JReferenceType type) {
+      if (instantiatedTypes.contains(type)) {
+        for (JMethod method : type.methods) {
+          if (!method.isStatic()) {
+            if (methodsLiveExceptForInstantiability.contains(method)) {
+              rescue(method);
+              continue;
+            }
+          }
+        }
+      }
      }

-    @Override
-    public boolean visit(JMethod x, Context ctx) {
-      if (liveFieldsAndMethods.contains(x)) {
-        return false;
-      }
+    /**
+     * Assume that <code>method</code> is live. Rescue any overriding  
methods
+     * that might be called if <code>method</code> is called through  
virtual
+     * dispatch.
+     */
+    private void rescueOverridingMethods(JMethod method) {
+      if (!method.isStatic()) {

-      for (JMethod override : program.typeOracle.getAllOverrides(x)) {
-        if (liveFieldsAndMethods.contains(override)) {
-          rescuer.rescue(x);
-          didRescue = true;
-          return false;
+        List<JMethod> overriders = methodsThatOverrideMe.get(method);
+        if (overriders != null) {
+          for (JMethod overrider : overriders) {
+            if (liveFieldsAndMethods.contains(overrider)) {
+              // The override is already alive, do nothing.
+            } else if  
(instantiatedTypes.contains(overrider.getEnclosingType())) {
+              // The enclosing class is alive, make my override reachable.
+              rescue(overrider);
+            } else {
+              // The enclosing class is not yet alive, put override in  
limbo.
+              methodsLiveExceptForInstantiability.add(overrider);
+            }
+          }
          }
        }
-      return false;
-    }
-
-    @Override
-    public boolean visit(JProgram x, Context ctx) {
-      didRescue = false;
-      return true;
      }
    }

    private Set<JReferenceType> instantiatedTypes = new  
HashSet<JReferenceType>();
    private Set<JNode> liveFieldsAndMethods = new HashSet<JNode>();
    private Set<String> liveStrings = new HashSet<String>();
+
+  /**
+   * Schrodinger's methods... aka "limbo". :) These are instance methods  
that
+   * seem to be reachable, only their enclosing type is uninstantiable. We  
place
+   * these methods into purgatory until/unless the enclosing type is found  
to be
+   * instantiable.
+   */
+  private Set<JMethod> methodsLiveExceptForInstantiability = new  
HashSet<JMethod>();
+
+  /**
+   * A precomputed map of all instance methods onto a set of methods that
+   * override each key method.
+   */
+  private Map<JMethod, List<JMethod>> methodsThatOverrideMe;
+
    private final JProgram program;
    private Set<JReferenceType> referencedTypes = new  
HashSet<JReferenceType>();
    private final RescueVisitor rescuer = new RescueVisitor();
    private JMethod stringValueOfChar = null;
-  private final UpRefVisitor upRefer = new UpRefVisitor();

    public ControlFlowAnalyzer(ControlFlowAnalyzer cfa) {
      program = cfa.program;
@@ -587,21 +623,14 @@
      referencedTypes = new HashSet<JReferenceType>(cfa.referencedTypes);
      stringValueOfChar = cfa.stringValueOfChar;
      liveStrings = new HashSet<String>(cfa.liveStrings);
+    methodsLiveExceptForInstantiability = new HashSet<JMethod>(
+        cfa.methodsLiveExceptForInstantiability);
+    methodsThatOverrideMe = cfa.methodsThatOverrideMe;
    }

    public ControlFlowAnalyzer(JProgram program) {
      this.program = program;
-  }
-
-  /**
-   * Finish any remaining traversal that is needed. This must be called  
after
-   * calling any of the other traversal methods in order to get accurate
-   * results. It can also be called eagerly.
-   */
-  public void finishTraversal() {
-    do {
-      upRefer.accept(program);
-    } while (upRefer.didRescue());
+    buildMethodsOverriding();
    }

    /**
@@ -653,9 +682,7 @@
      class ReplaceStringLiterals extends JModVisitor {
        @Override
        public void endVisit(JStringLiteral stringLiteral, Context ctx) {
-        ctx.replaceMe(program.getLiteralString(
-             
stringLiteral.getSourceInfo().makeChild(ControlFlowAnalyzer.class,
-                "remove string literals"), ""));
+        ctx.replaceMe(program.getLiteralNull());
        }
      }

@@ -682,5 +709,21 @@

    public void traverseFromReferenceTo(JReferenceType type) {
      rescuer.rescue(type, true, false);
+  }
+
+  private void buildMethodsOverriding() {
+    methodsThatOverrideMe = new HashMap<JMethod, List<JMethod>>();
+    for (JReferenceType type : program.getDeclaredTypes()) {
+      for (JMethod method : type.methods) {
+        for (JMethod overridden :  
program.typeOracle.getAllOverrides(method)) {
+          List<JMethod> overs = methodsThatOverrideMe.get(overridden);
+          if (overs == null) {
+            overs = new ArrayList<JMethod>();
+            methodsThatOverrideMe.put(overridden, overs);
+          }
+          overs.add(method);
+        }
+      }
+    }
    }
  }

Modified: trunk/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
==============================================================================
--- trunk/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java  (original)
+++ trunk/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java  Tue Nov 11  
07:29:02 2008
@@ -463,7 +463,6 @@
          livenessAnalyzer.traverseFrom(method);
        }
        livenessAnalyzer.traverseFromLeftoversFragmentHasLoaded();
-      livenessAnalyzer.finishTraversal();

         
program.typeOracle.setInstantiatedTypes(livenessAnalyzer.getInstantiatedTypes());


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

Reply via email to