Revision: 8829
Author: sp...@google.com
Date: Tue Sep 21 05:23:10 2010
Log: Gets the code splitter to be effective even in draft compile mode.

Review at http://gwt-code-reviews.appspot.com/875801

Review by: sco...@google.com
http://code.google.com/p/google-web-toolkit/source/detail?r=8829

Modified:
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java
 /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
/trunk/dev/core/test/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncsErrorMessagesTest.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java Mon Jun 7 12:20:31 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/FragmentLoaderCreator.java Tue Sep 21 05:23:10 2010
@@ -40,6 +40,7 @@
   public static final String ASYNC_LOADER_CLASS_PREFIX = "AsyncLoader";
public static final String ASYNC_LOADER_PACKAGE = "com.google.gwt.lang.asyncloaders"; public static final String BROWSER_LOADER = "AsyncFragmentLoader.BROWSER_LOADER";
+  public static final String CALLBACK_LIST_SUFFIX = "__Callback";
   public static final String LOADER_METHOD_RUN_ASYNC = "runAsync";
public static final String RUN_ASYNC_CALLBACK = "com.google.gwt.core.client.RunAsyncCallback";
   public static final String RUN_CALLBACKS = "runCallbacks";
@@ -198,11 +199,11 @@
   }

   private String getCallbackListQualifiedName() {
-    return ASYNC_LOADER_PACKAGE + "__Callback";
+    return ASYNC_LOADER_PACKAGE + getCallbackListSimpleName();
   }

   private String getCallbackListSimpleName() {
-    return getLoaderSimpleName() + "__Callback";
+    return getLoaderSimpleName() + CALLBACK_LIST_SUFFIX;
   }

   private String getLoaderQualifiedName() {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java Thu Sep 9 00:20:17 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/MethodCallTightener.java Tue Sep 21 05:23:10 2010
@@ -24,6 +24,7 @@
 import com.google.gwt.dev.jjs.ast.JMethodCall;
 import com.google.gwt.dev.jjs.ast.JModVisitor;
 import com.google.gwt.dev.jjs.ast.JNewInstance;
+import com.google.gwt.dev.jjs.ast.JNode;
 import com.google.gwt.dev.jjs.ast.JNullType;
 import com.google.gwt.dev.jjs.ast.JProgram;
 import com.google.gwt.dev.jjs.ast.JReferenceType;
@@ -148,6 +149,13 @@
     optimizeEvent.end("didChange", "" + stats.didChange());
     return stats;
   }
+
+  /**
+ * Tighten method calls that occur within <code>node</code> and its children.
+   */
+  public static void exec(JProgram program, JNode node) {
+    new MethodCallTightener(program).execImpl(node);
+  }

   private final JProgram program;

@@ -160,4 +168,9 @@
     tightener.accept(program);
     return new OptimizerStats(NAME).recordModified(tightener.getNumMods());
   }
-}
+
+  private void execImpl(JNode node) {
+ MethodCallTighteningVisitor tightener = new MethodCallTighteningVisitor();
+    tightener.accept(node);
+  }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java Fri Aug 6 12:01:02 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java Tue Sep 21 05:23:10 2010
@@ -1,12 +1,12 @@
 /*
  * Copyright 2008 Google Inc.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of
  * the License at
- *
+ *
  * http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
  * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -140,6 +140,8 @@
             loadMethod);
         methodCall.addArg(asyncCallback);

+        tightenCallbackType(entryNumber, asyncCallback.getType());
+
         program.addEntryMethod(getOnLoadMethod(loader), entryNumber);

         ctx.replaceMe(methodCall);
@@ -159,6 +161,51 @@
       return method.getEnclosingType() == program.getIndexedType("GWT")
           && method.getName().equals("runAsync");
     }
+
+    /**
+ * Tighten some types and method calls immediately, in case the optimizer is
+     * not run. Without a little bit of tightening, code splitting will be
+     * completely ineffective.
+     *
+ * Note that {...@link FragmentLoaderCreator} can't simply generate the tighter + * types to begin with, because when it runs, it doesn't know which runAsync
+     * call it is generating a loader for.
+     *
+     * This method can be deleted if {...@link FragmentLoaderCreator} is
+     * eliminated.
+     */
+    private void tightenCallbackType(int entryNumber, JType callbackType) {
+      JClassType loaderClass = getFragmentLoader(entryNumber);
+
+      /*
+ * Before: class AsyncLoader3 { static void runAsync(RunAsyncCallback cb)
+       * { ... } }
+       *
+ * After: class AsyncLoader3 { static void runAsync(RunAsyncCallback$3 cb)
+       * { ... } }
+       */
+      JMethod loadMethod = getRunAsyncMethod(loaderClass);
+      loadMethod.getParams().get(0).setType(callbackType);
+
+      /*
+ * Before: class AsyncLoader3__Callback { RunAsyncCallback callback; }
+       *
+ * After: class AsyncLoader3__Callback { RunAsyncCallback$3 callback; }
+       */
+ JClassType callbackListType = getFragmentLoaderCallbackList(entryNumber);
+      JField callbackField = getField(callbackListType, "callback");
+
+      /*
+ * The method AsyncLoaderNNN.runCallbacks has a lot of calls to onSuccess
+       * methods where the target is onSuccess in the RunAsyncCallback
+       * interface. Use MethodCallTightener to tighten those calls down to
+       * target the onSuccess method of a specific callback class.
+       */
+      callbackField.setType(callbackType);
+      JMethod runCallbacksMethod = getMethod(loaderClass,
+          FragmentLoaderCreator.RUN_CALLBACKS);
+      MethodCallTightener.exec(program, runCallbacksMethod);
+    }
   }
   private class ReplaceRunAsyncResources extends JModVisitor {
     private Map<String, List<RunAsyncReplacement>> replacementsByName;
@@ -229,8 +276,8 @@

   public static void exec(TreeLogger logger, JProgram program)
       throws UnableToCompleteException {
-    Event codeSplitterEvent =
- SpeedTracerLogger.start(CompilerEventType.CODE_SPLITTER, "phase", "ReplaceRunAsyncs");
+    Event codeSplitterEvent = SpeedTracerLogger.start(
+        CompilerEventType.CODE_SPLITTER, "phase", "ReplaceRunAsyncs");
     TreeLogger branch = logger.branch(TreeLogger.TRACE,
         "Replacing GWT.runAsync with island loader calls");
     new ReplaceRunAsyncs(branch, program).execImpl();
@@ -247,6 +294,35 @@
     assert initializerCall.getArgs().size() == 2;
     return initializerCall;
   }
+
+  private static JMethod getMethod(JClassType type, String name) {
+    for (JMethod method : type.getMethods()) {
+      if (method.getName().equals(name)) {
+        return method;
+      }
+    }
+ throw new InternalCompilerException("Method not found: " + type.getName()
+        + "." + name);
+  }
+
+  private static JMethod getOnLoadMethod(JClassType loaderType) {
+    assert loaderType != null;
+    assert loaderType.getMethods() != null;
+    JMethod method = getMethod(loaderType, "onLoad");
+    assert method.isStatic();
+    assert method.getParams().size() == 0;
+    return method;
+  }
+
+  private static JMethod getRunAsyncMethod(JClassType loaderType) {
+    assert loaderType != null;
+    assert loaderType.getMethods() != null;
+    JMethod method = getMethod(loaderType, "runAsync");
+    assert (method.isStatic());
+    assert (method.getParams().size() == 1);
+ assert (method.getParams().get(0).getType().getName().equals(FragmentLoaderCreator.RUN_ASYNC_CALLBACK));
+    return method;
+  }

   /**
    * Convert a class literal to a runAsync name.
@@ -288,6 +364,16 @@
       throw new UnableToCompleteException();
     }
   }
+
+  private JField getField(JClassType type, String name) {
+    for (JField field : type.getFields()) {
+      if (field.getName().equals(name)) {
+        return field;
+      }
+    }
+ throw new InternalCompilerException("Field not found: " + type.getName()
+        + "." + name);
+  }

   private JClassType getFragmentLoader(int fragmentNumber) {
String fragmentLoaderClassName = FragmentLoaderCreator.ASYNC_LOADER_PACKAGE
@@ -299,32 +385,13 @@
     return (JClassType) result;
   }

-  private JMethod getOnLoadMethod(JClassType loaderType) {
-    assert loaderType != null;
-    assert loaderType.getMethods() != null;
-    for (JMethod method : loaderType.getMethods()) {
-      if (method.getName().equals("onLoad")) {
-        assert (method.isStatic());
-        assert (method.getParams().size() == 0);
-        return method;
-      }
-    }
-    assert false;
-    return null;
-  }
-
-  private JMethod getRunAsyncMethod(JClassType loaderType) {
-    assert loaderType != null;
-    assert loaderType.getMethods() != null;
-    for (JMethod method : loaderType.getMethods()) {
-      if (method.getName().equals("runAsync")) {
-        assert (method.isStatic());
-        assert (method.getParams().size() == 1);
- assert (method.getParams().get(0).getType().getName().equals(FragmentLoaderCreator.RUN_ASYNC_CALLBACK));
-        return method;
-      }
-    }
-    return null;
+  private JClassType getFragmentLoaderCallbackList(int fragmentNumber) {
+    String className = FragmentLoaderCreator.ASYNC_LOADER_PACKAGE + "."
+        + FragmentLoaderCreator.ASYNC_LOADER_CLASS_PREFIX + fragmentNumber
+        + FragmentLoaderCreator.CALLBACK_LIST_SUFFIX;
+    JType result = program.getFromTypeMap(className);
+    assert (result != null);
+    return (JClassType) result;
   }

   private void setNumEntriesInAsyncFragmentLoader(int entryCount) {
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncsErrorMessagesTest.java Mon Jun 7 12:20:31 2010 +++ /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncsErrorMessagesTest.java Tue Sep 21 05:23:10 2010
@@ -52,7 +52,7 @@
     });
     addSnippetImport("test.SplitPoint3");

- expectError("Line 12: Multiple runAsync calls are named test.SplitPoint1"); + expectError("Line 15: Multiple runAsync calls are named test.SplitPoint1"); expectError("One call is in test.SplitPoint1.doStuff (/mock/test/SplitPoint1.java:4)"); expectError("One call is in test.SplitPoint3.doStuff (/mock/test/SplitPoint3.java:4)");

@@ -60,12 +60,12 @@
   }

   public void testNonClassLiteral() {
- expectError("Line 11: Only a class literal may be passed to runAsyncCode"); + expectError("Line 14: Only a class literal may be passed to runAsyncCode"); testSnippet("RunAsyncCode.runAsyncCode(new SplitPoint1().getClass());");
   }

   public void testNonExistentSplitPoint() {
-    expectError("Line 11: No runAsync call is named java.lang.String");
+    expectError("Line 14: No runAsync call is named java.lang.String");
     testSnippet("RunAsyncCode.runAsyncCode(String.class);");
   }

@@ -80,12 +80,32 @@
         code.append("public class AsyncLoader" + sp + " {\n");
         code.append("  public static void onLoad() { }\n");
code.append(" public static void runAsync(RunAsyncCallback cb) { }\n");
+        code.append("  public static void runCallbacks() { }\n");
         code.append("}\n");
         return code;
       }
     });

     addSnippetImport("com.google.gwt.lang.asyncloaders.AsyncLoader" + sp);
+
+    sourceOracle.addOrReplace(new MockJavaResource(
+        "com.google.gwt.lang.asyncloaders.AsyncLoader" + sp
+            + FragmentLoaderCreator.CALLBACK_LIST_SUFFIX) {
+      @Override
+      protected CharSequence getContent() {
+        StringBuffer code = new StringBuffer();
+        code.append("package com.google.gwt.lang.asyncloaders;\n");
+        code.append("import com.google.gwt.core.client.RunAsyncCallback;");
+        code.append("public class AsyncLoader" + sp
+            + FragmentLoaderCreator.CALLBACK_LIST_SUFFIX + "{\n");
+        code.append("  RunAsyncCallback callback;\n");
+        code.append("}\n");
+        return code;
+      }
+    });
+
+    addSnippetImport("com.google.gwt.lang.asyncloaders.AsyncLoader" + sp
+        + FragmentLoaderCreator.CALLBACK_LIST_SUFFIX);
   }

   private void addCommonTestCode() {

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

Reply via email to