lubomir@319: /** lubomir@319: * Back 2 Browser Bytecode Translator lubomir@319: * Copyright (C) 2012 Jaroslav Tulach lubomir@319: * lubomir@319: * This program is free software: you can redistribute it and/or modify lubomir@319: * it under the terms of the GNU General Public License as published by lubomir@319: * the Free Software Foundation, version 2 of the License. lubomir@319: * lubomir@319: * This program is distributed in the hope that it will be useful, lubomir@319: * but WITHOUT ANY WARRANTY; without even the implied warranty of lubomir@319: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the lubomir@319: * GNU General Public License for more details. lubomir@319: * lubomir@319: * You should have received a copy of the GNU General Public License lubomir@319: * along with this program. Look for COPYING file in the top folder. lubomir@319: * If not, see http://opensource.org/licenses/GPL-2.0. lubomir@319: */ lubomir@319: package org.apidesign.vm4brwsr; lubomir@319: lubomir@319: import java.io.IOException; lubomir@319: import org.apidesign.javap.RuntimeConstants; lubomir@319: import org.apidesign.javap.TypeArray; lubomir@319: lubomir@319: final class LocalsMapper { lubomir@319: private final TypeArray argTypeRecords; lubomir@319: private final TypeArray localTypeRecords; lubomir@319: lubomir@319: public LocalsMapper(final TypeArray stackMapArgs) { lubomir@319: final TypeArray initTypeRecords = new TypeArray(); lubomir@319: updateRecords(initTypeRecords, stackMapArgs); lubomir@319: lubomir@319: argTypeRecords = initTypeRecords; lubomir@319: localTypeRecords = new TypeArray(initTypeRecords); lubomir@319: } lubomir@319: jaroslav@442: public void outputArguments(final Appendable out, boolean isStatic) throws IOException { lubomir@319: final int argRecordCount = argTypeRecords.getSize(); jaroslav@442: int first = isStatic ? 0 : 1; jaroslav@442: if (argRecordCount > first) { jaroslav@442: Variable variable = getVariable(argTypeRecords, first); lubomir@319: out.append(variable); lubomir@319: jaroslav@442: int i = first + (variable.isCategory2() ? 2 : 1); lubomir@319: while (i < argRecordCount) { lubomir@319: variable = getVariable(argTypeRecords, i); lubomir@319: out.append(", "); lubomir@319: out.append(variable); lubomir@319: i += variable.isCategory2() ? 2 : 1; lubomir@319: } lubomir@319: } lubomir@319: } lubomir@319: lubomir@319: public void syncWithFrameLocals(final TypeArray frameLocals) { lubomir@319: updateRecords(localTypeRecords, frameLocals); lubomir@319: } lubomir@319: lubomir@319: public Variable setI(final int index) { lubomir@319: return setT(index, VarType.INTEGER); lubomir@319: } lubomir@319: lubomir@319: public Variable setL(final int index) { lubomir@319: return setT(index, VarType.LONG); lubomir@319: } lubomir@319: lubomir@319: public Variable setF(final int index) { lubomir@319: return setT(index, VarType.FLOAT); lubomir@319: } lubomir@319: lubomir@319: public Variable setD(final int index) { lubomir@319: return setT(index, VarType.DOUBLE); lubomir@319: } lubomir@319: lubomir@319: public Variable setA(final int index) { lubomir@319: return setT(index, VarType.REFERENCE); lubomir@319: } lubomir@319: lubomir@319: public Variable setT(final int index, final int type) { lubomir@319: updateRecord(localTypeRecords, index, type); lubomir@319: return Variable.getLocalVariable(type, index); lubomir@319: } lubomir@319: lubomir@319: public Variable getI(final int index) { lubomir@319: return getT(index, VarType.INTEGER); lubomir@319: } lubomir@319: lubomir@319: public Variable getL(final int index) { lubomir@319: return getT(index, VarType.LONG); lubomir@319: } lubomir@319: lubomir@319: public Variable getF(final int index) { lubomir@319: return getT(index, VarType.FLOAT); lubomir@319: } lubomir@319: lubomir@319: public Variable getD(final int index) { lubomir@319: return getT(index, VarType.DOUBLE); lubomir@319: } lubomir@319: lubomir@319: public Variable getA(final int index) { lubomir@319: return getT(index, VarType.REFERENCE); lubomir@319: } lubomir@319: lubomir@319: public Variable getT(final int index, final int type) { lubomir@319: final int oldRecordValue = localTypeRecords.get(index); lubomir@319: if ((oldRecordValue & 0xff) != type) { lubomir@319: throw new IllegalStateException("Type mismatch"); lubomir@319: } lubomir@319: lubomir@319: return Variable.getLocalVariable(type, index); lubomir@319: } lubomir@319: lubomir@319: private static void updateRecords(final TypeArray typeRecords, lubomir@319: final TypeArray stackMapTypes) { lubomir@319: final int srcSize = stackMapTypes.getSize(); lubomir@319: for (int i = 0, dstIndex = 0; i < srcSize; ++i) { lubomir@319: final int smType = stackMapTypes.get(i); lubomir@319: if (smType == RuntimeConstants.ITEM_Bogus) { lubomir@319: ++dstIndex; lubomir@319: continue; lubomir@319: } lubomir@319: final int varType = VarType.fromStackMapType(smType); lubomir@319: updateRecord(typeRecords, dstIndex, varType); lubomir@319: dstIndex += VarType.isCategory2(varType) ? 2 : 1; lubomir@319: } lubomir@319: } lubomir@319: lubomir@319: private static void updateRecord(final TypeArray typeRecords, lubomir@319: final int index, final int type) { lubomir@319: if (typeRecords.getSize() < (index + 1)) { lubomir@319: typeRecords.setSize(index + 1); lubomir@319: } lubomir@319: lubomir@319: final int oldRecordValue = typeRecords.get(index); lubomir@319: final int usedTypesMask = lubomir@319: (oldRecordValue >> 8) | (1 << type); lubomir@319: typeRecords.set(index, (usedTypesMask << 8) | type); lubomir@319: } lubomir@319: lubomir@319: private static Variable getVariable(final TypeArray typeRecords, lubomir@319: final int index) { lubomir@319: return Variable.getLocalVariable(typeRecords.get(index) & 0xff, index); lubomir@319: } lubomir@319: }