jaroslav@123: /** jaroslav@123: * HTML via Java(tm) Language Bindings jaroslav@123: * Copyright (C) 2013 Jaroslav Tulach jaroslav@123: * jaroslav@123: * This program is free software: you can redistribute it and/or modify jaroslav@123: * it under the terms of the GNU General Public License as published by jaroslav@123: * the Free Software Foundation, version 2 of the License. jaroslav@123: * jaroslav@123: * This program is distributed in the hope that it will be useful, jaroslav@123: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@123: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@123: * GNU General Public License for more details. apidesign.org jaroslav@123: * designates this particular file as subject to the jaroslav@123: * "Classpath" exception as provided by apidesign.org jaroslav@123: * in the License file that accompanied this code. jaroslav@123: * jaroslav@123: * You should have received a copy of the GNU General Public License jaroslav@123: * along with this program. Look for COPYING file in the top folder. jaroslav@123: * If not, see http://wiki.apidesign.org/wiki/GPLwithClassPathException jaroslav@123: */ jaroslav@123: package org.apidesign.html.boot.impl; jaroslav@123: jaroslav@323: import java.io.Closeable; jaroslav@163: import java.io.InputStream; jaroslav@163: import java.io.InputStreamReader; jaroslav@163: import java.io.Reader; jaroslav@123: import java.net.URL; jaroslav@123: import java.util.ArrayList; jaroslav@123: import java.util.Collections; jaroslav@123: import java.util.Enumeration; jaroslav@123: import java.util.List; jaroslav@323: import java.util.concurrent.Callable; jaroslav@123: import org.apidesign.html.boot.spi.Fn; jaroslav@323: import org.objectweb.asm.AnnotationVisitor; jaroslav@323: import org.objectweb.asm.ClassReader; jaroslav@323: import org.objectweb.asm.ClassVisitor; jaroslav@323: import org.objectweb.asm.ClassWriter; jaroslav@323: import org.objectweb.asm.Label; jaroslav@323: import org.objectweb.asm.MethodVisitor; jaroslav@323: import org.objectweb.asm.Opcodes; jaroslav@323: import org.objectweb.asm.Type; jaroslav@323: import org.objectweb.asm.signature.SignatureReader; jaroslav@323: import org.objectweb.asm.signature.SignatureVisitor; jaroslav@323: import org.objectweb.asm.signature.SignatureWriter; jaroslav@123: jaroslav@123: /** jaroslav@123: * jaroslav@123: * @author Jaroslav Tulach jaroslav@123: */ jaroslav@323: public final class FnUtils implements Fn.Presenter { jaroslav@288: jaroslav@123: private FnUtils() { jaroslav@123: } jaroslav@288: jaroslav@288: public static boolean isJavaScriptCapable(ClassLoader l) { jaroslav@323: if (l instanceof JsClassLoader) { jaroslav@323: return true; jaroslav@323: } jaroslav@323: Class clazz; jaroslav@323: try (Closeable c = Fn.activate(new FnUtils())) { jaroslav@323: clazz = Class.forName(Test.class.getName(), true, l); jaroslav@323: final Object is = ((Callable)clazz.newInstance()).call(); jaroslav@323: return Boolean.TRUE.equals(is); jaroslav@323: } catch (Exception ex) { jaroslav@323: return false; jaroslav@323: } jaroslav@288: } jaroslav@288: jaroslav@288: public static boolean isValid(Fn fn) { jaroslav@288: return fn != null && fn.isValid(); jaroslav@123: } jaroslav@123: jaroslav@128: public static ClassLoader newLoader(final FindResources f, final Fn.Presenter d, ClassLoader parent) { jaroslav@123: return new JsClassLoader(parent) { jaroslav@123: @Override jaroslav@123: protected URL findResource(String name) { jaroslav@123: List l = res(name, true); jaroslav@123: return l.isEmpty() ? null : l.get(0); jaroslav@123: } jaroslav@123: jaroslav@123: @Override jaroslav@123: protected Enumeration findResources(String name) { jaroslav@123: return Collections.enumeration(res(name, false)); jaroslav@123: } jaroslav@123: jaroslav@123: private List res(String name, boolean oneIsEnough) { jaroslav@123: List l = new ArrayList(); jaroslav@123: f.findResources(name, l, oneIsEnough); jaroslav@123: return l; jaroslav@123: } jaroslav@123: jaroslav@123: @Override jaroslav@123: protected Fn defineFn(String code, String... names) { jaroslav@123: return d.defineFn(code, names); jaroslav@123: } jaroslav@163: jaroslav@163: @Override jaroslav@163: protected void loadScript(Reader code) throws Exception { jaroslav@163: d.loadScript(code); jaroslav@163: } jaroslav@123: }; jaroslav@123: } jaroslav@160: jaroslav@189: static String callback(final String body) { jaroslav@184: return new JsCallback() { jaroslav@184: @Override jaroslav@184: protected CharSequence callMethod( jaroslav@184: String ident, String fqn, String method, String params jaroslav@184: ) { jaroslav@188: StringBuilder sb = new StringBuilder(); jaroslav@188: sb.append("vm.").append(mangle(fqn, method, params)); jaroslav@191: sb.append("("); jaroslav@191: if (ident != null) { jaroslav@191: sb.append(ident); jaroslav@191: } jaroslav@188: return sb; jaroslav@184: } jaroslav@184: jaroslav@184: }.parse(body); jaroslav@160: } jaroslav@163: jaroslav@323: static void loadScript(ClassLoader jcl, String resource) { jaroslav@163: final InputStream script = jcl.getResourceAsStream(resource); jaroslav@163: if (script == null) { jaroslav@163: throw new NullPointerException("Can't find " + resource); jaroslav@163: } jaroslav@163: try { jaroslav@163: Reader isr = null; jaroslav@163: try { jaroslav@163: isr = new InputStreamReader(script, "UTF-8"); jaroslav@323: FnContext.currentPresenter().loadScript(isr); jaroslav@163: } finally { jaroslav@163: if (isr != null) { jaroslav@163: isr.close(); jaroslav@163: } jaroslav@163: } jaroslav@163: } catch (Exception ex) { jaroslav@163: throw new IllegalStateException("Can't execute " + resource, ex); jaroslav@163: } jaroslav@163: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public Fn defineFn(String code, String... names) { jaroslav@323: return new TrueFn(); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void displayPage(URL page, Runnable onPageLoad) { jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void loadScript(Reader code) throws Exception { jaroslav@323: } jaroslav@323: jaroslav@323: private static final class FindInClass extends ClassVisitor { jaroslav@323: private String name; jaroslav@323: private int found; jaroslav@323: private ClassLoader loader; jaroslav@323: jaroslav@323: public FindInClass(ClassLoader l, ClassVisitor cv) { jaroslav@323: super(Opcodes.ASM4, cv); jaroslav@323: this.loader = l; jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { jaroslav@323: this.name = name; jaroslav@323: super.visit(version, access, name, signature, superName, interfaces); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public AnnotationVisitor visitAnnotation(String desc, boolean visible) { jaroslav@323: if ("Lnet/java/html/js/JavaScriptResource;".equals(desc)) { jaroslav@323: return new LoadResource(); jaroslav@323: } jaroslav@323: return super.visitAnnotation(desc, visible); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { jaroslav@323: return new FindInMethod(access, name, desc, jaroslav@323: super.visitMethod(access & (~Opcodes.ACC_NATIVE), name, desc, signature, exceptions) jaroslav@323: ); jaroslav@323: } jaroslav@323: jaroslav@323: private final class FindInMethod extends MethodVisitor { jaroslav@323: jaroslav@323: private final String name; jaroslav@323: private final String desc; jaroslav@323: private final int access; jaroslav@323: private List args; jaroslav@323: private String body; jaroslav@323: private boolean bodyGenerated; jaroslav@323: jaroslav@323: public FindInMethod(int access, String name, String desc, MethodVisitor mv) { jaroslav@323: super(Opcodes.ASM4, mv); jaroslav@323: this.access = access; jaroslav@323: this.name = name; jaroslav@323: this.desc = desc; jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public AnnotationVisitor visitAnnotation(String desc, boolean visible) { jaroslav@323: if ("Lnet/java/html/js/JavaScriptBody;".equals(desc) // NOI18N jaroslav@323: || "Lorg/apidesign/bck2brwsr/core/JavaScriptBody;".equals(desc) // NOI18N jaroslav@323: ) { jaroslav@323: found++; jaroslav@323: return new FindInAnno(); jaroslav@323: } jaroslav@323: return super.visitAnnotation(desc, visible); jaroslav@323: } jaroslav@323: jaroslav@323: private void generateJSBody(List args, String body) { jaroslav@323: this.args = args; jaroslav@323: this.body = body; jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void visitCode() { jaroslav@323: if (body == null) { jaroslav@323: return; jaroslav@323: } jaroslav@323: generateBody(); jaroslav@323: } jaroslav@323: jaroslav@323: private boolean generateBody() { jaroslav@323: if (bodyGenerated) { jaroslav@323: return false; jaroslav@323: } jaroslav@323: bodyGenerated = true; jaroslav@323: jaroslav@323: super.visitFieldInsn( jaroslav@323: Opcodes.GETSTATIC, FindInClass.this.name, jaroslav@323: "$$fn$$" + name + "_" + found, jaroslav@323: "Lorg/apidesign/html/boot/spi/Fn;" jaroslav@323: ); jaroslav@323: super.visitInsn(Opcodes.DUP); jaroslav@323: super.visitMethodInsn( jaroslav@323: Opcodes.INVOKESTATIC, jaroslav@323: "org/apidesign/html/boot/spi/Fn", "isValid", jaroslav@323: "(Lorg/apidesign/html/boot/spi/Fn;)Z" jaroslav@323: ); jaroslav@323: Label ifNotNull = new Label(); jaroslav@323: super.visitJumpInsn(Opcodes.IFNE, ifNotNull); jaroslav@323: jaroslav@323: // init Fn jaroslav@323: super.visitInsn(Opcodes.POP); jaroslav@323: super.visitLdcInsn(Type.getObjectType(FindInClass.this.name)); jaroslav@323: super.visitLdcInsn(body); jaroslav@323: super.visitIntInsn(Opcodes.SIPUSH, args.size()); jaroslav@323: super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/String"); jaroslav@323: boolean needsVM = false; jaroslav@323: for (int i = 0; i < args.size(); i++) { jaroslav@323: assert !needsVM; jaroslav@323: String argName = args.get(i); jaroslav@323: needsVM = "vm".equals(argName); jaroslav@323: super.visitInsn(Opcodes.DUP); jaroslav@323: super.visitIntInsn(Opcodes.BIPUSH, i); jaroslav@323: super.visitLdcInsn(argName); jaroslav@323: super.visitInsn(Opcodes.AASTORE); jaroslav@323: } jaroslav@323: super.visitMethodInsn(Opcodes.INVOKESTATIC, jaroslav@323: "org/apidesign/html/boot/spi/Fn", "define", jaroslav@323: "(Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/String;)Lorg/apidesign/html/boot/spi/Fn;" jaroslav@323: ); jaroslav@323: super.visitInsn(Opcodes.DUP); jaroslav@323: super.visitFieldInsn( jaroslav@323: Opcodes.PUTSTATIC, FindInClass.this.name, jaroslav@323: "$$fn$$" + name + "_" + found, jaroslav@323: "Lorg/apidesign/html/boot/spi/Fn;" jaroslav@323: ); jaroslav@323: // end of Fn init jaroslav@323: jaroslav@323: super.visitLabel(ifNotNull); jaroslav@323: jaroslav@323: final int offset; jaroslav@323: if ((access & Opcodes.ACC_STATIC) == 0) { jaroslav@323: offset = 1; jaroslav@323: super.visitIntInsn(Opcodes.ALOAD, 0); jaroslav@323: } else { jaroslav@323: offset = 0; jaroslav@323: super.visitInsn(Opcodes.ACONST_NULL); jaroslav@323: } jaroslav@323: jaroslav@323: super.visitIntInsn(Opcodes.SIPUSH, args.size()); jaroslav@323: super.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); jaroslav@323: jaroslav@323: class SV extends SignatureVisitor { jaroslav@323: jaroslav@323: private boolean nowReturn; jaroslav@323: private Type returnType; jaroslav@323: private int index; jaroslav@323: private int loadIndex = offset; jaroslav@323: jaroslav@323: public SV() { jaroslav@323: super(Opcodes.ASM4); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void visitBaseType(char descriptor) { jaroslav@323: final Type t = Type.getType("" + descriptor); jaroslav@323: if (nowReturn) { jaroslav@323: returnType = t; jaroslav@323: return; jaroslav@323: } jaroslav@323: FindInMethod.super.visitInsn(Opcodes.DUP); jaroslav@323: FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++); jaroslav@323: FindInMethod.super.visitVarInsn(t.getOpcode(Opcodes.ILOAD), loadIndex++); jaroslav@323: String factory; jaroslav@323: switch (descriptor) { jaroslav@323: case 'I': jaroslav@323: factory = "java/lang/Integer"; jaroslav@323: break; jaroslav@323: case 'J': jaroslav@323: factory = "java/lang/Long"; jaroslav@323: loadIndex++; jaroslav@323: break; jaroslav@323: case 'S': jaroslav@323: factory = "java/lang/Short"; jaroslav@323: break; jaroslav@323: case 'F': jaroslav@323: factory = "java/lang/Float"; jaroslav@323: break; jaroslav@323: case 'D': jaroslav@323: factory = "java/lang/Double"; jaroslav@323: loadIndex++; jaroslav@323: break; jaroslav@323: case 'Z': jaroslav@323: factory = "java/lang/Boolean"; jaroslav@323: break; jaroslav@323: case 'C': jaroslav@323: factory = "java/lang/Character"; jaroslav@323: break; jaroslav@323: case 'B': jaroslav@323: factory = "java/lang/Byte"; jaroslav@323: break; jaroslav@323: default: jaroslav@323: throw new IllegalStateException(t.toString()); jaroslav@323: } jaroslav@323: FindInMethod.super.visitMethodInsn(Opcodes.INVOKESTATIC, jaroslav@323: factory, "valueOf", "(" + descriptor + ")L" + factory + ";" jaroslav@323: ); jaroslav@323: FindInMethod.super.visitInsn(Opcodes.AASTORE); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public SignatureVisitor visitArrayType() { jaroslav@323: if (nowReturn) { jaroslav@323: throw new IllegalStateException("Not supported yet"); jaroslav@323: } jaroslav@323: loadObject(); jaroslav@323: return new SignatureWriter(); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void visitClassType(String name) { jaroslav@323: if (nowReturn) { jaroslav@323: returnType = Type.getObjectType(name); jaroslav@323: return; jaroslav@323: } jaroslav@323: loadObject(); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public SignatureVisitor visitReturnType() { jaroslav@323: nowReturn = true; jaroslav@323: return this; jaroslav@323: } jaroslav@323: jaroslav@323: private void loadObject() { jaroslav@323: FindInMethod.super.visitInsn(Opcodes.DUP); jaroslav@323: FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, index++); jaroslav@323: FindInMethod.super.visitVarInsn(Opcodes.ALOAD, loadIndex++); jaroslav@323: FindInMethod.super.visitInsn(Opcodes.AASTORE); jaroslav@323: } jaroslav@323: jaroslav@323: } jaroslav@323: SV sv = new SV(); jaroslav@323: SignatureReader sr = new SignatureReader(desc); jaroslav@323: sr.accept(sv); jaroslav@323: jaroslav@323: if (needsVM) { jaroslav@323: FindInMethod.super.visitInsn(Opcodes.DUP); jaroslav@323: FindInMethod.super.visitIntInsn(Opcodes.SIPUSH, sv.index); jaroslav@323: int lastSlash = FindInClass.this.name.lastIndexOf('/'); jaroslav@323: String jsCallbacks = FindInClass.this.name.substring(0, lastSlash + 1) + "$JsCallbacks$"; jaroslav@323: FindInMethod.super.visitFieldInsn(Opcodes.GETSTATIC, jsCallbacks, "VM", "L" + jsCallbacks + ";"); jaroslav@323: FindInMethod.super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jsCallbacks, "current", "()L" + jsCallbacks + ";"); jaroslav@323: FindInMethod.super.visitInsn(Opcodes.AASTORE); jaroslav@323: } jaroslav@323: jaroslav@323: super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jaroslav@323: "org/apidesign/html/boot/spi/Fn", "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;" jaroslav@323: ); jaroslav@323: switch (sv.returnType.getSort()) { jaroslav@323: case Type.VOID: jaroslav@323: super.visitInsn(Opcodes.RETURN); jaroslav@323: break; jaroslav@323: case Type.ARRAY: jaroslav@323: case Type.OBJECT: jaroslav@323: super.visitTypeInsn(Opcodes.CHECKCAST, sv.returnType.getInternalName()); jaroslav@323: super.visitInsn(Opcodes.ARETURN); jaroslav@323: break; jaroslav@323: case Type.BOOLEAN: jaroslav@323: super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Boolean"); jaroslav@323: super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jaroslav@323: "java/lang/Boolean", "booleanValue", "()Z" jaroslav@323: ); jaroslav@323: super.visitInsn(Opcodes.IRETURN); jaroslav@323: break; jaroslav@323: default: jaroslav@323: super.visitTypeInsn(Opcodes.CHECKCAST, "java/lang/Number"); jaroslav@323: super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, jaroslav@323: "java/lang/Number", sv.returnType.getClassName() + "Value", "()" + sv.returnType.getDescriptor() jaroslav@323: ); jaroslav@323: super.visitInsn(sv.returnType.getOpcode(Opcodes.IRETURN)); jaroslav@323: } jaroslav@323: return true; jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void visitEnd() { jaroslav@323: super.visitEnd(); jaroslav@323: if (body != null) { jaroslav@323: if (generateBody()) { jaroslav@323: // native method jaroslav@323: super.visitMaxs(1, 0); jaroslav@323: } jaroslav@323: FindInClass.this.visitField( jaroslav@323: Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC, jaroslav@323: "$$fn$$" + name + "_" + found, jaroslav@323: "Lorg/apidesign/html/boot/spi/Fn;", jaroslav@323: null, null jaroslav@323: ); jaroslav@323: } jaroslav@323: } jaroslav@323: jaroslav@323: private final class FindInAnno extends AnnotationVisitor { jaroslav@323: jaroslav@323: private List args = new ArrayList(); jaroslav@323: private String body; jaroslav@323: private boolean javacall = false; jaroslav@323: jaroslav@323: public FindInAnno() { jaroslav@323: super(Opcodes.ASM4); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void visit(String name, Object value) { jaroslav@323: if (name == null) { jaroslav@323: args.add((String) value); jaroslav@323: return; jaroslav@323: } jaroslav@323: if (name.equals("javacall")) { // NOI18N jaroslav@323: javacall = (Boolean) value; jaroslav@323: return; jaroslav@323: } jaroslav@323: assert name.equals("body"); jaroslav@323: body = (String) value; jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public AnnotationVisitor visitArray(String name) { jaroslav@323: return this; jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void visitEnd() { jaroslav@323: if (body != null) { jaroslav@323: if (javacall) { jaroslav@323: body = callback(body); jaroslav@323: args.add("vm"); jaroslav@323: } jaroslav@323: generateJSBody(args, body); jaroslav@323: } jaroslav@323: } jaroslav@323: } jaroslav@323: } jaroslav@323: jaroslav@323: private final class LoadResource extends AnnotationVisitor { jaroslav@323: jaroslav@323: public LoadResource() { jaroslav@323: super(Opcodes.ASM4); jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: public void visit(String attrName, Object value) { jaroslav@323: String relPath = (String) value; jaroslav@323: if (relPath.startsWith("/")) { jaroslav@323: loadScript(loader, relPath); jaroslav@323: } else { jaroslav@323: int last = name.lastIndexOf('/'); jaroslav@323: String fullPath = name.substring(0, last + 1) + relPath; jaroslav@323: loadScript(loader, fullPath); jaroslav@323: } jaroslav@323: } jaroslav@323: } jaroslav@323: } jaroslav@323: jaroslav@323: private static class ClassWriterEx extends ClassWriter { jaroslav@323: jaroslav@323: private ClassLoader loader; jaroslav@323: jaroslav@323: public ClassWriterEx(ClassLoader l, ClassReader classReader, int flags) { jaroslav@323: super(classReader, flags); jaroslav@323: this.loader = l; jaroslav@323: } jaroslav@323: jaroslav@323: @Override jaroslav@323: protected String getCommonSuperClass(final String type1, final String type2) { jaroslav@323: Class c, d; jaroslav@323: try { jaroslav@323: c = Class.forName(type1.replace('/', '.'), false, loader); jaroslav@323: d = Class.forName(type2.replace('/', '.'), false, loader); jaroslav@323: } catch (Exception e) { jaroslav@323: throw new RuntimeException(e.toString()); jaroslav@323: } jaroslav@323: if (c.isAssignableFrom(d)) { jaroslav@323: return type1; jaroslav@323: } jaroslav@323: if (d.isAssignableFrom(c)) { jaroslav@323: return type2; jaroslav@323: } jaroslav@323: if (c.isInterface() || d.isInterface()) { jaroslav@323: return "java/lang/Object"; jaroslav@323: } else { jaroslav@323: do { jaroslav@323: c = c.getSuperclass(); jaroslav@323: } while (!c.isAssignableFrom(d)); jaroslav@323: return c.getName().replace('.', '/'); jaroslav@323: } jaroslav@323: } jaroslav@323: } jaroslav@323: jaroslav@323: static byte[] transform(ClassLoader loader, byte[] arr) { jaroslav@323: ClassReader cr = new ClassReader(arr) { jaroslav@323: // to allow us to compile with -profile compact1 on jaroslav@323: // JDK8 while processing the class as JDK7, the highest jaroslav@323: // class format asm 4.1 understands to jaroslav@323: @Override jaroslav@323: public short readShort(int index) { jaroslav@323: short s = super.readShort(index); jaroslav@323: if (index == 6 && s > Opcodes.V1_7) { jaroslav@323: return Opcodes.V1_7; jaroslav@323: } jaroslav@323: return s; jaroslav@323: } jaroslav@323: }; jaroslav@323: FindInClass tst = new FindInClass(loader, null); jaroslav@323: cr.accept(tst, 0); jaroslav@323: if (tst.found > 0) { jaroslav@323: ClassWriter w = new ClassWriterEx(loader, cr, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); jaroslav@323: FindInClass fic = new FindInClass(loader, w); jaroslav@323: cr.accept(fic, 0); jaroslav@323: arr = w.toByteArray(); jaroslav@323: } jaroslav@323: return arr; jaroslav@323: } jaroslav@323: jaroslav@323: private static final class TrueFn extends Fn { jaroslav@323: @Override jaroslav@323: public Object invoke(Object thiz, Object... args) throws Exception { jaroslav@323: return Boolean.TRUE; jaroslav@323: } jaroslav@323: } // end of TrueFn jaroslav@123: }