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