/******************************************************************************* * Copyright (c) 2007, 2011 Association for Decentralized Information Management in * Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation *******************************************************************************/ package org.simantics.databoard.binding.reflection; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.simantics.databoard.binding.error.BindingConstructionException; public class AsmBindingClassLoader extends ClassLoader implements Opcodes { Map> map = new HashMap>(); public AsmBindingClassLoader() { super(Thread.currentThread().getContextClassLoader()); } public AsmBindingClassLoader(ClassLoader parent) { super(parent); } public String toBindingClassName( String targetClassName ) { if ( targetClassName.startsWith("java" ) ) { return "x"+targetClassName+".Binding"; } return targetClassName+".Binding"; } public String toTargetClassName( String bindingClassName ) { if (!bindingClassName.endsWith(".Binding")) return null; if (bindingClassName.substring(1,5).equals("java")) { return bindingClassName.substring(1, bindingClassName.length()-8); } else { return bindingClassName.substring(0, bindingClassName.length()-8); } } @Override protected synchronized Class findClass(String bindingClassName) throws ClassNotFoundException { Class c = map.get(bindingClassName); if ( c!= null) return c; try { String targetClassName = toTargetClassName(bindingClassName); if ( targetClassName == null ) { // try { return super.findClass(bindingClassName); // } catch( ClassNotFoundException e ) { // e.printStackTrace(); // throw e; // } } ClassLoader cl = getParent(); if (cl==null) { cl = Thread.currentThread().getContextClassLoader(); } Class targetClass = cl.loadClass( targetClassName ); ClassInfo ci = ClassInfo.getInfo( targetClass ); byte[] data = createBindingClass( ci, bindingClassName ); Class bindingClass = defineClass( bindingClassName, data, 0, data.length ); map.put(bindingClassName, bindingClass); return bindingClass; } catch (BindingConstructionException e) { throw new ClassNotFoundException( e.getMessage(), e.getCause() ); } } public synchronized Class getBindingClass(Class targetClass) throws ClassNotFoundException { String targetClassName = targetClass.getName(); String bindingClassName = toBindingClassName(targetClassName); Class c = map.get(bindingClassName); if ( c!= null) return c; try { ClassInfo ci = ClassInfo.getInfo( targetClass ); byte[] data = createBindingClass( ci, bindingClassName ); Class bindingClass = defineClass( bindingClassName, data, 0, data.length ); map.put(bindingClassName, bindingClass); return bindingClass; } catch (BindingConstructionException e) { throw new ClassNotFoundException( e.getMessage(), e.getCause() ); } } public byte[] createBindingClass(ClassInfo ci, String bindingClassName) { //System.out.println("BindingFactory: "+bindingClassName+" (for "+ci.clazz.getClassLoader()+")"); int count = ci.fields.length; ClassWriter cw = new ClassWriter( ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS ); ClassVisitor cv = cw;//new CheckClassAdapter(cw); FieldVisitor fv; MethodVisitor mv; AnnotationVisitor av0; String className = ci.clazz.getName().replaceAll("\\.", "/"); bindingClassName = bindingClassName.replaceAll("\\.", "/"); Object[] classNameX = new Object[] {className}; String signature = "L"+bindingClassName+";"; // Constructor String superClass = "org/simantics/databoard/binding/reflection/ClassBinding"; cv.visit(V1_6, ACC_PUBLIC + ACC_SUPER, bindingClassName, null, superClass, null); // Constructor { mv = cv.visitMethod(ACC_PUBLIC, "", "(Lorg/simantics/databoard/type/RecordType;)V", null, new String[] { "org/simantics/databoard/binding/error/BindingConstructionException" }); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 0); mv.visitLdcInsn(Type.getType("L"+className+";")); mv.visitMethodInsn(INVOKESPECIAL, superClass, "", "(Ljava/lang/Class;)V"); Label l1 = new Label(); mv.visitLabel(l1); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitFieldInsn(PUTFIELD, bindingClassName, "type", "Lorg/simantics/databoard/type/Datatype;"); Label l2 = new Label(); mv.visitLabel(l2); mv.visitInsn(RETURN); Label l3 = new Label(); mv.visitLabel(l3); mv.visitLocalVariable("this", signature, null, l0, l3, 0); mv.visitLocalVariable("type", "Lorg/simantics/databoard/type/RecordType;", null, l0, l3, 1); mv.visitMaxs(2, 2); mv.visitEnd(); } // getComponent { mv = cv.visitMethod(ACC_PUBLIC, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, new String[] { "org/simantics/databoard/binding/error/BindingException" }); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, className); mv.visitVarInsn(ASTORE, 3); Label l1 = new Label(); mv.visitLabel(l1); Label caseLabels[] = createFieldLabels( ci ); Label elseLabel = new Label(); if ( count > 0 ) { // Switch mv.visitVarInsn(ILOAD, 2); mv.visitTableSwitchInsn(0, count-1, elseLabel, caseLabels); // case i: x.field = value[i] for (int i=0; i fieldClass = ci.fields[i].getType(); String typeDescriptor = toTypeDescriptor( fieldClass ); Method getter = ci.getters[i]; boolean useGetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && getter!=null; mv.visitLabel( label ); if ( i==0 ) { mv.visitFrame(Opcodes.F_APPEND,1, classNameX, 0, null); } else { mv.visitFrame(Opcodes.F_SAME,0, null, 0, null); } // Read instance argument mv.visitVarInsn(ALOAD, 3); if ( useGetter ) { // call getField mv.visitMethodInsn(INVOKEVIRTUAL, className, getter.getName(), "()"+typeDescriptor); } else { // Read field mv.visitFieldInsn(GETFIELD, className, fieldName, typeDescriptor); } // Box box(mv, fieldClass); mv.visitInsn(ARETURN); } } mv.visitLabel(elseLabel); if (count>0) { mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); } mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException"); mv.visitInsn(DUP); mv.visitLdcInsn("Illegal field index"); mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "", "(Ljava/lang/String;)V"); mv.visitInsn(ATHROW); // End Label l19 = new Label(); mv.visitLabel(l19); mv.visitLocalVariable("this", "L"+className+";", null, l0, l19, 0); mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, l19, 1); mv.visitLocalVariable("index", "I", null, l0, l19, 2); //mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, l1, l19, 3); mv.visitMaxs(3, 4); mv.visitEnd(); } // Create { mv = cv.visitMethod(ACC_PUBLIC + ACC_VARARGS, "create", "([Ljava/lang/Object;)Ljava/lang/Object;", null, new String[] { "org/simantics/databoard/binding/error/BindingException" }); if ( ci.beanConstructor != null ) { mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitTypeInsn(NEW, className); mv.visitInsn(DUP); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, className, "", "(Lorg/simantics/databoard/binding/Binding;)V"); mv.visitVarInsn(ASTORE, 2); Label l1 = new Label(); mv.visitLabel(l1); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponents", "(Ljava/lang/Object;[Ljava/lang/Object;)V"); Label l2 = new Label(); mv.visitLabel(l2); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(ARETURN); Label l3 = new Label(); mv.visitLabel(l3); mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l3, 0); mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l3, 1); //mv.visitLocalVariable("x", "L"+className+";", null, l1, l3, 2); mv.visitMaxs(3, 3); mv.visitEnd(); } else if ( ci.argsConstructor != null ) { mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitTypeInsn(NEW, className); mv.visitInsn(DUP); String constArgsDescriptor = "("; Class[] args = ci.argsConstructor.getParameterTypes(); for (int i=0; i field = args[i]; String fieldName = field.getName(); Method getter = ci.getters[i]; Class fieldClass = ci.fields[i].getType(); Class boxClass = getBoxClass(fieldClass); String typeDescriptor = toTypeDescriptor( fieldClass ); String boxTypeDescriptor = toTypeDescriptor( boxClass ); constArgsDescriptor += typeDescriptor; mv.visitLabel(label); mv.visitVarInsn(ALOAD, 1); if (i<6) { mv.visitInsn(ICONST_0 + i); } else { mv.visitIntInsn(BIPUSH, i); } mv.visitInsn(AALOAD); mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass)); unbox(mv, fieldClass); } Label l17 = new Label(); mv.visitLabel(l17); constArgsDescriptor += ")V"; mv.visitMethodInsn(INVOKESPECIAL, className, "", constArgsDescriptor); mv.visitInsn(ARETURN); Label l18 = new Label(); mv.visitLabel(l18); mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l18, 0); mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l18, 1); mv.visitMaxs(21, 2); mv.visitEnd(); } else { mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitTypeInsn(NEW, className); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, className, "", "()V"); mv.visitVarInsn(ASTORE, 2); Label l1 = new Label(); mv.visitLabel(l1); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 2); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponents", "(Ljava/lang/Object;[Ljava/lang/Object;)V"); Label l2 = new Label(); mv.visitLabel(l2); mv.visitVarInsn(ALOAD, 2); mv.visitInsn(ARETURN); Label l3 = new Label(); mv.visitLabel(l3); mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l3, 0); mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l0, l3, 1); //mv.visitLocalVariable("x", "L"+className+";", null, l1, l3, 2); mv.visitMaxs(3, 3); mv.visitEnd(); } } // CreatePartial mv = cv.visitMethod(ACC_PUBLIC, "createPartial", "()Ljava/lang/Object;", null, new String[] { "org/simantics/databoard/binding/error/BindingException" }); if (ci.beanConstructor!=null) { mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitTypeInsn(NEW, className); mv.visitInsn(DUP); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, className, "", "(Lorg/simantics/databoard/binding/Binding;)V"); mv.visitInsn(ARETURN); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l1, 0); mv.visitMaxs(3, 1); mv.visitEnd(); } else if (ci.noArgsConstructor != null) { // return new MyClass(); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitTypeInsn(NEW, className); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, className, "", "()V"); mv.visitInsn(ARETURN); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l1, 0); mv.visitMaxs(2, 1); mv.visitEnd(); } else { mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitIntInsn(BIPUSH, count); mv.visitTypeInsn(ANEWARRAY, "java/lang/Object"); mv.visitVarInsn(ASTORE, 1); Label l1 = new Label(); mv.visitLabel(l1); mv.visitInsn(ICONST_0); mv.visitVarInsn(ISTORE, 2); Label l2 = new Label(); mv.visitLabel(l2); Label l3 = new Label(); mv.visitJumpInsn(GOTO, l3); Label l4 = new Label(); mv.visitLabel(l4); mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"[Ljava/lang/Object;", Opcodes.INTEGER}, 0, null); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings", "[Lorg/simantics/databoard/binding/Binding;"); mv.visitVarInsn(ILOAD, 2); mv.visitInsn(AALOAD); mv.visitVarInsn(ASTORE, 3); Label l5 = new Label(); mv.visitLabel(l5); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ALOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/Binding", "createDefault", "()Ljava/lang/Object;"); mv.visitInsn(AASTORE); Label l6 = new Label(); mv.visitLabel(l6); mv.visitIincInsn(2, 1); mv.visitLabel(l3); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ALOAD, 1); mv.visitInsn(ARRAYLENGTH); mv.visitJumpInsn(IF_ICMPLT, l4); Label l7 = new Label(); mv.visitLabel(l7); mv.visitLineNumber(109, l7); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "create", "([Ljava/lang/Object;)Ljava/lang/Object;"); mv.visitInsn(ARETURN); Label l8 = new Label(); mv.visitLabel(l8); mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, l8, 0); mv.visitLocalVariable("values", "[Ljava/lang/Object;", null, l1, l8, 1); mv.visitLocalVariable("i", "I", null, l2, l7, 2); mv.visitLocalVariable("fb", "Lorg/simantics/databoard/binding/Binding;", null, l5, l6, 3); mv.visitMaxs(3, 4); mv.visitEnd(); } // setComponent { mv = cv.visitMethod(ACC_PUBLIC, "setComponent", "(Ljava/lang/Object;ILjava/lang/Object;)V", null, new String[] { "org/simantics/databoard/binding/error/BindingException" }); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, className); mv.visitVarInsn(ASTORE, 4); Label endLabel = new Label(); Label l1 = new Label(); mv.visitLabel(l1); Label elseLabel = new Label(); Label labels[] = new Label[ count ]; for (int i=0; i0) { mv.visitVarInsn(ILOAD, 2); mv.visitTableSwitchInsn(0, count-1, elseLabel, labels); for (int i=0; i fieldClass = ci.fields[i].getType(); Class boxClass = getBoxClass(fieldClass); String typeDescriptor = toTypeDescriptor( fieldClass ); String boxTypeDescriptor = toTypeDescriptor( boxClass ); Method setter = ci.setters[i]; Class setterClass = setter!=null?setter.getParameterTypes()[0]:null; boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter!=null; if (i==0) { mv.visitFrame(Opcodes.F_APPEND,1, classNameX, 0, null); } else { mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); } mv.visitVarInsn(ALOAD, 4); mv.visitVarInsn(ALOAD, 3); mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass)); if (useSetter) { unbox(mv, setterClass); mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "("+typeDescriptor+")V"); } else { unbox(mv, fieldClass); mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor); } mv.visitInsn(RETURN); } } mv.visitLabel(elseLabel); mv.visitLineNumber(178, elseLabel); if (count>0) { mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); } mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException"); mv.visitInsn(DUP); mv.visitLdcInsn("Illegal field index"); mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "", "(Ljava/lang/String;)V"); mv.visitInsn(ATHROW); mv.visitLabel(endLabel); mv.visitLocalVariable("this", "L"+bindingClassName+";", null, l0, endLabel, 0); mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, endLabel, 1); mv.visitLocalVariable("index", "I", null, l0, endLabel, 2); mv.visitLocalVariable("value", "Ljava/lang/Object;", null, l0, endLabel, 3); //mv.visitLocalVariable("x", "L"+className+";", null, l1, endLabel, 4); mv.visitMaxs(3, 5); mv.visitEnd(); } // IsImmutable { mv = cv.visitMethod(ACC_PUBLIC, "isImmutable", "()Z", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitInsn(ICONST_0); mv.visitInsn(IRETURN); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLocalVariable("this", "L"+className+";", null, l0, l1, 0); mv.visitMaxs(1, 1); mv.visitEnd(); } // IsInstance { mv = cv.visitMethod(ACC_PUBLIC, "isInstance", "(Ljava/lang/Object;)Z", null, null); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(INSTANCEOF, className); mv.visitInsn(IRETURN); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLocalVariable("this", "L"+className+";", null, l0, l1, 0); mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, l1, 1); mv.visitMaxs(1, 2); mv.visitEnd(); } // SetComponents { mv = cv.visitMethod(ACC_PUBLIC + ACC_VARARGS, "setComponents", "(Ljava/lang/Object;[Ljava/lang/Object;)V", null, new String[] { "org/simantics/databoard/binding/error/BindingException" }); mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, className); mv.visitVarInsn(ASTORE, 3); Label firstLabel = l0; for (int i=0; i fieldClass = ci.fields[i].getType(); Class boxClass = getBoxClass(fieldClass); String typeDescriptor = toTypeDescriptor( fieldClass ); String boxTypeDescriptor = toTypeDescriptor( boxClass ); Method setter = ci.setters[i]; Class setterClass = setter!=null?setter.getParameterTypes()[0]:null; boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter!=null; mv.visitLabel(label); mv.visitVarInsn(ALOAD, 3); mv.visitVarInsn(ALOAD, 2); if (i<6) { mv.visitInsn(ICONST_0 + i); } else { mv.visitIntInsn(BIPUSH, i); } mv.visitInsn(AALOAD); mv.visitTypeInsn(CHECKCAST, toClassCanonicalName(boxClass)); if (useSetter) { unbox(mv, setterClass); mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "("+typeDescriptor+")V"); } else { unbox(mv, fieldClass); mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor); } } Label l17 = new Label(); mv.visitLabel(l17); mv.visitInsn(RETURN); Label endLabel = new Label(); mv.visitLabel(endLabel); mv.visitLocalVariable("this", "L"+className+";", null, l0, endLabel, 0); mv.visitLocalVariable("obj", "Ljava/lang/Object;", null, l0, endLabel, 1); mv.visitLocalVariable("value", "[Ljava/lang/Object;", null, l0, endLabel, 2); //mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, firstLabel, endLabel, 3); mv.visitMaxs(3, 4); mv.visitEnd(); } // Add primitive setters { addGetSetPrimitive(ci, cv, "Boolean", "Z", bindingClassName); addGetSetPrimitive(ci, cv, "Byte", "B", bindingClassName); addGetSetPrimitive(ci, cv, "Int", "I", bindingClassName); addGetSetPrimitive(ci, cv, "Long", "J", bindingClassName); addGetSetPrimitive(ci, cv, "Float", "F", bindingClassName); addGetSetPrimitive(ci, cv, "Double", "D", bindingClassName); } cv.visitEnd(); return cw.toByteArray(); } private void addGetSetPrimitive(ClassInfo ci, ClassVisitor cv, String setterName, String signature, String bindingClassName) { String className = ci.clazz.getName().replaceAll("\\.", "/"); Label firstLabel = new Label(); Label secondLabel = new Label(); Label errorLabel = new Label(); Label exitLabel = new Label(); Label lastLabel = new Label(); boolean oneByte = !signature.equals("J") && !signature.equals("D"); int c = 0; for (Field f : ci.fields) { if ( toTypeDescriptor(getPrimitiveClass(f.getType())).equals( signature ) ) c++; } int[] indices = new int[ c ]; Label[] caseLabel = new Label[ c ]; c = 0; for (int i=0; i fieldClass = ci.fields[i].getType(); fieldClass = getPrimitiveClass(fieldClass); String s = toTypeDescriptor(fieldClass); if ( !s.equals( signature ) ) continue; indices[c] = i; caseLabel[c] = new Label(); c++; } ////////////////// /// Setter /// MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "set"+setterName, "(Ljava/lang/Object;I"+signature+")V", null, new String[] { "org/simantics/databoard/binding/error/BindingException" }); mv.visitCode(); mv.visitLabel(firstLabel); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, className); mv.visitVarInsn(ASTORE, oneByte?4:5); mv.visitLabel(secondLabel); mv.visitVarInsn(ILOAD, 2); // switch mv.visitLookupSwitchInsn(errorLabel, indices, caseLabel); // case 1: if ( c>0 ) { for (int i=0; i fieldClass = field.getType(); Class setterClass = setter!=null?setter.getParameterTypes()[0]:null; boolean useSetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && setter!=null; String typeDescriptor = toTypeDescriptor( useSetter ? setterClass : fieldClass ); mv.visitLabel(caseLabel[i]); if ( i == 0 ) { mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {className}, 0, null); } else { mv.visitFrame(Opcodes.F_SAME, 0, new Object[] {className}, 0, null); } if ( signature.equals("F") ) { mv.visitVarInsn(ALOAD, 4); mv.visitVarInsn(FLOAD, 3); } else if ( signature.equals("D") ) { mv.visitVarInsn(ALOAD, 5); mv.visitVarInsn(DLOAD, 3); } else if ( signature.equals("J") ) { mv.visitVarInsn(ALOAD, 5); mv.visitVarInsn(LLOAD, 3); } else { mv.visitVarInsn(ALOAD, 4); mv.visitVarInsn(ILOAD, 3); } if ( useSetter ) { boxTo(mv, setterClass); mv.visitMethodInsn(INVOKEVIRTUAL, className, setter.getName(), "("+typeDescriptor+")V"); } else { boxTo(mv, fieldClass); mv.visitFieldInsn(PUTFIELD, className, field.getName(), typeDescriptor); } mv.visitJumpInsn(GOTO, exitLabel); } } else { mv.visitInsn(POP); } // default: (error) /* mv.visitLabel(errorLabel); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException"); mv.visitInsn(DUP); mv.visitLdcInsn("Field is not "+setterName); mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "", "(Ljava/lang/String;)V"); mv.visitInsn(ATHROW); */ // default: setComponent mv.visitLabel(errorLabel); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings", "[Lorg/simantics/databoard/binding/Binding;"); mv.visitVarInsn(ILOAD, 2); mv.visitInsn(AALOAD); if ( signature.equals("F") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/FloatBinding"); mv.visitVarInsn(FLOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/FloatBinding", "create", "(F)Ljava/lang/Object;"); } else if ( signature.equals("D") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/DoubleBinding"); mv.visitVarInsn(DLOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/DoubleBinding", "create", "(D)Ljava/lang/Object;"); } else if ( signature.equals("J") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/LongBinding"); mv.visitVarInsn(LLOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/LongBinding", "create", "(J)Ljava/lang/Object;"); } else if ( signature.equals("Z") ){ mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/BooleanBinding"); mv.visitVarInsn(ILOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/BooleanBinding", "create", "(Z)Ljava/lang/Object;"); } else if ( signature.equals("I") ){ mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/IntBinding"); mv.visitVarInsn(ILOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/IntBinding", "create", "(I)Ljava/lang/Object;"); } else if ( signature.equals("B") ){ mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/ByteBinding"); mv.visitVarInsn(ILOAD, 3); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/ByteBinding", "create", "(B)Ljava/lang/Object;"); } mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "setComponent", "(Ljava/lang/Object;ILjava/lang/Object;)V"); // return mv.visitLabel(exitLabel); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitInsn(RETURN); // Something at the end mv.visitLabel(lastLabel); // mv.visitLocalVariable("this", "L"+bindingClassName+";", null, firstLabel, lastLabel, 0); // mv.visitLocalVariable("r", "Ljava/lang/Object;", null, firstLabel, lastLabel, 1); // mv.visitLocalVariable("index", "I", null, firstLabel, lastLabel, 2); // mv.visitLocalVariable("z", signature, null, firstLabel, lastLabel, 3); // mv.visitLocalVariable("x", "L"+className+";", null, secondLabel, lastLabel, 4); mv.visitMaxs(oneByte?5:6, oneByte?5:6); mv.visitEnd(); ////////////////// /// Getter /// firstLabel = new Label(); secondLabel = new Label(); errorLabel = new Label(); exitLabel = new Label(); lastLabel = new Label(); for (int i=0; i0 ) { mv.visitLookupSwitchInsn(errorLabel, indices, caseLabel); // case i: for (int i=0; i fieldClass = field.getType(); Class getterClass = getter!=null?getter.getReturnType():null; boolean useGetter = ((field.getModifiers() & Modifier.PUBLIC) == 0) && getter!=null; String typeDescriptor = toTypeDescriptor( useGetter ? getterClass : fieldClass ); mv.visitLabel(caseLabel[i]); if ( i == 0 ) { mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {className}, 0, null); } else { mv.visitFrame(Opcodes.F_SAME, 0, new Object[] {className}, 0, null); } mv.visitVarInsn(ALOAD, 3); if ( useGetter ) { mv.visitMethodInsn(INVOKEVIRTUAL, className, getter.getName(), "()"+typeDescriptor); unboxFrom(mv, getterClass); } else { mv.visitFieldInsn(GETFIELD, className, field.getName(), typeDescriptor); unboxFrom(mv, fieldClass); } if ( signature.equals("F") ) { mv.visitInsn(FRETURN); } else if ( signature.equals("D") ) { mv.visitInsn(DRETURN); } else if ( signature.equals("J") ) { mv.visitInsn(LRETURN); } else { mv.visitInsn(IRETURN); } } } else { mv.visitInsn(POP); } // default: (error) /* mv.visitLabel(errorLabel); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitTypeInsn(NEW, "org/simantics/databoard/binding/error/BindingException"); mv.visitInsn(DUP); mv.visitLdcInsn("Field is not "+setterName); mv.visitMethodInsn(INVOKESPECIAL, "org/simantics/databoard/binding/error/BindingException", "", "(Ljava/lang/String;)V"); mv.visitInsn(ATHROW); */ // default: mv.visitLabel(errorLabel); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, bindingClassName, "componentBindings", "[Lorg/simantics/databoard/binding/Binding;"); mv.visitVarInsn(ILOAD, 2); mv.visitInsn(AALOAD); if ( signature.equals("Z") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/BooleanBinding"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;"); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/BooleanBinding", "getValue_", "(Ljava/lang/Object;)Z"); mv.visitInsn(IRETURN); } else if ( signature.equals("B") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/ByteBinding"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;"); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/ByteBinding", "getValue_", "(Ljava/lang/Object;)B"); mv.visitInsn(IRETURN); } else if ( signature.equals("I") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/IntBinding"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;"); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/IntBinding", "getValue_", "(Ljava/lang/Object;)I"); mv.visitInsn(IRETURN); } else if ( signature.equals("J") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/LongBinding"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;"); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/LongBinding", "getValue_", "(Ljava/lang/Object;)J"); mv.visitInsn(LRETURN); } else if ( signature.equals("F") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/FloatBinding"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;"); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/FloatBinding", "getValue_", "(Ljava/lang/Object;)F"); mv.visitInsn(FRETURN); } else if ( signature.equals("D") ) { mv.visitTypeInsn(CHECKCAST, "org/simantics/databoard/binding/DoubleBinding"); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitVarInsn(ILOAD, 2); mv.visitMethodInsn(INVOKEVIRTUAL, bindingClassName, "getComponent", "(Ljava/lang/Object;I)Ljava/lang/Object;"); mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/databoard/binding/DoubleBinding", "getValue_", "(Ljava/lang/Object;)D"); mv.visitInsn(DRETURN); } // Something at the end mv.visitLabel(lastLabel); // mv.visitLocalVariable("this", "Lorg/simantics/databoard/binding/reflection/MyBinding;", null, firstLabel, lastLabel, 0); // mv.visitLocalVariable("r", "Ljava/lang/Object;", null, firstLabel, lastLabel, 1); // mv.visitLocalVariable("index", "I", null, firstLabel, lastLabel, 2); // mv.visitLocalVariable("x", "Lorg/simantics/databoard/binding/reflection/MyClass;", null, secondLabel, lastLabel, 3); mv.visitMaxs(4, 4); mv.visitEnd(); } public static Label[] createFieldLabels(ClassInfo ci) { Label caseLabels[] = new Label[ ci.fields.length ]; for (int i=0; i clazz) { if (clazz==void.class) return "V"; if (clazz==boolean.class) return "Z"; if (clazz==char.class) return "C"; if (clazz==byte.class) return "B"; if (clazz==short.class) return "S"; if (clazz==int.class) return "I"; if (clazz==float.class) return "F"; if (clazz==long.class) return "J"; if (clazz==double.class) return "D"; if (clazz.isArray()) return clazz.getName().replaceAll("\\.", "/"); return "L"+clazz.getName().replaceAll("\\.", "/")+";"; } /** * Get respective boxed class * @param clazz * @return box-class */ public static Class getBoxClass(Class clazz) { if (clazz==void.class) return null; if (clazz==boolean.class) return Boolean.class; if (clazz==char.class) return Character.class; if (clazz==byte.class) return Byte.class; if (clazz==short.class) return Short.class; if (clazz==int.class) return Integer.class; if (clazz==float.class) return Float.class; if (clazz==long.class) return Long.class; if (clazz==double.class) return Double.class; return clazz; } /** * Get respective primitive class * @param clazz * @return primitive-class */ public static Class getPrimitiveClass(Class clazz) { if (clazz==Boolean.class) return boolean.class; if (clazz==Character.class) return char.class; if (clazz==Byte.class) return byte.class; if (clazz==Short.class) return short.class; if (clazz==Integer.class) return int.class; if (clazz==Float.class) return float.class; if (clazz==Long.class) return long.class; if (clazz==Double.class) return double.class; return clazz; } public static boolean isPrimitive(Class clazz) { return clazz==boolean.class || clazz==char.class || clazz==byte.class || clazz==short.class || clazz==int.class || clazz==float.class || clazz==long.class || clazz==double.class; } public static void unbox(MethodVisitor mv, Class clazz) { if (clazz==boolean.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z"); } else if (clazz==char.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); // C? } else if (clazz==byte.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B"); } else if (clazz==short.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S"); } else if (clazz==int.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I"); } else if (clazz==float.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F"); } else if (clazz==long.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J"); } else if (clazz==double.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D"); } } public static void box(MethodVisitor mv, Class clazz) { if (clazz==boolean.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); } else if (clazz==char.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); } else if (clazz==byte.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); } else if (clazz==short.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); } else if (clazz==int.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); } else if (clazz==float.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); } else if (clazz==long.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); } else if (clazz==double.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); } } public static void boxTo(MethodVisitor mv, Class clazz) { if (clazz==Boolean.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); } else if (clazz==Character.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); } else if (clazz==Byte.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); } else if (clazz==Short.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); } else if (clazz==Integer.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); } else if (clazz==Float.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); } else if (clazz==Long.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); } else if (clazz==Double.class) { mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); } } public static void unboxFrom(MethodVisitor mv, Class clazz) { if (clazz==Boolean.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z"); } else if (clazz==Character.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); // C? } else if (clazz==Byte.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B"); } else if (clazz==Short.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S"); } else if (clazz==Integer.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I"); } else if (clazz==Float.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F"); } else if (clazz==Long.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J"); } else if (clazz==Double.class) { mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D"); } } public static String toClassCanonicalName(Class clazz) { return clazz.getName().replaceAll("\\.", "/"); } }