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(" */");