launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader.java
1.1 --- a/launcher/fx/src/main/java/org/apidesign/bck2brwsr/launcher/fximpl/JsClassLoader.java Mon Jun 17 19:55:31 2013 +0200
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,396 +0,0 @@
1.4 -/**
1.5 - * Back 2 Browser Bytecode Translator
1.6 - * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.7 - *
1.8 - * This program is free software: you can redistribute it and/or modify
1.9 - * it under the terms of the GNU General Public License as published by
1.10 - * the Free Software Foundation, version 2 of the License.
1.11 - *
1.12 - * This program is distributed in the hope that it will be useful,
1.13 - * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.14 - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.15 - * GNU General Public License for more details.
1.16 - *
1.17 - * You should have received a copy of the GNU General Public License
1.18 - * along with this program. Look for COPYING file in the top folder.
1.19 - * If not, see http://opensource.org/licenses/GPL-2.0.
1.20 - */
1.21 -package org.apidesign.bck2brwsr.launcher.fximpl;
1.22 -
1.23 -import java.io.IOException;
1.24 -import java.io.InputStream;
1.25 -import java.net.URL;
1.26 -import java.util.ArrayList;
1.27 -import java.util.Enumeration;
1.28 -import java.util.List;
1.29 -import org.objectweb.asm.AnnotationVisitor;
1.30 -import org.objectweb.asm.ClassReader;
1.31 -import org.objectweb.asm.ClassVisitor;
1.32 -import org.objectweb.asm.ClassWriter;
1.33 -import org.objectweb.asm.Label;
1.34 -import org.objectweb.asm.MethodVisitor;
1.35 -import org.objectweb.asm.Opcodes;
1.36 -import org.objectweb.asm.Type;
1.37 -import org.objectweb.asm.signature.SignatureReader;
1.38 -import org.objectweb.asm.signature.SignatureVisitor;
1.39 -
1.40 -/**
1.41 - *
1.42 - * @author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
1.43 - */
1.44 -abstract class JsClassLoader extends ClassLoader {
1.45 - JsClassLoader(ClassLoader parent) {
1.46 - super(parent);
1.47 - }
1.48 -
1.49 - @Override
1.50 - protected abstract URL findResource(String name);
1.51 -
1.52 - @Override
1.53 - protected abstract Enumeration<URL> findResources(String name);
1.54 -
1.55 - @Override
1.56 - protected Class<?> findClass(String name) throws ClassNotFoundException {
1.57 - if (name.startsWith("javafx")) {
1.58 - return Class.forName(name);
1.59 - }
1.60 - if (name.startsWith("netscape")) {
1.61 - return Class.forName(name);
1.62 - }
1.63 - if (name.startsWith("com.sun")) {
1.64 - return Class.forName(name);
1.65 - }
1.66 - if (name.equals(JsClassLoader.class.getName())) {
1.67 - return JsClassLoader.class;
1.68 - }
1.69 - if (name.equals(Fn.class.getName())) {
1.70 - return Fn.class;
1.71 - }
1.72 - URL u = findResource(name.replace('.', '/') + ".class");
1.73 - if (u != null) {
1.74 - InputStream is = null;
1.75 - try {
1.76 - is = u.openStream();
1.77 - byte[] arr = new byte[is.available()];
1.78 - int len = 0;
1.79 - while (len < arr.length) {
1.80 - int read = is.read(arr, len, arr.length - len);
1.81 - if (read == -1) {
1.82 - throw new IOException("Can't read " + u);
1.83 - }
1.84 - len += read;
1.85 - }
1.86 - is.close();
1.87 - is = null;
1.88 - ClassReader cr = new ClassReader(arr);
1.89 - FindInClass tst = new FindInClass(null);
1.90 - cr.accept(tst, 0);
1.91 - if (tst.found > 0) {
1.92 - ClassWriter w = new ClassWriterEx(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
1.93 - FindInClass fic = new FindInClass(w);
1.94 - cr.accept(fic, 0);
1.95 - arr = w.toByteArray();
1.96 - }
1.97 - if (arr != null) {
1.98 - return defineClass(name, arr, 0, arr.length);
1.99 - }
1.100 - } catch (IOException ex) {
1.101 - throw new ClassNotFoundException("Can't load " + name, ex);
1.102 - } finally {
1.103 - try {
1.104 - if (is != null) is.close();
1.105 - } catch (IOException ex) {
1.106 - throw new ClassNotFoundException(null, ex);
1.107 - }
1.108 - }
1.109 - }
1.110 - if (name.startsWith("org.apidesign.bck2brwsr.launcher.fximpl.Fn")) {
1.111 - return Class.forName(name);
1.112 - }
1.113 -
1.114 - return super.findClass(name);
1.115 - }
1.116 -
1.117 - protected abstract Fn defineFn(String code, String... names);
1.118 -
1.119 -
1.120 - private static final class FindInClass extends ClassVisitor {
1.121 - private String name;
1.122 - private int found;
1.123 -
1.124 - public FindInClass(ClassVisitor cv) {
1.125 - super(Opcodes.ASM4, cv);
1.126 - }
1.127 -
1.128 - @Override
1.129 - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
1.130 - this.name = name;
1.131 - super.visit(version, access, name, signature, superName, interfaces);
1.132 - }
1.133 -
1.134 -
1.135 -
1.136 - @Override
1.137 - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
1.138 - return new FindInMethod(access, name, desc,
1.139 - super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions)
1.140 - );
1.141 - }
1.142 -
1.143 - private final class FindInMethod extends MethodVisitor {
1.144 - private final String name;
1.145 - private final String desc;
1.146 - private final int access;
1.147 - private List<String> args;
1.148 - private String body;
1.149 - private boolean bodyGenerated;
1.150 -
1.151 - public FindInMethod(int access, String name, String desc, MethodVisitor mv) {
1.152 - super(Opcodes.ASM4, mv);
1.153 - this.access = access;
1.154 - this.name = name;
1.155 - this.desc = desc;
1.156 - }
1.157 -
1.158 - @Override
1.159 - public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
1.160 - if ("Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc)) { // NOI18N
1.161 - found++;
1.162 - return new FindInAnno();
1.163 - }
1.164 - return super.visitAnnotation(desc, visible);
1.165 - }
1.166 -
1.167 - private void generateJSBody(List<String> args, String body) {
1.168 - this.args = args;
1.169 - this.body = body;
1.170 - }
1.171 -
1.172 - @Override
1.173 - public void visitCode() {
1.174 - if (body == null) {
1.175 - return;
1.176 - }
1.177 - generateBody();
1.178 - }
1.179 -
1.180 - private boolean generateBody() {
1.181 - if (bodyGenerated) {
1.182 - return false;
1.183 - }
1.184 - bodyGenerated = true;
1.185 -
1.186 - super.visitFieldInsn(
1.187 - Opcodes.GETSTATIC, FindInClass.this.name,
1.188 - "$$bck2brwsr$$" + name + "_" + found,
1.189 - "Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;"
1.190 - );
1.191 - super.visitInsn(Opcodes.DUP);
1.192 - Label ifNotNull = new Label();
1.193 - super.visitJumpInsn(Opcodes.IFNONNULL, ifNotNull);
1.194 -
1.195 - // init Fn
1.196 - super.visitInsn(Opcodes.POP);
1.197 - super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
1.198 - super.visitLdcInsn(body);
1.199 - super.visitIntInsn(Opcodes.SIPUSH, args.size());
1.200 - super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
1.201 - for (int i = 0; i < args.size(); i++) {
1.202 - String name = args.get(i);
1.203 - super.visitInsn(Opcodes.DUP);
1.204 - super.visitIntInsn(Opcodes.BIPUSH, i);
1.205 - super.visitLdcInsn(name);
1.206 - super.visitInsn(Opcodes.AASTORE);
1.207 - }
1.208 - super.visitMethodInsn(Opcodes.INVOKESTATIC,
1.209 - "org/apidesign/bck2brwsr/launcher/fximpl/Fn", "define",
1.210 - "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;"
1.211 - );
1.212 - // end of Fn init
1.213 -
1.214 - super.visitLabel(ifNotNull);
1.215 -
1.216 - final int offset;
1.217 - if ((access & Opcodes.ACC_STATIC) == 0) {
1.218 - offset = 1;
1.219 - super.visitIntInsn(Opcodes.ALOAD, 0);
1.220 - } else {
1.221 - offset = 0;
1.222 - super.visitInsn(Opcodes.ACONST_NULL);
1.223 - }
1.224 -
1.225 - super.visitIntInsn(Opcodes.SIPUSH, args.size());
1.226 - super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
1.227 -
1.228 - class SV extends SignatureVisitor {
1.229 - private boolean nowReturn;
1.230 - private Type returnType;
1.231 - private int index;
1.232 -
1.233 - public SV() {
1.234 - super(Opcodes.ASM4);
1.235 - }
1.236 -
1.237 - @Override
1.238 - public void visitBaseType(char descriptor) {
1.239 - final Type t = Type.getType("" + descriptor);
1.240 - if (nowReturn) {
1.241 - returnType = t;
1.242 - return;
1.243 - }
1.244 - FindInMethod.super.visitInsn(Opcodes.DUP);
1.245 - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index);
1.246 - FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), index + offset);
1.247 - String factory;
1.248 - switch (descriptor) {
1.249 - case 'I': factory = "java/lang/Integer"; break;
1.250 - case 'J': factory = "java/lang/Long"; break;
1.251 - case 'S': factory = "java/lang/Short"; break;
1.252 - case 'F': factory = "java/lang/Float"; break;
1.253 - case 'D': factory = "java/lang/Double"; break;
1.254 - case 'Z': factory = "java/lang/Boolean"; break;
1.255 - case 'C': factory = "java/lang/Character"; break;
1.256 - case 'B': factory = "java/lang/Byte"; break;
1.257 - default: throw new IllegalStateException(t.toString());
1.258 - }
1.259 - FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC,
1.260 - factory, "valueOf", "(" + descriptor + ")L" + factory + ";"
1.261 - );
1.262 - FindInMethod.super.visitInsn(Opcodes.AASTORE);
1.263 - index++;
1.264 - }
1.265 -
1.266 - @Override
1.267 - public void visitClassType(String name) {
1.268 - if (nowReturn) {
1.269 - returnType = Type.getObjectType(name);
1.270 - return;
1.271 - }
1.272 - FindInMethod.super.visitInsn(Opcodes.DUP);
1.273 - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index);
1.274 - FindInMethod.super.visitVarInsn(Opcodes.ALOAD, index + offset);
1.275 - FindInMethod.super.visitInsn(Opcodes.AASTORE);
1.276 - index++;
1.277 - }
1.278 -
1.279 - @Override
1.280 - public SignatureVisitor visitReturnType() {
1.281 - nowReturn = true;
1.282 - return this;
1.283 - }
1.284 -
1.285 -
1.286 - }
1.287 - SV sv = new SV();
1.288 - SignatureReader sr = new SignatureReader(desc);
1.289 - sr.accept(sv);
1.290 -
1.291 - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1.292 - "org/apidesign/bck2brwsr/launcher/fximpl/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
1.293 - );
1.294 - switch (sv.returnType.getSort()) {
1.295 - case Type.VOID:
1.296 - super.visitInsn(Opcodes.RETURN);
1.297 - break;
1.298 - case Type.ARRAY:
1.299 - case Type.OBJECT:
1.300 - super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName());
1.301 - super.visitInsn(Opcodes.ARETURN);
1.302 - break;
1.303 - default:
1.304 - super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
1.305 - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1.306 - "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor()
1.307 - );
1.308 - super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN));
1.309 - }
1.310 - return true;
1.311 - }
1.312 -
1.313 - @Override
1.314 - public void visitEnd() {
1.315 - super.visitEnd();
1.316 - if (body != null) {
1.317 - if (generateBody()) {
1.318 - // native method
1.319 - super.visitMaxs(1, 0);
1.320 - }
1.321 - FindInClass.this.visitField(
1.322 - Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
1.323 - "$$bck2brwsr$$" + name + "_" + found,
1.324 - "Lorg/apidesign/bck2brwsr/launcher/fximpl/Fn;",
1.325 - null, null
1.326 - );
1.327 - }
1.328 - }
1.329 -
1.330 -
1.331 -
1.332 -
1.333 -
1.334 - private final class FindInAnno extends AnnotationVisitor {
1.335 - private List<String> args = new ArrayList<String>();
1.336 - private String body;
1.337 -
1.338 - public FindInAnno() {
1.339 - super(Opcodes.ASM4);
1.340 - }
1.341 -
1.342 - @Override
1.343 - public void visit(String name, Object value) {
1.344 - if (name == null) {
1.345 - args.add((String) value);
1.346 - return;
1.347 - }
1.348 - assert name.equals("body");
1.349 - body = (String) value;
1.350 - }
1.351 -
1.352 - @Override
1.353 - public AnnotationVisitor visitArray(String name) {
1.354 - return this;
1.355 - }
1.356 -
1.357 - @Override
1.358 - public void visitEnd() {
1.359 - if (body != null) {
1.360 - generateJSBody(args, body);
1.361 - }
1.362 - }
1.363 - }
1.364 - }
1.365 - }
1.366 -
1.367 - private class ClassWriterEx extends ClassWriter {
1.368 -
1.369 - public ClassWriterEx(ClassReader classReader, int flags) {
1.370 - super(classReader, flags);
1.371 - }
1.372 -
1.373 - @Override
1.374 - protected String getCommonSuperClass(final String type1, final String type2) {
1.375 - Class<?> c, d;
1.376 - ClassLoader classLoader = JsClassLoader.this;
1.377 - try {
1.378 - c = Class.forName(type1.replace('/', '.'), false, classLoader);
1.379 - d = Class.forName(type2.replace('/', '.'), false, classLoader);
1.380 - } catch (Exception e) {
1.381 - throw new RuntimeException(e.toString());
1.382 - }
1.383 - if (c.isAssignableFrom(d)) {
1.384 - return type1;
1.385 - }
1.386 - if (d.isAssignableFrom(c)) {
1.387 - return type2;
1.388 - }
1.389 - if (c.isInterface() || d.isInterface()) {
1.390 - return "java/lang/Object";
1.391 - } else {
1.392 - do {
1.393 - c = c.getSuperclass();
1.394 - } while (!c.isAssignableFrom(d));
1.395 - return c.getName().replace('.', '/');
1.396 - }
1.397 - }
1.398 - }
1.399 -}