diff -r 3ee23267706c -r f2352e0b713e vm/src/main/java/org/apidesign/vm4brwsr/StackToVariableMapper.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/StackToVariableMapper.java Thu Nov 29 20:19:00 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/StackToVariableMapper.java Fri Dec 07 15:02:35 2012 +0100 @@ -17,77 +17,214 @@ */ package org.apidesign.vm4brwsr; +import org.apidesign.javap.TypeArray; + +import static org.apidesign.javap.RuntimeConstants.ITEM_Bogus; +import static org.apidesign.javap.RuntimeConstants.ITEM_Integer; +import static org.apidesign.javap.RuntimeConstants.ITEM_Float; +import static org.apidesign.javap.RuntimeConstants.ITEM_Double; +import static org.apidesign.javap.RuntimeConstants.ITEM_Long; +import static org.apidesign.javap.RuntimeConstants.ITEM_Null; +import static org.apidesign.javap.RuntimeConstants.ITEM_InitObject; +import static org.apidesign.javap.RuntimeConstants.ITEM_Object; +import static org.apidesign.javap.RuntimeConstants.ITEM_NewObject; + public final class StackToVariableMapper { - private static final String VAR_NAME_PREFIX = "stack"; - - private int stackSize; - private StringBuilder varNameBuilder; - - private int maxStackSize; + private final TypeArray stackTypeIndexPairs; + private int[] typeCounters; + private int[] typeMaxCounters; public StackToVariableMapper() { - varNameBuilder = new StringBuilder(VAR_NAME_PREFIX); + stackTypeIndexPairs = new TypeArray(); + typeCounters = new int[Variable.LAST_TYPE + 1]; + typeMaxCounters = new int[Variable.LAST_TYPE + 1]; } - public void reset(final int newStackSize) { - stackSize = newStackSize; - if (maxStackSize < stackSize) { - maxStackSize = stackSize; + public void clear() { + for (int type = 0; type <= Variable.LAST_TYPE; ++type) { + typeCounters[type] = 0; + } + stackTypeIndexPairs.clear(); + } + + public void syncWithFrameStack(final TypeArray frameStack) { + clear(); + + final int size = frameStack.getSize(); + for (int i = 0; i < size; ++i) { + final int frameStackValue = frameStack.get(i); + switch (frameStackValue & 0xff) { + case ITEM_Integer: + pushTypeImpl(Variable.TYPE_INT); + break; + case ITEM_Float: + pushTypeImpl(Variable.TYPE_FLOAT); + break; + case ITEM_Double: + pushTypeImpl(Variable.TYPE_DOUBLE); + break; + case ITEM_Long: + pushTypeImpl(Variable.TYPE_LONG); + break; + case ITEM_Object: + pushTypeImpl(Variable.TYPE_REF); + break; + + case ITEM_Bogus: + case ITEM_Null: + case ITEM_InitObject: + case ITEM_NewObject: + /* unclear how to handle for now */ + default: + throw new IllegalStateException( + "Unhandled frame stack type"); + } } } - public void push(final int numOfElements) { - stackSize += numOfElements; - if (maxStackSize < stackSize) { - maxStackSize = stackSize; + public Variable pushI() { + return pushT(Variable.TYPE_INT); + } + + public Variable pushL() { + return pushT(Variable.TYPE_LONG); + } + + public Variable pushF() { + return pushT(Variable.TYPE_FLOAT); + } + + public Variable pushD() { + return pushT(Variable.TYPE_DOUBLE); + } + + public Variable pushA() { + return pushT(Variable.TYPE_REF); + } + + public Variable pushT(final int type) { + return getVariable(pushTypeImpl(type)); + } + + public Variable popI() { + return popT(Variable.TYPE_INT); + } + + public Variable popL() { + return popT(Variable.TYPE_LONG); + } + + public Variable popF() { + return popT(Variable.TYPE_FLOAT); + } + + public Variable popD() { + return popT(Variable.TYPE_DOUBLE); + } + + public Variable popA() { + return popT(Variable.TYPE_REF); + } + + public Variable popT(final int type) { + final Variable variable = getT(0, type); + popImpl(1); + return variable; + } + + public Variable pop() { + final Variable variable = get(0); + popImpl(1); + return variable; + } + + public void pop(final int count) { + final int stackSize = stackTypeIndexPairs.getSize(); + if (count > stackSize) { + throw new IllegalStateException("Stack underflow"); + } + popImpl(count); + } + + public Variable getI(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_INT); + } + + public Variable getL(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_LONG); + } + + public Variable getF(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_FLOAT); + } + + public Variable getD(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_DOUBLE); + } + + public Variable getA(final int indexFromTop) { + return getT(indexFromTop, Variable.TYPE_REF); + } + + public Variable getT(final int indexFromTop, final int type) { + final int stackSize = stackTypeIndexPairs.getSize(); + if (indexFromTop >= stackSize) { + throw new IllegalStateException("Stack underflow"); + } + final int stackValue = + stackTypeIndexPairs.get(stackSize - indexFromTop - 1); + if ((stackValue & 0xff) != type) { + throw new IllegalStateException("Type mismatch"); + } + + return getVariable(stackValue); + } + + public Variable get(final int indexFromTop) { + final int stackSize = stackTypeIndexPairs.getSize(); + if (indexFromTop >= stackSize) { + throw new IllegalStateException("Stack underflow"); + } + final int stackValue = + stackTypeIndexPairs.get(stackSize - indexFromTop - 1); + + return getVariable(stackValue); + } + + private int pushTypeImpl(final int type) { + final int count = typeCounters[type]; + final int value = (count << 8) | (type & 0xff); + incCounter(type); + stackTypeIndexPairs.add(value); + + return value; + } + + private void popImpl(final int count) { + final int stackSize = stackTypeIndexPairs.getSize(); + for (int i = stackSize - count; i < stackSize; ++i) { + final int value = stackTypeIndexPairs.get(i); + decCounter(value & 0xff); + } + + stackTypeIndexPairs.setSize(stackSize - count); + } + + private void incCounter(final int type) { + final int newValue = ++typeCounters[type]; + if (typeMaxCounters[type] < newValue) { + typeMaxCounters[type] = newValue; } } - public String push() { - push(1); - return get(0); + private void decCounter(final int type) { + --typeCounters[type]; } - public void pop(final int numOfElements) { - if (numOfElements > stackSize) { - throw new IllegalStateException("Stack underflow"); - } - stackSize -= numOfElements; - } + public Variable getVariable(final int typeAndIndex) { + final int type = typeAndIndex & 0xff; + final int index = typeAndIndex >> 8; - public String pop() { - final String variableName = get(0); - pop(1); - return variableName; - } - - public String get(final int indexFromTop) { - if (indexFromTop >= stackSize) { - throw new IllegalStateException("Stack underflow"); - } - - return constructVariableName(stackSize - indexFromTop - 1); - } - - public String top() { - return get(0); - } - - public String bottom() { - if (stackSize == 0) { - throw new IllegalStateException("Stack underflow"); - } - - return constructVariableName(0); - } - - public int getMaxStackSize() { - return maxStackSize; - } - - public String constructVariableName(final int index) { - varNameBuilder.setLength(VAR_NAME_PREFIX.length()); - varNameBuilder.append(index); - return varNameBuilder.toString(); + return Variable.getStackVariable(type, index); } }