diff -r 7025177bd67e -r 86aabecda7a3 boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java Thu Oct 10 14:02:18 2013 +0200 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java Wed Nov 06 15:15:54 2013 +0100 @@ -25,20 +25,7 @@ import java.io.InputStream; import java.io.Reader; 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; -import org.objectweb.asm.signature.SignatureWriter; /** * @@ -102,27 +89,7 @@ } is.close(); is = null; - ClassReader cr = new ClassReader(arr) { - // to allow us to compile with -profile compact1 on - // JDK8 while processing the class as JDK7, the highest - // class format asm 4.1 understands to - @Override - public short readShort(int index) { - short s = super.readShort(index); - if (index == 6 && s > Opcodes.V1_7) { - return Opcodes.V1_7; - } - return s; - } - }; - 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(); - } + arr = FnUtils.transform(JsClassLoader.this, arr); if (arr != null) { return defineClass(name, arr, 0, arr.length); } @@ -141,363 +108,4 @@ protected abstract Fn defineFn(String code, String... names); protected abstract void loadScript(Reader code) throws Exception; - - private 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 AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if ("Lnet/java/html/js/JavaScriptResource;".equals(desc)) { - return new LoadResource(); - } - return super.visitAnnotation(desc, visible); - } - - - @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 ( - "Lnet/java/html/js/JavaScriptBody;".equals(desc) // NOI18N - || "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, - "$$fn$$" + name + "_" + found, - "Lorg/apidesign/html/boot/spi/Fn;" - ); - super.visitInsn(Opcodes.DUP); - super.visitMethodInsn( - Opcodes.INVOKESTATIC, - "org/apidesign/html/boot/impl/FnUtils", "isValid", - "(Lorg/apidesign/html/boot/spi/Fn;)Z" - ); - Label ifNotNull = new Label(); - super.visitJumpInsn(Opcodes.IFNE, 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"); - boolean needsVM = false; - for (int i = 0; i < args.size(); i++) { - assert !needsVM; - String argName = args.get(i); - needsVM = "vm".equals(argName); - super.visitInsn(Opcodes.DUP); - super.visitIntInsn(Opcodes.BIPUSH, i); - super.visitLdcInsn(argName); - super.visitInsn(Opcodes.AASTORE); - } - super.visitMethodInsn(Opcodes.INVOKESTATIC, - "org/apidesign/html/boot/impl/FnUtils", "define", - "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;" - ); - super.visitInsn(Opcodes.DUP); - super.visitFieldInsn( - Opcodes.PUTSTATIC, FindInClass.this.name, - "$$fn$$" + name + "_" + found, - "Lorg/apidesign/html/boot/spi/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; - private int loadIndex = offset; - - 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), loadIndex++); - String factory; - switch (descriptor) { - case 'I': factory = "java/lang/Integer"; break; - case 'J': factory = "java/lang/Long"; loadIndex++; break; - case 'S': factory = "java/lang/Short"; break; - case 'F': factory = "java/lang/Float"; break; - case 'D': factory = "java/lang/Double"; loadIndex++; 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); - } - - @Override - public SignatureVisitor visitArrayType() { - if (nowReturn) { - throw new IllegalStateException("Not supported yet"); - } - loadObject(); - return new SignatureWriter(); - } - - @Override - public void visitClassType(String name) { - if (nowReturn) { - returnType = Type.getObjectType(name); - return; - } - loadObject(); - } - - @Override - public SignatureVisitor visitReturnType() { - nowReturn = true; - return this; - } - - private void loadObject() { - FindInMethod.super.visitInsn(Opcodes.DUP); - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++); - FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++); - FindInMethod.super.visitInsn(Opcodes.AASTORE); - } - - } - SV sv = new SV(); - SignatureReader sr = new SignatureReader(desc); - sr.accept(sv); - - if (needsVM) { - FindInMethod.super.visitInsn(Opcodes.DUP); - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index); - int lastSlash = FindInClass.this.name.lastIndexOf('/'); - String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$"; - FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";"); - FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";"); - FindInMethod.super.visitInsn(Opcodes.AASTORE); - } - - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - "org/apidesign/html/boot/spi/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; - case Type.BOOLEAN: - super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean"); - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, - "java/lang/Boolean", "booleanValue", "()Z" - ); - super.visitInsn(Opcodes.IRETURN); - 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, - "$$fn$$" + name + "_" + found, - "Lorg/apidesign/html/boot/spi/Fn;", - null, null - ); - } - } - - - - - - private final class FindInAnno extends AnnotationVisitor { - private List args = new ArrayList(); - private String body; - private boolean javacall = false; - - public FindInAnno() { - super(Opcodes.ASM4); - } - - @Override - public void visit(String name, Object value) { - if (name == null) { - args.add((String) value); - return; - } - if (name.equals("javacall")) { // NOI18N - javacall = (Boolean)value; - return; - } - assert name.equals("body"); - body = (String) value; - } - - @Override - public AnnotationVisitor visitArray(String name) { - return this; - } - - @Override - public void visitEnd() { - if (body != null) { - if (javacall) { - body = FnUtils.callback(body); - args.add("vm"); - } - generateJSBody(args, body); - } - } - } - } - - private final class LoadResource extends AnnotationVisitor { - public LoadResource() { - super(Opcodes.ASM4); - } - - @Override - public void visit(String attrName, Object value) { - String relPath = (String) value; - if (relPath.startsWith("/")) { - FnUtils.loadScript(JsClassLoader.this, relPath); - } else { - int last = name.lastIndexOf('/'); - String fullPath = name.substring(0, last + 1) + relPath; - FnUtils.loadScript(JsClassLoader.this, fullPath); - } - } - } - } - - 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('.', '/'); - } - } - } }