Register based VM registers
authorLubomir Nerad <lubomir.nerad@oracle.com>
Thu, 29 Nov 2012 20:19:00 +0100
branchregisters
changeset 2213ee23267706c
parent 198 5c1604c5ca9a
child 242 8bd4adaf6590
Register based VM
javap/src/main/java/org/apidesign/javap/MethodData.java
javap/src/main/java/org/apidesign/javap/StackMapIterator.java
javap/src/main/java/org/apidesign/javap/StackMapTableData.java
vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
vm/src/main/java/org/apidesign/vm4brwsr/StackToVariableMapper.java
     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 +}