--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2010 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.tests;
+
+import static org.objectweb.asm.Opcodes.AALOAD;\r
+import static org.objectweb.asm.Opcodes.AASTORE;\r
+import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;\r
+import static org.objectweb.asm.Opcodes.ACC_FINAL;\r
+import static org.objectweb.asm.Opcodes.ACC_INTERFACE;\r
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;\r
+import static org.objectweb.asm.Opcodes.ACC_STATIC;\r
+import static org.objectweb.asm.Opcodes.ACC_SUPER;\r
+import static org.objectweb.asm.Opcodes.ALOAD;\r
+import static org.objectweb.asm.Opcodes.ANEWARRAY;\r
+import static org.objectweb.asm.Opcodes.ARETURN;\r
+import static org.objectweb.asm.Opcodes.ARRAYLENGTH;\r
+import static org.objectweb.asm.Opcodes.ASTORE;\r
+import static org.objectweb.asm.Opcodes.ATHROW;\r
+import static org.objectweb.asm.Opcodes.CHECKCAST;\r
+import static org.objectweb.asm.Opcodes.DLOAD;\r
+import static org.objectweb.asm.Opcodes.DRETURN;\r
+import static org.objectweb.asm.Opcodes.DUP;\r
+import static org.objectweb.asm.Opcodes.FLOAD;\r
+import static org.objectweb.asm.Opcodes.FRETURN;\r
+import static org.objectweb.asm.Opcodes.GETFIELD;\r
+import static org.objectweb.asm.Opcodes.GETSTATIC;\r
+import static org.objectweb.asm.Opcodes.GOTO;\r
+import static org.objectweb.asm.Opcodes.ICONST_0;\r
+import static org.objectweb.asm.Opcodes.IFEQ;\r
+import static org.objectweb.asm.Opcodes.IF_ICMPLT;\r
+import static org.objectweb.asm.Opcodes.ILOAD;\r
+import static org.objectweb.asm.Opcodes.INSTANCEOF;\r
+import static org.objectweb.asm.Opcodes.INVOKEINTERFACE;\r
+import static org.objectweb.asm.Opcodes.INVOKESPECIAL;\r
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;\r
+import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;\r
+import static org.objectweb.asm.Opcodes.IRETURN;\r
+import static org.objectweb.asm.Opcodes.ISTORE;\r
+import static org.objectweb.asm.Opcodes.LLOAD;\r
+import static org.objectweb.asm.Opcodes.LRETURN;\r
+import static org.objectweb.asm.Opcodes.NEW;\r
+import static org.objectweb.asm.Opcodes.POP;\r
+import static org.objectweb.asm.Opcodes.PUTFIELD;\r
+import static org.objectweb.asm.Opcodes.PUTSTATIC;\r
+import static org.objectweb.asm.Opcodes.RETURN;\r
+import static org.objectweb.asm.Opcodes.V1_6;\r
+\r
+import java.lang.reflect.Constructor;\r
+import java.util.Arrays;\r
+import java.util.HashSet;\r
+import java.util.Set;\r
+\r
+import org.objectweb.asm.AnnotationVisitor;\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.Methods;\r
+import org.simantics.databoard.binding.error.BindingConstructionException;\r
+import org.simantics.databoard.method.InvokeException;\r
+import org.simantics.databoard.method.MethodInterface;\r
+import org.simantics.databoard.method.MethodInterface.AsyncResult;\r
+import org.simantics.databoard.method.MethodInterface.ExecutionError;\r
+import org.simantics.databoard.method.MethodInterface.Method;\r
+import org.simantics.databoard.method.MethodInterfaceUtil;\r
+import org.simantics.databoard.method.MethodNotSupportedException;\r
+import org.simantics.databoard.method.MethodTypeBinding;\r
+import org.simantics.databoard.method.RuntimeInvokeException;\r
+
+public class testASM {
+
+ public interface Abu {
+
+ Integer x(Integer i) throws testASM.MyException, testASM.RandomException, InvokeException;
+ double y();
+ String hello(int[] args) throws testASM.MyException, InvokeException;
+
+ }
+
+ public interface Rajapinta {
+
+ void m0();
+ int m1();
+ int m2(int arg0);
+ int m3(int arg0, int arg1);
+ Integer m10(int color, String name) throws InvokeException, ExecutionError;
+ int m11(int color, String name) throws InvokeException, ExecutionError;
+ }
+
+ static class Toteutus implements Rajapinta {
+ Method _10, _11;
+
+ public Integer m10(int color, String name)
+ throws InvokeException, ExecutionError
+ {
+ AsyncResult result = _10.invoke(new Object[] {color, name});
+ try {
+ return (Integer) result.waitForResponse();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public int m11(int color, String name)
+ throws InvokeException, ExecutionError
+ {
+ AsyncResult result = _11.invoke(new Object[] {color, name});
+ try {
+ return (Integer) result.waitForResponse();
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void m0() {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public int m1() {
+ // TODO Auto-generated method stub
+ return 666;
+ }
+
+ @Override
+ public int m2(int arg0) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public int m3(int arg0, int arg1) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+
+ }
+
+
+ public static byte[] dump () throws Exception {
+ ClassWriter cw = new ClassWriter(0);
+ FieldVisitor fv;
+ MethodVisitor mv;
+ AnnotationVisitor av0;
+
+ cw.visit(V1_6, ACC_SUPER, "org/simantics/data/Virhe", null, "java/lang/Object", null);
+
+ cw.visitSource("testASM.java", null);
+
+ {
+ mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ mv.visitCode();
+ Label l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitLineNumber(157, l0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+ mv.visitInsn(RETURN);
+ Label l1 = new Label();
+ mv.visitLabel(l1);
+ mv.visitLocalVariable("this", "Lorg/simantics/data/Virhe;", null, l0, l1, 0);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+ cw.visitEnd();
+
+ return cw.toByteArray();
+ }
+
+ public static class MyException extends Exception {
+ String msg;
+ public MyException(String msg) {
+ this.msg = msg;
+ }
+ }
+ public static class RandomException extends Exception {
+ String msg;
+ public RandomException(String msg) {
+ this.msg = msg;
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.out.println(Object[][].class.getName());
+
+ System.out.println(Abu.class.getName());
+ System.out.println(void.class.getName());
+ System.out.println(int.class.getName());
+
+ try {
+ Toteutus t = new Toteutus();
+
+ Virhe3 server = new Virhe3();
+ MethodInterface serverMi = MethodInterfaceUtil.bindInterface(Abu.class, server);
+
+ StubClassLoader cl = new StubClassLoader();
+ Class<?> virhe = cl.loadClass("org.simantics.data.testASM$Abu_Stub");
+// Class<?> virhe = cl.loadClass("org.simantics.data.Virhe2");
+
+ Constructor<?> c = virhe.getConstructor(MethodInterface.class);
+ Abu client = (Abu) c.newInstance(serverMi);
+// client = new Virhe2(serverMi);
+
+ System.out.println(client);
+ System.out.println(client.hello(new int[] {0,5,0}));
+ System.out.println(client.y());
+ System.out.println(client.x(5));
+ } catch (testASM.MyException e) {
+ System.err.printf("MyException = %s", e.msg);
+ }
+
+ }
+
+}
+
+
+class Virhe3 implements testASM.Abu {
+ @Override
+ public Integer x(Integer i) throws testASM.MyException, testASM.RandomException, InvokeException {
+// throw new testASM.MyException("XYZ");
+ throw new testASM.RandomException("XYZ");
+// return 7;
+ }
+ @Override
+ public double y() {
+ return 5;
+ }
+ @Override
+ public String hello(int[] args) throws testASM.MyException, InvokeException {
+ return "World "+ Arrays.toString(args);
+ }
+
+}
+
+class Virhe2 implements testASM.Abu {
+// static final MethodBinding x = new MethodBinding("x", DataTypes.getBinding(int.class), DataTypes.getBinding(void.class), DataTypes.getErrorBinding());
+ static final Class<?> interfaze = testASM.Abu.class;
+ static final MethodTypeBinding[] bindings;
+
+ static {
+ java.lang.reflect.Method[] methods = interfaze.getMethods();
+ Arrays.sort(methods, MethodInterfaceUtil.methodComparator);
+
+ bindings = new MethodTypeBinding[methods.length];
+ for (int i=0; i<bindings.length; i++) {
+ try {
+ bindings[i] = Methods.getMethodTypeBinding(methods[i]);
+ } catch (BindingConstructionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ MethodInterface mi;
+ Method[] methods;
+ public Virhe2(MethodInterface mi)
+ throws MethodNotSupportedException
+ {
+ this.mi = mi;
+ methods = new Method[bindings.length];
+ for (int i=0; i<bindings.length; i++) {
+ methods[i] = mi.getMethod(bindings[i]);
+ }
+ }
+
+ public Integer x(Integer arg1) throws InvokeException, testASM.MyException {
+ Method m = methods[1];
+
+ Object args[] = new Object[] {arg1};
+
+ AsyncResult result = m.invoke(args);
+ try {
+ return (Integer) result.waitForResponse();
+ } catch (ExecutionError e) {
+ Object cause = e.getError();
+ if (cause instanceof testASM.MyException)
+ throw (testASM.MyException) cause;
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ public double y() {
+ Method m = methods[2];
+
+ Object args[] = new Object[] {};
+
+ AsyncResult result = m.invoke(args);
+ try {
+ return (Double) result.waitForResponse();
+ } catch (InvokeException e) {
+ throw new RuntimeInvokeException(e);
+ } catch (ExecutionError e) {
+ Object cause = e.getError();
+ throw new RuntimeException(e);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String hello(int[] args) throws testASM.MyException, InvokeException {
+ return null;
+ }
+}
+
+class StubClassLoader extends ClassLoader {
+
+ public StubClassLoader() {
+ super();
+ }
+
+ public StubClassLoader(ClassLoader parent) {
+ super(parent);
+ }
+
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ if (name.endsWith("_Stub")) {
+ Class<?> interfaze = loadClass(name.substring(0, name.length()-5));
+ ClassWriter cw = new ClassWriter(0);
+ createImpl(name, interfaze, cw);
+ byte[] b = cw.toByteArray();
+ Class<?> clazz = defineClass(name, b, 0, b.length);
+ return clazz;
+ }
+ return super.findClass(name);
+ }
+
+ static String classToTypeDescriptor(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==void.class) return "V";
+ if (clazz.isArray()) return clazz.getName();
+ return "L"+clazz.getName().replaceAll("\\.", "/")+";";
+ }
+
+ void createImpl(String className, Class<?> interfaze, ClassWriter cw) {
+ FieldVisitor fv;
+ MethodVisitor mv;
+ AnnotationVisitor av0;
+
+ java.lang.reflect.Method[] methods = interfaze.getMethods();
+ Arrays.sort(methods, MethodInterfaceUtil.methodComparator);
+
+ String classResourceName = className.replaceAll("\\.", "/");
+ String classTypeDescriptor = "L"+classResourceName+";";
+ String interfaceResourceName = classResourceName.substring(0, classResourceName.length()-5);
+ String interfaceTypeDescriptor = "L"+interfaceResourceName+";";
+
+ cw.visit(V1_6, ACC_SUPER | ACC_PUBLIC, classResourceName, null, "java/lang/Object", new String[] { interfaceResourceName });
+
+ // Imports
+ Set<Class<?>> imports = new HashSet<Class<?>>();
+ imports.add(AsyncResult.class);
+ imports.add(ExecutionError.class);
+ imports.add(Method.class);
+ imports.add(interfaze);
+
+ for (java.lang.reflect.Method m : methods) {
+ for (Class<?> clazz : m.getExceptionTypes()) {
+ imports.add(clazz);
+ }
+ for (Class<?> clazz : m.getParameterTypes()) {
+ imports.add(clazz);
+ }
+ imports.add(m.getReturnType());
+ }
+
+ for (Class<?> clazz : imports) {
+ if (clazz.isPrimitive()) continue;
+ String name = clazz.getName();
+ if (name.startsWith("java.lang")) continue;
+ String resourceName = name.replaceAll("\\.", "/");
+ String outerName = resourceName.contains("$") ? resourceName.substring(0, resourceName.indexOf('$')) : null;
+ String className_ = clazz.isArray() ? clazz.getSimpleName().substring(0, clazz.getSimpleName().length()-2) : clazz.getSimpleName();
+ int access = ACC_PUBLIC + ACC_STATIC + (clazz.isInterface() ? ACC_INTERFACE + ACC_ABSTRACT : 0);
+// System.out.printf("name=%s, outerName=%s, innerName=%s\n", resourceName, outerName, className_);
+ cw.visitInnerClass(resourceName, outerName, className_, access);
+ }
+
+ // Fields
+ {
+ fv = cw.visitField(ACC_FINAL + ACC_STATIC, "interfaze", "Ljava/lang/Class;", "Ljava/lang/Class<*>;", null);
+ fv.visitEnd();
+ }
+ {
+ fv = cw.visitField(ACC_FINAL + ACC_STATIC, "bindings", "[Lorg/simantics/databoard/method/MethodBinding;", null, null);
+ fv.visitEnd();
+ }
+ {
+ fv = cw.visitField(0, "mi", "Lorg/simantics/data/session/MethodInterface;", null, null);
+ fv.visitEnd();
+ }
+ {
+ fv = cw.visitField(0, "methods", "[Lorg/simantics/data/session/MethodInterface$Method;", null, null);
+ fv.visitEnd();
+ }
+
+ // Init class - static {}
+ {
+ mv = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
+ mv.visitCode();
+ Label l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitLdcInsn(Type.getType(interfaceTypeDescriptor));
+ mv.visitFieldInsn(PUTSTATIC, classResourceName, "interfaze", "Ljava/lang/Class;");
+ Label l1 = new Label();
+ mv.visitLabel(l1);
+ mv.visitFieldInsn(GETSTATIC, classResourceName, "interfaze", "Ljava/lang/Class;");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getMethods", "()[Ljava/lang/reflect/Method;");
+ mv.visitVarInsn(ASTORE, 0);
+ Label l2 = new Label();
+ mv.visitLabel(l2);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETSTATIC, "org/simantics/data/network/MethodInterfaceUtil", "methodComparator", "Ljava/util/Comparator;");
+ mv.visitMethodInsn(INVOKESTATIC, "java/util/Arrays", "sort", "([Ljava/lang/Object;Ljava/util/Comparator;)V");
+ Label l3 = new Label();
+ mv.visitLabel(l3);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitInsn(ARRAYLENGTH);
+ mv.visitTypeInsn(ANEWARRAY, "org/simantics/databoard/method/MethodBinding");
+ mv.visitFieldInsn(PUTSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodBinding;");
+ Label l4 = new Label();
+ mv.visitLabel(l4);
+ mv.visitInsn(ICONST_0);
+ mv.visitVarInsn(ISTORE, 1);
+ Label l5 = new Label();
+ mv.visitLabel(l5);
+ Label l6 = new Label();
+ mv.visitJumpInsn(GOTO, l6);
+ Label l7 = new Label();
+ mv.visitLabel(l7);
+ mv.visitFrame(Opcodes.F_APPEND,2, new Object[] {"[Ljava/lang/reflect/Method;", Opcodes.INTEGER}, 0, null);
+ mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodBinding;");
+ mv.visitVarInsn(ILOAD, 1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ILOAD, 1);
+ mv.visitInsn(AALOAD);
+ mv.visitMethodInsn(INVOKESTATIC, "org/simantics/databoard/DataTypes", "getMethodBinding", "(Ljava/lang/reflect/Method;)Lorg/simantics/databoard/method/MethodBinding;");
+ mv.visitInsn(AASTORE);
+ Label l8 = new Label();
+ mv.visitLabel(l8);
+ mv.visitIincInsn(1, 1);
+ mv.visitLabel(l6);
+ mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ mv.visitVarInsn(ILOAD, 1);
+ mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodBinding;");
+ mv.visitInsn(ARRAYLENGTH);
+ mv.visitJumpInsn(IF_ICMPLT, l7);
+ Label l9 = new Label();
+ mv.visitLabel(l9);
+ mv.visitInsn(RETURN);
+ Label l10 = new Label();
+ mv.visitLabel(l10);
+ mv.visitLocalVariable("methods", "[Ljava/lang/reflect/Method;", null, l2, l10, 0);
+ mv.visitLocalVariable("i", "I", null, l5, l9, 1);
+ mv.visitMaxs(4, 2);
+ mv.visitEnd();
+ }
+
+ // Constructor
+ {
+ mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Lorg/simantics/data/session/MethodInterface;)V", null, new String[] { "org/simantics/data/error/MethodNotSupportedException" });
+ mv.visitCode();
+ Label l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
+ Label l1 = new Label();
+ mv.visitLabel(l1);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(PUTFIELD, classResourceName, "mi", "Lorg/simantics/data/session/MethodInterface;");
+ Label l2 = new Label();
+ mv.visitLabel(l2);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodBinding;");
+ mv.visitInsn(ARRAYLENGTH);
+ mv.visitTypeInsn(ANEWARRAY, "org/simantics/data/session/MethodInterface$Method");
+ mv.visitFieldInsn(PUTFIELD, classResourceName, "methods", "[Lorg/simantics/data/session/MethodInterface$Method;");
+ Label l3 = new Label();
+ mv.visitLabel(l3);
+ mv.visitInsn(ICONST_0);
+ mv.visitVarInsn(ISTORE, 2);
+ Label l4 = new Label();
+ mv.visitLabel(l4);
+ Label l5 = new Label();
+ mv.visitJumpInsn(GOTO, l5);
+ Label l6 = new Label();
+ mv.visitLabel(l6);
+ mv.visitFrame(Opcodes.F_FULL, 3, new Object[] {classResourceName, "org/simantics/data/session/MethodInterface", Opcodes.INTEGER}, 0, new Object[] {});
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, classResourceName, "methods", "[Lorg/simantics/data/session/MethodInterface$Method;");
+ mv.visitVarInsn(ILOAD, 2);
+ mv.visitVarInsn(ALOAD, 1);
+ mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodBinding;");
+ mv.visitVarInsn(ILOAD, 2);
+ mv.visitInsn(AALOAD);
+ mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/data/session/MethodInterface", "getMethod", "(Lorg/simantics/databoard/method/MethodBinding;)Lorg/simantics/data/session/MethodInterface$Method;");
+ mv.visitInsn(AASTORE);
+ Label l7 = new Label();
+ mv.visitLabel(l7);
+ mv.visitIincInsn(2, 1);
+ mv.visitLabel(l5);
+ mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+ mv.visitVarInsn(ILOAD, 2);
+ mv.visitFieldInsn(GETSTATIC, classResourceName, "bindings", "[Lorg/simantics/databoard/method/MethodBinding;");
+ mv.visitInsn(ARRAYLENGTH);
+ mv.visitJumpInsn(IF_ICMPLT, l6);
+ Label l8 = new Label();
+ mv.visitLabel(l8);
+ mv.visitInsn(RETURN);
+ Label l9 = new Label();
+ mv.visitLabel(l9);
+ mv.visitLocalVariable("this", classTypeDescriptor, null, l0, l9, 0);
+ mv.visitLocalVariable("mi", "Lorg/simantics/data/session/MethodInterface;", null, l0, l9, 1);
+ mv.visitLocalVariable("i", "I", null, l4, l8, 2);
+ mv.visitMaxs(5, 3);
+ mv.visitEnd();
+ }
+
+ // Method
+ int methodNumber = 0;
+ for (java.lang.reflect.Method m : methods)
+ {
+ String typeDescription = "";
+ Class<?>[] params = m.getParameterTypes();
+ for (int i=0; i<params.length; i++) {
+ if (i>0) typeDescription += ";";
+ typeDescription += classToTypeDescriptor(params[i]);
+ }
+ typeDescription = "("+typeDescription+")"+classToTypeDescriptor(m.getReturnType());
+ System.out.println(typeDescription+" "+m.getName());
+
+ Class<?>[] exceptions = m.getExceptionTypes();
+ String[] exceptionResourceNames = new String[exceptions.length];
+ for (int i=0; i<exceptionResourceNames.length; i++) {
+ exceptionResourceNames[i] = exceptions[i].getName().replaceAll("\\.", "/");
+ }
+
+ // Registers
+ // 0 - this
+ // 1..argRegs args
+ // argRegs+1 - method
+ // argRegs+2 - args (the array)
+ // argRegs+3 - AsyncResult
+ // argRegs+4 - e
+ // argRegs+5 - ExecutionError.cause
+ // argRegs+6 - e
+
+ int argRegs = 0;
+ for (int i=0; i<params.length; i++) {
+ Class<?> clazz = params[i];
+ argRegs++;
+ if (clazz==long.class || clazz==float.class || clazz==Double.class) argRegs++;
+ }
+
+ mv = cw.visitMethod(ACC_PUBLIC, m.getName(), typeDescription, null, exceptionResourceNames);
+ mv.visitCode();
+ Label l0 = new Label();
+ Label l1 = new Label();
+ Label l2 = new Label();
+ mv.visitTryCatchBlock(l0, l1, l2, "org/simantics/data/session/MethodInterface$ExecutionError");
+ Label l3 = new Label();
+ mv.visitTryCatchBlock(l0, l1, l3, "java/lang/InterruptedException");
+ Label l4 = new Label();
+ mv.visitLabel(l4);
+ mv.visitVarInsn(ALOAD, 0);
+ mv.visitFieldInsn(GETFIELD, classResourceName, "methods", "[Lorg/simantics/data/session/MethodInterface$Method;");
+ // Method m and puts into register
+ mv.visitLdcInsn(Integer.valueOf(methodNumber));
+ mv.visitInsn(AALOAD);
+ mv.visitVarInsn(ASTORE, argRegs+1);
+ Label l5 = new Label();
+ mv.visitLabel(l5);
+ mv.visitLdcInsn(Integer.valueOf(params.length));
+ mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
+
+ int register = 1; // argument register
+ for (int i=0; i<params.length; i++) {
+ Class<?> clazz = params[i];
+ mv.visitInsn(DUP);
+ mv.visitLdcInsn(Integer.valueOf(i));
+
+ if (clazz==byte.class) {
+ mv.visitVarInsn(ILOAD, register++);
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
+ } else if (clazz==char.class) {
+ mv.visitVarInsn(ILOAD, register++);
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
+ } else if (clazz==boolean.class) {
+ mv.visitVarInsn(ILOAD, register++);
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
+ } else if (clazz==byte.class) {
+ mv.visitVarInsn(ILOAD, register++);
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
+ } else if (clazz==int.class) {
+ mv.visitVarInsn(ILOAD, register++);
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
+ } else if (clazz==long.class) {
+ mv.visitVarInsn(LLOAD, register); register += 2;
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(F)Ljava/lang/Long;");
+ } else if (clazz==float.class) {
+ mv.visitVarInsn(FLOAD, register); register += 2;
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
+ } else if (clazz==Double.class) {
+ mv.visitVarInsn(DLOAD, register); register += 2;
+ mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
+ } else {
+ // Push argument to stack
+ mv.visitVarInsn(ALOAD, register++);
+ }
+ mv.visitInsn(AASTORE);
+ }
+
+ // Store args to argRegs+2
+ mv.visitVarInsn(ASTORE, argRegs+2);
+ Label l6 = new Label();
+ mv.visitLabel(l6);
+ mv.visitVarInsn(ALOAD, argRegs+1 /* m */);
+ mv.visitVarInsn(ALOAD, argRegs+2 /*args*/);
+ mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/data/session/MethodInterface$Method", "invoke", "(Ljava/lang/Object;)Lorg/simantics/data/session/MethodInterface$AsyncResult;");
+ mv.visitVarInsn(ASTORE, argRegs+3);
+ mv.visitLabel(l0);
+ mv.visitVarInsn(ALOAD, argRegs+3);
+ mv.visitMethodInsn(INVOKEINTERFACE, "org/simantics/data/session/MethodInterface$AsyncResult", "waitForResponse", "()Ljava/lang/Object;");
+ // TODO Return typecase result
+ Class<?> returnType = m.getReturnType();
+
+ if (returnType==void.class) {
+ mv.visitInsn(POP);
+ mv.visitInsn(RETURN);
+ } else if (returnType==int.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
+ mv.visitLabel(l1);
+ mv.visitInsn(IRETURN);
+ } else if (returnType==byte.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "B()");
+ mv.visitLabel(l1);
+ mv.visitInsn(IRETURN);
+ } else if (returnType==char.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
+ mv.visitLabel(l1);
+ mv.visitInsn(IRETURN);
+ } else if (returnType==boolean.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
+ mv.visitLabel(l1);
+ mv.visitInsn(IRETURN);
+ } else if (returnType==short.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
+ mv.visitLabel(l1);
+ mv.visitInsn(IRETURN);
+ } else if (returnType==long.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
+ mv.visitLabel(l1);
+ mv.visitInsn(LRETURN);
+ } else if (returnType==double.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
+ mv.visitLabel(l1);
+ mv.visitInsn(DRETURN);
+ } else if (returnType==float.class) {
+ mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
+ mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
+ mv.visitLabel(l1);
+ mv.visitInsn(FRETURN);
+ } else {
+ // Object
+ mv.visitTypeInsn(CHECKCAST, returnType.getName().replaceAll("\\.", "/"));
+ mv.visitLabel(l1);
+ mv.visitInsn(ARETURN);
+ }
+
+
+ // Handle exceptions
+ mv.visitLabel(l2);
+ mv.visitFrame(Opcodes.F_FULL, argRegs+4, new Object[] {classResourceName, "java/lang/Integer", "org/simantics/data/session/MethodInterface$Method", "[Ljava/lang/Object;", "org/simantics/data/session/MethodInterface$AsyncResult"}, 1, new Object[] {"org/simantics/data/session/MethodInterface$ExecutionError"});
+ mv.visitVarInsn(ASTORE, argRegs+4);
+ Label l7 = new Label();
+ mv.visitLabel(l7);
+ mv.visitVarInsn(ALOAD, argRegs+4);
+ mv.visitMethodInsn(INVOKEVIRTUAL, "org/simantics/data/session/MethodInterface$ExecutionError", "getError", "()Ljava/lang/Object;");
+ mv.visitVarInsn(ASTORE, argRegs+5); // argRegs+5 <- ExecutionError.cause
+
+ Class<?>[] exceptionClasses = m.getExceptionTypes();
+ Label nextException[] = new Label[exceptionClasses.length];
+ for (int i=0; i<exceptionClasses.length; i++)
+ {
+ Class<?> exceptionClass = exceptionClasses[i];
+ String exceptionClassResourceName = exceptionClass.getName().replaceAll("\\.", "/");
+ nextException[i] = new Label();
+ // If instanceof MyException
+ Label l8 = new Label();
+ mv.visitLabel(l8);
+ mv.visitVarInsn(ALOAD, argRegs+5); // Cause
+ mv.visitTypeInsn(INSTANCEOF, exceptionClassResourceName);
+ mv.visitJumpInsn(IFEQ, nextException[i]); // If not, go to ExecutionError
+ // If so, throw it
+ mv.visitVarInsn(ALOAD, argRegs+5); // e
+ mv.visitTypeInsn(CHECKCAST, exceptionClassResourceName);
+ mv.visitInsn(ATHROW);
+ mv.visitLabel(nextException[i]);
+ }
+
+ // ExecutionError
+ mv.visitFrame(Opcodes.F_APPEND,argRegs+1, new Object[] {"org/simantics/data/session/MethodInterface$ExecutionError", "java/lang/Object"}, 0, null);
+ mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(ALOAD, argRegs+4);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
+ mv.visitInsn(ATHROW);
+
+ // InteruptedException
+ mv.visitLabel(l3);
+ mv.visitFrame(Opcodes.F_FULL, argRegs+4, new Object[] {classResourceName, "java/lang/Integer", "org/simantics/data/session/MethodInterface$Method", "[Ljava/lang/Object;", "org/simantics/data/session/MethodInterface$AsyncResult"}, 1, new Object[] {"java/lang/InterruptedException"});
+ mv.visitVarInsn(ASTORE, argRegs+4);
+ Label l10 = new Label();
+ mv.visitLabel(l10);
+ mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
+ mv.visitInsn(DUP);
+ mv.visitVarInsn(ALOAD, argRegs+4);
+ mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
+ mv.visitInsn(ATHROW);
+
+ Label l11 = new Label();
+ mv.visitLabel(l11);
+ mv.visitLocalVariable("this", classTypeDescriptor, null, l4, l11, 0);
+// mv.visitLocalVariable("arg1", "Ljava/lang/Integer;", null, l4, l11, 1);
+ register = 1;
+ for (int i=0; i<params.length; i++) {
+ Class<?> clazz = params[i];
+ mv.visitLocalVariable("arg"+(i+1), classToTypeDescriptor(clazz), null, l4, l11, register);
+ register++;
+ if (clazz==long.class || clazz==float.class || clazz==Double.class) argRegs++;
+ }
+ mv.visitLocalVariable("m", "Lorg/simantics/data/session/MethodInterface$Method;", null, l5, l11, argRegs+1);
+ mv.visitLocalVariable("args", "[Ljava/lang/Object;", null, l6, l11, argRegs+2);
+ mv.visitLocalVariable("result", "Lorg/simantics/data/session/MethodInterface$AsyncResult;", null, l0, l11, argRegs+3);
+ mv.visitLocalVariable("e", "Lorg/simantics/data/session/MethodInterface$ExecutionError;", null, l7, l3, argRegs+4);
+ mv.visitLocalVariable("cause", "Ljava/lang/Object;", null, l7, l3, argRegs+5);
+ mv.visitLocalVariable("e", "Ljava/lang/InterruptedException;", null, l10, l11, argRegs+4);
+ mv.visitMaxs(argRegs+3, argRegs+6);
+ mv.visitEnd();
+ methodNumber++;
+ }
+
+ cw.visitEnd();
+ }
+
+}
+