package janala.interpreters;
import janala.solvers.History;
import java.util.Map;
/**
* IntValue contains a pair of concrete value and a path constraint.
* Note that the path constraint flip the boolean signs according to the
* evaluated concrete value.
*/
public class IntValue extends Value {
public SymbolicInt symbolic;
public Constraint nonIntConstraint;
public int concrete;
final public static IntValue TRUE = new IntValue(1);
final public static IntValue FALSE = new IntValue(0);
@Override
public Object getConcrete() {
return concrete;
}
public IntValue(int i) {
concrete = i;
symbolic = null;
nonIntConstraint = null;
}
public IntValue(int concrete, Constraint nonIntConstraint) {
this.concrete = concrete;
if (nonIntConstraint instanceof SymbolicInt) {
this.symbolic = (SymbolicInt) nonIntConstraint;
} else {
this.nonIntConstraint = nonIntConstraint;
}
}
public boolean equals(Object other) {
if (other == null ) {
return false;
}
if (other == this) {
return true;
}
if (other instanceof IntValue) {
IntValue otherVal = (IntValue) other;
return (this.concrete == otherVal.concrete &&
(this.symbolic == otherVal.symbolic ||
this.symbolic.equals(otherVal.symbolic)) &&
(this.nonIntConstraint == otherVal.nonIntConstraint ||
this.nonIntConstraint.equals(otherVal.nonIntConstraint)));
} else {
return false;
}
}
public int getSymbol() {
if (symbolic == null) {
throw new RuntimeException("No symbols created.");
}
Integer[] result = symbolic.getLinear().keySet().toArray(new Integer[0]);
return result[0];
}
@Override
public int MAKE_SYMBOLIC(History history) {
symbol = symbol + inc;
symbolic = new SymbolicInt(symbol - inc);
return symbol - inc;
}
public long substituteInLinear(Map<String, Long> assignments) {
long val = 0;
if (symbolic == null) {
return concrete;
}
for (Map.Entry<Integer, Long> it : symbolic.getLinear().entrySet()) {
int key = it.getKey();
long l = it.getValue();
if (assignments.containsKey("x" + key)) {
val += assignments.get("x" + key) * l;
} else {
return this.concrete;
}
}
val += symbolic.getConstant();
return val;
}
public IntValue IINC(int increment) {
IntValue ret = new IntValue(concrete + increment);
if (symbolic != null) {
ret.symbolic = symbolic.add(increment);
}
return ret;
}
public IntValue IFEQ() {
boolean result = concrete == 0;
if (symbolic == null && nonIntConstraint == null) {
return result ? IntValue.TRUE : IntValue.FALSE;
} else if (symbolic != null) {
if (symbolic.getOp() == COMPARISON_OPS.UN)
return new IntValue(
result ? 1 : 0,
result
? symbolic.setop(COMPARISON_OPS.EQ)
: symbolic.setop(COMPARISON_OPS.NE));
else return new IntValue(result ? 1 : 0, result ? (SymbolicInt) symbolic.not() : symbolic);
} else {
return new IntValue(result ? 1 : 0, result ? nonIntConstraint.not() : nonIntConstraint);
}
}
public IntValue IFNE() {
boolean result = (concrete != 0);
if (symbolic == null && nonIntConstraint == null) {
return result ? IntValue.TRUE : IntValue.FALSE;
} else if (symbolic != null) {
if (symbolic.getOp() == COMPARISON_OPS.UN)
return new IntValue(
result ? 1 : 0,
result
? symbolic.setop(COMPARISON_OPS.NE)
: symbolic.setop(COMPARISON_OPS.EQ));
else return new IntValue(result ? 1 : 0, result ? symbolic : (SymbolicInt) symbolic.not());
} else {
return new IntValue(result ? 1 : 0, result ? nonIntConstraint : nonIntConstraint.not());
}
}
public IntValue IFLT() {
if (symbolic == null) {
return (concrete < 0) ? IntValue.TRUE : IntValue.FALSE;
} else {
boolean result = concrete < 0;
return new IntValue(
result ? 1 : 0,
result
? symbolic.setop(COMPARISON_OPS.LT)
: symbolic.setop(COMPARISON_OPS.GE));
}
}
public IntValue IFGE() {
if (symbolic == null) {
return (concrete >= 0) ? IntValue.TRUE : IntValue.FALSE;
} else {
boolean result = concrete >= 0;
return new IntValue(
result ? 1 : 0,
result
? symbolic.setop(COMPARISON_OPS.GE)
: symbolic.setop(COMPARISON_OPS.LT));
}
}
public IntValue IFGT() {
if (symbolic == null) {
return (concrete > 0) ? IntValue.TRUE : IntValue.FALSE;
} else {
boolean result = concrete > 0;
return new IntValue(
result ? 1 : 0,
result
? symbolic.setop(COMPARISON_OPS.GT)
: symbolic.setop(COMPARISON_OPS.LE));
}
}
public IntValue IFLE() {
if (symbolic == null) {
return (concrete <= 0) ? IntValue.TRUE : IntValue.FALSE;
} else {
boolean result = concrete <= 0;
return new IntValue(
result ? 1 : 0,
result
? symbolic.setop(COMPARISON_OPS.LE)
: symbolic.setop(COMPARISON_OPS.GT));
}
}
public IntValue IF_ICMPEQ(IntValue i2) {
boolean result = (concrete == i2.concrete);
COMPARISON_OPS op =
result ? COMPARISON_OPS.EQ : COMPARISON_OPS.NE;
if (symbolic == null && i2.symbolic == null) {
return result ? IntValue.TRUE : IntValue.FALSE;
} else if (symbolic != null && i2.symbolic != null) {
SymbolicInt tmp = symbolic.subtract(i2.symbolic);
if (tmp != null) {
tmp = tmp.setop(op);
}
return new IntValue(result ? 1 : 0, tmp);
} else if (symbolic != null) {
return new IntValue(result ? 1 : 0, symbolic.subtract(i2.concrete).setop(op));
} else {
return new IntValue(result ? 1 : 0, i2.symbolic.subtractFrom(concrete).setop(op));
}
}
public IntValue IF_ICMPNE(IntValue i2) {
boolean result = (concrete != i2.concrete);
COMPARISON_OPS op =
result ? COMPARISON_OPS.NE : COMPARISON_OPS.EQ;
if (symbolic == null && i2.symbolic == null) {
return result ? IntValue.TRUE : IntValue.FALSE;
} else if (symbolic != null && i2.symbolic != null) {
SymbolicInt tmp = symbolic.subtract(i2.symbolic);
if (tmp != null) {
tmp = tmp.setop(op);
}
return new IntValue(result ? 1 : 0, tmp);
} else if (symbolic != null) {
return new IntValue(result ? 1 : 0, symbolic.subtract(i2.concrete).setop(op));
} else {
return new IntValue(result ? 1 : 0, i2.symbolic.subtractFrom(concrete).setop(op));
}
}
public IntValue IF_ICMPLT(IntValue i2) {
boolean result = (concrete < i2.concrete);
COMPARISON_OPS op =
result ? COMPARISON_OPS.LT : COMPARISON_OPS.GE;
if (symbolic == null && i2.symbolic == null) {
return result ? IntValue.TRUE : IntValue.FALSE;
} else if (symbolic != null && i2.symbolic != null) {
SymbolicInt tmp = symbolic.subtract(i2.symbolic);
if (tmp != null) {
tmp = tmp.setop(op);
}
return new IntValue(result ? 1 : 0, tmp);
} else if (symbolic != null) {
return new IntValue(result ? 1 : 0, symbolic.subtract(i2.concrete).setop(op));
} else {
return new IntValue(result ? 1 : 0, i2.symbolic.subtractFrom(concrete).setop(op));
}
}
public IntValue IF_ICMPGE(IntValue i2) {
boolean result = (concrete >= i2.concrete);
COMPARISON_OPS op =
result ? COMPARISON_OPS.GE : COMPARISON_OPS.LT;
if (symbolic == null && i2.symbolic == null) {
return result ? IntValue.TRUE : IntValue.FALSE;
} else if (symbolic != null && i2.symbolic != null) {
SymbolicInt tmp = symbolic.subtract(i2.symbolic);
if (tmp != null) {
tmp = tmp.setop(op);
}
return new IntValue(result ? 1 : 0, tmp);
} else if (symbolic != null) {
return new IntValue(result ? 1 : 0, symbolic.subtract(i2.concrete).setop(op));
} else {
return new IntValue(result ? 1 : 0, i2.symbolic.subtractFrom(concrete).setop(op));
}
}
public IntValue IF_ICMPGT(IntValue i2) {
boolean result = (concrete > i2.concrete);
COMPARISON_OPS op =
result ? COMPARISON_OPS.GT : COMPARISON_OPS.LE;
if (symbolic == null && i2.symbolic == null) {
return result ? IntValue.TRUE : IntValue.FALSE;
} else if (symbolic != null && i2.symbolic != null) {
SymbolicInt tmp = symbolic.subtract(i2.symbolic);
if (tmp != null) {
tmp = tmp.setop(op);
}
return new IntValue(result ? 1 : 0, tmp);
} else if (symbolic != null) {
return new IntValue(result ? 1 : 0, symbolic.subtract(i2.concrete).setop(op));
} else {
return new IntValue(result ? 1 : 0, i2.symbolic.subtractFrom(concrete).setop(op));
}
}
public IntValue IF_ICMPLE(IntValue i2) {
boolean result = (concrete <= i2.concrete);
COMPARISON_OPS op =
result ? COMPARISON_OPS.LE : COMPARISON_OPS.GT;
if (symbolic == null && i2.symbolic == null) {
return result ? IntValue.TRUE : IntValue.FALSE;
} else if (symbolic != null && i2.symbolic != null) {
SymbolicInt tmp = symbolic.subtract(i2.symbolic);
if (tmp != null) {
tmp = tmp.setop(op);
}
return new IntValue(result ? 1 : 0, tmp);
} else if (symbolic != null) {
return new IntValue(result ? 1 : 0, symbolic.subtract(i2.concrete).setop(op));
} else {
return new IntValue(result ? 1 : 0, i2.symbolic.subtractFrom(concrete).setop(op));
}
}
public IntValue IADD(IntValue i) {
if (symbolic == null && i.symbolic == null) {
return new IntValue(concrete + i.concrete);
} else if (symbolic != null && i.symbolic != null) {
return new IntValue(concrete + i.concrete, symbolic.add(i.symbolic));
} else if (symbolic != null) {
return new IntValue(concrete + i.concrete, symbolic.add(i.concrete));
} else {
return new IntValue(concrete + i.concrete, i.symbolic.add(concrete));
}
}
public IntValue ISUB(IntValue i) {
if (symbolic == null && i.symbolic == null) {
return new IntValue(concrete - i.concrete);
} else if (symbolic != null && i.symbolic != null) {
return new IntValue(concrete - i.concrete, symbolic.subtract(i.symbolic));
} else if (symbolic != null) {
return new IntValue(concrete - i.concrete, symbolic.subtract(i.concrete));
} else {
return new IntValue(concrete - i.concrete, i.symbolic.subtractFrom(concrete));
}
}
public IntValue IMUL(IntValue i) {
if (symbolic == null && i.symbolic == null) {
return new IntValue(concrete * i.concrete);
} else if (symbolic != null && i.symbolic != null) {
return new IntValue(concrete * i.concrete, symbolic.multiply(i.concrete));
} else if (symbolic != null) {
return new IntValue(concrete * i.concrete, symbolic.multiply(i.concrete));
} else {
return new IntValue(concrete * i.concrete, i.symbolic.multiply(concrete));
}
}
// TODO: this does not look like properly supported.
public IntValue IDIV(IntValue i) {
return new IntValue(concrete / i.concrete);
}
public IntValue IREM(IntValue i) {
return new IntValue(concrete % i.concrete);
}
public IntValue INEG() {
if (symbolic == null) return new IntValue(-concrete);
else {
IntValue ret = new IntValue(-concrete);
ret.symbolic = symbolic.subtractFrom(0);
return ret;
}
}
public IntValue ISHL(IntValue i) {
return new IntValue(concrete << i.concrete);
}
public IntValue ISHR(IntValue i) {
return new IntValue(concrete >> i.concrete);
}
public IntValue IUSHR(IntValue i) {
return new IntValue(concrete >>> i.concrete);
}
public IntValue IAND(IntValue i) {
return new IntValue(concrete & i.concrete);
}
public IntValue IOR(IntValue i) {
return new IntValue(concrete | i.concrete);
}
public IntValue IXOR(IntValue i) {
return new IntValue(concrete ^ i.concrete);
}
public LongValue I2L() {
return new LongValue((long) concrete, symbolic);
}
public FloatValue I2F() {
return new FloatValue((float) concrete);
}
public DoubleValue I2D() {
return new DoubleValue((double) concrete);
}
public IntValue I2B() {
return new IntValue((byte) concrete, symbolic);
}
public IntValue I2C() {
return new IntValue((char) concrete, symbolic);
}
public IntValue I2S() {
return new IntValue((short) concrete, symbolic);
}
@Override
public String toString() {
return "IntValue{" + "symbolic=" +
symbolic + ", concrete=" + concrete +
", nonIntConstraint=" + nonIntConstraint + '}';
}
public Constraint getSymbolic() {
return symbolic != null ? symbolic : (nonIntConstraint != null ? nonIntConstraint : null);
}
public SymbolicInt getSymbolicInt() {
return symbolic;
}
}