Revision: 6097
Author: [email protected]
Date: Tue Sep  8 11:07:39 2009
Log: Allow naming a runAsync call using a class literal.  There are now
two overloads of GWT.runAsync, and the new overload takes an
extra argument supplying the class literal.

Review by: kprobst (SplitPointRecorder), scottb (the bulk of it)

http://code.google.com/p/google-web-toolkit/source/detail?r=6097

Added:
  /trunk/dev/core/test/com/google/gwt/dev/javac/RunAsyncNameTest.java
Modified:
   
/trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java
   
/trunk/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java
  /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java
  /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java
  /trunk/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java
  /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java
  /trunk/user/src/com/google/gwt/core/client/GWT.java
  /trunk/user/test/com/google/gwt/dev/jjs/InitialLoadSequence.gwt.xml
  /trunk/user/test/com/google/gwt/dev/jjs/test/InitialLoadSequenceTest.java

=======================================
--- /dev/null
+++ /trunk/dev/core/test/com/google/gwt/dev/javac/RunAsyncNameTest.java Tue  
Sep  8 11:07:39 2009
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2009 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
+ * License for the specific language governing permissions and limitations  
under
+ * the License.
+ */
+package com.google.gwt.dev.javac;
+
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.core.ext.UnableToCompleteException;
+import com.google.gwt.dev.javac.impl.MockJavaResource;
+import com.google.gwt.dev.jjs.impl.OptimizerTestBase;
+import com.google.gwt.dev.util.UnitTestTreeLogger;
+
+/**
+ * This class tests naming of runAsync calls. Mostly it tests names that  
are
+ * invalid.
+ */
+public class RunAsyncNameTest extends OptimizerTestBase {
+  @Override
+  public void setUp() {
+    sourceOracle.addOrReplace(new MockJavaResource("test.CallRunAsync") {
+      @Override
+      protected CharSequence getContent() {
+        StringBuffer code = new StringBuffer();
+        code.append("package test;\n");
+        code.append("import com.google.gwt.core.client.GWT;\n");
+        code.append("public class CallRunAsync {\n");
+        code.append("  public static int notAmethod;");
+        code.append("  public static void call0() { }\n");
+        code.append("  public static void call1() {\n");
+        code.append("    GWT.runAsync(null);\n");
+        code.append("  }\n");
+        code.append("  public static void call2() {\n");
+        code.append("    GWT.runAsync(null);\n");
+        code.append("    GWT.runAsync(null);\n");
+        code.append("  }\n");
+        code.append("}\n");
+        return code;
+      }
+    });
+  }
+
+  /**
+   * Tests that it's an error to call the 2-argument version of  
GWT.runAsync
+   * with anything but a class literal.
+   */
+  public void testNonLiteralInCall() throws UnableToCompleteException {
+    UnitTestTreeLogger logger;
+    {
+      UnitTestTreeLogger.Builder builder = new  
UnitTestTreeLogger.Builder();
+      builder.setLowestLogLevel(TreeLogger.ERROR);
+      builder.expectError("Errors in /mock/test/EntryPoint.java", null);
+      builder.expectError(
+          "Line 5:  Only class literals may be used to name a call to  
GWT.runAsync()",
+          null);
+      builder.expectError("Cannot proceed due to previous errors", null);
+      logger = builder.createLogger();
+      this.logger = logger;
+    }
+
+    addSnippetImport("com.google.gwt.core.client.GWT");
+    try {
+      compileSnippet("void", "GWT.runAsync((new Object()).getClass(),  
null);");
+      fail("Expected compilation to fail");
+    } catch (UnableToCompleteException e) {
+      // expected
+    }
+
+    logger.assertCorrectLogEntries();
+  }
+}
=======================================
---  
/trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java   
 
Mon Jul  6 15:03:31 2009
+++  
/trunk/dev/core/src/com/google/gwt/core/ext/soyc/impl/SplitPointRecorder.java   
 
Tue Sep  8 11:07:39 2009
@@ -80,7 +80,7 @@
          htmlOut.printRaw(curLine);
          htmlOut.newline();
        }
-
+
        if (!jprogram.getSplitPointInitialSequence().isEmpty()) {
          curLine = "<initialseq>";
          htmlOut.printRaw(curLine);
@@ -92,7 +92,7 @@
            htmlOut.printRaw(curLine);
            htmlOut.newline();
          }
-
+
          htmlOut.indentOut();
          curLine = "</initialseq>";
          htmlOut.printRaw(curLine);
@@ -127,13 +127,19 @@
      Map<String, Integer> counts = new HashMap<String, Integer>();
      for (RunAsyncReplacement replacement :  
program.getRunAsyncReplacements().values()) {
        int entryNumber = replacement.getNumber();
-      String methodDescription =  
fullMethodDescription(replacement.getEnclosingMethod());
-      if (counts.containsKey(methodDescription)) {
-        counts.put(methodDescription, counts.get(methodDescription) + 1);
-        methodDescription += "#"
-            + Integer.toString(counts.get(methodDescription));
+      String methodDescription;
+      if (replacement.getName() != null) {
+        methodDescription = replacement.getName();
        } else {
-        counts.put(methodDescription, 1);
+        methodDescription = "@"
+            + fullMethodDescription(replacement.getEnclosingMethod());
+        if (counts.containsKey(methodDescription)) {
+          counts.put(methodDescription, counts.get(methodDescription) + 1);
+          methodDescription += "#"
+              + Integer.toString(counts.get(methodDescription));
+        } else {
+          counts.put(methodDescription, 1);
+        }
        }

        names.put(entryNumber, methodDescription);
=======================================
---  
/trunk/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java 
 
Thu Oct 30 09:17:17 2008
+++  
/trunk/dev/core/src/com/google/gwt/dev/jdt/FindDeferredBindingSitesVisitor.java 
 
Tue Sep  8 11:07:39 2009
@@ -59,8 +59,7 @@
    public static final String REBIND_MAGIC_METHOD = "create";
    public static final String ASYNC_MAGIC_METHOD = "runAsync";

-  public static void reportRebindProblem(MessageSendSite site,
-      String message) {
+  public static void reportRebindProblem(MessageSendSite site, String  
message) {
      MessageSend messageSend = site.messageSend;
      Scope scope = site.scope;
      // Safe since CUS.referenceContext is set in its constructor.
@@ -111,11 +110,18 @@
        }
      } else {
        assert asyncMagicMethod;
-      if (args.length != 1) {
+      if (args.length != 1 && args.length != 2) {
          reportRebindProblem(site,
-            "GWT.runAsync() should take exactly one argument");
+            "GWT.runAsync() should take one or two arguments");
          return;
        }
+      if (args.length == 2) {
+        if (!(args[0] instanceof ClassLiteralAccess)) {
+          reportRebindProblem(site,
+              "Only class literals may be used to name a call to  
GWT.runAsync()");
+          return;
+        }
+      }
      }

      if (asyncMagicMethod) {
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java   Tue  
Jul 28 12:00:07 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/CodeSplitter.java   Tue  
Sep  8 11:07:39 2009
@@ -259,6 +259,74 @@
      new CodeSplitter(logger, jprogram, jsprogram, map,  
dependencyRecorder).execImpl();
      dependencyRecorder.close();
    }
+
+  /**
+   * Find a split point as designated in the {...@link #PROP_INITIAL_SEQUENCE}
+   * configuration property.
+   */
+  public static int findSplitPoint(String refString, JProgram program,
+      TreeLogger branch) throws UnableToCompleteException {
+    Map<JMethod, List<Integer>> methodToSplitPoint =  
reverseByEnclosingMethod(program.getRunAsyncReplacements());
+    Map<String, List<Integer>> nameToSplitPoint =  
reverseByName(program.getRunAsyncReplacements());
+
+    if (refString.startsWith("@")) {
+      JsniRef jsniRef = JsniRef.parse(refString);
+      if (jsniRef == null) {
+        branch.log(TreeLogger.ERROR, "Badly formatted JSNI reference in "
+            + PROP_INITIAL_SEQUENCE + ": " + refString);
+        throw new UnableToCompleteException();
+      }
+      final String lookupErrorHolder[] = new String[1];
+      HasEnclosingType referent = JsniRefLookup.findJsniRefTarget(jsniRef,
+          program, new JsniRefLookup.ErrorReporter() {
+            public void reportError(String error) {
+              lookupErrorHolder[0] = error;
+            }
+          });
+      if (referent == null) {
+        TreeLogger resolveLogger = branch.branch(TreeLogger.ERROR,
+            "Could not resolve JSNI reference: " + jsniRef);
+        resolveLogger.log(TreeLogger.ERROR, lookupErrorHolder[0]);
+        throw new UnableToCompleteException();
+      }
+
+      if (!(referent instanceof JMethod)) {
+        branch.log(TreeLogger.ERROR, "Not a method: " + referent);
+        throw new UnableToCompleteException();
+      }
+
+      JMethod method = (JMethod) referent;
+      List<Integer> splitPoints = methodToSplitPoint.get(method);
+      if (splitPoints == null) {
+        branch.log(TreeLogger.ERROR,
+            "Method does not enclose a runAsync call: " + jsniRef);
+        throw new UnableToCompleteException();
+      }
+      if (splitPoints.size() > 1) {
+        branch.log(TreeLogger.ERROR,
+            "Method includes multiple runAsync calls, "
+                + "so it's ambiguous which one is meant: " + jsniRef);
+        throw new UnableToCompleteException();
+      }
+
+      return splitPoints.get(0);
+    }
+
+    // Assume it's a raw class name
+    List<Integer> splitPoints = nameToSplitPoint.get(refString);
+    if (splitPoints == null || splitPoints.size() == 0) {
+      branch.log(TreeLogger.ERROR, "No runAsync call is labelled with  
class "
+          + refString);
+      throw new UnableToCompleteException();
+    }
+    if (splitPoints.size() > 1) {
+      branch.log(TreeLogger.ERROR,
+          "More than one runAsync call is labelled with class " +  
refString);
+      throw new UnableToCompleteException();
+    }
+
+    return splitPoints.get(0);
+  }

    public static int getExclusiveFragmentNumber(int splitPoint,
        int numSplitPoints) {
@@ -295,8 +363,6 @@
        JProgram program, Properties properties) throws  
UnableToCompleteException {
      TreeLogger branch = logger.branch(TreeLogger.TRACE,
          "Looking up initial load sequence for split points");
-    Map<JMethod, List<Integer>> reversedRunAsyncMap =  
reverse(program.getRunAsyncReplacements());
-
      LinkedHashSet<Integer> initialLoadSequence = new  
LinkedHashSet<Integer>();

      ConfigurationProperty prop;
@@ -314,8 +380,7 @@
      }

      for (String refString : prop.getValues()) {
-      int splitPoint = findSplitPoint(refString, program, branch,
-          reversedRunAsyncMap);
+      int splitPoint = findSplitPoint(refString, program, branch);
        if (initialLoadSequence.contains(splitPoint)) {
          branch.log(TreeLogger.ERROR, "Split point specified more than  
once: "
              + refString);
@@ -323,8 +388,6 @@
        initialLoadSequence.add(splitPoint);
      }

-    // TODO(spoon) create an artifact in the aux dir describing the  
choice, so
-    // that SOYC can use it
      logInitialLoadSequence(logger, initialLoadSequence);
      installInitialLoadSequenceField(program, initialLoadSequence);
      program.setSplitPointInitialSequence(new ArrayList<Integer>(
@@ -394,63 +457,6 @@
      dependencyRecorder.endDependencyGraph();
      return cfa;
    }
-
-  /**
-   * Find a split point as designated in the {...@link #PROP_INITIAL_SEQUENCE}
-   * configuration property.
-   *
-   * TODO(spoon) accept a labeled runAsync call, once runAsyncs can be  
labeled
-   */
-  private static int findSplitPoint(String refString, JProgram program,
-      TreeLogger branch, Map<JMethod, List<Integer>> reversedRunAsyncMap)
-      throws UnableToCompleteException {
-    if (refString.startsWith("@")) {
-      JsniRef jsniRef = JsniRef.parse(refString);
-      if (jsniRef == null) {
-        branch.log(TreeLogger.ERROR, "Badly formatted JSNI reference in "
-            + PROP_INITIAL_SEQUENCE + ": " + refString);
-        throw new UnableToCompleteException();
-      }
-      final String lookupErrorHolder[] = new String[1];
-      HasEnclosingType referent = JsniRefLookup.findJsniRefTarget(jsniRef,
-          program, new JsniRefLookup.ErrorReporter() {
-            public void reportError(String error) {
-              lookupErrorHolder[0] = error;
-            }
-          });
-      if (referent == null) {
-        TreeLogger resolveLogger = branch.branch(TreeLogger.ERROR,
-            "Could not resolve JSNI reference: " + jsniRef);
-        resolveLogger.log(TreeLogger.ERROR, lookupErrorHolder[0]);
-        throw new UnableToCompleteException();
-      }
-
-      if (!(referent instanceof JMethod)) {
-        branch.log(TreeLogger.ERROR, "Not a method: " + referent);
-        throw new UnableToCompleteException();
-      }
-
-      JMethod method = (JMethod) referent;
-      List<Integer> splitPoints = reversedRunAsyncMap.get(method);
-      if (splitPoints == null) {
-        branch.log(TreeLogger.ERROR,
-            "Method does not enclose a runAsync call: " + jsniRef);
-        throw new UnableToCompleteException();
-      }
-      if (splitPoints.size() != 1) {
-        branch.log(TreeLogger.ERROR,
-            "Method includes multiple runAsync calls, "
-                + "so it's ambiguous which one is meant: " + jsniRef);
-        throw new UnableToCompleteException();
-      }
-
-      return splitPoints.get(0);
-    }
-
-    branch.log(TreeLogger.ERROR, "Unrecognized designation of a split  
point: "
-        + refString);
-    throw new UnableToCompleteException();
-  }

    private static String fullNameString(JField field) {
      return field.getEnclosingType().getName() + "." + field.getName();
@@ -527,7 +533,7 @@
     * Reverses a runAsync map, returning a map from methods to the split  
point
     * numbers invoked from within that method.
     */
-  private static Map<JMethod, List<Integer>> reverse(
+  private static Map<JMethod, List<Integer>> reverseByEnclosingMethod(
        Map<Integer, RunAsyncReplacement> runAsyncMap) {
      Map<JMethod, List<Integer>> revmap = new HashMap<JMethod,  
List<Integer>>();
      for (RunAsyncReplacement replacement : runAsyncMap.values()) {
@@ -541,6 +547,23 @@
      }
      return revmap;
    }
+
+  private static Map<String, List<Integer>> reverseByName(
+      Map<Integer, RunAsyncReplacement> runAsyncReplacements) {
+    Map<String, List<Integer>> revmap = new HashMap<String,  
List<Integer>>();
+    for (RunAsyncReplacement replacement : runAsyncReplacements.values()) {
+      String name = replacement.getName();
+      if (name != null) {
+        List<Integer> list = revmap.get(name);
+        if (list == null) {
+          list = new ArrayList<Integer>();
+          revmap.put(name, list);
+        }
+        list.add(replacement.getNumber());
+      }
+    }
+    return revmap;
+  }

    /**
     * Traverse all code in the program that is reachable via split point
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java       
 
Thu Jul 16 16:35:08 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/ReplaceRunAsyncs.java       
 
Tue Sep  8 11:07:39 2009
@@ -16,7 +16,9 @@
  package com.google.gwt.dev.jjs.impl;

  import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.jjs.InternalCompilerException;
  import com.google.gwt.dev.jjs.ast.Context;
+import com.google.gwt.dev.jjs.ast.JClassLiteral;
  import com.google.gwt.dev.jjs.ast.JClassType;
  import com.google.gwt.dev.jjs.ast.JExpression;
  import com.google.gwt.dev.jjs.ast.JField;
@@ -34,6 +36,8 @@
  /**
   * Replaces calls to
   * {...@link  
com.google.gwt.core.client.GWT#runAsync(com.google.gwt.core.client.RunAsyncCallback)}
+ * and
+ * {...@link com.google.gwt.core.client.GWT#runAsync(Class,  
com.google.gwt.core.client.RunAsyncCallback)
   * by calls to a fragment loader.
   */
  public class ReplaceRunAsyncs {
@@ -44,12 +48,15 @@
    public static class RunAsyncReplacement implements Serializable {
      private final JMethod enclosingMethod;
      private final JMethod loadMethod;
+    private final String name;
      private final int number;

-    RunAsyncReplacement(int number, JMethod enclosingMethod, JMethod  
loadMethod) {
+    RunAsyncReplacement(int number, JMethod enclosingMethod,
+        JMethod loadMethod, String name) {
        this.number = number;
        this.enclosingMethod = enclosingMethod;
        this.loadMethod = loadMethod;
+      this.name = name;
      }

      /**
@@ -66,6 +73,15 @@
      public JMethod getLoadMethod() {
        return loadMethod;
      }
+
+    /**
+     * Return the name of this runAsync, which is specified by a class  
literal
+     * in the two-argument version of runAsync(). Returns  
<code>null</code> if
+     * there is no name for the call.
+     */
+    public String getName() {
+      return name;
+    }

      /**
       * The index of this runAsync, numbered from 1 to n.
@@ -87,16 +103,29 @@
      @Override
      public void endVisit(JMethodCall x, Context ctx) {
        JMethod method = x.getTarget();
-      if (method == program.getIndexedMethod("GWT.runAsync")) {
-        assert (x.getArgs().size() == 1);
-        JExpression asyncCallback = x.getArgs().get(0);
+      if (isRunAsyncMethod(method)) {
+        JExpression asyncCallback;
+        String name;
+        switch (x.getArgs().size()) {
+          case 1:
+            name = null;
+            asyncCallback = x.getArgs().get(0);
+            break;
+          case 2:
+            name = ((JClassLiteral)  
x.getArgs().get(0)).getRefType().getName();
+            asyncCallback = x.getArgs().get(1);
+            break;
+          default:
+            throw new InternalCompilerException(
+                "runAsync call found with neither 1 nor 2 arguments: " +  
x);
+        }

          int entryNumber = entryCount++;
          JClassType loader = getFragmentLoader(entryNumber);
          JMethod loadMethod = getRunAsyncMethod(loader);
          assert loadMethod != null;
          runAsyncReplacements.put(entryNumber, new RunAsyncReplacement(
-            entryNumber, currentMethod, loadMethod));
+            entryNumber, currentMethod, loadMethod, name));

          JMethodCall methodCall = new JMethodCall(x.getSourceInfo(), null,
              loadMethod);
@@ -113,6 +142,14 @@
        currentMethod = x;
        return true;
      }
+
+    private boolean isRunAsyncMethod(JMethod method) {
+      /*
+       * The method is overloaded, so check the enclosing type plus the  
name.
+       */
+      return method.getEnclosingType() == program.getIndexedType("GWT")
+          && method.getName().equals("runAsync");
+    }
    }

    public static void exec(TreeLogger logger, JProgram program) {
@@ -133,6 +170,7 @@
    }

    private JProgram program;
+
    private Map<Integer, RunAsyncReplacement> runAsyncReplacements = new  
HashMap<Integer, RunAsyncReplacement>();

    private ReplaceRunAsyncs(JProgram program) {
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java Tue  
Aug 11 12:45:07 2009
+++ /trunk/dev/core/test/com/google/gwt/dev/jjs/JavaAstConstructor.java Tue  
Sep  8 11:07:39 2009
@@ -21,6 +21,7 @@
  import com.google.gwt.dev.javac.impl.JavaResourceBase;
  import com.google.gwt.dev.javac.impl.MockJavaResource;
  import com.google.gwt.dev.jdt.BasicWebModeCompiler;
+import com.google.gwt.dev.jdt.FindDeferredBindingSitesVisitor;
  import com.google.gwt.dev.jjs.CorrelationFactory.DummyCorrelationFactory;
  import com.google.gwt.dev.jjs.ast.JDeclaredType;
  import com.google.gwt.dev.jjs.ast.JMethod;
@@ -98,6 +99,8 @@
        code.append("public final class GWT {\n");
        code.append("  public boolean isClient() { return true; };\n");
        code.append("  public boolean isScript() { return true; };\n");
+      code.append("  public static void runAsync(Object callback) { }\n");
+      code.append("  public static void runAsync(Class<?> name, Object  
callback) { }\n");
        code.append("}\n");
        return code;
      }
@@ -131,6 +134,16 @@
      //
      JavaToJavaScriptCompiler.checkForErrors(logger, goldenCuds, false);

+    /*
+     * FindDeferredBindingSitesVisitor detects errors in usage of magic  
methods
+     * in the GWT class.
+     */
+    for (CompilationUnitDeclaration jdtCud : goldenCuds) {
+      jdtCud.traverse(new FindDeferredBindingSitesVisitor(), jdtCud.scope);
+    }
+
+    JavaToJavaScriptCompiler.checkForErrors(logger, goldenCuds, true);
+
      CorrelationFactory correlator = new DummyCorrelationFactory();
      JProgram jprogram = new JProgram(correlator);
      JsProgram jsProgram = new JsProgram(correlator);
=======================================
--- /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java     
 
Tue Aug 11 12:45:07 2009
+++ /trunk/dev/core/test/com/google/gwt/dev/jjs/impl/OptimizerTestBase.java     
 
Tue Sep  8 11:07:39 2009
@@ -77,8 +77,8 @@

    /**
     * Finds a type by name. The type name may be short, e.g.  
<code>"Foo"</code>,
-   * or fully-qualified, e.g. <code>"com.google.example.Foo"</code>. If a
-   * short name is used, it must be unambiguous.
+   * or fully-qualified, e.g. <code>"com.google.example.Foo"</code>. If a  
short
+   * name is used, it must be unambiguous.
     */
    public static JDeclaredType findType(JProgram program, String typeName) {
      JDeclaredType type = program.getFromTypeMap(typeName);
@@ -116,11 +116,11 @@
      }
      return TreeLogger.NULL;
    }
+
+  protected TreeLogger logger = createTreeLogger();

    protected final MockResourceOracle sourceOracle = new  
MockResourceOracle();

-  private final TreeLogger logger = createTreeLogger();
-
    private final Set<String> snippetClassDecls = new TreeSet<String>();

    private final Set<String> snippetImports = new TreeSet<String>();
@@ -133,19 +133,20 @@
    }

    /**
-   * Adds an import statement for any code subsequently passed to
+   * Adds a snippet of code, for example a field declaration, to the class  
that
+   * encloses the snippet subsequently passed to
     * {...@link #compileSnippet(String, String)}.
     */
-  protected void addSnippetImport(String typeName) {
-    snippetImports.add(typeName);
+  protected void addSnippetClassDecl(String fieldDecl) {
+    snippetClassDecls.add(fieldDecl);
    }

    /**
-   * Adds a local field declaration for code subsequently passed to
+   * Adds an import statement for any code subsequently passed to
     * {...@link #compileSnippet(String, String)}.
     */
-  protected void addSnippetClassDecl(String fieldDecl) {
-    snippetClassDecls.add(fieldDecl);
+  protected void addSnippetImport(String typeName) {
+    snippetImports.add(typeName);
    }

    /**
=======================================
--- /trunk/user/src/com/google/gwt/core/client/GWT.java Thu Aug 20 11:38:19  
2009
+++ /trunk/user/src/com/google/gwt/core/client/GWT.java Tue Sep  8 11:07:39  
2009
@@ -202,36 +202,22 @@
        sGWTBridge.log(message, e);
      }
    }
+
+  /**
+   * The same as {...@link #runAsync(RunAsyncCallback)}, except with an extra
+   * parameter to provide a name for the call. The name parameter should be
+   * supplied with a class literal. No two runAsync calls in the same  
program
+   * should use the same name.
+   */
+  public static void runAsync(Class<?> name, RunAsyncCallback callback) {
+    runAsyncWithoutCodeSplitting(callback);
+  }

    /**
     * Run the specified callback once the necessary code for it has been  
loaded.
     */
    public static void runAsync(RunAsyncCallback callback) {
-    /*
-     * By default, just call the callback. This allows using
-     * <code>runAsync</code> in code that might or might not run in a web
-     * browser.
-     */
-    if (isScript()) {
-      /*
-       * It's possible that the code splitter does not run, even for a
-       * production build. Signal a lightweight event, anyway, just so that
-       * there isn't a complete lack of lightweight events for runAsync.
-       */
-       
AsyncFragmentLoader.BROWSER_LOADER.logEventProgress("noDownloadNeeded", 
"begin");
-       
AsyncFragmentLoader.BROWSER_LOADER.logEventProgress("noDownloadNeeded", "end");
-    }
-
-    UncaughtExceptionHandler handler = sUncaughtExceptionHandler;
-    if (handler == null) {
-      callback.onSuccess();
-    } else {
-      try {
-        callback.onSuccess();
-      } catch (Throwable e) {
-        handler.onUncaughtException(e);
-      }
-    }
+    runAsyncWithoutCodeSplitting(callback);
    }

    /**
@@ -261,4 +247,36 @@
    private static native String getVersion0() /*-{
      return $gwt_version;
    }-*/;
-}
+
+  /**
+   * This implementation of runAsync simply calls the callback. It is only  
used
+   * when no code splitting has occurred.
+   */
+  private static void runAsyncWithoutCodeSplitting(RunAsyncCallback  
callback) {
+    /*
+     * By default, just call the callback. This allows using
+     * <code>runAsync</code> in code that might or might not run in a web
+     * browser.
+     */
+    if (isScript()) {
+      /*
+       * It's possible that the code splitter does not run, even for a
+       * production build. Signal a lightweight event, anyway, just so that
+       * there isn't a complete lack of lightweight events for runAsync.
+       */
+       
AsyncFragmentLoader.BROWSER_LOADER.logEventProgress("noDownloadNeeded", 
"begin");
+       
AsyncFragmentLoader.BROWSER_LOADER.logEventProgress("noDownloadNeeded", "end");
+    }
+
+    UncaughtExceptionHandler handler = sUncaughtExceptionHandler;
+    if (handler == null) {
+      callback.onSuccess();
+    } else {
+      try {
+        callback.onSuccess();
+      } catch (Throwable e) {
+        handler.onUncaughtException(e);
+      }
+    }
+  }
+}
=======================================
--- /trunk/user/test/com/google/gwt/dev/jjs/InitialLoadSequence.gwt.xml Fri  
Jun 19 09:06:11 2009
+++ /trunk/user/test/com/google/gwt/dev/jjs/InitialLoadSequence.gwt.xml Tue  
Sep  8 11:07:39 2009
@@ -21,5 +21,5 @@
    <extend-configuration-property  
name="compiler.splitpoint.initial.sequence"
       
value="@com.google.gwt.dev.jjs.test.InitialLoadSequenceTest::callback1()" />
    <extend-configuration-property  
name="compiler.splitpoint.initial.sequence"
-     
value="@com.google.gwt.dev.jjs.test.InitialLoadSequenceTest::callback2()" />
+     
value="com.google.gwt.dev.jjs.test.InitialLoadSequenceTest$Callback2Marker"  
/>
  </module>
=======================================
---  
/trunk/user/test/com/google/gwt/dev/jjs/test/InitialLoadSequenceTest.java       
 
Fri Jun 19 09:06:11 2009
+++  
/trunk/user/test/com/google/gwt/dev/jjs/test/InitialLoadSequenceTest.java       
 
Tue Sep  8 11:07:39 2009
@@ -26,6 +26,13 @@
   */
  public class InitialLoadSequenceTest extends GWTTestCase {
    private static final int TIMEOUT = 10000;
+
+  /**
+   * This class is used to mark the second runAsync call.
+   */
+  public static class Callback2Marker {
+  }
+
    /**
     * The number of callbacks outstanding. When this gets to zero, the test
     * finishes.
@@ -58,7 +65,7 @@
    }

    private void callback2() {
-    GWT.runAsync(new RunAsyncCallback() {
+    GWT.runAsync(Callback2Marker.class, new RunAsyncCallback() {
        public void onFailure(Throwable reason) {
          fail(reason.toString());
        }

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

Reply via email to