nuke overflow detection as we cannot guarantee for def. simplify life :)

This commit is contained in:
Robert Muir 2016-05-19 15:25:31 -04:00
parent 915ab16176
commit b9c7dbcfbd
14 changed files with 66 additions and 1758 deletions

View File

@ -24,47 +24,16 @@ package org.elasticsearch.painless;
*/
public final class CompilerSettings {
/**
* Constant to be used when specifying numeric overflow when compiling a script.
*/
public static final String NUMERIC_OVERFLOW = "numeric_overflow";
/**
* Constant to be used when specifying the maximum loop counter when compiling a script.
*/
public static final String MAX_LOOP_COUNTER = "max_loop_counter";
/**
* Whether or not to allow numeric values to overflow without exception.
*/
private boolean numericOverflow = true;
/**
* The maximum number of statements allowed to be run in a loop.
*/
private int maxLoopCounter = 10000;
/**
* Returns {@code true} if numeric operations should overflow, {@code false}
* if they should signal an exception.
* <p>
* If this value is {@code true} (default), then things behave like java:
* overflow for integer types can result in unexpected values / unexpected
* signs, and overflow for floating point types can result in infinite or
* {@code NaN} values.
*/
public final boolean getNumericOverflow() {
return numericOverflow;
}
/**
* Set {@code true} for numerics to overflow, false to deliver exceptions.
* @see #getNumericOverflow
*/
public final void setNumericOverflow(boolean allow) {
this.numericOverflow = allow;
}
/**
* Returns the value for the cumulative total number of statements that can be made in all loops
* in a script before an exception is thrown. This attempts to prevent infinite loops. Note if

View File

@ -34,10 +34,6 @@ import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
import static org.elasticsearch.painless.WriterConstants.ADDEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.ADDEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.ADDWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.ADDWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.DEF_ADD_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_AND_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_DIV_CALL;
@ -49,19 +45,9 @@ import static org.elasticsearch.painless.WriterConstants.DEF_RSH_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_SUB_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_USH_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_XOR_CALL;
import static org.elasticsearch.painless.WriterConstants.DIVWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.DIVWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.DIVWOOVERLOW_INT;
import static org.elasticsearch.painless.WriterConstants.DIVWOOVERLOW_LONG;
import static org.elasticsearch.painless.WriterConstants.INDY_STRING_CONCAT_BOOTSTRAP_HANDLE;
import static org.elasticsearch.painless.WriterConstants.MAX_INDY_STRING_CONCAT_ARGS;
import static org.elasticsearch.painless.WriterConstants.MULEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.MULEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.MULWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.MULWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.PAINLESS_ERROR_TYPE;
import static org.elasticsearch.painless.WriterConstants.REMWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.REMWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_BOOLEAN;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_CHAR;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_APPEND_DOUBLE;
@ -74,28 +60,6 @@ import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_CONSTRUCT
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_TOSTRING;
import static org.elasticsearch.painless.WriterConstants.STRINGBUILDER_TYPE;
import static org.elasticsearch.painless.WriterConstants.STRING_TYPE;
import static org.elasticsearch.painless.WriterConstants.SUBEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.SUBEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.SUBWOOVERLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.SUBWOOVERLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOBYTEEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.TOBYTEEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.TOBYTEWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOBYTEWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOCHAREXACT_INT;
import static org.elasticsearch.painless.WriterConstants.TOCHAREXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.TOCHARWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOCHARWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOFLOATWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOINTEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.TOINTWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOINTWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOLONGWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOLONGWOOVERFLOW_FLOAT;
import static org.elasticsearch.painless.WriterConstants.TOSHORTEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.TOSHORTEXACT_LONG;
import static org.elasticsearch.painless.WriterConstants.TOSHORTWOOVERFLOW_DOUBLE;
import static org.elasticsearch.painless.WriterConstants.TOSHORTWOOVERFLOW_FLOAT;
/**
* Extension of {@link GeneratorAdapter} with some utility methods.
@ -236,231 +200,53 @@ public final class MethodWriter extends GeneratorAdapter {
}
}
public void writeBinaryInstruction(final CompilerSettings settings, final Definition definition,
public void writeBinaryInstruction(final Definition definition,
final String location,
final Type type, final Operation operation) {
final Sort sort = type.sort;
boolean exact = !settings.getNumericOverflow() &&
((sort == Sort.INT || sort == Sort.LONG) &&
(operation == Operation.MUL || operation == Operation.DIV ||
operation == Operation.ADD || operation == Operation.SUB) ||
(sort == Sort.FLOAT || sort == Sort.DOUBLE) &&
(operation == Operation.MUL || operation == Operation.DIV || operation == Operation.REM ||
operation == Operation.ADD || operation == Operation.SUB));
if (exact) {
switch (sort) {
case INT:
switch (operation) {
case MUL: invokeStatic(definition.getType("Math").type, MULEXACT_INT); break;
case DIV: invokeStatic(definition.getType("Utility").type, DIVWOOVERLOW_INT); break;
case ADD: invokeStatic(definition.getType("Math").type, ADDEXACT_INT); break;
case SUB: invokeStatic(definition.getType("Math").type, SUBEXACT_INT); break;
}
if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) &&
(operation == Operation.LSH || operation == Operation.USH ||
operation == Operation.RSH || operation == Operation.BWAND ||
operation == Operation.XOR || operation == Operation.BWOR)) {
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
break;
case LONG:
switch (operation) {
case MUL: invokeStatic(definition.getType("Math").type, MULEXACT_LONG); break;
case DIV: invokeStatic(definition.getType("Utility").type, DIVWOOVERLOW_LONG); break;
case ADD: invokeStatic(definition.getType("Math").type, ADDEXACT_LONG); break;
case SUB: invokeStatic(definition.getType("Math").type, SUBEXACT_LONG); break;
}
break;
case FLOAT:
switch (operation) {
case MUL: invokeStatic(definition.getType("Utility").type, MULWOOVERLOW_FLOAT); break;
case DIV: invokeStatic(definition.getType("Utility").type, DIVWOOVERLOW_FLOAT); break;
case REM: invokeStatic(definition.getType("Utility").type, REMWOOVERLOW_FLOAT); break;
case ADD: invokeStatic(definition.getType("Utility").type, ADDWOOVERLOW_FLOAT); break;
case SUB: invokeStatic(definition.getType("Utility").type, SUBWOOVERLOW_FLOAT); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
break;
case DOUBLE:
switch (operation) {
case MUL: invokeStatic(definition.getType("Utility").type, MULWOOVERLOW_DOUBLE); break;
case DIV: invokeStatic(definition.getType("Utility").type, DIVWOOVERLOW_DOUBLE); break;
case REM: invokeStatic(definition.getType("Utility").type, REMWOOVERLOW_DOUBLE); break;
case ADD: invokeStatic(definition.getType("Utility").type, ADDWOOVERLOW_DOUBLE); break;
case SUB: invokeStatic(definition.getType("Utility").type, SUBWOOVERLOW_DOUBLE); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
break;
if (sort == Sort.DEF) {
switch (operation) {
case MUL: invokeStatic(definition.getType("Def").type, DEF_MUL_CALL); break;
case DIV: invokeStatic(definition.getType("Def").type, DEF_DIV_CALL); break;
case REM: invokeStatic(definition.getType("Def").type, DEF_REM_CALL); break;
case ADD: invokeStatic(definition.getType("Def").type, DEF_ADD_CALL); break;
case SUB: invokeStatic(definition.getType("Def").type, DEF_SUB_CALL); break;
case LSH: invokeStatic(definition.getType("Def").type, DEF_LSH_CALL); break;
case USH: invokeStatic(definition.getType("Def").type, DEF_RSH_CALL); break;
case RSH: invokeStatic(definition.getType("Def").type, DEF_USH_CALL); break;
case BWAND: invokeStatic(definition.getType("Def").type, DEF_AND_CALL); break;
case XOR: invokeStatic(definition.getType("Def").type, DEF_XOR_CALL); break;
case BWOR: invokeStatic(definition.getType("Def").type, DEF_OR_CALL); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
} else {
if ((sort == Sort.FLOAT || sort == Sort.DOUBLE) &&
(operation == Operation.LSH || operation == Operation.USH ||
operation == Operation.RSH || operation == Operation.BWAND ||
operation == Operation.XOR || operation == Operation.BWOR)) {
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
if (sort == Sort.DEF) {
switch (operation) {
case MUL: invokeStatic(definition.getType("Def").type, DEF_MUL_CALL); break;
case DIV: invokeStatic(definition.getType("Def").type, DEF_DIV_CALL); break;
case REM: invokeStatic(definition.getType("Def").type, DEF_REM_CALL); break;
case ADD: invokeStatic(definition.getType("Def").type, DEF_ADD_CALL); break;
case SUB: invokeStatic(definition.getType("Def").type, DEF_SUB_CALL); break;
case LSH: invokeStatic(definition.getType("Def").type, DEF_LSH_CALL); break;
case USH: invokeStatic(definition.getType("Def").type, DEF_RSH_CALL); break;
case RSH: invokeStatic(definition.getType("Def").type, DEF_USH_CALL); break;
case BWAND: invokeStatic(definition.getType("Def").type, DEF_AND_CALL); break;
case XOR: invokeStatic(definition.getType("Def").type, DEF_XOR_CALL); break;
case BWOR: invokeStatic(definition.getType("Def").type, DEF_OR_CALL); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
} else {
switch (operation) {
case MUL: math(GeneratorAdapter.MUL, type.type); break;
case DIV: math(GeneratorAdapter.DIV, type.type); break;
case REM: math(GeneratorAdapter.REM, type.type); break;
case ADD: math(GeneratorAdapter.ADD, type.type); break;
case SUB: math(GeneratorAdapter.SUB, type.type); break;
case LSH: math(GeneratorAdapter.SHL, type.type); break;
case USH: math(GeneratorAdapter.USHR, type.type); break;
case RSH: math(GeneratorAdapter.SHR, type.type); break;
case BWAND: math(GeneratorAdapter.AND, type.type); break;
case XOR: math(GeneratorAdapter.XOR, type.type); break;
case BWOR: math(GeneratorAdapter.OR, type.type); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
switch (operation) {
case MUL: math(GeneratorAdapter.MUL, type.type); break;
case DIV: math(GeneratorAdapter.DIV, type.type); break;
case REM: math(GeneratorAdapter.REM, type.type); break;
case ADD: math(GeneratorAdapter.ADD, type.type); break;
case SUB: math(GeneratorAdapter.SUB, type.type); break;
case LSH: math(GeneratorAdapter.SHL, type.type); break;
case USH: math(GeneratorAdapter.USHR, type.type); break;
case RSH: math(GeneratorAdapter.SHR, type.type); break;
case BWAND: math(GeneratorAdapter.AND, type.type); break;
case XOR: math(GeneratorAdapter.XOR, type.type); break;
case BWOR: math(GeneratorAdapter.OR, type.type); break;
default:
throw new IllegalStateException("Error " + location + ": Illegal tree structure.");
}
}
}
/**
* Called for any compound assignment (including increment/decrement instructions).
* We have to be stricter than writeBinary and do overflow checks against the original type's size
* instead of the promoted type's size, since the result will be implicitly cast back.
*
* @return This will be true if an instruction is written, false otherwise.
*/
public boolean writeExactInstruction(
final Definition definition, final Sort fsort, final Sort tsort) {
if (fsort == Sort.DOUBLE) {
if (tsort == Sort.FLOAT) {
invokeStatic(definition.getType("Utility").type, TOFLOATWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.FLOAT_OBJ) {
invokeStatic(definition.getType("Utility").type, TOFLOATWOOVERFLOW_DOUBLE);
checkCast(definition.getType("Float").type);
} else if (tsort == Sort.LONG) {
invokeStatic(definition.getType("Utility").type, TOLONGWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.LONG_OBJ) {
invokeStatic(definition.getType("Utility").type, TOLONGWOOVERFLOW_DOUBLE);
checkCast(definition.getType("Long").type);
} else if (tsort == Sort.INT) {
invokeStatic(definition.getType("Utility").type, TOINTWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.INT_OBJ) {
invokeStatic(definition.getType("Utility").type, TOINTWOOVERFLOW_DOUBLE);
checkCast(definition.getType("Integer").type);
} else if (tsort == Sort.CHAR) {
invokeStatic(definition.getType("Utility").type, TOCHARWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.CHAR_OBJ) {
invokeStatic(definition.getType("Utility").type, TOCHARWOOVERFLOW_DOUBLE);
checkCast(definition.getType("Character").type);
} else if (tsort == Sort.SHORT) {
invokeStatic(definition.getType("Utility").type, TOSHORTWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.SHORT_OBJ) {
invokeStatic(definition.getType("Utility").type, TOSHORTWOOVERFLOW_DOUBLE);
checkCast(definition.getType("Short").type);
} else if (tsort == Sort.BYTE) {
invokeStatic(definition.getType("Utility").type, TOBYTEWOOVERFLOW_DOUBLE);
} else if (tsort == Sort.BYTE_OBJ) {
invokeStatic(definition.getType("Utility").type, TOBYTEWOOVERFLOW_DOUBLE);
checkCast(definition.getType("Byte").type);
} else {
return false;
}
} else if (fsort == Sort.FLOAT) {
if (tsort == Sort.LONG) {
invokeStatic(definition.getType("Utility").type, TOLONGWOOVERFLOW_FLOAT);
} else if (tsort == Sort.LONG_OBJ) {
invokeStatic(definition.getType("Utility").type, TOLONGWOOVERFLOW_FLOAT);
checkCast(definition.getType("Long").type);
} else if (tsort == Sort.INT) {
invokeStatic(definition.getType("Utility").type, TOINTWOOVERFLOW_FLOAT);
} else if (tsort == Sort.INT_OBJ) {
invokeStatic(definition.getType("Utility").type, TOINTWOOVERFLOW_FLOAT);
checkCast(definition.getType("Integer").type);
} else if (tsort == Sort.CHAR) {
invokeStatic(definition.getType("Utility").type, TOCHARWOOVERFLOW_FLOAT);
} else if (tsort == Sort.CHAR_OBJ) {
invokeStatic(definition.getType("Utility").type, TOCHARWOOVERFLOW_FLOAT);
checkCast(definition.getType("Character").type);
} else if (tsort == Sort.SHORT) {
invokeStatic(definition.getType("Utility").type, TOSHORTWOOVERFLOW_FLOAT);
} else if (tsort == Sort.SHORT_OBJ) {
invokeStatic(definition.getType("Utility").type, TOSHORTWOOVERFLOW_FLOAT);
checkCast(definition.getType("Short").type);
} else if (tsort == Sort.BYTE) {
invokeStatic(definition.getType("Utility").type, TOBYTEWOOVERFLOW_FLOAT);
} else if (tsort == Sort.BYTE_OBJ) {
invokeStatic(definition.getType("Utility").type, TOBYTEWOOVERFLOW_FLOAT);
checkCast(definition.getType("Byte").type);
} else {
return false;
}
} else if (fsort == Sort.LONG) {
if (tsort == Sort.INT) {
invokeStatic(definition.getType("Math").type, TOINTEXACT_LONG);
} else if (tsort == Sort.INT_OBJ) {
invokeStatic(definition.getType("Math").type, TOINTEXACT_LONG);
checkCast(definition.getType("Integer").type);
} else if (tsort == Sort.CHAR) {
invokeStatic(definition.getType("Utility").type, TOCHAREXACT_LONG);
} else if (tsort == Sort.CHAR_OBJ) {
invokeStatic(definition.getType("Utility").type, TOCHAREXACT_LONG);
checkCast(definition.getType("Character").type);
} else if (tsort == Sort.SHORT) {
invokeStatic(definition.getType("Utility").type, TOSHORTEXACT_LONG);
} else if (tsort == Sort.SHORT_OBJ) {
invokeStatic(definition.getType("Utility").type, TOSHORTEXACT_LONG);
checkCast(definition.getType("Short").type);
} else if (tsort == Sort.BYTE) {
invokeStatic(definition.getType("Utility").type, TOBYTEEXACT_LONG);
} else if (tsort == Sort.BYTE_OBJ) {
invokeStatic(definition.getType("Utility").type, TOBYTEEXACT_LONG);
checkCast(definition.getType("Byte").type);
} else {
return false;
}
} else if (fsort == Sort.INT) {
if (tsort == Sort.CHAR) {
invokeStatic(definition.getType("Utility").type, TOCHAREXACT_INT);
} else if (tsort == Sort.CHAR_OBJ) {
invokeStatic(definition.getType("Utility").type, TOCHAREXACT_INT);
checkCast(definition.getType("Character").type);
} else if (tsort == Sort.SHORT) {
invokeStatic(definition.getType("Utility").type, TOSHORTEXACT_INT);
} else if (tsort == Sort.SHORT_OBJ) {
invokeStatic(definition.getType("Utility").type, TOSHORTEXACT_INT);
checkCast(definition.getType("Short").type);
} else if (tsort == Sort.BYTE) {
invokeStatic(definition.getType("Utility").type, TOBYTEEXACT_INT);
} else if (tsort == Sort.BYTE_OBJ) {
invokeStatic(definition.getType("Utility").type, TOBYTEEXACT_INT);
checkCast(definition.getType("Byte").type);
} else {
return false;
}
} else {
return false;
}
return true;
}
public void writeDup(final int size, final int xsize) {
if (size == 1) {
if (xsize == 2) {

View File

@ -115,13 +115,7 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
// Use custom settings specified by params.
compilerSettings = new CompilerSettings();
Map<String, String> copy = new HashMap<>(params);
String value = copy.remove(CompilerSettings.NUMERIC_OVERFLOW);
if (value != null) {
compilerSettings.setNumericOverflow(Boolean.parseBoolean(value));
}
value = copy.remove(CompilerSettings.MAX_LOOP_COUNTER);
String value = copy.remove(CompilerSettings.MAX_LOOP_COUNTER);
if (value != null) {
compilerSettings.setMaxLoopCounter(Integer.parseInt(value));

View File

@ -481,347 +481,6 @@ public class Utility {
return value.charAt(0);
}
// although divide by zero is guaranteed, the special overflow case is not caught.
// its not needed for remainder because it is not possible there.
// see https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17.2
/**
* Integer divide without overflow
* @throws ArithmeticException on overflow or divide-by-zero
*/
public static int divideWithoutOverflow(int x, int y) {
if (x == Integer.MIN_VALUE && y == -1) {
throw new ArithmeticException("integer overflow");
}
return x / y;
}
/**
* Long divide without overflow
* @throws ArithmeticException on overflow or divide-by-zero
*/
public static long divideWithoutOverflow(long x, long y) {
if (x == Long.MIN_VALUE && y == -1L) {
throw new ArithmeticException("long overflow");
}
return x / y;
}
// byte, short, and char are promoted to int for normal operations,
// so the JDK exact methods are typically used, and the result has a wider range.
// but compound assignments and increment/decrement operators (e.g. byte b = Byte.MAX_VALUE; b++;)
// implicitly cast back to the original type: so these need to be checked against the original range.
/**
* Like {@link Math#toIntExact(long)} but for byte range.
*/
public static byte toByteExact(int value) {
byte s = (byte) value;
if (s != value) {
throw new ArithmeticException("byte overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for byte range.
*/
public static byte toByteExact(long value) {
byte s = (byte) value;
if (s != value) {
throw new ArithmeticException("byte overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for byte range.
*/
public static byte toByteWithoutOverflow(float value) {
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
throw new ArithmeticException("byte overflow");
}
return (byte)value;
}
/**
* Like {@link Math#toIntExact(long)} but for byte range.
*/
public static byte toByteWithoutOverflow(double value) {
if (value < Byte.MIN_VALUE || value > Byte.MAX_VALUE) {
throw new ArithmeticException("byte overflow");
}
return (byte)value;
}
/**
* Like {@link Math#toIntExact(long)} but for short range.
*/
public static short toShortExact(int value) {
short s = (short) value;
if (s != value) {
throw new ArithmeticException("short overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for short range.
*/
public static short toShortExact(long value) {
short s = (short) value;
if (s != value) {
throw new ArithmeticException("short overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for short range.
*/
public static short toShortWithoutOverflow(float value) {
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
throw new ArithmeticException("short overflow");
}
return (short)value;
}
/**
* Like {@link Math#toIntExact(long)} but for short range.
*/
public static short toShortExact(double value) {
if (value < Short.MIN_VALUE || value > Short.MAX_VALUE) {
throw new ArithmeticException("short overflow");
}
return (short)value;
}
/**
* Like {@link Math#toIntExact(long)} but for char range.
*/
public static char toCharExact(int value) {
char s = (char) value;
if (s != value) {
throw new ArithmeticException("char overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for char range.
*/
public static char toCharExact(long value) {
char s = (char) value;
if (s != value) {
throw new ArithmeticException("char overflow");
}
return s;
}
/**
* Like {@link Math#toIntExact(long)} but for char range.
*/
public static char toCharWithoutOverflow(float value) {
if (value < Character.MIN_VALUE || value > Character.MAX_VALUE) {
throw new ArithmeticException("char overflow");
}
return (char)value;
}
/**
* Like {@link Math#toIntExact(long)} but for char range.
*/
public static char toCharWithoutOverflow(double value) {
if (value < Character.MIN_VALUE || value > Character.MAX_VALUE) {
throw new ArithmeticException("char overflow");
}
return (char)value;
}
/**
* Like {@link Math#toIntExact(long)} but for int range.
*/
public static int toIntWithoutOverflow(float value) {
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new ArithmeticException("int overflow");
}
return (int)value;
}
/**
* Like {@link Math#toIntExact(long)} but for int range.
*/
public static int toIntWithoutOverflow(double value) {
if (value < Integer.MIN_VALUE || value > Integer.MAX_VALUE) {
throw new ArithmeticException("int overflow");
}
return (int)value;
}
/**
* Like {@link Math#toIntExact(long)} but for long range.
*/
public static long toLongWithoutOverflow(float value) {
if (value < Long.MIN_VALUE || value > Long.MAX_VALUE) {
throw new ArithmeticException("long overflow");
}
return (long)value;
}
/**
* Like {@link Math#toIntExact(long)} but for long range.
*/
public static float toLongWithoutOverflow(double value) {
if (value < Long.MIN_VALUE || value > Long.MAX_VALUE) {
throw new ArithmeticException("long overflow");
}
return (long)value;
}
/**
* Like {@link Math#toIntExact(long)} but for float range.
*/
public static float toFloatWithoutOverflow(double value) {
if (value < Float.MIN_VALUE || value > Float.MAX_VALUE) {
throw new ArithmeticException("float overflow");
}
return (float)value;
}
/**
* Checks for overflow, result is infinite but operands are finite
* @throws ArithmeticException if overflow occurred
*/
private static float checkInfFloat(float x, float y, float z) {
if (Float.isInfinite(z)) {
if (Float.isFinite(x) && Float.isFinite(y)) {
throw new ArithmeticException("float overflow");
}
}
return z;
}
/**
* Checks for NaN, result is NaN but operands are finite
* @throws ArithmeticException if overflow occurred
*/
private static float checkNaNFloat(float x, float y, float z) {
if (Float.isNaN(z)) {
if (Float.isFinite(x) && Float.isFinite(y)) {
throw new ArithmeticException("NaN");
}
}
return z;
}
/**
* Checks for NaN, result is infinite but operands are finite
* @throws ArithmeticException if overflow occurred
*/
private static double checkInfDouble(double x, double y, double z) {
if (Double.isInfinite(z)) {
if (Double.isFinite(x) && Double.isFinite(y)) {
throw new ArithmeticException("double overflow");
}
}
return z;
}
/**
* Checks for NaN, result is NaN but operands are finite
* @throws ArithmeticException if overflow occurred
*/
private static double checkNaNDouble(double x, double y, double z) {
if (Double.isNaN(z)) {
if (Double.isFinite(x) && Double.isFinite(y)) {
throw new ArithmeticException("NaN");
}
}
return z;
}
/**
* Adds two floats but throws {@code ArithmeticException}
* if the result overflows.
*/
public static float addWithoutOverflow(float x, float y) {
return checkInfFloat(x, y, x + y);
}
/**
* Adds two doubles but throws {@code ArithmeticException}
* if the result overflows.
*/
public static double addWithoutOverflow(double x, double y) {
return checkInfDouble(x, y, x + y);
}
/**
* Subtracts two floats but throws {@code ArithmeticException}
* if the result overflows.
*/
public static float subtractWithoutOverflow(float x, float y) {
return checkInfFloat(x, y, x - y);
}
/**
* Subtracts two doubles but throws {@code ArithmeticException}
* if the result overflows.
*/
public static double subtractWithoutOverflow(double x, double y) {
return checkInfDouble(x, y , x - y);
}
/**
* Multiplies two floats but throws {@code ArithmeticException}
* if the result overflows.
*/
public static float multiplyWithoutOverflow(float x, float y) {
return checkInfFloat(x, y, x * y);
}
/**
* Multiplies two doubles but throws {@code ArithmeticException}
* if the result overflows.
*/
public static double multiplyWithoutOverflow(double x, double y) {
return checkInfDouble(x, y, x * y);
}
/**
* Divides two floats but throws {@code ArithmeticException}
* if the result overflows, or would create NaN from finite
* inputs ({@code x == 0, y == 0})
*/
public static float divideWithoutOverflow(float x, float y) {
return checkNaNFloat(x, y, checkInfFloat(x, y, x / y));
}
/**
* Divides two doubles but throws {@code ArithmeticException}
* if the result overflows, or would create NaN from finite
* inputs ({@code x == 0, y == 0})
*/
public static double divideWithoutOverflow(double x, double y) {
return checkNaNDouble(x, y, checkInfDouble(x, y, x / y));
}
/**
* Takes remainder two floats but throws {@code ArithmeticException}
* if the result would create NaN from finite inputs ({@code y == 0})
*/
public static float remainderWithoutOverflow(float x, float y) {
return checkNaNFloat(x, y, x % y);
}
/**
* Divides two doubles but throws {@code ArithmeticException}
* if the result would create NaN from finite inputs ({@code y == 0})
*/
public static double remainderWithoutOverflow(double x, double y) {
return checkNaNDouble(x, y, x % y);
}
public static boolean checkEquals(final Object left, final Object right) {
if (left != null) {
return left.equals(right);

View File

@ -27,7 +27,6 @@ import org.objectweb.asm.Type;
import org.objectweb.asm.commons.Method;
import java.lang.invoke.CallSite;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Map;
@ -116,59 +115,8 @@ public final class WriterConstants {
public final static Method STRINGBUILDER_APPEND_OBJECT = getAsmMethod(StringBuilder.class, "append", Object.class);
public final static Method STRINGBUILDER_TOSTRING = getAsmMethod(String.class, "toString");
public final static Method TOINTEXACT_LONG = getAsmMethod(int.class, "toIntExact", long.class);
public final static Method NEGATEEXACT_INT = getAsmMethod(int.class, "negateExact", int.class);
public final static Method NEGATEEXACT_LONG = getAsmMethod(long.class, "negateExact", long.class);
public final static Method MULEXACT_INT = getAsmMethod(int.class, "multiplyExact", int.class, int.class);
public final static Method MULEXACT_LONG = getAsmMethod(long.class, "multiplyExact", long.class, long.class);
public final static Method ADDEXACT_INT = getAsmMethod(int.class, "addExact", int.class, int.class);
public final static Method ADDEXACT_LONG = getAsmMethod(long.class, "addExact", long.class, long.class);
public final static Method SUBEXACT_INT = getAsmMethod(int.class, "subtractExact", int.class, int.class);
public final static Method SUBEXACT_LONG = getAsmMethod(long.class, "subtractExact", long.class, long.class);
public final static Method CHECKEQUALS =
getAsmMethod(boolean.class, "checkEquals", Object.class, Object.class);
public final static Method TOBYTEEXACT_INT = getAsmMethod(byte.class, "toByteExact", int.class);
public final static Method TOBYTEEXACT_LONG = getAsmMethod(byte.class, "toByteExact", long.class);
public final static Method TOBYTEWOOVERFLOW_FLOAT = getAsmMethod(byte.class, "toByteWithoutOverflow", float.class);
public final static Method TOBYTEWOOVERFLOW_DOUBLE = getAsmMethod(byte.class, "toByteWithoutOverflow", double.class);
public final static Method TOSHORTEXACT_INT = getAsmMethod(short.class, "toShortExact", int.class);
public final static Method TOSHORTEXACT_LONG = getAsmMethod(short.class, "toShortExact", long.class);
public final static Method TOSHORTWOOVERFLOW_FLOAT = getAsmMethod(short.class, "toShortWithoutOverflow", float.class);
public final static Method TOSHORTWOOVERFLOW_DOUBLE = getAsmMethod(short.class, "toShortWihtoutOverflow", double.class);
public final static Method TOCHAREXACT_INT = getAsmMethod(char.class, "toCharExact", int.class);
public final static Method TOCHAREXACT_LONG = getAsmMethod(char.class, "toCharExact", long.class);
public final static Method TOCHARWOOVERFLOW_FLOAT = getAsmMethod(char.class, "toCharWithoutOverflow", float.class);
public final static Method TOCHARWOOVERFLOW_DOUBLE = getAsmMethod(char.class, "toCharWithoutOverflow", double.class);
public final static Method TOINTWOOVERFLOW_FLOAT = getAsmMethod(int.class, "toIntWithoutOverflow", float.class);
public final static Method TOINTWOOVERFLOW_DOUBLE = getAsmMethod(int.class, "toIntWithoutOverflow", double.class);
public final static Method TOLONGWOOVERFLOW_FLOAT = getAsmMethod(long.class, "toLongWithoutOverflow", float.class);
public final static Method TOLONGWOOVERFLOW_DOUBLE = getAsmMethod(long.class, "toLongWithoutOverflow", double.class);
public final static Method TOFLOATWOOVERFLOW_DOUBLE = getAsmMethod(float.class , "toFloatWihtoutOverflow", double.class);
public final static Method MULWOOVERLOW_FLOAT =
getAsmMethod(float.class, "multiplyWithoutOverflow", float.class, float.class);
public final static Method MULWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "multiplyWithoutOverflow", double.class, double.class);
public final static Method DIVWOOVERLOW_INT =
getAsmMethod(int.class, "divideWithoutOverflow", int.class, int.class);
public final static Method DIVWOOVERLOW_LONG =
getAsmMethod(long.class, "divideWithoutOverflow", long.class, long.class);
public final static Method DIVWOOVERLOW_FLOAT =
getAsmMethod(float.class, "divideWithoutOverflow", float.class, float.class);
public final static Method DIVWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "divideWithoutOverflow", double.class, double.class);
public final static Method REMWOOVERLOW_FLOAT =
getAsmMethod(float.class, "remainderWithoutOverflow", float.class, float.class);
public final static Method REMWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "remainderWithoutOverflow", double.class, double.class);
public final static Method ADDWOOVERLOW_FLOAT =
getAsmMethod(float.class, "addWithoutOverflow", float.class, float.class);
public final static Method ADDWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "addWithoutOverflow", double.class, double.class);
public final static Method SUBWOOVERLOW_FLOAT =
getAsmMethod(float.class, "subtractWithoutOverflow", float.class, float.class);
public final static Method SUBWOOVERLOW_DOUBLE =
getAsmMethod(double.class, "subtractWithoutOverflow", double.class, double.class);
private static Method getAsmMethod(final Class<?> rtype, final String name, final Class<?>... ptypes) {
return new Method(name, MethodType.methodType(rtype, ptypes).toMethodDescriptorString());

View File

@ -94,21 +94,16 @@ public final class EBinary extends AExpression {
right = right.cast(settings, definition, variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = overflow ? (int)left.constant * (int)right.constant :
Math.multiplyExact((int)left.constant, (int)right.constant);
constant = (int)left.constant * (int)right.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? (long)left.constant * (long)right.constant :
Math.multiplyExact((long)left.constant, (long)right.constant);
constant = (long)left.constant * (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant * (float)right.constant :
org.elasticsearch.painless.Utility.multiplyWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant * (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant * (double)right.constant :
org.elasticsearch.painless.Utility.multiplyWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant * (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -135,21 +130,16 @@ public final class EBinary extends AExpression {
right = right.cast(settings, definition, variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = overflow ? (int)left.constant / (int)right.constant :
org.elasticsearch.painless.Utility.divideWithoutOverflow((int)left.constant, (int)right.constant);
constant = (int)left.constant / (int)right.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? (long)left.constant / (long)right.constant :
org.elasticsearch.painless.Utility.divideWithoutOverflow((long)left.constant, (long)right.constant);
constant = (long)left.constant / (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant / (float)right.constant :
org.elasticsearch.painless.Utility.divideWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant / (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant / (double)right.constant :
org.elasticsearch.painless.Utility.divideWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant / (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -176,7 +166,6 @@ public final class EBinary extends AExpression {
right = right.cast(settings, definition, variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
@ -184,11 +173,9 @@ public final class EBinary extends AExpression {
} else if (sort == Sort.LONG) {
constant = (long)left.constant % (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant % (float)right.constant :
org.elasticsearch.painless.Utility.remainderWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant % (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant % (double)right.constant :
org.elasticsearch.painless.Utility.remainderWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant % (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -231,20 +218,14 @@ public final class EBinary extends AExpression {
right = right.cast(settings, definition, variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
if (sort == Sort.INT) {
constant = overflow ? (int)left.constant + (int)right.constant :
Math.addExact((int)left.constant, (int)right.constant);
constant = (int)left.constant + (int)right.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? (long)left.constant + (long)right.constant :
Math.addExact((long)left.constant, (long)right.constant);
constant = (long)left.constant + (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant + (float)right.constant :
org.elasticsearch.painless.Utility.addWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant + (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant + (double)right.constant :
org.elasticsearch.painless.Utility.addWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant + (double)right.constant;
} else if (sort == Sort.STRING) {
constant = "" + left.constant + right.constant;
} else {
@ -273,21 +254,16 @@ public final class EBinary extends AExpression {
right = right.cast(settings, definition, variables);
if (left.constant != null && right.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = overflow ? (int)left.constant - (int)right.constant :
Math.subtractExact((int)left.constant, (int)right.constant);
constant = (int)left.constant - (int)right.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? (long)left.constant - (long)right.constant :
Math.subtractExact((long)left.constant, (long)right.constant);
constant = (long)left.constant - (long)right.constant;
} else if (sort == Sort.FLOAT) {
constant = overflow ? (float)left.constant - (float)right.constant :
org.elasticsearch.painless.Utility.subtractWithoutOverflow((float)left.constant, (float)right.constant);
constant = (float)left.constant - (float)right.constant;
} else if (sort == Sort.DOUBLE) {
constant = overflow ? (double)left.constant - (double)right.constant :
org.elasticsearch.painless.Utility.subtractWithoutOverflow((double)left.constant, (double)right.constant);
constant = (double)left.constant - (double)right.constant;
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
@ -519,7 +495,7 @@ public final class EBinary extends AExpression {
left.write(settings, definition, adapter);
right.write(settings, definition, adapter);
adapter.writeBinaryInstruction(settings, definition, location, actual, operation);
adapter.writeBinaryInstruction(definition, location, actual, operation);
}
adapter.writeBranch(tru, fals);

View File

@ -44,7 +44,6 @@ public final class EChain extends AExpression {
boolean cat = false;
Type promote = null;
boolean exact = false;
Cast there = null;
Cast back = null;
@ -208,9 +207,6 @@ public final class EChain extends AExpression {
expression = expression.cast(settings, definition, variables);
exact = !settings.getNumericOverflow() &&
(operation == Operation.MUL || operation == Operation.DIV || operation == Operation.REM ||
operation == Operation.ADD || operation == Operation.SUB);
there = AnalyzerCaster.getLegalCast(definition, location, last.after, promote, false);
back = AnalyzerCaster.getLegalCast(definition, location, promote, last.after, true);
@ -293,11 +289,9 @@ public final class EChain extends AExpression {
adapter.writeCast(there);
expression.write(settings, definition, adapter);
adapter.writeBinaryInstruction(settings, definition, location, promote, operation);
adapter.writeBinaryInstruction(definition, location, promote, operation);
if (!exact || !adapter.writeExactInstruction(definition, promote.sort, link.after.sort)) {
adapter.writeCast(back);
}
adapter.writeCast(back);
if (link.load && !post) {
adapter.writeDup(link.after.sort.size, link.size);

View File

@ -31,8 +31,6 @@ import org.elasticsearch.painless.MethodWriter;
import static org.elasticsearch.painless.WriterConstants.DEF_NEG_CALL;
import static org.elasticsearch.painless.WriterConstants.DEF_NOT_CALL;
import static org.elasticsearch.painless.WriterConstants.NEGATEEXACT_INT;
import static org.elasticsearch.painless.WriterConstants.NEGATEEXACT_LONG;
/**
* Represents a unary math expression.
@ -147,14 +145,13 @@ public final class EUnary extends AExpression {
child = child.cast(settings, definition, variables);
if (child.constant != null) {
final boolean overflow = settings.getNumericOverflow();
final Sort sort = promote.sort;
if (sort == Sort.INT) {
constant = overflow ? -(int)child.constant : Math.negateExact((int)child.constant);
constant = -(int)child.constant;
} else if (sort == Sort.LONG) {
constant = overflow ? -(long)child.constant : Math.negateExact((long)child.constant);
constant = -(long)child.constant;
} else if (sort == Sort.FLOAT) {
constant = -(float)child.constant;
} else if (sort == Sort.DOUBLE) {
@ -211,17 +208,7 @@ public final class EUnary extends AExpression {
if (sort == Sort.DEF) {
adapter.invokeStatic(definition.getType("Def").type, DEF_NEG_CALL);
} else {
if (settings.getNumericOverflow()) {
adapter.math(MethodWriter.NEG, type);
} else {
if (sort == Sort.INT) {
adapter.invokeStatic(definition.getType("Math").type, NEGATEEXACT_INT);
} else if (sort == Sort.LONG) {
adapter.invokeStatic(definition.getType("Math").type, NEGATEEXACT_LONG);
} else {
throw new IllegalStateException(error("Illegal tree structure."));
}
}
adapter.math(MethodWriter.NEG, type);
}
} else if (operation != Operation.ADD) {
throw new IllegalStateException(error("Illegal tree structure."));

View File

@ -1,293 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless;
import java.util.Collections;
import java.util.Map;
/** Tests floating point overflow with numeric overflow disabled */
public class FloatOverflowDisabledTests extends ScriptTestCase {
/** wire overflow to false for all tests */
@Override
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "false"));
}
public void testAssignmentAdditionOverflow() {
// float
try {
exec("float x = 3.4028234663852886E38f; x += 3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = -3.4028234663852886E38f; x += -3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double
try {
exec("double x = 1.7976931348623157E308; x += 1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = -1.7976931348623157E308; x += -1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentSubtractionOverflow() {
// float
try {
exec("float x = 3.4028234663852886E38f; x -= -3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = -3.4028234663852886E38f; x -= 3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double
try {
exec("double x = 1.7976931348623157E308; x -= -1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = -1.7976931348623157E308; x -= 1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentMultiplicationOverflow() {
// float
try {
exec("float x = 3.4028234663852886E38f; x *= 3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 3.4028234663852886E38f; x *= -3.4028234663852886E38f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double
try {
exec("double x = 1.7976931348623157E308; x *= 1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; x *= -1.7976931348623157E308; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentDivisionOverflow() {
// float
try {
exec("float x = 3.4028234663852886E38f; x /= 1.401298464324817E-45f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 3.4028234663852886E38f; x /= -1.401298464324817E-45f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 1.0f; x /= 0.0f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double
try {
exec("double x = 1.7976931348623157E308; x /= 4.9E-324; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; x /= -4.9E-324; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.0f; x /= 0.0; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAddition() throws Exception {
try {
exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x + y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; double y = 1.7976931348623157E308; return x + y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testAdditionConst() throws Exception {
try {
exec("return 3.4028234663852886E38f + 3.4028234663852886E38f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.7976931348623157E308 + 1.7976931348623157E308;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testSubtraction() throws Exception {
try {
exec("float x = -3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x - y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = -1.7976931348623157E308; double y = 1.7976931348623157E308; return x - y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testSubtractionConst() throws Exception {
try {
exec("return -3.4028234663852886E38f - 3.4028234663852886E38f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return -1.7976931348623157E308 - 1.7976931348623157E308;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplication() throws Exception {
try {
exec("float x = 3.4028234663852886E38f; float y = 3.4028234663852886E38f; return x * y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; double y = 1.7976931348623157E308; return x * y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplicationConst() throws Exception {
try {
exec("return 3.4028234663852886E38f * 3.4028234663852886E38f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.7976931348623157E308 * 1.7976931348623157E308;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivision() throws Exception {
try {
exec("float x = 3.4028234663852886E38f; float y = 1.401298464324817E-45f; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 1.0f; float y = 0.0f; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.7976931348623157E308; double y = 4.9E-324; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.0; double y = 0.0; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivisionConst() throws Exception {
try {
exec("return 3.4028234663852886E38f / 1.401298464324817E-45f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.0f / 0.0f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.7976931348623157E308 / 4.9E-324;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.0 / 0.0;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivisionNaN() throws Exception {
// float division, constant division, and assignment
try {
exec("float x = 0f; float y = 0f; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 0f / 0f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 0f; x /= 0f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double division, constant division, and assignment
try {
exec("double x = 0.0; double y = 0.0; return x / y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 0.0 / 0.0;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 0.0; x /= 0.0; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
public void testRemainderNaN() throws Exception {
// float division, constant division, and assignment
try {
exec("float x = 1f; float y = 0f; return x % y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1f % 0f;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("float x = 1f; x %= 0f; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
// double division, constant division, and assignment
try {
exec("double x = 1.0; double y = 0.0; return x % y;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("return 1.0 % 0.0;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
try {
exec("double x = 1.0; x %= 0.0; return x;");
fail("didn't hit expected exception");
} catch (ArithmeticException expected) {}
}
}

View File

@ -19,17 +19,8 @@
package org.elasticsearch.painless;
import java.util.Collections;
import java.util.Map;
/** Tests floating point overflow with numeric overflow enabled */
public class FloatOverflowEnabledTests extends ScriptTestCase {
/** wire overflow to true for all tests */
@Override
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "true"));
}
/** Tests floating point overflow cases */
public class FloatOverflowTests extends ScriptTestCase {
public void testAssignmentAdditionOverflow() {
// float

View File

@ -1,444 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless;
import java.util.Collections;
import java.util.Map;
/** Tests integer overflow with numeric overflow disabled */
public class IntegerOverflowDisabledTests extends ScriptTestCase {
/** wire overflow to true for all tests */
@Override
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "false"));
}
public void testAssignmentAdditionOverflow() {
// byte
try {
exec("byte x = 0; x += 128; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 0; x += -129; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// short
try {
exec("short x = 0; x += 32768; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 0; x += -32769; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// char
try {
exec("char x = 0; x += 65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("char x = 0; x += -65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// int
try {
exec("int x = 1; x += 2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = -2; x += -2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = 1; x += 9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -2; x += -9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentSubtractionOverflow() {
// byte
try {
exec("byte x = 0; x -= -128; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 0; x -= 129; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// short
try {
exec("short x = 0; x -= -32768; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 0; x -= 32769; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// char
try {
exec("char x = 0; x -= -65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("char x = 0; x -= 65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// int
try {
exec("int x = 1; x -= -2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = -2; x -= 2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = 1; x -= -9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -2; x -= 9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentMultiplicationOverflow() {
// byte
try {
exec("byte x = 2; x *= 128; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 2; x *= -128; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// char
try {
exec("char x = 2; x *= 65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("char x = 2; x *= -65536; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// int
try {
exec("int x = 2; x *= 2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = 2; x *= -2147483647; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = 2; x *= 9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = 2; x *= -9223372036854775807L; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAssignmentDivisionOverflow() {
// byte
try {
exec("byte x = (byte) -128; x /= -1; return x;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
// short
try {
exec("short x = (short) -32768; x /= -1; return x;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
// cannot happen for char: unsigned
// int
try {
exec("int x = -2147483647 - 1; x /= -1; return x;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = -9223372036854775807L - 1L; x /=-1L; return x;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testIncrementOverFlow() throws Exception {
// byte
try {
exec("byte x = 127; ++x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = 127; x++; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = (byte) -128; --x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("byte x = (byte) -128; x--; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// short
try {
exec("short x = 32767; ++x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("short x = 32767; x++; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("short x = (short) -32768; --x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("short x = (short) -32768; x--; return x;");
} catch (ArithmeticException expected) {}
// char
try {
exec("char x = 65535; ++x; return x;");
} catch (ArithmeticException expected) {}
try {
exec("char x = 65535; x++; return x;");
} catch (ArithmeticException expected) {}
try {
exec("char x = (char) 0; --x; return x;");
} catch (ArithmeticException expected) {}
try {
exec("char x = (char) 0; x--; return x;");
} catch (ArithmeticException expected) {}
// int
try {
exec("int x = 2147483647; ++x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = 2147483647; x++; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = (int) -2147483648L; --x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("int x = (int) -2147483648L; x--; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
// long
try {
exec("long x = 9223372036854775807L; ++x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = 9223372036854775807L; x++; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -9223372036854775807L - 1L; --x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -9223372036854775807L - 1L; x--; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAddition() throws Exception {
try {
exec("int x = 2147483647; int y = 2147483647; return x + y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = 9223372036854775807L; long y = 9223372036854775807L; return x + y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testAdditionConst() throws Exception {
try {
exec("return 2147483647 + 2147483647;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("return 9223372036854775807L + 9223372036854775807L;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testSubtraction() throws Exception {
try {
exec("int x = -10; int y = 2147483647; return x - y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -10L; long y = 9223372036854775807L; return x - y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testSubtractionConst() throws Exception {
try {
exec("return -10 - 2147483647;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("return -10L - 9223372036854775807L;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplication() throws Exception {
try {
exec("int x = 2147483647; int y = 2147483647; return x * y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = 9223372036854775807L; long y = 9223372036854775807L; return x * y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplicationConst() throws Exception {
try {
exec("return 2147483647 * 2147483647;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("return 9223372036854775807L * 9223372036854775807L;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testDivision() throws Exception {
try {
exec("int x = -2147483647 - 1; int y = -1; return x / y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -9223372036854775808L; long y = -1L; return x / y;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testDivisionConst() throws Exception {
try {
exec("return (-2147483648) / -1;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
try {
exec("return (-9223372036854775808L) / -1L;");
fail("should have hit exception");
} catch (ArithmeticException expected) {}
}
public void testNegationOverflow() throws Exception {
try {
exec("int x = -2147483648; x = -x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -9223372036854775808L; x = -x; return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testNegationOverflowConst() throws Exception {
try {
exec("int x = -(-2147483648); return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
exec("long x = -(-9223372036854775808L); return x;");
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
}

View File

@ -19,17 +19,8 @@
package org.elasticsearch.painless;
import java.util.Collections;
import java.util.Map;
/** Tests integer overflow with numeric overflow enabled */
public class IntegerOverflowEnabledTests extends ScriptTestCase {
/** wire overflow to true for all tests */
@Override
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, "true"));
}
/** Tests integer overflow cases */
public class IntegerOverflowTests extends ScriptTestCase {
public void testAssignmentAdditionOverflow() {
// byte

View File

@ -48,7 +48,7 @@ public abstract class ScriptTestCase extends ESTestCase {
/** Compiles and returns the result of {@code script} with access to {@code vars} */
public Object exec(String script, Map<String, Object> vars) {
return exec(script, vars, Collections.singletonMap(CompilerSettings.NUMERIC_OVERFLOW, Boolean.toString(random().nextBoolean())));
return exec(script, vars, Collections.emptyMap());
}
/** Compiles and returns the result of {@code script} with access to {@code vars} and compile-time parameters */

View File

@ -1,250 +0,0 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.painless;
import org.elasticsearch.test.ESTestCase;
/**
* Tests utility methods (typically built-ins)
*/
public class UtilityTests extends ESTestCase {
public void testDivideWithoutOverflowInt() {
assertEquals(5 / 2, Utility.divideWithoutOverflow(5, 2));
try {
Utility.divideWithoutOverflow(Integer.MIN_VALUE, -1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(5, 0);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivideWithoutOverflowLong() {
assertEquals(5L / 2L, Utility.divideWithoutOverflow(5L, 2L));
try {
Utility.divideWithoutOverflow(Long.MIN_VALUE, -1L);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(5L, 0L);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testToByteExact() {
for (int b = Byte.MIN_VALUE; b < Byte.MAX_VALUE; b++) {
assertEquals((byte)b, Utility.toByteExact(b));
}
try {
Utility.toByteExact(Byte.MIN_VALUE - 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.toByteExact(Byte.MAX_VALUE + 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testToShortExact() {
for (int s = Short.MIN_VALUE; s < Short.MAX_VALUE; s++) {
assertEquals((short)s, Utility.toShortExact(s));
}
try {
Utility.toShortExact(Short.MIN_VALUE - 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.toShortExact(Short.MAX_VALUE + 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testToCharExact() {
for (int c = Character.MIN_VALUE; c < Character.MAX_VALUE; c++) {
assertEquals((char)c, Utility.toCharExact(c));
}
try {
Utility.toCharExact(Character.MIN_VALUE - 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.toCharExact(Character.MAX_VALUE + 1);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAddWithoutOverflowFloat() {
assertEquals(10F, Utility.addWithoutOverflow(5F, 5F), 0F);
assertTrue(Float.isNaN(Utility.addWithoutOverflow(5F, Float.NaN)));
assertTrue(Float.isNaN(Utility.addWithoutOverflow(Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY)));
try {
Utility.addWithoutOverflow(Float.MAX_VALUE, Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.addWithoutOverflow(-Float.MAX_VALUE, -Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testAddWithoutOverflowDouble() {
assertEquals(10D, Utility.addWithoutOverflow(5D, 5D), 0D);
assertTrue(Double.isNaN(Utility.addWithoutOverflow(5D, Double.NaN)));
assertTrue(Double.isNaN(Utility.addWithoutOverflow(Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY)));
try {
Utility.addWithoutOverflow(Double.MAX_VALUE, Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.addWithoutOverflow(-Double.MAX_VALUE, -Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testSubtractWithoutOverflowFloat() {
assertEquals(5F, Utility.subtractWithoutOverflow(10F, 5F), 0F);
assertTrue(Float.isNaN(Utility.subtractWithoutOverflow(5F, Float.NaN)));
assertTrue(Float.isNaN(Utility.subtractWithoutOverflow(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)));
try {
Utility.subtractWithoutOverflow(Float.MAX_VALUE, -Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.subtractWithoutOverflow(-Float.MAX_VALUE, Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testSubtractWithoutOverflowDouble() {
assertEquals(5D, Utility.subtractWithoutOverflow(10D, 5D), 0D);
assertTrue(Double.isNaN(Utility.subtractWithoutOverflow(5D, Double.NaN)));
assertTrue(Double.isNaN(Utility.subtractWithoutOverflow(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY)));
try {
Utility.subtractWithoutOverflow(Double.MAX_VALUE, -Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.subtractWithoutOverflow(-Double.MAX_VALUE, Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplyWithoutOverflowFloat() {
assertEquals(25F, Utility.multiplyWithoutOverflow(5F, 5F), 0F);
assertTrue(Float.isNaN(Utility.multiplyWithoutOverflow(5F, Float.NaN)));
assertEquals(Float.POSITIVE_INFINITY, Utility.multiplyWithoutOverflow(5F, Float.POSITIVE_INFINITY), 0F);
try {
Utility.multiplyWithoutOverflow(Float.MAX_VALUE, Float.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testMultiplyWithoutOverflowDouble() {
assertEquals(25D, Utility.multiplyWithoutOverflow(5D, 5D), 0D);
assertTrue(Double.isNaN(Utility.multiplyWithoutOverflow(5D, Double.NaN)));
assertEquals(Double.POSITIVE_INFINITY, Utility.multiplyWithoutOverflow(5D, Double.POSITIVE_INFINITY), 0D);
try {
Utility.multiplyWithoutOverflow(Double.MAX_VALUE, Double.MAX_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivideWithoutOverflowFloat() {
assertEquals(5F, Utility.divideWithoutOverflow(25F, 5F), 0F);
assertTrue(Float.isNaN(Utility.divideWithoutOverflow(5F, Float.NaN)));
assertEquals(Float.POSITIVE_INFINITY, Utility.divideWithoutOverflow(Float.POSITIVE_INFINITY, 5F), 0F);
try {
Utility.divideWithoutOverflow(Float.MAX_VALUE, Float.MIN_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(0F, 0F);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(5F, 0F);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testDivideWithoutOverflowDouble() {
assertEquals(5D, Utility.divideWithoutOverflow(25D, 5D), 0D);
assertTrue(Double.isNaN(Utility.divideWithoutOverflow(5D, Double.NaN)));
assertEquals(Double.POSITIVE_INFINITY, Utility.divideWithoutOverflow(Double.POSITIVE_INFINITY, 5D), 0D);
try {
Utility.divideWithoutOverflow(Double.MAX_VALUE, Double.MIN_VALUE);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(0D, 0D);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
try {
Utility.divideWithoutOverflow(5D, 0D);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testRemainderWithoutOverflowFloat() {
assertEquals(1F, Utility.remainderWithoutOverflow(25F, 4F), 0F);
try {
Utility.remainderWithoutOverflow(5F, 0F);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
public void testRemainderWithoutOverflowDouble() {
assertEquals(1D, Utility.remainderWithoutOverflow(25D, 4D), 0D);
try {
Utility.remainderWithoutOverflow(5D, 0D);
fail("did not get expected exception");
} catch (ArithmeticException expected) {}
}
}