//
// Copyright (C) 2006 United States Government as represented by the
// Administrator of the National Aeronautics and Space Administration
// (NASA). All Rights Reserved.
//
// This software is distributed under the NASA Open Source Agreement
// (NOSA), version 1.3. The NOSA has been approved by the Open Source
// Initiative. See the file NOSA-1.3-JPF at the top of the distribution
// directory tree for the complete NOSA document.
//
// THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY
// KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT
// LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO
// SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR
// A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT
// THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT
// DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE.
//
package gov.nasa.jpf.jvm.bytecode;
import java.util.function.BiFunction;
import cmu.conditional.Conditional;
import java.util.function.Function;
import cmu.conditional.One;
import de.fosd.typechef.featureexpr.FeatureExpr;
import de.fosd.typechef.featureexpr.FeatureExprFactory;
import gov.nasa.jpf.jvm.JVMInstruction;
import gov.nasa.jpf.vm.BooleanChoiceGenerator;
import gov.nasa.jpf.vm.Instruction;
import gov.nasa.jpf.vm.KernelState;
import gov.nasa.jpf.vm.MethodInfo;
import gov.nasa.jpf.vm.StackFrame;
import gov.nasa.jpf.vm.SystemState;
import gov.nasa.jpf.vm.ThreadInfo;
/**
* abstraction for all comparison instructions
*/
public abstract class IfInstruction extends JVMInstruction {
protected int targetPosition; // insn position at jump insnIndex
protected Instruction target; // jump target
protected Conditional<Boolean> conditionValue; /** value of last evaluation of branch condition */
protected IfInstruction(int targetPosition){
this.targetPosition = targetPosition;
}
/**
* return which branch was taken. Only useful after instruction got executed
* WATCH OUT - 'true' means the jump condition is met, which logically is
* the 'false' branch
*/
public boolean getConditionValue() {
return conditionValue.getValue();
}
/**
* Added so that SimpleIdleFilter can detect do-while loops when
* the while statement evaluates to true.
*/
public boolean isBackJump () {
return (conditionValue.getValue()) && (targetPosition <= position);
}
/**
* retrieve value of jump condition from operand stack
* (not ideal to have this public, but some listeners might need it for
* skipping the insn, plus we require it for subclass factorization)
*
*/
public abstract Conditional<Boolean> popConditionValue(FeatureExpr ctx, StackFrame frame);
public Instruction getTarget() {
if (target == null) {
target = mi.getInstructionAt(targetPosition);
}
return target;
}
public Conditional<Instruction> execute (final FeatureExpr ctx, final ThreadInfo ti) {
StackFrame frame = ti.getModifiableTopFrame();
conditionValue = popConditionValue(ctx, frame);
return conditionValue.mapf(ctx, new BiFunction<FeatureExpr, Boolean, Conditional<Instruction>>() {
@Override
public Conditional<Instruction> apply(FeatureExpr x, Boolean condition) {
if (condition) {
return new One<>(getTarget());
} else {
return getNext(x, ti);
}
}
}).simplify();
}
/**
* use this as a delegatee in overridden executes of derived IfInstructions
* (e.g. for symbolic execution)
*/
protected Instruction executeBothBranches (SystemState ss, KernelState ks, ThreadInfo ti){
if (!ti.isFirstStepInsn()) {
BooleanChoiceGenerator cg = new BooleanChoiceGenerator(ti.getVM().getConfig(), "ifAll");
if (ss.setNextChoiceGenerator(cg)){
return this;
} else {
StackFrame frame = ti.getModifiableTopFrame();
// some listener did override the CG, fallback to normal operation
conditionValue = popConditionValue(FeatureExprFactory.True(), frame);
if (conditionValue.getValue()) {
return getTarget();
} else {
return getNext(FeatureExprFactory.True(),ti).getValue();
}
}
} else {
BooleanChoiceGenerator cg = ss.getCurrentChoiceGenerator("ifAll", BooleanChoiceGenerator.class);
assert (cg != null) : "no BooleanChoiceGenerator";
StackFrame frame = ti.getModifiableTopFrame();
popConditionValue(FeatureExprFactory.True(), frame); // we are not interested in concrete values
conditionValue = new One<>(cg.getNextChoice());
if (conditionValue.getValue()) {
return getTarget();
} else {
return getNext(FeatureExprFactory.True(),ti).getValue();
}
}
}
public String toString () {
return super.toString() + " " + targetPosition;
}
public int getLength() {
return 3; // usually opcode, bb1, bb2
}
public void accept(InstructionVisitor insVisitor) {
insVisitor.visit(this);
}
@Override
public Instruction typeSafeClone(MethodInfo mi) {
IfInstruction clone = null;
try {
clone = (IfInstruction) super.clone();
// reset the method that this insn belongs to
clone.mi = mi;
clone.target = null;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
protected Conditional<Boolean> maprIf(final Conditional<Integer> v1, final Conditional<Integer> v2) {
return v1.mapr(new Function<Integer, Conditional<Boolean>>() {
@Override
public Conditional<Boolean> apply(final Integer x1) {
return v2.mapr(new Function<Integer, Conditional<Boolean>>() {
@Override
public Conditional<Boolean> apply(Integer x2) {
return One.valueOf(compare(x1.intValue(), x2.intValue()));
}
});
}
}).simplifyValues();
}
protected boolean compare(int x, int y) {
throw new RuntimeException("compare not implemented");
}
}