Lazy loading is now part of GenJS lazyvm
authorJaroslav Tulach <jaroslav.tulach@apidesign.org>
Fri, 07 Dec 2012 06:29:54 +0100
branchlazyvm
changeset 277e4b9eee9be83
parent 276 aeb9fe11cd60
child 278 ad49b48b7919
Lazy loading is now part of GenJS
vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java
vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java
vm/src/test/java/org/apidesign/vm4brwsr/VMLazy.java
vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java
     1.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java	Thu Dec 06 22:02:10 2012 +0100
     1.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java	Fri Dec 07 06:29:54 2012 +0100
     1.3 @@ -31,6 +31,11 @@
     1.4          super(out);
     1.5      }
     1.6      
     1.7 +    static {
     1.8 +        // uses VMLazy to load dynamic classes
     1.9 +        VMLazy.init();
    1.10 +    }
    1.11 +    
    1.12      static void compile(Appendable out, String... names) throws IOException {
    1.13          compile(out, StringArray.asList(names));
    1.14      }
    1.15 @@ -113,9 +118,19 @@
    1.16              }
    1.17          }
    1.18          out.append(
    1.19 -              "  global.bck2brwsr = function() { return {\n"
    1.20 -            + "    loadClass : function(name) { return vm[name.replace__Ljava_lang_String_2CC(name, '.','_')](true); }\n"
    1.21 -            + "  };\n};\n");
    1.22 +              "  global.bck2brwsr = function() {\n"
    1.23 +            + "    var args = arguments;\n"
    1.24 +            + "    var loader = {};\n"
    1.25 +            + "    loader.vm = vm;\n"
    1.26 +            + "    loader.loadClass = function(name) {\n"
    1.27 +            + "      var attr = name.replace__Ljava_lang_String_2CC(name, '.','_');\n"
    1.28 +            + "      var fn = vm[attr];\n"
    1.29 +            + "      if (fn) return fn(false);\n"
    1.30 +            + "      return vm.org_apidesign_vm4brwsr_VMLazy(false).\n"
    1.31 +            + "        load___3Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n"
    1.32 +            + "    }\n"
    1.33 +            + "    return loader;\n"
    1.34 +            + "  };\n");
    1.35          out.append("}(this));");
    1.36      }
    1.37      private static void readResource(InputStream emul, Appendable out) throws IOException {
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java	Fri Dec 07 06:29:54 2012 +0100
     2.3 @@ -0,0 +1,100 @@
     2.4 +/**
     2.5 + * Back 2 Browser Bytecode Translator
     2.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     2.7 + *
     2.8 + * This program is free software: you can redistribute it and/or modify
     2.9 + * it under the terms of the GNU General Public License as published by
    2.10 + * the Free Software Foundation, version 2 of the License.
    2.11 + *
    2.12 + * This program is distributed in the hope that it will be useful,
    2.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    2.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    2.15 + * GNU General Public License for more details.
    2.16 + *
    2.17 + * You should have received a copy of the GNU General Public License
    2.18 + * along with this program. Look for COPYING file in the top folder.
    2.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
    2.20 + */
    2.21 +package org.apidesign.vm4brwsr;
    2.22 +
    2.23 +import java.io.ByteArrayInputStream;
    2.24 +import java.io.IOException;
    2.25 +import org.apidesign.bck2brwsr.core.JavaScriptBody;
    2.26 +
    2.27 +/**
    2.28 + *
    2.29 + * @author Jaroslav Tulach <jtulach@netbeans.org>
    2.30 + */
    2.31 +class VMLazy extends ByteCodeToJavaScript {
    2.32 +    private final Object loader;
    2.33 +    
    2.34 +    private VMLazy(Object loader, Appendable out) {
    2.35 +        super(out);
    2.36 +        this.loader = loader;
    2.37 +    }
    2.38 +    
    2.39 +    static void init() {
    2.40 +    }
    2.41 +    
    2.42 +    @JavaScriptBody(args={"res", "args" }, body = "return args[0](res.toString());")
    2.43 +    private static native byte[] read(String res, Object[] args);
    2.44 +    
    2.45 +    static Object load(Object loader, String name, Object[] arguments) 
    2.46 +    throws IOException, ClassNotFoundException {
    2.47 +        String res = name.replace('.', '/') + ".class";
    2.48 +        byte[] arr = read(res, arguments);
    2.49 +        if (arr == null) {
    2.50 +            throw new ClassNotFoundException(name);
    2.51 +        }
    2.52 +        String code = toJavaScript(loader, arr);
    2.53 +        return applyCode(loader, name, code);
    2.54 +    }
    2.55 +    
    2.56 +    @JavaScriptBody(args = {"loader", "name", "script" }, body =
    2.57 +        "try {\n" +
    2.58 +        "  new Function(script)(loader, name);\n" +
    2.59 +        "} catch (ex) {\n" +
    2.60 +        "  throw 'Cannot compile ' + ex + ' script:\\\\n' + script;\n" +
    2.61 +        "}\n" +
    2.62 +        "return vm[name](false);\n"
    2.63 +    )
    2.64 +    private static native Object applyCode(Object loader, String name, String script);
    2.65 +    
    2.66 +    private static String toJavaScript(Object loader, byte[] is) throws IOException {
    2.67 +        StringBuilder sb = new StringBuilder();
    2.68 +        sb.append("var loader = arguments[0];\n");
    2.69 +        sb.append("var vm = loader.vm;\n");
    2.70 +        new VMLazy(loader, sb).compile(new ByteArrayInputStream(is));
    2.71 +        return sb.toString().toString();
    2.72 +    }
    2.73 +
    2.74 +    @JavaScriptBody(args = { "self", "n" }, 
    2.75 +        body=
    2.76 +          "var cls = n.replace__Ljava_lang_String_2CC(n,'/','_').toString();"
    2.77 +        + "var loader = self.fld_loader;"
    2.78 +        + "var vm = loader.vm;"
    2.79 +        + "if (vm[cls]) return false;"
    2.80 +        + "vm[cls] = function() {"
    2.81 +        + "  return loader.loadClass(n,cls);"
    2.82 +        + "};"
    2.83 +        + "return true;"
    2.84 +    )
    2.85 +    @Override
    2.86 +    protected boolean requireReference(String internalClassName) {
    2.87 +        throw new UnsupportedOperationException();
    2.88 +    }
    2.89 +
    2.90 +    @Override
    2.91 +    protected void requireScript(String resourcePath) {
    2.92 +    }
    2.93 +
    2.94 +    @Override
    2.95 +    String assignClass(String className) {
    2.96 +        return "vm[arguments[1]]=";
    2.97 +    }
    2.98 +
    2.99 +    @Override
   2.100 +    String accessClass(String classOperation) {
   2.101 +        return "vm." + classOperation;
   2.102 +    }
   2.103 +}
     3.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazy.java	Thu Dec 06 22:02:10 2012 +0100
     3.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.3 @@ -1,68 +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.ByteArrayInputStream;
    3.24 -import java.io.IOException;
    3.25 -import org.apidesign.bck2brwsr.core.JavaScriptBody;
    3.26 -
    3.27 -/**
    3.28 - *
    3.29 - * @author Jaroslav Tulach <jtulach@netbeans.org>
    3.30 - */
    3.31 -class VMLazy extends ByteCodeToJavaScript {
    3.32 -    private final Object vm;
    3.33 -    private final Object global;
    3.34 -    
    3.35 -    private VMLazy(Object global, Object vm, Appendable out) {
    3.36 -        super(out);
    3.37 -        this.vm = vm;
    3.38 -        this.global = global;
    3.39 -    }
    3.40 -    
    3.41 -    static String toJavaScript(Object global, Object vm, byte[] is) throws IOException {
    3.42 -        StringBuilder sb = new StringBuilder();
    3.43 -        new VMLazy(global, vm, sb).compile(new ByteArrayInputStream(is));
    3.44 -        return sb.toString().toString();
    3.45 -    }
    3.46 -
    3.47 -    @JavaScriptBody(args = { "self", "n" }, 
    3.48 -        body=
    3.49 -          "var cls = n.replace__Ljava_lang_String_2CC(n,'/','_').toString();"
    3.50 -        + "var glb = self.fld_global;"
    3.51 -        + "var vm = self.fld_vm;"
    3.52 -        + "if (glb[cls]) return false;"
    3.53 -        + "glb[cls] = function() {"
    3.54 -        + "  return vm.loadClass(n,cls);"
    3.55 -        + "};"
    3.56 -        + "return true;"
    3.57 -    )
    3.58 -    @Override
    3.59 -    protected boolean requireReference(String internalClassName) {
    3.60 -        throw new UnsupportedOperationException();
    3.61 -    }
    3.62 -
    3.63 -    @Override
    3.64 -    protected void requireScript(String resourcePath) {
    3.65 -    }
    3.66 -
    3.67 -    @Override
    3.68 -    protected String assignClass(String className) {
    3.69 -        return "arguments[0][arguments[1]]=";
    3.70 -    }
    3.71 -}
     4.1 --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java	Thu Dec 06 22:02:10 2012 +0100
     4.2 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java	Fri Dec 07 06:29:54 2012 +0100
     4.3 @@ -19,6 +19,8 @@
     4.4  
     4.5  import java.io.IOException;
     4.6  import java.io.InputStream;
     4.7 +import java.util.Set;
     4.8 +import java.util.TreeSet;
     4.9  import javax.script.Invocable;
    4.10  import javax.script.ScriptContext;
    4.11  import javax.script.ScriptEngine;
    4.12 @@ -40,36 +42,18 @@
    4.13      @BeforeClass
    4.14      public void compileTheCode() throws Exception {
    4.15          StringBuilder sb = new StringBuilder();
    4.16 -        
    4.17 -        sb.append("\nfunction test(clazz, as, method) {");
    4.18 -        sb.append("\n  var l = new lazyVM(this);");
    4.19 -        sb.append("\n  var c = l.loadClass(clazz, as);");
    4.20 +        sb.append("\nvar data = {};");
    4.21 +        sb.append("\nfunction test(clazz, method) {");
    4.22 +        sb.append("\n  if (!data.bck2brwsr) data.bck2brwsr = bck2brwsr(function(name) { return loader.get(name); });");
    4.23 +        sb.append("\n  var c = data.bck2brwsr.loadClass(clazz);");
    4.24          sb.append("\n  return c[method]();");
    4.25          sb.append("\n}");
    4.26          
    4.27          
    4.28 -        sb.append("\nfunction lazyVM(global) {");
    4.29 -        sb.append("\n  var self = this;");
    4.30 -        sb.append("\n  var glb = global;");
    4.31 -        sb.append("\n  lazyVM.prototype.loadClass = function(res, name) {");
    4.32 -        sb.append("\n    var script = org_apidesign_vm4brwsr_VMLazy(true)."
    4.33 -            + "toJavaScript__Ljava_lang_String_2Ljava_lang_Object_2Ljava_lang_Object_2_3B("
    4.34 -            + "  glb, self,"
    4.35 -            + "  loader.get(res + '.class')"
    4.36 -            + ");");
    4.37 -        sb.append("\n    try {");
    4.38 -        sb.append("\n      new Function(script)(glb, name);");
    4.39 -        sb.append("\n    } catch (ex) {");
    4.40 -        sb.append("\n      throw 'Cannot compile ' + res + ' error: ' + ex + ' script:\\n' + script;");
    4.41 -        sb.append("\n    };");
    4.42 -        sb.append("\n    return glb[name](true);");
    4.43 -        sb.append("\n  };");
    4.44 -        sb.append("\n");
    4.45 -        sb.append("\n}\n");
    4.46 -        
    4.47 +       
    4.48          ScriptEngine[] arr = { null };
    4.49          code = StaticMethodTest.compileClass(sb, arr,
    4.50 -            "org/apidesign/vm4brwsr/VMLazy"
    4.51 +            "org/apidesign/vm4brwsr/GenJS"
    4.52          );
    4.53          arr[0].getContext().setAttribute("loader", new FindBytes(), ScriptContext.ENGINE_SCOPE);
    4.54          codeSeq = sb;
    4.55 @@ -77,13 +61,13 @@
    4.56      
    4.57      @Test public void invokeStaticMethod() throws Exception {
    4.58          assertExec("Trying to get -1", "test", Double.valueOf(-1),
    4.59 -            "org/apidesign/vm4brwsr/StaticMethod", "org_apidesign_vm4brwsr_StaticMethod", "minusOne__I"
    4.60 +            StaticMethod.class.getName(), "minusOne__I"
    4.61          );
    4.62      }
    4.63  
    4.64      @Test public void loadDependantClass() throws Exception {
    4.65 -        assertExec("Trying to get zero", "test", Double.valueOf(0),
    4.66 -            "org/apidesign/vm4brwsr/InstanceSub", "org_apidesign_vm4brwsr_InstanceSub", "recallDbl__D"
    4.67 +        assertExec("Expecting zero", "test", Double.valueOf(0),
    4.68 +            InstanceSub.class.getName(), "recallDbl__D"
    4.69          );
    4.70      }
    4.71  
    4.72 @@ -106,7 +90,13 @@
    4.73      }
    4.74  
    4.75      public static final class FindBytes {
    4.76 +        private static Set<String> requested = new TreeSet<String>();
    4.77 +        
    4.78          public byte[] get(String name) throws IOException {
    4.79 +            if (!requested.add(name)) {
    4.80 +                throw new IllegalStateException("Requested for second time: " + name);
    4.81 +            }
    4.82 +            
    4.83              InputStream is = VMLazyTest.class.getClassLoader().getResourceAsStream(name);
    4.84              if (is == null) {
    4.85                  throw new IOException("Can't find " + name);