Merging lazyvm into default branch - it seems to be stable enough to be used.
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Wed, 12 Dec 2012 09:09:42 +0100
changeset 306f36b3c273de6
parent 297 a20721a10717
parent 305 503b158cc093
child 309 825e468aa4a7
child 315 fc52cbbcbeb9
Merging lazyvm into default branch - it seems to be stable enough to be used.
vm/src/main/java/org/apidesign/vm4brwsr/ByteCodeToJavaScript.java
vm/src/main/java/org/apidesign/vm4brwsr/GenJS.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/VMLazy.java
     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  }