Revision: 6400
Author: rj...@google.com
Date: Fri Oct 16 14:04:54 2009
Log: Add $entry magic function to guarantee correct entry and exit of GWT  
code from ex

Patch by: bobv
Review by: scottb, bruce, rjrjr, jgw
http://code.google.com/p/google-web-toolkit/source/detail?r=6400

Modified:
  /trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html
  /trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
  /trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
  /trunk/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java
  /trunk/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java
  /trunk/user/src/com/google/gwt/core/client/impl/Impl.java

=======================================
--- /trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html Thu  
Oct 15 08:36:29 2009
+++ /trunk/dev/core/src/com/google/gwt/core/ext/linker/impl/hosted.html Fri  
Oct 16 14:04:54 2009
@@ -4,7 +4,7 @@
  //    separate functions.
  var $wnd = parent;
  var $doc = $wnd.document;
-var $moduleName, $moduleBase
+var $moduleName, $moduleBase, $entry
  ,$stats = $wnd.__gwtStatsEvent ? function(a) {return  
$wnd.__gwtStatsEvent(a);} : null;
  // Lightweight metrics
  if ($stats) {
=======================================
---  
/trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java        
 
Tue Oct 13 16:57:19 2009
+++  
/trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java        
 
Fri Oct 16 14:04:54 2009
@@ -760,6 +760,11 @@

      JMethodBody body = (JMethodBody) bootStrapMethod.getBody();
      JBlock block = body.getBlock();
+
+    // Also remember $entry, which we'll handle specially in GenerateJsAst
+    JMethod registerEntry = program.getIndexedMethod("Impl.registerEntry");
+    program.addEntryMethod(registerEntry);
+
      for (String mainClassName : mainClassNames) {
        block.addStmt(makeStatsCalls(program, mainClassName));
        JDeclaredType mainType = program.getFromTypeMap(mainClassName);
@@ -986,10 +991,12 @@
          }
        } catch (ParserConfigurationException e) {
          throw new InternalCompilerException(
-            "Error reading compile report information that was just  
generated", e);
+            "Error reading compile report information that was just  
generated",
+            e);
        } catch (SAXException e) {
          throw new InternalCompilerException(
-            "Error reading compile report information that was just  
generated", e);
+            "Error reading compile report information that was just  
generated",
+            e);
        }
        dashboard.generateForOnePermutation();
        reportArtifacts = outDir.getArtifacts();
=======================================
---  
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java      
 
Fri Aug 21 10:53:16 2009
+++  
/trunk/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java      
 
Fri Oct 16 14:04:54 2009
@@ -1453,23 +1453,37 @@
          List<JsStatement> globalStmts) {
        /**
         * <pre>
+       * var $entry = Impl.registerEntry();
         * function gwtOnLoad(errFn, modName, modBase){
         *   $moduleName = modName;
         *   $moduleBase = modBase;
         *   if (errFn) {
         *     try {
-       *       init();
+       *       $entry(init)();
         *     } catch(e) {
         *       errFn(modName);
         *     }
         *   } else {
-       *     init();
+       *     $entry(init)();
         *   }
         * }
         * </pre>
         */
        SourceInfo sourceInfo = program.createSourceInfoSynthetic(
            GenerateJavaScriptAST.class, "gwtOnLoad");
+
+      JsName entryName = topScope.findExistingName("$entry");
+      entryName.setObfuscatable(true);
+      JsVar entryVar = new JsVar(sourceInfo, entryName);
+      JsInvocation registerEntryCall = new JsInvocation(sourceInfo);
+      JsFunction registerEntryFunction =  
indexedFunctions.get("Impl.registerEntry");
+       
registerEntryCall.setQualifier(registerEntryFunction.getName().makeRef(
+          sourceInfo));
+      entryVar.setInitExpr(registerEntryCall);
+      JsVars entryVars = new JsVars(sourceInfo);
+      entryVars.add(entryVar);
+      globalStmts.add(entryVars);
+
        JsName gwtOnLoadName = topScope.declareName("gwtOnLoad");
        gwtOnLoadName.setObfuscatable(false);
        JsFunction gwtOnLoad = new JsFunction(sourceInfo, topScope,
@@ -1501,10 +1515,15 @@
        jsIf.setElseStmt(callBlock);
        jsTry.setTryBlock(callBlock);
        for (JsFunction func : entryFuncs) {
-        if (func != null) {
+        if (func == registerEntryFunction) {
+          continue;
+        } else if (func != null) {
            JsInvocation call = new JsInvocation(sourceInfo);
-          call.setQualifier(func.getName().makeRef(sourceInfo));
-          callBlock.getStatements().add(call.makeStmt());
+          call.setQualifier(entryName.makeRef(sourceInfo));
+          call.getArguments().add(func.getName().makeRef(sourceInfo));
+          JsInvocation entryCall = new JsInvocation(sourceInfo);
+          entryCall.setQualifier(call);
+          callBlock.getStatements().add(entryCall.makeStmt());
          }
        }
        JsCatch jsCatch = new JsCatch(sourceInfo, fnScope, "e");
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java      Tue Jul 
 
28 09:27:08 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/js/ast/JsRootScope.java      Fri Oct 
 
16 14:04:54 2009
@@ -110,7 +110,7 @@
          "JavaArray", "JavaMember",

          // GWT-defined identifiers
-        "$wnd", "$doc", "$moduleName", "$moduleBase", "$gwt_version",
+        "$wnd", "$doc", "$entry", "$moduleName", "$moduleBase", "$gwt_version",

          // Identifiers used by JsStackEmulator; later set to obfuscatable
          "$stack", "$stackDepth", "$location",
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java       Tue Oct 
 
13 16:57:19 2009
+++ /trunk/dev/core/src/com/google/gwt/dev/shell/ModuleSpace.java       Fri Oct 
 
16 14:04:54 2009
@@ -100,7 +100,7 @@
      try {
        Class<?> javaScriptExceptionClass = Class.forName(
            "com.google.gwt.core.client.JavaScriptException", true, cl);
-
+
        if (!javaScriptExceptionClass.isInstance(javaScriptException)) {
          // Not a JavaScriptException
          return null;
@@ -341,11 +341,16 @@
      //
      String entryPointTypeName = null;
      try {
+      // Set up GWT-entry code
+      Class<?> clazz =  
loadClassFromSourceName("com.google.gwt.core.client.impl.Impl");
+      Method registerEntry = clazz.getMethod("registerEntry");
+      registerEntry.invoke(null);
+
        String[] entryPoints = host.getEntryPointTypeNames();
        if (entryPoints.length > 0) {
          for (int i = 0; i < entryPoints.length; i++) {
            entryPointTypeName = entryPoints[i];
-          Class<?> clazz = loadClassFromSourceName(entryPointTypeName);
+          clazz = loadClassFromSourceName(entryPointTypeName);
            Method onModuleLoad = null;
            try {
              onModuleLoad = clazz.getMethod("onModuleLoad");
=======================================
--- /trunk/user/src/com/google/gwt/core/client/impl/Impl.java   Mon Jul  6  
14:45:31 2009
+++ /trunk/user/src/com/google/gwt/core/client/impl/Impl.java   Fri Oct 16  
14:04:54 2009
@@ -16,6 +16,7 @@
  package com.google.gwt.core.client.impl;

  import com.google.gwt.core.client.GWT;
+import com.google.gwt.core.client.JavaScriptObject;

  /**
   * Private implementation class for GWT core. This API is should not be
@@ -23,8 +24,39 @@
   */
  public final class Impl {

+  /**
+   * Used by {...@link #entry0(Object, Object)} to handle reentrancy.
+   */
+  private static int entryDepth = 0;
    private static int sNextHashId = 0;

+  /**
+   * This method should be used whenever GWT code is entered from a JS  
context
+   * and there is no GWT code in the same module on the call stack.  
Examples
+   * include event handlers, exported methods, and module initialization.
+   * <p>
+   * The GWT compiler and hosted mode will provide a module-scoped  
variable,
+   * <code>$entry</code>, which is an alias for this method.
+   * <p>
+   * This method can be called reentrantly, which will simply delegate to  
the
+   * function.
+   * <p>
+   * The function passed to this method will be invoked via
+   * <code>Function.apply()</code> with the current <code>this</code>  
value and
+   * the invocation arguments passed to <code>$entry</code>.
+   *
+   * @param jsFunction a JS function to invoke, which is typically a JSNI
+   *          reference to a static Java method
+   * @return the value returned when <code>jsFunction</code> is invoked, or
+   *         <code>undefined</code> if the UncaughtExceptionHandler  
catches an
+   *         exception raised by <code>jsFunction</code>
+   */
+  public static native JavaScriptObject entry(JavaScriptObject jsFunction)  
/*-{
+    return function() {
+      return  
@com.google.gwt.core.client.impl.Impl::entry0(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)(jsFunction,
  
this, arguments);
+    };
+  }-*/;
+
    /**
     * Gets an identity-based hash code on the passed-in Object by adding an
     * expando. This method should not be used with <code>null</code> or any
@@ -94,6 +126,76 @@
    public static native String getPermutationStrongName() /*-{
      return $strongName;
    }-*/;
+
+  /**
+   * Implicitly called by JavaToJavaScriptCompiler.findEntryPoints().
+   */
+  public static native JavaScriptObject registerEntry() /*-{
+    if (@com.google.gwt.core.client.GWT::isScript()()) {
+      // Assignment to $entry is done by the compiler
+      return  
@com.google.gwt.core.client.impl.Impl::entry(Lcom/google/gwt/core/client/JavaScriptObject;);
+    } else {
+      // But we have to do in in hosted mode
+      return $entry =  
@com.google.gwt.core.client.impl.Impl::entry(Lcom/google/gwt/core/client/JavaScriptObject;);
+    }
+  }-*/;
+
+  private static native Object apply(Object jsFunction, Object thisObj,
+      Object arguments) /*-{
+    if (@com.google.gwt.core.client.GWT::isScript()()) {
+      return jsFunction.apply(thisObj, arguments);
+    } else {
+      _ = jsFunction.apply(thisObj, arguments);
+      if (_ != null) {
+        // Wrap for hosted mode
+        _ = Object(_);
+      }
+      return _;
+    }
+  }-*/;
+
+  /**
+   * Implements {...@link #entry(JavaScriptObject)}.
+   */
+  @SuppressWarnings("unused")
+  private static Object entry0(Object jsFunction, Object thisObj,
+      Object arguments) throws Throwable {
+    assert entryDepth >= 0 : "Negative entryDepth value at entry " +  
entryDepth;
+
+    // We want to disable some actions in the reentrant case
+    boolean initialEntry = entryDepth++ == 0;
+
+    try {
+      /*
+       * Always invoke the UCE if we have one so that the exception never
+       * percolates up to the browser's event loop, even in a reentrant
+       * situation.
+       */
+      if (GWT.getUncaughtExceptionHandler() != null) {
+        /*
+         * This try block is guarded by the if statement so that we don't  
molest
+         * the exception object traveling up the stack unless we're  
capable of
+         * doing something useful with it.
+         */
+        try {
+          return apply(jsFunction, thisObj, arguments);
+        } catch (Throwable t) {
+          GWT.getUncaughtExceptionHandler().onUncaughtException(t);
+          return undefined();
+        }
+      } else {
+        // Can't handle any exceptions, let them percolate normally
+        return apply(jsFunction, thisObj, arguments);
+      }
+    } finally {
+      if (initialEntry) {
+        // TODO(bobv) FinallyCommand.flush() goes here
+      }
+      entryDepth--;
+      assert entryDepth >= 0 : "Negative entryDepth value at exit "
+          + entryDepth;
+    }
+  }

    /**
     * Called from JSNI. Do not change this implementation without updating:
@@ -105,4 +207,9 @@
    private static int getNextHashId() {
      return ++sNextHashId;
    }
-}
+
+  private static native Object undefined() /*-{
+    // Intentionally not returning a value
+    return;
+  }-*/;
+}

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

Reply via email to