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: }