# HG changeset patch # User Jaroslav Tulach # Date 1354858194 -3600 # Node ID e4b9eee9be83b8e88afd04940cad63ca98fbf5cf # Parent aeb9fe11cd60a649eb38a6a37d50e0e83e36e970 Lazy loading is now part of GenJS diff -r aeb9fe11cd60 -r e4b9eee9be83 vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java --- a/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java Thu Dec 06 22:02:10 2012 +0100 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/GenJS.java Fri Dec 07 06:29:54 2012 +0100 @@ -31,6 +31,11 @@ super(out); } + static { + // uses VMLazy to load dynamic classes + VMLazy.init(); + } + static void compile(Appendable out, String... names) throws IOException { compile(out, StringArray.asList(names)); } @@ -113,9 +118,19 @@ } } out.append( - " global.bck2brwsr = function() { return {\n" - + " loadClass : function(name) { return vm[name.replace__Ljava_lang_String_2CC(name, '.','_')](true); }\n" - + " };\n};\n"); + " global.bck2brwsr = function() {\n" + + " var args = arguments;\n" + + " var loader = {};\n" + + " loader.vm = vm;\n" + + " loader.loadClass = function(name) {\n" + + " var attr = name.replace__Ljava_lang_String_2CC(name, '.','_');\n" + + " var fn = vm[attr];\n" + + " if (fn) return fn(false);\n" + + " return vm.org_apidesign_vm4brwsr_VMLazy(false).\n" + + " load___3Ljava_lang_Object_2Ljava_lang_Object_2Ljava_lang_String_2_3Ljava_lang_Object_2(loader, name, args);\n" + + " }\n" + + " return loader;\n" + + " };\n"); out.append("}(this));"); } private static void readResource(InputStream emul, Appendable out) throws IOException { diff -r aeb9fe11cd60 -r e4b9eee9be83 vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/VMLazy.java Fri Dec 07 06:29:54 2012 +0100 @@ -0,0 +1,100 @@ +/** + * Back 2 Browser Bytecode Translator + * Copyright (C) 2012 Jaroslav Tulach + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. Look for COPYING file in the top folder. + * If not, see http://opensource.org/licenses/GPL-2.0. + */ +package org.apidesign.vm4brwsr; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import org.apidesign.bck2brwsr.core.JavaScriptBody; + +/** + * + * @author Jaroslav Tulach + */ +class VMLazy extends ByteCodeToJavaScript { + private final Object loader; + + private VMLazy(Object loader, Appendable out) { + super(out); + this.loader = loader; + } + + static void init() { + } + + @JavaScriptBody(args={"res", "args" }, body = "return args[0](res.toString());") + private static native byte[] read(String res, Object[] args); + + static Object load(Object loader, String name, Object[] arguments) + throws IOException, ClassNotFoundException { + String res = name.replace('.', '/') + ".class"; + byte[] arr = read(res, arguments); + if (arr == null) { + throw new ClassNotFoundException(name); + } + String code = toJavaScript(loader, arr); + return applyCode(loader, name, code); + } + + @JavaScriptBody(args = {"loader", "name", "script" }, body = + "try {\n" + + " new Function(script)(loader, name);\n" + + "} catch (ex) {\n" + + " throw 'Cannot compile ' + ex + ' script:\\\\n' + script;\n" + + "}\n" + + "return vm[name](false);\n" + ) + private static native Object applyCode(Object loader, String name, String script); + + private static String toJavaScript(Object loader, byte[] is) throws IOException { + StringBuilder sb = new StringBuilder(); + sb.append("var loader = arguments[0];\n"); + sb.append("var vm = loader.vm;\n"); + new VMLazy(loader, sb).compile(new ByteArrayInputStream(is)); + return sb.toString().toString(); + } + + @JavaScriptBody(args = { "self", "n" }, + body= + "var cls = n.replace__Ljava_lang_String_2CC(n,'/','_').toString();" + + "var loader = self.fld_loader;" + + "var vm = loader.vm;" + + "if (vm[cls]) return false;" + + "vm[cls] = function() {" + + " return loader.loadClass(n,cls);" + + "};" + + "return true;" + ) + @Override + protected boolean requireReference(String internalClassName) { + throw new UnsupportedOperationException(); + } + + @Override + protected void requireScript(String resourcePath) { + } + + @Override + String assignClass(String className) { + return "vm[arguments[1]]="; + } + + @Override + String accessClass(String classOperation) { + return "vm." + classOperation; + } +} diff -r aeb9fe11cd60 -r e4b9eee9be83 vm/src/test/java/org/apidesign/vm4brwsr/VMLazy.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazy.java Thu Dec 06 22:02:10 2012 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/** - * Back 2 Browser Bytecode Translator - * Copyright (C) 2012 Jaroslav Tulach - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. Look for COPYING file in the top folder. - * If not, see http://opensource.org/licenses/GPL-2.0. - */ -package org.apidesign.vm4brwsr; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import org.apidesign.bck2brwsr.core.JavaScriptBody; - -/** - * - * @author Jaroslav Tulach - */ -class VMLazy extends ByteCodeToJavaScript { - private final Object vm; - private final Object global; - - private VMLazy(Object global, Object vm, Appendable out) { - super(out); - this.vm = vm; - this.global = global; - } - - static String toJavaScript(Object global, Object vm, byte[] is) throws IOException { - StringBuilder sb = new StringBuilder(); - new VMLazy(global, vm, sb).compile(new ByteArrayInputStream(is)); - return sb.toString().toString(); - } - - @JavaScriptBody(args = { "self", "n" }, - body= - "var cls = n.replace__Ljava_lang_String_2CC(n,'/','_').toString();" - + "var glb = self.fld_global;" - + "var vm = self.fld_vm;" - + "if (glb[cls]) return false;" - + "glb[cls] = function() {" - + " return vm.loadClass(n,cls);" - + "};" - + "return true;" - ) - @Override - protected boolean requireReference(String internalClassName) { - throw new UnsupportedOperationException(); - } - - @Override - protected void requireScript(String resourcePath) { - } - - @Override - protected String assignClass(String className) { - return "arguments[0][arguments[1]]="; - } -} diff -r aeb9fe11cd60 -r e4b9eee9be83 vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java --- a/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Thu Dec 06 22:02:10 2012 +0100 +++ b/vm/src/test/java/org/apidesign/vm4brwsr/VMLazyTest.java Fri Dec 07 06:29:54 2012 +0100 @@ -19,6 +19,8 @@ import java.io.IOException; import java.io.InputStream; +import java.util.Set; +import java.util.TreeSet; import javax.script.Invocable; import javax.script.ScriptContext; import javax.script.ScriptEngine; @@ -40,36 +42,18 @@ @BeforeClass public void compileTheCode() throws Exception { StringBuilder sb = new StringBuilder(); - - sb.append("\nfunction test(clazz, as, method) {"); - sb.append("\n var l = new lazyVM(this);"); - sb.append("\n var c = l.loadClass(clazz, as);"); + sb.append("\nvar data = {};"); + sb.append("\nfunction test(clazz, method) {"); + sb.append("\n if (!data.bck2brwsr) data.bck2brwsr = bck2brwsr(function(name) { return loader.get(name); });"); + sb.append("\n var c = data.bck2brwsr.loadClass(clazz);"); sb.append("\n return c[method]();"); sb.append("\n}"); - sb.append("\nfunction lazyVM(global) {"); - sb.append("\n var self = this;"); - sb.append("\n var glb = global;"); - sb.append("\n lazyVM.prototype.loadClass = function(res, name) {"); - sb.append("\n var script = org_apidesign_vm4brwsr_VMLazy(true)." - + "toJavaScript__Ljava_lang_String_2Ljava_lang_Object_2Ljava_lang_Object_2_3B(" - + " glb, self," - + " loader.get(res + '.class')" - + ");"); - sb.append("\n try {"); - sb.append("\n new Function(script)(glb, name);"); - sb.append("\n } catch (ex) {"); - sb.append("\n throw 'Cannot compile ' + res + ' error: ' + ex + ' script:\\n' + script;"); - sb.append("\n };"); - sb.append("\n return glb[name](true);"); - sb.append("\n };"); - sb.append("\n"); - sb.append("\n}\n"); - + ScriptEngine[] arr = { null }; code = StaticMethodTest.compileClass(sb, arr, - "org/apidesign/vm4brwsr/VMLazy" + "org/apidesign/vm4brwsr/GenJS" ); arr[0].getContext().setAttribute("loader", new FindBytes(), ScriptContext.ENGINE_SCOPE); codeSeq = sb; @@ -77,13 +61,13 @@ @Test public void invokeStaticMethod() throws Exception { assertExec("Trying to get -1", "test", Double.valueOf(-1), - "org/apidesign/vm4brwsr/StaticMethod", "org_apidesign_vm4brwsr_StaticMethod", "minusOne__I" + StaticMethod.class.getName(), "minusOne__I" ); } @Test public void loadDependantClass() throws Exception { - assertExec("Trying to get zero", "test", Double.valueOf(0), - "org/apidesign/vm4brwsr/InstanceSub", "org_apidesign_vm4brwsr_InstanceSub", "recallDbl__D" + assertExec("Expecting zero", "test", Double.valueOf(0), + InstanceSub.class.getName(), "recallDbl__D" ); } @@ -106,7 +90,13 @@ } public static final class FindBytes { + private static Set requested = new TreeSet(); + public byte[] get(String name) throws IOException { + if (!requested.add(name)) { + throw new IllegalStateException("Requested for second time: " + name); + } + InputStream is = VMLazyTest.class.getClassLoader().getResourceAsStream(name); if (is == null) { throw new IOException("Can't find " + name);