# HG changeset patch # User attila # Date 1414996088 -3600 # Node ID 8898e06e68c1cec9b793bb86fecdad05fa400c0e # Parent 8caab9a29b623594decc7657cd61ae40fad55e86 8061957: Some arithmetic operations have unnecessary widening Reviewed-by: hannesw, lagergren diff -r 8caab9a29b62 -r 8898e06e68c1 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Fri Oct 31 16:50:31 2014 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java Mon Nov 03 07:28:08 2014 +0100 @@ -3569,7 +3569,8 @@ operandBounds = new TypeBounds(binaryNode.getType(), Type.OBJECT); } else { // Non-optimistic, non-FP +. Allow it to overflow. - operandBounds = new TypeBounds(binaryNode.getWidestOperandType(), Type.OBJECT); + operandBounds = new TypeBounds(Type.narrowest(binaryNode.getWidestOperandType(), resultBounds.widest), + Type.OBJECT); forceConversionSeparation = binaryNode.getWidestOperationType().narrowerThan(resultBounds.widest); } loadBinaryOperands(binaryNode.lhs(), binaryNode.rhs(), operandBounds, false, forceConversionSeparation); @@ -3856,12 +3857,8 @@ operandBounds = numericBounds; } else { final boolean isOptimistic = isValid(getProgramPoint()); - if(isOptimistic) { + if(isOptimistic || node.isTokenType(TokenType.DIV) || node.isTokenType(TokenType.MOD)) { operandBounds = new TypeBounds(node.getType(), Type.NUMBER); - } else if(node.isTokenType(TokenType.DIV) || node.isTokenType(TokenType.MOD)) { - // Non-optimistic division must always take double arguments as its result must also be - // double. - operandBounds = TypeBounds.NUMBER; } else { // Non-optimistic, non-FP subtraction or multiplication. Allow them to overflow. operandBounds = new TypeBounds(Type.narrowest(node.getWidestOperandType(), diff -r 8caab9a29b62 -r 8898e06e68c1 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/IntType.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/IntType.java Fri Oct 31 16:50:31 2014 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/IntType.java Mon Nov 03 07:28:08 2014 +0100 @@ -55,6 +55,7 @@ import jdk.internal.org.objectweb.asm.MethodVisitor; import jdk.nashorn.internal.codegen.CompilerConstants; +import jdk.nashorn.internal.runtime.JSType; /** * Type class: INT @@ -230,19 +231,21 @@ @Override public Type div(final MethodVisitor method, final int programPoint) { - // Never perform non-optimistic integer division in JavaScript. - assert programPoint != INVALID_PROGRAM_POINT; - - method.visitInvokeDynamicInsn("idiv", "(II)I", MATHBOOTSTRAP, programPoint); + if (programPoint == INVALID_PROGRAM_POINT) { + JSType.DIV_ZERO.invoke(method); + } else { + method.visitInvokeDynamicInsn("idiv", "(II)I", MATHBOOTSTRAP, programPoint); + } return INT; } @Override public Type rem(final MethodVisitor method, final int programPoint) { - // Never perform non-optimistic integer remainder in JavaScript. - assert programPoint != INVALID_PROGRAM_POINT; - - method.visitInvokeDynamicInsn("irem", "(II)I", MATHBOOTSTRAP, programPoint); + if (programPoint == INVALID_PROGRAM_POINT) { + JSType.REM_ZERO.invoke(method); + } else { + method.visitInvokeDynamicInsn("irem", "(II)I", MATHBOOTSTRAP, programPoint); + } return INT; } diff -r 8caab9a29b62 -r 8898e06e68c1 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/LongType.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/LongType.java Fri Oct 31 16:50:31 2014 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/types/LongType.java Mon Nov 03 07:28:08 2014 +0100 @@ -170,19 +170,21 @@ @Override public Type div(final MethodVisitor method, final int programPoint) { - // Never perform non-optimistic integer division in JavaScript. - assert programPoint != INVALID_PROGRAM_POINT; - - method.visitInvokeDynamicInsn("ldiv", "(JJ)J", MATHBOOTSTRAP, programPoint); + if (programPoint == INVALID_PROGRAM_POINT) { + JSType.DIV_ZERO_LONG.invoke(method); + } else { + method.visitInvokeDynamicInsn("ldiv", "(JJ)J", MATHBOOTSTRAP, programPoint); + } return LONG; } @Override public Type rem(final MethodVisitor method, final int programPoint) { - // Never perform non-optimistic integer remainder in JavaScript. - assert programPoint != INVALID_PROGRAM_POINT; - - method.visitInvokeDynamicInsn("lrem", "(JJ)J", MATHBOOTSTRAP, programPoint); + if (programPoint == INVALID_PROGRAM_POINT) { + JSType.REM_ZERO_LONG.invoke(method); + } else { + method.visitInvokeDynamicInsn("lrem", "(JJ)J", MATHBOOTSTRAP, programPoint); + } return LONG; } diff -r 8caab9a29b62 -r 8898e06e68c1 nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java --- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Fri Oct 31 16:50:31 2014 +0100 +++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/JSType.java Mon Nov 03 07:28:08 2014 +0100 @@ -150,6 +150,12 @@ /** Div exact wrapper for potentially integer division that turns into float point */ public static final Call DIV_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", int.class, int.class, int.class, int.class); + /** Div zero wrapper for integer division that handles (0/0)|0 == 0 */ + public static final Call DIV_ZERO = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", int.class, int.class, int.class); + + /** Mod zero wrapper for integer division that handles (0%0)|0 == 0 */ + public static final Call REM_ZERO = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", int.class, int.class, int.class); + /** Mod exact wrapper for potentially integer remainders that turns into float point */ public static final Call REM_EXACT = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", int.class, int.class, int.class, int.class); @@ -174,6 +180,12 @@ /** Div exact wrapper for potentially integer division that turns into float point */ public static final Call DIV_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divExact", long.class, long.class, long.class, int.class); + /** Div zero wrapper for long division that handles (0/0) >>> 0 == 0 */ + public static final Call DIV_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "divZero", long.class, long.class, long.class); + + /** Mod zero wrapper for long division that handles (0%0) >>> 0 == 0 */ + public static final Call REM_ZERO_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remZero", long.class, long.class, long.class); + /** Mod exact wrapper for potentially integer remainders that turns into float point */ public static final Call REM_EXACT_LONG = staticCall(JSTYPE_LOOKUP, JSType.class, "remExact", long.class, long.class, long.class, int.class); @@ -1486,6 +1498,28 @@ } /** + * Implements int division but allows {@code x / 0} to be represented as 0. Basically equivalent to + * {@code (x / y)|0} JavaScript expression (division of two ints coerced to int). + * @param x the dividend + * @param y the divisor + * @return the result + */ + public static int divZero(final int x, final int y) { + return y == 0 ? 0 : x / y; + } + + /** + * Implements int remainder but allows {@code x % 0} to be represented as 0. Basically equivalent to + * {@code (x % y)|0} JavaScript expression (remainder of two ints coerced to int). + * @param x the dividend + * @param y the divisor + * @return the remainder + */ + public static int remZero(final int x, final int y) { + return y == 0 ? 0 : x % y; + } + + /** * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. * * @param x first term @@ -1529,6 +1563,28 @@ } /** + * Implements long division but allows {@code x / 0} to be represented as 0. Useful when division of two longs + * is coerced to long. + * @param x the dividend + * @param y the divisor + * @return the result + */ + public static long divZero(final long x, final long y) { + return y == 0L ? 0L : x / y; + } + + /** + * Implements long remainder but allows {@code x % 0} to be represented as 0. Useful when remainder of two longs + * is coerced to long. + * @param x the dividend + * @param y the divisor + * @return the remainder + */ + public static long remZero(final long x, final long y) { + return y == 0L ? 0L : x % y; + } + + /** * Wrapper for modExact. Throws UnwarrantedOptimismException if the modulo can't be represented as int. * * @param x first term