vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
branchregisters
changeset 221 3ee23267706c
parent 191 c18c3df35966
child 242 8bd4adaf6590
     1.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Wed Nov 21 21:03:10 2012 +0100
     1.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Thu Nov 29 20:19:00 2012 +0100
     1.3 @@ -24,6 +24,7 @@
     1.4  import org.apidesign.javap.ClassData;
     1.5  import org.apidesign.javap.FieldData;
     1.6  import org.apidesign.javap.MethodData;
     1.7 +import org.apidesign.javap.StackMapIterator;
     1.8  import static org.apidesign.javap.RuntimeConstants.*;
     1.9  
    1.10  /** Translator of the code inside class files to JavaScript.
    1.11 @@ -153,15 +154,13 @@
    1.12              }
    1.13          }
    1.14          out.append(") {").append("\n");
    1.15 -        final byte[] code = m.getCode();
    1.16 -        if (code != null) {
    1.17 +        if (m.getCode() != null) {
    1.18              int len = m.getMaxLocals();
    1.19 -            for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) {
    1.20 +            for (int i = argsCnt.length(); i < len; i++) {
    1.21                  out.append("  var ");
    1.22                  out.append("arg").append(String.valueOf(i)).append(";\n");
    1.23              }
    1.24 -            out.append("  var stack = new Array();\n");
    1.25 -            produceCode(code);
    1.26 +            produceCode(m);
    1.27          } else {
    1.28              out.append("  /* no code found for ").append(m.getInternalSig()).append(" */\n");
    1.29          }
    1.30 @@ -195,26 +194,49 @@
    1.31              }
    1.32          }
    1.33          out.append(") {").append("\n");
    1.34 -        final byte[] code = m.getCode();
    1.35 -        if (code != null) {
    1.36 +        if (m.getCode() != null) {
    1.37              int len = m.getMaxLocals();
    1.38 -            for (int index = argsCnt.length(), i = argsCnt.length(); i < len; i++) {
    1.39 +            for (int i = argsCnt.length(); i < len; i++) {
    1.40                  out.append("  var ");
    1.41                  out.append("arg").append(String.valueOf(i + 1)).append(";\n");
    1.42              }
    1.43 -            out.append(";\n  var stack = new Array();\n");
    1.44 -            produceCode(code);
    1.45 +            produceCode(m);
    1.46          } else {
    1.47              out.append("  /* no code found for ").append(m.getInternalSig()).append(" */\n");
    1.48          }
    1.49          out.append("}");
    1.50      }
    1.51  
    1.52 -    private void produceCode(byte[] byteCodes) throws IOException {
    1.53 +    private void produceCode(MethodData m) throws IOException {
    1.54 +        final byte[] byteCodes = m.getCode();
    1.55 +        final StackMapIterator stackMapIterator = m.createStackMapIterator();
    1.56 +        final StackToVariableMapper mapper = new StackToVariableMapper();
    1.57 +
    1.58 +        // maxStack includes two stack positions for every pushed long / double
    1.59 +        // so this might generate more stack variables than we need
    1.60 +        final int maxStack = m.getMaxStack();
    1.61 +        if (maxStack > 0) {
    1.62 +            out.append("\n  var ").append(mapper.constructVariableName(0));
    1.63 +            for (int i = 1; i < maxStack; ++i) {
    1.64 +                out.append(", ");
    1.65 +                out.append(mapper.constructVariableName(i));
    1.66 +            }
    1.67 +            out.append(';');
    1.68 +        }
    1.69 +
    1.70 +        int lastStackFrame = -1;
    1.71 +
    1.72          out.append("\n  var gt = 0;\n  for(;;) switch(gt) {\n");
    1.73          for (int i = 0; i < byteCodes.length; i++) {
    1.74              int prev = i;
    1.75 -            out.append("    case " + i).append(": ");
    1.76 +            stackMapIterator.advanceTo(i);
    1.77 +            if (lastStackFrame != stackMapIterator.getFrameIndex()) {
    1.78 +                lastStackFrame = stackMapIterator.getFrameIndex();
    1.79 +                mapper.reset(stackMapIterator.getFrameStackItemsCount());
    1.80 +                out.append("    case " + i).append(": ");
    1.81 +            } else {
    1.82 +                out.append("    /* " + i).append(" */ ");
    1.83 +            }
    1.84              final int c = readByte(byteCodes, i);
    1.85              switch (c) {
    1.86                  case opc_aload_0:
    1.87 @@ -222,28 +244,28 @@
    1.88                  case opc_lload_0:
    1.89                  case opc_fload_0:
    1.90                  case opc_dload_0:
    1.91 -                    out.append("stack.push(arg0);");
    1.92 +                    out.append(mapper.push()).append(" = arg0;");
    1.93                      break;
    1.94                  case opc_aload_1:
    1.95                  case opc_iload_1:
    1.96                  case opc_lload_1:
    1.97                  case opc_fload_1:
    1.98                  case opc_dload_1:
    1.99 -                    out.append("stack.push(arg1);");
   1.100 +                    out.append(mapper.push()).append(" = arg1;");
   1.101                      break;
   1.102                  case opc_aload_2:
   1.103                  case opc_iload_2:
   1.104                  case opc_lload_2:
   1.105                  case opc_fload_2:
   1.106                  case opc_dload_2:
   1.107 -                    out.append("stack.push(arg2);");
   1.108 +                    out.append(mapper.push()).append(" = arg2;");
   1.109                      break;
   1.110                  case opc_aload_3:
   1.111                  case opc_iload_3:
   1.112                  case opc_lload_3:
   1.113                  case opc_fload_3:
   1.114                  case opc_dload_3:
   1.115 -                    out.append("stack.push(arg3);");
   1.116 +                    out.append(mapper.push()).append(" = arg3;");
   1.117                      break;
   1.118                  case opc_iload:
   1.119                  case opc_lload:
   1.120 @@ -251,7 +273,9 @@
   1.121                  case opc_dload:
   1.122                  case opc_aload: {
   1.123                      final int indx = readByte(byteCodes, ++i);
   1.124 -                    out.append("stack.push(arg").append(indx + ");");
   1.125 +                    out.append(mapper.push())
   1.126 +                       .append(" = arg")
   1.127 +                       .append(indx + ";");
   1.128                      break;
   1.129                  }
   1.130                  case opc_istore:
   1.131 @@ -260,7 +284,10 @@
   1.132                  case opc_dstore:
   1.133                  case opc_astore: {
   1.134                      final int indx = readByte(byteCodes, ++i);
   1.135 -                    out.append("arg" + indx).append(" = stack.pop();");
   1.136 +                    out.append("arg" + indx)
   1.137 +                       .append(" = ")
   1.138 +                       .append(mapper.pop())
   1.139 +                       .append(';');
   1.140                      break;
   1.141                  }
   1.142                  case opc_astore_0:
   1.143 @@ -268,90 +295,107 @@
   1.144                  case opc_lstore_0:
   1.145                  case opc_fstore_0:
   1.146                  case opc_dstore_0:
   1.147 -                    out.append("arg0 = stack.pop();");
   1.148 +                    out.append("arg0 = ").append(mapper.pop()).append(';');
   1.149                      break;
   1.150                  case opc_astore_1:
   1.151                  case opc_istore_1:
   1.152                  case opc_lstore_1:
   1.153                  case opc_fstore_1:
   1.154                  case opc_dstore_1:
   1.155 -                    out.append("arg1 = stack.pop();");
   1.156 +                    out.append("arg1 = ").append(mapper.pop()).append(';');
   1.157                      break;
   1.158                  case opc_astore_2:
   1.159                  case opc_istore_2:
   1.160                  case opc_lstore_2:
   1.161                  case opc_fstore_2:
   1.162                  case opc_dstore_2:
   1.163 -                    out.append("arg2 = stack.pop();");
   1.164 +                    out.append("arg2 = ").append(mapper.pop()).append(';');
   1.165                      break;
   1.166                  case opc_astore_3:
   1.167                  case opc_istore_3:
   1.168                  case opc_lstore_3:
   1.169                  case opc_fstore_3:
   1.170                  case opc_dstore_3:
   1.171 -                    out.append("arg3 = stack.pop();");
   1.172 +                    out.append("arg3 = ").append(mapper.pop()).append(';');
   1.173                      break;
   1.174                  case opc_iadd:
   1.175                  case opc_ladd:
   1.176                  case opc_fadd:
   1.177                  case opc_dadd:
   1.178 -                    out.append("stack.push(stack.pop() + stack.pop());");
   1.179 +                    out.append(mapper.get(1)).append(" += ")
   1.180 +                       .append(mapper.pop()).append(';');
   1.181                      break;
   1.182                  case opc_isub:
   1.183                  case opc_lsub:
   1.184                  case opc_fsub:
   1.185                  case opc_dsub:
   1.186 -                    out.append("{ var tmp = stack.pop(); stack.push(stack.pop() - tmp); }");
   1.187 +                    out.append(mapper.get(1)).append(" -= ")
   1.188 +                       .append(mapper.pop()).append(';');
   1.189                      break;
   1.190                  case opc_imul:
   1.191                  case opc_lmul:
   1.192                  case opc_fmul:
   1.193                  case opc_dmul:
   1.194 -                    out.append("stack.push(stack.pop() * stack.pop());");
   1.195 +                    out.append(mapper.get(1)).append(" *= ")
   1.196 +                       .append(mapper.pop()).append(';');
   1.197                      break;
   1.198                  case opc_idiv:
   1.199                  case opc_ldiv:
   1.200 -                    out.append("{ var tmp = stack.pop(); stack.push(Math.floor(stack.pop() / tmp)); }");
   1.201 +                    out.append(mapper.get(1))
   1.202 +                       .append(" = Math.floor(")
   1.203 +                       .append(mapper.get(1))
   1.204 +                       .append(" / ")
   1.205 +                       .append(mapper.pop())
   1.206 +                       .append(");");
   1.207                      break;
   1.208                  case opc_fdiv:
   1.209                  case opc_ddiv:
   1.210 -                    out.append("{ var tmp = stack.pop(); stack.push(stack.pop() / tmp); }");
   1.211 +                    out.append(mapper.get(1)).append(" /= ")
   1.212 +                       .append(mapper.pop()).append(';');
   1.213                      break;
   1.214                  case opc_irem:
   1.215                  case opc_lrem:
   1.216                  case opc_frem:
   1.217                  case opc_drem:
   1.218 -                    out.append("{ var d = stack.pop(); stack.push(stack.pop() % d); }");
   1.219 +                    out.append(mapper.get(1)).append(" %= ")
   1.220 +                       .append(mapper.pop()).append(';');
   1.221                      break;
   1.222                  case opc_iand:
   1.223                  case opc_land:
   1.224 -                    out.append("stack.push(stack.pop() & stack.pop());");
   1.225 +                    out.append(mapper.get(1)).append(" &= ")
   1.226 +                       .append(mapper.pop()).append(';');
   1.227                      break;
   1.228                  case opc_ior:
   1.229                  case opc_lor:
   1.230 -                    out.append("stack.push(stack.pop() | stack.pop());");
   1.231 +                    out.append(mapper.get(1)).append(" |= ")
   1.232 +                       .append(mapper.pop()).append(';');
   1.233                      break;
   1.234                  case opc_ixor:
   1.235                  case opc_lxor:
   1.236 -                    out.append("stack.push(stack.pop() ^ stack.pop());");
   1.237 +                    out.append(mapper.get(1)).append(" ^= ")
   1.238 +                       .append(mapper.pop()).append(';');
   1.239                      break;
   1.240                  case opc_ineg:
   1.241                  case opc_lneg:
   1.242                  case opc_fneg:
   1.243                  case opc_dneg:
   1.244 -                    out.append("stack.push(- stack.pop());");
   1.245 +                    out.append(mapper.get(0)).append(" = -")
   1.246 +                       .append(mapper.get(0)).append(';');
   1.247                      break;
   1.248                  case opc_ishl:
   1.249                  case opc_lshl:
   1.250 -                    out.append("{ var v = stack.pop(); stack.push(stack.pop() << v); }");
   1.251 +                    out.append(mapper.get(1)).append(" <<= ")
   1.252 +                       .append(mapper.pop()).append(';');
   1.253                      break;
   1.254                  case opc_ishr:
   1.255                  case opc_lshr:
   1.256 -                    out.append("{ var v = stack.pop(); stack.push(stack.pop() >> v); }");
   1.257 +                    out.append(mapper.get(1)).append(" >>= ")
   1.258 +                       .append(mapper.pop()).append(';');
   1.259                      break;
   1.260                  case opc_iushr:
   1.261                  case opc_lushr:
   1.262 -                    out.append("{ var v = stack.pop(); stack.push(stack.pop() >>> v); }");
   1.263 +                    out.append(mapper.get(1)).append(" >>>= ")
   1.264 +                       .append(mapper.pop()).append(';');
   1.265                      break;
   1.266                  case opc_iinc: {
   1.267                      final int varIndx = readByte(byteCodes, ++i);
   1.268 @@ -371,7 +415,7 @@
   1.269                  case opc_freturn:
   1.270                  case opc_dreturn:
   1.271                  case opc_areturn:
   1.272 -                    out.append("return stack.pop();");
   1.273 +                    out.append("return ").append(mapper.pop()).append(';');
   1.274                      break;
   1.275                  case opc_i2l:
   1.276                  case opc_i2f:
   1.277 @@ -388,7 +432,10 @@
   1.278                  case opc_f2l:
   1.279                  case opc_d2i:
   1.280                  case opc_d2l:
   1.281 -                    out.append("stack.push(Math.floor(stack.pop()));");
   1.282 +                    out.append(mapper.get(0))
   1.283 +                       .append(" = Math.floor(")
   1.284 +                       .append(mapper.get(0))
   1.285 +                       .append(");");
   1.286                      break;
   1.287                  case opc_i2b:
   1.288                  case opc_i2c:
   1.289 @@ -396,40 +443,43 @@
   1.290                      out.append("/* number conversion */");
   1.291                      break;
   1.292                  case opc_aconst_null:
   1.293 -                    out.append("stack.push(null);");
   1.294 +                    out.append(mapper.push()).append(" = null;");
   1.295                      break;
   1.296                  case opc_iconst_m1:
   1.297 -                    out.append("stack.push(-1);");
   1.298 +                    out.append(mapper.push()).append(" = -1;");
   1.299                      break;
   1.300                  case opc_iconst_0:
   1.301                  case opc_dconst_0:
   1.302                  case opc_lconst_0:
   1.303                  case opc_fconst_0:
   1.304 -                    out.append("stack.push(0);");
   1.305 +                    out.append(mapper.push()).append(" = 0;");
   1.306                      break;
   1.307                  case opc_iconst_1:
   1.308                  case opc_lconst_1:
   1.309                  case opc_fconst_1:
   1.310                  case opc_dconst_1:
   1.311 -                    out.append("stack.push(1);");
   1.312 +                    out.append(mapper.push()).append(" = 1;");
   1.313                      break;
   1.314                  case opc_iconst_2:
   1.315                  case opc_fconst_2:
   1.316 -                    out.append("stack.push(2);");
   1.317 +                    out.append(mapper.push()).append(" = 2;");
   1.318                      break;
   1.319                  case opc_iconst_3:
   1.320 -                    out.append("stack.push(3);");
   1.321 +                    out.append(mapper.push()).append(" = 3;");
   1.322                      break;
   1.323                  case opc_iconst_4:
   1.324 -                    out.append("stack.push(4);");
   1.325 +                    out.append(mapper.push()).append(" = 4;");
   1.326                      break;
   1.327                  case opc_iconst_5:
   1.328 -                    out.append("stack.push(5);");
   1.329 +                    out.append(mapper.push()).append(" = 5;");
   1.330                      break;
   1.331                  case opc_ldc: {
   1.332                      int indx = readByte(byteCodes, ++i);
   1.333                      String v = encodeConstant(indx);
   1.334 -                    out.append("stack.push(").append(v).append(");");
   1.335 +                    out.append(mapper.push())
   1.336 +                       .append(" = ")
   1.337 +                       .append(v)
   1.338 +                       .append(';');
   1.339                      break;
   1.340                  }
   1.341                  case opc_ldc_w:
   1.342 @@ -437,7 +487,10 @@
   1.343                      int indx = readIntArg(byteCodes, i);
   1.344                      i += 2;
   1.345                      String v = encodeConstant(indx);
   1.346 -                    out.append("stack.push(").append(v).append(");");
   1.347 +                    out.append(mapper.push())
   1.348 +                       .append(" = ")
   1.349 +                       .append(v)
   1.350 +                       .append(';');
   1.351                      break;
   1.352                  }
   1.353                  case opc_lcmp:
   1.354 @@ -445,89 +498,108 @@
   1.355                  case opc_fcmpg:
   1.356                  case opc_dcmpl:
   1.357                  case opc_dcmpg: {
   1.358 -                    out.append("{ var delta = stack.pop() - stack.pop(); stack.push(delta < 0 ?-1 : (delta == 0 ? 0 : 1)); }");
   1.359 +                    out.append(mapper.get(1))
   1.360 +                       .append(" = (")
   1.361 +                       .append(mapper.get(1))
   1.362 +                       .append(" == ")
   1.363 +                       .append(mapper.get(0))
   1.364 +                       .append(") ? 0 : ((")
   1.365 +                       .append(mapper.get(1))
   1.366 +                       .append(" < ")
   1.367 +                       .append(mapper.get(0))
   1.368 +                       .append(") ? -1 : 1);");
   1.369 +
   1.370 +                    mapper.pop(1);
   1.371                      break;
   1.372                  }
   1.373                  case opc_if_acmpeq:
   1.374 -                    i = generateIf(byteCodes, i, "===");
   1.375 +                    i = generateIf(byteCodes, i, mapper, "===");
   1.376                      break;
   1.377                  case opc_if_acmpne:
   1.378 -                    i = generateIf(byteCodes, i, "!=");
   1.379 +                    i = generateIf(byteCodes, i, mapper, "!=");
   1.380                      break;
   1.381                  case opc_if_icmpeq: {
   1.382 -                    i = generateIf(byteCodes, i, "==");
   1.383 +                    i = generateIf(byteCodes, i, mapper, "==");
   1.384                      break;
   1.385                  }
   1.386                  case opc_ifeq: {
   1.387                      int indx = i + readIntArg(byteCodes, i);
   1.388 -                    out.append("if (stack.pop() == 0) { gt = " + indx);
   1.389 +                    out.append("if (").append(mapper.pop())
   1.390 +                                      .append(" == 0) { gt = " + indx);
   1.391                      out.append("; continue; }");
   1.392                      i += 2;
   1.393                      break;
   1.394                  }
   1.395                  case opc_ifne: {
   1.396                      int indx = i + readIntArg(byteCodes, i);
   1.397 -                    out.append("if (stack.pop() != 0) { gt = " + indx);
   1.398 +                    out.append("if (").append(mapper.pop())
   1.399 +                                      .append(" != 0) { gt = " + indx);
   1.400                      out.append("; continue; }");
   1.401                      i += 2;
   1.402                      break;
   1.403                  }
   1.404                  case opc_iflt: {
   1.405                      int indx = i + readIntArg(byteCodes, i);
   1.406 -                    out.append("if (stack.pop() < 0) { gt = " + indx);
   1.407 +                    out.append("if (").append(mapper.pop())
   1.408 +                                      .append(" < 0) { gt = " + indx);
   1.409                      out.append("; continue; }");
   1.410                      i += 2;
   1.411                      break;
   1.412                  }
   1.413                  case opc_ifle: {
   1.414                      int indx = i + readIntArg(byteCodes, i);
   1.415 -                    out.append("if (stack.pop() <= 0) { gt = " + indx);
   1.416 +                    out.append("if (").append(mapper.pop())
   1.417 +                                      .append(" <= 0) { gt = " + indx);
   1.418                      out.append("; continue; }");
   1.419                      i += 2;
   1.420                      break;
   1.421                  }
   1.422                  case opc_ifgt: {
   1.423                      int indx = i + readIntArg(byteCodes, i);
   1.424 -                    out.append("if (stack.pop() > 0) { gt = " + indx);
   1.425 +                    out.append("if (").append(mapper.pop())
   1.426 +                                      .append(" > 0) { gt = " + indx);
   1.427                      out.append("; continue; }");
   1.428                      i += 2;
   1.429                      break;
   1.430                  }
   1.431                  case opc_ifge: {
   1.432                      int indx = i + readIntArg(byteCodes, i);
   1.433 -                    out.append("if (stack.pop() >= 0) { gt = " + indx);
   1.434 +                    out.append("if (").append(mapper.pop())
   1.435 +                                      .append(" >= 0) { gt = " + indx);
   1.436                      out.append("; continue; }");
   1.437                      i += 2;
   1.438                      break;
   1.439                  }
   1.440                  case opc_ifnonnull: {
   1.441                      int indx = i + readIntArg(byteCodes, i);
   1.442 -                    out.append("if (stack.pop() !== null) { gt = " + indx);
   1.443 +                    out.append("if (").append(mapper.pop())
   1.444 +                                      .append(" !== null) { gt = " + indx);
   1.445                      out.append("; continue; }");
   1.446                      i += 2;
   1.447                      break;
   1.448                  }
   1.449                  case opc_ifnull: {
   1.450                      int indx = i + readIntArg(byteCodes, i);
   1.451 -                    out.append("if (stack.pop() === null) { gt = " + indx);
   1.452 +                    out.append("if (").append(mapper.pop())
   1.453 +                                      .append(" === null) { gt = " + indx);
   1.454                      out.append("; continue; }");
   1.455                      i += 2;
   1.456                      break;
   1.457                  }
   1.458                  case opc_if_icmpne:
   1.459 -                    i = generateIf(byteCodes, i, "!=");
   1.460 +                    i = generateIf(byteCodes, i, mapper, "!=");
   1.461                      break;
   1.462                  case opc_if_icmplt:
   1.463 -                    i = generateIf(byteCodes, i, ">");
   1.464 +                    i = generateIf(byteCodes, i, mapper, "<");
   1.465                      break;
   1.466                  case opc_if_icmple:
   1.467 -                    i = generateIf(byteCodes, i, ">=");
   1.468 +                    i = generateIf(byteCodes, i, mapper, "<=");
   1.469                      break;
   1.470                  case opc_if_icmpgt:
   1.471 -                    i = generateIf(byteCodes, i, "<");
   1.472 +                    i = generateIf(byteCodes, i, mapper, ">");
   1.473                      break;
   1.474                  case opc_if_icmpge:
   1.475 -                    i = generateIf(byteCodes, i, "<=");
   1.476 +                    i = generateIf(byteCodes, i, mapper, ">=");
   1.477                      break;
   1.478                  case opc_goto: {
   1.479                      int indx = i + readIntArg(byteCodes, i);
   1.480 @@ -541,7 +613,7 @@
   1.481                      table += 4;
   1.482                      int n = readInt4(byteCodes, table);
   1.483                      table += 4;
   1.484 -                    out.append("switch (stack.pop()) {\n");
   1.485 +                    out.append("switch (").append(mapper.pop()).append(") {\n");
   1.486                      while (n-- > 0) {
   1.487                          int cnstnt = readInt4(byteCodes, table);
   1.488                          table += 4;
   1.489 @@ -561,7 +633,7 @@
   1.490                      table += 4;
   1.491                      int high = readInt4(byteCodes, table);
   1.492                      table += 4;
   1.493 -                    out.append("switch (stack.pop()) {\n");
   1.494 +                    out.append("switch (").append(mapper.pop()).append(") {\n");
   1.495                      while (low <= high) {
   1.496                          int offset = i + readInt4(byteCodes, table);
   1.497                          table += 4;
   1.498 @@ -573,44 +645,52 @@
   1.499                      break;
   1.500                  }
   1.501                  case opc_invokeinterface: {
   1.502 -                    i = invokeVirtualMethod(byteCodes, i) + 2;
   1.503 +                    i = invokeVirtualMethod(byteCodes, i, mapper) + 2;
   1.504                      break;
   1.505                  }
   1.506                  case opc_invokevirtual:
   1.507 -                    i = invokeVirtualMethod(byteCodes, i);
   1.508 +                    i = invokeVirtualMethod(byteCodes, i, mapper);
   1.509                      break;
   1.510                  case opc_invokespecial:
   1.511 -                    i = invokeStaticMethod(byteCodes, i, false);
   1.512 +                    i = invokeStaticMethod(byteCodes, i, mapper, false);
   1.513                      break;
   1.514                  case opc_invokestatic:
   1.515 -                    i = invokeStaticMethod(byteCodes, i, true);
   1.516 +                    i = invokeStaticMethod(byteCodes, i, mapper, true);
   1.517                      break;
   1.518                  case opc_new: {
   1.519                      int indx = readIntArg(byteCodes, i);
   1.520                      String ci = jc.getClassName(indx);
   1.521 -                    out.append("stack.push(");
   1.522 +                    out.append(mapper.push()).append(" = ");
   1.523                      out.append("new ").append(ci.replace('/','_'));
   1.524 -                    out.append(");");
   1.525 +                    out.append(';');
   1.526                      addReference(ci);
   1.527                      i += 2;
   1.528                      break;
   1.529                  }
   1.530                  case opc_newarray: {
   1.531 -                    int type = byteCodes[i++];
   1.532 -                    out.append("stack.push(new Array(stack.pop()).fillNulls());");
   1.533 +                    ++i; // skip type of array
   1.534 +                    out.append(mapper.get(0))
   1.535 +                       .append(" = new Array(")
   1.536 +                       .append(mapper.get(0))
   1.537 +                       .append(").fillNulls();");
   1.538                      break;
   1.539                  }
   1.540                  case opc_anewarray: {
   1.541                      i += 2; // skip type of array
   1.542 -                    out.append("stack.push(new Array(stack.pop()).fillNulls());");
   1.543 +                    out.append(mapper.get(0))
   1.544 +                       .append(" = new Array(")
   1.545 +                       .append(mapper.get(0))
   1.546 +                       .append(").fillNulls();");
   1.547                      break;
   1.548                  }
   1.549                  case opc_multianewarray: {
   1.550                      i += 2;
   1.551                      int dim = readByte(byteCodes, ++i);
   1.552 -                    out.append("{ var a0 = new Array(stack.pop()).fillNulls();");
   1.553 +                    out.append("{ var a0 = new Array(").append(mapper.pop())
   1.554 +                       .append(").fillNulls();");
   1.555                      for (int d = 1; d < dim; d++) {
   1.556 -                        out.append("\n  var l" + d).append(" = stack.pop();");
   1.557 +                        out.append("\n  var l" + d).append(" = ")
   1.558 +                           .append(mapper.pop()).append(';');
   1.559                          out.append("\n  for (var i" + d).append (" = 0; i" + d).
   1.560                              append(" < a" + (d - 1)).
   1.561                              append(".length; i" + d).append("++) {");
   1.562 @@ -622,11 +702,12 @@
   1.563                      for (int d = 1; d < dim; d++) {
   1.564                          out.append("\n  }");
   1.565                      }
   1.566 -                    out.append("\nstack.push(a0); }");
   1.567 +                    out.append("\n").append(mapper.push()).append(" = a0; }");
   1.568                      break;
   1.569                  }
   1.570                  case opc_arraylength:
   1.571 -                    out.append("stack.push(stack.pop().length);");
   1.572 +                    out.append(mapper.get(0)).append(" = ")
   1.573 +                       .append(mapper.get(0)).append(".length;");
   1.574                      break;
   1.575                  case opc_iastore:
   1.576                  case opc_lastore:
   1.577 @@ -636,7 +717,12 @@
   1.578                  case opc_bastore:
   1.579                  case opc_castore:
   1.580                  case opc_sastore: {
   1.581 -                    out.append("{ var value = stack.pop(); var indx = stack.pop(); stack.pop()[indx] = value; }");
   1.582 +                    out.append(mapper.get(2))
   1.583 +                       .append('[').append(mapper.get(1)).append(']')
   1.584 +                       .append(" = ")
   1.585 +                       .append(mapper.get(0))
   1.586 +                       .append(';');
   1.587 +                    mapper.pop(3);
   1.588                      break;
   1.589                  }
   1.590                  case opc_iaload:
   1.591 @@ -647,43 +733,68 @@
   1.592                  case opc_baload:
   1.593                  case opc_caload:
   1.594                  case opc_saload: {
   1.595 -                    out.append("{ var indx = stack.pop(); stack.push(stack.pop()[indx]); }");
   1.596 +                    out.append(mapper.get(1))
   1.597 +                       .append(" = ")
   1.598 +                       .append(mapper.get(1))
   1.599 +                       .append('[').append(mapper.pop()).append("];");
   1.600                      break;
   1.601                  }
   1.602 +                case opc_pop:
   1.603                  case opc_pop2:
   1.604 -                    out.append("stack.pop();");
   1.605 -                case opc_pop:
   1.606 -                    out.append("stack.pop();");
   1.607 +                    mapper.pop(1);
   1.608 +                    out.append("/* pop */");
   1.609                      break;
   1.610                  case opc_dup:
   1.611 -                    out.append("stack.push(stack[stack.length - 1]);");
   1.612 +                    out.append(mapper.push()).append(" = ")
   1.613 +                       .append(mapper.get(1)).append(';');
   1.614                      break;
   1.615                  case opc_dup_x1:
   1.616 -                    out.append("{ var v1 = stack.pop(); var v2 = stack.pop(); stack.push(v1); stack.push(v2); stack.push(v1); }");
   1.617 +                    out.append("{ ");
   1.618 +                    out.append(mapper.push()).append(" = ")
   1.619 +                       .append(mapper.get(1)).append("; ");
   1.620 +                    out.append(mapper.get(1)).append(" = ")
   1.621 +                       .append(mapper.get(2)).append("; ");
   1.622 +                    out.append(mapper.get(2)).append(" = ")
   1.623 +                       .append(mapper.get(0)).append("; ");
   1.624 +                    out.append('}');
   1.625                      break;
   1.626                  case opc_dup_x2:
   1.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); }");
   1.628 +                    out.append("{ ");
   1.629 +                    out.append(mapper.push()).append(" = ")
   1.630 +                       .append(mapper.get(1)).append("; ");
   1.631 +                    out.append(mapper.get(1)).append(" = ")
   1.632 +                       .append(mapper.get(2)).append("; ");
   1.633 +                    out.append(mapper.get(2)).append(" = ")
   1.634 +                       .append(mapper.get(3)).append("; ");
   1.635 +                    out.append(mapper.get(3)).append(" = ")
   1.636 +                       .append(mapper.get(0)).append("; ");
   1.637 +                    out.append('}');
   1.638                      break;
   1.639                  case opc_bipush:
   1.640 -                    out.append("stack.push(" + byteCodes[++i] + ");");
   1.641 +                    out.append(mapper.push()).append(" = ")
   1.642 +                       .append(Integer.toString(byteCodes[++i])).append(';');
   1.643                      break;
   1.644                  case opc_sipush:
   1.645 -                    out.append("stack.push(" + readIntArg(byteCodes, i) + ");");
   1.646 +                    out.append(mapper.push()).append(" = ")
   1.647 +                       .append(Integer.toString(readIntArg(byteCodes, i)))
   1.648 +                       .append(';');
   1.649                      i += 2;
   1.650                      break;
   1.651                  case opc_getfield: {
   1.652                      int indx = readIntArg(byteCodes, i);
   1.653                      String[] fi = jc.getFieldInfoName(indx);
   1.654 -                    out.append("stack.push(stack.pop().fld_").
   1.655 -                        append(fi[1]).append(");");
   1.656 +                    out.append(mapper.get(0)).append(" = ")
   1.657 +                       .append(mapper.get(0)).append(".fld_")
   1.658 +                       .append(fi[1]).append(';');
   1.659                      i += 2;
   1.660                      break;
   1.661                  }
   1.662                  case opc_getstatic: {
   1.663                      int indx = readIntArg(byteCodes, i);
   1.664                      String[] fi = jc.getFieldInfoName(indx);
   1.665 -                    out.append("stack.push(").append(fi[0].replace('/', '_'));
   1.666 -                    out.append('.').append(fi[1]).append(");");
   1.667 +                    out.append(mapper.push()).append(" = ")
   1.668 +                       .append(fi[0].replace('/', '_'))
   1.669 +                       .append('.').append(fi[1]).append(';');
   1.670                      i += 2;
   1.671                      addReference(fi[0]);
   1.672                      break;
   1.673 @@ -692,7 +803,8 @@
   1.674                      int indx = readIntArg(byteCodes, i);
   1.675                      String[] fi = jc.getFieldInfoName(indx);
   1.676                      out.append(fi[0].replace('/', '_'));
   1.677 -                    out.append('.').append(fi[1]).append(" = stack.pop();");
   1.678 +                    out.append('.').append(fi[1]).append(" = ")
   1.679 +                       .append(mapper.pop()).append(';');
   1.680                      i += 2;
   1.681                      addReference(fi[0]);
   1.682                      break;
   1.683 @@ -700,8 +812,10 @@
   1.684                  case opc_putfield: {
   1.685                      int indx = readIntArg(byteCodes, i);
   1.686                      String[] fi = jc.getFieldInfoName(indx);
   1.687 -                    out.append("{ var v = stack.pop(); stack.pop().fld_")
   1.688 -                       .append(fi[1]).append(" = v; }");
   1.689 +                    out.append(mapper.get(1)).append(".fld_").append(fi[1])
   1.690 +                       .append(" = ")
   1.691 +                       .append(mapper.get(0)).append(';');
   1.692 +                    mapper.pop(2);
   1.693                      i += 2;
   1.694                      break;
   1.695                  }
   1.696 @@ -710,8 +824,8 @@
   1.697                      final String type = jc.getClassName(indx);
   1.698                      if (!type.startsWith("[")) {
   1.699                          // no way to check arrays right now
   1.700 -                        out.append("if(stack[stack.length - 1].$instOf_")
   1.701 -                           .append(type.replace('/', '_'))
   1.702 +                        out.append("if (").append(mapper.get(0))
   1.703 +                           .append(".$instOf_").append(type.replace('/', '_'))
   1.704                             .append(" != 1) throw {};"); // XXX proper exception
   1.705                      }
   1.706                      i += 2;
   1.707 @@ -720,16 +834,36 @@
   1.708                  case opc_instanceof: {
   1.709                      int indx = readIntArg(byteCodes, i);
   1.710                      final String type = jc.getClassName(indx);
   1.711 -                    out.append("stack.push(stack.pop().$instOf_")
   1.712 +                    out.append(mapper.get(0)).append(" = ")
   1.713 +                       .append(mapper.get(0)).append(".$instOf_")
   1.714                         .append(type.replace('/', '_'))
   1.715 -                       .append(" ? 1 : 0);");
   1.716 +                       .append(" ? 1 : 0;");
   1.717                      i += 2;
   1.718                      break;
   1.719                  }
   1.720                  case opc_athrow: {
   1.721 -                    out.append("{ var t = stack.pop(); stack = new Array(1); stack[0] = t; throw t; }");
   1.722 +                    out.append("{ ");
   1.723 +                    out.append(mapper.bottom()).append(" = ")
   1.724 +                       .append(mapper.top()).append("; ");
   1.725 +                    out.append("throw ").append(mapper.bottom()).append("; ");
   1.726 +                    out.append('}');
   1.727 +
   1.728 +                    mapper.reset(1);
   1.729                      break;
   1.730                  }
   1.731 +
   1.732 +                case opc_monitorenter: {
   1.733 +                    out.append("/* monitor enter */");
   1.734 +                    mapper.pop(1);
   1.735 +                    break;
   1.736 +                }
   1.737 +
   1.738 +                case opc_monitorexit: {
   1.739 +                    out.append("/* monitor exit */");
   1.740 +                    mapper.pop(1);
   1.741 +                    break;
   1.742 +                }
   1.743 +
   1.744                  default: {
   1.745                      out.append("throw 'unknown bytecode " + c + "';");
   1.746                  }
   1.747 @@ -744,12 +878,19 @@
   1.748              out.append("\n");
   1.749          }
   1.750          out.append("  }\n");
   1.751 +
   1.752 +        if (mapper.getMaxStackSize() > maxStack) {
   1.753 +            throw new IllegalStateException("Incorrect stack usage");
   1.754 +        }
   1.755      }
   1.756  
   1.757 -    private int generateIf(byte[] byteCodes, int i, final String test) throws IOException {
   1.758 +    private int generateIf(byte[] byteCodes, int i, final StackToVariableMapper mapper, final String test) throws IOException {
   1.759          int indx = i + readIntArg(byteCodes, i);
   1.760 -        out.append("if (stack.pop() ").append(test).append(" stack.pop()) { gt = " + indx);
   1.761 -        out.append("; continue; }");
   1.762 +        out.append("if (").append(mapper.get(1))
   1.763 +           .append(' ').append(test).append(' ')
   1.764 +           .append(mapper.get(0)).append(") { gt = " + indx)
   1.765 +           .append("; continue; }");
   1.766 +        mapper.pop(2);
   1.767          return i + 2;
   1.768      }
   1.769  
   1.770 @@ -766,7 +907,7 @@
   1.771          return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff);
   1.772      }
   1.773      private int readByte(byte[] byteCodes, int offsetInstruction) {
   1.774 -        return (byteCodes[offsetInstruction] + 256) % 256;
   1.775 +        return byteCodes[offsetInstruction] & 0xff;
   1.776      }
   1.777      
   1.778      private static void countArgs(String descriptor, boolean[] hasReturnType, StringBuilder sig, StringBuilder cnt) {
   1.779 @@ -880,77 +1021,69 @@
   1.780          return name.toString();
   1.781      }
   1.782  
   1.783 -    private int invokeStaticMethod(byte[] byteCodes, int i, boolean isStatic)
   1.784 +    private int invokeStaticMethod(byte[] byteCodes, int i, final StackToVariableMapper mapper, boolean isStatic)
   1.785      throws IOException {
   1.786          int methodIndex = readIntArg(byteCodes, i);
   1.787          String[] mi = jc.getFieldInfoName(methodIndex);
   1.788          boolean[] hasReturn = { false };
   1.789          StringBuilder cnt = new StringBuilder();
   1.790          String mn = findMethodName(mi, cnt, hasReturn);
   1.791 -        out.append("{ ");
   1.792 -        for (int j = cnt.length() - 1; j >= 0; j--) {
   1.793 -            out.append("var v" + j).append(" = stack.pop(); ");
   1.794 +
   1.795 +        final int numArguments = isStatic ? cnt.length() : cnt.length() + 1;
   1.796 +
   1.797 +        if (hasReturn[0]) {
   1.798 +            out.append((numArguments > 0) ? mapper.get(numArguments - 1)
   1.799 +                                          : mapper.push()).append(" = ");
   1.800          }
   1.801 -        
   1.802 -        if (hasReturn[0]) {
   1.803 -            out.append("stack.push(");
   1.804 -        }
   1.805 +
   1.806          final String in = mi[0];
   1.807          out.append(in.replace('/', '_'));
   1.808          out.append(".prototype.");
   1.809          out.append(mn);
   1.810          out.append('(');
   1.811 -        String sep = "";
   1.812 -        if (!isStatic) {
   1.813 -            out.append("stack.pop()");
   1.814 -            sep = ", ";
   1.815 +        if (numArguments > 0) {
   1.816 +            out.append(mapper.get(numArguments - 1));
   1.817 +            for (int j = numArguments - 2; j >= 0; --j) {
   1.818 +                out.append(", ");
   1.819 +                out.append(mapper.get(j));
   1.820 +            }
   1.821          }
   1.822 -        for (int j = 0; j < cnt.length(); j++) {
   1.823 -            out.append(sep);
   1.824 -            out.append("v" + j);
   1.825 -            sep = ", ";
   1.826 +        out.append(");");
   1.827 +        if (numArguments > 0) {
   1.828 +            mapper.pop(hasReturn[0] ? numArguments - 1 : numArguments);
   1.829          }
   1.830 -        out.append(")");
   1.831 -        if (hasReturn[0]) {
   1.832 -            out.append(")");
   1.833 -        }
   1.834 -        out.append("; }");
   1.835          i += 2;
   1.836          addReference(in);
   1.837          return i;
   1.838      }
   1.839 -    private int invokeVirtualMethod(byte[] byteCodes, int i)
   1.840 +    private int invokeVirtualMethod(byte[] byteCodes, int i, final StackToVariableMapper mapper)
   1.841      throws IOException {
   1.842          int methodIndex = readIntArg(byteCodes, i);
   1.843          String[] mi = jc.getFieldInfoName(methodIndex);
   1.844          boolean[] hasReturn = { false };
   1.845          StringBuilder cnt = new StringBuilder();
   1.846          String mn = findMethodName(mi, cnt, hasReturn);
   1.847 -        out.append("{ ");
   1.848 -        for (int j = cnt.length() - 1; j >= 0; j--) {
   1.849 -            out.append("var v" + j).append(" = stack.pop(); ");
   1.850 +
   1.851 +        final int numArguments = cnt.length();
   1.852 +
   1.853 +        if (hasReturn[0]) {
   1.854 +            out.append(mapper.get(numArguments)).append(" = ");
   1.855          }
   1.856 -        out.append("var self = stack.pop(); ");
   1.857 -        if (hasReturn[0]) {
   1.858 -            out.append("stack.push(");
   1.859 -        }
   1.860 -        out.append("self.");
   1.861 +
   1.862 +        out.append(mapper.get(numArguments)).append('.');
   1.863          out.append(mn);
   1.864          out.append('(');
   1.865 -        out.append("self");
   1.866 -        for (int j = 0; j < cnt.length(); j++) {
   1.867 +        out.append(mapper.get(numArguments));
   1.868 +        for (int j = numArguments - 1; j >= 0; --j) {
   1.869              out.append(", ");
   1.870 -            out.append("v" + j);
   1.871 +            out.append(mapper.get(j));
   1.872          }
   1.873 -        out.append(")");
   1.874 -        if (hasReturn[0]) {
   1.875 -            out.append(")");
   1.876 -        }
   1.877 -        out.append("; }");
   1.878 +        out.append(");");
   1.879 +        mapper.pop(hasReturn[0] ? numArguments : numArguments + 1);
   1.880          i += 2;
   1.881          return i;
   1.882      }
   1.883 -    
   1.884 +
   1.885      private void addReference(String cn) throws IOException {
   1.886          if (requireReference(cn)) {
   1.887              out.append(" /* needs ").append(cn).append(" */");