# HG changeset patch # User Jaroslav Tulach # Date 1371716570 -7200 # Node ID ccf2447021f6d9b92645fb8b5581fcae790b7b3d # Parent 29302b4c07769eeb5981337bb07a526454a8ba53 Using the Browser Bootstrap classloader diff -r 29302b4c0776 -r ccf2447021f6 launcher/fx/pom.xml --- a/launcher/fx/pom.xml Mon Jun 17 19:55:31 2013 +0200 +++ b/launcher/fx/pom.xml Thu Jun 20 10:22:50 2013 +0200 @@ -75,5 +75,10 @@ asm 4.1 + + org.apidesign.html + net.java.html.boot + 0.4-SNAPSHOT + diff -r 29302b4c0776 -r ccf2447021f6 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Fn.java --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/Fn.java Mon Jun 17 19:55:31 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +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.bck2brwsr.launcher.fximpl; - -/** - * - * @author Jaroslav Tulach - */ -public abstract class Fn { - public static Fn define(Class caller, String code, String... names) { - JsClassLoader cl = (JsClassLoader)caller.getClassLoader(); - return cl.defineFn(code, names); - } - - public abstract Object invoke(Object thiz, Object... args) throws Exception; - -} diff -r 29302b4c0776 -r ccf2447021f6 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Mon Jun 17 19:55:31 2013 +0200 +++ b/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JVMBridge.java Thu Jun 20 10:22:50 2013 +0200 @@ -17,17 +17,21 @@ */ package org.apidesign.bck2brwsr.launcher.fximpl; +import org.apidesign.html.boot.spi.Fn; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.TooManyListenersException; import javafx.beans.value.ChangeListener; import javafx.scene.web.WebEngine; -import javax.script.Invocable; +import net.java.html.boot.BrowserBuilder; import netscape.javascript.JSObject; +import org.apidesign.html.boot.impl.FindResources; +import org.apidesign.html.boot.impl.FnUtils; /** * @@ -35,14 +39,16 @@ */ public final class JVMBridge { private final WebEngine engine; - private final WebClassLoader cl; + private final ClassLoader cl; private static ClassLoader[] ldrs; private static ChangeListener onBck2BrwsrLoad; JVMBridge(WebEngine eng) { this.engine = eng; - this.cl = new WebClassLoader(JVMBridge.class.getClassLoader().getParent()); + final ClassLoader p = JVMBridge.class.getClassLoader().getParent(); + WebClassLoader wcl = new WebClassLoader(p); + this.cl = FnUtils.newLoader(wcl, wcl, p); } public static void registerClassLoaders(ClassLoader[] loaders) { @@ -67,38 +73,25 @@ return Class.forName(name, true, cl); } - private final class WebClassLoader extends JsClassLoader { + private final class WebClassLoader implements FindResources, Fn.Presenter { + private final ClassLoader cl; + public WebClassLoader(ClassLoader parent) { - super(parent); + this.cl = parent; } @Override - protected URL findResource(String name) { + public void findResources(String name, Collection results, boolean oneIsEnough) { if (ldrs != null) for (ClassLoader l : ldrs) { URL u = l.getResource(name); if (u != null) { - return u; + results.add(u); } } - return null; - } - - @Override - protected Enumeration findResources(String name) { - List arr = new ArrayList(); - if (ldrs != null) { - for (ClassLoader l : ldrs) { - URL u = l.getResource(name); - if (u != null) { - arr.add(u); - } - } - } - return Collections.enumeration(arr); } @Override - protected Fn defineFn(String code, String... names) { + public Fn defineFn(String code, String... names) { StringBuilder sb = new StringBuilder(); sb.append("(function() {"); sb.append(" return function("); @@ -115,6 +108,11 @@ JSObject x = (JSObject) engine.executeScript(sb.toString()); return new JSFn(x); } + + @Override + public void displayPage(URL page, Runnable onPageLoad) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } } private static final class JSFn extends Fn { diff -r 29302b4c0776 -r ccf2447021f6 launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader.java --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader.java Mon Jun 17 19:55:31 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,396 +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.bck2brwsr.launcher.fximpl; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.signature.SignatureReader; -import org.objectweb.asm.signature.SignatureVisitor; - -/** - * - * @author Jaroslav Tulach - */ -abstract class JsClassLoader extends ClassLoader { - JsClassLoader(ClassLoader parent) { - super(parent); - } - - @Override - protected abstract URL findResource(String name); - - @Override - protected abstract Enumeration findResources(String name); - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - if (name.startsWith("javafx")) { - return Class.forName(name); - } - if (name.startsWith("netscape")) { - return Class.forName(name); - } - if (name.startsWith("com.sun")) { - return Class.forName(name); - } - if (name.equals(JsClassLoader.class.getName())) { - return JsClassLoader.class; - } - if (name.equals(Fn.class.getName())) { - return Fn.class; - } - URL u = findResource(name.replace('.', '/') + ".class"); - if (u != null) { - InputStream is = null; - try { - is = u.openStream(); - byte[] arr = new byte[is.available()]; - int len = 0; - while (len < arr.length) { - int read = is.read(arr, len, arr.length - len); - if (read == -1) { - throw new IOException("Can't read " + u); - } - len += read; - } - is.close(); - is = null; - ClassReader cr = new ClassReader(arr); - FindInClass tst = new FindInClass(null); - cr.accept(tst, 0); - if (tst.found > 0) { - ClassWriter w = new ClassWriterEx(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); - FindInClass fic = new FindInClass(w); - cr.accept(fic, 0); - arr = w.toByteArray(); - } - if (arr != null) { - return defineClass(name, arr, 0, arr.length); - } - } catch (IOException ex) { - throw new ClassNotFoundException("Can't load " + name, ex); - } finally { - try { - if (is != null) is.close(); - } catch (IOException ex) { - throw new ClassNotFoundException(null, ex); - } - } - } - if (name.startsWith("org.apidesign.bck2brwsr.launcher.fximpl.Fn")) { - return Class.forName(name); - } - - return super.findClass(name); - } - - protected abstract Fn defineFn(String code, String... names); - - - private static final class FindInClass extends ClassVisitor { - private String name; - private int found; - - public FindInClass(ClassVisitor cv) { - super(Opcodes.ASM4, cv); - } - - @Override - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { - this.name = name; - super.visit(version, access, name, signature, superName, interfaces); - } - - - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { - return new FindInMethod(access, name, desc, - super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions) - ); - } - - private final class FindInMethod extends MethodVisitor { - private final String name; - private final String desc; - private final int access; - private List args; - private String body; - private boolean bodyGenerated; - - public FindInMethod(int access, String name, String desc, MethodVisitor mv) { - super(Opcodes.ASM4, mv); - this.access = access; - this.name = name; - this.desc = desc; - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if ("Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc)) { // NOI18N - found++; - return new FindInAnno(); - } - return super.visitAnnotation(desc, visible); - } - - private void generateJSBody(List args, String body) { - this.args = args; - this.body = body; - } - - @Override - public void visitCode() { - if (body == null) { - return; - } - generateBody(); - } - - private boolean generateBody() { - if (bodyGenerated) { - return false; - } - bodyGenerated = true; - - super.visitFieldInsn( - Opcodes.GETSTATIC, FindInClass.this.name, - "$$bck2brwsr$$" + name + "_" + found, - "Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;" - ); - super.visitInsn(Opcodes.DUP); - Label ifNotNull = new Label(); - super.visitJumpInsn(Opcodes.IFNONNULL, ifNotNull); - - // init Fn - super.visitInsn(Opcodes.POP); - super.visitLdcInsn(Type.getObjectType(FindInClass.this.name)); - super.visitLdcInsn(body); - super.visitIntInsn(Opcodes.SIPUSH, args.size()); - super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String"); - for (int i = 0; i < args.size(); i++) { - String name = args.get(i); - super.visitInsn(Opcodes.DUP); - super.visitIntInsn(Opcodes.BIPUSH, i); - super.visitLdcInsn(name); - super.visitInsn(Opcodes.AASTORE); - } - super.visitMethodInsn(Opcodes.INVOKESTATIC, - "org/apidesign/bck2brwsr/launcher/fximpl/Fn", "define", - "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;" - ); - // end of Fn init - - super.visitLabel(ifNotNull); - - final int offset; - if ((access & Opcodes.ACC_STATIC) == 0) { - offset = 1; - super.visitIntInsn(Opcodes.ALOAD, 0); - } else { - offset = 0; - super.visitInsn(Opcodes.ACONST_NULL); - } - - super.visitIntInsn(Opcodes.SIPUSH, args.size()); - super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); - - class SV extends SignatureVisitor { - private boolean nowReturn; - private Type returnType; - private int index; - - public SV() { - super(Opcodes.ASM4); - } - - @Override - public void visitBaseType(char descriptor) { - final Type t = Type.getType("" + descriptor); - if (nowReturn) { - returnType = t; - return; - } - FindInMethod.super.visitInsn(Opcodes.DUP); - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index); - FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), index + offset); - String factory; - switch (descriptor) { - case 'I': factory = "java/lang/Integer"; break; - case 'J': factory = "java/lang/Long"; break; - case 'S': factory = "java/lang/Short"; break; - case 'F': factory = "java/lang/Float"; break; - case 'D': factory = "java/lang/Double"; break; - case 'Z': factory = "java/lang/Boolean"; break; - case 'C': factory = "java/lang/Character"; break; - case 'B': factory = "java/lang/Byte"; break; - default: throw new IllegalStateException(t.toString()); - } - FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC, - factory, "valueOf", "(" + descriptor + ")L" + factory + ";" - ); - FindInMethod.super.visitInsn(Opcodes.AASTORE); - index++; - } - - @Override - public void visitClassType(String name) { - if (nowReturn) { - returnType = Type.getObjectType(name); - return; - } - FindInMethod.super.visitInsn(Opcodes.DUP); - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index); - FindInMethod.super.visitVarInsn(Opcodes.ALOAD, index + offset); - FindInMethod.super.visitInsn(Opcodes.AASTORE); - index++; - } - - @Override - public SignatureVisitor visitReturnType() { - nowReturn = true; - return this; - } - - - } - SV sv = new SV(); - SignatureReader sr = new SignatureReader(desc); - sr.accept(sv); - - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - "org/apidesign/bck2brwsr/launcher/fximpl/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" - ); - switch (sv.returnType.getSort()) { - case Type.VOID: - super.visitInsn(Opcodes.RETURN); - break; - case Type.ARRAY: - case Type.OBJECT: - super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName()); - super.visitInsn(Opcodes.ARETURN); - break; - default: - super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number"); - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor() - ); - super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN)); - } - return true; - } - - @Override - public void visitEnd() { - super.visitEnd(); - if (body != null) { - if (generateBody()) { - // native method - super.visitMaxs(1, 0); - } - FindInClass.this.visitField( - Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, - "$$bck2brwsr$$" + name + "_" + found, - "Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;", - null, null - ); - } - } - - - - - - private final class FindInAnno extends AnnotationVisitor { - private List args = new ArrayList(); - private String body; - - public FindInAnno() { - super(Opcodes.ASM4); - } - - @Override - public void visit(String name, Object value) { - if (name == null) { - args.add((String) value); - return; - } - assert name.equals("body"); - body = (String) value; - } - - @Override - public AnnotationVisitor visitArray(String name) { - return this; - } - - @Override - public void visitEnd() { - if (body != null) { - generateJSBody(args, body); - } - } - } - } - } - - private class ClassWriterEx extends ClassWriter { - - public ClassWriterEx(ClassReader classReader, int flags) { - super(classReader, flags); - } - - @Override - protected String getCommonSuperClass(final String type1, final String type2) { - Class c, d; - ClassLoader classLoader = JsClassLoader.this; - try { - c = Class.forName(type1.replace('/', '.'), false, classLoader); - d = Class.forName(type2.replace('/', '.'), false, classLoader); - } catch (Exception e) { - throw new RuntimeException(e.toString()); - } - if (c.isAssignableFrom(d)) { - return type1; - } - if (d.isAssignableFrom(c)) { - return type2; - } - if (c.isInterface() || d.isInterface()) { - return "java/lang/Object"; - } else { - do { - c = c.getSuperclass(); - } while (!c.isAssignableFrom(d)); - return c.getName().replace('.', '/'); - } - } - } -} diff -r 29302b4c0776 -r ccf2447021f6 launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoaderTest.java --- a/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoaderTest.java Mon Jun 17 19:55:31 2013 +0200 +++ b/launcher/fx/src/test/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoaderTest.java Thu Jun 20 10:22:50 2013 +0200 @@ -23,12 +23,15 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Arrays; -import java.util.Enumeration; +import java.util.Collection; import java.util.List; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; +import org.apidesign.html.boot.spi.Fn; +import org.apidesign.html.boot.impl.FindResources; +import org.apidesign.html.boot.impl.FnUtils; import static org.testng.Assert.*; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; @@ -52,13 +55,17 @@ final URL my = JsClassLoaderTest.class.getProtectionDomain().getCodeSource().getLocation(); ClassLoader parent = JsClassLoaderTest.class.getClassLoader().getParent(); final URLClassLoader ul = new URLClassLoader(new URL[] { my }, parent); - loader = new JsClassLoader(parent) { + class Fr implements FindResources, Fn.Presenter { @Override - protected URL findResource(String name) { - return ul.getResource(name); + public void findResources(String path, Collection results, boolean oneIsEnough) { + URL u = ul.getResource(path); + if (u != null) { + results.add(u); + } } + @Override - protected Fn defineFn(String code, String... names) { + public Fn defineFn(String code, String... names) { StringBuilder sb = new StringBuilder(); sb.append("(function() {"); sb.append("return function("); @@ -91,11 +98,12 @@ } @Override - protected Enumeration findResources(String name) { + public void displayPage(URL page, Runnable onPageLoad) { throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. } - }; + } + loader = FnUtils.newLoader(new Fr(), new Fr(), parent); methodClass = loader.loadClass(JsMethods.class.getName()); }