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