Author: [EMAIL PROTECTED]
Date: Sat Oct 18 19:42:21 2008
New Revision: 3784

Modified:
     
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
     
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
     
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
     
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
     
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
     
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
     
changes/spoon/runAsync/user/src/com/google/gwt/core/client/AsyncFragmentLoader.java

Log:
CodeSplitter now generates separate fragments for the
"base" fragment of initially needed code and the "leftovers"
fragment for all code that has no other particular fragment
to be placed in.  Before this patch, both categories
of code were combined into the base fragment.

Modified:  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java
==============================================================================
---  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java   
 
(original)
+++  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/ast/JVariable.java   
 
Sat Oct 18 19:42:21 2008
@@ -43,6 +43,10 @@
      }
      return null;
    }
+
+  public JDeclarationStatement getDeclarationStatement() {
+    return declStmt;
+  }

    public JExpression getInitializer() {
      if (declStmt != null) {

Modified:  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
==============================================================================
---  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
        
(original)
+++  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
        
Sat Oct 18 19:42:21 2008
@@ -25,6 +25,7 @@
  import com.google.gwt.dev.jjs.ast.JReferenceType;
  import com.google.gwt.dev.jjs.ast.JStringLiteral;
  import com.google.gwt.dev.jjs.ast.JVisitor;
+import com.google.gwt.dev.jjs.impl.FragmentExtractor.CfaLivenessPredicate;
  import com.google.gwt.dev.jjs.impl.FragmentExtractor.LivenessPredicate;
  import com.google.gwt.dev.jjs.impl.FragmentExtractor.NothingAlivePredicate;
  import com.google.gwt.dev.jjs.impl.FragmentExtractor.StatementLogger;
@@ -76,7 +77,8 @@
    }

    /**
-   * A map from program atoms to the fragment they should be placed in.
+   * A map from program atoms to the fragment they should be placed in. An  
entry
+   * of 0 means it did not go into any fragment in particular.
     */
    private static class FragmentMap {
      public Map<JField, Integer> fields = new HashMap<JField, Integer>();
@@ -149,6 +151,18 @@
      return (value == null) ? 0 : value;
    }

+  private static Set<String> stringsIn(JExpression exp) {
+    final Set<String> strings = new HashSet<String>();
+    class StringFinder extends JVisitor {
+      @Override
+      public void endVisit(JStringLiteral stringLiteral, Context ctx) {
+        strings.add(stringLiteral.getValue());
+      }
+    }
+    (new StringFinder()).accept(exp);
+    return strings;
+  }
+
    private static <T> void updateMap(int entry, Map<T, Integer> map,
        Set<?> liveWithoutEntry, Iterable<T> all) {
      for (T each : all) {
@@ -223,23 +237,39 @@
      PerfLogger.start("CodeSplitter");

      FragmentMap fragmentMap = mapFragments();
+    ControlFlowAnalyzer initiallyLive = new ControlFlowAnalyzer(jprogram);
+    traverseEntry(initiallyLive, 0);
+    initiallyLive.finishTraversal();

      List<List<JsStatement>> fragmentStats = new  
ArrayList<List<JsStatement>>(
-        numEntries);
+        numEntries + 1);

      FragmentExtractor fragmentExtractor = new FragmentExtractor(jprogram,
          jsprogram, map);
-    if (logging) {
-    }

-    for (int i = 0; i < numEntries; i++) {
-      LivenessPredicate pred = new  
FragmentMapLivenessPredicate(fragmentMap, i);
-
-      LivenessPredicate alreadyLoaded;
+    for (int i = 0; i <= numEntries; i++) {
+      LivenessPredicate alreadyLoaded, pred;
        if (i == 0) {
+        /*
+         * The base fragment. It includes everything that is live when the
+         * program starts.
+         */
          alreadyLoaded = new NothingAlivePredicate();
+        pred = new CfaLivenessPredicate(initiallyLive);
+      } else if (i == numEntries) {
+        /*
+         * The leftovers fragment. It includes everything mapped to 0  
except for
+         * things that are initially live.
+         */
+        alreadyLoaded = new CfaLivenessPredicate(initiallyLive);
+        pred = new FragmentMapLivenessPredicate(fragmentMap, 0);
        } else {
+        /*
+         * An exclusively live fragment. It includes everything  
exclusively live
+         * after entry point i.
+         */
          alreadyLoaded = new FragmentMapLivenessPredicate(fragmentMap, 0);
+        pred = new FragmentMapLivenessPredicate(fragmentMap, i);
        }

        if (logging) {
@@ -248,18 +278,20 @@
          fragmentExtractor.setStatementLogger(new EchoStatementLogger());
        }

-      List<JsStatement> entryStats =  
fragmentExtractor.extractStatements(pred,
+      List<JsStatement> stats = fragmentExtractor.extractStatements(pred,
            alreadyLoaded);

-      if (i > 0) {
-        fragmentExtractor.addCallsToEntryMethods(i, entryStats);
+      if (i == numEntries) {
+        fragmentExtractor.addCallToLeftoversFragmentHasLoaded(stats);
+      } else if (i > 0) {
+        fragmentExtractor.addCallsToEntryMethods(i, stats);
        }

-      fragmentStats.add(entryStats);
+      fragmentStats.add(stats);
      }

      // now install the new statements in the program fragments
-    jsprogram.setFragmentCount(numEntries);
+    jsprogram.setFragmentCount(numEntries + 1);
      for (int i = 0; i < fragmentStats.size(); i++) {
        JsBlock fragBlock = jsprogram.getFragmentBlock(i);
        fragBlock.getStatements().clear();
@@ -354,18 +386,6 @@
      return fragmentMap;
    }

-  private Set<String> stringsIn(JExpression exp) {
-    final Set<String> strings = new HashSet<String>();
-    class StringFinder extends JVisitor {
-      @Override
-      public void endVisit(JStringLiteral stringLiteral, Context ctx) {
-        strings.add(stringLiteral.getValue());
-      }
-    }
-    (new StringFinder()).accept(exp);
-    return strings;
-  }
-
    /**
     * Traverse all code in the program except for that reachable only via
     * fragment <code>frag</code>. This does not call
@@ -384,15 +404,15 @@
     * <code>frag</code>. This does not call
     * [EMAIL PROTECTED] ControlFlowAnalyzer#finishTraversal()}.
     */
-  private void traverseEntry(ControlFlowAnalyzer cfa, int entry) {
-    for (JMethod entryMethod : jprogram.entryMethods.get(entry)) {
+  private void traverseEntry(ControlFlowAnalyzer cfa, int splitPoint) {
+    for (JMethod entryMethod : jprogram.entryMethods.get(splitPoint)) {
        cfa.traverseFrom(entryMethod);
      }
-    if (entry == 0) {
+    if (splitPoint == 0) {
        /*
         * Include class literal factories for simplicity. It is possible to  
move
         * them out, if they are only needed by one fragment, but they are  
tiny,
-       * so it does not look like it is worth the complexity in the  
compiler.
+       * so it does not seem worth the complexity in the compiler.
         */
        cfa.traverseFromClassLiteralFactories();
      }

Modified:  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
==============================================================================
---  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
   
(original)
+++  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java
   
Sat Oct 18 19:42:21 2008
@@ -183,8 +183,8 @@
    }

    /**
-       * Add direct calls to the entry methods of the specified entry  
number.
-       */
+   * Add direct calls to the entry methods of the specified entry number.
+   */
    public void addCallsToEntryMethods(int entry, List<JsStatement> stats) {
      for (JMethod entryMethod : jprogram.entryMethods.get(entry)) {
        JsName name = map.nameForMethod(entryMethod);
@@ -197,6 +197,16 @@
      }
    }

+  public void addCallToLeftoversFragmentHasLoaded(List<JsStatement> stats)  
{
+    JMethod loadedMethod =  
jprogram.getIndexedMethod("AsyncFragmentLoader.leftoversFragmentHasLoaded");
+    JsName loadedMethodName = map.nameForMethod(loadedMethod);
+    SourceInfo sourceInfo = jsprogram.getSourceInfo().makeChild(
+        "call to leftoversFragmentHasLoaded ");
+    JsInvocation call = new JsInvocation(sourceInfo);
+    call.setQualifier(loadedMethodName.makeRef(sourceInfo));
+    stats.add(call.makeStmt());
+  }
+
    /**
     * Assume that all code described by <code>alreadyLoadedPredicate</code>  
has
     * been downloaded. Extract enough JavaScript statements that the code
@@ -259,6 +269,13 @@
      entryMethodNames = new HashSet<JsName>();
      for (JMethod entryMethod : jprogram.getAllEntryMethods()) {
        JsName name = map.nameForMethod(entryMethod);
+      assert name != null;
+      entryMethodNames.add(name);
+    }
+
+    JMethod leftoverFragmentLoaded =  
jprogram.getIndexedMethod("AsyncFragmentLoader.leftoverFragmentHasLoaded");
+    if (leftoverFragmentLoaded != null) {
+      JsName name = map.nameForMethod(leftoverFragmentLoaded);
        assert name != null;
        entryMethodNames.add(name);
      }

Modified:  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
==============================================================================
---  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
       
(original)
+++  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
       
Sat Oct 18 19:42:21 2008
@@ -1022,9 +1022,19 @@
        /*
         * Add calls to all split points other than the initial ones. That  
way, if
         * the code splitter does not run, the resulting code will still  
function.
+       * Likewise, add a call to  
AsyncFragmentLoader.leftoversFragmentHasLoaded().
         */
        List<JsFunction> nonInitialEntries =  
Arrays.asList(entryFunctions).subList(
            x.getEntryCount(0), entryFunctions.length);
+      if (!nonInitialEntries.isEmpty()) {
+        JMethod loadedMethod =  
program.getIndexedMethod("AsyncFragmentLoader.leftoversFragmentHasLoaded");
+        JsName loadedMethodName = names.get(loadedMethod);
+        SourceInfo sourceInfo = jsProgram.getSourceInfo().makeChild(
+            "call to leftoversFragmentHasLoaded ");
+        JsInvocation call = new JsInvocation(sourceInfo);
+        call.setQualifier(loadedMethodName.makeRef(sourceInfo));
+        globalStmts.add(call.makeStmt());
+      }
        for (JsFunction func : nonInitialEntries) {
          if (func != null) {
            SourceInfo sourceInfo = jsProgram.getSourceInfo().makeChild(

Modified:  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java
==============================================================================
---  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java     
 
(original)
+++  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/Pruner.java     
 
Sat Oct 18 19:42:21 2008
@@ -462,6 +462,9 @@
        for (JMethod method : program.getAllEntryMethods()) {
          livenessAnalyzer.traverseFrom(method);
        }
+      if (program.entryMethods.size() > 1) {
+         
livenessAnalyzer.traverseFrom(program.getIndexedMethod("AsyncFragmentLoader.leftoversFragmentHasLoaded"));
+      }
        livenessAnalyzer.finishTraversal();

         
program.typeOracle.setInstantiatedTypes(livenessAnalyzer.getInstantiatedTypes());
@@ -483,5 +486,4 @@
      }
      return madeChanges;
    }
-
  }

Modified:  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
==============================================================================
---  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
    
(original)
+++  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
    
Sat Oct 18 19:42:21 2008
@@ -19,6 +19,7 @@
  import com.google.gwt.dev.jjs.ast.Context;
  import com.google.gwt.dev.jjs.ast.JClassType;
  import com.google.gwt.dev.jjs.ast.JExpression;
+import com.google.gwt.dev.jjs.ast.JField;
  import com.google.gwt.dev.jjs.ast.JMethod;
  import com.google.gwt.dev.jjs.ast.JMethodCall;
  import com.google.gwt.dev.jjs.ast.JModVisitor;
@@ -83,6 +84,7 @@
    private int execImpl() {
      AsyncCreateVisitor visitor = new AsyncCreateVisitor();
      visitor.accept(program);
+    setNumEntriesInAsyncFragmentLoader(visitor.entryCount);
      return visitor.entryCount;
    }

@@ -122,5 +124,10 @@
        }
      }
      return null;
+  }
+
+  private void setNumEntriesInAsyncFragmentLoader(int entryCount) {
+    JField field =  
program.getIndexedField("AsyncFragmentLoader.numEntries");
+    field.getDeclarationStatement().initializer =  
program.getLiteralInt(entryCount);
    }
  }

Modified:  
changes/spoon/runAsync/user/src/com/google/gwt/core/client/AsyncFragmentLoader.java
==============================================================================
---  
changes/spoon/runAsync/user/src/com/google/gwt/core/client/AsyncFragmentLoader.java
      
(original)
+++  
changes/spoon/runAsync/user/src/com/google/gwt/core/client/AsyncFragmentLoader.java
      
Sat Oct 18 19:42:21 2008
@@ -18,12 +18,38 @@
  import com.google.gwt.user.client.DOM;
  import com.google.gwt.user.client.Element;

+import java.util.LinkedList;
+import java.util.Queue;
+
  /**
   * Low-level support to download an extra fragment of code. This should  
not be
   * invoked directly by user code.
   */
  public class AsyncFragmentLoader {
    /**
+   * Whether the leftovers fragment has loaded yet.
+   */
+  private static boolean leftoversLoaded = false;
+
+  /**
+   * Whether the leftovers fragment is currently loading.
+   */
+  private static boolean leftoversLoading = false;
+
+  /**
+   * The total number of split points in the program, counting the initial  
entry
+   * as a split point. This is changed to the correct value by
+   * [EMAIL PROTECTED] com.google.gwt.dev.jjs.impl.ReplaceRunAsyncs}.
+   */
+  private static int numEntries = 1;
+
+  /**
+   * Split points that have been reached, but that cannot be downloaded
+   * until the leftovers fragment finishes downloading.
+   */
+  private static Queue<Integer> waitingForLeftovers = new  
LinkedList<Integer>();
+
+  /**
     * Inform the loader that the code for an entry point has now finished
     * loading.
     *
@@ -39,14 +65,26 @@
     * @param fragment the fragment to load
     */
    public static void inject(int fragment) {
-    logEventProgress("download" + fragment, "begin");
+    if (leftoversLoaded) {
+      startDownloadingFragment(fragment);
+    } else {
+      waitingForLeftovers.add(fragment);
+      if (!leftoversLoading) {
+        leftoversLoading = true;
+        startDownloadingFragment(numEntries);
+      }
+    }
+  }

-    Element head = getHeadElement();
-    Element script = createScriptElement();
-    DOM.setElementAttribute(script, "type", "text/javascript");
-    String src = getFragmentName(fragment);
-    DOM.setElementAttribute(script, "src", src);
-    DOM.appendChild(head, script);
+  /**
+   * Inform the loader that the "leftovers" fragment has loaded.
+   */
+  public static void leftoversFragmentHasLoaded() {
+    leftoversLoaded = true;
+    leftoversLoading = false;
+    while (!waitingForLeftovers.isEmpty()) {
+      inject(waitingForLeftovers.remove());
+    }
    }

    /**
@@ -92,6 +130,17 @@
    private static native boolean isStatsAvailable() /*-{
      return !!$stats;
    }-*/;
+
+  private static void startDownloadingFragment(int fragment) {
+    logEventProgress("download" + fragment, "begin");
+
+    Element head = getHeadElement();
+    Element script = createScriptElement();
+    DOM.setElementAttribute(script, "type", "text/javascript");
+    String src = getFragmentName(fragment);
+    DOM.setElementAttribute(script, "src", src);
+    DOM.appendChild(head, script);
+  }

    /**
     * Always use this as [EMAIL PROTECTED] isStatsAvailable} &amp;&amp;

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

Reply via email to