launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Mon, 10 Jun 2013 18:19:40 +0200
branchclassloader
changeset 1171 9753524d698f
parent 1170 ebedd84fba80
child 1172 c04c43d5fdc6
permissions -rw-r--r--
Separating the Fn class outside of the classloader and moving methods the generated code deals with into it
     1 /**
     2  * Back 2 Browser Bytecode Translator
     3  * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
     4  *
     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.
     8  *
     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.
    13  *
    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.
    17  */
    18 package org.apidesign.bck2brwsr.launcher.fximpl;
    19 
    20 import java.io.IOException;
    21 import java.io.InputStream;
    22 import java.net.URL;
    23 import java.net.URLClassLoader;
    24 import java.util.ArrayList;
    25 import java.util.List;
    26 import org.objectweb.asm.AnnotationVisitor;
    27 import org.objectweb.asm.ClassReader;
    28 import org.objectweb.asm.ClassVisitor;
    29 import org.objectweb.asm.ClassWriter;
    30 import org.objectweb.asm.Label;
    31 import org.objectweb.asm.MethodVisitor;
    32 import org.objectweb.asm.Opcodes;
    33 import org.objectweb.asm.Type;
    34 
    35 /** 
    36  *
    37  * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
    38  */
    39 abstract class JsClassLoader extends URLClassLoader {
    40     JsClassLoader(URL[] urls, ClassLoader parent) {
    41         super(urls, parent);
    42     }
    43 
    44     @Override
    45     protected Class<?> findClass(String name) throws ClassNotFoundException {
    46         URL u = findResource(name.replace('.', '/') + ".class");
    47         if (u != null) {
    48             InputStream is = null;
    49             try {
    50                 is = u.openStream();
    51                 ClassReader cr = new ClassReader(is);
    52                 ClassWriter w = new ClassWriter(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
    53                 FindInClass fic = new FindInClass(w);
    54                 cr.accept(fic, 0);
    55                 byte[] arr = w.toByteArray();
    56                 return defineClass(name, arr, 0, arr.length);
    57             } catch (IOException ex) {
    58                 throw new ClassNotFoundException("Can't load " + name, ex);
    59             } finally {
    60                 try {
    61                     if (is != null) is.close();
    62                 } catch (IOException ex) {
    63                     throw new ClassNotFoundException(null, ex);
    64                 }
    65             }
    66         }
    67         if (name.startsWith("org.apidesign.bck2brwsr.launcher.fximpl.Fn")) {
    68             return Class.forName(name);
    69         }
    70         
    71         return super.findClass(name);
    72     }
    73     
    74     protected abstract Fn defineFn(String code, String... names);
    75     
    76     
    77     private static final class FindInClass extends ClassVisitor {
    78         private String name;
    79         
    80         public FindInClass(ClassVisitor cv) {
    81             super(Opcodes.ASM4, cv);
    82         }
    83 
    84         @Override
    85         public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
    86             this.name = name;
    87             super.visit(version, access, name, signature, superName, interfaces);
    88         }
    89         
    90         
    91 
    92         @Override
    93         public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
    94             return new FindInMethod(name,
    95                 super.visitMethod(access, name, desc, signature, exceptions)
    96             );
    97         }
    98         
    99         private final class FindInMethod extends MethodVisitor {
   100             private final String name;
   101             private List<String> args;
   102             private String body;
   103             
   104             public FindInMethod(String name, MethodVisitor mv) {
   105                 super(Opcodes.ASM4, mv);
   106                 this.name = name;
   107             }
   108 
   109             @Override
   110             public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
   111                 if ("Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc)) { // NOI18N
   112                     return new FindInAnno();
   113                 }
   114                 return super.visitAnnotation(desc, visible);
   115             }
   116 
   117             private void generateJSBody(List<String> args, String body) {
   118                 this.args = args;
   119                 this.body = body;
   120             }
   121             
   122             @Override
   123             public void visitCode() {
   124                 if (body == null) {
   125                     return;
   126                 } 
   127                 
   128                 super.visitFieldInsn(
   129                     Opcodes.GETSTATIC, FindInClass.this.name, 
   130                     "$$bck2brwsr$$" + name, 
   131                     "Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;"
   132                 );
   133                 super.visitInsn(Opcodes.DUP);
   134                 Label ifNotNull = new Label();
   135                 super.visitJumpInsn(Opcodes.IFNONNULL, ifNotNull);
   136                 
   137                 // init Fn
   138                 super.visitInsn(Opcodes.POP);
   139                 super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
   140                 super.visitLdcInsn(body);
   141                 super.visitIntInsn(Opcodes.SIPUSH, args.size());
   142                 super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
   143                 for (int i = 0; i < args.size(); i++) {
   144                     String name = args.get(i);
   145                     super.visitInsn(Opcodes.DUP);
   146                     super.visitIntInsn(Opcodes.BIPUSH, i);
   147                     super.visitLdcInsn(name);
   148                     super.visitInsn(Opcodes.AASTORE);
   149                 }
   150                 super.visitMethodInsn(Opcodes.INVOKESTATIC, 
   151                     "org/apidesign/bck2brwsr/launcher/fximpl/Fn", "define", 
   152                     "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;"
   153                 );
   154                 // end of Fn init
   155                 
   156                 super.visitLabel(ifNotNull);
   157                 super.visitIntInsn(Opcodes.SIPUSH, args.size());
   158                 super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
   159                 super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, 
   160                     "org/apidesign/bck2brwsr/launcher/fximpl/Fn", "invoke", "([Ljava/lang/Object;)Ljava/lang/Object;"
   161                 );
   162                 super.visitInsn(Opcodes.ARETURN);
   163             }
   164 
   165             @Override
   166             public void visitEnd() {
   167                 super.visitEnd();
   168                 if (body != null) {
   169                     FindInClass.this.visitField(
   170                         Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, 
   171                         "$$bck2brwsr$$" + name, 
   172                         "Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;", 
   173                         null, null
   174                     );
   175                 }
   176             }
   177             
   178             
   179             
   180             
   181         
   182             private final class FindInAnno extends AnnotationVisitor {
   183                 private List<String> args = new ArrayList<String>();
   184                 private String body;
   185 
   186                 public FindInAnno() {
   187                     super(Opcodes.ASM4);
   188                 }
   189 
   190                 @Override
   191                 public void visit(String name, Object value) {
   192                     if (name == null) {
   193                         args.add((String) value);
   194                         return;
   195                     }
   196                     assert name.equals("body");
   197                     body = (String) value;
   198                 }
   199 
   200                 @Override
   201                 public AnnotationVisitor visitArray(String name) {
   202                     return this;
   203                 }
   204 
   205                 @Override
   206                 public void visitEnd() {
   207                     if (body != null) {
   208                         generateJSBody(args, body);
   209                     }
   210                 }
   211             }
   212         }
   213     }
   214 }