Mon, 03 Nov 2014 07:28:08 +0100
8061957: Some arithmetic operations have unnecessary widening
Reviewed-by: hannesw, lagergren
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