Author: [EMAIL PROTECTED]
Date: Sat Oct 18 17:16:09 2008
New Revision: 3783

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/ControlFlowAnalyzer.java
     
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentExtractor.java

Log:
Updates CodeSplitter to more thoroughly address
load-order dependencies.  For example, no type's
JS prototype is emitted except in a conext where
its superty's JS prototype is known to have already
been loaded.

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 17:16:09 2008
@@ -15,11 +15,16 @@
   */
  package com.google.gwt.dev.jjs.impl;

+import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
+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.JNode;
  import com.google.gwt.dev.jjs.ast.JProgram;
  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.LivenessPredicate;
  import com.google.gwt.dev.jjs.impl.FragmentExtractor.NothingAlivePredicate;
  import com.google.gwt.dev.jjs.impl.FragmentExtractor.StatementLogger;
@@ -36,7 +41,9 @@
  import java.util.HashSet;
  import java.util.List;
  import java.util.Map;
+import java.util.Queue;
  import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;

  /**
   * Divides a [EMAIL PROTECTED] JsProgram} into separate fragments. All access 
to code  
in a
@@ -137,6 +144,11 @@
      new CodeSplitter(jprogram, jsprogram, map).execImpl();
    }

+  private static <T> int getOrZero(Map<T, Integer> map, T key) {
+    Integer value = map.get(key);
+    return (value == null) ? 0 : value;
+  }
+
    private static <T> void updateMap(int entry, Map<T, Integer> map,
        Set<?> liveWithoutEntry, Iterable<T> all) {
      for (T each : all) {
@@ -153,6 +165,7 @@
      }
    }

+  private final Map<JField, JClassLiteral> fieldToLiteralOfClass;
    private JProgram jprogram;
    private JsProgram jsprogram;
    private final boolean logging;
@@ -166,6 +179,7 @@
      this.map = map;
      numEntries = jprogram.entryMethods.size();
      logging = Boolean.getBoolean(PROP_LOG_FRAGMENT_MAP);
+    fieldToLiteralOfClass =  
FragmentExtractor.buildFieldToClassLiteralMap(jprogram);
    }

    /**
@@ -255,8 +269,49 @@
      PerfLogger.end();
    }

+  private void fixUpLoadOrderDependencies(FragmentMap fragmentMap) {
+    fixUpLoadOrderDependenciesForTypes(fragmentMap);
+    fixUpLoadOrderDependenciesForClassLiterals(fragmentMap);
+  }
+
+  private void fixUpLoadOrderDependenciesForClassLiterals(
+      FragmentMap fragmentMap) {
+    for (JField field : fragmentMap.fields.keySet()) {
+      JClassLiteral classLit = fieldToLiteralOfClass.get(field);
+      if (classLit != null) {
+        int classLitFrag = fragmentMap.fields.get(field);
+        if (classLitFrag != 0) {
+          for (String string : stringsIn(field.getInitializer())) {
+            int stringFrag = getOrZero(fragmentMap.strings, string);
+            if (stringFrag != classLitFrag && stringFrag != 0) {
+              fragmentMap.strings.put(string, 0);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  private void fixUpLoadOrderDependenciesForTypes(FragmentMap fragmentMap)  
{
+    Queue<JReferenceType> typesToCheck = new  
ArrayBlockingQueue<JReferenceType>(
+        jprogram.getDeclaredTypes().size());
+    typesToCheck.addAll(jprogram.getDeclaredTypes());
+    while (!typesToCheck.isEmpty()) {
+      JReferenceType type = typesToCheck.remove();
+      if (type.extnds != null) {
+        int typeFrag = getOrZero(fragmentMap.types, type);
+        int supertypeFrag = getOrZero(fragmentMap.types, type.extnds);
+        if (typeFrag != supertypeFrag && supertypeFrag != 0) {
+          fragmentMap.types.put(type.extnds, 0);
+          typesToCheck.add(type.extnds);
+        }
+      }
+    }
+  }
+
    private void mapExclusiveAtoms(FragmentMap fragmentMap) {
      List<ControlFlowAnalyzer> allButOnes = computeAllButOneCfas();
+
      ControlFlowAnalyzer everything = computeCompleteCfa();

      Set<JField> allFields = new HashSet<JField>();
@@ -285,56 +340,6 @@
    }

    /**
-   * Make sure that all field initializers can run in their specified  
fragment.
-   * To do this, trace the code needed by each initializer, and make sure  
it is
-   * either in 0 or in the same entry point as the field itself.
-   */
-  private void mapFieldInitializerCode(FragmentMap fragmentMap) {
-    ControlFlowAnalyzer initiallyLive = new ControlFlowAnalyzer(jprogram);
-    traverseEntry(initiallyLive, 0);
-    initiallyLive.finishTraversal();
-
-    // Note: do split point 0 last, to account for any fields moved to it
-    for (int splitPoint = numEntries - 1; splitPoint >= 0; splitPoint--) {
-      ControlFlowAnalyzer neededByFields = initiallyLive.clone();
-      for (JField field : fragmentMap.fields.keySet()) {
-        if (fragmentMap.fields.get(field) == splitPoint) {
-          if (field.getInitializer() != null) {
-            neededByFields.traverseFrom(field.getInitializer());
-          }
-        }
-      }
-      neededByFields.finishTraversal();
-      for (JNode node : neededByFields.getLiveFieldsAndMethods()) {
-        if (node instanceof JField) {
-          if (!fragmentMap.fields.containsKey(node)
-              || (fragmentMap.fields.get(node) != splitPoint)) {
-            fragmentMap.fields.put((JField) node, 0);
-          }
-        }
-        if (node instanceof JMethod) {
-          if (!fragmentMap.methods.containsKey(node)
-              || (fragmentMap.methods.get(node) != splitPoint)) {
-            fragmentMap.methods.put((JMethod) node, 0);
-          }
-        }
-      }
-      for (String string : neededByFields.getLiveStrings()) {
-        if (!fragmentMap.strings.containsKey(string)
-            || (fragmentMap.strings.get(string) != splitPoint)) {
-          fragmentMap.strings.put(string, 0);
-        }
-      }
-      for (JReferenceType type : neededByFields.getInstantiatedTypes()) {
-        if (!fragmentMap.types.containsKey(type)
-            || (fragmentMap.types.get(type) != splitPoint)) {
-          fragmentMap.types.put(type, 0);
-        }
-      }
-    }
-  }
-
-  /**
     * Map each program atom to a fragment. Atoms are mapped to a non-zero
     * fragment whenever they are known not to be needed whenever that  
fragment's
     * split point has not been reached. Any atoms that cannot be so mapped  
are
@@ -344,10 +349,23 @@
      FragmentMap fragmentMap = new FragmentMap();

      mapExclusiveAtoms(fragmentMap);
-    mapFieldInitializerCode(fragmentMap);
+    fixUpLoadOrderDependencies(fragmentMap);
+
      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
@@ -369,6 +387,14 @@
    private void traverseEntry(ControlFlowAnalyzer cfa, int entry) {
      for (JMethod entryMethod : jprogram.entryMethods.get(entry)) {
        cfa.traverseFrom(entryMethod);
+    }
+    if (entry == 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.
+       */
+      cfa.traverseFromClassLiteralFactories();
      }
    }
  }

Modified:  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
==============================================================================
---  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
         
(original)
+++  
changes/spoon/runAsync/dev/core/src/com/google/gwt/dev/jjs/impl/ControlFlowAnalyzer.java
         
Sat Oct 18 17:16:09 2008
@@ -32,6 +32,7 @@
  import com.google.gwt.dev.jjs.ast.JLocalRef;
  import com.google.gwt.dev.jjs.ast.JMethod;
  import com.google.gwt.dev.jjs.ast.JMethodCall;
+import com.google.gwt.dev.jjs.ast.JModVisitor;
  import com.google.gwt.dev.jjs.ast.JNewArray;
  import com.google.gwt.dev.jjs.ast.JNewInstance;
  import com.google.gwt.dev.jjs.ast.JNode;
@@ -650,15 +651,32 @@
    }

    /**
-   * Traverse from all class literals anywhere in the program.
+   * Trace all code needed by class literal constructor expressions except  
for
+   * the string literals they include. At the time of writing, these would
+   * include the factory methods for class literals.
     */
-  public void traverseFromClassLiterals() {
+  public void traverseFromClassLiteralFactories() {
+    class ReplaceStringLiterals extends JModVisitor {
+      @Override
+      public void endVisit(JStringLiteral stringLiteral, Context ctx) {
+        ctx.replaceMe(program.getLiteralString(
+            stringLiteral.getSourceInfo().makeChild("remove string  
literals"),
+            ""));
+      }
+    }
+
+    final JModVisitor stringLiteralReplacer = new ReplaceStringLiterals();
+    final CloneExpressionVisitor cloner = new  
CloneExpressionVisitor(program);
+
      class ClassLitTraverser extends JVisitor {
        @Override
        public void endVisit(JClassLiteral classLiteral, Context ctx) {
-        rescuer.accept(classLiteral);
+        JExpression initializer = classLiteral.getField().getInitializer();
+        JExpression initializerWithoutStrings =  
stringLiteralReplacer.accept(cloner.cloneExpression(initializer));
+        rescuer.accept(initializerWithoutStrings);
        }
      }
+
      (new ClassLitTraverser()).accept(program);
    }


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 17:16:09 2008
@@ -22,7 +22,6 @@
  import com.google.gwt.dev.jjs.ast.JMethod;
  import com.google.gwt.dev.jjs.ast.JProgram;
  import com.google.gwt.dev.jjs.ast.JReferenceType;
-import com.google.gwt.dev.jjs.ast.JType;
  import com.google.gwt.dev.jjs.ast.JVisitor;
  import com.google.gwt.dev.js.ast.JsBinaryOperation;
  import com.google.gwt.dev.js.ast.JsBinaryOperator;
@@ -143,11 +142,22 @@
      }
    }

-  private Set<JsName> entryMethodNames;
+  public static Map<JField, JClassLiteral> buildFieldToClassLiteralMap(
+      JProgram jprogram) {
+    final Map<JField, JClassLiteral> map = new HashMap<JField,  
JClassLiteral>();
+    class BuildFieldToLiteralVisitor extends JVisitor {
+      @Override
+      public void endVisit(JClassLiteral lit, Context ctx) {
+        map.put(lit.getField(), lit);
+      }
+    }
+    (new BuildFieldToLiteralVisitor()).accept(jprogram);
+    return map;
+  }

-  private Map<JField, JType> fieldToLiteralOfClass;
+  private Set<JsName> entryMethodNames;

-  private StatementLogger statementLogger = new NullStatementLogger();
+  private Map<JField, JClassLiteral> fieldToLiteralOfClass;

    private final JProgram jprogram;

@@ -155,6 +165,8 @@

    private final JavaToJavaScriptMap map;

+  private StatementLogger statementLogger = new NullStatementLogger();
+
    public FragmentExtractor(JavaAndJavaScript javaAndJavaScript) {
      this(javaAndJavaScript.jprogram, javaAndJavaScript.jsprogram,
          javaAndJavaScript.map);
@@ -166,13 +178,13 @@
      this.jsprogram = jsprogram;
      this.map = map;

-    buildFieldToClassLiteralMap();
+    fieldToLiteralOfClass = buildFieldToClassLiteralMap(jprogram);
      buildEntryMethodSet();
    }

    /**
-   * 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);
@@ -250,17 +262,6 @@
        assert name != null;
        entryMethodNames.add(name);
      }
-  }
-
-  private void buildFieldToClassLiteralMap() {
-    fieldToLiteralOfClass = new HashMap<JField, JType>();
-    class BuildFieldToLiteralVisitor extends JVisitor {
-      @Override
-      public void endVisit(JClassLiteral lit, Context ctx) {
-        fieldToLiteralOfClass.put(lit.getField(), lit.getRefType());
-      }
-    }
-    (new BuildFieldToLiteralVisitor()).accept(jprogram);
    }

    /**

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

Reply via email to