nuke overflow detection as we cannot guarantee for def. simplify life :)
This commit is contained in:
parent
915ab16176
commit
b9c7dbcfbd
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
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.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 {
|
||||
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) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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."));
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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) {}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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) {}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue