Reimplements x == null => !x transforms in EqualityNormalizer; the replacements to Cast.jsEquals() were thwarting the GenerateJavaScriptAST version.

Review by: spoon


git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@2544 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java b/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
index c17fbc0..4c3e437 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/EqualityNormalizer.java
@@ -93,19 +93,40 @@
             x.getSourceInfo(), x.getType(), x.getOp(), lhs, rhs);
         ctx.replaceMe(binOp);
       } else {
-        // Replace with a call to Cast.jsEquals, which does a == internally.
-        String methodName;
-        if (op == JBinaryOperator.EQ) {
-          methodName = "Cast.jsEquals";
+        boolean lhsNullLit = lhs == program.getLiteralNull();
+        boolean rhsNullLit = rhs == program.getLiteralNull();
+        if ((lhsNullLit && rhsStatus == StringStatus.NOTSTRING)
+            || (rhsNullLit && lhsStatus == StringStatus.NOTSTRING)) {
+          /*
+           * If either side is a null literal and the other is non-String,
+           * replace with a null-check.
+           */
+          String methodName;
+          if (op == JBinaryOperator.EQ) {
+            methodName = "Cast.isNull";
+          } else {
+            methodName = "Cast.isNotNull";
+          }
+          JMethod isNullMethod = program.getIndexedMethod(methodName);
+          JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
+              isNullMethod);
+          call.getArgs().add(lhsNullLit ? rhs : lhs);
+          ctx.replaceMe(call);
         } else {
-          methodName = "Cast.jsNotEquals";
+          // Replace with a call to Cast.jsEquals, which does a == internally.
+          String methodName;
+          if (op == JBinaryOperator.EQ) {
+            methodName = "Cast.jsEquals";
+          } else {
+            methodName = "Cast.jsNotEquals";
+          }
+          JMethod eqMethod = program.getIndexedMethod(methodName);
+          JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
+              eqMethod);
+          call.getArgs().add(lhs);
+          call.getArgs().add(rhs);
+          ctx.replaceMe(call);
         }
-        JMethod eqMethod = program.getIndexedMethod(methodName);
-        JMethodCall call = new JMethodCall(program, x.getSourceInfo(), null,
-            eqMethod);
-        call.getArgs().add(lhs);
-        call.getArgs().add(rhs);
-        ctx.replaceMe(call);
       }
     }
 
diff --git a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
index f027b4d..ec71c24 100644
--- a/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
+++ b/dev/core/src/com/google/gwt/dev/jjs/impl/GenerateJavaScriptAST.java
@@ -54,7 +54,6 @@
 import com.google.gwt.dev.jjs.ast.JMethodCall;
 import com.google.gwt.dev.jjs.ast.JNewArray;
 import com.google.gwt.dev.jjs.ast.JNewInstance;
-import com.google.gwt.dev.jjs.ast.JNullLiteral;
 import com.google.gwt.dev.jjs.ast.JParameter;
 import com.google.gwt.dev.jjs.ast.JParameterRef;
 import com.google.gwt.dev.jjs.ast.JPostfixOperation;
@@ -407,33 +406,6 @@
       JsBinaryOperator myOp = JavaToJsOperatorMap.get(x.getOp());
 
       /*
-       * Optimize null tests. We cannot do this with strings, however, because
-       * in JavaScript the empty string evaluates to boolean false.
-       * 
-       * (foo == null) => !foo
-       * 
-       * (foo != null) => !!foo (coerces to boolean)
-       */
-      if ((x.getOp() == JBinaryOperator.EQ)
-          || (x.getOp() == JBinaryOperator.NEQ)) {
-        boolean lhsNull = x.getLhs() instanceof JNullLiteral;
-        boolean rhsNull = x.getRhs() instanceof JNullLiteral;
-        if (lhsNull || rhsNull) {
-          JExpression toUse = lhsNull ? x.getRhs() : x.getLhs();
-          JsExpression toUseJs = lhsNull ? rhs : lhs;
-          if (!couldBeString(toUse)) {
-            if ((x.getOp() == JBinaryOperator.EQ)) {
-              push(new JsPrefixOperation(JsUnaryOperator.NOT, toUseJs));
-            } else {
-              push(new JsPrefixOperation(JsUnaryOperator.NOT,
-                  new JsPrefixOperation(JsUnaryOperator.NOT, toUseJs)));
-            }
-            return;
-          }
-        }
-      }
-
-      /*
        * Use === and !== on reference types, or else you can get wrong answers
        * when Object.toString() == 'some string'.
        */
diff --git a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
index 2691f4b..54136c1 100644
--- a/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
+++ b/dev/core/super/com/google/gwt/dev/jjs/intrinsic/com/google/gwt/lang/Cast.java
@@ -78,6 +78,23 @@
     return src.typeMarker != getNullMethod() && src.typeId != 2;
   }
 
+  /**
+   * Uses the not operator to perform a null-check; do NOT use on anything that
+   * could be a String.
+   */
+  static native boolean isNotNull(Object src) /*-{
+    // Coerce to boolean.
+    return !!src;
+  }-*/;
+
+  /**
+   * Uses the not operator to perform a null-check; do NOT use on anything that
+   * could be a String.
+   */
+  static native boolean isNull(Object src) /*-{
+    return !src;
+  }-*/;
+
   static native boolean jsEquals(Object a, Object b) /*-{
     return a == b;
   }-*/;