1.1 --- a/javap/src/main/java/org/apidesign/javap/MethodData.java Thu Nov 22 10:38:38 2012 +0100
1.2 +++ b/javap/src/main/java/org/apidesign/javap/MethodData.java Thu Nov 29 20:19:00 2012 +0100
1.3 @@ -335,6 +335,10 @@
1.4 return stackMapTable;
1.5 }
1.6
1.7 + public StackMapIterator createStackMapIterator() {
1.8 + return new StackMapIterator(stackMapTable);
1.9 + }
1.10 +
1.11 /**
1.12 * Return number of arguments of that method.
1.13 */
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/javap/src/main/java/org/apidesign/javap/StackMapIterator.java Thu Nov 29 20:19:00 2012 +0100
2.3 @@ -0,0 +1,94 @@
2.4 +/*
2.5 + * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2.7 + *
2.8 + * This code is free software; you can redistribute it and/or modify it
2.9 + * under the terms of the GNU General Public License version 2 only, as
2.10 + * published by the Free Software Foundation. Oracle designates this
2.11 + * particular file as subject to the "Classpath" exception as provided
2.12 + * by Oracle in the LICENSE file that accompanied this code.
2.13 + *
2.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
2.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2.17 + * version 2 for more details (a copy is included in the LICENSE file that
2.18 + * accompanied this code).
2.19 + *
2.20 + * You should have received a copy of the GNU General Public License version
2.21 + * 2 along with this work; if not, write to the Free Software Foundation,
2.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2.23 + *
2.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2.25 + * or visit www.oracle.com if you need additional information or have any
2.26 + * questions.
2.27 + */
2.28 +
2.29 +package org.apidesign.javap;
2.30 +
2.31 +public final class StackMapIterator {
2.32 + private static final StackMapTableData INITIAL_FRAME =
2.33 + new StackMapTableData(-1) {
2.34 + @Override
2.35 + int getStackItemsCount() {
2.36 + return 0;
2.37 + }
2.38 +
2.39 + @Override
2.40 + public String toString() {
2.41 + return "INITIAL(0)";
2.42 + }
2.43 + };
2.44 +
2.45 + private final StackMapTableData[] stackMapTable;
2.46 +
2.47 + private int nextFrameIndex;
2.48 + private int lastFrameByteCodeOffset;
2.49 +
2.50 + private int byteCodeOffset;
2.51 +
2.52 + StackMapIterator(final StackMapTableData[] stackMapTable) {
2.53 + this.stackMapTable = (stackMapTable != null)
2.54 + ? stackMapTable
2.55 + : new StackMapTableData[0];
2.56 + this.lastFrameByteCodeOffset = -1;
2.57 + advanceBy(0);
2.58 + }
2.59 +
2.60 + public String getFrameAsString() {
2.61 + return getCurrentFrame().toString();
2.62 + }
2.63 +
2.64 + public int getFrameIndex() {
2.65 + return nextFrameIndex;
2.66 + }
2.67 +
2.68 + public int getFrameStackItemsCount() {
2.69 + return getCurrentFrame().getStackItemsCount();
2.70 + }
2.71 +
2.72 + public void advanceBy(final int numByteCodes) {
2.73 + if (numByteCodes < 0) {
2.74 + throw new IllegalStateException("Forward only iterator");
2.75 + }
2.76 +
2.77 + byteCodeOffset += numByteCodes;
2.78 + while ((nextFrameIndex < stackMapTable.length)
2.79 + && ((byteCodeOffset - lastFrameByteCodeOffset)
2.80 + >= (stackMapTable[nextFrameIndex].offsetDelta
2.81 + + 1))) {
2.82 + lastFrameByteCodeOffset +=
2.83 + stackMapTable[nextFrameIndex].offsetDelta + 1;
2.84 + ++nextFrameIndex;
2.85 + }
2.86 + }
2.87 +
2.88 + public void advanceTo(final int nextByteCodeOffset) {
2.89 + advanceBy(nextByteCodeOffset - byteCodeOffset);
2.90 + }
2.91 +
2.92 + private StackMapTableData getCurrentFrame() {
2.93 + return (nextFrameIndex == 0)
2.94 + ? INITIAL_FRAME
2.95 + : stackMapTable[nextFrameIndex - 1];
2.96 + }
2.97 +}
3.1 --- a/javap/src/main/java/org/apidesign/javap/StackMapTableData.java Thu Nov 22 10:38:38 2012 +0100
3.2 +++ b/javap/src/main/java/org/apidesign/javap/StackMapTableData.java Thu Nov 29 20:19:00 2012 +0100
3.3 @@ -32,7 +32,7 @@
3.4
3.5 /* represents one entry of StackMapTable attribute
3.6 */
3.7 -class StackMapTableData {
3.8 +abstract class StackMapTableData {
3.9 final int frameType;
3.10 int offsetDelta;
3.11
3.12 @@ -40,11 +40,26 @@
3.13 this.frameType = frameType;
3.14 }
3.15
3.16 + abstract int getStackItemsCount();
3.17 +
3.18 static class SameFrame extends StackMapTableData {
3.19 SameFrame(int frameType, int offsetDelta) {
3.20 super(frameType);
3.21 this.offsetDelta = offsetDelta;
3.22 }
3.23 +
3.24 + @Override
3.25 + int getStackItemsCount() {
3.26 + return 0;
3.27 + }
3.28 +
3.29 + @Override
3.30 + public String toString() {
3.31 + return "SAME"
3.32 + + ((frameType == SAME_FRAME_EXTENDED)
3.33 + ? "_FRAME_EXTENDED" : "")
3.34 + + "(" + offsetDelta + ")";
3.35 + }
3.36 }
3.37
3.38 static class SameLocals1StackItem extends StackMapTableData {
3.39 @@ -54,6 +69,19 @@
3.40 this.offsetDelta = offsetDelta;
3.41 this.stack = stack;
3.42 }
3.43 +
3.44 + @Override
3.45 + int getStackItemsCount() {
3.46 + return 1;
3.47 + }
3.48 +
3.49 + @Override
3.50 + public String toString() {
3.51 + return "SAME_LOCALS_1_STACK_ITEM"
3.52 + + ((frameType == SAME_LOCALS_1_STACK_ITEM_EXTENDED)
3.53 + ? "_EXTENDED" : "")
3.54 + + "(" + offsetDelta + ")";
3.55 + }
3.56 }
3.57
3.58 static class ChopFrame extends StackMapTableData {
3.59 @@ -61,6 +89,16 @@
3.60 super(frameType);
3.61 this.offsetDelta = offsetDelta;
3.62 }
3.63 +
3.64 + @Override
3.65 + int getStackItemsCount() {
3.66 + return 0;
3.67 + }
3.68 +
3.69 + @Override
3.70 + public String toString() {
3.71 + return "CHOP(" + offsetDelta + ")";
3.72 + }
3.73 }
3.74
3.75 static class AppendFrame extends StackMapTableData {
3.76 @@ -70,6 +108,16 @@
3.77 this.offsetDelta = offsetDelta;
3.78 this.locals = locals;
3.79 }
3.80 +
3.81 + @Override
3.82 + int getStackItemsCount() {
3.83 + return 0;
3.84 + }
3.85 +
3.86 + @Override
3.87 + public String toString() {
3.88 + return "APPEND(" + offsetDelta + ")";
3.89 + }
3.90 }
3.91
3.92 static class FullFrame extends StackMapTableData {
3.93 @@ -81,6 +129,16 @@
3.94 this.locals = locals;
3.95 this.stack = stack;
3.96 }
3.97 +
3.98 + @Override
3.99 + int getStackItemsCount() {
3.100 + return stack.length;
3.101 + }
3.102 +
3.103 + @Override
3.104 + public String toString() {
3.105 + return "FULL(" + offsetDelta + ")";
3.106 + }
3.107 }
3.108
3.109 static StackMapTableData getInstance(DataInputStream in, MethodData method)
4.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Nov 22 10:38:38 2012 +0100
4.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Nov 29 20:19:00 2012 +0100
4.3 @@ -24,6 +24,7 @@
4.4 import org.apidesign.javap.ClassData;
4.5 import org.apidesign.javap.FieldData;
4.6 import org.apidesign.javap.MethodData;
4.7 +import org.apidesign.javap.StackMapIterator;
4.8 import static org.apidesign.javap.RuntimeConstants.*;
4.9
4.10 /** Translator of the code inside class files to JavaScript.
4.11 @@ -153,15 +154,13 @@
4.12 }
4.13 }
4.14 out.append(") {").append("\n");
4.15 - final byte[] code = m.getCode();
4.16 - if (code != null) {
4.17 + if (m.getCode() != null) {
4.18 int len = m.getMaxLocals();
4.19 - for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) {
4.20 + for (int i = argsCnt.length(); i < len; i++) {
4.21 out.append(" var ");
4.22 out.append("arg").append(String.valueOf(i)).append(";\n");
4.23 }
4.24 - out.append(" var stack = new Array();\n");
4.25 - produceCode(code);
4.26 + produceCode(m);
4.27 } else {
4.28 out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n");
4.29 }
4.30 @@ -195,26 +194,49 @@
4.31 }
4.32 }
4.33 out.append(") {").append("\n");
4.34 - final byte[] code = m.getCode();
4.35 - if (code != null) {
4.36 + if (m.getCode() != null) {
4.37 int len = m.getMaxLocals();
4.38 - for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) {
4.39 + for (int i = argsCnt.length(); i < len; i++) {
4.40 out.append(" var ");
4.41 out.append("arg").append(String.valueOf(i + 1)).append(";\n");
4.42 }
4.43 - out.append(";\n var stack = new Array();\n");
4.44 - produceCode(code);
4.45 + produceCode(m);
4.46 } else {
4.47 out.append(" /* no code found for ").append(m.getInternalSig()).append(" */\n");
4.48 }
4.49 out.append("}");
4.50 }
4.51
4.52 - private void produceCode(byte[] byteCodes) throws IOException {
4.53 + private void produceCode(MethodData m) throws IOException {
4.54 + final byte[] byteCodes = m.getCode();
4.55 + final StackMapIterator stackMapIterator = m.createStackMapIterator();
4.56 + final StackToVariableMapper mapper = new StackToVariableMapper();
4.57 +
4.58 + // maxStack includes two stack positions for every pushed long / double
4.59 + // so this might generate more stack variables than we need
4.60 + final int maxStack = m.getMaxStack();
4.61 + if (maxStack > 0) {
4.62 + out.append("\n var ").append(mapper.constructVariableName(0));
4.63 + for (int i = 1; i < maxStack; ++i) {
4.64 + out.append(", ");
4.65 + out.append(mapper.constructVariableName(i));
4.66 + }
4.67 + out.append(';');
4.68 + }
4.69 +
4.70 + int lastStackFrame = -1;
4.71 +
4.72 out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
4.73 for (int i = 0; i < byteCodes.length; i++) {
4.74 int prev = i;
4.75 - out.append(" case " + i).append(": ");
4.76 + stackMapIterator.advanceTo(i);
4.77 + if (lastStackFrame != stackMapIterator.getFrameIndex()) {
4.78 + lastStackFrame = stackMapIterator.getFrameIndex();
4.79 + mapper.reset(stackMapIterator.getFrameStackItemsCount());
4.80 + out.append(" case " + i).append(": ");
4.81 + } else {
4.82 + out.append(" /* " + i).append(" */ ");
4.83 + }
4.84 final int c = readByte(byteCodes, i);
4.85 switch (c) {
4.86 case opc_aload_0:
4.87 @@ -222,28 +244,28 @@
4.88 case opc_lload_0:
4.89 case opc_fload_0:
4.90 case opc_dload_0:
4.91 - out.append("stack.push(arg0);");
4.92 + out.append(mapper.push()).append(" = arg0;");
4.93 break;
4.94 case opc_aload_1:
4.95 case opc_iload_1:
4.96 case opc_lload_1:
4.97 case opc_fload_1:
4.98 case opc_dload_1:
4.99 - out.append("stack.push(arg1);");
4.100 + out.append(mapper.push()).append(" = arg1;");
4.101 break;
4.102 case opc_aload_2:
4.103 case opc_iload_2:
4.104 case opc_lload_2:
4.105 case opc_fload_2:
4.106 case opc_dload_2:
4.107 - out.append("stack.push(arg2);");
4.108 + out.append(mapper.push()).append(" = arg2;");
4.109 break;
4.110 case opc_aload_3:
4.111 case opc_iload_3:
4.112 case opc_lload_3:
4.113 case opc_fload_3:
4.114 case opc_dload_3:
4.115 - out.append("stack.push(arg3);");
4.116 + out.append(mapper.push()).append(" = arg3;");
4.117 break;
4.118 case opc_iload:
4.119 case opc_lload:
4.120 @@ -251,7 +273,9 @@
4.121 case opc_dload:
4.122 case opc_aload: {
4.123 final int indx = readByte(byteCodes, ++i);
4.124 - out.append("stack.push(arg").append(indx + ");");
4.125 + out.append(mapper.push())
4.126 + .append(" = arg")
4.127 + .append(indx + ";");
4.128 break;
4.129 }
4.130 case opc_istore:
4.131 @@ -260,7 +284,10 @@
4.132 case opc_dstore:
4.133 case opc_astore: {
4.134 final int indx = readByte(byteCodes, ++i);
4.135 - out.append("arg" + indx).append(" = stack.pop();");
4.136 + out.append("arg" + indx)
4.137 + .append(" = ")
4.138 + .append(mapper.pop())
4.139 + .append(';');
4.140 break;
4.141 }
4.142 case opc_astore_0:
4.143 @@ -268,90 +295,107 @@
4.144 case opc_lstore_0:
4.145 case opc_fstore_0:
4.146 case opc_dstore_0:
4.147 - out.append("arg0 = stack.pop();");
4.148 + out.append("arg0 = ").append(mapper.pop()).append(';');
4.149 break;
4.150 case opc_astore_1:
4.151 case opc_istore_1:
4.152 case opc_lstore_1:
4.153 case opc_fstore_1:
4.154 case opc_dstore_1:
4.155 - out.append("arg1 = stack.pop();");
4.156 + out.append("arg1 = ").append(mapper.pop()).append(';');
4.157 break;
4.158 case opc_astore_2:
4.159 case opc_istore_2:
4.160 case opc_lstore_2:
4.161 case opc_fstore_2:
4.162 case opc_dstore_2:
4.163 - out.append("arg2 = stack.pop();");
4.164 + out.append("arg2 = ").append(mapper.pop()).append(';');
4.165 break;
4.166 case opc_astore_3:
4.167 case opc_istore_3:
4.168 case opc_lstore_3:
4.169 case opc_fstore_3:
4.170 case opc_dstore_3:
4.171 - out.append("arg3 = stack.pop();");
4.172 + out.append("arg3 = ").append(mapper.pop()).append(';');
4.173 break;
4.174 case opc_iadd:
4.175 case opc_ladd:
4.176 case opc_fadd:
4.177 case opc_dadd:
4.178 - out.append("stack.push(stack.pop() + stack.pop());");
4.179 + out.append(mapper.get(1)).append(" += ")
4.180 + .append(mapper.pop()).append(';');
4.181 break;
4.182 case opc_isub:
4.183 case opc_lsub:
4.184 case opc_fsub:
4.185 case opc_dsub:
4.186 - out.append("{ var tmp = stack.pop(); stack.push(stack.pop() - tmp); }");
4.187 + out.append(mapper.get(1)).append(" -= ")
4.188 + .append(mapper.pop()).append(';');
4.189 break;
4.190 case opc_imul:
4.191 case opc_lmul:
4.192 case opc_fmul:
4.193 case opc_dmul:
4.194 - out.append("stack.push(stack.pop() * stack.pop());");
4.195 + out.append(mapper.get(1)).append(" *= ")
4.196 + .append(mapper.pop()).append(';');
4.197 break;
4.198 case opc_idiv:
4.199 case opc_ldiv:
4.200 - out.append("{ var tmp = stack.pop(); stack.push(Math.floor(stack.pop() / tmp)); }");
4.201 + out.append(mapper.get(1))
4.202 + .append(" = Math.floor(")
4.203 + .append(mapper.get(1))
4.204 + .append(" / ")
4.205 + .append(mapper.pop())
4.206 + .append(");");
4.207 break;
4.208 case opc_fdiv:
4.209 case opc_ddiv:
4.210 - out.append("{ var tmp = stack.pop(); stack.push(stack.pop() / tmp); }");
4.211 + out.append(mapper.get(1)).append(" /= ")
4.212 + .append(mapper.pop()).append(';');
4.213 break;
4.214 case opc_irem:
4.215 case opc_lrem:
4.216 case opc_frem:
4.217 case opc_drem:
4.218 - out.append("{ var d = stack.pop(); stack.push(stack.pop() % d); }");
4.219 + out.append(mapper.get(1)).append(" %= ")
4.220 + .append(mapper.pop()).append(';');
4.221 break;
4.222 case opc_iand:
4.223 case opc_land:
4.224 - out.append("stack.push(stack.pop() & stack.pop());");
4.225 + out.append(mapper.get(1)).append(" &= ")
4.226 + .append(mapper.pop()).append(';');
4.227 break;
4.228 case opc_ior:
4.229 case opc_lor:
4.230 - out.append("stack.push(stack.pop() | stack.pop());");
4.231 + out.append(mapper.get(1)).append(" |= ")
4.232 + .append(mapper.pop()).append(';');
4.233 break;
4.234 case opc_ixor:
4.235 case opc_lxor:
4.236 - out.append("stack.push(stack.pop() ^ stack.pop());");
4.237 + out.append(mapper.get(1)).append(" ^= ")
4.238 + .append(mapper.pop()).append(';');
4.239 break;
4.240 case opc_ineg:
4.241 case opc_lneg:
4.242 case opc_fneg:
4.243 case opc_dneg:
4.244 - out.append("stack.push(- stack.pop());");
4.245 + out.append(mapper.get(0)).append(" = -")
4.246 + .append(mapper.get(0)).append(';');
4.247 break;
4.248 case opc_ishl:
4.249 case opc_lshl:
4.250 - out.append("{ var v = stack.pop(); stack.push(stack.pop() << v); }");
4.251 + out.append(mapper.get(1)).append(" <<= ")
4.252 + .append(mapper.pop()).append(';');
4.253 break;
4.254 case opc_ishr:
4.255 case opc_lshr:
4.256 - out.append("{ var v = stack.pop(); stack.push(stack.pop() >> v); }");
4.257 + out.append(mapper.get(1)).append(" >>= ")
4.258 + .append(mapper.pop()).append(';');
4.259 break;
4.260 case opc_iushr:
4.261 case opc_lushr:
4.262 - out.append("{ var v = stack.pop(); stack.push(stack.pop() >>> v); }");
4.263 + out.append(mapper.get(1)).append(" >>>= ")
4.264 + .append(mapper.pop()).append(';');
4.265 break;
4.266 case opc_iinc: {
4.267 final int varIndx = readByte(byteCodes, ++i);
4.268 @@ -371,7 +415,7 @@
4.269 case opc_freturn:
4.270 case opc_dreturn:
4.271 case opc_areturn:
4.272 - out.append("return stack.pop();");
4.273 + out.append("return ").append(mapper.pop()).append(';');
4.274 break;
4.275 case opc_i2l:
4.276 case opc_i2f:
4.277 @@ -388,7 +432,10 @@
4.278 case opc_f2l:
4.279 case opc_d2i:
4.280 case opc_d2l:
4.281 - out.append("stack.push(Math.floor(stack.pop()));");
4.282 + out.append(mapper.get(0))
4.283 + .append(" = Math.floor(")
4.284 + .append(mapper.get(0))
4.285 + .append(");");
4.286 break;
4.287 case opc_i2b:
4.288 case opc_i2c:
4.289 @@ -396,40 +443,43 @@
4.290 out.append("/* number conversion */");
4.291 break;
4.292 case opc_aconst_null:
4.293 - out.append("stack.push(null);");
4.294 + out.append(mapper.push()).append(" = null;");
4.295 break;
4.296 case opc_iconst_m1:
4.297 - out.append("stack.push(-1);");
4.298 + out.append(mapper.push()).append(" = -1;");
4.299 break;
4.300 case opc_iconst_0:
4.301 case opc_dconst_0:
4.302 case opc_lconst_0:
4.303 case opc_fconst_0:
4.304 - out.append("stack.push(0);");
4.305 + out.append(mapper.push()).append(" = 0;");
4.306 break;
4.307 case opc_iconst_1:
4.308 case opc_lconst_1:
4.309 case opc_fconst_1:
4.310 case opc_dconst_1:
4.311 - out.append("stack.push(1);");
4.312 + out.append(mapper.push()).append(" = 1;");
4.313 break;
4.314 case opc_iconst_2:
4.315 case opc_fconst_2:
4.316 - out.append("stack.push(2);");
4.317 + out.append(mapper.push()).append(" = 2;");
4.318 break;
4.319 case opc_iconst_3:
4.320 - out.append("stack.push(3);");
4.321 + out.append(mapper.push()).append(" = 3;");
4.322 break;
4.323 case opc_iconst_4:
4.324 - out.append("stack.push(4);");
4.325 + out.append(mapper.push()).append(" = 4;");
4.326 break;
4.327 case opc_iconst_5:
4.328 - out.append("stack.push(5);");
4.329 + out.append(mapper.push()).append(" = 5;");
4.330 break;
4.331 case opc_ldc: {
4.332 int indx = readByte(byteCodes, ++i);
4.333 String v = encodeConstant(indx);
4.334 - out.append("stack.push(").append(v).append(");");
4.335 + out.append(mapper.push())
4.336 + .append(" = ")
4.337 + .append(v)
4.338 + .append(';');
4.339 break;
4.340 }
4.341 case opc_ldc_w:
4.342 @@ -437,7 +487,10 @@
4.343 int indx = readIntArg(byteCodes, i);
4.344 i += 2;
4.345 String v = encodeConstant(indx);
4.346 - out.append("stack.push(").append(v).append(");");
4.347 + out.append(mapper.push())
4.348 + .append(" = ")
4.349 + .append(v)
4.350 + .append(';');
4.351 break;
4.352 }
4.353 case opc_lcmp:
4.354 @@ -445,89 +498,108 @@
4.355 case opc_fcmpg:
4.356 case opc_dcmpl:
4.357 case opc_dcmpg: {
4.358 - out.append("{ var delta = stack.pop() - stack.pop(); stack.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }");
4.359 + out.append(mapper.get(1))
4.360 + .append(" = (")
4.361 + .append(mapper.get(1))
4.362 + .append(" == ")
4.363 + .append(mapper.get(0))
4.364 + .append(") ? 0 : ((")
4.365 + .append(mapper.get(1))
4.366 + .append(" < ")
4.367 + .append(mapper.get(0))
4.368 + .append(") ? -1 : 1);");
4.369 +
4.370 + mapper.pop(1);
4.371 break;
4.372 }
4.373 case opc_if_acmpeq:
4.374 - i = generateIf(byteCodes, i, "===");
4.375 + i = generateIf(byteCodes, i, mapper, "===");
4.376 break;
4.377 case opc_if_acmpne:
4.378 - i = generateIf(byteCodes, i, "!=");
4.379 + i = generateIf(byteCodes, i, mapper, "!=");
4.380 break;
4.381 case opc_if_icmpeq: {
4.382 - i = generateIf(byteCodes, i, "==");
4.383 + i = generateIf(byteCodes, i, mapper, "==");
4.384 break;
4.385 }
4.386 case opc_ifeq: {
4.387 int indx = i + readIntArg(byteCodes, i);
4.388 - out.append("if (stack.pop() == 0) { gt = " + indx);
4.389 + out.append("if (").append(mapper.pop())
4.390 + .append(" == 0) { gt = " + indx);
4.391 out.append("; continue; }");
4.392 i += 2;
4.393 break;
4.394 }
4.395 case opc_ifne: {
4.396 int indx = i + readIntArg(byteCodes, i);
4.397 - out.append("if (stack.pop() != 0) { gt = " + indx);
4.398 + out.append("if (").append(mapper.pop())
4.399 + .append(" != 0) { gt = " + indx);
4.400 out.append("; continue; }");
4.401 i += 2;
4.402 break;
4.403 }
4.404 case opc_iflt: {
4.405 int indx = i + readIntArg(byteCodes, i);
4.406 - out.append("if (stack.pop() < 0) { gt = " + indx);
4.407 + out.append("if (").append(mapper.pop())
4.408 + .append(" < 0) { gt = " + indx);
4.409 out.append("; continue; }");
4.410 i += 2;
4.411 break;
4.412 }
4.413 case opc_ifle: {
4.414 int indx = i + readIntArg(byteCodes, i);
4.415 - out.append("if (stack.pop() <= 0) { gt = " + indx);
4.416 + out.append("if (").append(mapper.pop())
4.417 + .append(" <= 0) { gt = " + indx);
4.418 out.append("; continue; }");
4.419 i += 2;
4.420 break;
4.421 }
4.422 case opc_ifgt: {
4.423 int indx = i + readIntArg(byteCodes, i);
4.424 - out.append("if (stack.pop() > 0) { gt = " + indx);
4.425 + out.append("if (").append(mapper.pop())
4.426 + .append(" > 0) { gt = " + indx);
4.427 out.append("; continue; }");
4.428 i += 2;
4.429 break;
4.430 }
4.431 case opc_ifge: {
4.432 int indx = i + readIntArg(byteCodes, i);
4.433 - out.append("if (stack.pop() >= 0) { gt = " + indx);
4.434 + out.append("if (").append(mapper.pop())
4.435 + .append(" >= 0) { gt = " + indx);
4.436 out.append("; continue; }");
4.437 i += 2;
4.438 break;
4.439 }
4.440 case opc_ifnonnull: {
4.441 int indx = i + readIntArg(byteCodes, i);
4.442 - out.append("if (stack.pop() !== null) { gt = " + indx);
4.443 + out.append("if (").append(mapper.pop())
4.444 + .append(" !== null) { gt = " + indx);
4.445 out.append("; continue; }");
4.446 i += 2;
4.447 break;
4.448 }
4.449 case opc_ifnull: {
4.450 int indx = i + readIntArg(byteCodes, i);
4.451 - out.append("if (stack.pop() === null) { gt = " + indx);
4.452 + out.append("if (").append(mapper.pop())
4.453 + .append(" === null) { gt = " + indx);
4.454 out.append("; continue; }");
4.455 i += 2;
4.456 break;
4.457 }
4.458 case opc_if_icmpne:
4.459 - i = generateIf(byteCodes, i, "!=");
4.460 + i = generateIf(byteCodes, i, mapper, "!=");
4.461 break;
4.462 case opc_if_icmplt:
4.463 - i = generateIf(byteCodes, i, ">");
4.464 + i = generateIf(byteCodes, i, mapper, "<");
4.465 break;
4.466 case opc_if_icmple:
4.467 - i = generateIf(byteCodes, i, ">=");
4.468 + i = generateIf(byteCodes, i, mapper, "<=");
4.469 break;
4.470 case opc_if_icmpgt:
4.471 - i = generateIf(byteCodes, i, "<");
4.472 + i = generateIf(byteCodes, i, mapper, ">");
4.473 break;
4.474 case opc_if_icmpge:
4.475 - i = generateIf(byteCodes, i, "<=");
4.476 + i = generateIf(byteCodes, i, mapper, ">=");
4.477 break;
4.478 case opc_goto: {
4.479 int indx = i + readIntArg(byteCodes, i);
4.480 @@ -541,7 +613,7 @@
4.481 table += 4;
4.482 int n = readInt4(byteCodes, table);
4.483 table += 4;
4.484 - out.append("switch (stack.pop()) {\n");
4.485 + out.append("switch (").append(mapper.pop()).append(") {\n");
4.486 while (n-- > 0) {
4.487 int cnstnt = readInt4(byteCodes, table);
4.488 table += 4;
4.489 @@ -561,7 +633,7 @@
4.490 table += 4;
4.491 int high = readInt4(byteCodes, table);
4.492 table += 4;
4.493 - out.append("switch (stack.pop()) {\n");
4.494 + out.append("switch (").append(mapper.pop()).append(") {\n");
4.495 while (low <= high) {
4.496 int offset = i + readInt4(byteCodes, table);
4.497 table += 4;
4.498 @@ -573,44 +645,52 @@
4.499 break;
4.500 }
4.501 case opc_invokeinterface: {
4.502 - i = invokeVirtualMethod(byteCodes, i) + 2;
4.503 + i = invokeVirtualMethod(byteCodes, i, mapper) + 2;
4.504 break;
4.505 }
4.506 case opc_invokevirtual:
4.507 - i = invokeVirtualMethod(byteCodes, i);
4.508 + i = invokeVirtualMethod(byteCodes, i, mapper);
4.509 break;
4.510 case opc_invokespecial:
4.511 - i = invokeStaticMethod(byteCodes, i, false);
4.512 + i = invokeStaticMethod(byteCodes, i, mapper, false);
4.513 break;
4.514 case opc_invokestatic:
4.515 - i = invokeStaticMethod(byteCodes, i, true);
4.516 + i = invokeStaticMethod(byteCodes, i, mapper, true);
4.517 break;
4.518 case opc_new: {
4.519 int indx = readIntArg(byteCodes, i);
4.520 String ci = jc.getClassName(indx);
4.521 - out.append("stack.push(");
4.522 + out.append(mapper.push()).append(" = ");
4.523 out.append("new ").append(ci.replace('/','_'));
4.524 - out.append(");");
4.525 + out.append(';');
4.526 addReference(ci);
4.527 i += 2;
4.528 break;
4.529 }
4.530 case opc_newarray: {
4.531 - int type = byteCodes[i++];
4.532 - out.append("stack.push(new Array(stack.pop()).fillNulls());");
4.533 + ++i; // skip type of array
4.534 + out.append(mapper.get(0))
4.535 + .append(" = new Array(")
4.536 + .append(mapper.get(0))
4.537 + .append(").fillNulls();");
4.538 break;
4.539 }
4.540 case opc_anewarray: {
4.541 i += 2; // skip type of array
4.542 - out.append("stack.push(new Array(stack.pop()).fillNulls());");
4.543 + out.append(mapper.get(0))
4.544 + .append(" = new Array(")
4.545 + .append(mapper.get(0))
4.546 + .append(").fillNulls();");
4.547 break;
4.548 }
4.549 case opc_multianewarray: {
4.550 i += 2;
4.551 int dim = readByte(byteCodes, ++i);
4.552 - out.append("{ var a0 = new Array(stack.pop()).fillNulls();");
4.553 + out.append("{ var a0 = new Array(").append(mapper.pop())
4.554 + .append(").fillNulls();");
4.555 for (int d = 1; d < dim; d++) {
4.556 - out.append("\n var l" + d).append(" = stack.pop();");
4.557 + out.append("\n var l" + d).append(" = ")
4.558 + .append(mapper.pop()).append(';');
4.559 out.append("\n for (var i" + d).append (" = 0; i" + d).
4.560 append(" < a" + (d - 1)).
4.561 append(".length; i" + d).append("++) {");
4.562 @@ -622,11 +702,12 @@
4.563 for (int d = 1; d < dim; d++) {
4.564 out.append("\n }");
4.565 }
4.566 - out.append("\nstack.push(a0); }");
4.567 + out.append("\n").append(mapper.push()).append(" = a0; }");
4.568 break;
4.569 }
4.570 case opc_arraylength:
4.571 - out.append("stack.push(stack.pop().length);");
4.572 + out.append(mapper.get(0)).append(" = ")
4.573 + .append(mapper.get(0)).append(".length;");
4.574 break;
4.575 case opc_iastore:
4.576 case opc_lastore:
4.577 @@ -636,7 +717,12 @@
4.578 case opc_bastore:
4.579 case opc_castore:
4.580 case opc_sastore: {
4.581 - out.append("{ var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; }");
4.582 + out.append(mapper.get(2))
4.583 + .append('[').append(mapper.get(1)).append(']')
4.584 + .append(" = ")
4.585 + .append(mapper.get(0))
4.586 + .append(';');
4.587 + mapper.pop(3);
4.588 break;
4.589 }
4.590 case opc_iaload:
4.591 @@ -647,43 +733,68 @@
4.592 case opc_baload:
4.593 case opc_caload:
4.594 case opc_saload: {
4.595 - out.append("{ var indx = stack.pop(); stack.push(stack.pop()[indx]); }");
4.596 + out.append(mapper.get(1))
4.597 + .append(" = ")
4.598 + .append(mapper.get(1))
4.599 + .append('[').append(mapper.pop()).append("];");
4.600 break;
4.601 }
4.602 + case opc_pop:
4.603 case opc_pop2:
4.604 - out.append("stack.pop();");
4.605 - case opc_pop:
4.606 - out.append("stack.pop();");
4.607 + mapper.pop(1);
4.608 + out.append("/* pop */");
4.609 break;
4.610 case opc_dup:
4.611 - out.append("stack.push(stack[stack.length - 1]);");
4.612 + out.append(mapper.push()).append(" = ")
4.613 + .append(mapper.get(1)).append(';');
4.614 break;
4.615 case opc_dup_x1:
4.616 - out.append("{ var v1 = stack.pop(); var v2 = stack.pop(); stack.push(v1); stack.push(v2); stack.push(v1); }");
4.617 + out.append("{ ");
4.618 + out.append(mapper.push()).append(" = ")
4.619 + .append(mapper.get(1)).append("; ");
4.620 + out.append(mapper.get(1)).append(" = ")
4.621 + .append(mapper.get(2)).append("; ");
4.622 + out.append(mapper.get(2)).append(" = ")
4.623 + .append(mapper.get(0)).append("; ");
4.624 + out.append('}');
4.625 break;
4.626 case opc_dup_x2:
4.627 - out.append("{ var v1 = stack.pop(); var v2 = stack.pop(); var v3 = stack.pop(); stack.push(v1); stack.push(v3); stack.push(v2); stack.push(v1); }");
4.628 + out.append("{ ");
4.629 + out.append(mapper.push()).append(" = ")
4.630 + .append(mapper.get(1)).append("; ");
4.631 + out.append(mapper.get(1)).append(" = ")
4.632 + .append(mapper.get(2)).append("; ");
4.633 + out.append(mapper.get(2)).append(" = ")
4.634 + .append(mapper.get(3)).append("; ");
4.635 + out.append(mapper.get(3)).append(" = ")
4.636 + .append(mapper.get(0)).append("; ");
4.637 + out.append('}');
4.638 break;
4.639 case opc_bipush:
4.640 - out.append("stack.push(" + byteCodes[++i] + ");");
4.641 + out.append(mapper.push()).append(" = ")
4.642 + .append(Integer.toString(byteCodes[++i])).append(';');
4.643 break;
4.644 case opc_sipush:
4.645 - out.append("stack.push(" + readIntArg(byteCodes, i) + ");");
4.646 + out.append(mapper.push()).append(" = ")
4.647 + .append(Integer.toString(readIntArg(byteCodes, i)))
4.648 + .append(';');
4.649 i += 2;
4.650 break;
4.651 case opc_getfield: {
4.652 int indx = readIntArg(byteCodes, i);
4.653 String[] fi = jc.getFieldInfoName(indx);
4.654 - out.append("stack.push(stack.pop().fld_").
4.655 - append(fi[1]).append(");");
4.656 + out.append(mapper.get(0)).append(" = ")
4.657 + .append(mapper.get(0)).append(".fld_")
4.658 + .append(fi[1]).append(';');
4.659 i += 2;
4.660 break;
4.661 }
4.662 case opc_getstatic: {
4.663 int indx = readIntArg(byteCodes, i);
4.664 String[] fi = jc.getFieldInfoName(indx);
4.665 - out.append("stack.push(").append(fi[0].replace('/', '_'));
4.666 - out.append('.').append(fi[1]).append(");");
4.667 + out.append(mapper.push()).append(" = ")
4.668 + .append(fi[0].replace('/', '_'))
4.669 + .append('.').append(fi[1]).append(';');
4.670 i += 2;
4.671 addReference(fi[0]);
4.672 break;
4.673 @@ -692,7 +803,8 @@
4.674 int indx = readIntArg(byteCodes, i);
4.675 String[] fi = jc.getFieldInfoName(indx);
4.676 out.append(fi[0].replace('/', '_'));
4.677 - out.append('.').append(fi[1]).append(" = stack.pop();");
4.678 + out.append('.').append(fi[1]).append(" = ")
4.679 + .append(mapper.pop()).append(';');
4.680 i += 2;
4.681 addReference(fi[0]);
4.682 break;
4.683 @@ -700,8 +812,10 @@
4.684 case opc_putfield: {
4.685 int indx = readIntArg(byteCodes, i);
4.686 String[] fi = jc.getFieldInfoName(indx);
4.687 - out.append("{ var v = stack.pop(); stack.pop().fld_")
4.688 - .append(fi[1]).append(" = v; }");
4.689 + out.append(mapper.get(1)).append(".fld_").append(fi[1])
4.690 + .append(" = ")
4.691 + .append(mapper.get(0)).append(';');
4.692 + mapper.pop(2);
4.693 i += 2;
4.694 break;
4.695 }
4.696 @@ -710,8 +824,8 @@
4.697 final String type = jc.getClassName(indx);
4.698 if (!type.startsWith("[")) {
4.699 // no way to check arrays right now
4.700 - out.append("if(stack[stack.length - 1].$instOf_")
4.701 - .append(type.replace('/', '_'))
4.702 + out.append("if (").append(mapper.get(0))
4.703 + .append(".$instOf_").append(type.replace('/', '_'))
4.704 .append(" != 1) throw {};"); // XXX proper exception
4.705 }
4.706 i += 2;
4.707 @@ -720,16 +834,36 @@
4.708 case opc_instanceof: {
4.709 int indx = readIntArg(byteCodes, i);
4.710 final String type = jc.getClassName(indx);
4.711 - out.append("stack.push(stack.pop().$instOf_")
4.712 + out.append(mapper.get(0)).append(" = ")
4.713 + .append(mapper.get(0)).append(".$instOf_")
4.714 .append(type.replace('/', '_'))
4.715 - .append(" ? 1 : 0);");
4.716 + .append(" ? 1 : 0;");
4.717 i += 2;
4.718 break;
4.719 }
4.720 case opc_athrow: {
4.721 - out.append("{ var t = stack.pop(); stack = new Array(1); stack[0] = t; throw t; }");
4.722 + out.append("{ ");
4.723 + out.append(mapper.bottom()).append(" = ")
4.724 + .append(mapper.top()).append("; ");
4.725 + out.append("throw ").append(mapper.bottom()).append("; ");
4.726 + out.append('}');
4.727 +
4.728 + mapper.reset(1);
4.729 break;
4.730 }
4.731 +
4.732 + case opc_monitorenter: {
4.733 + out.append("/* monitor enter */");
4.734 + mapper.pop(1);
4.735 + break;
4.736 + }
4.737 +
4.738 + case opc_monitorexit: {
4.739 + out.append("/* monitor exit */");
4.740 + mapper.pop(1);
4.741 + break;
4.742 + }
4.743 +
4.744 default: {
4.745 out.append("throw 'unknown bytecode " + c + "';");
4.746 }
4.747 @@ -744,12 +878,19 @@
4.748 out.append("\n");
4.749 }
4.750 out.append(" }\n");
4.751 +
4.752 + if (mapper.getMaxStackSize() > maxStack) {
4.753 + throw new IllegalStateException("Incorrect stack usage");
4.754 + }
4.755 }
4.756
4.757 - private int generateIf(byte[] byteCodes, int i, final String test) throws IOException {
4.758 + private int generateIf(byte[] byteCodes, int i, final StackToVariableMapper mapper, final String test) throws IOException {
4.759 int indx = i + readIntArg(byteCodes, i);
4.760 - out.append("if (stack.pop() ").append(test).append(" stack.pop()) { gt = " + indx);
4.761 - out.append("; continue; }");
4.762 + out.append("if (").append(mapper.get(1))
4.763 + .append(' ').append(test).append(' ')
4.764 + .append(mapper.get(0)).append(") { gt = " + indx)
4.765 + .append("; continue; }");
4.766 + mapper.pop(2);
4.767 return i + 2;
4.768 }
4.769
4.770 @@ -766,7 +907,7 @@
4.771 return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff);
4.772 }
4.773 private int readByte(byte[] byteCodes, int offsetInstruction) {
4.774 - return (byteCodes[offsetInstruction] + 256) % 256;
4.775 + return byteCodes[offsetInstruction] & 0xff;
4.776 }
4.777
4.778 private static void countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig, StringBuilder cnt) {
4.779 @@ -880,77 +1021,69 @@
4.780 return name.toString();
4.781 }
4.782
4.783 - private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic)
4.784 + private int invokeStaticMethod(byte[] byteCodes, int i, final StackToVariableMapper mapper, boolean isStatic)
4.785 throws IOException {
4.786 int methodIndex = readIntArg(byteCodes, i);
4.787 String[] mi = jc.getFieldInfoName(methodIndex);
4.788 boolean[] hasReturn = { false };
4.789 StringBuilder cnt = new StringBuilder();
4.790 String mn = findMethodName(mi, cnt, hasReturn);
4.791 - out.append("{ ");
4.792 - for (int j = cnt.length() - 1; j >= 0; j--) {
4.793 - out.append("var v" + j).append(" = stack.pop(); ");
4.794 +
4.795 + final int numArguments = isStatic ? cnt.length() : cnt.length() + 1;
4.796 +
4.797 + if (hasReturn[0]) {
4.798 + out.append((numArguments > 0) ? mapper.get(numArguments - 1)
4.799 + : mapper.push()).append(" = ");
4.800 }
4.801 -
4.802 - if (hasReturn[0]) {
4.803 - out.append("stack.push(");
4.804 - }
4.805 +
4.806 final String in = mi[0];
4.807 out.append(in.replace('/', '_'));
4.808 out.append(".prototype.");
4.809 out.append(mn);
4.810 out.append('(');
4.811 - String sep = "";
4.812 - if (!isStatic) {
4.813 - out.append("stack.pop()");
4.814 - sep = ", ";
4.815 + if (numArguments > 0) {
4.816 + out.append(mapper.get(numArguments - 1));
4.817 + for (int j = numArguments - 2; j >= 0; --j) {
4.818 + out.append(", ");
4.819 + out.append(mapper.get(j));
4.820 + }
4.821 }
4.822 - for (int j = 0; j < cnt.length(); j++) {
4.823 - out.append(sep);
4.824 - out.append("v" + j);
4.825 - sep = ", ";
4.826 + out.append(");");
4.827 + if (numArguments > 0) {
4.828 + mapper.pop(hasReturn[0] ? numArguments - 1 : numArguments);
4.829 }
4.830 - out.append(")");
4.831 - if (hasReturn[0]) {
4.832 - out.append(")");
4.833 - }
4.834 - out.append("; }");
4.835 i += 2;
4.836 addReference(in);
4.837 return i;
4.838 }
4.839 - private int invokeVirtualMethod(byte[] byteCodes, int i)
4.840 + private int invokeVirtualMethod(byte[] byteCodes, int i, final StackToVariableMapper mapper)
4.841 throws IOException {
4.842 int methodIndex = readIntArg(byteCodes, i);
4.843 String[] mi = jc.getFieldInfoName(methodIndex);
4.844 boolean[] hasReturn = { false };
4.845 StringBuilder cnt = new StringBuilder();
4.846 String mn = findMethodName(mi, cnt, hasReturn);
4.847 - out.append("{ ");
4.848 - for (int j = cnt.length() - 1; j >= 0; j--) {
4.849 - out.append("var v" + j).append(" = stack.pop(); ");
4.850 +
4.851 + final int numArguments = cnt.length();
4.852 +
4.853 + if (hasReturn[0]) {
4.854 + out.append(mapper.get(numArguments)).append(" = ");
4.855 }
4.856 - out.append("var self = stack.pop(); ");
4.857 - if (hasReturn[0]) {
4.858 - out.append("stack.push(");
4.859 - }
4.860 - out.append("self.");
4.861 +
4.862 + out.append(mapper.get(numArguments)).append('.');
4.863 out.append(mn);
4.864 out.append('(');
4.865 - out.append("self");
4.866 - for (int j = 0; j < cnt.length(); j++) {
4.867 + out.append(mapper.get(numArguments));
4.868 + for (int j = numArguments - 1; j >= 0; --j) {
4.869 out.append(", ");
4.870 - out.append("v" + j);
4.871 + out.append(mapper.get(j));
4.872 }
4.873 - out.append(")");
4.874 - if (hasReturn[0]) {
4.875 - out.append(")");
4.876 - }
4.877 - out.append("; }");
4.878 + out.append(");");
4.879 + mapper.pop(hasReturn[0] ? numArguments : numArguments + 1);
4.880 i += 2;
4.881 return i;
4.882 }
4.883 -
4.884 +
4.885 private void addReference(String cn) throws IOException {
4.886 if (requireReference(cn)) {
4.887 out.append(" /* needs ").append(cn).append(" */");
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/StackToVariableMapper.java Thu Nov 29 20:19:00 2012 +0100
5.3 @@ -0,0 +1,93 @@
5.4 +/**
5.5 + * Back 2 Browser Bytecode Translator
5.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5.7 + *
5.8 + * This program is free software: you can redistribute it and/or modify
5.9 + * it under the terms of the GNU General Public License as published by
5.10 + * the Free Software Foundation, version 2 of the License.
5.11 + *
5.12 + * This program is distributed in the hope that it will be useful,
5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.15 + * GNU General Public License for more details.
5.16 + *
5.17 + * You should have received a copy of the GNU General Public License
5.18 + * along with this program. Look for COPYING file in the top folder.
5.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
5.20 + */
5.21 +package org.apidesign.vm4brwsr;
5.22 +
5.23 +public final class StackToVariableMapper {
5.24 + private static final String VAR_NAME_PREFIX = "stack";
5.25 +
5.26 + private int stackSize;
5.27 + private StringBuilder varNameBuilder;
5.28 +
5.29 + private int maxStackSize;
5.30 +
5.31 + public StackToVariableMapper() {
5.32 + varNameBuilder = new StringBuilder(VAR_NAME_PREFIX);
5.33 + }
5.34 +
5.35 + public void reset(final int newStackSize) {
5.36 + stackSize = newStackSize;
5.37 + if (maxStackSize < stackSize) {
5.38 + maxStackSize = stackSize;
5.39 + }
5.40 + }
5.41 +
5.42 + public void push(final int numOfElements) {
5.43 + stackSize += numOfElements;
5.44 + if (maxStackSize < stackSize) {
5.45 + maxStackSize = stackSize;
5.46 + }
5.47 + }
5.48 +
5.49 + public String push() {
5.50 + push(1);
5.51 + return get(0);
5.52 + }
5.53 +
5.54 + public void pop(final int numOfElements) {
5.55 + if (numOfElements > stackSize) {
5.56 + throw new IllegalStateException("Stack underflow");
5.57 + }
5.58 + stackSize -= numOfElements;
5.59 + }
5.60 +
5.61 + public String pop() {
5.62 + final String variableName = get(0);
5.63 + pop(1);
5.64 + return variableName;
5.65 + }
5.66 +
5.67 + public String get(final int indexFromTop) {
5.68 + if (indexFromTop >= stackSize) {
5.69 + throw new IllegalStateException("Stack underflow");
5.70 + }
5.71 +
5.72 + return constructVariableName(stackSize - indexFromTop - 1);
5.73 + }
5.74 +
5.75 + public String top() {
5.76 + return get(0);
5.77 + }
5.78 +
5.79 + public String bottom() {
5.80 + if (stackSize == 0) {
5.81 + throw new IllegalStateException("Stack underflow");
5.82 + }
5.83 +
5.84 + return constructVariableName(0);
5.85 + }
5.86 +
5.87 + public int getMaxStackSize() {
5.88 + return maxStackSize;
5.89 + }
5.90 +
5.91 + public String constructVariableName(final int index) {
5.92 + varNameBuilder.setLength(VAR_NAME_PREFIX.length());
5.93 + varNameBuilder.append(index);
5.94 + return varNameBuilder.toString();
5.95 + }
5.96 +}