Revision: 8300
Author: j...@google.com
Date: Tue Jun 22 11:13:30 2010
Log: Work around Safari 5 failures where right-shift of a non-integer is not
coerced to an integer.

See https://bugs.webkit.org/show_bug.cgi?id=40367 and
http://trac.webkit.org/changeset/60990 for details.

Patch by: jat
Review by: spoon, jgw

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

Added:
 /trunk/dev/core/src/com/google/gwt/dev/js/JsCoerceIntShift.java
 /trunk/dev/core/test/com/google/gwt/dev/js/JsCoerceIntShiftTest.java
Modified:
 /trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java

=======================================
--- /dev/null
+++ /trunk/dev/core/src/com/google/gwt/dev/js/JsCoerceIntShift.java Tue Jun 22 11:13:30 2010
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2010 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.js;
+
+import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.core.ext.SelectionProperty;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.jjs.SourceInfo;
+import com.google.gwt.dev.js.ast.JsBinaryOperation;
+import com.google.gwt.dev.js.ast.JsBinaryOperator;
+import com.google.gwt.dev.js.ast.JsContext;
+import com.google.gwt.dev.js.ast.JsExpression;
+import com.google.gwt.dev.js.ast.JsModVisitor;
+import com.google.gwt.dev.js.ast.JsPrefixOperation;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsUnaryOperator;
+
+/**
+ * Coerces lhs of right shift operations to int. Necessary for Safari 5 bug
+ * https://bugs.webkit.org/show_bug.cgi?id=40367 fixed in
+ * http://trac.webkit.org/changeset/60990 -- this should be removed once that
+ * fix has been pushed.
+ */
+public class JsCoerceIntShift {
+  // TODO(jat): remove this once Safari 5 has the update
+
+  /**
+   * Rewrite a >> b as (~~a) >> b.
+   */
+  private static class MyVisitor extends JsModVisitor {
+
+    @Override
+ public void endVisit(JsBinaryOperation x, JsContext<JsExpression> ctx) {
+      JsBinaryOperator op = x.getOperator();
+      if (op != JsBinaryOperator.SHR && op != JsBinaryOperator.SHRU) {
+        return;
+      }
+
+      SourceInfo sourceInfo = x.getSourceInfo();
+      JsExpression lhs = x.getArg1();
+      JsExpression rhs = x.getArg2();
+      JsExpression newNode = new JsBinaryOperation(sourceInfo, op,
+          new JsPrefixOperation(sourceInfo, JsUnaryOperator.BIT_NOT,
+          new JsPrefixOperation(sourceInfo, JsUnaryOperator.BIT_NOT, lhs)),
+          rhs);
+      ctx.replaceMe(newNode);
+    }
+  }
+
+  /**
+ * If this permutation may be executed on WebKit, rewrite a >> b as ~~a
b.
+   *
+   * @param program
+   * @param logger
+   * @param propertyOracles
+   * @return true if any changes were made
+   */
+  public static boolean exec(JsProgram program, TreeLogger logger,
+      PropertyOracle[] propertyOracles) {
+    boolean seenWebKit = false;
+    for (PropertyOracle oracle : propertyOracles) {
+      try {
+        SelectionProperty prop = oracle.getSelectionProperty(logger,
+            "user.agent");
+        // TODO(jat): more checks if we split up the safari permutation
+        if ("safari".equals(prop.getCurrentValue())) {
+          seenWebKit = true;
+          break;
+        }
+      } catch (BadPropertyValueException e) {
+ // if we couldn't get the property, assume this might be used on WebKit.
+        seenWebKit = true;
+        break;
+      }
+    }
+    if (!seenWebKit) {
+      return false;
+    }
+    MyVisitor v = new MyVisitor();
+    v.accept(program);
+    return v.didChange();
+  }
+}
=======================================
--- /dev/null
+++ /trunk/dev/core/test/com/google/gwt/dev/js/JsCoerceIntShiftTest.java Tue Jun 22 11:13:30 2010
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2010 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.js;
+
+import com.google.gwt.core.ext.BadPropertyValueException;
+import com.google.gwt.core.ext.ConfigurationProperty;
+import com.google.gwt.core.ext.DefaultSelectionProperty;
+import com.google.gwt.core.ext.PropertyOracle;
+import com.google.gwt.core.ext.SelectionProperty;
+import com.google.gwt.core.ext.TreeLogger;
+import com.google.gwt.dev.jjs.SourceOrigin;
+import com.google.gwt.dev.js.ast.JsProgram;
+import com.google.gwt.dev.js.ast.JsStatement;
+import com.google.gwt.dev.js.ast.JsVisitor;
+import com.google.gwt.dev.shell.FailErrorLogger;
+import com.google.gwt.dev.util.DefaultTextOutput;
+import com.google.gwt.dev.util.TextOutput;
+
+import junit.framework.TestCase;
+
+import java.io.StringReader;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+/**
+ * Test for {...@link JsCoerceIntShift}.
+ */
+public class JsCoerceIntShiftTest extends TestCase {
+
+  /**
+   * Oracle that mocks the user.agent property.
+   */
+  private static class MockOracle implements PropertyOracle {
+
+ private static SelectionProperty createSelectionProperty(String value) {
+      if (value == null) {
+        return null;
+      } else {
+        SortedSet<String> valueSet = new TreeSet<String>();
+        valueSet.add(value);
+        return new DefaultSelectionProperty(value, value, value, valueSet);
+      }
+    }
+
+    private final SelectionProperty userAgent;
+
+    /**
+     * @param userAgentName value of user.agent property, if null then the
+     *     user.agent property is treated as if it doesn't exist.
+     */
+    public MockOracle(String userAgentName) {
+      userAgent = createSelectionProperty(userAgentName);
+    }
+
+ public ConfigurationProperty getConfigurationProperty(String propertyName)
+        throws BadPropertyValueException {
+      throw new BadPropertyValueException("no config properties");
+    }
+
+    @Deprecated
+    public String getPropertyValue(TreeLogger logger, String propertyName)
+        throws BadPropertyValueException {
+      throw new BadPropertyValueException("no deprecated api");
+    }
+
+    @Deprecated
+ public String[] getPropertyValueSet(TreeLogger logger, String propertyName)
+        throws BadPropertyValueException {
+      throw new BadPropertyValueException("no deprecated api");
+    }
+
+    public SelectionProperty getSelectionProperty(TreeLogger logger,
+        String propertyName) throws BadPropertyValueException {
+      if (userAgent != null && "user.agent".equals(propertyName)) {
+        return userAgent;
+      }
+      throw new BadPropertyValueException("no property " + propertyName);
+    }
+  }
+
+  private PropertyOracle safariOracle = new MockOracle("safari");
+  private PropertyOracle firefoxOracle = new MockOracle("gecko1_8");
+  private PropertyOracle ieOracle = new MockOracle("ie6");
+  private PropertyOracle noAgentOracle = new MockOracle(null);
+
+  private TreeLogger logger = new FailErrorLogger();
+
+  public void testNonSafari() throws Exception {
+    assertNotRewritten(firefoxOracle);
+    assertNotRewritten(ieOracle, firefoxOracle);
+  }
+
+  public void testNoUserAgent() throws Exception {
+    assertRewritten(noAgentOracle);
+    assertRewritten(firefoxOracle, noAgentOracle);
+  }
+
+  public void testSafari() throws Exception {
+    assertRewritten(safariOracle);
+    assertRewritten(firefoxOracle, safariOracle);
+  }
+
+  /**
+   * Assert that the provided PropertyOracles do not cause a rewrite of
+   * right-shift operations.
+   *
+   * @param oracles
+   * @throws Exception
+   */
+ private void assertNotRewritten(PropertyOracle... oracles) throws Exception {
+    assertEquals("a<<b;", process("a<<b;", oracles));
+    assertEquals("a>>b;", process("a>>b;", oracles));
+    assertEquals("a>>>b;", process("a>>>b;", oracles));
+    assertEquals("1+1>>2;", process("1+1>>2;", oracles));
+  }
+
+  /**
+ * Assert that the provided PropertyOracles do cause a rewrite of right-shift
+   * operations.
+   *
+   * @param oracles
+   * @throws Exception
+   */
+ private void assertRewritten(PropertyOracle... oracles) throws Exception {
+    assertEquals("a<<b;", process("a<<b;", oracles));
+    assertEquals("~~a>>b;", process("a>>b;", oracles));
+    assertEquals("~~a>>>b;", process("a>>>b;", oracles));
+    assertEquals("~~(1+1)>>2;", process("1+1>>2;", oracles));
+  }
+
+  /**
+   * Process a JS program with the {...@link JsCoerceIntShift} pass.
+   *
+   * @param js the source program
+   * @param oracles
+   * @return processed JS
+   */
+  private String process(String js, PropertyOracle[] oracles)
+      throws Exception {
+    JsProgram program = new JsProgram();
+    List<JsStatement> expected = JsParser.parse(SourceOrigin.UNKNOWN,
+        program.getScope(), new StringReader(js));
+
+    program.getGlobalBlock().getStatements().addAll(expected);
+
+    JsCoerceIntShift.exec(program, logger, oracles);
+
+    TextOutput text = new DefaultTextOutput(true);
+    JsVisitor generator = new JsSourceGenerationVisitor(text);
+
+    generator.accept(program);
+    return text.toString();
+  }
+}
=======================================
--- /trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java Mon Apr 26 12:05:27 2010 +++ /trunk/dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java Tue Jun 22 11:13:30 2010
@@ -95,6 +95,7 @@
 import com.google.gwt.dev.jjs.impl.gflow.DataflowOptimizer;
 import com.google.gwt.dev.js.EvalFunctionsAtTopScope;
 import com.google.gwt.dev.js.JsBreakUpLargeVarStatements;
+import com.google.gwt.dev.js.JsCoerceIntShift;
 import com.google.gwt.dev.js.JsDuplicateFunctionRemover;
 import com.google.gwt.dev.js.JsIEBlockSizeVisitor;
 import com.google.gwt.dev.js.JsInliner;
@@ -302,6 +303,13 @@
        */
       JsStackEmulator.exec(jsProgram, propertyOracles);

+      /*
+       * Work around Safari 5 bug by rewriting a >> b as ~~a >> b.
+       *
+       * No shifts may be generated after this point.
+       */
+      JsCoerceIntShift.exec(jsProgram, logger, propertyOracles);
+
       // (10) Split up the program into fragments
       SyntheticArtifact dependencies = null;
       if (options.isRunAsyncEnabled()) {

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

Reply via email to