Merging lazyvm into default branch - it seems to be stable enough to be used.
1.1 --- a/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Mon Dec 10 12:03:22 2012 +0100
1.2 +++ b/emul/src/main/resources/org/apidesign/vm4brwsr/emul/java_lang_String.js Wed Dec 12 09:09:42 2012 +0100
1.3 @@ -1,5 +1,5 @@
1.4 // initialize methods on String constants
1.5 -java_lang_String(false);
1.6 +vm.java_lang_String(false);
1.7
1.8 // we need initialized arrays
1.9 Array.prototype.fillNulls = function() {
2.1 --- a/javap/src/main/java/org/apidesign/javap/ClassData.java Mon Dec 10 12:03:22 2012 +0100
2.2 +++ b/javap/src/main/java/org/apidesign/javap/ClassData.java Wed Dec 12 09:09:42 2012 +0100
2.3 @@ -554,14 +554,14 @@
2.4 return in.toString();
2.5 }
2.6 case CONSTANT_CLASS:
2.7 - String jn = javaName(getClassName(cpx));
2.8 + String jn = getClassName(cpx);
2.9 if (textual) {
2.10 if (refs != null) {
2.11 refs[0] = jn;
2.12 }
2.13 - return jn.replace('/', '_') + "(false).constructor.$class";
2.14 + return jn;
2.15 }
2.16 - return jn;
2.17 + return javaName(jn);
2.18 case CONSTANT_STRING:
2.19 String sv = stringValue(((CPX)x).cpx, textual);
2.20 if (textual) {
3.1 --- a/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Mon Dec 10 12:03:22 2012 +0100
3.2 +++ b/javaquery/api/src/test/java/org/apidesign/bck2brwsr/htmlpage/ProcessPageTest.java Wed Dec 12 09:09:42 2012 +0100
3.3 @@ -19,12 +19,12 @@
3.4
3.5 import java.io.IOException;
3.6 import java.io.InputStream;
3.7 -import java.lang.reflect.Method;
3.8 import java.util.Set;
3.9 import javax.script.Invocable;
3.10 import javax.script.ScriptEngine;
3.11 import javax.script.ScriptEngineManager;
3.12 import javax.script.ScriptException;
3.13 +import org.apidesign.vm4brwsr.Bck2Brwsr;
3.14 import org.testng.annotations.Test;
3.15 import static org.testng.Assert.*;
3.16
3.17 @@ -125,15 +125,7 @@
3.18 if (sb == null) {
3.19 sb = new StringBuilder();
3.20 }
3.21 - try {
3.22 - Method m;
3.23 - Class<?> genJS = Class.forName("org.apidesign.vm4brwsr.GenJS");
3.24 - m = genJS.getDeclaredMethod("compile", Appendable.class, String[].class);
3.25 - m.setAccessible(true);
3.26 - m.invoke(null, sb, names);
3.27 - } catch (Exception exception) {
3.28 - throw new IOException(exception);
3.29 - }
3.30 + Bck2Brwsr.generate(sb, ProcessPageTest.class.getClassLoader(), names);
3.31 ScriptEngineManager sem = new ScriptEngineManager();
3.32 ScriptEngine js = sem.getEngineByExtension("js");
3.33 try {
4.1 --- a/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Bck2BrswrMojo.java Mon Dec 10 12:03:22 2012 +0100
4.2 +++ b/mojo/src/main/java/org/apidesign/bck2brwsr/mojo/Bck2BrswrMojo.java Wed Dec 12 09:09:42 2012 +0100
4.3 @@ -21,7 +21,7 @@
4.4
4.5 import java.io.File;
4.6 import java.io.FileWriter;
4.7 -import java.lang.reflect.Method;
4.8 +import java.io.IOException;
4.9 import java.net.MalformedURLException;
4.10 import java.net.URL;
4.11 import java.net.URLClassLoader;
4.12 @@ -34,6 +34,7 @@
4.13 import org.apache.maven.plugins.annotations.Mojo;
4.14 import org.apache.maven.plugins.annotations.Parameter;
4.15 import org.apache.maven.project.MavenProject;
4.16 +import org.apidesign.vm4brwsr.Bck2Brwsr;
4.17
4.18 /** Compiles classes into JavaScript. */
4.19 @Mojo(name="j2js", defaultPhase=LifecyclePhase.PROCESS_CLASSES)
4.20 @@ -72,14 +73,10 @@
4.21
4.22 try {
4.23 URLClassLoader url = buildClassLoader(classes, prj.getDependencyArtifacts());
4.24 -
4.25 - Class<?> c = Class.forName("org.apidesign.vm4brwsr.GenJS");
4.26 - Method m = c.getDeclaredMethod("compile", ClassLoader.class, Appendable.class, String[].class);
4.27 - m.setAccessible(true);
4.28 FileWriter w = new FileWriter(javascript);
4.29 - m.invoke(null, url, w, arr.toArray(new String[0]));
4.30 + Bck2Brwsr.generate(w, url, arr.toArray(new String[0]));
4.31 w.close();
4.32 - } catch (Exception ex) {
4.33 + } catch (IOException ex) {
4.34 throw new MojoExecutionException("Can't compile", ex);
4.35 }
4.36 }
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java Wed Dec 12 09:09:42 2012 +0100
5.3 @@ -0,0 +1,106 @@
5.4 +/**
5.5 + * Back 2 Browser Bytecode Translator
5.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5.7 + *
5.8 + * This program is free software: you can redistribute it and/or modify
5.9 + * it under the terms of the GNU General Public License as published by
5.10 + * the Free Software Foundation, version 2 of the License.
5.11 + *
5.12 + * This program is distributed in the hope that it will be useful,
5.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
5.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5.15 + * GNU General Public License for more details.
5.16 + *
5.17 + * You should have received a copy of the GNU General Public License
5.18 + * along with this program. Look for COPYING file in the top folder.
5.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
5.20 + */
5.21 +package org.apidesign.vm4brwsr;
5.22 +
5.23 +import java.io.IOException;
5.24 +import java.io.InputStream;
5.25 +import java.net.URL;
5.26 +import java.util.Enumeration;
5.27 +
5.28 +/** Build your own virtual machine! Use methods in this class to generate
5.29 + * a skeleton JVM in JavaScript that contains pre-compiled classes of your
5.30 + * choice. The generated script defines one JavaScript method that can
5.31 + * be used to bootstrap and load the virtual machine: <pre>
5.32 + * var vm = bck2brwsr();
5.33 + * var main = vm.loadClass('org.your.pkg.Main');
5.34 + * main.main__V_3Ljava_lang_String_2(null);
5.35 + * </pre>
5.36 + * In case one wants to initialize the virtual machine with ability to
5.37 + * load classes lazily when needed, one can provide a loader function to
5.38 + * when creating the virtual machine: <pre>
5.39 + * var vm = bck2brwsr(function(resource) {
5.40 + * return null; // byte[] for the resource
5.41 + * });
5.42 + * </pre>
5.43 + * In this scenario, when a request for a unknown class is made, the loader
5.44 + * function is asked for its byte code and the system dynamically transforms
5.45 + * it to JavaScript.
5.46 + *
5.47 + * @author Jaroslav Tulach <jtulach@netbeans.org>
5.48 + */
5.49 +public final class Bck2Brwsr {
5.50 + private Bck2Brwsr() {
5.51 + }
5.52 +
5.53 + /** Generates virtual machine from bytes served by a <code>resources</code>
5.54 + * provider.
5.55 + *
5.56 + * @param out the output to write the generated JavaScript to
5.57 + * @param resources provider of class files to use
5.58 + * @param classes additional classes to include in the generated script
5.59 + * @throws IOException I/O exception can be thrown when something goes wrong
5.60 + */
5.61 + public static void generate(Appendable out, Resources resources, String... classes) throws IOException {
5.62 + StringArray arr = StringArray.asList(classes);
5.63 + arr.add(VM.class.getName().replace('.', '/'));
5.64 + VM.compile(resources, out, arr);
5.65 + }
5.66 +
5.67 + /** Generates virtual machine from bytes served by a class loader.
5.68 + *
5.69 + * @param out the output to write the generated JavaScript to
5.70 + * @param loader class loader to load needed classes from
5.71 + * @param classes additional classes to include in the generated script
5.72 + * @throws IOException I/O exception can be thrown when something goes wrong
5.73 + */
5.74 + public static void generate(Appendable out, final ClassLoader loader, String... classes) throws IOException {
5.75 + class R implements Resources {
5.76 + @Override
5.77 + public InputStream get(String name) throws IOException {
5.78 + Enumeration<URL> en = loader.getResources(name);
5.79 + URL u = null;
5.80 + while (en.hasMoreElements()) {
5.81 + u = en.nextElement();
5.82 + }
5.83 + if (u == null) {
5.84 + throw new IOException("Can't find " + name);
5.85 + }
5.86 + return u.openStream();
5.87 + }
5.88 + }
5.89 + generate(out, new R(), classes);
5.90 + }
5.91 +
5.92 + /** Provider of resources (classes and other files). The
5.93 + * {@link #generate(java.lang.Appendable, org.apidesign.vm4brwsr.Bck2Brwsr.Resources, java.lang.String[])
5.94 + * generator method} will call back here for all classes needed during
5.95 + * translation to JavaScript.
5.96 + */
5.97 + public interface Resources {
5.98 + /** Loads given resource (class or other file like image). The
5.99 + * resource name to load bytes for the {@link String} class
5.100 + * would be <code>"java/lang/String.class"</code>.
5.101 + *
5.102 + * @param resource path to resource to load
5.103 + * @return the input stream for the resource
5.104 + * @throws IOException can be thrown if the loading fails on some error
5.105 + * or the file cannot be found
5.106 + */
5.107 + public InputStream get(String resource) throws IOException;
5.108 + }
5.109 +}
6.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Mon Dec 10 12:03:22 2012 +0100
6.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java Wed Dec 12 09:09:42 2012 +0100
6.3 @@ -19,6 +19,7 @@
6.4
6.5 import java.io.IOException;
6.6 import java.io.InputStream;
6.7 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
6.8 import org.apidesign.javap.AnnotationParser;
6.9 import org.apidesign.javap.ClassData;
6.10 import org.apidesign.javap.FieldData;
6.11 @@ -29,7 +30,7 @@
6.12 *
6.13 * @author Jaroslav Tulach <jtulach@netbeans.org>
6.14 */
6.15 -public abstract class ByteCodeToJavaScript {
6.16 +abstract class ByteCodeToJavaScript {
6.17 private ClassData jc;
6.18 final Appendable out;
6.19
6.20 @@ -56,9 +57,12 @@
6.21 *
6.22 * @param className suggested name of the class
6.23 */
6.24 - protected String assignClass(String className) {
6.25 + /* protected */ String assignClass(String className) {
6.26 return className + " = ";
6.27 }
6.28 + /* protected */ String accessClass(String classOperation) {
6.29 + return classOperation;
6.30 + }
6.31
6.32 /**
6.33 * Converts a given class file to a JavaScript version.
6.34 @@ -99,7 +103,7 @@
6.35 if (proto == null) {
6.36 String sc = jc.getSuperClassName(); // with _
6.37 out.append("\n var pp = ").
6.38 - append(sc.replace('/', '_')).append("(true);");
6.39 + append(accessClass(sc.replace('/', '_'))).append("(true);");
6.40 out.append("\n var p = CLS.prototype = pp;");
6.41 out.append("\n var c = p;");
6.42 out.append("\n var sprcls = pp.constructor.$class;");
6.43 @@ -139,7 +143,8 @@
6.44 for (String superInterface : jc.getSuperInterfaces()) {
6.45 out.append("\n c.$instOf_").append(superInterface.replace('/', '_')).append(" = true;");
6.46 }
6.47 - out.append("\n CLS.$class = java_lang_Class(true);");
6.48 + out.append("\n CLS.$class = ");
6.49 + out.append(accessClass("java_lang_Class(true);"));
6.50 out.append("\n CLS.$class.jvmName = '").append(jc.getClassName()).append("';");
6.51 out.append("\n CLS.$class.superclass = sprcls;");
6.52 out.append("\n CLS.$class.cnstr = CLS;");
6.53 @@ -191,7 +196,7 @@
6.54 final String mn = findMethodName(m, argsCnt);
6.55 out.append(prefix).append(mn).append(" = function");
6.56 if (mn.equals("class__V")) {
6.57 - toInitilize.add(className(jc) + "(false)." + mn);
6.58 + toInitilize.add(accessClass(className(jc)) + "(false)." + mn);
6.59 }
6.60 out.append('(');
6.61 String space = "";
6.62 @@ -638,7 +643,7 @@
6.63 int indx = readIntArg(byteCodes, i);
6.64 String ci = jc.getClassName(indx);
6.65 out.append("s.push(new ");
6.66 - out.append(ci.replace('/','_'));
6.67 + out.append(accessClass(ci.replace('/','_')));
6.68 out.append("());");
6.69 addReference(ci);
6.70 i += 2;
6.71 @@ -731,7 +736,7 @@
6.72 case opc_getstatic: {
6.73 int indx = readIntArg(byteCodes, i);
6.74 String[] fi = jc.getFieldInfoName(indx);
6.75 - out.append("s.push(").append(fi[0].replace('/', '_'));
6.76 + out.append("s.push(").append(accessClass(fi[0].replace('/', '_')));
6.77 out.append('.').append(fi[1]).append(");");
6.78 i += 2;
6.79 addReference(fi[0]);
6.80 @@ -740,7 +745,7 @@
6.81 case opc_putstatic: {
6.82 int indx = readIntArg(byteCodes, i);
6.83 String[] fi = jc.getFieldInfoName(indx);
6.84 - out.append(fi[0].replace('/', '_'));
6.85 + out.append(accessClass(fi[0].replace('/', '_')));
6.86 out.append('.').append(fi[1]).append(" = s.pop();");
6.87 i += 2;
6.88 addReference(fi[0]);
6.89 @@ -951,7 +956,7 @@
6.90 out.append("s.push(");
6.91 }
6.92 final String in = mi[0];
6.93 - out.append(in.replace('/', '_'));
6.94 + out.append(accessClass(in.replace('/', '_')));
6.95 out.append("(false).");
6.96 out.append(mn);
6.97 out.append('(');
6.98 @@ -1031,6 +1036,7 @@
6.99 String s = jc.stringValue(entryIndex, classRef);
6.100 if (classRef[0] != null) {
6.101 addReference(classRef[0]);
6.102 + s = accessClass(s.replace('/', '_')) + "(false).constructor.$class";
6.103 }
6.104 return s;
6.105 }
7.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java Mon Dec 10 12:03:22 2012 +0100
7.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
7.3 @@ -1,198 +0,0 @@
7.4 -/**
7.5 - * Back 2 Browser Bytecode Translator
7.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
7.7 - *
7.8 - * This program is free software: you can redistribute it and/or modify
7.9 - * it under the terms of the GNU General Public License as published by
7.10 - * the Free Software Foundation, version 2 of the License.
7.11 - *
7.12 - * This program is distributed in the hope that it will be useful,
7.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
7.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7.15 - * GNU General Public License for more details.
7.16 - *
7.17 - * You should have received a copy of the GNU General Public License
7.18 - * along with this program. Look for COPYING file in the top folder.
7.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
7.20 - */
7.21 -package org.apidesign.vm4brwsr;
7.22 -
7.23 -import java.io.IOException;
7.24 -import java.io.InputStream;
7.25 -import java.net.URL;
7.26 -import java.util.Enumeration;
7.27 -
7.28 -/** Generator of JavaScript from bytecode of classes on classpath of the VM.
7.29 - *
7.30 - * @author Jaroslav Tulach <jtulach@netbeans.org>
7.31 - */
7.32 -class GenJS extends ByteCodeToJavaScript {
7.33 - public GenJS(Appendable out) {
7.34 - super(out);
7.35 - }
7.36 -
7.37 - static void compile(Appendable out, String... names) throws IOException {
7.38 - compile(out, StringArray.asList(names));
7.39 - }
7.40 - static void compile(ClassLoader l, Appendable out, String... names) throws IOException {
7.41 - compile(l, out, StringArray.asList(names));
7.42 - }
7.43 - static void compile(Appendable out, StringArray names) throws IOException {
7.44 - compile(GenJS.class.getClassLoader(), out, names);
7.45 - }
7.46 - static void compile(ClassLoader l, Appendable out, StringArray names) throws IOException {
7.47 - new GenJS(out).doCompile(l, names);
7.48 - }
7.49 - protected void doCompile(ClassLoader l, StringArray names) throws IOException {
7.50 - StringArray processed = new StringArray();
7.51 - StringArray initCode = new StringArray();
7.52 - for (String baseClass : names.toArray()) {
7.53 - references.add(baseClass);
7.54 - for (;;) {
7.55 - String name = null;
7.56 - for (String n : references.toArray()) {
7.57 - if (processed.contains(n)) {
7.58 - continue;
7.59 - }
7.60 - name = n;
7.61 - }
7.62 - if (name == null) {
7.63 - break;
7.64 - }
7.65 - InputStream is = loadClass(l, name);
7.66 - if (is == null) {
7.67 - throw new IOException("Can't find class " + name);
7.68 - }
7.69 - try {
7.70 - String ic = compile(is);
7.71 - processed.add(name);
7.72 - initCode.add(ic == null ? "" : ic);
7.73 - } catch (RuntimeException ex) {
7.74 - if (out instanceof CharSequence) {
7.75 - CharSequence seq = (CharSequence)out;
7.76 - int lastBlock = seq.length();
7.77 - while (lastBlock-- > 0) {
7.78 - if (seq.charAt(lastBlock) == '{') {
7.79 - break;
7.80 - }
7.81 - }
7.82 - throw new IOException("Error while compiling " + name + "\n"
7.83 - + seq.subSequence(lastBlock + 1, seq.length()), ex
7.84 - );
7.85 - } else {
7.86 - throw new IOException("Error while compiling " + name + "\n"
7.87 - + out, ex
7.88 - );
7.89 - }
7.90 - }
7.91 - }
7.92 -
7.93 - for (String resource : scripts.toArray()) {
7.94 - while (resource.startsWith("/")) {
7.95 - resource = resource.substring(1);
7.96 - }
7.97 - InputStream emul = l.getResourceAsStream(resource);
7.98 - if (emul == null) {
7.99 - throw new IOException("Can't find " + resource);
7.100 - }
7.101 - readResource(emul, out);
7.102 - }
7.103 - scripts = new StringArray();
7.104 -
7.105 - StringArray toInit = StringArray.asList(references.toArray());
7.106 - toInit.reverse();
7.107 -
7.108 - for (String ic : toInit.toArray()) {
7.109 - int indx = processed.indexOf(ic);
7.110 - if (indx >= 0) {
7.111 - out.append(initCode.toArray()[indx]).append("\n");
7.112 - initCode.toArray()[indx] = "";
7.113 - }
7.114 - }
7.115 -
7.116 - }
7.117 - }
7.118 - private static void readResource(InputStream emul, Appendable out) throws IOException {
7.119 - try {
7.120 - int state = 0;
7.121 - for (;;) {
7.122 - int ch = emul.read();
7.123 - if (ch == -1) {
7.124 - break;
7.125 - }
7.126 - if (ch < 0 || ch > 255) {
7.127 - throw new IOException("Invalid char in emulation " + ch);
7.128 - }
7.129 - switch (state) {
7.130 - case 0:
7.131 - if (ch == '/') {
7.132 - state = 1;
7.133 - } else {
7.134 - out.append((char)ch);
7.135 - }
7.136 - break;
7.137 - case 1:
7.138 - if (ch == '*') {
7.139 - state = 2;
7.140 - } else {
7.141 - out.append('/').append((char)ch);
7.142 - state = 0;
7.143 - }
7.144 - break;
7.145 - case 2:
7.146 - if (ch == '*') {
7.147 - state = 3;
7.148 - }
7.149 - break;
7.150 - case 3:
7.151 - if (ch == '/') {
7.152 - state = 0;
7.153 - } else {
7.154 - state = 2;
7.155 - }
7.156 - break;
7.157 - }
7.158 - }
7.159 - } finally {
7.160 - emul.close();
7.161 - }
7.162 - }
7.163 -
7.164 - private static InputStream loadClass(ClassLoader l, String name) throws IOException {
7.165 - Enumeration<URL> en = l.getResources(name + ".class");
7.166 - URL u = null;
7.167 - while (en.hasMoreElements()) {
7.168 - u = en.nextElement();
7.169 - }
7.170 - if (u == null) {
7.171 - throw new IOException("Can't find " + name);
7.172 - }
7.173 - if (u.toExternalForm().contains("rt.jar!")) {
7.174 - throw new IOException("No emulation for " + u);
7.175 - }
7.176 - return u.openStream();
7.177 - }
7.178 -
7.179 - static String toString(String name) throws IOException {
7.180 - StringBuilder sb = new StringBuilder();
7.181 - compile(sb, name);
7.182 - return sb.toString().toString();
7.183 - }
7.184 -
7.185 - private StringArray scripts = new StringArray();
7.186 - private StringArray references = new StringArray();
7.187 -
7.188 - @Override
7.189 - protected boolean requireReference(String cn) {
7.190 - if (references.contains(cn)) {
7.191 - return false;
7.192 - }
7.193 - references.add(cn);
7.194 - return true;
7.195 - }
7.196 -
7.197 - @Override
7.198 - protected void requireScript(String resourcePath) {
7.199 - scripts.add(resourcePath);
7.200 - }
7.201 -}
8.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Mon Dec 10 12:03:22 2012 +0100
8.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Main.java Wed Dec 12 09:09:42 2012 +0100
8.3 @@ -32,6 +32,7 @@
8.4
8.5 public static void main(String... args) throws IOException {
8.6 if (args.length < 2) {
8.7 + System.err.println("Bck2Brwsr Translator from Java(tm) to JavaScript, (c) Jaroslav Tulach 2012");
8.8 System.err.println("Usage: java -cp ... -jar ... <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
8.9 return;
8.10 }
8.11 @@ -39,7 +40,7 @@
8.12 Writer w = new BufferedWriter(new FileWriter(args[0]));
8.13 StringArray classes = StringArray.asList(args);
8.14 classes.delete(0);
8.15 - GenJS.compile(w, classes);
8.16 + Bck2Brwsr.generate(w, Main.class.getClassLoader(), classes.toArray());
8.17 w.close();
8.18 }
8.19 }
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VM.java Wed Dec 12 09:09:42 2012 +0100
9.3 @@ -0,0 +1,208 @@
9.4 +/**
9.5 + * Back 2 Browser Bytecode Translator
9.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
9.7 + *
9.8 + * This program is free software: you can redistribute it and/or modify
9.9 + * it under the terms of the GNU General Public License as published by
9.10 + * the Free Software Foundation, version 2 of the License.
9.11 + *
9.12 + * This program is distributed in the hope that it will be useful,
9.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
9.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9.15 + * GNU General Public License for more details.
9.16 + *
9.17 + * You should have received a copy of the GNU General Public License
9.18 + * along with this program. Look for COPYING file in the top folder.
9.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
9.20 + */
9.21 +package org.apidesign.vm4brwsr;
9.22 +
9.23 +import java.io.IOException;
9.24 +import java.io.InputStream;
9.25 +
9.26 +/** Generator of JavaScript from bytecode of classes on classpath of the VM.
9.27 + *
9.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
9.29 + */
9.30 +class VM extends ByteCodeToJavaScript {
9.31 + public VM(Appendable out) {
9.32 + super(out);
9.33 + }
9.34 +
9.35 + static {
9.36 + // uses VMLazy to load dynamic classes
9.37 + VMLazy.init();
9.38 + }
9.39 +
9.40 + static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException {
9.41 + new VM(out).doCompile(l, names);
9.42 + }
9.43 + protected void doCompile(Bck2Brwsr.Resources l, StringArray names) throws IOException {
9.44 + out.append("(function VM(global) {");
9.45 + out.append("\n var vm = {};");
9.46 + StringArray processed = new StringArray();
9.47 + StringArray initCode = new StringArray();
9.48 + for (String baseClass : names.toArray()) {
9.49 + references.add(baseClass);
9.50 + for (;;) {
9.51 + String name = null;
9.52 + for (String n : references.toArray()) {
9.53 + if (processed.contains(n)) {
9.54 + continue;
9.55 + }
9.56 + name = n;
9.57 + }
9.58 + if (name == null) {
9.59 + break;
9.60 + }
9.61 + InputStream is = loadClass(l, name);
9.62 + if (is == null) {
9.63 + throw new IOException("Can't find class " + name);
9.64 + }
9.65 + try {
9.66 + String ic = compile(is);
9.67 + processed.add(name);
9.68 + initCode.add(ic == null ? "" : ic);
9.69 + } catch (RuntimeException ex) {
9.70 + if (out instanceof CharSequence) {
9.71 + CharSequence seq = (CharSequence)out;
9.72 + int lastBlock = seq.length();
9.73 + while (lastBlock-- > 0) {
9.74 + if (seq.charAt(lastBlock) == '{') {
9.75 + break;
9.76 + }
9.77 + }
9.78 + throw new IOException("Error while compiling " + name + "\n"
9.79 + + seq.subSequence(lastBlock + 1, seq.length()), ex
9.80 + );
9.81 + } else {
9.82 + throw new IOException("Error while compiling " + name + "\n"
9.83 + + out, ex
9.84 + );
9.85 + }
9.86 + }
9.87 + }
9.88 +
9.89 + for (String resource : scripts.toArray()) {
9.90 + while (resource.startsWith("/")) {
9.91 + resource = resource.substring(1);
9.92 + }
9.93 + InputStream emul = l.get(resource);
9.94 + if (emul == null) {
9.95 + throw new IOException("Can't find " + resource);
9.96 + }
9.97 + readResource(emul, out);
9.98 + }
9.99 + scripts = new StringArray();
9.100 +
9.101 + StringArray toInit = StringArray.asList(references.toArray());
9.102 + toInit.reverse();
9.103 +
9.104 + for (String ic : toInit.toArray()) {
9.105 + int indx = processed.indexOf(ic);
9.106 + if (indx >= 0) {
9.107 + out.append(initCode.toArray()[indx]).append("\n");
9.108 + initCode.toArray()[indx] = "";
9.109 + }
9.110 + }
9.111 + }
9.112 + out.append(
9.113 + " global.bck2brwsr = function() {\n"
9.114 + + " var args = arguments;\n"
9.115 + + " var loader = {};\n"
9.116 + + " loader.vm = vm;\n"
9.117 + + " loader.loadClass = function(name) {\n"
9.118 + + " var attr = name.replace__Ljava_lang_String_2CC(name, '.','_');\n"
9.119 + + " var fn = vm[attr];\n"
9.120 + + " if (fn) return fn(false);\n"
9.121 + + " if (!args[0]) throw 'bck2brwsr initialized without loader function, cannot load ' + name;\n"
9.122 + + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
9.123 + + " load___3Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
9.124 + + " }\n"
9.125 + + " return loader;\n"
9.126 + + " };\n");
9.127 + out.append("}(this));");
9.128 + }
9.129 + private static void readResource(InputStream emul, Appendable out) throws IOException {
9.130 + try {
9.131 + int state = 0;
9.132 + for (;;) {
9.133 + int ch = emul.read();
9.134 + if (ch == -1) {
9.135 + break;
9.136 + }
9.137 + if (ch < 0 || ch > 255) {
9.138 + throw new IOException("Invalid char in emulation " + ch);
9.139 + }
9.140 + switch (state) {
9.141 + case 0:
9.142 + if (ch == '/') {
9.143 + state = 1;
9.144 + } else {
9.145 + out.append((char)ch);
9.146 + }
9.147 + break;
9.148 + case 1:
9.149 + if (ch == '*') {
9.150 + state = 2;
9.151 + } else {
9.152 + out.append('/').append((char)ch);
9.153 + state = 0;
9.154 + }
9.155 + break;
9.156 + case 2:
9.157 + if (ch == '*') {
9.158 + state = 3;
9.159 + }
9.160 + break;
9.161 + case 3:
9.162 + if (ch == '/') {
9.163 + state = 0;
9.164 + } else {
9.165 + state = 2;
9.166 + }
9.167 + break;
9.168 + }
9.169 + }
9.170 + } finally {
9.171 + emul.close();
9.172 + }
9.173 + }
9.174 +
9.175 + private static InputStream loadClass(Bck2Brwsr.Resources l, String name) throws IOException {
9.176 + return l.get(name + ".class"); // NOI18N
9.177 + }
9.178 +
9.179 + static String toString(String name) throws IOException {
9.180 + StringBuilder sb = new StringBuilder();
9.181 +// compile(sb, name);
9.182 + return sb.toString().toString();
9.183 + }
9.184 +
9.185 + private StringArray scripts = new StringArray();
9.186 + private StringArray references = new StringArray();
9.187 +
9.188 + @Override
9.189 + protected boolean requireReference(String cn) {
9.190 + if (references.contains(cn)) {
9.191 + return false;
9.192 + }
9.193 + references.add(cn);
9.194 + return true;
9.195 + }
9.196 +
9.197 + @Override
9.198 + protected void requireScript(String resourcePath) {
9.199 + scripts.add(resourcePath);
9.200 + }
9.201 +
9.202 + @Override
9.203 + String assignClass(String className) {
9.204 + return "vm." + className + " = ";
9.205 + }
9.206 +
9.207 + @Override
9.208 + String accessClass(String className) {
9.209 + return "vm." + className;
9.210 + }
9.211 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Wed Dec 12 09:09:42 2012 +0100
10.3 @@ -0,0 +1,129 @@
10.4 +/**
10.5 + * Back 2 Browser Bytecode Translator
10.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
10.7 + *
10.8 + * This program is free software: you can redistribute it and/or modify
10.9 + * it under the terms of the GNU General Public License as published by
10.10 + * the Free Software Foundation, version 2 of the License.
10.11 + *
10.12 + * This program is distributed in the hope that it will be useful,
10.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
10.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10.15 + * GNU General Public License for more details.
10.16 + *
10.17 + * You should have received a copy of the GNU General Public License
10.18 + * along with this program. Look for COPYING file in the top folder.
10.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
10.20 + */
10.21 +package org.apidesign.vm4brwsr;
10.22 +
10.23 +import java.io.ByteArrayInputStream;
10.24 +import java.io.IOException;
10.25 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
10.26 +
10.27 +/**
10.28 + *
10.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
10.30 + */
10.31 +final class VMLazy {
10.32 + private final Object loader;
10.33 + private final Object[] args;
10.34 +
10.35 + private VMLazy(Object loader, Object[] args) {
10.36 + this.loader = loader;
10.37 + this.args = args;
10.38 + }
10.39 +
10.40 + static void init() {
10.41 + }
10.42 +
10.43 + @JavaScriptBody(args={"l", "res", "args" }, body = ""
10.44 + + "\ntry {"
10.45 + + "\n return args[0](res.toString());"
10.46 + + "\n} catch (x) {"
10.47 + + "\n throw Object.getOwnPropertyNames(l.vm).toString() + x.toString();"
10.48 + + "\n}")
10.49 + private static native byte[] read(Object l, String res, Object[] args);
10.50 +
10.51 + static Object load(Object loader, String name, Object[] arguments)
10.52 + throws IOException, ClassNotFoundException {
10.53 + return new VMLazy(loader, arguments).load(name);
10.54 + }
10.55 +
10.56 + private Object load(String name)
10.57 + throws IOException, ClassNotFoundException {
10.58 + String res = name.replace('.', '/') + ".class";
10.59 + byte[] arr = read(loader, res, args);
10.60 + if (arr == null) {
10.61 + throw new ClassNotFoundException(name);
10.62 + }
10.63 +// beingDefined(loader, name);
10.64 + StringBuilder out = new StringBuilder();
10.65 + out.append("var loader = arguments[0];\n");
10.66 + out.append("var vm = loader.vm;\n");
10.67 + new Gen(this, out).compile(new ByteArrayInputStream(arr));
10.68 + String code = out.toString().toString();
10.69 + String under = name.replace('.', '_');
10.70 + return applyCode(loader, under, code);
10.71 + }
10.72 +
10.73 +/* possibly not needed:
10.74 + @JavaScriptBody(args = {"loader", "n" }, body =
10.75 + "var cls = n.replace__Ljava_lang_String_2CC(n, '.','_').toString();" +
10.76 + "loader.vm[cls] = true;\n"
10.77 + )
10.78 + private static native void beingDefined(Object loader, String name);
10.79 +*/
10.80 +
10.81 +
10.82 + @JavaScriptBody(args = {"loader", "name", "script" }, body =
10.83 + "try {\n" +
10.84 + " new Function(script)(loader, name);\n" +
10.85 + "} catch (ex) {\n" +
10.86 + " throw 'Cannot compile ' + ex + ' line: ' + ex.lineNumber + ' script:\\n' + script;\n" +
10.87 + "}\n" +
10.88 + "return vm[name](false);\n"
10.89 + )
10.90 + private static native Object applyCode(Object loader, String name, String script);
10.91 +
10.92 +
10.93 + private static final class Gen extends ByteCodeToJavaScript {
10.94 + private final VMLazy lazy;
10.95 +
10.96 + public Gen(VMLazy vm, Appendable out) {
10.97 + super(out);
10.98 + this.lazy = vm;
10.99 + }
10.100 +
10.101 + @JavaScriptBody(args = {"self", "n"},
10.102 + body =
10.103 + "var cls = n.replace__Ljava_lang_String_2CC(n, '/','_').toString();"
10.104 + + "\nvar dot = n.replace__Ljava_lang_String_2CC(n,'/','.').toString();"
10.105 + + "\nvar lazy = self.fld_lazy;"
10.106 + + "\nvar loader = lazy.fld_loader;"
10.107 + + "\nvar vm = loader.vm;"
10.108 + + "\nif (vm[cls]) return false;"
10.109 + + "\nvm[cls] = function() {"
10.110 + + "\n return lazy.load__Ljava_lang_Object_2Ljava_lang_String_2(lazy, dot);"
10.111 + + "\n};"
10.112 + + "\nreturn true;")
10.113 + @Override
10.114 + protected boolean requireReference(String internalClassName) {
10.115 + throw new UnsupportedOperationException();
10.116 + }
10.117 +
10.118 + @Override
10.119 + protected void requireScript(String resourcePath) {
10.120 + }
10.121 +
10.122 + @Override
10.123 + String assignClass(String className) {
10.124 + return "vm[arguments[1]]=";
10.125 + }
10.126 +
10.127 + @Override
10.128 + String accessClass(String classOperation) {
10.129 + return "vm." + classOperation;
10.130 + }
10.131 + }
10.132 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java Wed Dec 12 09:09:42 2012 +0100
11.3 @@ -0,0 +1,58 @@
11.4 +/**
11.5 + * Back 2 Browser Bytecode Translator
11.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
11.7 + *
11.8 + * This program is free software: you can redistribute it and/or modify
11.9 + * it under the terms of the GNU General Public License as published by
11.10 + * the Free Software Foundation, version 2 of the License.
11.11 + *
11.12 + * This program is distributed in the hope that it will be useful,
11.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
11.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11.15 + * GNU General Public License for more details.
11.16 + *
11.17 + * You should have received a copy of the GNU General Public License
11.18 + * along with this program. Look for COPYING file in the top folder.
11.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
11.20 + */
11.21 +package org.apidesign.vm4brwsr;
11.22 +
11.23 +import java.io.IOException;
11.24 +import java.io.InputStream;
11.25 +import java.util.Set;
11.26 +import java.util.TreeSet;
11.27 +
11.28 +/**
11.29 + *
11.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
11.31 + */
11.32 +public final class BytesLoader {
11.33 + private static Set<String> requested = new TreeSet<String>();
11.34 +
11.35 + public byte[] get(String name) throws IOException {
11.36 + if (!requested.add(name)) {
11.37 + throw new IllegalStateException("Requested for second time: " + name);
11.38 + }
11.39 + InputStream is = BytesLoader.class.getClassLoader().getResourceAsStream(name);
11.40 + if (is == null) {
11.41 + throw new IOException("Can't find " + name);
11.42 + }
11.43 + byte[] arr = new byte[is.available()];
11.44 + int len = is.read(arr);
11.45 + if (len != arr.length) {
11.46 + throw new IOException("Read only " + len + " wanting " + arr.length);
11.47 + }
11.48 + /*
11.49 + System.err.print("loader['" + name + "'] = [");
11.50 + for (int i = 0; i < arr.length; i++) {
11.51 + if (i > 0) {
11.52 + System.err.print(", ");
11.53 + }
11.54 + System.err.print(arr[i]);
11.55 + }
11.56 + System.err.println("]");
11.57 + */
11.58 + return arr;
11.59 + }
11.60 +
11.61 +}
12.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Mon Dec 10 12:03:22 2012 +0100
12.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/ClassTest.java Wed Dec 12 09:09:42 2012 +0100
12.3 @@ -110,6 +110,12 @@
12.4 "java.io.IOException", false, null
12.5 );
12.6 }
12.7 + @Test public void jsClassParam() throws Exception {
12.8 + assertExec("Calls the nameOfIO()", Classes.class,
12.9 + "nameOfIO__Ljava_lang_String_2",
12.10 + "java.io.IOException"
12.11 + );
12.12 + }
12.13
12.14 private static CharSequence codeSeq;
12.15 private static Invocable code;
13.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Mon Dec 10 12:03:22 2012 +0100
13.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/Classes.java Wed Dec 12 09:09:42 2012 +0100
13.3 @@ -30,6 +30,14 @@
13.4 @ClassesMarker(number = 10)
13.5 @ClassesNamer(name = "my text")
13.6 public class Classes {
13.7 + public static String nameOfIO() {
13.8 + return nameFor(IOException.class);
13.9 + }
13.10 +
13.11 + private static String nameFor(Class<?> c) {
13.12 + return c.getName();
13.13 + }
13.14 +
13.15 public static boolean equalsClassesOfExceptions() {
13.16 return MalformedURLException.class.getSuperclass() == IOException.class;
13.17 }
14.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java Mon Dec 10 12:03:22 2012 +0100
14.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java Wed Dec 12 09:09:42 2012 +0100
14.3 @@ -21,6 +21,7 @@
14.4 import java.util.Map;
14.5 import java.util.WeakHashMap;
14.6 import javax.script.Invocable;
14.7 +import javax.script.ScriptContext;
14.8 import javax.script.ScriptEngine;
14.9 import javax.script.ScriptEngineManager;
14.10 import org.testng.Assert;
14.11 @@ -104,26 +105,17 @@
14.12 return;
14.13 }
14.14 StringBuilder sb = new StringBuilder();
14.15 - class SkipMe extends GenJS {
14.16 -
14.17 - public SkipMe(Appendable out) {
14.18 - super(out);
14.19 - }
14.20 -
14.21 - @Override
14.22 - protected boolean requireReference(String cn) {
14.23 - if (cn.contains("CompareVMs")) {
14.24 - return true;
14.25 - }
14.26 - return super.requireReference(cn);
14.27 - }
14.28 - }
14.29 - SkipMe sm = new SkipMe(sb);
14.30 - sm.doCompile(CompareVMs.class.getClassLoader(), StringArray.asList(
14.31 - clazz.getName().replace('.', '/')));
14.32 + Bck2Brwsr.generate(sb, CompareVMs.class.getClassLoader());
14.33
14.34 ScriptEngineManager sem = new ScriptEngineManager();
14.35 ScriptEngine js = sem.getEngineByExtension("js");
14.36 + js.getContext().setAttribute("loader", new BytesLoader(), ScriptContext.ENGINE_SCOPE);
14.37 +
14.38 + sb.append("\nfunction initVM() {"
14.39 + + "\n return bck2brwsr("
14.40 + + "\n function(name) { return loader.get(name);}"
14.41 + + "\n );"
14.42 + + "\n};");
14.43
14.44 Object res = js.eval(sb.toString());
14.45 Assert.assertTrue(js instanceof Invocable, "It is invocable object: " + res);
14.46 @@ -136,7 +128,8 @@
14.47 if (js) {
14.48 try {
14.49 compileTheCode(m.getDeclaringClass());
14.50 - Object inst = code.invokeFunction(m.getDeclaringClass().getName().replace('.', '_'), false);
14.51 + Object vm = code.invokeFunction("initVM");
14.52 + Object inst = code.invokeMethod(vm, "loadClass", m.getDeclaringClass().getName());
14.53 value = code.invokeMethod(inst, m.getName() + "__" + computeSignature(m));
14.54 } catch (Exception ex) {
14.55 throw new AssertionError(StaticMethodTest.dumpJS(codeSeq)).initCause(ex);
15.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Mon Dec 10 12:03:22 2012 +0100
15.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/NumberTest.java Wed Dec 12 09:09:42 2012 +0100
15.3 @@ -161,7 +161,8 @@
15.4
15.5 Object ret = null;
15.6 try {
15.7 - ret = code.invokeFunction(clazz.getName().replace('.', '_'), true);
15.8 + ret = code.invokeFunction("bck2brwsr");
15.9 + ret = code.invokeMethod(ret, "loadClass", clazz.getName());
15.10 ret = code.invokeMethod(ret, method, args);
15.11 } catch (ScriptException ex) {
15.12 fail("Execution failed in\n" + StaticMethodTest.dumpJS(codeSeq), ex);
16.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Mon Dec 10 12:03:22 2012 +0100
16.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java Wed Dec 12 09:09:42 2012 +0100
16.3 @@ -20,6 +20,9 @@
16.4 import java.io.File;
16.5 import java.io.FileWriter;
16.6 import java.io.IOException;
16.7 +import java.io.InputStream;
16.8 +import java.net.URL;
16.9 +import java.util.Enumeration;
16.10 import javax.script.Invocable;
16.11 import javax.script.ScriptEngine;
16.12 import javax.script.ScriptEngineManager;
16.13 @@ -269,7 +272,8 @@
16.14 ) throws Exception {
16.15 Object ret = null;
16.16 try {
16.17 - ret = toRun.invokeFunction(clazz.getName().replace('.', '_'), true);
16.18 + ret = toRun.invokeFunction("bck2brwsr");
16.19 + ret = toRun.invokeMethod(ret, "loadClass", clazz.getName());
16.20 ret = toRun.invokeMethod(ret, method, args);
16.21 } catch (ScriptException ex) {
16.22 fail("Execution failed in\n" + dumpJS(theCode), ex);
16.23 @@ -295,7 +299,7 @@
16.24 if (sb == null) {
16.25 sb = new StringBuilder();
16.26 }
16.27 - GenJS.compile(sb, names);
16.28 + Bck2Brwsr.generate(sb, new EmulationResources(), names);
16.29 ScriptEngineManager sem = new ScriptEngineManager();
16.30 ScriptEngine js = sem.getEngineByExtension("js");
16.31 if (eng != null) {
16.32 @@ -320,4 +324,21 @@
16.33 w.close();
16.34 return new StringBuilder(f.getPath());
16.35 }
16.36 + private static class EmulationResources implements Bck2Brwsr.Resources {
16.37 + @Override
16.38 + public InputStream get(String name) throws IOException {
16.39 + Enumeration<URL> en = StaticMethodTest.class.getClassLoader().getResources(name);
16.40 + URL u = null;
16.41 + while (en.hasMoreElements()) {
16.42 + u = en.nextElement();
16.43 + }
16.44 + if (u == null) {
16.45 + throw new IOException("Can't find " + name);
16.46 + }
16.47 + if (u.toExternalForm().contains("rt.jar!")) {
16.48 + throw new IOException("No emulation for " + u);
16.49 + }
16.50 + return u.openStream();
16.51 + }
16.52 + }
16.53 }
17.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazy.java Mon Dec 10 12:03:22 2012 +0100
17.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
17.3 @@ -1,68 +0,0 @@
17.4 -/**
17.5 - * Back 2 Browser Bytecode Translator
17.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
17.7 - *
17.8 - * This program is free software: you can redistribute it and/or modify
17.9 - * it under the terms of the GNU General Public License as published by
17.10 - * the Free Software Foundation, version 2 of the License.
17.11 - *
17.12 - * This program is distributed in the hope that it will be useful,
17.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
17.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17.15 - * GNU General Public License for more details.
17.16 - *
17.17 - * You should have received a copy of the GNU General Public License
17.18 - * along with this program. Look for COPYING file in the top folder.
17.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
17.20 - */
17.21 -package org.apidesign.vm4brwsr;
17.22 -
17.23 -import java.io.ByteArrayInputStream;
17.24 -import java.io.IOException;
17.25 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
17.26 -
17.27 -/**
17.28 - *
17.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
17.30 - */
17.31 -class VMLazy extends ByteCodeToJavaScript {
17.32 - private final Object vm;
17.33 - private final Object global;
17.34 -
17.35 - private VMLazy(Object global, Object vm, Appendable out) {
17.36 - super(out);
17.37 - this.vm = vm;
17.38 - this.global = global;
17.39 - }
17.40 -
17.41 - static String toJavaScript(Object global, Object vm, byte[] is) throws IOException {
17.42 - StringBuilder sb = new StringBuilder();
17.43 - new VMLazy(global, vm, sb).compile(new ByteArrayInputStream(is));
17.44 - return sb.toString().toString();
17.45 - }
17.46 -
17.47 - @JavaScriptBody(args = { "self", "n" },
17.48 - body=
17.49 - "var cls = n.replace__Ljava_lang_String_2CC(n,'/','_').toString();"
17.50 - + "var glb = self.fld_global;"
17.51 - + "var vm = self.fld_vm;"
17.52 - + "if (glb[cls]) return false;"
17.53 - + "glb[cls] = function() {"
17.54 - + " return vm.loadClass(n,cls);"
17.55 - + "};"
17.56 - + "return true;"
17.57 - )
17.58 - @Override
17.59 - protected boolean requireReference(String internalClassName) {
17.60 - throw new UnsupportedOperationException();
17.61 - }
17.62 -
17.63 - @Override
17.64 - protected void requireScript(String resourcePath) {
17.65 - }
17.66 -
17.67 - @Override
17.68 - protected String assignClass(String className) {
17.69 - return "arguments[0][arguments[1]]=";
17.70 - }
17.71 -}
18.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Mon Dec 10 12:03:22 2012 +0100
18.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Wed Dec 12 09:09:42 2012 +0100
18.3 @@ -17,8 +17,6 @@
18.4 */
18.5 package org.apidesign.vm4brwsr;
18.6
18.7 -import java.io.IOException;
18.8 -import java.io.InputStream;
18.9 import javax.script.Invocable;
18.10 import javax.script.ScriptContext;
18.11 import javax.script.ScriptEngine;
18.12 @@ -40,50 +38,32 @@
18.13 @BeforeClass
18.14 public void compileTheCode() throws Exception {
18.15 StringBuilder sb = new StringBuilder();
18.16 -
18.17 - sb.append("\nfunction test(clazz, as, method) {");
18.18 - sb.append("\n var l = new lazyVM(this);");
18.19 - sb.append("\n var c = l.loadClass(clazz, as);");
18.20 + sb.append("\nvar data = {};");
18.21 + sb.append("\nfunction test(clazz, method) {");
18.22 + sb.append("\n if (!data.bck2brwsr) data.bck2brwsr = bck2brwsr(function(name) { return loader.get(name); });");
18.23 + sb.append("\n var c = data.bck2brwsr.loadClass(clazz);");
18.24 sb.append("\n return c[method]();");
18.25 sb.append("\n}");
18.26
18.27
18.28 - sb.append("\nfunction lazyVM(global) {");
18.29 - sb.append("\n var self = this;");
18.30 - sb.append("\n var glb = global;");
18.31 - sb.append("\n lazyVM.prototype.loadClass = function(res, name) {");
18.32 - sb.append("\n var script = org_apidesign_vm4brwsr_VMLazy(true)."
18.33 - + "toJavaScript__Ljava_lang_String_2Ljava_lang_Object_2Ljava_lang_Object_2_3B("
18.34 - + " glb, self,"
18.35 - + " loader.get(res + '.class')"
18.36 - + ");");
18.37 - sb.append("\n try {");
18.38 - sb.append("\n new Function(script)(glb, name);");
18.39 - sb.append("\n } catch (ex) {");
18.40 - sb.append("\n throw 'Cannot compile ' + res + ' error: ' + ex + ' script:\\n' + script;");
18.41 - sb.append("\n };");
18.42 - sb.append("\n return glb[name](true);");
18.43 - sb.append("\n };");
18.44 - sb.append("\n");
18.45 - sb.append("\n}\n");
18.46 -
18.47 +
18.48 ScriptEngine[] arr = { null };
18.49 code = StaticMethodTest.compileClass(sb, arr,
18.50 - "org/apidesign/vm4brwsr/VMLazy"
18.51 + "org/apidesign/vm4brwsr/VM"
18.52 );
18.53 - arr[0].getContext().setAttribute("loader", new FindBytes(), ScriptContext.ENGINE_SCOPE);
18.54 + arr[0].getContext().setAttribute("loader", new BytesLoader(), ScriptContext.ENGINE_SCOPE);
18.55 codeSeq = sb;
18.56 }
18.57
18.58 @Test public void invokeStaticMethod() throws Exception {
18.59 assertExec("Trying to get -1", "test", Double.valueOf(-1),
18.60 - "org/apidesign/vm4brwsr/StaticMethod", "org_apidesign_vm4brwsr_StaticMethod", "minusOne__I"
18.61 + StaticMethod.class.getName(), "minusOne__I"
18.62 );
18.63 }
18.64
18.65 @Test public void loadDependantClass() throws Exception {
18.66 - assertExec("Trying to get zero", "test", Double.valueOf(0),
18.67 - "org/apidesign/vm4brwsr/InstanceSub", "org_apidesign_vm4brwsr_InstanceSub", "recallDbl__D"
18.68 + assertExec("Expecting zero", "test", Double.valueOf(0),
18.69 + InstanceSub.class.getName(), "recallDbl__D"
18.70 );
18.71 }
18.72
18.73 @@ -104,29 +84,4 @@
18.74 }
18.75 assertEquals(ret, expRes, msg + "was: " + ret + "\n" + StaticMethodTest.dumpJS(codeSeq));
18.76 }
18.77 -
18.78 - public static final class FindBytes {
18.79 - public byte[] get(String name) throws IOException {
18.80 - InputStream is = VMLazyTest.class.getClassLoader().getResourceAsStream(name);
18.81 - if (is == null) {
18.82 - throw new IOException("Can't find " + name);
18.83 - }
18.84 - byte[] arr = new byte[is.available()];
18.85 - int len = is.read(arr);
18.86 - if (len != arr.length) {
18.87 - throw new IOException("Read only " + len + " wanting " + arr.length);
18.88 - }
18.89 - /*
18.90 - System.err.print("loader['" + name + "'] = [");
18.91 - for (int i = 0; i < arr.length; i++) {
18.92 - if (i > 0) {
18.93 - System.err.print(", ");
18.94 - }
18.95 - System.err.print(arr[i]);
18.96 - }
18.97 - System.err.println("]");
18.98 - */
18.99 - return arr;
18.100 - }
18.101 - }
18.102 }
19.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Mon Dec 10 12:03:22 2012 +0100
19.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMinVMTest.java Wed Dec 12 09:09:42 2012 +0100
19.3 @@ -35,13 +35,43 @@
19.4 private static CharSequence codeSeq;
19.5 private static Invocable code;
19.6
19.7 - @Test public void compareTheGeneratedCode() throws Exception {
19.8 - byte[] arr = readClass("/org/apidesign/vm4brwsr/Array.class");
19.9 + @Test public void compareGeneratedCodeForArrayClass() throws Exception {
19.10 + compareCode("/org/apidesign/vm4brwsr/Array.class");
19.11 + }
19.12 +
19.13 + @Test public void compareGeneratedCodeForClassesClass() throws Exception {
19.14 + compareCode("/org/apidesign/vm4brwsr/Classes.class");
19.15 + }
19.16 +
19.17 + @BeforeClass
19.18 + public void compileTheCode() throws Exception {
19.19 + StringBuilder sb = new StringBuilder();
19.20 + code = StaticMethodTest.compileClass(sb,
19.21 + "org/apidesign/vm4brwsr/VMinVM"
19.22 + );
19.23 + codeSeq = sb;
19.24 + }
19.25 +
19.26 + private static byte[] readClass(String res) throws IOException {
19.27 + InputStream is1 = VMinVMTest.class.getResourceAsStream(res);
19.28 + assertNotNull(is1, "Stream found");
19.29 + byte[] arr = new byte[is1.available()];
19.30 + int len = is1.read(arr);
19.31 + is1.close();
19.32 + if (len != arr.length) {
19.33 + throw new IOException("Wrong len " + len + " for arr: " + arr.length);
19.34 + }
19.35 + return arr;
19.36 + }
19.37 +
19.38 + private void compareCode(final String nm) throws Exception, IOException {
19.39 + byte[] arr = readClass(nm);
19.40 String ret1 = VMinVM.toJavaScript(arr);
19.41
19.42 Object ret;
19.43 try {
19.44 - ret = code.invokeFunction(VMinVM.class.getName().replace('.', '_'), true);
19.45 + ret = code.invokeFunction("bck2brwsr");
19.46 + ret = code.invokeMethod(ret, "loadClass", VMinVM.class.getName());
19.47 ret = code.invokeMethod(ret, "toJavaScript__Ljava_lang_String_2_3B", arr);
19.48 } catch (Exception ex) {
19.49 File f = File.createTempFile("execution", ".js");
19.50 @@ -64,27 +94,14 @@
19.51
19.52 assertTrue(ret instanceof String, "It is string: " + ret);
19.53
19.54 - assertEquals((String)ret, ret1.toString(), "The code is the same");
19.55 - }
19.56 -
19.57 - @BeforeClass
19.58 - public void compileTheCode() throws Exception {
19.59 - StringBuilder sb = new StringBuilder();
19.60 - code = StaticMethodTest.compileClass(sb,
19.61 - "org/apidesign/vm4brwsr/VMinVM"
19.62 - );
19.63 - codeSeq = sb;
19.64 - }
19.65 -
19.66 - private static byte[] readClass(String res) throws IOException {
19.67 - InputStream is1 = VMinVMTest.class.getResourceAsStream(res);
19.68 - assertNotNull(is1, "Stream found");
19.69 - byte[] arr = new byte[is1.available()];
19.70 - int len = is1.read(arr);
19.71 - is1.close();
19.72 - if (len != arr.length) {
19.73 - throw new IOException("Wrong len " + len + " for arr: " + arr.length);
19.74 + if (!ret1.toString().equals(ret)) {
19.75 + StringBuilder msg = new StringBuilder("Difference found between ");
19.76 + msg.append(StaticMethodTest.dumpJS(ret1));
19.77 + msg.append(" ");
19.78 + msg.append(StaticMethodTest.dumpJS((CharSequence) ret));
19.79 + msg.append(" compiled by ");
19.80 + msg.append(StaticMethodTest.dumpJS(codeSeq));
19.81 + fail(msg.toString());
19.82 }
19.83 - return arr;
19.84 }
19.85 }