2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. Look for COPYING file in the top folder.
16 * If not, see http://opensource.org/licenses/GPL-2.0.
18 package org.apidesign.vm4brwsr;
20 import java.io.IOException;
21 import org.apidesign.javap.RuntimeConstants;
22 import org.apidesign.javap.TypeArray;
24 final class LocalsMapper {
25 private final TypeArray argTypeRecords;
26 private final TypeArray localTypeRecords;
28 public LocalsMapper(final TypeArray stackMapArgs) {
29 final TypeArray initTypeRecords = new TypeArray();
30 updateRecords(initTypeRecords, stackMapArgs);
32 argTypeRecords = initTypeRecords;
33 localTypeRecords = new TypeArray(initTypeRecords);
36 public void outputArguments(final Appendable out, boolean isStatic) throws IOException {
37 final int argRecordCount = argTypeRecords.getSize();
38 int first = isStatic ? 0 : 1;
39 if (argRecordCount > first) {
40 Variable variable = getVariable(argTypeRecords, first);
43 int i = first + (variable.isCategory2() ? 2 : 1);
44 while (i < argRecordCount) {
45 variable = getVariable(argTypeRecords, i);
48 i += variable.isCategory2() ? 2 : 1;
53 public void syncWithFrameLocals(final TypeArray frameLocals) {
54 updateRecords(localTypeRecords, frameLocals);
57 public Variable setI(final int index) {
58 return setT(index, VarType.INTEGER);
61 public Variable setL(final int index) {
62 return setT(index, VarType.LONG);
65 public Variable setF(final int index) {
66 return setT(index, VarType.FLOAT);
69 public Variable setD(final int index) {
70 return setT(index, VarType.DOUBLE);
73 public Variable setA(final int index) {
74 return setT(index, VarType.REFERENCE);
77 public Variable setT(final int index, final int type) {
78 updateRecord(localTypeRecords, index, type);
79 return Variable.getLocalVariable(type, index);
82 public Variable getI(final int index) {
83 return getT(index, VarType.INTEGER);
86 public Variable getL(final int index) {
87 return getT(index, VarType.LONG);
90 public Variable getF(final int index) {
91 return getT(index, VarType.FLOAT);
94 public Variable getD(final int index) {
95 return getT(index, VarType.DOUBLE);
98 public Variable getA(final int index) {
99 return getT(index, VarType.REFERENCE);
102 public Variable getT(final int index, final int type) {
103 final int oldRecordValue = localTypeRecords.get(index);
104 if ((oldRecordValue & 0xff) != type) {
105 throw new IllegalStateException("Type mismatch");
108 return Variable.getLocalVariable(type, index);
111 private static void updateRecords(final TypeArray typeRecords,
112 final TypeArray stackMapTypes) {
113 final int srcSize = stackMapTypes.getSize();
114 for (int i = 0, dstIndex = 0; i < srcSize; ++i) {
115 final int smType = stackMapTypes.get(i);
116 if (smType == RuntimeConstants.ITEM_Bogus) {
120 final int varType = VarType.fromStackMapType(smType);
121 updateRecord(typeRecords, dstIndex, varType);
122 dstIndex += VarType.isCategory2(varType) ? 2 : 1;
126 private static void updateRecord(final TypeArray typeRecords,
127 final int index, final int type) {
128 if (typeRecords.getSize() < (index + 1)) {
129 typeRecords.setSize(index + 1);
132 final int oldRecordValue = typeRecords.get(index);
133 final int usedTypesMask =
134 (oldRecordValue >> 8) | (1 << type);
135 typeRecords.set(index, (usedTypesMask << 8) | type);
138 private static Variable getVariable(final TypeArray typeRecords,
140 return Variable.getLocalVariable(typeRecords.get(index) & 0xff, index);