# HG changeset patch # User Jaroslav Tulach # Date 1363881654 -3600 # Node ID b3768be30aa05170b3c78bfd9773618fce10e1db # Parent 9b4751828cebd034e7033d25fdfb96fcb5205e74# Parent 03fe918c468439524e8dbdba213ab62953a653df Bringing in the most recent advances on the default branch diff -r 9b4751828ceb -r b3768be30aa0 benchmarks/matrix-multiplication/pom.xml --- a/benchmarks/matrix-multiplication/pom.xml Thu Mar 21 15:45:42 2013 +0100 +++ b/benchmarks/matrix-multiplication/pom.xml Thu Mar 21 17:00:54 2013 +0100 @@ -37,6 +37,36 @@ true + + org.codehaus.mojo + xml-maven-plugin + 1.0 + + + + transform + + install + + + + + + target/surefire-reports + target/surefire-reports + + TEST*.xml + + src/main/select-time.xsl + + + .csv + + + + + + diff -r 9b4751828ceb -r b3768be30aa0 benchmarks/matrix-multiplication/src/main/select-time.xsl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/benchmarks/matrix-multiplication/src/main/select-time.xsl Thu Mar 21 17:00:54 2013 +0100 @@ -0,0 +1,55 @@ + + + + + + + + End + + NaN + + + + + + + + + + , + + + + + + + + + + + , + + + + + + diff -r 9b4751828ceb -r b3768be30aa0 benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java --- a/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Thu Mar 21 15:45:42 2013 +0100 +++ b/benchmarks/matrix-multiplication/src/test/java/org/apidesign/benchmark/matrixmul/MatrixTest.java Thu Mar 21 17:00:54 2013 +0100 @@ -31,6 +31,22 @@ } @Compare(scripting = false) + public String oneIteration() throws IOException { + + Matrix m1 = new Matrix(5); + Matrix m2 = new Matrix(5); + + m1.generateData(); + m2.generateData(); + + Matrix res = m1.multiply(m2); + + StringBuilder sb = new StringBuilder(); + res.printOn(sb); + return sb.toString(); + } + + @Compare(scripting = false) public String tenThousandIterations() throws IOException { Matrix m1 = new Matrix(5); @@ -50,6 +66,27 @@ return sb.toString(); } + @Compare(scripting = false) + public String tenUselessIterations() throws IOException { + + Matrix m1 = new Matrix(5); + Matrix m2 = new Matrix(5); + + m1.generateData(); + m2.generateData(); + + Matrix res = null; + for (int i = 0; i < 10; i++) { + res = m1.multiply(m2); + m1 = res; + } + + StringBuilder sb = new StringBuilder(); + res.printOn(sb); + return sb.toString(); + } + + @Factory public static Object[] create() { return VMTest.create(MatrixTest.class); diff -r 9b4751828ceb -r b3768be30aa0 ide/editor/pom.xml --- a/ide/editor/pom.xml Thu Mar 21 15:45:42 2013 +0100 +++ b/ide/editor/pom.xml Thu Mar 21 17:00:54 2013 +0100 @@ -16,7 +16,7 @@ UTF-8 - RELEASE72 + RELEASE73 ${project.build.directory}/endorsed diff -r 9b4751828ceb -r b3768be30aa0 javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Thu Mar 21 15:45:42 2013 +0100 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Thu Mar 21 17:00:54 2013 +0100 @@ -180,6 +180,9 @@ } Bck2Brwsr.generate(sb, ProcessPageTest.class.getClassLoader(), names); sb.append("var vm = this.bck2brwsr();\n"); + for (String c : names) { + sb.append("vm.loadClass('").append(c.replace('/', '.')).append("');\n"); + } ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine js = sem.getEngineByExtension("js"); diff -r 9b4751828ceb -r b3768be30aa0 javaquery/demo-calculator-dynamic/nbactions.xml --- a/javaquery/demo-calculator-dynamic/nbactions.xml Thu Mar 21 15:45:42 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/nbactions.xml Thu Mar 21 17:00:54 2013 +0100 @@ -23,7 +23,7 @@ run process-classes - org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr + org.apidesign.bck2brwsr:mojo:0.5-SNAPSHOT:brwsr diff -r 9b4751828ceb -r b3768be30aa0 javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java --- a/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java Thu Mar 21 15:45:42 2013 +0100 +++ b/javaquery/demo-calculator-dynamic/src/main/java/org/apidesign/bck2brwsr/demo/calc/Calc.java Thu Mar 21 17:00:54 2013 +0100 @@ -48,18 +48,18 @@ } @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) - static void applyOp(Calculator c, String op) { + static void applyOp(Calculator c, String id) { c.setMemory(c.getDisplay()); - c.setOperation(op); + c.setOperation(id); c.setDisplay(0); } @On(event = MOUSE_OVER, id= { "result" }) - static void attemptingIn(Calculator c, String op) { + static void attemptingIn(Calculator c) { c.setHover(true); } @On(event = MOUSE_OUT, id= { "result" }) - static void attemptingOut(Calculator c, String op) { + static void attemptingOut(Calculator c) { c.setHover(false); } @@ -84,18 +84,18 @@ } @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) - static void addDigit(String digit, Calculator c) { - digit = digit.substring(1); + static void addDigit(String id, Calculator c) { + id = id.substring(1); double v = c.getDisplay(); if (v == 0.0) { - c.setDisplay(Integer.parseInt(digit)); + c.setDisplay(Integer.parseInt(id)); } else { String txt = Double.toString(v); if (txt.endsWith(".0")) { txt = txt.substring(0, txt.length() - 2); } - txt = txt + digit; + txt = txt + id; c.setDisplay(Double.parseDouble(txt)); } } diff -r 9b4751828ceb -r b3768be30aa0 javaquery/demo-calculator/nbactions.xml --- a/javaquery/demo-calculator/nbactions.xml Thu Mar 21 15:45:42 2013 +0100 +++ b/javaquery/demo-calculator/nbactions.xml Thu Mar 21 17:00:54 2013 +0100 @@ -23,7 +23,7 @@ run package - org.apidesign.bck2brwsr:mojo:0.3-SNAPSHOT:brwsr + org.apidesign.bck2brwsr:mojo:0.5-SNAPSHOT:brwsr true diff -r 9b4751828ceb -r b3768be30aa0 javaquery/demo-calculator/pom.xml --- a/javaquery/demo-calculator/pom.xml Thu Mar 21 15:45:42 2013 +0100 +++ b/javaquery/demo-calculator/pom.xml Thu Mar 21 17:00:54 2013 +0100 @@ -22,6 +22,7 @@ + j2js brwsr @@ -29,6 +30,7 @@ ${project.build.directory}/${project.build.finalName}-bck2brwsr/public_html/ index.xhtml + ${project.build.directory}/bck2brwsr.js @@ -102,13 +104,5 @@ javaquery.api 0.5-SNAPSHOT - - org.apidesign.bck2brwsr - vm4brwsr - js - zip - 0.5-SNAPSHOT - provided - diff -r 9b4751828ceb -r b3768be30aa0 javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml --- a/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Thu Mar 21 15:45:42 2013 +0100 +++ b/javaquery/demo-calculator/src/main/assembly/bck2brwsr.xml Thu Mar 21 17:00:54 2013 +0100 @@ -37,15 +37,6 @@ *:rt - - false - provided - - *:js - - true - / - @@ -53,6 +44,10 @@ / + ${project.build.directory}/bck2brwsr.js + / + + ${project.build.directory}/classes/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml / index.xhtml diff -r 9b4751828ceb -r b3768be30aa0 javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java --- a/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Thu Mar 21 15:45:42 2013 +0100 +++ b/javaquery/demo-calculator/src/main/java/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calc.java Thu Mar 21 17:00:54 2013 +0100 @@ -48,18 +48,18 @@ } @On(event = CLICK, id= { "plus", "minus", "mul", "div" }) - static void applyOp(Calculator c, String op) { + static void applyOp(Calculator c, String id) { c.setMemory(c.getDisplay()); - c.setOperation(op); + c.setOperation(id); c.setDisplay(0); } @On(event = MOUSE_OVER, id= { "result" }) - static void attemptingIn(Calculator c, String op) { + static void attemptingIn(Calculator c) { c.setHover(true); } @On(event = MOUSE_OUT, id= { "result" }) - static void attemptingOut(Calculator c, String op) { + static void attemptingOut(Calculator c) { c.setHover(false); } @@ -84,18 +84,18 @@ } @On(event = CLICK, id={"n0", "n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9"}) - static void addDigit(String digit, Calculator c) { - digit = digit.substring(1); + static void addDigit(String id, Calculator c) { + id = id.substring(1); double v = c.getDisplay(); if (v == 0.0) { - c.setDisplay(Integer.parseInt(digit)); + c.setDisplay(Integer.parseInt(id)); } else { String txt = Double.toString(v); if (txt.endsWith(".0")) { txt = txt.substring(0, txt.length() - 2); } - txt = txt + digit; + txt = txt + id; c.setDisplay(Double.parseDouble(txt)); } } diff -r 9b4751828ceb -r b3768be30aa0 javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml --- a/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Thu Mar 21 15:45:42 2013 +0100 +++ b/javaquery/demo-calculator/src/main/resources/org/apidesign/bck2brwsr/demo/calc/staticcompilation/Calculator.xhtml Thu Mar 21 17:00:54 2013 +0100 @@ -79,7 +79,7 @@
diff -r 9b4751828ceb -r b3768be30aa0 pom.xml --- a/pom.xml Thu Mar 21 15:45:42 2013 +0100 +++ b/pom.xml Thu Mar 21 17:00:54 2013 +0100 @@ -139,13 +139,13 @@ org.netbeans.api org-netbeans-modules-classfile - RELEASE72 + RELEASE73 jar org.netbeans.api org-openide-util-lookup - RELEASE72 + RELEASE73 compile jar diff -r 9b4751828ceb -r b3768be30aa0 rt/emul/mini/src/main/java/java/lang/AbstractStringBuilder.java --- a/rt/emul/mini/src/main/java/java/lang/AbstractStringBuilder.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/emul/mini/src/main/java/java/lang/AbstractStringBuilder.java Thu Mar 21 17:00:54 2013 +0100 @@ -126,7 +126,7 @@ throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } - value = copyOf(value, newCapacity); + value = System.expandArray(value, newCapacity); } /** diff -r 9b4751828ceb -r b3768be30aa0 rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java --- a/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/lang/System.java Thu Mar 21 17:00:54 2013 +0100 @@ -54,6 +54,11 @@ ) public static native byte[] expandArray(byte[] arr, int expectedSize); + @JavaScriptBody(args = { "arr", "expectedSize" }, body = + "while (expectedSize-- > arr.length) { arr.push(0); }; return arr;" + ) + public static native char[] expandArray(char[] arr, int expectedSize); + @JavaScriptBody(args = {}, body = "return new Date().getTime();") private static native double currentTimeMillisDouble(); diff -r 9b4751828ceb -r b3768be30aa0 rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js --- a/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/emul/mini/src/main/resources/org/apidesign/vm4brwsr/emul/lang/java_lang_Number.js Thu Mar 21 17:00:54 2013 +0100 @@ -551,3 +551,5 @@ return negateResult ? result.neg64() : result; } })(Number.prototype); + +vm.java_lang_Number(false); diff -r 9b4751828ceb -r b3768be30aa0 rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java --- a/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/launcher/src/main/java/org/apidesign/bck2brwsr/launcher/Launcher.java Thu Mar 21 17:00:54 2013 +0100 @@ -20,7 +20,6 @@ import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.net.URLClassLoader; import org.apidesign.vm4brwsr.Bck2Brwsr; /** An abstraction for executing tests in a Bck2Brwsr virtual machine. @@ -93,7 +92,7 @@ * @return interface that allows one to stop the server * @throws IOException if something goes wrong */ - public static Closeable showURL(URLClassLoader classes, String startpage) throws IOException { + public static Closeable showURL(ClassLoader classes, String startpage) throws IOException { Bck2BrwsrLauncher l = new Bck2BrwsrLauncher(null); l.addClassLoader(classes); l.showURL(startpage); diff -r 9b4751828ceb -r b3768be30aa0 rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java --- a/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Java2JavaScript.java Thu Mar 21 17:00:54 2013 +0100 @@ -44,11 +44,17 @@ /** Root of the class files */ @Parameter(defaultValue="${project.build.directory}/classes") private File classes; - /** File to generate. Defaults bootjava.js in the first non-empty - package under the classes directory */ + /** JavaScript file to generate */ @Parameter private File javascript; + /** Additional classes that should be pre-compiled into the javascript + * file. By default compiles all classes found under classes + * directory and their transitive closure. + */ + @Parameter + private List compileclasses; + @Parameter(defaultValue="${project}") private MavenProject prj; @@ -60,13 +66,14 @@ throw new MojoExecutionException("Can't find " + classes); } - if (javascript == null) { - javascript = new File(findNonEmptyFolder(classes), "bootjava.js"); - } - List arr = new ArrayList(); long newest = collectAllClasses("", classes, arr); + if (compileclasses != null) { + arr.retainAll(compileclasses); + arr.addAll(compileclasses); + } + if (javascript.lastModified() > newest) { return; } @@ -81,17 +88,6 @@ } } - private static File findNonEmptyFolder(File dir) throws MojoExecutionException { - if (!dir.isDirectory()) { - throw new MojoExecutionException("Not a directory " + dir); - } - File[] arr = dir.listFiles(); - if (arr.length == 1 && arr[0].isDirectory()) { - return findNonEmptyFolder(arr[0]); - } - return dir; - } - private static long collectAllClasses(String prefix, File toCheck, List arr) { File[] files = toCheck.listFiles(); if (files != null) { @@ -104,7 +100,8 @@ } return newest; } else if (toCheck.getName().endsWith(".class")) { - arr.add(prefix.substring(0, prefix.length() - 7)); + final String cls = prefix.substring(0, prefix.length() - 7); + arr.add(cls); return toCheck.lastModified(); } else { return 0L; @@ -115,7 +112,9 @@ List arr = new ArrayList(); arr.add(root.toURI().toURL()); for (Artifact a : deps) { - arr.add(a.getFile().toURI().toURL()); + if (a.getFile() != null) { + arr.add(a.getFile().toURI().toURL()); + } } return new URLClassLoader(arr.toArray(new URL[0]), Java2JavaScript.class.getClassLoader()); } diff -r 9b4751828ceb -r b3768be30aa0 rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Thu Mar 21 17:00:54 2013 +0100 @@ -191,6 +191,9 @@ generateAnno(jc, out, classAnno); out.append("\n };"); } + for (String init : toInitilize.toArray()) { + out.append("\n ").append(init).append("();"); + } out.append("\n }"); out.append("\n if (arguments.length === 0) {"); out.append("\n if (!(this instanceof CLS)) {"); @@ -219,11 +222,11 @@ out.append("\n }"); out.append("\n return arguments[0] ? new CLS() : CLS.prototype;"); out.append("\n};"); - StringBuilder sb = new StringBuilder(); - for (String init : toInitilize.toArray()) { - sb.append("\n").append(init).append("();"); - } - return sb.toString(); +// StringBuilder sb = new StringBuilder(); +// for (String init : toInitilize.toArray()) { +// sb.append("\n").append(init).append("();"); +// } + return ""; } private String generateStaticMethod(String prefix, MethodData m, StringArray toInitilize) throws IOException { String jsb = javaScriptBody(prefix, m, true); @@ -278,22 +281,36 @@ TrapData[] previousTrap = null; boolean wide = false; - out.append("\n var gt = 0;\n for(;;) switch(gt) {\n"); + out.append("\n var gt = 0;\n"); + int openBraces = 0; + int topMostLabel = 0; for (int i = 0; i < byteCodes.length; i++) { int prev = i; stackMapIterator.advanceTo(i); boolean changeInCatch = trap.advanceTo(i); if (changeInCatch || lastStackFrame != stackMapIterator.getFrameIndex()) { if (previousTrap != null) { - generateCatch(previousTrap); + generateCatch(previousTrap, i, topMostLabel); previousTrap = null; } } if (lastStackFrame != stackMapIterator.getFrameIndex()) { + if (i != 0) { + out.append(" }\n"); + } + if (openBraces > 64) { + for (int c = 0; c < 64; c++) { + out.append("break;}\n"); + } + openBraces = 1; + topMostLabel = i; + } + lastStackFrame = stackMapIterator.getFrameIndex(); lmapper.syncWithFrameLocals(stackMapIterator.getFrameLocals()); smapper.syncWithFrameStack(stackMapIterator.getFrameStack()); - out.append(" case " + i).append(": "); + out.append(" X_" + i).append(": for (;;) { IF: if (gt <= " + i + ") {\n"); + openBraces++; changeInCatch = true; } else { debug(" /* " + i + " */ "); @@ -765,7 +782,7 @@ } case opc_ldc_w: case opc_ldc2_w: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); i += 2; String v = encodeConstant(indx); int type = VarType.fromConstantType(jc.getTag(indx)); @@ -796,133 +813,104 @@ break; case opc_if_acmpeq: i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), - "==="); + "===", topMostLabel); break; case opc_if_acmpne: i = generateIf(byteCodes, i, smapper.popA(), smapper.popA(), - "!=="); + "!==", topMostLabel); break; case opc_if_icmpeq: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - "=="); + "==", topMostLabel); break; case opc_ifeq: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 == 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 == 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifne: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 != 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 != 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_iflt: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 < 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 < 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifle: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 <= 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 <= 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifgt: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 > 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 > 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifge: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 >= 0) { gt = @2; continue; }", - smapper.popI(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 >= 0) ", + smapper.popI(), i, indx, topMostLabel); i += 2; break; } case opc_ifnonnull: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 !== null) { gt = @2; continue; }", - smapper.popA(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 !== null) ", + smapper.popA(), i, indx, topMostLabel); i += 2; break; } case opc_ifnull: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "if (@1 === null) { gt = @2; continue; }", - smapper.popA(), Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + emitIf(out, "if (@1 === null) ", + smapper.popA(), i, indx, topMostLabel); i += 2; break; } case opc_if_icmpne: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - "!="); + "!=", topMostLabel); break; case opc_if_icmplt: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - "<"); + "<", topMostLabel); break; case opc_if_icmple: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - "<="); + "<=", topMostLabel); break; case opc_if_icmpgt: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - ">"); + ">", topMostLabel); break; case opc_if_icmpge: i = generateIf(byteCodes, i, smapper.popI(), smapper.popI(), - ">="); + ">=", topMostLabel); break; case opc_goto: { - int indx = i + readIntArg(byteCodes, i); - emit(out, "gt = @1; continue;", Integer.toString(indx)); + int indx = i + readShortArg(byteCodes, i); + goTo(out, i, indx, topMostLabel); i += 2; break; } case opc_lookupswitch: { - int table = i / 4 * 4 + 4; - int dflt = i + readInt4(byteCodes, table); - table += 4; - int n = readInt4(byteCodes, table); - table += 4; - out.append("switch (").append(smapper.popI()).append(") {\n"); - while (n-- > 0) { - int cnstnt = readInt4(byteCodes, table); - table += 4; - int offset = i + readInt4(byteCodes, table); - table += 4; - out.append(" case " + cnstnt).append(": gt = " + offset).append("; continue;\n"); - } - out.append(" default: gt = " + dflt).append("; continue;\n}"); - i = table - 1; + i = generateLookupSwitch(i, byteCodes, smapper, topMostLabel); break; } case opc_tableswitch: { - int table = i / 4 * 4 + 4; - int dflt = i + readInt4(byteCodes, table); - table += 4; - int low = readInt4(byteCodes, table); - table += 4; - int high = readInt4(byteCodes, table); - table += 4; - out.append("switch (").append(smapper.popI()).append(") {\n"); - while (low <= high) { - int offset = i + readInt4(byteCodes, table); - table += 4; - out.append(" case " + low).append(": gt = " + offset).append("; continue;\n"); - low++; - } - out.append(" default: gt = " + dflt).append("; continue;\n}"); - i = table - 1; + i = generateTableSwitch(i, byteCodes, smapper, topMostLabel); break; } case opc_invokeinterface: { @@ -939,7 +927,7 @@ i = invokeStaticMethod(byteCodes, i, smapper, true); break; case opc_new: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String ci = jc.getClassName(indx); emit(out, "var @1 = new @2;", smapper.pushA(), accessClass(ci.replace('/', '_'))); @@ -949,50 +937,18 @@ } case opc_newarray: int atype = readUByte(byteCodes, ++i); - String jvmType; - switch (atype) { - case 4: jvmType = "[Z"; break; - case 5: jvmType = "[C"; break; - case 6: jvmType = "[F"; break; - case 7: jvmType = "[D"; break; - case 8: jvmType = "[B"; break; - case 9: jvmType = "[S"; break; - case 10: jvmType = "[I"; break; - case 11: jvmType = "[J"; break; - default: throw new IllegalStateException("Array type: " + atype); - } - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);", - smapper.popI(), smapper.pushA(), jvmType); + generateNewArray(atype, smapper); break; case opc_anewarray: { - int type = readIntArg(byteCodes, i); + int type = readUShortArg(byteCodes, i); i += 2; - String typeName = jc.getClassName(type); - if (typeName.startsWith("[")) { - typeName = "[" + typeName; - } else { - typeName = "[L" + typeName + ";"; - } - emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);", - smapper.popI(), smapper.pushA(), typeName); + generateANewArray(type, smapper); break; } case opc_multianewarray: { - int type = readIntArg(byteCodes, i); + int type = readUShortArg(byteCodes, i); i += 2; - String typeName = jc.getClassName(type); - int dim = readUByte(byteCodes, ++i); - StringBuilder dims = new StringBuilder(); - dims.append('['); - for (int d = 0; d < dim; d++) { - if (d != 0) { - dims.insert(1, ","); - } - dims.insert(1, smapper.popI()); - } - dims.append(']'); - emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);", - dims.toString(), smapper.pushA(), typeName); + i = generateMultiANewArray(type, byteCodes, i, smapper); break; } case opc_arraylength: @@ -1206,11 +1162,11 @@ case opc_sipush: emit(out, "var @1 = @2;", smapper.pushI(), - Integer.toString(readIntArg(byteCodes, i))); + Integer.toString(readShortArg(byteCodes, i))); i += 2; break; case opc_getfield: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); final String mangleClass = mangleSig(fi[0]); @@ -1223,7 +1179,7 @@ break; } case opc_putfield: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); final String mangleClass = mangleSig(fi[0]); @@ -1237,7 +1193,7 @@ break; } case opc_getstatic: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); emit(out, "var @1 = @2(false)._@3();", @@ -1248,7 +1204,7 @@ break; } case opc_putstatic: { - int indx = readIntArg(byteCodes, i); + int indx = readUShortArg(byteCodes, i); String[] fi = jc.getFieldInfoName(indx); final int type = VarType.fromFieldType(fi[2].charAt(0)); emit(out, "@1(false)._@2(@3);", @@ -1259,33 +1215,14 @@ break; } case opc_checkcast: { - int indx = readIntArg(byteCodes, i); - final String type = jc.getClassName(indx); - if (!type.startsWith("[")) { - emit(out, - "if (@1 !== null && !@1.$instOf_@2) throw {};", - smapper.getA(0), type.replace('/', '_')); - } else { - 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);", - smapper.getA(0), type - ); - } + int indx = readUShortArg(byteCodes, i); + generateCheckcast(indx, smapper); i += 2; break; } case opc_instanceof: { - int indx = readIntArg(byteCodes, i); - final String type = jc.getClassName(indx); - if (!type.startsWith("[")) { - emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;", - smapper.popA(), smapper.pushI(), - type.replace('/', '_')); - } else { - emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);", - smapper.popA(), smapper.pushI(), - type - ); - } + int indx = readUShortArg(byteCodes, i); + generateInstanceOf(indx, smapper); i += 2; break; } @@ -1321,37 +1258,29 @@ } } if (debug(" //")) { - for (int j = prev; j <= i; j++) { - out.append(" "); - final int cc = readUByte(byteCodes, j); - out.append(Integer.toString(cc)); - } + generateByteCodeComment(prev, i, byteCodes); } out.append("\n"); } if (previousTrap != null) { - generateCatch(previousTrap); + generateCatch(previousTrap, byteCodes.length, topMostLabel); } - out.append(" }\n"); - out.append("};"); + out.append("\n }\n"); + while (openBraces-- > 0) { + out.append('}'); + } + out.append("\n};"); } - private int generateIf(byte[] byteCodes, int i, - final Variable v2, final Variable v1, - final String test) throws IOException { - int indx = i + readIntArg(byteCodes, i); + private int generateIf(byte[] byteCodes, int i, final Variable v2, final Variable v1, final String test, int topMostLabel) throws IOException { + int indx = i + readShortArg(byteCodes, i); out.append("if (").append(v1) .append(' ').append(test).append(' ') - .append(v2).append(") { gt = " + indx) - .append("; continue; }"); + .append(v2).append(") "); + goTo(out, i, indx, topMostLabel); return i + 2; } - - private int readIntArg(byte[] byteCodes, int offsetInstruction) { - final int indxHi = byteCodes[offsetInstruction + 1] << 8; - final int indxLo = byteCodes[offsetInstruction + 2]; - return (indxHi & 0xffffff00) | (indxLo & 0xff); - } + private int readInt4(byte[] byteCodes, int offset) { final int d = byteCodes[offset + 0] << 24; final int c = byteCodes[offset + 1] << 16; @@ -1359,18 +1288,25 @@ final int a = byteCodes[offset + 3]; return (d & 0xff000000) | (c & 0xff0000) | (b & 0xff00) | (a & 0xff); } - private int readUByte(byte[] byteCodes, int offset) { + private static int readUByte(byte[] byteCodes, int offset) { return byteCodes[offset] & 0xff; } - private int readUShort(byte[] byteCodes, int offset) { + private static int readUShort(byte[] byteCodes, int offset) { return ((byteCodes[offset] & 0xff) << 8) | (byteCodes[offset + 1] & 0xff); } + private static int readUShortArg(byte[] byteCodes, int offsetInstruction) { + return readUShort(byteCodes, offsetInstruction + 1); + } - private int readShort(byte[] byteCodes, int offset) { - return (byteCodes[offset] << 8) - | (byteCodes[offset + 1] & 0xff); + private static int readShort(byte[] byteCodes, int offset) { + int signed = byteCodes[offset]; + byte b0 = (byte)signed; + return (b0 << 8) | (byteCodes[offset + 1] & 0xff); + } + private static int readShortArg(byte[] byteCodes, int offsetInstruction) { + return readShort(byteCodes, offsetInstruction + 1); } private static void countArgs(String descriptor, char[] returnType, StringBuilder sig, StringBuilder cnt) { @@ -1498,7 +1434,7 @@ private int invokeStaticMethod(byte[] byteCodes, int i, final StackMapper mapper, boolean isStatic) throws IOException { - int methodIndex = readIntArg(byteCodes, i); + int methodIndex = readUShortArg(byteCodes, i); String[] mi = jc.getFieldInfoName(methodIndex); char[] returnType = { 'V' }; StringBuilder cnt = new StringBuilder(); @@ -1543,7 +1479,7 @@ } private int invokeVirtualMethod(byte[] byteCodes, int i, final StackMapper mapper) throws IOException { - int methodIndex = readIntArg(byteCodes, i); + int methodIndex = readUShortArg(byteCodes, i); String[] mi = jc.getFieldInfoName(methodIndex); char[] returnType = { 'V' }; StringBuilder cnt = new StringBuilder(); @@ -1818,7 +1754,7 @@ out.append(format, processed, length); } - private void generateCatch(TrapData[] traps) throws IOException { + private void generateCatch(TrapData[] traps, int current, int topMostLabel) throws IOException { out.append("} catch (e) {\n"); int finallyPC = -1; for (TrapData e : traps) { @@ -1835,10 +1771,11 @@ out.append(" var stA0 = vm.java_lang_Throwable(true);"); out.append(" vm.java_lang_Throwable.cons__VLjava_lang_String_2.call(stA0, e.toString());"); out.append("}"); - out.append("gt=" + e.handler_pc + "; continue;"); + goTo(out, current, e.handler_pc, topMostLabel); } else { out.append("if (e.$instOf_" + classInternalName.replace('/', '_') + ") {"); - out.append("gt=" + e.handler_pc + "; var stA0 = e; continue;"); + out.append("var stA0 = e;"); + goTo(out, current, e.handler_pc, topMostLabel); out.append("}\n"); } } else { @@ -1848,8 +1785,152 @@ if (finallyPC == -1) { out.append("throw e;"); } else { - out.append("gt=" + finallyPC + "; var stA0 = e; continue;"); + out.append("var stA0 = e;"); + goTo(out, current, finallyPC, topMostLabel); } out.append("\n}"); } + + private static void goTo(Appendable out, int current, int to, int canBack) throws IOException { + if (to < current) { + if (canBack < to) { + out.append("{ gt = 0; continue X_" + to + "; }"); + } else { + out.append("{ gt = " + to + "; continue X_0; }"); + } + } else { + out.append("{ gt = " + to + "; break IF; }"); + } + } + + private static void emitIf( + Appendable out, String pattern, Variable param, + int current, int to, int canBack + ) throws IOException { + emit(out, pattern, param); + goTo(out, current, to, canBack); + } + + private void generateNewArray(int atype, final StackMapper smapper) throws IOException, IllegalStateException { + String jvmType; + switch (atype) { + case 4: jvmType = "[Z"; break; + case 5: jvmType = "[C"; break; + case 6: jvmType = "[F"; break; + case 7: jvmType = "[D"; break; + case 8: jvmType = "[B"; break; + case 9: jvmType = "[S"; break; + case 10: jvmType = "[I"; break; + case 11: jvmType = "[J"; break; + default: throw new IllegalStateException("Array type: " + atype); + } + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(true, '@3', @1);", + smapper.popI(), smapper.pushA(), jvmType); + } + + private void generateANewArray(int type, final StackMapper smapper) throws IOException { + String typeName = jc.getClassName(type); + if (typeName.startsWith("[")) { + typeName = "[" + typeName; + } else { + typeName = "[L" + typeName + ";"; + } + emit(out, "var @2 = Array.prototype.newArray__Ljava_lang_Object_2ZLjava_lang_String_2I(false, '@3', @1);", + smapper.popI(), smapper.pushA(), typeName); + } + + private int generateMultiANewArray(int type, final byte[] byteCodes, int i, final StackMapper smapper) throws IOException { + String typeName = jc.getClassName(type); + int dim = readUByte(byteCodes, ++i); + StringBuilder dims = new StringBuilder(); + dims.append('['); + for (int d = 0; d < dim; d++) { + if (d != 0) { + dims.insert(1, ","); + } + dims.insert(1, smapper.popI()); + } + dims.append(']'); + emit(out, "var @2 = Array.prototype.multiNewArray__Ljava_lang_Object_2Ljava_lang_String_2_3II('@3', @1, 0);", + dims.toString(), smapper.pushA(), typeName); + return i; + } + + private int generateTableSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException { + int table = i / 4 * 4 + 4; + int dflt = i + readInt4(byteCodes, table); + table += 4; + int low = readInt4(byteCodes, table); + table += 4; + int high = readInt4(byteCodes, table); + table += 4; + out.append("switch (").append(smapper.popI()).append(") {\n"); + while (low <= high) { + int offset = i + readInt4(byteCodes, table); + table += 4; + out.append(" case " + low).append(":"); goTo(out, i, offset, topMostLabel); out.append('\n'); + low++; + } + out.append(" default: "); + goTo(out, i, dflt, topMostLabel); + out.append("\n}"); + i = table - 1; + return i; + } + + private int generateLookupSwitch(int i, final byte[] byteCodes, final StackMapper smapper, int topMostLabel) throws IOException { + int table = i / 4 * 4 + 4; + int dflt = i + readInt4(byteCodes, table); + table += 4; + int n = readInt4(byteCodes, table); + table += 4; + out.append("switch (").append(smapper.popI()).append(") {\n"); + while (n-- > 0) { + int cnstnt = readInt4(byteCodes, table); + table += 4; + int offset = i + readInt4(byteCodes, table); + table += 4; + out.append(" case " + cnstnt).append(": "); goTo(out, i, offset, topMostLabel); out.append('\n'); + } + out.append(" default: "); + goTo(out, i, dflt, topMostLabel); + out.append("\n}"); + i = table - 1; + return i; + } + + private void generateInstanceOf(int indx, final StackMapper smapper) throws IOException { + final String type = jc.getClassName(indx); + if (!type.startsWith("[")) { + emit(out, "var @2 = @1 != null && @1.$instOf_@3 ? 1 : 0;", + smapper.popA(), smapper.pushI(), + type.replace('/', '_')); + } else { + emit(out, "var @2 = vm.java_lang_Class(false).forName__Ljava_lang_Class_2Ljava_lang_String_2('@3').isInstance__ZLjava_lang_Object_2(@1);", + smapper.popA(), smapper.pushI(), + type + ); + } + } + + private void generateCheckcast(int indx, final StackMapper smapper) throws IOException { + final String type = jc.getClassName(indx); + if (!type.startsWith("[")) { + emit(out, + "if (@1 !== null && !@1.$instOf_@2) throw {};", + smapper.getA(0), type.replace('/', '_')); + } else { + 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);", + smapper.getA(0), type + ); + } + } + + private void generateByteCodeComment(int prev, int i, final byte[] byteCodes) throws IOException { + for (int j = prev; j <= i; j++) { + out.append(" "); + final int cc = readUByte(byteCodes, j); + out.append(Integer.toString(cc)); + } + } } diff -r 9b4751828ceb -r b3768be30aa0 rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java --- a/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Thu Mar 21 17:00:54 2013 +0100 @@ -110,7 +110,10 @@ for (String ic : toInit.toArray()) { int indx = processed.indexOf(ic); if (indx >= 0) { - out.append(initCode.toArray()[indx]).append("\n"); + final String theCode = initCode.toArray()[indx]; + if (!theCode.isEmpty()) { + out.append(theCode).append("\n"); + } initCode.toArray()[indx] = ""; } } diff -r 9b4751828ceb -r b3768be30aa0 rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/TestVM.java Thu Mar 21 17:00:54 2013 +0100 @@ -115,7 +115,7 @@ if (sb.length() > 2000) { sb = dumpJS(sb); } - fail("Could not evaluate:\n" + sb, ex); + fail("Could not evaluate:" + ex.getClass() + ":" + ex.getMessage() + "\n" + sb, ex); return null; } } diff -r 9b4751828ceb -r b3768be30aa0 rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java --- a/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Thu Mar 21 17:00:54 2013 +0100 @@ -40,6 +40,14 @@ compareCode("org/apidesign/vm4brwsr/Classes.class"); } + @Test public void compareGeneratedCodeForToolkitClass() throws Exception { + String genCode = compareCode("org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class"); + int indx = genCode.indexOf("gt = 65604"); + if (indx >= 0) { + fail("Goto to an invalid label:\n...." + genCode.substring(indx - 30, indx + 30) + "...."); + } + } + @BeforeClass public static void compileTheCode() throws Exception { code = TestVM.compileClass("org/apidesign/vm4brwsr/VMinVM"); @@ -49,7 +57,7 @@ code = null; } - private void compareCode(final String nm) throws Exception, IOException { + private String compareCode(final String nm) throws Exception, IOException { byte[] arr = BytesLoader.readClass(nm); String ret1 = VMinVM.toJavaScript(arr); @@ -88,5 +96,7 @@ msg.append(code.toString()); fail(msg.toString()); } + + return ret1; } } diff -r 9b4751828ceb -r b3768be30aa0 rt/vm/src/test/resources/org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class Binary file rt/vm/src/test/resources/org/apidesign/vm4brwsr/Bck2BrwsrToolkit.class has changed diff -r 9b4751828ceb -r b3768be30aa0 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/ByteArithmeticTest.java Thu Mar 21 17:00:54 2013 +0100 @@ -17,6 +17,7 @@ */ package org.apidesign.bck2brwsr.tck; +import org.apidesign.bck2brwsr.core.JavaScriptBody; import org.apidesign.bck2brwsr.vmtest.Compare; import org.apidesign.bck2brwsr.vmtest.VMTest; import org.testng.annotations.Factory; @@ -94,6 +95,50 @@ @Compare public byte divisionReminder() { return mod((byte)1, (byte)2); } + + private static int readShort(byte[] byteCodes, int offset) { + int signed = byteCodes[offset]; + byte b0 = (byte)signed; + return (b0 << 8) | (byteCodes[offset + 1] & 0xff); + } + + private static int readShortArg(byte[] byteCodes, int offsetInstruction) { + return readShort(byteCodes, offsetInstruction + 1); + } + + @Compare public int readIntArgs255and156() { + final byte[] arr = new byte[] { (byte)0, (byte)255, (byte)156 }; + + assert arr[1] == -1 : "First byte: " + arr[1]; + assert arr[2] == -100 : "Second byte: " + arr[2]; + final int ret = readShortArg(arr, 0); + assert ret < 65000: "Value: " + ret; + return ret; + } + + @JavaScriptBody(args = { "arr" }, body = "arr[1] = 255; arr[2] = 156; return arr;") + private static byte[] fill255and156(byte[] arr) { + arr[1] = (byte)255; + arr[2] = (byte)156; + return arr; + } + + @Compare public int readIntArgs255and156JSArray() { + final byte[] arr = fill255and156(new byte[] { 0, 0, 0 }); + + final int ret = readShortArg(arr, 0); + assert ret < 65000: "Value: " + ret; + return ret; + } + + @Compare public int readIntArgsMinus1andMinus100() { + final byte[] arr = new byte[] { (byte)0, (byte)-1, (byte)-100 }; + + assert arr[1] == -1 : "First byte: " + arr[1]; + assert arr[2] == -100 : "Second byte: " + arr[2]; + + return readShortArg(arr, 0); + } @Factory public static Object[] create() { diff -r 9b4751828ceb -r b3768be30aa0 rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java --- a/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java Thu Mar 21 15:45:42 2013 +0100 +++ b/rt/vmtest/src/test/java/org/apidesign/bck2brwsr/tck/StaticUse.java Thu Mar 21 17:00:54 2013 +0100 @@ -19,6 +19,13 @@ class StaticUse { public static final Object NON_NULL = new Object(); + public static int cnt; + static { + if (cnt++ != 0) { + throw new IllegalStateException("Multiple initialization of a "); + } + } + StaticUse() { }