Creating Bck2Brwsr entrypoint to for those who wish to generate their JavaScript based Java VM lazyvm
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 11 Dec 2012 09:36:44 +0100
branchlazyvm
changeset 298885acca2fa0b
parent 284 58bd38caf70d
child 299 86b65a599e4d
Creating Bck2Brwsr entrypoint to for those who wish to generate their JavaScript based Java VM
vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java
vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java
vm/src/main/java/org/apidesign/vm4brwsr/Main.java
vm/src/main/java/org/apidesign/vm4brwsr/VM.java
vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java
vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java
vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java
vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Bck2Brwsr.java	Tue Dec 11 09:36:44 2012 +0100
     1.3 @@ -0,0 +1,106 @@
     1.4 +/**
     1.5 + * Back 2 Browser Bytecode Translator
     1.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     1.7 + *
     1.8 + * This program is free software: you can redistribute it and/or modify
     1.9 + * it under the terms of the GNU General Public License as published by
    1.10 + * the Free Software Foundation, version 2 of the License.
    1.11 + *
    1.12 + * This program is distributed in the hope that it will be useful,
    1.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    1.15 + * GNU General Public License for more details.
    1.16 + *
    1.17 + * You should have received a copy of the GNU General Public License
    1.18 + * along with this program. Look for COPYING file in the top folder.
    1.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    1.20 + */
    1.21 +package org.apidesign.vm4brwsr;
    1.22 +
    1.23 +import java.io.IOException;
    1.24 +import java.io.InputStream;
    1.25 +import java.net.URL;
    1.26 +import java.util.Enumeration;
    1.27 +
    1.28 +/** Build your own virtual machine! Use methods in this class to generate
    1.29 + * a skeleton JVM in JavaScript that contains pre-compiled classes of your
    1.30 + * choice. The generated script defines one JavaScript method that can
    1.31 + * be used to bootstrap and load the virtual machine: <pre>
    1.32 + * var vm = bck2brwsr();
    1.33 + * var main = vm.loadClass('org.your.pkg.Main');
    1.34 + * main.main__V_3Ljava_lang_String_2(null);
    1.35 + * </pre>
    1.36 + * In case one wants to initialize the virtual machine with ability to
    1.37 + * load classes lazily when needed, one can provide a loader function to
    1.38 + * when creating the virtual machine: <pre>
    1.39 + * var vm = bck2brwsr(function(resource) { 
    1.40 + *   return null; // byte[] for the resource
    1.41 + * });
    1.42 + * </pre>
    1.43 + * In this scenario, when a request for a unknown class is made, the loader
    1.44 + * function is asked for its byte code and the system dynamically transforms
    1.45 + * it to JavaScript.
    1.46 + *
    1.47 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    1.48 + */
    1.49 +public final class Bck2Brwsr {
    1.50 +    private Bck2Brwsr() {
    1.51 +    }
    1.52 +    
    1.53 +    /** Generates virtual machine from bytes served by a <code>resources</code>
    1.54 +     * provider.
    1.55 +     * 
    1.56 +     * @param out the output to write the generated JavaScript to
    1.57 +     * @param resources provider of class files to use
    1.58 +     * @param classes additional classes to include in the generated script
    1.59 +     * @throws IOException I/O exception can be thrown when something goes wrong
    1.60 +     */
    1.61 +    public static void generate(Appendable out, Resources resources, String... classes) throws IOException {
    1.62 +        StringArray arr = StringArray.asList(classes);
    1.63 +        arr.add(VM.class.getName().replace('.', '/'));
    1.64 +        VM.compile(resources, out, arr);
    1.65 +    }
    1.66 +    
    1.67 +    /** Generates virtual machine from bytes served by a class loader.
    1.68 +     * 
    1.69 +     * @param out the output to write the generated JavaScript to
    1.70 +     * @param loader class loader to load needed classes from
    1.71 +     * @param classes additional classes to include in the generated script
    1.72 +     * @throws IOException I/O exception can be thrown when something goes wrong
    1.73 +     */
    1.74 +    public static void generate(Appendable out, final ClassLoader loader, String... classes) throws IOException {
    1.75 +        class R implements Resources {
    1.76 +            @Override
    1.77 +            public InputStream get(String name) throws IOException {
    1.78 +                Enumeration<URL> en = loader.getResources(name);
    1.79 +                URL u = null;
    1.80 +                while (en.hasMoreElements()) {
    1.81 +                    u = en.nextElement();
    1.82 +                }
    1.83 +                if (u == null) {
    1.84 +                    throw new IOException("Can't find " + name);
    1.85 +                }
    1.86 +                return u.openStream();
    1.87 +            }
    1.88 +        }
    1.89 +        generate(out, new R(), classes);
    1.90 +    }
    1.91 +    
    1.92 +    /** Provider of resources (classes and other files). The 
    1.93 +     * {@link #generate(java.lang.Appendable, org.apidesign.vm4brwsr.Bck2Brwsr.Resources, java.lang.String[]) 
    1.94 +     * generator method} will call back here for all classes needed during
    1.95 +     * translation to JavaScript.
    1.96 +     */
    1.97 +    public interface Resources {
    1.98 +        /** Loads given resource (class or other file like image). The 
    1.99 +         * resource name to load bytes for the {@link String} class
   1.100 +         * would be <code>"java/lang/String.class"</code>.
   1.101 +         * 
   1.102 +         * @param resource path to resource to load
   1.103 +         * @return the input stream for the resource 
   1.104 +         * @throws IOException can be thrown if the loading fails on some error
   1.105 +         *   or the file cannot be found
   1.106 +         */
   1.107 +        public InputStream get(String resource) throws IOException;
   1.108 +    }
   1.109 +}
     2.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Fri Dec 07 14:10:37 2012 +0100
     2.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java	Tue Dec 11 09:36:44 2012 +0100
     2.3 @@ -29,7 +29,7 @@
     2.4   *
     2.5   * @author Jaroslav Tulach <jtulach@netbeans.org>
     2.6   */
     2.7 -public abstract class ByteCodeToJavaScript {
     2.8 +abstract class ByteCodeToJavaScript {
     2.9      private ClassData jc;
    2.10      final Appendable out;
    2.11  
     3.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java	Fri Dec 07 14:10:37 2012 +0100
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,229 +0,0 @@
     3.4 -/**
     3.5 - * Back 2 Browser Bytecode Translator
     3.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     3.7 - *
     3.8 - * This program is free software: you can redistribute it and/or modify
     3.9 - * it under the terms of the GNU General Public License as published by
    3.10 - * the Free Software Foundation, version 2 of the License.
    3.11 - *
    3.12 - * This program is distributed in the hope that it will be useful,
    3.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
    3.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    3.15 - * GNU General Public License for more details.
    3.16 - *
    3.17 - * You should have received a copy of the GNU General Public License
    3.18 - * along with this program. Look for COPYING file in the top folder.
    3.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
    3.20 - */
    3.21 -package org.apidesign.vm4brwsr;
    3.22 -
    3.23 -import java.io.IOException;
    3.24 -import java.io.InputStream;
    3.25 -import java.net.URL;
    3.26 -import java.util.Enumeration;
    3.27 -
    3.28 -/** Generator of JavaScript from bytecode of classes on classpath of the VM.
    3.29 - *
    3.30 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    3.31 - */
    3.32 -class GenJS extends ByteCodeToJavaScript {
    3.33 -    public GenJS(Appendable out) {
    3.34 -        super(out);
    3.35 -    }
    3.36 -    
    3.37 -    static {
    3.38 -        // uses VMLazy to load dynamic classes
    3.39 -        VMLazy.init();
    3.40 -    }
    3.41 -    
    3.42 -    static void compile(Appendable out, String... names) throws IOException {
    3.43 -        compile(out, StringArray.asList(names));
    3.44 -    }
    3.45 -    static void compile(ClassLoader l, Appendable out, String... names) throws IOException {
    3.46 -        compile(l, out, StringArray.asList(names));
    3.47 -    }
    3.48 -    static void compile(Appendable out, StringArray names) throws IOException {
    3.49 -        compile(GenJS.class.getClassLoader(), out, names);
    3.50 -    }
    3.51 -    static void compile(ClassLoader l, Appendable out, StringArray names) throws IOException {
    3.52 -        new GenJS(out).doCompile(l, names);
    3.53 -    }
    3.54 -    protected void doCompile(ClassLoader l, StringArray names) throws IOException {
    3.55 -        out.append("(function VM(global) {");
    3.56 -        out.append("\n  var vm = {};");
    3.57 -        StringArray processed = new StringArray();
    3.58 -        StringArray initCode = new StringArray();
    3.59 -        for (String baseClass : names.toArray()) {
    3.60 -            references.add(baseClass);
    3.61 -            for (;;) {
    3.62 -                String name = null;
    3.63 -                for (String n : references.toArray()) {
    3.64 -                    if (processed.contains(n)) {
    3.65 -                        continue;
    3.66 -                    }
    3.67 -                    name = n;
    3.68 -                }
    3.69 -                if (name == null) {
    3.70 -                    break;
    3.71 -                }
    3.72 -                InputStream is = loadClass(l, name);
    3.73 -                if (is == null) {
    3.74 -                    throw new IOException("Can't find class " + name); 
    3.75 -                }
    3.76 -                try {
    3.77 -                    String ic = compile(is);
    3.78 -                    processed.add(name);
    3.79 -                    initCode.add(ic == null ? "" : ic);
    3.80 -                } catch (RuntimeException ex) {
    3.81 -                    if (out instanceof CharSequence) {
    3.82 -                        CharSequence seq = (CharSequence)out;
    3.83 -                        int lastBlock = seq.length();
    3.84 -                        while (lastBlock-- > 0) {
    3.85 -                            if (seq.charAt(lastBlock) == '{') {
    3.86 -                                break;
    3.87 -                            }
    3.88 -                        }
    3.89 -                        throw new IOException("Error while compiling " + name + "\n" 
    3.90 -                            + seq.subSequence(lastBlock + 1, seq.length()), ex
    3.91 -                        );
    3.92 -                    } else {
    3.93 -                        throw new IOException("Error while compiling " + name + "\n" 
    3.94 -                            + out, ex
    3.95 -                        );
    3.96 -                    }
    3.97 -                }
    3.98 -            }
    3.99 -
   3.100 -            for (String resource : scripts.toArray()) {
   3.101 -                while (resource.startsWith("/")) {
   3.102 -                    resource = resource.substring(1);
   3.103 -                }
   3.104 -                InputStream emul = l.getResourceAsStream(resource);
   3.105 -                if (emul == null) {
   3.106 -                    throw new IOException("Can't find " + resource);
   3.107 -                }
   3.108 -                readResource(emul, out);
   3.109 -            }
   3.110 -            scripts = new StringArray();
   3.111 -            
   3.112 -            StringArray toInit = StringArray.asList(references.toArray());
   3.113 -            toInit.reverse();
   3.114 -
   3.115 -            for (String ic : toInit.toArray()) {
   3.116 -                int indx = processed.indexOf(ic);
   3.117 -                if (indx >= 0) {
   3.118 -                    out.append(initCode.toArray()[indx]).append("\n");
   3.119 -                    initCode.toArray()[indx] = "";
   3.120 -                }
   3.121 -            }
   3.122 -        }
   3.123 -        out.append(
   3.124 -              "  global.bck2brwsr = function() {\n"
   3.125 -            + "    var args = arguments;\n"
   3.126 -            + "    var loader = {};\n"
   3.127 -            + "    loader.vm = vm;\n"
   3.128 -            + "    loader.loadClass = function(name) {\n"
   3.129 -            + "      var attr = name.replace__Ljava_lang_String_2CC(name, '.','_');\n"
   3.130 -            + "      var fn = vm[attr];\n"
   3.131 -            + "      if (fn) return fn(false);\n"
   3.132 -            + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
   3.133 -            + "        load___3Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
   3.134 -            + "    }\n"
   3.135 -            + "    return loader;\n"
   3.136 -            + "  };\n");
   3.137 -        out.append("}(this));");
   3.138 -    }
   3.139 -    private static void readResource(InputStream emul, Appendable out) throws IOException {
   3.140 -        try {
   3.141 -            int state = 0;
   3.142 -            for (;;) {
   3.143 -                int ch = emul.read();
   3.144 -                if (ch == -1) {
   3.145 -                    break;
   3.146 -                }
   3.147 -                if (ch < 0 || ch > 255) {
   3.148 -                    throw new IOException("Invalid char in emulation " + ch);
   3.149 -                }
   3.150 -                switch (state) {
   3.151 -                    case 0: 
   3.152 -                        if (ch == '/') {
   3.153 -                            state = 1;
   3.154 -                        } else {
   3.155 -                            out.append((char)ch);
   3.156 -                        }
   3.157 -                        break;
   3.158 -                    case 1:
   3.159 -                        if (ch == '*') {
   3.160 -                            state = 2;
   3.161 -                        } else {
   3.162 -                            out.append('/').append((char)ch);
   3.163 -                            state = 0;
   3.164 -                        }
   3.165 -                        break;
   3.166 -                    case 2:
   3.167 -                        if (ch == '*') {
   3.168 -                            state = 3;
   3.169 -                        }
   3.170 -                        break;
   3.171 -                    case 3:
   3.172 -                        if (ch == '/') {
   3.173 -                            state = 0;
   3.174 -                        } else {
   3.175 -                            state = 2;
   3.176 -                        }
   3.177 -                        break;
   3.178 -                }
   3.179 -            }
   3.180 -        } finally {
   3.181 -            emul.close();
   3.182 -        }
   3.183 -    }
   3.184 -
   3.185 -    private static InputStream loadClass(ClassLoader l, String name) throws IOException {
   3.186 -        Enumeration<URL> en = l.getResources(name + ".class");
   3.187 -        URL u = null;
   3.188 -        while (en.hasMoreElements()) {
   3.189 -            u = en.nextElement();
   3.190 -        }
   3.191 -        if (u == null) {
   3.192 -            throw new IOException("Can't find " + name);
   3.193 -        }
   3.194 -        if (u.toExternalForm().contains("rt.jar!")) {
   3.195 -            throw new IOException("No emulation for " + u);
   3.196 -        }
   3.197 -        return u.openStream();
   3.198 -    }
   3.199 -
   3.200 -    static String toString(String name) throws IOException {
   3.201 -        StringBuilder sb = new StringBuilder();
   3.202 -        compile(sb, name);
   3.203 -        return sb.toString().toString();
   3.204 -    }
   3.205 -
   3.206 -    private StringArray scripts = new StringArray();
   3.207 -    private StringArray references = new StringArray();
   3.208 -    
   3.209 -    @Override
   3.210 -    protected boolean requireReference(String cn) {
   3.211 -        if (references.contains(cn)) {
   3.212 -            return false;
   3.213 -        }
   3.214 -        references.add(cn);
   3.215 -        return true;
   3.216 -    }
   3.217 -
   3.218 -    @Override
   3.219 -    protected void requireScript(String resourcePath) {
   3.220 -        scripts.add(resourcePath);
   3.221 -    }
   3.222 -
   3.223 -    @Override
   3.224 -    String assignClass(String className) {
   3.225 -        return "vm." + className + " = ";
   3.226 -    }
   3.227 -    
   3.228 -    @Override
   3.229 -    String accessClass(String className) {
   3.230 -        return "vm." + className;
   3.231 -    }
   3.232 -}
     4.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Fri Dec 07 14:10:37 2012 +0100
     4.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Main.java	Tue Dec 11 09:36:44 2012 +0100
     4.3 @@ -32,6 +32,7 @@
     4.4      
     4.5      public static void main(String... args) throws IOException {
     4.6          if (args.length < 2) {
     4.7 +            System.err.println("Bck2Brwsr Translator from Java(tm) to JavaScript, (c) Jaroslav Tulach 2012");
     4.8              System.err.println("Usage: java -cp ... -jar ... <file_to_generate_js_code_to> java/lang/Class org/your/App ...");
     4.9              return;
    4.10          }
    4.11 @@ -39,7 +40,7 @@
    4.12          Writer w = new BufferedWriter(new FileWriter(args[0]));
    4.13          StringArray classes = StringArray.asList(args);
    4.14          classes.delete(0);
    4.15 -        GenJS.compile(w, classes);
    4.16 +        Bck2Brwsr.generate(w, Main.class.getClassLoader(), classes.toArray());
    4.17          w.close();
    4.18      }
    4.19  }
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VM.java	Tue Dec 11 09:36:44 2012 +0100
     5.3 @@ -0,0 +1,207 @@
     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 +
    5.26 +/** Generator of JavaScript from bytecode of classes on classpath of the VM.
    5.27 + *
    5.28 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    5.29 + */
    5.30 +class VM extends ByteCodeToJavaScript {
    5.31 +    public VM(Appendable out) {
    5.32 +        super(out);
    5.33 +    }
    5.34 +    
    5.35 +    static {
    5.36 +        // uses VMLazy to load dynamic classes
    5.37 +        VMLazy.init();
    5.38 +    }
    5.39 +    
    5.40 +    static void compile(Bck2Brwsr.Resources l, Appendable out, StringArray names) throws IOException {
    5.41 +        new VM(out).doCompile(l, names);
    5.42 +    }
    5.43 +    protected void doCompile(Bck2Brwsr.Resources l, StringArray names) throws IOException {
    5.44 +        out.append("(function VM(global) {");
    5.45 +        out.append("\n  var vm = {};");
    5.46 +        StringArray processed = new StringArray();
    5.47 +        StringArray initCode = new StringArray();
    5.48 +        for (String baseClass : names.toArray()) {
    5.49 +            references.add(baseClass);
    5.50 +            for (;;) {
    5.51 +                String name = null;
    5.52 +                for (String n : references.toArray()) {
    5.53 +                    if (processed.contains(n)) {
    5.54 +                        continue;
    5.55 +                    }
    5.56 +                    name = n;
    5.57 +                }
    5.58 +                if (name == null) {
    5.59 +                    break;
    5.60 +                }
    5.61 +                InputStream is = loadClass(l, name);
    5.62 +                if (is == null) {
    5.63 +                    throw new IOException("Can't find class " + name); 
    5.64 +                }
    5.65 +                try {
    5.66 +                    String ic = compile(is);
    5.67 +                    processed.add(name);
    5.68 +                    initCode.add(ic == null ? "" : ic);
    5.69 +                } catch (RuntimeException ex) {
    5.70 +                    if (out instanceof CharSequence) {
    5.71 +                        CharSequence seq = (CharSequence)out;
    5.72 +                        int lastBlock = seq.length();
    5.73 +                        while (lastBlock-- > 0) {
    5.74 +                            if (seq.charAt(lastBlock) == '{') {
    5.75 +                                break;
    5.76 +                            }
    5.77 +                        }
    5.78 +                        throw new IOException("Error while compiling " + name + "\n" 
    5.79 +                            + seq.subSequence(lastBlock + 1, seq.length()), ex
    5.80 +                        );
    5.81 +                    } else {
    5.82 +                        throw new IOException("Error while compiling " + name + "\n" 
    5.83 +                            + out, ex
    5.84 +                        );
    5.85 +                    }
    5.86 +                }
    5.87 +            }
    5.88 +
    5.89 +            for (String resource : scripts.toArray()) {
    5.90 +                while (resource.startsWith("/")) {
    5.91 +                    resource = resource.substring(1);
    5.92 +                }
    5.93 +                InputStream emul = l.get(resource);
    5.94 +                if (emul == null) {
    5.95 +                    throw new IOException("Can't find " + resource);
    5.96 +                }
    5.97 +                readResource(emul, out);
    5.98 +            }
    5.99 +            scripts = new StringArray();
   5.100 +            
   5.101 +            StringArray toInit = StringArray.asList(references.toArray());
   5.102 +            toInit.reverse();
   5.103 +
   5.104 +            for (String ic : toInit.toArray()) {
   5.105 +                int indx = processed.indexOf(ic);
   5.106 +                if (indx >= 0) {
   5.107 +                    out.append(initCode.toArray()[indx]).append("\n");
   5.108 +                    initCode.toArray()[indx] = "";
   5.109 +                }
   5.110 +            }
   5.111 +        }
   5.112 +        out.append(
   5.113 +              "  global.bck2brwsr = function() {\n"
   5.114 +            + "    var args = arguments;\n"
   5.115 +            + "    var loader = {};\n"
   5.116 +            + "    loader.vm = vm;\n"
   5.117 +            + "    loader.loadClass = function(name) {\n"
   5.118 +            + "      var attr = name.replace__Ljava_lang_String_2CC(name, '.','_');\n"
   5.119 +            + "      var fn = vm[attr];\n"
   5.120 +            + "      if (fn) return fn(false);\n"
   5.121 +            + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
   5.122 +            + "        load___3Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
   5.123 +            + "    }\n"
   5.124 +            + "    return loader;\n"
   5.125 +            + "  };\n");
   5.126 +        out.append("}(this));");
   5.127 +    }
   5.128 +    private static void readResource(InputStream emul, Appendable out) throws IOException {
   5.129 +        try {
   5.130 +            int state = 0;
   5.131 +            for (;;) {
   5.132 +                int ch = emul.read();
   5.133 +                if (ch == -1) {
   5.134 +                    break;
   5.135 +                }
   5.136 +                if (ch < 0 || ch > 255) {
   5.137 +                    throw new IOException("Invalid char in emulation " + ch);
   5.138 +                }
   5.139 +                switch (state) {
   5.140 +                    case 0: 
   5.141 +                        if (ch == '/') {
   5.142 +                            state = 1;
   5.143 +                        } else {
   5.144 +                            out.append((char)ch);
   5.145 +                        }
   5.146 +                        break;
   5.147 +                    case 1:
   5.148 +                        if (ch == '*') {
   5.149 +                            state = 2;
   5.150 +                        } else {
   5.151 +                            out.append('/').append((char)ch);
   5.152 +                            state = 0;
   5.153 +                        }
   5.154 +                        break;
   5.155 +                    case 2:
   5.156 +                        if (ch == '*') {
   5.157 +                            state = 3;
   5.158 +                        }
   5.159 +                        break;
   5.160 +                    case 3:
   5.161 +                        if (ch == '/') {
   5.162 +                            state = 0;
   5.163 +                        } else {
   5.164 +                            state = 2;
   5.165 +                        }
   5.166 +                        break;
   5.167 +                }
   5.168 +            }
   5.169 +        } finally {
   5.170 +            emul.close();
   5.171 +        }
   5.172 +    }
   5.173 +
   5.174 +    private static InputStream loadClass(Bck2Brwsr.Resources l, String name) throws IOException {
   5.175 +        return l.get(name + ".class"); // NOI18N
   5.176 +    }
   5.177 +
   5.178 +    static String toString(String name) throws IOException {
   5.179 +        StringBuilder sb = new StringBuilder();
   5.180 +//        compile(sb, name);
   5.181 +        return sb.toString().toString();
   5.182 +    }
   5.183 +
   5.184 +    private StringArray scripts = new StringArray();
   5.185 +    private StringArray references = new StringArray();
   5.186 +    
   5.187 +    @Override
   5.188 +    protected boolean requireReference(String cn) {
   5.189 +        if (references.contains(cn)) {
   5.190 +            return false;
   5.191 +        }
   5.192 +        references.add(cn);
   5.193 +        return true;
   5.194 +    }
   5.195 +
   5.196 +    @Override
   5.197 +    protected void requireScript(String resourcePath) {
   5.198 +        scripts.add(resourcePath);
   5.199 +    }
   5.200 +
   5.201 +    @Override
   5.202 +    String assignClass(String className) {
   5.203 +        return "vm." + className + " = ";
   5.204 +    }
   5.205 +    
   5.206 +    @Override
   5.207 +    String accessClass(String className) {
   5.208 +        return "vm." + className;
   5.209 +    }
   5.210 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/BytesLoader.java	Tue Dec 11 09:36:44 2012 +0100
     6.3 @@ -0,0 +1,58 @@
     6.4 +/**
     6.5 + * Back 2 Browser Bytecode Translator
     6.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     6.7 + *
     6.8 + * This program is free software: you can redistribute it and/or modify
     6.9 + * it under the terms of the GNU General Public License as published by
    6.10 + * the Free Software Foundation, version 2 of the License.
    6.11 + *
    6.12 + * This program is distributed in the hope that it will be useful,
    6.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    6.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    6.15 + * GNU General Public License for more details.
    6.16 + *
    6.17 + * You should have received a copy of the GNU General Public License
    6.18 + * along with this program. Look for COPYING file in the top folder.
    6.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    6.20 + */
    6.21 +package org.apidesign.vm4brwsr;
    6.22 +
    6.23 +import java.io.IOException;
    6.24 +import java.io.InputStream;
    6.25 +import java.util.Set;
    6.26 +import java.util.TreeSet;
    6.27 +
    6.28 +/**
    6.29 + *
    6.30 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    6.31 + */
    6.32 +public final class BytesLoader {
    6.33 +    private static Set<String> requested = new TreeSet<String>();
    6.34 +
    6.35 +    public byte[] get(String name) throws IOException {
    6.36 +        if (!requested.add(name)) {
    6.37 +            throw new IllegalStateException("Requested for second time: " + name);
    6.38 +        }
    6.39 +        InputStream is = BytesLoader.class.getClassLoader().getResourceAsStream(name);
    6.40 +        if (is == null) {
    6.41 +            throw new IOException("Can't find " + name);
    6.42 +        }
    6.43 +        byte[] arr = new byte[is.available()];
    6.44 +        int len = is.read(arr);
    6.45 +        if (len != arr.length) {
    6.46 +            throw new IOException("Read only " + len + " wanting " + arr.length);
    6.47 +        }
    6.48 +        /*
    6.49 +        System.err.print("loader['" + name + "'] = [");
    6.50 +        for (int i = 0; i < arr.length; i++) {
    6.51 +        if (i > 0) {
    6.52 +        System.err.print(", ");
    6.53 +        }
    6.54 +        System.err.print(arr[i]);
    6.55 +        }
    6.56 +        System.err.println("]");
    6.57 +         */
    6.58 +        return arr;
    6.59 +    }
    6.60 +    
    6.61 +}
     7.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java	Fri Dec 07 14:10:37 2012 +0100
     7.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/CompareVMs.java	Tue Dec 11 09:36:44 2012 +0100
     7.3 @@ -19,6 +19,7 @@
     7.4  
     7.5  import java.lang.reflect.Method;
     7.6  import javax.script.Invocable;
     7.7 +import javax.script.ScriptContext;
     7.8  import javax.script.ScriptEngine;
     7.9  import javax.script.ScriptEngineManager;
    7.10  import org.testng.Assert;
    7.11 @@ -98,26 +99,11 @@
    7.12                  return;
    7.13              }
    7.14              StringBuilder sb = new StringBuilder();
    7.15 -            class SkipMe extends GenJS {
    7.16 -
    7.17 -                public SkipMe(Appendable out) {
    7.18 -                    super(out);
    7.19 -                }
    7.20 -
    7.21 -                @Override
    7.22 -                protected boolean requireReference(String cn) {
    7.23 -                    if (cn.contains("CompareVMs")) {
    7.24 -                        return true;
    7.25 -                    }
    7.26 -                    return super.requireReference(cn);
    7.27 -                }
    7.28 -            }
    7.29 -            SkipMe sm = new SkipMe(sb);
    7.30 -            sm.doCompile(CompareVMs.class.getClassLoader(), StringArray.asList(
    7.31 -                clazz.getName().replace('.', '/')));
    7.32 +            Bck2Brwsr.generate(sb, CompareVMs.class.getClassLoader());
    7.33  
    7.34              ScriptEngineManager sem = new ScriptEngineManager();
    7.35              ScriptEngine js = sem.getEngineByExtension("js");
    7.36 +            js.getContext().setAttribute("loader", new BytesLoader(), ScriptContext.ENGINE_SCOPE);
    7.37  
    7.38              Object res = js.eval(sb.toString());
    7.39              Assert.assertTrue(js instanceof Invocable, "It is invocable object: " + res);
     8.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java	Fri Dec 07 14:10:37 2012 +0100
     8.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/StaticMethodTest.java	Tue Dec 11 09:36:44 2012 +0100
     8.3 @@ -20,6 +20,9 @@
     8.4  import java.io.File;
     8.5  import java.io.FileWriter;
     8.6  import java.io.IOException;
     8.7 +import java.io.InputStream;
     8.8 +import java.net.URL;
     8.9 +import java.util.Enumeration;
    8.10  import javax.script.Invocable;
    8.11  import javax.script.ScriptEngine;
    8.12  import javax.script.ScriptEngineManager;
    8.13 @@ -289,7 +292,7 @@
    8.14          if (sb == null) {
    8.15              sb = new StringBuilder();
    8.16          }
    8.17 -        GenJS.compile(sb, names);
    8.18 +        Bck2Brwsr.generate(sb, new EmulationResources(), names);
    8.19          ScriptEngineManager sem = new ScriptEngineManager();
    8.20          ScriptEngine js = sem.getEngineByExtension("js");
    8.21          if (eng != null) {
    8.22 @@ -314,4 +317,21 @@
    8.23          w.close();
    8.24          return new StringBuilder(f.getPath());
    8.25      }
    8.26 +    private static class EmulationResources implements Bck2Brwsr.Resources {
    8.27 +        @Override
    8.28 +        public InputStream get(String name) throws IOException {
    8.29 +            Enumeration<URL> en = StaticMethodTest.class.getClassLoader().getResources(name);
    8.30 +            URL u = null;
    8.31 +            while (en.hasMoreElements()) {
    8.32 +                u = en.nextElement();
    8.33 +            }
    8.34 +            if (u == null) {
    8.35 +                throw new IOException("Can't find " + name);
    8.36 +            }
    8.37 +            if (u.toExternalForm().contains("rt.jar!")) {
    8.38 +                throw new IOException("No emulation for " + u);
    8.39 +            }
    8.40 +            return u.openStream();
    8.41 +        }
    8.42 +    }
    8.43  }
     9.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java	Fri Dec 07 14:10:37 2012 +0100
     9.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java	Tue Dec 11 09:36:44 2012 +0100
     9.3 @@ -17,10 +17,6 @@
     9.4   */
     9.5  package org.apidesign.vm4brwsr;
     9.6  
     9.7 -import java.io.IOException;
     9.8 -import java.io.InputStream;
     9.9 -import java.util.Set;
    9.10 -import java.util.TreeSet;
    9.11  import javax.script.Invocable;
    9.12  import javax.script.ScriptContext;
    9.13  import javax.script.ScriptEngine;
    9.14 @@ -53,9 +49,9 @@
    9.15         
    9.16          ScriptEngine[] arr = { null };
    9.17          code = StaticMethodTest.compileClass(sb, arr,
    9.18 -            "org/apidesign/vm4brwsr/GenJS"
    9.19 +            "org/apidesign/vm4brwsr/VM"
    9.20          );
    9.21 -        arr[0].getContext().setAttribute("loader", new FindBytes(), ScriptContext.ENGINE_SCOPE);
    9.22 +        arr[0].getContext().setAttribute("loader", new BytesLoader(), ScriptContext.ENGINE_SCOPE);
    9.23          codeSeq = sb;
    9.24      }
    9.25      
    9.26 @@ -88,35 +84,4 @@
    9.27          }
    9.28          assertEquals(ret, expRes, msg + "was: " + ret + "\n" + StaticMethodTest.dumpJS(codeSeq));
    9.29      }
    9.30 -
    9.31 -    public static final class FindBytes {
    9.32 -        private static Set<String> requested = new TreeSet<String>();
    9.33 -        
    9.34 -        public byte[] get(String name) throws IOException {
    9.35 -            if (!requested.add(name)) {
    9.36 -                throw new IllegalStateException("Requested for second time: " + name);
    9.37 -            }
    9.38 -            
    9.39 -            InputStream is = VMLazyTest.class.getClassLoader().getResourceAsStream(name);
    9.40 -            if (is == null) {
    9.41 -                throw new IOException("Can't find " + name);
    9.42 -            }
    9.43 -            byte[] arr = new byte[is.available()];
    9.44 -            int len = is.read(arr);
    9.45 -            if (len != arr.length) {
    9.46 -                throw new IOException("Read only " + len + " wanting " + arr.length);
    9.47 -            }
    9.48 -            /*
    9.49 -            System.err.print("loader['" + name + "'] = [");
    9.50 -            for (int i = 0; i < arr.length; i++) {
    9.51 -                if (i > 0) {
    9.52 -                    System.err.print(", ");
    9.53 -                }
    9.54 -                System.err.print(arr[i]);
    9.55 -            }
    9.56 -            System.err.println("]");
    9.57 -            */
    9.58 -            return arr;
    9.59 -        }
    9.60 -    }
    9.61  }