Replacing for/switch flow control with multiple labeled for loops allowing fast jump back and if blocks for relatively cheap fall through. Local measurements on chrome indicate 30% speedup in the matrix multiplication benchmark.
1.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Mar 11 20:53:18 2013 +0100
1.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Tue Mar 12 09:25:08 2013 +0100
1.3 @@ -281,22 +281,28 @@
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 for (int i = 0; i < byteCodes.length; i++) {
1.11 int prev = i;
1.12 stackMapIterator.advanceTo(i);
1.13 boolean changeInCatch = trap.advanceTo(i);
1.14 if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
1.15 if (previousTrap != null) {
1.16 - generateCatch(previousTrap);
1.17 + generateCatch(previousTrap, i);
1.18 previousTrap = null;
1.19 }
1.20 }
1.21 if (lastStackFrame != stackMapIterator.getFrameIndex()) {
1.22 + if (i != 0) {
1.23 + out.append(" }\n");
1.24 + }
1.25 +
1.26 lastStackFrame = stackMapIterator.getFrameIndex();
1.27 lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
1.28 smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
1.29 - out.append(" case " + i).append(": ");
1.30 + out.append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
1.31 + openBraces++;
1.32 changeInCatch = true;
1.33 } else {
1.34 debug(" /* " + i + " */ ");
1.35 @@ -811,57 +817,57 @@
1.36 break;
1.37 case opc_ifeq: {
1.38 int indx = i + readIntArg(byteCodes, i);
1.39 - emit(out, "if (@1 == 0) { gt = @2; continue; }",
1.40 - smapper.popI(), Integer.toString(indx));
1.41 + emitIf(out, "if (@1 == 0) ",
1.42 + smapper.popI(), i, indx);
1.43 i += 2;
1.44 break;
1.45 }
1.46 case opc_ifne: {
1.47 int indx = i + readIntArg(byteCodes, i);
1.48 - emit(out, "if (@1 != 0) { gt = @2; continue; }",
1.49 - smapper.popI(), Integer.toString(indx));
1.50 + emitIf(out, "if (@1 != 0) ",
1.51 + smapper.popI(), i, indx);
1.52 i += 2;
1.53 break;
1.54 }
1.55 case opc_iflt: {
1.56 int indx = i + readIntArg(byteCodes, i);
1.57 - emit(out, "if (@1 < 0) { gt = @2; continue; }",
1.58 - smapper.popI(), Integer.toString(indx));
1.59 + emitIf(out, "if (@1 < 0) ",
1.60 + smapper.popI(), i, indx);
1.61 i += 2;
1.62 break;
1.63 }
1.64 case opc_ifle: {
1.65 int indx = i + readIntArg(byteCodes, i);
1.66 - emit(out, "if (@1 <= 0) { gt = @2; continue; }",
1.67 - smapper.popI(), Integer.toString(indx));
1.68 + emitIf(out, "if (@1 <= 0) ",
1.69 + smapper.popI(), i, indx);
1.70 i += 2;
1.71 break;
1.72 }
1.73 case opc_ifgt: {
1.74 int indx = i + readIntArg(byteCodes, i);
1.75 - emit(out, "if (@1 > 0) { gt = @2; continue; }",
1.76 - smapper.popI(), Integer.toString(indx));
1.77 + emitIf(out, "if (@1 > 0) ",
1.78 + smapper.popI(), i, indx);
1.79 i += 2;
1.80 break;
1.81 }
1.82 case opc_ifge: {
1.83 int indx = i + readIntArg(byteCodes, i);
1.84 - emit(out, "if (@1 >= 0) { gt = @2; continue; }",
1.85 - smapper.popI(), Integer.toString(indx));
1.86 + emitIf(out, "if (@1 >= 0) ",
1.87 + smapper.popI(), i, indx);
1.88 i += 2;
1.89 break;
1.90 }
1.91 case opc_ifnonnull: {
1.92 int indx = i + readIntArg(byteCodes, i);
1.93 - emit(out, "if (@1 !== null) { gt = @2; continue; }",
1.94 - smapper.popA(), Integer.toString(indx));
1.95 + emitIf(out, "if (@1 !== null) ",
1.96 + smapper.popA(), i, indx);
1.97 i += 2;
1.98 break;
1.99 }
1.100 case opc_ifnull: {
1.101 int indx = i + readIntArg(byteCodes, i);
1.102 - emit(out, "if (@1 === null) { gt = @2; continue; }",
1.103 - smapper.popA(), Integer.toString(indx));
1.104 + emitIf(out, "if (@1 === null) ",
1.105 + smapper.popA(), i, indx);
1.106 i += 2;
1.107 break;
1.108 }
1.109 @@ -887,7 +893,7 @@
1.110 break;
1.111 case opc_goto: {
1.112 int indx = i + readIntArg(byteCodes, i);
1.113 - emit(out, "gt = @1; continue;", Integer.toString(indx));
1.114 + goTo(out, i, indx);
1.115 i += 2;
1.116 break;
1.117 }
1.118 @@ -903,9 +909,9 @@
1.119 table += 4;
1.120 int offset = i + readInt4(byteCodes, table);
1.121 table += 4;
1.122 - out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n");
1.123 + out.append(" case " + cnstnt).append(": "); goTo(out, i, offset); out.append('\n');
1.124 }
1.125 - out.append(" default: gt = " + dflt).append("; continue;\n}");
1.126 + out.append(" default: "); goTo(out, i, dflt); out.append("\n}");
1.127 i = table - 1;
1.128 break;
1.129 }
1.130 @@ -921,10 +927,10 @@
1.131 while (low <= high) {
1.132 int offset = i + readInt4(byteCodes, table);
1.133 table += 4;
1.134 - out.append(" case " + low).append(": gt = " + offset).append("; continue;\n");
1.135 + out.append(" case " + low).append(":"); goTo(out, i, offset); out.append('\n');
1.136 low++;
1.137 }
1.138 - out.append(" default: gt = " + dflt).append("; continue;\n}");
1.139 + out.append(" default: "); goTo(out, i, dflt); out.append("\n}");
1.140 i = table - 1;
1.141 break;
1.142 }
1.143 @@ -1333,10 +1339,13 @@
1.144 out.append("\n");
1.145 }
1.146 if (previousTrap != null) {
1.147 - generateCatch(previousTrap);
1.148 + generateCatch(previousTrap, byteCodes.length);
1.149 }
1.150 - out.append(" }\n");
1.151 - out.append("};");
1.152 + out.append("\n }\n");
1.153 + while (openBraces-- > 0) {
1.154 + out.append('}');
1.155 + }
1.156 + out.append("\n};");
1.157 }
1.158
1.159 private int generateIf(byte[] byteCodes, int i,
1.160 @@ -1345,11 +1354,11 @@
1.161 int indx = i + readIntArg(byteCodes, i);
1.162 out.append("if (").append(v1)
1.163 .append(' ').append(test).append(' ')
1.164 - .append(v2).append(") { gt = " + indx)
1.165 - .append("; continue; }");
1.166 + .append(v2).append(") ");
1.167 + goTo(out, i, indx);
1.168 return i + 2;
1.169 }
1.170 -
1.171 +
1.172 private int readIntArg(byte[] byteCodes, int offsetInstruction) {
1.173 final int indxHi = byteCodes[offsetInstruction + 1] << 8;
1.174 final int indxLo = byteCodes[offsetInstruction + 2];
1.175 @@ -1821,7 +1830,7 @@
1.176 out.append(format, processed, length);
1.177 }
1.178
1.179 - private void generateCatch(TrapData[] traps) throws IOException {
1.180 + private void generateCatch(TrapData[] traps, int current) throws IOException {
1.181 out.append("} catch (e) {\n");
1.182 int finallyPC = -1;
1.183 for (TrapData e : traps) {
1.184 @@ -1838,10 +1847,11 @@
1.185 out.append(" var stA0 = vm.java_lang_Throwable(true);");
1.186 out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());");
1.187 out.append("}");
1.188 - out.append("gt=" + e.handler_pc + "; continue;");
1.189 + goTo(out, current, e.handler_pc);
1.190 } else {
1.191 out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
1.192 - out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;");
1.193 + out.append("var stA0 = e;");
1.194 + goTo(out, current, e.handler_pc);
1.195 out.append("}\n");
1.196 }
1.197 } else {
1.198 @@ -1851,8 +1861,22 @@
1.199 if (finallyPC == -1) {
1.200 out.append("throw e;");
1.201 } else {
1.202 - out.append("gt=" + finallyPC + "; var stA0 = e; continue;");
1.203 + out.append("var stA0 = e;");
1.204 + goTo(out, current, finallyPC);
1.205 }
1.206 out.append("\n}");
1.207 }
1.208 +
1.209 + private static void goTo(Appendable out, int current, int to) throws IOException {
1.210 + if (to < current) {
1.211 + out.append("{ gt = 0; continue X_" + to + "; }");
1.212 + } else {
1.213 + out.append("{ gt = " + to + "; break IF; }");
1.214 + }
1.215 + }
1.216 +
1.217 + private static void emitIf(Appendable out, String pattern, Variable param, int current, int to) throws IOException {
1.218 + emit(out, pattern, param);
1.219 + goTo(out, current, to);
1.220 + }
1.221 }