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; /** * Stack implementation where locals are separated from stack.<br> * Locals: Entry[]<br> * Stack: -Stack- * * @author Jens Meinicke * */ public class OneStackHandler implements Cloneable, IStackHandler { /** Locals are directly accessed with index **/ protected Entry[] locals; protected Stack stack; protected int length = 0; public FeatureExpr stackCTX; static Entry NULL_ENTRY = new Entry(MJIEnv.NULL, false); public OneStackHandler(FeatureExpr ctx, int nLocals, int nOperands) { length = nLocals + nOperands; locals = new Entry[nLocals]; Arrays.fill(locals, NULL_ENTRY); stack = new Stack(nOperands); stackCTX = ctx; } public OneStackHandler() { stack = new Stack(0); locals = new Entry[0]; stackCTX = FeatureExprFactory.True(); } public OneStackHandler(OneStackHandler oneStackHandler) { length = oneStackHandler.length; locals = new Entry[oneStackHandler.locals.length]; for (int i = 0; i < locals.length; i++) { locals[i] = oneStackHandler.locals[i].copy(); } stack = oneStackHandler.stack.copy(); // 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 OneStackHandler(this); } @Override public int getLength() { return stack.slots.length + locals.length; } @Override public Conditional<Stack> getStack() { return new One<>(stack); } @Override public void pushLocal(FeatureExpr ctx, int index) { stack.push(locals[index]); } @Override public void pushLongLocal(FeatureExpr ctx, int index) { stack.push(locals[index]); stack.push(locals[index + 1]); } @Override public void storeOperand(FeatureExpr ctx, int index) { locals[index] = stack.popEntry(); } @Override public void storeLongOperand(FeatureExpr ctx, int index) { locals[index + 1] = stack.popEntry(); locals[index] = stack.popEntry(); } @Override public void setLocal(FeatureExpr ctx, int index, Conditional<Integer> value, boolean isRef) { locals[index] = new Entry(value.getValue(), isRef); } @Override public void setLocal(FeatureExpr ctx, int index, int value, boolean isRef) { locals[index] = new Entry(value, isRef); } @Override public Conditional<Integer> getLocal(FeatureExpr ctx, int index) { if (index < 0) { return One.valueOf(-1); } if (index < locals.length) { return One.valueOf(locals[index].value); } return One.valueOf(stack.slots[index - locals.length].value); } @Override public boolean isRefLocal(FeatureExpr ctx, int index) { if (index < 0) { return false; } if (index < locals.length) { return locals[index].isRef; } return stack.slots[index - locals.length].isRef; } @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(true), isRef); return; } if (value instanceof Integer) { stack.push((Integer) value, isRef); } else if (value instanceof Long) { long v = ((Long) value).longValue(); stack.push((int) (v >> 32), isRef); stack.push((int) v, isRef); } else if (value instanceof Double) { long v = Double.doubleToLongBits((Double) value); stack.push((int) (v >> 32), isRef); stack.push((int) v, isRef); } else if (value instanceof Float) { stack.push(Float.floatToIntBits((Float) value), isRef); } else if (value instanceof Byte) { stack.push(((Byte) value).intValue(), isRef); } else if (value instanceof Short) { stack.push((int) (Short) value, isRef); } else if (value == null) { stack.push(MJIEnv.NULL, 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); } @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; final int lo = stack.pop(); switch (t) { case INT: res = Integer.valueOf(lo); break; case DOUBLE: res = Types.intsToDouble(lo, stack.pop()); break; case FLOAT: res = Types.intToFloat(lo); break; case LONG: res = Types.intsToLong(lo, stack.pop()); break; default: return null; } return (Conditional<T>) new One<>(res); } @Override public void pop(FeatureExpr ctx, int n) { for (int i = n; i > 0; i--) { stack.pop(); } } @Override public Conditional<Integer> peek(FeatureExpr ctx) { return peek(ctx, 0); } @Override public Conditional<Integer> peek(FeatureExpr ctx, int offset) { return new One<>(stack.peek(offset)); } @Override public Conditional<Double> peekDouble(FeatureExpr ctx, int offset) { return new One<>(Types.intsToDouble(stack.peek(offset), stack.peek(offset + 1))); } @Override public Conditional<Long> peekLong(FeatureExpr ctx, int offset) { return new One<>(Types.intsToLong(stack.peek(offset), stack.peek(offset + 1))); } @Override public Conditional<Float> peekFloat(FeatureExpr ctx, int offset) { return new One<>(Types.intToFloat(stack.peek(offset))); } @Override public boolean isRef(FeatureExpr ctx, int offset) { return stack.isRef(offset); } @Override public void set(FeatureExpr ctx, int offset, int value, boolean isRef) { stack.set(offset, value, isRef); } @Override public Conditional<Integer> getTop() { return One.valueOf(stack.top); } @Override public void setTop(FeatureExpr ctx, int i) { stack.top = i; } @Override public void clear(FeatureExpr ctx) { stack.clear(); } @Override public int[] getSlots() { return getSlots(null); } @Override public int[] getSlots(FeatureExpr ctx) { final int[] slots = new int[length]; int j = 0; for (int i = 0; i < locals.length; i++) { slots[j++] = locals[i].value; } for (int i = 0; i <= stack.top; i++) { slots[j++] = stack.slots[i].value; } return slots; } @Override public boolean hasAnyRef(FeatureExpr ctx) { for (Entry local: locals) { if (local.isRef) { return true; } } for (int i = 0; i < stack.top; i++) { if (stack.slots[i].isRef) { return true; } } return false; } @Override public void dup_x1(FeatureExpr ctx) { stack.dup_x1(); } @Override public void dup2_x2(FeatureExpr ctx) { stack.dup2_x2(); } @Override public void dup2_x1(FeatureExpr ctx) { stack.dup2_x1(); } @Override public void dup2(FeatureExpr ctx) { stack.dup2(); } @Override public void dup(FeatureExpr ctx) { stack.dup(); } @Override public void dup_x2(FeatureExpr ctx) { stack.dup_x2(); } @Override public void swap(FeatureExpr ctx) { stack.swap(); } @Override public void setCtx(FeatureExpr ctx) { stackCTX = ctx; } @Override public Collection<Integer> getAllReferences() { Set<Integer> references = new HashSet<>(); for (Entry l : locals) { if (l.isRef) { references.add(l.value); } } references.addAll(stack.getReferences()); return references; } @Override public void IINC(FeatureExpr ctx, int index, int increment) { locals[index] = new Entry(locals[index].value + increment, locals[index].isRef); } @Override public Object getLocal(int index) { return locals[index]; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + length; result = prime * result + Arrays.hashCode(locals); result = prime * result + ((stack == null) ? 0 : stack.hashCode()); 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; OneStackHandler other = (OneStackHandler) obj; if (length != other.length) return false; if (!Arrays.equals(locals, other.locals)) return false; if (stack == null) { if (other.stack != null) return false; } else if (!stack.equals(other.stack)) 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: ["); for (int i = 0; i < locals.length; i++) { string.append(locals[i]); string.append(" "); } string.append("] \nStack: "); string.append(stack); return string.toString(); } }