1.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Mar 13 11:00:08 2013 +0100
1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Mar 19 13:18:02 2013 +0100
1.3 @@ -283,22 +283,36 @@
1.4 TrapData[] previousTrap = null;
1.5 boolean wide = false;
1.6
1.7 - out.append("\n var gt = 0;\n for(;;) switch(gt) {\n");
1.8 + out.append("\n var gt = 0;\n");
1.9 + int openBraces = 0;
1.10 + int topMostLabel = 0;
1.11 for (int i = 0; i < byteCodes.length; i++) {
1.12 int prev = i;
1.13 stackMapIterator.advanceTo(i);
1.14 boolean changeInCatch = trap.advanceTo(i);
1.15 if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
1.16 if (previousTrap != null) {
1.17 - generateCatch(previousTrap);
1.18 + generateCatch(previousTrap, i, topMostLabel);
1.19 previousTrap = null;
1.20 }
1.21 }
1.22 if (lastStackFrame != stackMapIterator.getFrameIndex()) {
1.23 + if (i != 0) {
1.24 + out.append(" }\n");
1.25 + }
1.26 + if (openBraces > 64) {
1.27 + for (int c = 0; c < 64; c++) {
1.28 + out.append("break;}\n");
1.29 + }
1.30 + openBraces = 1;
1.31 + topMostLabel = i;
1.32 + }
1.33 +
1.34 lastStackFrame = stackMapIterator.getFrameIndex();
1.35 lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
1.36 smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
1.37 - out.append(" case " + i).append(": ");
1.38 + out.append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
1.39 + openBraces++;
1.40 changeInCatch = true;
1.41 } else {
1.42 debug(" /* " + i + " */ ");
1.43 @@ -801,133 +815,104 @@
1.44 break;
1.45 case opc_if_acmpeq:
1.46 i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
1.47 - "===");
1.48 + "===", topMostLabel);
1.49 break;
1.50 case opc_if_acmpne:
1.51 i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
1.52 - "!==");
1.53 + "!==", topMostLabel);
1.54 break;
1.55 case opc_if_icmpeq:
1.56 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.57 - "==");
1.58 + "==", topMostLabel);
1.59 break;
1.60 case opc_ifeq: {
1.61 int indx = i + readIntArg(byteCodes, i);
1.62 - emit(out, "if (@1 == 0) { gt = @2; continue; }",
1.63 - smapper.popI(), Integer.toString(indx));
1.64 + emitIf(out, "if (@1 == 0) ",
1.65 + smapper.popI(), i, indx, topMostLabel);
1.66 i += 2;
1.67 break;
1.68 }
1.69 case opc_ifne: {
1.70 int indx = i + readIntArg(byteCodes, i);
1.71 - emit(out, "if (@1 != 0) { gt = @2; continue; }",
1.72 - smapper.popI(), Integer.toString(indx));
1.73 + emitIf(out, "if (@1 != 0) ",
1.74 + smapper.popI(), i, indx, topMostLabel);
1.75 i += 2;
1.76 break;
1.77 }
1.78 case opc_iflt: {
1.79 int indx = i + readIntArg(byteCodes, i);
1.80 - emit(out, "if (@1 < 0) { gt = @2; continue; }",
1.81 - smapper.popI(), Integer.toString(indx));
1.82 + emitIf(out, "if (@1 < 0) ",
1.83 + smapper.popI(), i, indx, topMostLabel);
1.84 i += 2;
1.85 break;
1.86 }
1.87 case opc_ifle: {
1.88 int indx = i + readIntArg(byteCodes, i);
1.89 - emit(out, "if (@1 <= 0) { gt = @2; continue; }",
1.90 - smapper.popI(), Integer.toString(indx));
1.91 + emitIf(out, "if (@1 <= 0) ",
1.92 + smapper.popI(), i, indx, topMostLabel);
1.93 i += 2;
1.94 break;
1.95 }
1.96 case opc_ifgt: {
1.97 int indx = i + readIntArg(byteCodes, i);
1.98 - emit(out, "if (@1 > 0) { gt = @2; continue; }",
1.99 - smapper.popI(), Integer.toString(indx));
1.100 + emitIf(out, "if (@1 > 0) ",
1.101 + smapper.popI(), i, indx, topMostLabel);
1.102 i += 2;
1.103 break;
1.104 }
1.105 case opc_ifge: {
1.106 int indx = i + readIntArg(byteCodes, i);
1.107 - emit(out, "if (@1 >= 0) { gt = @2; continue; }",
1.108 - smapper.popI(), Integer.toString(indx));
1.109 + emitIf(out, "if (@1 >= 0) ",
1.110 + smapper.popI(), i, indx, topMostLabel);
1.111 i += 2;
1.112 break;
1.113 }
1.114 case opc_ifnonnull: {
1.115 int indx = i + readIntArg(byteCodes, i);
1.116 - emit(out, "if (@1 !== null) { gt = @2; continue; }",
1.117 - smapper.popA(), Integer.toString(indx));
1.118 + emitIf(out, "if (@1 !== null) ",
1.119 + smapper.popA(), i, indx, topMostLabel);
1.120 i += 2;
1.121 break;
1.122 }
1.123 case opc_ifnull: {
1.124 int indx = i + readIntArg(byteCodes, i);
1.125 - emit(out, "if (@1 === null) { gt = @2; continue; }",
1.126 - smapper.popA(), Integer.toString(indx));
1.127 + emitIf(out, "if (@1 === null) ",
1.128 + smapper.popA(), i, indx, topMostLabel);
1.129 i += 2;
1.130 break;
1.131 }
1.132 case opc_if_icmpne:
1.133 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.134 - "!=");
1.135 + "!=", topMostLabel);
1.136 break;
1.137 case opc_if_icmplt:
1.138 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.139 - "<");
1.140 + "<", topMostLabel);
1.141 break;
1.142 case opc_if_icmple:
1.143 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.144 - "<=");
1.145 + "<=", topMostLabel);
1.146 break;
1.147 case opc_if_icmpgt:
1.148 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.149 - ">");
1.150 + ">", topMostLabel);
1.151 break;
1.152 case opc_if_icmpge:
1.153 i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
1.154 - ">=");
1.155 + ">=", topMostLabel);
1.156 break;
1.157 case opc_goto: {
1.158 int indx = i + readIntArg(byteCodes, i);
1.159 - emit(out, "gt = @1; continue;", Integer.toString(indx));
1.160 + goTo(out, i, indx, topMostLabel);
1.161 i += 2;
1.162 break;
1.163 }
1.164 case opc_lookupswitch: {
1.165 - int table = i / 4 * 4 + 4;
1.166 - int dflt = i + readInt4(byteCodes, table);
1.167 - table += 4;
1.168 - int n = readInt4(byteCodes, table);
1.169 - table += 4;
1.170 - out.append("switch (").append(smapper.popI()).append(") {\n");
1.171 - while (n-- > 0) {
1.172 - int cnstnt = readInt4(byteCodes, table);
1.173 - table += 4;
1.174 - int offset = i + readInt4(byteCodes, table);
1.175 - table += 4;
1.176 - out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n");
1.177 - }
1.178 - out.append(" default: gt = " + dflt).append("; continue;\n}");
1.179 - i = table - 1;
1.180 + i = generateLookupSwitch(i, byteCodes, smapper, topMostLabel);
1.181 break;
1.182 }
1.183 case opc_tableswitch: {
1.184 - int table = i / 4 * 4 + 4;
1.185 - int dflt = i + readInt4(byteCodes, table);
1.186 - table += 4;
1.187 - int low = readInt4(byteCodes, table);
1.188 - table += 4;
1.189 - int high = readInt4(byteCodes, table);
1.190 - table += 4;
1.191 - out.append("switch (").append(smapper.popI()).append(") {\n");
1.192 - while (low <= high) {
1.193 - int offset = i + readInt4(byteCodes, table);
1.194 - table += 4;
1.195 - out.append(" case " + low).append(": gt = " + offset).append("; continue;\n");
1.196 - low++;
1.197 - }
1.198 - out.append(" default: gt = " + dflt).append("; continue;\n}");
1.199 - i = table - 1;
1.200 + i = generateTableSwitch(i, byteCodes, smapper, topMostLabel);
1.201 break;
1.202 }
1.203 case opc_invokeinterface: {
1.204 @@ -954,50 +939,18 @@
1.205 }
1.206 case opc_newarray:
1.207 int atype = readUByte(byteCodes, ++i);
1.208 - String jvmType;
1.209 - switch (atype) {
1.210 - case 4: jvmType = "[Z"; break;
1.211 - case 5: jvmType = "[C"; break;
1.212 - case 6: jvmType = "[F"; break;
1.213 - case 7: jvmType = "[D"; break;
1.214 - case 8: jvmType = "[B"; break;
1.215 - case 9: jvmType = "[S"; break;
1.216 - case 10: jvmType = "[I"; break;
1.217 - case 11: jvmType = "[J"; break;
1.218 - default: throw new IllegalStateException("Array type: " + atype);
1.219 - }
1.220 - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
1.221 - smapper.popI(), smapper.pushA(), jvmType);
1.222 + generateNewArray(atype, smapper);
1.223 break;
1.224 case opc_anewarray: {
1.225 int type = readIntArg(byteCodes, i);
1.226 i += 2;
1.227 - String typeName = jc.getClassName(type);
1.228 - if (typeName.startsWith("[")) {
1.229 - typeName = "[" + typeName;
1.230 - } else {
1.231 - typeName = "[L" + typeName + ";";
1.232 - }
1.233 - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
1.234 - smapper.popI(), smapper.pushA(), typeName);
1.235 + generateANewArray(type, smapper);
1.236 break;
1.237 }
1.238 case opc_multianewarray: {
1.239 int type = readIntArg(byteCodes, i);
1.240 i += 2;
1.241 - String typeName = jc.getClassName(type);
1.242 - int dim = readUByte(byteCodes, ++i);
1.243 - StringBuilder dims = new StringBuilder();
1.244 - dims.append('[');
1.245 - for (int d = 0; d < dim; d++) {
1.246 - if (d != 0) {
1.247 - dims.insert(1, ",");
1.248 - }
1.249 - dims.insert(1, smapper.popI());
1.250 - }
1.251 - dims.append(']');
1.252 - emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
1.253 - dims.toString(), smapper.pushA(), typeName);
1.254 + i = generateMultiANewArray(type, byteCodes, i, smapper);
1.255 break;
1.256 }
1.257 case opc_arraylength:
1.258 @@ -1265,32 +1218,13 @@
1.259 }
1.260 case opc_checkcast: {
1.261 int indx = readIntArg(byteCodes, i);
1.262 - final String type = jc.getClassName(indx);
1.263 - if (!type.startsWith("[")) {
1.264 - emit(out,
1.265 - "if (@1 !== null && !@1.$instOf_@2) throw {};",
1.266 - smapper.getA(0), type.replace('/', '_'));
1.267 - } else {
1.268 - emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);",
1.269 - smapper.getA(0), type
1.270 - );
1.271 - }
1.272 + generateCheckcast(indx, smapper);
1.273 i += 2;
1.274 break;
1.275 }
1.276 case opc_instanceof: {
1.277 int indx = readIntArg(byteCodes, i);
1.278 - final String type = jc.getClassName(indx);
1.279 - if (!type.startsWith("[")) {
1.280 - emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;",
1.281 - smapper.popA(), smapper.pushI(),
1.282 - type.replace('/', '_'));
1.283 - } else {
1.284 - emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);",
1.285 - smapper.popA(), smapper.pushI(),
1.286 - type
1.287 - );
1.288 - }
1.289 + generateInstanceOf(indx, smapper);
1.290 i += 2;
1.291 break;
1.292 }
1.293 @@ -1326,32 +1260,29 @@
1.294 }
1.295 }
1.296 if (debug(" //")) {
1.297 - for (int j = prev; j <= i; j++) {
1.298 - out.append(" ");
1.299 - final int cc = readUByte(byteCodes, j);
1.300 - out.append(Integer.toString(cc));
1.301 - }
1.302 + generateByteCodeComment(prev, i, byteCodes);
1.303 }
1.304 out.append("\n");
1.305 }
1.306 if (previousTrap != null) {
1.307 - generateCatch(previousTrap);
1.308 + generateCatch(previousTrap, byteCodes.length, topMostLabel);
1.309 }
1.310 - out.append(" }\n");
1.311 - out.append("};");
1.312 + out.append("\n }\n");
1.313 + while (openBraces-- > 0) {
1.314 + out.append('}');
1.315 + }
1.316 + out.append("\n};");
1.317 }
1.318
1.319 - private int generateIf(byte[] byteCodes, int i,
1.320 - final Variable v2, final Variable v1,
1.321 - final String test) throws IOException {
1.322 + private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException {
1.323 int indx = i + readIntArg(byteCodes, i);
1.324 out.append("if (").append(v1)
1.325 .append(' ').append(test).append(' ')
1.326 - .append(v2).append(") { gt = " + indx)
1.327 - .append("; continue; }");
1.328 + .append(v2).append(") ");
1.329 + goTo(out, i, indx, topMostLabel);
1.330 return i + 2;
1.331 }
1.332 -
1.333 +
1.334 private int readIntArg(byte[] byteCodes, int offsetInstruction) {
1.335 final int indxHi = byteCodes[offsetInstruction + 1] << 8;
1.336 final int indxLo = byteCodes[offsetInstruction + 2];
1.337 @@ -1823,7 +1754,7 @@
1.338 out.append(format, processed, length);
1.339 }
1.340
1.341 - private void generateCatch(TrapData[] traps) throws IOException {
1.342 + private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException {
1.343 out.append("} catch (e) {\n");
1.344 int finallyPC = -1;
1.345 for (TrapData e : traps) {
1.346 @@ -1840,10 +1771,11 @@
1.347 out.append(" var stA0 = vm.java_lang_Throwable(true);");
1.348 out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());");
1.349 out.append("}");
1.350 - out.append("gt=" + e.handler_pc + "; continue;");
1.351 + goTo(out, current, e.handler_pc, topMostLabel);
1.352 } else {
1.353 out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
1.354 - out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;");
1.355 + out.append("var stA0 = e;");
1.356 + goTo(out, current, e.handler_pc, topMostLabel);
1.357 out.append("}\n");
1.358 }
1.359 } else {
1.360 @@ -1853,8 +1785,152 @@
1.361 if (finallyPC == -1) {
1.362 out.append("throw e;");
1.363 } else {
1.364 - out.append("gt=" + finallyPC + "; var stA0 = e; continue;");
1.365 + out.append("var stA0 = e;");
1.366 + goTo(out, current, finallyPC, topMostLabel);
1.367 }
1.368 out.append("\n}");
1.369 }
1.370 +
1.371 + private static void goTo(Appendable out, int current, int to, int canBack) throws IOException {
1.372 + if (to < current) {
1.373 + if (canBack < to) {
1.374 + out.append("{ gt = 0; continue X_" + to + "; }");
1.375 + } else {
1.376 + out.append("{ gt = " + to + "; continue X_0; }");
1.377 + }
1.378 + } else {
1.379 + out.append("{ gt = " + to + "; break IF; }");
1.380 + }
1.381 + }
1.382 +
1.383 + private static void emitIf(
1.384 + Appendable out, String pattern, Variable param,
1.385 + int current, int to, int canBack
1.386 + ) throws IOException {
1.387 + emit(out, pattern, param);
1.388 + goTo(out, current, to, canBack);
1.389 + }
1.390 +
1.391 + private void generateNewArray(int atype, final StackMapper smapper) throws IOException, IllegalStateException {
1.392 + String jvmType;
1.393 + switch (atype) {
1.394 + case 4: jvmType = "[Z"; break;
1.395 + case 5: jvmType = "[C"; break;
1.396 + case 6: jvmType = "[F"; break;
1.397 + case 7: jvmType = "[D"; break;
1.398 + case 8: jvmType = "[B"; break;
1.399 + case 9: jvmType = "[S"; break;
1.400 + case 10: jvmType = "[I"; break;
1.401 + case 11: jvmType = "[J"; break;
1.402 + default: throw new IllegalStateException("Array type: " + atype);
1.403 + }
1.404 + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
1.405 + smapper.popI(), smapper.pushA(), jvmType);
1.406 + }
1.407 +
1.408 + private void generateANewArray(int type, final StackMapper smapper) throws IOException {
1.409 + String typeName = jc.getClassName(type);
1.410 + if (typeName.startsWith("[")) {
1.411 + typeName = "[" + typeName;
1.412 + } else {
1.413 + typeName = "[L" + typeName + ";";
1.414 + }
1.415 + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
1.416 + smapper.popI(), smapper.pushA(), typeName);
1.417 + }
1.418 +
1.419 + private int generateMultiANewArray(int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException {
1.420 + String typeName = jc.getClassName(type);
1.421 + int dim = readUByte(byteCodes, ++i);
1.422 + StringBuilder dims = new StringBuilder();
1.423 + dims.append('[');
1.424 + for (int d = 0; d < dim; d++) {
1.425 + if (d != 0) {
1.426 + dims.insert(1, ",");
1.427 + }
1.428 + dims.insert(1, smapper.popI());
1.429 + }
1.430 + dims.append(']');
1.431 + emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
1.432 + dims.toString(), smapper.pushA(), typeName);
1.433 + return i;
1.434 + }
1.435 +
1.436 + private int generateTableSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException {
1.437 + int table = i / 4 * 4 + 4;
1.438 + int dflt = i + readInt4(byteCodes, table);
1.439 + table += 4;
1.440 + int low = readInt4(byteCodes, table);
1.441 + table += 4;
1.442 + int high = readInt4(byteCodes, table);
1.443 + table += 4;
1.444 + out.append("switch (").append(smapper.popI()).append(") {\n");
1.445 + while (low <= high) {
1.446 + int offset = i + readInt4(byteCodes, table);
1.447 + table += 4;
1.448 + out.append(" case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n');
1.449 + low++;
1.450 + }
1.451 + out.append(" default: ");
1.452 + goTo(out, i, dflt, topMostLabel);
1.453 + out.append("\n}");
1.454 + i = table - 1;
1.455 + return i;
1.456 + }
1.457 +
1.458 + private int generateLookupSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException {
1.459 + int table = i / 4 * 4 + 4;
1.460 + int dflt = i + readInt4(byteCodes, table);
1.461 + table += 4;
1.462 + int n = readInt4(byteCodes, table);
1.463 + table += 4;
1.464 + out.append("switch (").append(smapper.popI()).append(") {\n");
1.465 + while (n-- > 0) {
1.466 + int cnstnt = readInt4(byteCodes, table);
1.467 + table += 4;
1.468 + int offset = i + readInt4(byteCodes, table);
1.469 + table += 4;
1.470 + out.append(" case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n');
1.471 + }
1.472 + out.append(" default: ");
1.473 + goTo(out, i, dflt, topMostLabel);
1.474 + out.append("\n}");
1.475 + i = table - 1;
1.476 + return i;
1.477 + }
1.478 +
1.479 + private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException {
1.480 + final String type = jc.getClassName(indx);
1.481 + if (!type.startsWith("[")) {
1.482 + emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;",
1.483 + smapper.popA(), smapper.pushI(),
1.484 + type.replace('/', '_'));
1.485 + } else {
1.486 + emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);",
1.487 + smapper.popA(), smapper.pushI(),
1.488 + type
1.489 + );
1.490 + }
1.491 + }
1.492 +
1.493 + private void generateCheckcast(int indx, final StackMapper smapper) throws IOException {
1.494 + final String type = jc.getClassName(indx);
1.495 + if (!type.startsWith("[")) {
1.496 + emit(out,
1.497 + "if (@1 !== null && !@1.$instOf_@2) throw {};",
1.498 + smapper.getA(0), type.replace('/', '_'));
1.499 + } else {
1.500 + emit(out, "vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@2').cast__Ljava_lang_Object_2Ljava_lang_Object_2(@1);",
1.501 + smapper.getA(0), type
1.502 + );
1.503 + }
1.504 + }
1.505 +
1.506 + private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException {
1.507 + for (int j = prev; j <= i; j++) {
1.508 + out.append(" ");
1.509 + final int cc = readUByte(byteCodes, j);
1.510 + out.append(Integer.toString(cc));
1.511 + }
1.512 + }
1.513 }