launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader.java
2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. Look for COPYING file in the top folder.
16 * If not, see http://opensource.org/licenses/GPL-2.0.
18 package org.apidesign.bck2brwsr.launcher.fximpl;
20 import java.io.IOException;
21 import java.io.InputStream;
23 import java.net.URLClassLoader;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.List;
27 import org.objectweb.asm.AnnotationVisitor;
28 import org.objectweb.asm.ClassReader;
29 import org.objectweb.asm.ClassVisitor;
30 import org.objectweb.asm.ClassWriter;
31 import org.objectweb.asm.Label;
32 import org.objectweb.asm.MethodVisitor;
33 import org.objectweb.asm.Opcodes;
34 import org.objectweb.asm.Type;
38 * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
40 public abstract class JsClassLoader extends URLClassLoader {
41 JsClassLoader(URL[] urls, ClassLoader parent) {
46 protected Class<?> findClass(String name) throws ClassNotFoundException {
47 URL u = findResource(name.replace('.', '/') + ".class");
49 InputStream is = null;
52 ClassReader cr = new ClassReader(is);
53 ClassWriter w = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
54 FindInClass fic = new FindInClass(w);
56 byte[] arr = w.toByteArray();
57 return defineClass(name, arr, 0, arr.length);
58 } catch (IOException ex) {
59 throw new ClassNotFoundException("Can't load " + name, ex);
62 if (is != null) is.close();
63 } catch (IOException ex) {
64 throw new ClassNotFoundException(null, ex);
68 if (name.startsWith("org.apidesign.bck2brwsr.launcher.fximpl.JsClassLoader")) {
69 return Class.forName(name);
72 return super.findClass(name);
75 public final Fn define(String code, String... names) {
76 return defineFn(code, names);
80 protected abstract Fn defineFn(String code, String... names);
82 public static abstract class Fn {
83 public abstract Object invoke(Object... args) throws Exception;
87 private static final class FindInClass extends ClassVisitor {
90 public FindInClass(ClassVisitor cv) {
91 super(Opcodes.ASM4, cv);
95 public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
97 super.visit(version, access, name, signature, superName, interfaces);
103 public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
104 return new FindInMethod(name,
105 super.visitMethod(access, name, desc, signature, exceptions)
109 private final class FindInMethod extends MethodVisitor {
110 private final String name;
111 private List<String> args;
114 public FindInMethod(String name, MethodVisitor mv) {
115 super(Opcodes.ASM4, mv);
120 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
121 if ("Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc)) { // NOI18N
122 return new FindInAnno();
124 return super.visitAnnotation(desc, visible);
127 private void generateJSBody(List<String> args, String body) {
133 public void visitCode() {
138 super.visitFieldInsn(
139 Opcodes.GETSTATIC, FindInClass.this.name,
140 "$$bck2brwsr$$" + name,
141 "Lorg/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader$Fn;"
143 super.visitInsn(Opcodes.DUP);
144 Label ifNotNull = new Label();
145 super.visitJumpInsn(Opcodes.IFNONNULL, ifNotNull);
148 super.visitInsn(Opcodes.POP);
149 super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
150 super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
151 "java/lang/Class", "getClassLoader", "()Ljava/lang/ClassLoader;"
153 super.visitTypeInsn(Opcodes.CHECKCAST, "org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader");
154 super.visitLdcInsn(body);
155 super.visitIntInsn(Opcodes.SIPUSH, args.size());
156 super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
157 for (int i = 0; i < args.size(); i++) {
158 String name = args.get(i);
159 super.visitInsn(Opcodes.DUP);
160 super.visitIntInsn(Opcodes.BIPUSH, i);
161 super.visitLdcInsn(name);
162 super.visitInsn(Opcodes.AASTORE);
164 super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
165 "org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader",
166 "define", "(Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader$Fn;"
170 super.visitLabel(ifNotNull);
171 super.visitIntInsn(Opcodes.SIPUSH, args.size());
172 super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
173 super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
174 "org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader$Fn", "invoke", "([Ljava/lang/Object;)Ljava/lang/Object;"
176 super.visitInsn(Opcodes.ARETURN);
180 public void visitEnd() {
183 FindInClass.this.visitField(
184 Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
185 "$$bck2brwsr$$" + name,
186 "Lorg/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader$Fn;",
196 private final class FindInAnno extends AnnotationVisitor {
197 private List<String> args = new ArrayList<String>();
200 public FindInAnno() {
205 public void visit(String name, Object value) {
207 args.add((String) value);
210 assert name.equals("body");
211 body = (String) value;
215 public AnnotationVisitor visitArray(String name) {
220 public void visitEnd() {
222 generateJSBody(args, body);