package gov.nasa.jpf.vm.va; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Set; import cmu.conditional.Conditional; import cmu.conditional.One; import de.fosd.typechef.featureexpr.FeatureExpr; import de.fosd.typechef.featureexpr.FeatureExprFactory; import gov.nasa.jpf.vm.MJIEnv; import gov.nasa.jpf.vm.Types; /** * Similar stack implementation as originally from JPF. * Not variability aware. * * @see HybridStackHandler * * @author Jens Meinicke * */ public class JPFStackHandler implements Cloneable, IStackHandler { protected int top; protected int[] slots; protected int length = 0; protected boolean[] isRef; protected int nLocals = 0; private int nOperands = 0; public FeatureExpr stackCTX; static Entry NULL_ENTRY = new Entry(MJIEnv.NULL, false); public JPFStackHandler(FeatureExpr ctx, int nLocals, int nOperands) { this.nLocals = nLocals; this.nOperands = nOperands; length = nLocals + nOperands; slots = new int[length]; isRef = new boolean[length]; this.nLocals = nLocals; stackCTX = ctx; top = nLocals - 1; } public JPFStackHandler() { slots = new int[0]; stackCTX = FeatureExprFactory.True(); } public JPFStackHandler(JPFStackHandler oneStackHandler) { length = oneStackHandler.length; this.nLocals = oneStackHandler.nLocals; this.nOperands = oneStackHandler.nOperands; slots = new int [length]; isRef = new boolean[length]; top = oneStackHandler.top; System.arraycopy(oneStackHandler.slots, 0, slots, 0, top + 1); System.arraycopy(oneStackHandler.isRef, 0, isRef, 0, top + 1); // stackCTX = oneStackHandler.stackCTX; // TODO this needs to be fixed (see StackHandler) stackCTX = FeatureExprFactory.True(); } @Override public FeatureExpr getCtx() { return stackCTX; } @Override public int getStackWidth() { return 1; } @Override public int getLocalWidth() { return 1; } @Override public String getMaxLocal() { return ""; } @Override public IStackHandler clone() { return new JPFStackHandler(this); } @Override public int getLength() { return length; } @Override public Conditional<Stack> getStack() { return null; } @Override public void pushLocal(FeatureExpr ctx, int index) { push(ctx, slots[index], isRef[index]); } @Override public void pushLongLocal(FeatureExpr ctx, int index) { push(ctx, slots[index], false); push(ctx, slots[index + 1], false); } @Override public void storeOperand(FeatureExpr ctx, int index) { isRef[index] = isRef[top]; slots[index] = slots[top--]; } @Override public void storeLongOperand(FeatureExpr ctx, int index) { slots[index + 1] = slots[top--]; slots[index] = slots[top--]; } @Override public void setLocal(FeatureExpr ctx, int index, Conditional<Integer> value, boolean isRef) { slots[index] = value.getValue(); this.isRef[index] = isRef; } @Override public void setLocal(FeatureExpr ctx, int index, int value, boolean isRef) { slots[index] = value; } @Override public Conditional<Integer> getLocal(FeatureExpr ctx, int index) { if (index < 0) { return One.valueOf(-1); } return One.valueOf(slots[index]); } @Override public boolean isRefLocal(FeatureExpr ctx, int index) { if (index < 0) { return false; } return isRef[index]; } @Override public <T> void push(FeatureExpr ctx, T value) { push(ctx, value, false); } @SuppressWarnings("rawtypes") @Override public void push(FeatureExpr ctx, Object value, boolean isRef) { if (value instanceof Conditional) { push(ctx, ((Conditional) value).simplify(stackCTX).getValue(), isRef); return; } if (value instanceof Integer) { slots[++top] = ((Integer) value); this.isRef[top] = isRef; } else if (value instanceof Long) { long v = ((Long) value).longValue(); slots[++top] = ((int) (v >> 32)); this.isRef[top] = isRef; slots[++top] = ((int) v); this.isRef[top] = isRef; } else if (value instanceof Double) { long v = Double.doubleToLongBits((Double) value); slots[++top] = ((int) (v >> 32)); this.isRef[top] = isRef; slots[++top] = ((int) v); this.isRef[top] = isRef; } else if (value instanceof Float) { slots[++top] = (Float.floatToIntBits((Float) value)); this.isRef[top] = isRef; } else if (value instanceof Byte) { slots[++top] = (((Byte) value).intValue()); this.isRef[top] = isRef; } else if (value instanceof Short) { slots[++top] = ((int) (Short) value); this.isRef[top] = isRef; } else if (value == null) { slots[++top] = (MJIEnv.NULL); this.isRef[top] = isRef; } else { throw new RuntimeException(value + " of type " + value.getClass() + " cannot be pushed to the stack."); } } @Override public Conditional<Integer> pop(final FeatureExpr ctx) { return pop(ctx, Type.INT); } @Override public Conditional<Long> popLong(final FeatureExpr ctx) { return pop(ctx, Type.LONG); } @Override public Conditional<Double> popDouble(final FeatureExpr ctx) { return pop(ctx, Type.DOUBLE); } /* (non-Javadoc) * @see gov.nasa.jpf.vm.IStackHandler#popFloat(de.fosd.typechef.featureexpr.FeatureExpr) */ @Override public Conditional<Float> popFloat(final FeatureExpr ctx) { return pop(ctx, Type.FLOAT); } @SuppressWarnings("unchecked") @Override public <T> Conditional<T> pop(FeatureExpr ctx, Type t) { Number res; this.isRef[top] = false; final int lo = slots[top--]; switch (t) { case INT: res = Integer.valueOf(lo); break; case DOUBLE: this.isRef[top] = false; res = Types.intsToDouble(lo, slots[top--]); break; case FLOAT: res = Types.intToFloat(lo); break; case LONG: this.isRef[top] = false; res = Types.intsToLong(lo, slots[top--]); break; default: return null; } return (Conditional<T>) new One<>(res); } @Override public void pop(FeatureExpr ctx, int n) { top -= n; } @Override public Conditional<Integer> peek(FeatureExpr ctx) { return peek(ctx, 0); } @Override public Conditional<Integer> peek(FeatureExpr ctx, int offset) { return new One<>(slots[top - offset]); } @Override public Conditional<Double> peekDouble(FeatureExpr ctx, int offset) { return new One<>(Types.intsToDouble(slots[top - offset], slots[top - offset - 1])); } @Override public Conditional<Long> peekLong(FeatureExpr ctx, int offset) { return new One<>(Types.intsToLong(slots[top - offset], slots[top - offset - 1])); } @Override public Conditional<Float> peekFloat(FeatureExpr ctx, int offset) { return new One<>(Types.intToFloat(slots[top - offset])); } @Override public boolean isRef(FeatureExpr ctx, int offset) { return this.isRef[top - offset]; } @Override public void set(FeatureExpr ctx, int offset, int value, boolean isRef) { slots[top - offset] = value; this.isRef[top - offset] = isRef; } @Override public Conditional<Integer> getTop() { return One.valueOf(top - nLocals); } @Override public void setTop(FeatureExpr ctx, int i) { top = i; } @Override public void clear(FeatureExpr ctx) { top = nLocals - 1; } @Override public int[] getSlots() { return slots; } @Override public int[] getSlots(FeatureExpr ctx) { return slots; } @Override public boolean hasAnyRef(FeatureExpr ctx) { for (int i = 0; i <= top;i++) { if (isRef[i]) { return true; } } return false; } @Override public void dup_x1(FeatureExpr ctx) { int A = slots[top - 1]; int B = slots[top]; boolean bA = isRef[top - 1]; boolean bB = isRef[top]; slots[top - 1] = B; isRef[top - 1] = bB; slots[top] = A; isRef[top] = bA; slots[top + 1] = B; isRef[top + 1] = bB; top++; } /** * .. A B C D => .. C D A B C D */ @Override public void dup2_x2(FeatureExpr ctx) { final int s0 = top - 3; final int s1 = s0 + 1; final int s2 = s0 + 2; final int s3 = s0 + 3; final int s4 = s0 + 4; final int s5 = s0 + 5; final int A = slots[s0]; final int B = slots[s1]; final int C = slots[s2]; final int D = slots[s3]; slots[s0] = C; slots[s1] = D; slots[s2] = A; slots[s3] = B; slots[s4] = C; slots[s5] = D; top += 2; } @Override public void dup2_x1(FeatureExpr ctx) { int A = slots[top - 2]; int B = slots[top - 1]; int C = slots[top]; slots[top - 2] = B; slots[top - 1] = C; slots[top] = A; slots[top + 1] = B; slots[top + 2] = C; top += 2; } @Override public void dup2(FeatureExpr ctx) { int A = slots[top - 1]; int B = slots[top]; slots[top - 1] = A; slots[top] = B; slots[top + 1] = A; slots[top + 2] = B; top += 2; } @Override public void dup(FeatureExpr ctx) { final int src = this.top; final int dst = this.top + 1; slots[dst] = slots[src]; isRef[dst] = isRef[src]; this.top++; } @Override public void dup_x2(FeatureExpr ctx) { int A = slots[top - 2]; int B = slots[top - 1]; int C = slots[top]; slots[top - 2] = C; slots[top - 1] = A; slots[top] = B; slots[top + 1] = C; top++; } @Override public void swap(FeatureExpr ctx) { final int A = slots[top - 1]; slots[top - 1] = slots[top]; slots[top] = A; } @Override public void setCtx(FeatureExpr ctx) { stackCTX = ctx; } @Override public Collection<Integer> getAllReferences() { Set<Integer> references = new HashSet<>(); for (int i = 0; i <= top; i++) { if (isRef[i]) { references.add(slots[i]); } } return references; } @Override public void IINC(FeatureExpr ctx, int index, int increment) { slots[index] += increment; } @Override public Object getLocal(int index) { return slots[index]; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + length; result = prime * result + Arrays.hashCode(slots); result = prime * result + ((stackCTX == null) ? 0 : stackCTX.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; JPFStackHandler other = (JPFStackHandler) obj; if (length != other.length) return false; if (!Arrays.equals(slots, other.slots)) return false; if (stackCTX == null) { if (other.stackCTX != null) return false; } else if (!stackCTX.equals(other.stackCTX)) return false; return true; } @Override public String toString() { StringBuilder string = new StringBuilder(); string.append(stackCTX); string.append("\nLocals: ["); int i = 0; for (; i < nLocals; i++) { string.append(slots[i]); string.append(" "); } string.append("] \nStack: "); for (; i <= top; i++) { string.append(slots[i]); string.append(" "); } for (; i < slots.length; i++) { string.append("_ "); } return string.toString(); } }