8061957: Some arithmetic operations have unnecessary widening

Mon, 03 Nov 2014 07:28:08 +0100

author
attila
date
Mon, 03 Nov 2014 07:28:08 +0100
changeset 1080
ad5f0c0eb313
parent 1077
d60fbb5343c1
child 1081
a54684572f14

8061957: Some arithmetic operations have unnecessary widening
Reviewed-by: hannesw, lagergren

src/jdk/nashorn/internal/codegen/CodeGenerator.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/IntType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/codegen/types/LongType.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/JSType.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Fri Oct 31 20:17:42 2014 -0700
     1.2 +++ b/src/jdk/nashorn/internal/codegen/CodeGenerator.java	Mon Nov 03 07:28:08 2014 +0100
     1.3 @@ -3569,7 +3569,8 @@
     1.4                      operandBounds = new TypeBounds(binaryNode.getType(), Type.OBJECT);
     1.5                  } else {
     1.6                      // Non-optimistic, non-FP +. Allow it to overflow.
     1.7 -                    operandBounds = new TypeBounds(binaryNode.getWidestOperandType(), Type.OBJECT);
     1.8 +                    operandBounds = new TypeBounds(Type.narrowest(binaryNode.getWidestOperandType(), resultBounds.widest),
     1.9 +                            Type.OBJECT);
    1.10                      forceConversionSeparation = binaryNode.getWidestOperationType().narrowerThan(resultBounds.widest);
    1.11                  }
    1.12                  loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false, forceConversionSeparation);
    1.13 @@ -3856,12 +3857,8 @@
    1.14                          operandBounds = numericBounds;
    1.15                      } else {
    1.16                          final boolean isOptimistic = isValid(getProgramPoint());
    1.17 -                        if(isOptimistic) {
    1.18 +                        if(isOptimistic || node.isTokenType(TokenType.DIV) || node.isTokenType(TokenType.MOD)) {
    1.19                              operandBounds = new TypeBounds(node.getType(), Type.NUMBER);
    1.20 -                        } else if(node.isTokenType(TokenType.DIV) || node.isTokenType(TokenType.MOD)) {
    1.21 -                            // Non-optimistic division must always take double arguments as its result must also be
    1.22 -                            // double.
    1.23 -                            operandBounds = TypeBounds.NUMBER;
    1.24                          } else {
    1.25                              // Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow.
    1.26                              operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(),
     2.1 --- a/src/jdk/nashorn/internal/codegen/types/IntType.java	Fri Oct 31 20:17:42 2014 -0700
     2.2 +++ b/src/jdk/nashorn/internal/codegen/types/IntType.java	Mon Nov 03 07:28:08 2014 +0100
     2.3 @@ -55,6 +55,7 @@
     2.4  
     2.5  import jdk.internal.org.objectweb.asm.MethodVisitor;
     2.6  import jdk.nashorn.internal.codegen.CompilerConstants;
     2.7 +import jdk.nashorn.internal.runtime.JSType;
     2.8  
     2.9  /**
    2.10   * Type class: INT
    2.11 @@ -230,19 +231,21 @@
    2.12  
    2.13      @Override
    2.14      public Type div(final MethodVisitor method, final int programPoint) {
    2.15 -        // Never perform non-optimistic integer division in JavaScript.
    2.16 -        assert programPoint != INVALID_PROGRAM_POINT;
    2.17 -
    2.18 -        method.visitInvokeDynamicInsn("idiv", "(II)I", MATHBOOTSTRAP, programPoint);
    2.19 +        if (programPoint == INVALID_PROGRAM_POINT) {
    2.20 +            JSType.DIV_ZERO.invoke(method);
    2.21 +        } else {
    2.22 +            method.visitInvokeDynamicInsn("idiv", "(II)I", MATHBOOTSTRAP, programPoint);
    2.23 +        }
    2.24          return INT;
    2.25      }
    2.26  
    2.27      @Override
    2.28      public Type rem(final MethodVisitor method, final int programPoint) {
    2.29 -        // Never perform non-optimistic integer remainder in JavaScript.
    2.30 -        assert programPoint != INVALID_PROGRAM_POINT;
    2.31 -
    2.32 -        method.visitInvokeDynamicInsn("irem", "(II)I", MATHBOOTSTRAP, programPoint);
    2.33 +        if (programPoint == INVALID_PROGRAM_POINT) {
    2.34 +            JSType.REM_ZERO.invoke(method);
    2.35 +        } else {
    2.36 +            method.visitInvokeDynamicInsn("irem", "(II)I", MATHBOOTSTRAP, programPoint);
    2.37 +        }
    2.38          return INT;
    2.39      }
    2.40  
     3.1 --- a/src/jdk/nashorn/internal/codegen/types/LongType.java	Fri Oct 31 20:17:42 2014 -0700
     3.2 +++ b/src/jdk/nashorn/internal/codegen/types/LongType.java	Mon Nov 03 07:28:08 2014 +0100
     3.3 @@ -170,19 +170,21 @@
     3.4  
     3.5      @Override
     3.6      public Type div(final MethodVisitor method, final int programPoint) {
     3.7 -        // Never perform non-optimistic integer division in JavaScript.
     3.8 -        assert programPoint != INVALID_PROGRAM_POINT;
     3.9 -
    3.10 -        method.visitInvokeDynamicInsn("ldiv", "(JJ)J", MATHBOOTSTRAP, programPoint);
    3.11 +        if (programPoint == INVALID_PROGRAM_POINT) {
    3.12 +            JSType.DIV_ZERO_LONG.invoke(method);
    3.13 +        } else {
    3.14 +            method.visitInvokeDynamicInsn("ldiv", "(JJ)J", MATHBOOTSTRAP, programPoint);
    3.15 +        }
    3.16          return LONG;
    3.17      }
    3.18  
    3.19      @Override
    3.20      public Type rem(final MethodVisitor method, final int programPoint) {
    3.21 -        // Never perform non-optimistic integer remainder in JavaScript.
    3.22 -        assert programPoint != INVALID_PROGRAM_POINT;
    3.23 -
    3.24 -        method.visitInvokeDynamicInsn("lrem", "(JJ)J", MATHBOOTSTRAP, programPoint);
    3.25 +        if (programPoint == INVALID_PROGRAM_POINT) {
    3.26 +            JSType.REM_ZERO_LONG.invoke(method);
    3.27 +        } else {
    3.28 +            method.visitInvokeDynamicInsn("lrem", "(JJ)J", MATHBOOTSTRAP, programPoint);
    3.29 +        }
    3.30          return LONG;
    3.31      }
    3.32  
     4.1 --- a/src/jdk/nashorn/internal/runtime/JSType.java	Fri Oct 31 20:17:42 2014 -0700
     4.2 +++ b/src/jdk/nashorn/internal/runtime/JSType.java	Mon Nov 03 07:28:08 2014 +0100
     4.3 @@ -150,6 +150,12 @@
     4.4      /** Div exact wrapper for potentially integer division that turns into float point */
     4.5      public static final Call DIV_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class);
     4.6  
     4.7 +    /** Div zero wrapper for integer division that handles (0/0)|0 == 0 */
     4.8 +    public static final Call DIV_ZERO        = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", int.class, int.class, int.class);
     4.9 +
    4.10 +    /** Mod zero wrapper for integer division that handles (0%0)|0 == 0 */
    4.11 +    public static final Call REM_ZERO        = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", int.class, int.class, int.class);
    4.12 +
    4.13      /** Mod exact wrapper for potentially integer remainders that turns into float point */
    4.14      public static final Call REM_EXACT       = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class);
    4.15  
    4.16 @@ -174,6 +180,12 @@
    4.17      /** Div exact wrapper for potentially integer division that turns into float point */
    4.18      public static final Call DIV_EXACT_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class);
    4.19  
    4.20 +    /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */
    4.21 +    public static final Call DIV_ZERO_LONG        = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class);
    4.22 +
    4.23 +    /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */
    4.24 +    public static final Call REM_ZERO_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class);
    4.25 +
    4.26      /** Mod exact wrapper for potentially integer remainders that turns into float point */
    4.27      public static final Call REM_EXACT_LONG       = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class);
    4.28  
    4.29 @@ -1486,6 +1498,28 @@
    4.30      }
    4.31  
    4.32      /**
    4.33 +     * Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to
    4.34 +     * {@code (x / y)|0} JavaScript expression (division of two ints coerced to int).
    4.35 +     * @param x the dividend
    4.36 +     * @param y the divisor
    4.37 +     * @return the result
    4.38 +     */
    4.39 +    public static int divZero(final int x, final int y) {
    4.40 +        return y == 0 ? 0 : x / y;
    4.41 +    }
    4.42 +
    4.43 +    /**
    4.44 +     * Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to
    4.45 +     * {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int).
    4.46 +     * @param x the dividend
    4.47 +     * @param y the divisor
    4.48 +     * @return the remainder
    4.49 +     */
    4.50 +    public static int remZero(final int x, final int y) {
    4.51 +        return y == 0 ? 0 : x % y;
    4.52 +    }
    4.53 +
    4.54 +    /**
    4.55       * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
    4.56       *
    4.57       * @param x first term
    4.58 @@ -1529,6 +1563,28 @@
    4.59      }
    4.60  
    4.61      /**
    4.62 +     * Implements long division but allows {@code x / 0} to be represented as 0. Useful when division of two longs
    4.63 +     * is coerced to long.
    4.64 +     * @param x the dividend
    4.65 +     * @param y the divisor
    4.66 +     * @return the result
    4.67 +     */
    4.68 +    public static long divZero(final long x, final long y) {
    4.69 +        return y == 0L ? 0L : x / y;
    4.70 +    }
    4.71 +
    4.72 +    /**
    4.73 +     * Implements long remainder but allows {@code x % 0} to be represented as 0. Useful when remainder of two longs
    4.74 +     * is coerced to long.
    4.75 +     * @param x the dividend
    4.76 +     * @param y the divisor
    4.77 +     * @return the remainder
    4.78 +     */
    4.79 +    public static long remZero(final long x, final long y) {
    4.80 +        return y == 0L ? 0L : x % y;
    4.81 +    }
    4.82 +
    4.83 +    /**
    4.84       * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int.
    4.85       *
    4.86       * @param x first term

mercurial