X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.databoard%2Fsrc%2Forg%2Fsimantics%2Fdataboard%2Fbinding%2Freflection%2FAsmBindingClassLoader.java;h=7cdb28df77c68b0d009f999f0fb4bbc0fb42d1f9;hb=0ae2b770234dfc3cbb18bd38f324125cf0faca07;hp=3593565acc894ee3a7de2a2d11ca58cf40dfcf9b;hpb=24e2b34260f219f0d1644ca7a138894980e25b14;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/AsmBindingClassLoader.java b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/AsmBindingClassLoader.java index 3593565ac..7cdb28df7 100644 --- a/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/AsmBindingClassLoader.java +++ b/bundles/org.simantics.databoard/src/org/simantics/databoard/binding/reflection/AsmBindingClassLoader.java @@ -1,1061 +1,1061 @@ -/******************************************************************************* - * 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("\\.", "/"); - } - - - -} +/******************************************************************************* + * 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("\\.", "/"); + } + + + +}