Reviewers: scottb,

Description:
Operations like i += d where i is an int and d is a double are not
properly
truncated (narrowed) to the LHS type. This patch forces i += d to be
written as
i = i + d, and applies a narrowing cast as needed, e.g. i = (int)(i +
d);

Updated to fix String concat issue:


Please review this at http://gwt-code-reviews.appspot.com/1385803/

Affected files:
  M dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
M dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java M dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java


Index: dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java
===================================================================
--- dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java (revision 9856) +++ dev/core/src/com/google/gwt/dev/jjs/JavaToJavaScriptCompiler.java (working copy)
@@ -292,10 +292,10 @@
// (5) "Normalize" the high-level Java tree into a lower-level tree more
       // suited for JavaScript code generation. Don't go reordering these
       // willy-nilly because there are some subtle interdependencies.
-      LongCastNormalizer.exec(jprogram);
       JsoDevirtualizer.exec(jprogram);
       CatchBlockNormalizer.exec(jprogram);
       PostOptimizationCompoundAssignmentNormalizer.exec(jprogram);
+      LongCastNormalizer.exec(jprogram);
       LongEmulationNormalizer.exec(jprogram);
       CastNormalizer.exec(jprogram, options.isCastCheckingDisabled());
       ArrayNormalizer.exec(jprogram);
Index: dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java
===================================================================
--- dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java (revision 9856) +++ dev/core/src/com/google/gwt/dev/jjs/impl/CompoundAssignmentNormalizer.java (working copy)
@@ -161,8 +161,10 @@
           new JMultiExpression(x.getSourceInfo()));
       JExpression newLhs = replacer.accept(x.getLhs());

-      JBinaryOperation operation = new JBinaryOperation(x.getSourceInfo(),
+      JExpression operation = new JBinaryOperation(x.getSourceInfo(),
           newLhs.getType(), op.getNonAssignmentOf(), newLhs, x.getRhs());
+      operation = modifyResultOperation((JBinaryOperation) operation);
+
       // newLhs is cloned below because it was used in operation
JBinaryOperation asg = new JBinaryOperation(x.getSourceInfo(), newLhs.getType(),
           JBinaryOperator.ASG, cloner.cloneExpression(newLhs),
@@ -285,6 +287,16 @@
     return lhs;
   }

+  /**
+ * Decide what expression to return when breaking up a compound assignment of + * the form <code>lhs op= rhs</code>. The breakup creates an expression of
+   * the form <code>lhs = lhs op rhs</code>, and the right hand side of the
+   * newly created expression is passed to this method.
+   */
+  protected JExpression modifyResultOperation(JBinaryOperation op) {
+    return op;
+  }
+
   protected abstract boolean shouldBreakUp(JBinaryOperation x);

   protected abstract boolean shouldBreakUp(JPostfixOperation x);
Index: dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java
===================================================================
--- dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java (revision 9856) +++ dev/core/src/com/google/gwt/dev/jjs/impl/PostOptimizationCompoundAssignmentNormalizer.java (working copy)
@@ -17,10 +17,13 @@

 import com.google.gwt.dev.jjs.ast.JBinaryOperation;
 import com.google.gwt.dev.jjs.ast.JBinaryOperator;
+import com.google.gwt.dev.jjs.ast.JCastOperation;
+import com.google.gwt.dev.jjs.ast.JExpression;
 import com.google.gwt.dev.jjs.ast.JPostfixOperation;
 import com.google.gwt.dev.jjs.ast.JPrefixOperation;
 import com.google.gwt.dev.jjs.ast.JPrimitiveType;
 import com.google.gwt.dev.jjs.ast.JProgram;
+import com.google.gwt.dev.jjs.ast.JType;

 /**
* Normalize compound assignments as needed after optimization. Integer division
@@ -36,6 +39,21 @@
   }

   @Override
+  protected JExpression modifyResultOperation(JBinaryOperation op) {
+    JType lhsType = op.getLhs().getType();
+    JType rhsType = op.getRhs().getType();
+    if (lhsType != rhsType) {
+ // first widen binary op to encompass both sides, then add narrow cast
+      return new JCastOperation(op.getSourceInfo(), lhsType,
+          new JBinaryOperation(op.getSourceInfo(),
+              widenType(lhsType, rhsType),
+              op.getOp(),
+              op.getLhs(), op.getRhs()));
+    }
+    return op;
+  }
+
+  @Override
   protected boolean shouldBreakUp(JBinaryOperation x) {
     if (x.getType() == JPrimitiveType.LONG) {
       return true;
@@ -43,6 +61,13 @@
     if (x.getOp() == JBinaryOperator.ASG_DIV
         && x.getType() != JPrimitiveType.FLOAT
         && x.getType() != JPrimitiveType.DOUBLE) {
+      return true;
+    }
+
+    JType lhsType = x.getLhs().getType();
+    JType rhsType = x.getRhs().getType();
+    // break up so that result may be coerced to LHS type
+    if (isIntegral(lhsType) && !isIntegral(rhsType)) {
       return true;
     }
     return false;
@@ -63,4 +88,25 @@
     }
     return false;
   }
+
+  private boolean isIntegral(JType type) {
+    // if it can't be widened into a long, it must be float
+    return type instanceof JPrimitiveType &&
+        widenType(type, JPrimitiveType.LONG) == JPrimitiveType.LONG;
+  }
+
+  private JType widenType(JType lhsType, JType rhsType) {
+    if (lhsType == JPrimitiveType.DOUBLE ||
+        rhsType == JPrimitiveType.DOUBLE) {
+      return JPrimitiveType.DOUBLE;
+    } else if (lhsType == JPrimitiveType.FLOAT ||
+        rhsType == JPrimitiveType.FLOAT) {
+      return JPrimitiveType.FLOAT;
+    } else if (lhsType == JPrimitiveType.LONG ||
+        rhsType == JPrimitiveType.LONG) {
+      return JPrimitiveType.LONG;
+    } else {
+      return JPrimitiveType.INT;
+    }
+  }
 }


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

Reply via email to