Merge with trunk closure
authorLubomir Nerad <lubomir.nerad@oracle.com>
Tue, 19 Mar 2013 13:18:02 +0100
branchclosure
changeset 861f41a1fef7738
parent 860 35507d1a5069
parent 847 094e10a97511
child 863 eba8fd2ff535
Merge with trunk
rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java
rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
     1.1 --- a/benchmarks/matrix-multiplication/pom.xml	Tue Mar 19 13:08:44 2013 +0100
     1.2 +++ b/benchmarks/matrix-multiplication/pom.xml	Tue Mar 19 13:18:02 2013 +0100
     1.3 @@ -37,6 +37,36 @@
     1.4                    <skip>true</skip>
     1.5                </configuration>
     1.6            </plugin>      
     1.7 +          <plugin>
     1.8 +              <groupId>org.codehaus.mojo</groupId>
     1.9 +              <artifactId>xml-maven-plugin</artifactId>
    1.10 +              <version>1.0</version>
    1.11 +              <executions>
    1.12 +                  <execution>
    1.13 +                      <goals>
    1.14 +                          <goal>transform</goal>
    1.15 +                      </goals>
    1.16 +                      <phase>install</phase>
    1.17 +                  </execution>
    1.18 +              </executions>
    1.19 +              <configuration>
    1.20 +                  <transformationSets>
    1.21 +                      <transformationSet>
    1.22 +                          <dir>target/surefire-reports</dir>
    1.23 +                          <outputDir>target/surefire-reports</outputDir>
    1.24 +                          <includes>
    1.25 +                              <include>TEST*.xml</include>
    1.26 +                          </includes>
    1.27 +                          <stylesheet>src/main/select-time.xsl</stylesheet>
    1.28 +                          <fileMappers>
    1.29 +                              <fileMapper implementation="org.codehaus.plexus.components.io.filemappers.FileExtensionMapper">
    1.30 +                                  <targetExtension>.csv</targetExtension>
    1.31 +                              </fileMapper>
    1.32 +                          </fileMappers>                          
    1.33 +                      </transformationSet>
    1.34 +                  </transformationSets>
    1.35 +              </configuration>
    1.36 +          </plugin>
    1.37        </plugins>
    1.38    </build>
    1.39    
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/benchmarks/matrix-multiplication/src/main/select-time.xsl	Tue Mar 19 13:18:02 2013 +0100
     2.3 @@ -0,0 +1,55 @@
     2.4 +<?xml version="1.0" encoding="UTF-8"?>
     2.5 +<!--
     2.6 +
     2.7 +    Back 2 Browser Bytecode Translator
     2.8 +    Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     2.9 +
    2.10 +    This program is free software: you can redistribute it and/or modify
    2.11 +    it under the terms of the GNU General Public License as published by
    2.12 +    the Free Software Foundation, version 2 of the License.
    2.13 +
    2.14 +    This program is distributed in the hope that it will be useful,
    2.15 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.16 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.17 +    GNU General Public License for more details.
    2.18 +
    2.19 +    You should have received a copy of the GNU General Public License
    2.20 +    along with this program. Look for COPYING file in the top folder.
    2.21 +    If not, see http://opensource.org/licenses/GPL-2.0.
    2.22 +
    2.23 +-->
    2.24 +
    2.25 +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    2.26 +    <xsl:output method="text"/>
    2.27 +
    2.28 +    <xsl:template match="/">
    2.29 +        <xsl:apply-templates mode="header" select="testsuite/testcase"/><xsl:text>End
    2.30 +</xsl:text>
    2.31 +        <xsl:apply-templates mode="value" select="testsuite/testcase"/><xsl:text>NaN
    2.32 +</xsl:text>
    2.33 +    </xsl:template>
    2.34 +        
    2.35 +    
    2.36 +    <xsl:template match="testcase" mode="header">
    2.37 +      <xsl:if test="contains(@name,'tenThousand')">
    2.38 +        <xsl:if test="not(contains(@name, '[Java]'))">
    2.39 +          <xsl:if test="not(contains(@name, '[Compare'))">
    2.40 +              <xsl:value-of select="@name"/>
    2.41 +              <xsl:text>,</xsl:text>
    2.42 +          </xsl:if>
    2.43 +        </xsl:if>
    2.44 +      </xsl:if>
    2.45 +    </xsl:template>
    2.46 +
    2.47 +    <xsl:template match="testcase" mode="value">
    2.48 +      <xsl:if test="contains(@name,'tenThousand')">
    2.49 +        <xsl:if test="not(contains(@name, '[Java]'))">
    2.50 +          <xsl:if test="not(contains(@name, '[Compare'))">
    2.51 +            <xsl:value-of select="@time"/>
    2.52 +            <xsl:text>,</xsl:text>
    2.53 +          </xsl:if>
    2.54 +        </xsl:if>
    2.55 +      </xsl:if>
    2.56 +    </xsl:template>
    2.57 +
    2.58 +</xsl:stylesheet>
     3.1 --- a/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java	Tue Mar 19 13:08:44 2013 +0100
     3.2 +++ b/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java	Tue Mar 19 13:18:02 2013 +0100
     3.3 @@ -31,6 +31,22 @@
     3.4      }
     3.5  
     3.6      @Compare(scripting = false) 
     3.7 +    public String oneIteration() throws IOException {
     3.8 +    
     3.9 +        Matrix m1 = new Matrix(5);
    3.10 +        Matrix m2 = new Matrix(5);
    3.11 +        
    3.12 +        m1.generateData();
    3.13 +        m2.generateData();
    3.14 +        
    3.15 +        Matrix res = m1.multiply(m2);
    3.16 +        
    3.17 +        StringBuilder sb = new StringBuilder();
    3.18 +        res.printOn(sb);
    3.19 +        return sb.toString();
    3.20 +    }
    3.21 +    
    3.22 +    @Compare(scripting = false) 
    3.23      public String tenThousandIterations() throws IOException {
    3.24      
    3.25          Matrix m1 = new Matrix(5);
    3.26 @@ -50,6 +66,27 @@
    3.27          return sb.toString();
    3.28      }
    3.29      
    3.30 +    @Compare(scripting = false) 
    3.31 +    public String tenUselessIterations() throws IOException {
    3.32 +    
    3.33 +        Matrix m1 = new Matrix(5);
    3.34 +        Matrix m2 = new Matrix(5);
    3.35 +        
    3.36 +        m1.generateData();
    3.37 +        m2.generateData();
    3.38 +        
    3.39 +        Matrix res = null;
    3.40 +        for (int i = 0; i < 10; i++) {
    3.41 +            res = m1.multiply(m2);
    3.42 +            m1 = res;
    3.43 +        }
    3.44 +        
    3.45 +        StringBuilder sb = new StringBuilder();
    3.46 +        res.printOn(sb);
    3.47 +        return sb.toString();
    3.48 +    }
    3.49 +
    3.50 +    
    3.51      @Factory
    3.52      public static Object[] create() {
    3.53          return VMTest.create(MatrixTest.class);
     4.1 --- a/javaquery/demo-calculator-dynamic/nbactions.xml	Tue Mar 19 13:08:44 2013 +0100
     4.2 +++ b/javaquery/demo-calculator-dynamic/nbactions.xml	Tue Mar 19 13:18:02 2013 +0100
     4.3 @@ -23,7 +23,7 @@
     4.4              <actionName>run</actionName>
     4.5              <goals>
     4.6                  <goal>process-classes</goal>
     4.7 -                <goal>org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr</goal>
     4.8 +                <goal>org.apidesign.bck2brwsr:mojo:0.5-SNAPSHOT:brwsr</goal>
     4.9              </goals>
    4.10          </action>
    4.11      </actions>
     5.1 --- a/javaquery/demo-calculator/nbactions.xml	Tue Mar 19 13:08:44 2013 +0100
     5.2 +++ b/javaquery/demo-calculator/nbactions.xml	Tue Mar 19 13:18:02 2013 +0100
     5.3 @@ -23,7 +23,7 @@
     5.4              <actionName>run</actionName>
     5.5              <goals>
     5.6                  <goal>package</goal>
     5.7 -                <goal>org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr</goal>
     5.8 +                <goal>org.apidesign.bck2brwsr:mojo:0.5-SNAPSHOT:brwsr</goal>
     5.9              </goals>
    5.10              <properties>
    5.11                  <skipTests>true</skipTests>
     6.1 --- a/javaquery/demo-calculator/pom.xml	Tue Mar 19 13:08:44 2013 +0100
     6.2 +++ b/javaquery/demo-calculator/pom.xml	Tue Mar 19 13:18:02 2013 +0100
     6.3 @@ -22,6 +22,7 @@
     6.4                  <executions>
     6.5                      <execution>
     6.6                          <goals>
     6.7 +                            <goal>j2js</goal>
     6.8                              <goal>brwsr</goal>
     6.9                          </goals>
    6.10                      </execution>
    6.11 @@ -29,6 +30,7 @@
    6.12                  <configuration>
    6.13                      <directory>${project.build.directory}/${project.build.finalName}-bck2brwsr/public_html/</directory>
    6.14                      <startpage>index.xhtml</startpage>
    6.15 +                    <javascript>${project.build.directory}/bck2brwsr.js</javascript>
    6.16                  </configuration>
    6.17              </plugin>
    6.18           <plugin>
    6.19 @@ -102,13 +104,5 @@
    6.20        <artifactId>javaquery.api</artifactId>
    6.21        <version>0.5-SNAPSHOT</version>
    6.22      </dependency>
    6.23 -    <dependency>
    6.24 -      <groupId>org.apidesign.bck2brwsr</groupId>
    6.25 -      <artifactId>vm4brwsr</artifactId>
    6.26 -      <classifier>js</classifier>
    6.27 -      <type>zip</type>
    6.28 -      <version>0.5-SNAPSHOT</version>
    6.29 -      <scope>provided</scope>
    6.30 -    </dependency>
    6.31    </dependencies>
    6.32  </project>
     7.1 --- a/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml	Tue Mar 19 13:08:44 2013 +0100
     7.2 +++ b/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml	Tue Mar 19 13:18:02 2013 +0100
     7.3 @@ -37,15 +37,6 @@
     7.4              <include>*:rt</include>
     7.5          </includes>
     7.6      </dependencySet>
     7.7 -    <dependencySet>
     7.8 -        <useProjectArtifact>false</useProjectArtifact>
     7.9 -        <scope>provided</scope>
    7.10 -        <includes>
    7.11 -            <include>*:js</include>
    7.12 -        </includes>
    7.13 -        <unpack>true</unpack>
    7.14 -        <outputDirectory>/</outputDirectory>
    7.15 -    </dependencySet>
    7.16    </dependencySets> 
    7.17    <files>
    7.18      <file>
    7.19 @@ -53,6 +44,10 @@
    7.20        <outputDirectory>/</outputDirectory>
    7.21      </file>
    7.22      <file>
    7.23 +      <source>${project.build.directory}/bck2brwsr.js</source>
    7.24 +      <outputDirectory>/</outputDirectory>
    7.25 +    </file>
    7.26 +    <file>
    7.27        <source>${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml</source>
    7.28        <outputDirectory>/</outputDirectory>
    7.29        <destName>index.xhtml</destName>
     8.1 --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java	Tue Mar 19 13:08:44 2013 +0100
     8.2 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java	Tue Mar 19 13:18:02 2013 +0100
     8.3 @@ -45,11 +45,17 @@
     8.4      /** Root of the class files */
     8.5      @Parameter(defaultValue="${project.build.directory}/classes")
     8.6      private File classes;
     8.7 -    /** File to generate. Defaults bootjava.js in the first non-empty 
     8.8 -     package under the classes directory */
     8.9 +    /** JavaScript file to generate */
    8.10      @Parameter
    8.11      private File javascript;
    8.12  
    8.13 +    /** Additional classes that should be pre-compiled into the javascript 
    8.14 +     * file. By default compiles all classes found under <code>classes</code>
    8.15 +     * directory and their transitive closure.
    8.16 +     */
    8.17 +    @Parameter
    8.18 +    private List<String> compileclasses;
    8.19 +    
    8.20      @Parameter(defaultValue="${project}")
    8.21      private MavenProject prj;
    8.22  
    8.23 @@ -67,13 +73,14 @@
    8.24              throw new MojoExecutionException("Can't find " + classes);
    8.25          }
    8.26  
    8.27 -        if (javascript == null) {
    8.28 -            javascript = new File(findNonEmptyFolder(classes), "bootjava.js");
    8.29 -        }
    8.30 -
    8.31          List<String> arr = new ArrayList<String>();
    8.32          long newest = collectAllClasses("", classes, arr);
    8.33          
    8.34 +        if (compileclasses != null) {
    8.35 +            arr.retainAll(compileclasses);
    8.36 +            arr.addAll(compileclasses);
    8.37 +        }
    8.38 +        
    8.39          if (javascript.lastModified() > newest) {
    8.40              return;
    8.41          }
    8.42 @@ -88,17 +95,6 @@
    8.43          }
    8.44      }
    8.45  
    8.46 -    private static File findNonEmptyFolder(File dir) throws MojoExecutionException {
    8.47 -        if (!dir.isDirectory()) {
    8.48 -            throw new MojoExecutionException("Not a directory " + dir);
    8.49 -        }
    8.50 -        File[] arr = dir.listFiles();
    8.51 -        if (arr.length == 1 && arr[0].isDirectory()) {
    8.52 -            return findNonEmptyFolder(arr[0]);
    8.53 -        }
    8.54 -        return dir;
    8.55 -    }
    8.56 -
    8.57      private static long collectAllClasses(String prefix, File toCheck, List<String> arr) {
    8.58          File[] files = toCheck.listFiles();
    8.59          if (files != null) {
    8.60 @@ -111,7 +107,8 @@
    8.61              }
    8.62              return newest;
    8.63          } else if (toCheck.getName().endsWith(".class")) {
    8.64 -            arr.add(prefix.substring(0, prefix.length() - 7));
    8.65 +            final String cls = prefix.substring(0, prefix.length() - 7);
    8.66 +            arr.add(cls);
    8.67              return toCheck.lastModified();
    8.68          } else {
    8.69              return 0L;
    8.70 @@ -122,7 +119,9 @@
    8.71          List<URL> arr = new ArrayList<URL>();
    8.72          arr.add(root.toURI().toURL());
    8.73          for (Artifact a : deps) {
    8.74 -            arr.add(a.getFile().toURI().toURL());
    8.75 +            if (a.getFile() != null) {
    8.76 +                arr.add(a.getFile().toURI().toURL());
    8.77 +            }
    8.78          }
    8.79          return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader());
    8.80      }
     9.1 --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Tue Mar 19 13:08:44 2013 +0100
     9.2 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Tue Mar 19 13:18:02 2013 +0100
     9.3 @@ -283,22 +283,36 @@
     9.4          TrapData[] previousTrap = null;
     9.5          boolean wide = false;
     9.6          
     9.7 -        out.append("\n  var gt = 0;\n  for(;;) switch(gt) {\n");
     9.8 +        out.append("\n  var gt = 0;\n");
     9.9 +        int openBraces = 0;
    9.10 +        int topMostLabel = 0;
    9.11          for (int i = 0; i < byteCodes.length; i++) {
    9.12              int prev = i;
    9.13              stackMapIterator.advanceTo(i);
    9.14              boolean changeInCatch = trap.advanceTo(i);
    9.15              if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) {
    9.16                  if (previousTrap != null) {
    9.17 -                    generateCatch(previousTrap);
    9.18 +                    generateCatch(previousTrap, i, topMostLabel);
    9.19                      previousTrap = null;
    9.20                  }
    9.21              }
    9.22              if (lastStackFrame != stackMapIterator.getFrameIndex()) {
    9.23 +                if (i != 0) {
    9.24 +                    out.append("    }\n");
    9.25 +                }
    9.26 +                if (openBraces > 64) {
    9.27 +                    for (int c = 0; c < 64; c++) {
    9.28 +                        out.append("break;}\n");
    9.29 +                    }
    9.30 +                    openBraces = 1;
    9.31 +                    topMostLabel = i;
    9.32 +                }
    9.33 +                
    9.34                  lastStackFrame = stackMapIterator.getFrameIndex();
    9.35                  lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals());
    9.36                  smapper.syncWithFrameStack(stackMapIterator.getFrameStack());
    9.37 -                out.append("    case " + i).append(": ");            
    9.38 +                out.append("    X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n");
    9.39 +                openBraces++;
    9.40                  changeInCatch = true;
    9.41              } else {
    9.42                  debug("    /* " + i + " */ ");
    9.43 @@ -801,133 +815,104 @@
    9.44                      break;
    9.45                  case opc_if_acmpeq:
    9.46                      i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
    9.47 -                                   "===");
    9.48 +                                   "===", topMostLabel);
    9.49                      break;
    9.50                  case opc_if_acmpne:
    9.51                      i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(),
    9.52 -                                   "!==");
    9.53 +                                   "!==", topMostLabel);
    9.54                      break;
    9.55                  case opc_if_icmpeq:
    9.56                      i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
    9.57 -                                   "==");
    9.58 +                                   "==", topMostLabel);
    9.59                      break;
    9.60                  case opc_ifeq: {
    9.61                      int indx = i + readIntArg(byteCodes, i);
    9.62 -                    emit(out, "if (@1 == 0) { gt = @2; continue; }",
    9.63 -                         smapper.popI(), Integer.toString(indx));
    9.64 +                    emitIf(out, "if (@1 == 0) ",
    9.65 +                         smapper.popI(), i, indx, topMostLabel);
    9.66                      i += 2;
    9.67                      break;
    9.68                  }
    9.69                  case opc_ifne: {
    9.70                      int indx = i + readIntArg(byteCodes, i);
    9.71 -                    emit(out, "if (@1 != 0) { gt = @2; continue; }",
    9.72 -                         smapper.popI(), Integer.toString(indx));
    9.73 +                    emitIf(out, "if (@1 != 0) ",
    9.74 +                         smapper.popI(), i, indx, topMostLabel);
    9.75                      i += 2;
    9.76                      break;
    9.77                  }
    9.78                  case opc_iflt: {
    9.79                      int indx = i + readIntArg(byteCodes, i);
    9.80 -                    emit(out, "if (@1 < 0) { gt = @2; continue; }",
    9.81 -                         smapper.popI(), Integer.toString(indx));
    9.82 +                    emitIf(out, "if (@1 < 0) ",
    9.83 +                         smapper.popI(), i, indx, topMostLabel);
    9.84                      i += 2;
    9.85                      break;
    9.86                  }
    9.87                  case opc_ifle: {
    9.88                      int indx = i + readIntArg(byteCodes, i);
    9.89 -                    emit(out, "if (@1 <= 0) { gt = @2; continue; }",
    9.90 -                         smapper.popI(), Integer.toString(indx));
    9.91 +                    emitIf(out, "if (@1 <= 0) ",
    9.92 +                         smapper.popI(), i, indx, topMostLabel);
    9.93                      i += 2;
    9.94                      break;
    9.95                  }
    9.96                  case opc_ifgt: {
    9.97                      int indx = i + readIntArg(byteCodes, i);
    9.98 -                    emit(out, "if (@1 > 0) { gt = @2; continue; }",
    9.99 -                         smapper.popI(), Integer.toString(indx));
   9.100 +                    emitIf(out, "if (@1 > 0) ",
   9.101 +                         smapper.popI(), i, indx, topMostLabel);
   9.102                      i += 2;
   9.103                      break;
   9.104                  }
   9.105                  case opc_ifge: {
   9.106                      int indx = i + readIntArg(byteCodes, i);
   9.107 -                    emit(out, "if (@1 >= 0) { gt = @2; continue; }",
   9.108 -                         smapper.popI(), Integer.toString(indx));
   9.109 +                    emitIf(out, "if (@1 >= 0) ",
   9.110 +                         smapper.popI(), i, indx, topMostLabel);
   9.111                      i += 2;
   9.112                      break;
   9.113                  }
   9.114                  case opc_ifnonnull: {
   9.115                      int indx = i + readIntArg(byteCodes, i);
   9.116 -                    emit(out, "if (@1 !== null) { gt = @2; continue; }",
   9.117 -                         smapper.popA(), Integer.toString(indx));
   9.118 +                    emitIf(out, "if (@1 !== null) ",
   9.119 +                         smapper.popA(), i, indx, topMostLabel);
   9.120                      i += 2;
   9.121                      break;
   9.122                  }
   9.123                  case opc_ifnull: {
   9.124                      int indx = i + readIntArg(byteCodes, i);
   9.125 -                    emit(out, "if (@1 === null) { gt = @2; continue; }",
   9.126 -                         smapper.popA(), Integer.toString(indx));
   9.127 +                    emitIf(out, "if (@1 === null) ",
   9.128 +                         smapper.popA(), i, indx, topMostLabel);
   9.129                      i += 2;
   9.130                      break;
   9.131                  }
   9.132                  case opc_if_icmpne:
   9.133                      i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
   9.134 -                                   "!=");
   9.135 +                                   "!=", topMostLabel);
   9.136                      break;
   9.137                  case opc_if_icmplt:
   9.138                      i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
   9.139 -                                   "<");
   9.140 +                                   "<", topMostLabel);
   9.141                      break;
   9.142                  case opc_if_icmple:
   9.143                      i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
   9.144 -                                   "<=");
   9.145 +                                   "<=", topMostLabel);
   9.146                      break;
   9.147                  case opc_if_icmpgt:
   9.148                      i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
   9.149 -                                   ">");
   9.150 +                                   ">", topMostLabel);
   9.151                      break;
   9.152                  case opc_if_icmpge:
   9.153                      i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(),
   9.154 -                                   ">=");
   9.155 +                                   ">=", topMostLabel);
   9.156                      break;
   9.157                  case opc_goto: {
   9.158                      int indx = i + readIntArg(byteCodes, i);
   9.159 -                    emit(out, "gt = @1; continue;", Integer.toString(indx));
   9.160 +                    goTo(out, i, indx, topMostLabel);
   9.161                      i += 2;
   9.162                      break;
   9.163                  }
   9.164                  case opc_lookupswitch: {
   9.165 -                    int table = i / 4 * 4 + 4;
   9.166 -                    int dflt = i + readInt4(byteCodes, table);
   9.167 -                    table += 4;
   9.168 -                    int n = readInt4(byteCodes, table);
   9.169 -                    table += 4;
   9.170 -                    out.append("switch (").append(smapper.popI()).append(") {\n");
   9.171 -                    while (n-- > 0) {
   9.172 -                        int cnstnt = readInt4(byteCodes, table);
   9.173 -                        table += 4;
   9.174 -                        int offset = i + readInt4(byteCodes, table);
   9.175 -                        table += 4;
   9.176 -                        out.append("  case " + cnstnt).append(": gt = " + offset).append("; continue;\n");
   9.177 -                    }
   9.178 -                    out.append("  default: gt = " + dflt).append("; continue;\n}");
   9.179 -                    i = table - 1;
   9.180 +                    i = generateLookupSwitch(i, byteCodes, smapper, topMostLabel);
   9.181                      break;
   9.182                  }
   9.183                  case opc_tableswitch: {
   9.184 -                    int table = i / 4 * 4 + 4;
   9.185 -                    int dflt = i + readInt4(byteCodes, table);
   9.186 -                    table += 4;
   9.187 -                    int low = readInt4(byteCodes, table);
   9.188 -                    table += 4;
   9.189 -                    int high = readInt4(byteCodes, table);
   9.190 -                    table += 4;
   9.191 -                    out.append("switch (").append(smapper.popI()).append(") {\n");
   9.192 -                    while (low <= high) {
   9.193 -                        int offset = i + readInt4(byteCodes, table);
   9.194 -                        table += 4;
   9.195 -                        out.append("  case " + low).append(": gt = " + offset).append("; continue;\n");
   9.196 -                        low++;
   9.197 -                    }
   9.198 -                    out.append("  default: gt = " + dflt).append("; continue;\n}");
   9.199 -                    i = table - 1;
   9.200 +                    i = generateTableSwitch(i, byteCodes, smapper, topMostLabel);
   9.201                      break;
   9.202                  }
   9.203                  case opc_invokeinterface: {
   9.204 @@ -954,50 +939,18 @@
   9.205                  }
   9.206                  case opc_newarray:
   9.207                      int atype = readUByte(byteCodes, ++i);
   9.208 -                    String jvmType;
   9.209 -                    switch (atype) {
   9.210 -                        case 4: jvmType = "[Z"; break;
   9.211 -                        case 5: jvmType = "[C"; break;
   9.212 -                        case 6: jvmType = "[F"; break;
   9.213 -                        case 7: jvmType = "[D"; break;
   9.214 -                        case 8: jvmType = "[B"; break;
   9.215 -                        case 9: jvmType = "[S"; break;
   9.216 -                        case 10: jvmType = "[I"; break;
   9.217 -                        case 11: jvmType = "[J"; break;
   9.218 -                        default: throw new IllegalStateException("Array type: " + atype);
   9.219 -                    }
   9.220 -                    emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
   9.221 -                         smapper.popI(), smapper.pushA(), jvmType);
   9.222 +                    generateNewArray(atype, smapper);
   9.223                      break;
   9.224                  case opc_anewarray: {
   9.225                      int type = readIntArg(byteCodes, i);
   9.226                      i += 2;
   9.227 -                    String typeName = jc.getClassName(type);
   9.228 -                    if (typeName.startsWith("[")) {
   9.229 -                        typeName = "[" + typeName;
   9.230 -                    } else {
   9.231 -                        typeName = "[L" + typeName + ";";
   9.232 -                    }
   9.233 -                    emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
   9.234 -                         smapper.popI(), smapper.pushA(), typeName);
   9.235 +                    generateANewArray(type, smapper);
   9.236                      break;
   9.237                  }
   9.238                  case opc_multianewarray: {
   9.239                      int type = readIntArg(byteCodes, i);
   9.240                      i += 2;
   9.241 -                    String typeName = jc.getClassName(type);
   9.242 -                    int dim = readUByte(byteCodes, ++i);
   9.243 -                    StringBuilder dims = new StringBuilder();
   9.244 -                    dims.append('[');
   9.245 -                    for (int d = 0; d < dim; d++) {
   9.246 -                        if (d != 0) {
   9.247 -                            dims.insert(1, ",");
   9.248 -                        }
   9.249 -                        dims.insert(1, smapper.popI());
   9.250 -                    }
   9.251 -                    dims.append(']');
   9.252 -                    emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
   9.253 -                         dims.toString(), smapper.pushA(), typeName);
   9.254 +                    i = generateMultiANewArray(type, byteCodes, i, smapper);
   9.255                      break;
   9.256                  }
   9.257                  case opc_arraylength:
   9.258 @@ -1265,32 +1218,13 @@
   9.259                  }
   9.260                  case opc_checkcast: {
   9.261                      int indx = readIntArg(byteCodes, i);
   9.262 -                    final String type = jc.getClassName(indx);
   9.263 -                    if (!type.startsWith("[")) {
   9.264 -                        emit(out,
   9.265 -                             "if (@1 !== null && !@1.$instOf_@2) throw {};",
   9.266 -                             smapper.getA(0), type.replace('/', '_'));
   9.267 -                    } else {
   9.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);",
   9.269 -                             smapper.getA(0), type
   9.270 -                        );
   9.271 -                    }
   9.272 +                    generateCheckcast(indx, smapper);
   9.273                      i += 2;
   9.274                      break;
   9.275                  }
   9.276                  case opc_instanceof: {
   9.277                      int indx = readIntArg(byteCodes, i);
   9.278 -                    final String type = jc.getClassName(indx);
   9.279 -                    if (!type.startsWith("[")) {
   9.280 -                        emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;",
   9.281 -                             smapper.popA(), smapper.pushI(),
   9.282 -                             type.replace('/', '_'));
   9.283 -                    } else {
   9.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);",
   9.285 -                            smapper.popA(), smapper.pushI(),
   9.286 -                            type
   9.287 -                        );
   9.288 -                    }
   9.289 +                    generateInstanceOf(indx, smapper);
   9.290                      i += 2;
   9.291                      break;
   9.292                  }
   9.293 @@ -1326,32 +1260,29 @@
   9.294                  }
   9.295              }
   9.296              if (debug(" //")) {
   9.297 -                for (int j = prev; j <= i; j++) {
   9.298 -                    out.append(" ");
   9.299 -                    final int cc = readUByte(byteCodes, j);
   9.300 -                    out.append(Integer.toString(cc));
   9.301 -                }
   9.302 +                generateByteCodeComment(prev, i, byteCodes);
   9.303              }
   9.304              out.append("\n");            
   9.305          }
   9.306          if (previousTrap != null) {
   9.307 -            generateCatch(previousTrap);
   9.308 +            generateCatch(previousTrap, byteCodes.length, topMostLabel);
   9.309          }
   9.310 -        out.append("  }\n");
   9.311 -        out.append("};");
   9.312 +        out.append("\n    }\n");
   9.313 +        while (openBraces-- > 0) {
   9.314 +            out.append('}');
   9.315 +        }
   9.316 +        out.append("\n};");
   9.317      }
   9.318  
   9.319 -    private int generateIf(byte[] byteCodes, int i,
   9.320 -                           final Variable v2, final Variable v1,
   9.321 -                           final String test) throws IOException {
   9.322 +    private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException {
   9.323          int indx = i + readIntArg(byteCodes, i);
   9.324          out.append("if (").append(v1)
   9.325             .append(' ').append(test).append(' ')
   9.326 -           .append(v2).append(") { gt = " + indx)
   9.327 -           .append("; continue; }");
   9.328 +           .append(v2).append(") ");
   9.329 +        goTo(out, i, indx, topMostLabel);
   9.330          return i + 2;
   9.331      }
   9.332 -
   9.333 +    
   9.334      private int readIntArg(byte[] byteCodes, int offsetInstruction) {
   9.335          final int indxHi = byteCodes[offsetInstruction + 1] << 8;
   9.336          final int indxLo = byteCodes[offsetInstruction + 2];
   9.337 @@ -1823,7 +1754,7 @@
   9.338          out.append(format, processed, length);
   9.339      }
   9.340  
   9.341 -    private void generateCatch(TrapData[] traps) throws IOException {
   9.342 +    private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException {
   9.343          out.append("} catch (e) {\n");
   9.344          int finallyPC = -1;
   9.345          for (TrapData e : traps) {
   9.346 @@ -1840,10 +1771,11 @@
   9.347                      out.append("  var stA0 = vm.java_lang_Throwable(true);");
   9.348                      out.append("  vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());");
   9.349                      out.append("}");
   9.350 -                    out.append("gt=" + e.handler_pc + "; continue;");
   9.351 +                    goTo(out, current, e.handler_pc, topMostLabel);
   9.352                  } else {
   9.353                      out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {");
   9.354 -                    out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;");
   9.355 +                    out.append("var stA0 = e;");
   9.356 +                    goTo(out, current, e.handler_pc, topMostLabel);
   9.357                      out.append("}\n");
   9.358                  }
   9.359              } else {
   9.360 @@ -1853,8 +1785,152 @@
   9.361          if (finallyPC == -1) {
   9.362              out.append("throw e;");
   9.363          } else {
   9.364 -            out.append("gt=" + finallyPC + "; var stA0 = e; continue;");
   9.365 +            out.append("var stA0 = e;");
   9.366 +            goTo(out, current, finallyPC, topMostLabel);
   9.367          }
   9.368          out.append("\n}");
   9.369      }
   9.370 +
   9.371 +    private static void goTo(Appendable out, int current, int to, int canBack) throws IOException {
   9.372 +        if (to < current) {
   9.373 +            if (canBack < to) {
   9.374 +                out.append("{ gt = 0; continue X_" + to + "; }");
   9.375 +            } else {
   9.376 +                out.append("{ gt = " + to + "; continue X_0; }");
   9.377 +            }
   9.378 +        } else {
   9.379 +            out.append("{ gt = " + to + "; break IF; }");
   9.380 +        }
   9.381 +    }
   9.382 +
   9.383 +    private static void emitIf(
   9.384 +        Appendable out, String pattern, Variable param, 
   9.385 +        int current, int to, int canBack
   9.386 +    ) throws IOException {
   9.387 +        emit(out, pattern, param);
   9.388 +        goTo(out, current, to, canBack);
   9.389 +    }
   9.390 +
   9.391 +    private void generateNewArray(int atype, final StackMapper smapper) throws IOException, IllegalStateException {
   9.392 +        String jvmType;
   9.393 +        switch (atype) {
   9.394 +            case 4: jvmType = "[Z"; break;
   9.395 +            case 5: jvmType = "[C"; break;
   9.396 +            case 6: jvmType = "[F"; break;
   9.397 +            case 7: jvmType = "[D"; break;
   9.398 +            case 8: jvmType = "[B"; break;
   9.399 +            case 9: jvmType = "[S"; break;
   9.400 +            case 10: jvmType = "[I"; break;
   9.401 +            case 11: jvmType = "[J"; break;
   9.402 +            default: throw new IllegalStateException("Array type: " + atype);
   9.403 +        }
   9.404 +        emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);",
   9.405 +             smapper.popI(), smapper.pushA(), jvmType);
   9.406 +    }
   9.407 +
   9.408 +    private void generateANewArray(int type, final StackMapper smapper) throws IOException {
   9.409 +        String typeName = jc.getClassName(type);
   9.410 +        if (typeName.startsWith("[")) {
   9.411 +            typeName = "[" + typeName;
   9.412 +        } else {
   9.413 +            typeName = "[L" + typeName + ";";
   9.414 +        }
   9.415 +        emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);",
   9.416 +             smapper.popI(), smapper.pushA(), typeName);
   9.417 +    }
   9.418 +
   9.419 +    private int generateMultiANewArray(int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException {
   9.420 +        String typeName = jc.getClassName(type);
   9.421 +        int dim = readUByte(byteCodes, ++i);
   9.422 +        StringBuilder dims = new StringBuilder();
   9.423 +        dims.append('[');
   9.424 +        for (int d = 0; d < dim; d++) {
   9.425 +            if (d != 0) {
   9.426 +                dims.insert(1, ",");
   9.427 +            }
   9.428 +            dims.insert(1, smapper.popI());
   9.429 +        }
   9.430 +        dims.append(']');
   9.431 +        emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);",
   9.432 +             dims.toString(), smapper.pushA(), typeName);
   9.433 +        return i;
   9.434 +    }
   9.435 +
   9.436 +    private int generateTableSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException {
   9.437 +        int table = i / 4 * 4 + 4;
   9.438 +        int dflt = i + readInt4(byteCodes, table);
   9.439 +        table += 4;
   9.440 +        int low = readInt4(byteCodes, table);
   9.441 +        table += 4;
   9.442 +        int high = readInt4(byteCodes, table);
   9.443 +        table += 4;
   9.444 +        out.append("switch (").append(smapper.popI()).append(") {\n");
   9.445 +        while (low <= high) {
   9.446 +            int offset = i + readInt4(byteCodes, table);
   9.447 +            table += 4;
   9.448 +            out.append("  case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n');
   9.449 +            low++;
   9.450 +        }
   9.451 +        out.append("  default: ");
   9.452 +        goTo(out, i, dflt, topMostLabel);
   9.453 +        out.append("\n}");
   9.454 +        i = table - 1;
   9.455 +        return i;
   9.456 +    }
   9.457 +
   9.458 +    private int generateLookupSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException {
   9.459 +        int table = i / 4 * 4 + 4;
   9.460 +        int dflt = i + readInt4(byteCodes, table);
   9.461 +        table += 4;
   9.462 +        int n = readInt4(byteCodes, table);
   9.463 +        table += 4;
   9.464 +        out.append("switch (").append(smapper.popI()).append(") {\n");
   9.465 +        while (n-- > 0) {
   9.466 +            int cnstnt = readInt4(byteCodes, table);
   9.467 +            table += 4;
   9.468 +            int offset = i + readInt4(byteCodes, table);
   9.469 +            table += 4;
   9.470 +            out.append("  case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n');
   9.471 +        }
   9.472 +        out.append("  default: ");
   9.473 +        goTo(out, i, dflt, topMostLabel);
   9.474 +        out.append("\n}");
   9.475 +        i = table - 1;
   9.476 +        return i;
   9.477 +    }
   9.478 +
   9.479 +    private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException {
   9.480 +        final String type = jc.getClassName(indx);
   9.481 +        if (!type.startsWith("[")) {
   9.482 +            emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;",
   9.483 +                 smapper.popA(), smapper.pushI(),
   9.484 +                 type.replace('/', '_'));
   9.485 +        } else {
   9.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);",
   9.487 +                smapper.popA(), smapper.pushI(),
   9.488 +                type
   9.489 +            );
   9.490 +        }
   9.491 +    }
   9.492 +
   9.493 +    private void generateCheckcast(int indx, final StackMapper smapper) throws IOException {
   9.494 +        final String type = jc.getClassName(indx);
   9.495 +        if (!type.startsWith("[")) {
   9.496 +            emit(out,
   9.497 +                 "if (@1 !== null && !@1.$instOf_@2) throw {};",
   9.498 +                 smapper.getA(0), type.replace('/', '_'));
   9.499 +        } else {
   9.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);",
   9.501 +                 smapper.getA(0), type
   9.502 +            );
   9.503 +        }
   9.504 +    }
   9.505 +
   9.506 +    private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException {
   9.507 +        for (int j = prev; j <= i; j++) {
   9.508 +            out.append(" ");
   9.509 +            final int cc = readUByte(byteCodes, j);
   9.510 +            out.append(Integer.toString(cc));
   9.511 +        }
   9.512 +    }
   9.513  }
    10.1 --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Tue Mar 19 13:08:44 2013 +0100
    10.2 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java	Tue Mar 19 13:18:02 2013 +0100
    10.3 @@ -115,7 +115,7 @@
    10.4              if (sb.length() > 2000) {
    10.5                  sb = dumpJS(sb);
    10.6              }
    10.7 -            fail("Could not evaluate:\n" + sb, ex);
    10.8 +            fail("Could not evaluate:" + ex.getClass() + ":" + ex.getMessage() + "\n" + sb, ex);
    10.9              return null;
   10.10          }
   10.11      }