1.1 --- a/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java Thu Oct 10 14:02:18 2013 +0200
1.2 +++ b/boot/src/main/java/org/apidesign/html/boot/impl/JsClassLoader.java Wed Nov 06 15:15:54 2013 +0100
1.3 @@ -25,20 +25,7 @@
1.4 import java.io.InputStream;
1.5 import java.io.Reader;
1.6 import java.net.URL;
1.7 -import java.util.ArrayList;
1.8 import java.util.Enumeration;
1.9 -import java.util.List;
1.10 -import org.objectweb.asm.AnnotationVisitor;
1.11 -import org.objectweb.asm.ClassReader;
1.12 -import org.objectweb.asm.ClassVisitor;
1.13 -import org.objectweb.asm.ClassWriter;
1.14 -import org.objectweb.asm.Label;
1.15 -import org.objectweb.asm.MethodVisitor;
1.16 -import org.objectweb.asm.Opcodes;
1.17 -import org.objectweb.asm.Type;
1.18 -import org.objectweb.asm.signature.SignatureReader;
1.19 -import org.objectweb.asm.signature.SignatureVisitor;
1.20 -import org.objectweb.asm.signature.SignatureWriter;
1.21
1.22 /**
1.23 *
1.24 @@ -102,27 +89,7 @@
1.25 }
1.26 is.close();
1.27 is = null;
1.28 - ClassReader cr = new ClassReader(arr) {
1.29 - // to allow us to compile with -profile compact1 on
1.30 - // JDK8 while processing the class as JDK7, the highest
1.31 - // class format asm 4.1 understands to
1.32 - @Override
1.33 - public short readShort(int index) {
1.34 - short s = super.readShort(index);
1.35 - if (index == 6 && s > Opcodes.V1_7) {
1.36 - return Opcodes.V1_7;
1.37 - }
1.38 - return s;
1.39 - }
1.40 - };
1.41 - FindInClass tst = new FindInClass(null);
1.42 - cr.accept(tst, 0);
1.43 - if (tst.found > 0) {
1.44 - ClassWriter w = new ClassWriterEx(cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
1.45 - FindInClass fic = new FindInClass(w);
1.46 - cr.accept(fic, 0);
1.47 - arr = w.toByteArray();
1.48 - }
1.49 + arr = FnUtils.transform(JsClassLoader.this, arr);
1.50 if (arr != null) {
1.51 return defineClass(name, arr, 0, arr.length);
1.52 }
1.53 @@ -141,363 +108,4 @@
1.54
1.55 protected abstract Fn defineFn(String code, String... names);
1.56 protected abstract void loadScript(Reader code) throws Exception;
1.57 -
1.58 - private final class FindInClass extends ClassVisitor {
1.59 - private String name;
1.60 - private int found;
1.61 -
1.62 - public FindInClass(ClassVisitor cv) {
1.63 - super(Opcodes.ASM4, cv);
1.64 - }
1.65 -
1.66 - @Override
1.67 - public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
1.68 - this.name = name;
1.69 - super.visit(version, access, name, signature, superName, interfaces);
1.70 - }
1.71 -
1.72 - @Override
1.73 - public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
1.74 - if ("Lnet/java/html/js/JavaScriptResource;".equals(desc)) {
1.75 - return new LoadResource();
1.76 - }
1.77 - return super.visitAnnotation(desc, visible);
1.78 - }
1.79 -
1.80 -
1.81 - @Override
1.82 - public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
1.83 - return new FindInMethod(access, name, desc,
1.84 - super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions)
1.85 - );
1.86 - }
1.87 -
1.88 - private final class FindInMethod extends MethodVisitor {
1.89 - private final String name;
1.90 - private final String desc;
1.91 - private final int access;
1.92 - private List<String> args;
1.93 - private String body;
1.94 - private boolean bodyGenerated;
1.95 -
1.96 - public FindInMethod(int access, String name, String desc, MethodVisitor mv) {
1.97 - super(Opcodes.ASM4, mv);
1.98 - this.access = access;
1.99 - this.name = name;
1.100 - this.desc = desc;
1.101 - }
1.102 -
1.103 - @Override
1.104 - public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
1.105 - if (
1.106 - "Lnet/java/html/js/JavaScriptBody;".equals(desc) // NOI18N
1.107 - || "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc) // NOI18N
1.108 - ) {
1.109 - found++;
1.110 - return new FindInAnno();
1.111 - }
1.112 - return super.visitAnnotation(desc, visible);
1.113 - }
1.114 -
1.115 - private void generateJSBody(List<String> args, String body) {
1.116 - this.args = args;
1.117 - this.body = body;
1.118 - }
1.119 -
1.120 - @Override
1.121 - public void visitCode() {
1.122 - if (body == null) {
1.123 - return;
1.124 - }
1.125 - generateBody();
1.126 - }
1.127 -
1.128 - private boolean generateBody() {
1.129 - if (bodyGenerated) {
1.130 - return false;
1.131 - }
1.132 - bodyGenerated = true;
1.133 -
1.134 - super.visitFieldInsn(
1.135 - Opcodes.GETSTATIC, FindInClass.this.name,
1.136 - "$$fn$$" + name + "_" + found,
1.137 - "Lorg/apidesign/html/boot/spi/Fn;"
1.138 - );
1.139 - super.visitInsn(Opcodes.DUP);
1.140 - super.visitMethodInsn(
1.141 - Opcodes.INVOKESTATIC,
1.142 - "org/apidesign/html/boot/impl/FnUtils", "isValid",
1.143 - "(Lorg/apidesign/html/boot/spi/Fn;)Z"
1.144 - );
1.145 - Label ifNotNull = new Label();
1.146 - super.visitJumpInsn(Opcodes.IFNE, ifNotNull);
1.147 -
1.148 - // init Fn
1.149 - super.visitInsn(Opcodes.POP);
1.150 - super.visitLdcInsn(Type.getObjectType(FindInClass.this.name));
1.151 - super.visitLdcInsn(body);
1.152 - super.visitIntInsn(Opcodes.SIPUSH, args.size());
1.153 - super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String");
1.154 - boolean needsVM = false;
1.155 - for (int i = 0; i < args.size(); i++) {
1.156 - assert !needsVM;
1.157 - String argName = args.get(i);
1.158 - needsVM = "vm".equals(argName);
1.159 - super.visitInsn(Opcodes.DUP);
1.160 - super.visitIntInsn(Opcodes.BIPUSH, i);
1.161 - super.visitLdcInsn(argName);
1.162 - super.visitInsn(Opcodes.AASTORE);
1.163 - }
1.164 - super.visitMethodInsn(Opcodes.INVOKESTATIC,
1.165 - "org/apidesign/html/boot/impl/FnUtils", "define",
1.166 - "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;"
1.167 - );
1.168 - super.visitInsn(Opcodes.DUP);
1.169 - super.visitFieldInsn(
1.170 - Opcodes.PUTSTATIC, FindInClass.this.name,
1.171 - "$$fn$$" + name + "_" + found,
1.172 - "Lorg/apidesign/html/boot/spi/Fn;"
1.173 - );
1.174 - // end of Fn init
1.175 -
1.176 - super.visitLabel(ifNotNull);
1.177 -
1.178 - final int offset;
1.179 - if ((access & Opcodes.ACC_STATIC) == 0) {
1.180 - offset = 1;
1.181 - super.visitIntInsn(Opcodes.ALOAD, 0);
1.182 - } else {
1.183 - offset = 0;
1.184 - super.visitInsn(Opcodes.ACONST_NULL);
1.185 - }
1.186 -
1.187 - super.visitIntInsn(Opcodes.SIPUSH, args.size());
1.188 - super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
1.189 -
1.190 - class SV extends SignatureVisitor {
1.191 - private boolean nowReturn;
1.192 - private Type returnType;
1.193 - private int index;
1.194 - private int loadIndex = offset;
1.195 -
1.196 - public SV() {
1.197 - super(Opcodes.ASM4);
1.198 - }
1.199 -
1.200 - @Override
1.201 - public void visitBaseType(char descriptor) {
1.202 - final Type t = Type.getType("" + descriptor);
1.203 - if (nowReturn) {
1.204 - returnType = t;
1.205 - return;
1.206 - }
1.207 - FindInMethod.super.visitInsn(Opcodes.DUP);
1.208 - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
1.209 - FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), loadIndex++);
1.210 - String factory;
1.211 - switch (descriptor) {
1.212 - case 'I': factory = "java/lang/Integer"; break;
1.213 - case 'J': factory = "java/lang/Long"; loadIndex++; break;
1.214 - case 'S': factory = "java/lang/Short"; break;
1.215 - case 'F': factory = "java/lang/Float"; break;
1.216 - case 'D': factory = "java/lang/Double"; loadIndex++; break;
1.217 - case 'Z': factory = "java/lang/Boolean"; break;
1.218 - case 'C': factory = "java/lang/Character"; break;
1.219 - case 'B': factory = "java/lang/Byte"; break;
1.220 - default: throw new IllegalStateException(t.toString());
1.221 - }
1.222 - FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC,
1.223 - factory, "valueOf", "(" + descriptor + ")L" + factory + ";"
1.224 - );
1.225 - FindInMethod.super.visitInsn(Opcodes.AASTORE);
1.226 - }
1.227 -
1.228 - @Override
1.229 - public SignatureVisitor visitArrayType() {
1.230 - if (nowReturn) {
1.231 - throw new IllegalStateException("Not supported yet");
1.232 - }
1.233 - loadObject();
1.234 - return new SignatureWriter();
1.235 - }
1.236 -
1.237 - @Override
1.238 - public void visitClassType(String name) {
1.239 - if (nowReturn) {
1.240 - returnType = Type.getObjectType(name);
1.241 - return;
1.242 - }
1.243 - loadObject();
1.244 - }
1.245 -
1.246 - @Override
1.247 - public SignatureVisitor visitReturnType() {
1.248 - nowReturn = true;
1.249 - return this;
1.250 - }
1.251 -
1.252 - private void loadObject() {
1.253 - FindInMethod.super.visitInsn(Opcodes.DUP);
1.254 - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++);
1.255 - FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++);
1.256 - FindInMethod.super.visitInsn(Opcodes.AASTORE);
1.257 - }
1.258 -
1.259 - }
1.260 - SV sv = new SV();
1.261 - SignatureReader sr = new SignatureReader(desc);
1.262 - sr.accept(sv);
1.263 -
1.264 - if (needsVM) {
1.265 - FindInMethod.super.visitInsn(Opcodes.DUP);
1.266 - FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index);
1.267 - int lastSlash = FindInClass.this.name.lastIndexOf('/');
1.268 - String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$";
1.269 - FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";");
1.270 - FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";");
1.271 - FindInMethod.super.visitInsn(Opcodes.AASTORE);
1.272 - }
1.273 -
1.274 - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1.275 - "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"
1.276 - );
1.277 - switch (sv.returnType.getSort()) {
1.278 - case Type.VOID:
1.279 - super.visitInsn(Opcodes.RETURN);
1.280 - break;
1.281 - case Type.ARRAY:
1.282 - case Type.OBJECT:
1.283 - super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName());
1.284 - super.visitInsn(Opcodes.ARETURN);
1.285 - break;
1.286 - case Type.BOOLEAN:
1.287 - super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean");
1.288 - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1.289 - "java/lang/Boolean", "booleanValue", "()Z"
1.290 - );
1.291 - super.visitInsn(Opcodes.IRETURN);
1.292 - break;
1.293 - default:
1.294 - super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number");
1.295 - super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
1.296 - "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor()
1.297 - );
1.298 - super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN));
1.299 - }
1.300 - return true;
1.301 - }
1.302 -
1.303 - @Override
1.304 - public void visitEnd() {
1.305 - super.visitEnd();
1.306 - if (body != null) {
1.307 - if (generateBody()) {
1.308 - // native method
1.309 - super.visitMaxs(1, 0);
1.310 - }
1.311 - FindInClass.this.visitField(
1.312 - Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC,
1.313 - "$$fn$$" + name + "_" + found,
1.314 - "Lorg/apidesign/html/boot/spi/Fn;",
1.315 - null, null
1.316 - );
1.317 - }
1.318 - }
1.319 -
1.320 -
1.321 -
1.322 -
1.323 -
1.324 - private final class FindInAnno extends AnnotationVisitor {
1.325 - private List<String> args = new ArrayList<String>();
1.326 - private String body;
1.327 - private boolean javacall = false;
1.328 -
1.329 - public FindInAnno() {
1.330 - super(Opcodes.ASM4);
1.331 - }
1.332 -
1.333 - @Override
1.334 - public void visit(String name, Object value) {
1.335 - if (name == null) {
1.336 - args.add((String) value);
1.337 - return;
1.338 - }
1.339 - if (name.equals("javacall")) { // NOI18N
1.340 - javacall = (Boolean)value;
1.341 - return;
1.342 - }
1.343 - assert name.equals("body");
1.344 - body = (String) value;
1.345 - }
1.346 -
1.347 - @Override
1.348 - public AnnotationVisitor visitArray(String name) {
1.349 - return this;
1.350 - }
1.351 -
1.352 - @Override
1.353 - public void visitEnd() {
1.354 - if (body != null) {
1.355 - if (javacall) {
1.356 - body = FnUtils.callback(body);
1.357 - args.add("vm");
1.358 - }
1.359 - generateJSBody(args, body);
1.360 - }
1.361 - }
1.362 - }
1.363 - }
1.364 -
1.365 - private final class LoadResource extends AnnotationVisitor {
1.366 - public LoadResource() {
1.367 - super(Opcodes.ASM4);
1.368 - }
1.369 -
1.370 - @Override
1.371 - public void visit(String attrName, Object value) {
1.372 - String relPath = (String) value;
1.373 - if (relPath.startsWith("/")) {
1.374 - FnUtils.loadScript(JsClassLoader.this, relPath);
1.375 - } else {
1.376 - int last = name.lastIndexOf('/');
1.377 - String fullPath = name.substring(0, last + 1) + relPath;
1.378 - FnUtils.loadScript(JsClassLoader.this, fullPath);
1.379 - }
1.380 - }
1.381 - }
1.382 - }
1.383 -
1.384 - private class ClassWriterEx extends ClassWriter {
1.385 -
1.386 - public ClassWriterEx(ClassReader classReader, int flags) {
1.387 - super(classReader, flags);
1.388 - }
1.389 -
1.390 - @Override
1.391 - protected String getCommonSuperClass(final String type1, final String type2) {
1.392 - Class<?> c, d;
1.393 - ClassLoader classLoader = JsClassLoader.this;
1.394 - try {
1.395 - c = Class.forName(type1.replace('/', '.'), false, classLoader);
1.396 - d = Class.forName(type2.replace('/', '.'), false, classLoader);
1.397 - } catch (Exception e) {
1.398 - throw new RuntimeException(e.toString());
1.399 - }
1.400 - if (c.isAssignableFrom(d)) {
1.401 - return type1;
1.402 - }
1.403 - if (d.isAssignableFrom(c)) {
1.404 - return type2;
1.405 - }
1.406 - if (c.isInterface() || d.isInterface()) {
1.407 - return "java/lang/Object";
1.408 - } else {
1.409 - do {
1.410 - c = c.getSuperclass();
1.411 - } while (!c.isAssignableFrom(d));
1.412 - return c.getName().replace('.', '/');
1.413 - }
1.414 - }
1.415 - }
1.416 }