lubomir@221: /** lubomir@221: * Back 2 Browser Bytecode Translator lubomir@221: * Copyright (C) 2012 Jaroslav Tulach lubomir@221: * lubomir@221: * This program is free software: you can redistribute it and/or modify lubomir@221: * it under the terms of the GNU General Public License as published by lubomir@221: * the Free Software Foundation, version 2 of the License. lubomir@221: * lubomir@221: * This program is distributed in the hope that it will be useful, lubomir@221: * but WITHOUT ANY WARRANTY; without even the implied warranty of lubomir@221: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the lubomir@221: * GNU General Public License for more details. lubomir@221: * lubomir@221: * You should have received a copy of the GNU General Public License lubomir@221: * along with this program. Look for COPYING file in the top folder. lubomir@221: * If not, see http://opensource.org/licenses/GPL-2.0. lubomir@221: */ lubomir@221: package org.apidesign.vm4brwsr; lubomir@221: jaroslav@1453: import java.io.IOException; jaroslav@810: import org.apidesign.vm4brwsr.ByteCodeParser.TypeArray; lubomir@281: lubomir@310: final class StackMapper { lubomir@281: private final TypeArray stackTypeIndexPairs; jaroslav@1455: private final StringArray stackValues; lubomir@221: lubomir@307: public StackMapper() { lubomir@281: stackTypeIndexPairs = new TypeArray(); jaroslav@1455: stackValues = new StringArray(); lubomir@221: } lubomir@221: lubomir@281: public void clear() { lubomir@281: stackTypeIndexPairs.clear(); jaroslav@1455: stackValues.clear(); lubomir@281: } lubomir@281: lubomir@281: public void syncWithFrameStack(final TypeArray frameStack) { lubomir@281: clear(); lubomir@281: lubomir@281: final int size = frameStack.getSize(); lubomir@281: for (int i = 0; i < size; ++i) { lubomir@307: pushTypeImpl(VarType.fromStackMapType(frameStack.get(i))); lubomir@221: } lubomir@221: } lubomir@221: lubomir@281: public Variable pushI() { lubomir@307: return pushT(VarType.INTEGER); lubomir@281: } lubomir@281: lubomir@281: public Variable pushL() { lubomir@307: return pushT(VarType.LONG); lubomir@281: } lubomir@281: lubomir@281: public Variable pushF() { lubomir@307: return pushT(VarType.FLOAT); lubomir@281: } lubomir@281: lubomir@281: public Variable pushD() { lubomir@307: return pushT(VarType.DOUBLE); lubomir@281: } lubomir@281: lubomir@281: public Variable pushA() { lubomir@307: return pushT(VarType.REFERENCE); lubomir@281: } lubomir@281: lubomir@281: public Variable pushT(final int type) { lubomir@281: return getVariable(pushTypeImpl(type)); lubomir@281: } lubomir@281: jaroslav@1453: void assign(Appendable out, int varType, CharSequence s) throws IOException { jaroslav@1455: pushTypeAndValue(varType, s); jaroslav@1457: } jaroslav@1457: jaroslav@1457: void replace(Appendable out, int varType, String format, CharSequence... arr) jaroslav@1457: throws IOException { jaroslav@1457: StringBuilder sb = new StringBuilder(); jaroslav@1457: ByteCodeToJavaScript.emitImpl(sb, format, arr); jaroslav@1457: String[] values = stackValues.toArray(); jaroslav@1457: final int last = stackTypeIndexPairs.getSize() - 1; jaroslav@1457: values[last] = sb.toString(); jaroslav@1457: stackTypeIndexPairs.set(last, varType); jaroslav@1455: } jaroslav@1455: jaroslav@1455: void flush(Appendable out) throws IOException { jaroslav@1455: int count = stackTypeIndexPairs.getSize(); jaroslav@1455: for (int i = 0; i < count; i++) { jaroslav@1466: String val = stackValues.getAndClear(i, true); jaroslav@1455: if (val == null) { jaroslav@1455: continue; jaroslav@1455: } jaroslav@1455: CharSequence var = getVariable(stackTypeIndexPairs.get(i)); jaroslav@1455: ByteCodeToJavaScript.emitImpl(out, "var @1 = @2;", var, val); jaroslav@1455: } jaroslav@1453: } jaroslav@1453: jaroslav@1457: public CharSequence popI() { lubomir@307: return popT(VarType.INTEGER); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence popL() { lubomir@307: return popT(VarType.LONG); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence popF() { lubomir@307: return popT(VarType.FLOAT); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence popD() { lubomir@307: return popT(VarType.DOUBLE); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence popA() { lubomir@307: return popT(VarType.REFERENCE); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence popT(final int type) { jaroslav@1457: final CharSequence variable = getT(0, type); lubomir@281: popImpl(1); lubomir@281: return variable; lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence popValue() { jaroslav@1457: final CharSequence variable = getT(0, -1); jaroslav@1457: popImpl(1); jaroslav@1457: return variable; jaroslav@1457: } jaroslav@1457: public Variable pop(Appendable out) throws IOException { jaroslav@1457: flush(out); lubomir@281: final Variable variable = get(0); lubomir@281: popImpl(1); lubomir@281: return variable; lubomir@281: } lubomir@281: lubomir@281: public void pop(final int count) { lubomir@281: final int stackSize = stackTypeIndexPairs.getSize(); lubomir@281: if (count > stackSize) { lubomir@281: throw new IllegalStateException("Stack underflow"); lubomir@281: } lubomir@281: popImpl(count); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence getI(final int indexFromTop) { lubomir@307: return getT(indexFromTop, VarType.INTEGER); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence getL(final int indexFromTop) { lubomir@307: return getT(indexFromTop, VarType.LONG); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence getF(final int indexFromTop) { lubomir@307: return getT(indexFromTop, VarType.FLOAT); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence getD(final int indexFromTop) { lubomir@307: return getT(indexFromTop, VarType.DOUBLE); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence getA(final int indexFromTop) { lubomir@307: return getT(indexFromTop, VarType.REFERENCE); lubomir@281: } lubomir@281: jaroslav@1457: public CharSequence getT(final int indexFromTop, final int type) { jaroslav@1466: return getT(indexFromTop, type, true); jaroslav@1466: } jaroslav@1466: public CharSequence getT(final int indexFromTop, final int type, boolean clear) { lubomir@281: final int stackSize = stackTypeIndexPairs.getSize(); lubomir@281: if (indexFromTop >= stackSize) { lubomir@281: throw new IllegalStateException("Stack underflow"); lubomir@281: } lubomir@281: final int stackValue = lubomir@281: stackTypeIndexPairs.get(stackSize - indexFromTop - 1); jaroslav@1457: if (type != -1 && (stackValue & 0xff) != type) { lubomir@281: throw new IllegalStateException("Type mismatch"); lubomir@281: } jaroslav@1457: String value = jaroslav@1466: stackValues.getAndClear(stackSize - indexFromTop - 1, clear); jaroslav@1457: if (value != null) { jaroslav@1457: return value; jaroslav@1457: } lubomir@281: return getVariable(stackValue); lubomir@281: } lubomir@281: lubomir@281: public Variable get(final int indexFromTop) { lubomir@281: final int stackSize = stackTypeIndexPairs.getSize(); lubomir@281: if (indexFromTop >= stackSize) { lubomir@281: throw new IllegalStateException("Stack underflow"); lubomir@281: } lubomir@281: final int stackValue = lubomir@281: stackTypeIndexPairs.get(stackSize - indexFromTop - 1); lubomir@281: lubomir@281: return getVariable(stackValue); lubomir@281: } lubomir@281: lubomir@281: private int pushTypeImpl(final int type) { jaroslav@1454: final int count = stackTypeIndexPairs.getSize(); lubomir@281: final int value = (count << 8) | (type & 0xff); lubomir@281: stackTypeIndexPairs.add(value); jaroslav@1455: jaroslav@1455: addStackValue(count, null); jaroslav@1455: return value; jaroslav@1455: } lubomir@281: jaroslav@1455: private void pushTypeAndValue(final int type, CharSequence v) { jaroslav@1455: final int count = stackTypeIndexPairs.getSize(); jaroslav@1455: final int value = (count << 8) | (type & 0xff); jaroslav@1455: stackTypeIndexPairs.add(value); jaroslav@1455: final String val = v.toString(); jaroslav@1455: addStackValue(count, val); jaroslav@1455: } jaroslav@1455: jaroslav@1455: private void addStackValue(int at, final String val) { jaroslav@1455: final String[] arr = stackValues.toArray(); jaroslav@1455: if (arr.length > at) { jaroslav@1455: arr[at] = val; jaroslav@1455: } else { jaroslav@1455: stackValues.add(val); jaroslav@1455: } lubomir@281: } lubomir@281: lubomir@281: private void popImpl(final int count) { lubomir@281: final int stackSize = stackTypeIndexPairs.getSize(); lubomir@281: stackTypeIndexPairs.setSize(stackSize - count); lubomir@281: } lubomir@281: lubomir@281: public Variable getVariable(final int typeAndIndex) { lubomir@281: final int type = typeAndIndex & 0xff; lubomir@281: final int index = typeAndIndex >> 8; lubomir@221: lubomir@281: return Variable.getStackVariable(type, index); lubomir@221: } lubomir@221: }