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.
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 12 Mar 2013 09:25:08 +0100
changeset 8392838bc348caf
parent 838 5141f3baf9f0
child 840 5efe49aeaf99
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.
rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
     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  }