Package ioke.lang.java

Source Code of ioke.lang.java.JavaIntegration

/*
* See LICENSE file in distribution for copyright and licensing information.
*/
package ioke.lang.java;

import java.util.Arrays;
import java.util.Comparator;
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
import java.util.List;
import java.util.LinkedList;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import static org.objectweb.asm.Opcodes.*;

/**
*
* @author <a href="mailto:ola.bini@gmail.com">Ola Bini</a>
*/
public class JavaIntegration {
    public static Class getOrCreate(Class[] types, ClassRegistry registry) {
        sort(types);
        String name = createCompositeNameFor(types);
        if(!hasImplementation(name, registry)) {
            createImplementationFor(name, types, registry);
        }
        return getImplementationFor(name, registry);
    }

    private static void sort(Class[] types) {
        Arrays.sort(types, new Comparator<Class>() {
                public int compare(Class one, Class two) {
                    return one.getName().compareTo(two.getName());
                }
            });
    }

    private static String createCompositeNameFor(Class[] types) {
        StringBuilder sb = new StringBuilder(types.length*15);
        String sep = "";
        for(Class type : types) {
            sb.append(sep).append(type.getName());
            sep = ",";
        }
        return sb.toString();
    }

    private static boolean hasImplementation(String name, ClassRegistry registry) {
        return registry.hasImplementation(name);
    }

    private static Class getImplementationFor(String name, ClassRegistry registry) {
        return registry.getImplementation(name);
    }

    private static void createImplementationFor(String name, Class[] types, ClassRegistry registry) {
        String className = findFirstUnusedNameFor(types);
//         System.err.println("have name: " + className);

        Class superClass = Object.class;
        List<Class> interfaces = new LinkedList<Class>();
        for(Class type : types) {
            if(!type.isInterface()) {
                superClass = type;
            } else {
                interfaces.add(type);
            }
        }

        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
        String[] ifs = new String[interfaces.size() + 1];
        int ix = 0;
        for(Class type : interfaces) {
            ifs[ix++] = p(type);
        }
        ifs[ix] = "ioke/lang/java/IokeJavaIntegrated";

        cw.visit(V1_5, ACC_PUBLIC, p(className), null, p(superClass), ifs);
        cw.visitField(0, "__real_ioke_proxy", "Lioke/lang/IokeObject;", null, null);

        implementConstructor(cw, className, superClass);
        implementIntegrationMethods(cw, className, superClass);

        if(superClass != Object.class) {
            implementStubMethodsFor(cw, className, superClass);
        }

        for(Class iface : interfaces) {
            implementStubMethodsFor(cw, className, iface);
        }

        cw.visitEnd();

        byte[] b = cw.toByteArray();

        registry.defineClass(className, name, b);
    }

    private static void implementConstructor(ClassWriter cw, String className, Class superClass) {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Lioke/lang/IokeObject;)V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitInsn(DUP);
        mv.visitMethodInsn(INVOKESPECIAL, p(superClass), "<init>", "()V");
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(PUTFIELD, p(className), "__real_ioke_proxy", "Lioke/lang/IokeObject;");
        mv.visitInsn(RETURN);
        mv.visitMaxs(1,1);
        mv.visitEnd();
    }

    private static void implementIntegrationMethods(ClassWriter cw, String className, Class superClass) {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "__get_IokeProxy", "()Lioke/lang/IokeObject;", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, p(className), "__real_ioke_proxy", "Lioke/lang/IokeObject;");
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1,1);
        mv.visitEnd();

        mv = cw.visitMethod(ACC_PUBLIC, "__get_IokeRuntime", "()Lioke/lang/Runtime;", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitFieldInsn(GETFIELD, p(className), "__real_ioke_proxy", "Lioke/lang/IokeObject;");
        mv.visitFieldInsn(GETFIELD, "ioke/lang/IokeObject", "runtime", "Lioke/lang/Runtime;");
        mv.visitInsn(ARETURN);
        mv.visitMaxs(1,1);
        mv.visitEnd();
    }

    private static void implementStubMethodsFor(ClassWriter cw, String className, Class type) {
        for(Method m : type.getDeclaredMethods()) {
            int modifiers = m.getModifiers();
            if(Modifier.isPublic(modifiers) && !Modifier.isFinal(modifiers) && !Modifier.isStatic(modifiers)) {
                implementStubMethod(cw, className, type, m);
            }
        }
    }

    private static void loadParameter(MethodVisitor mv, Class parameterType, int position) {
        if(parameterType == Byte.TYPE || parameterType == Integer.TYPE || parameterType == Short.TYPE || parameterType == Character.TYPE || parameterType == Boolean.TYPE) {
            mv.visitVarInsn(ILOAD, position);
        } else if(parameterType == Long.TYPE) {
            mv.visitVarInsn(LLOAD, position);
        } else if(parameterType == Float.TYPE) {
            mv.visitVarInsn(FLOAD, position);
        } else if(parameterType == Double.TYPE) {
            mv.visitVarInsn(DLOAD, position);
        } else {
            mv.visitVarInsn(ALOAD, position);
        }
    }

    private static void loadParameterWithConversion(MethodVisitor mv, Class parameterType, int position) {
        if(parameterType == Byte.TYPE) {
            mv.visitVarInsn(ILOAD, position);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
        } else if(parameterType == Integer.TYPE) {
            mv.visitVarInsn(ILOAD, position);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
        } else if(parameterType == Short.TYPE) {
            mv.visitVarInsn(ILOAD, position);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
        } else if(parameterType == Character.TYPE) {
            mv.visitVarInsn(ILOAD, position);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
        } else if(parameterType == Long.TYPE) {
            mv.visitVarInsn(LLOAD, position);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
        } else if(parameterType == Float.TYPE) {
            mv.visitVarInsn(FLOAD, position);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
        } else if(parameterType == Double.TYPE) {
            mv.visitVarInsn(DLOAD, position);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
        } else if(parameterType == Boolean.TYPE) {
            mv.visitVarInsn(ILOAD, position);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
        } else {
            mv.visitVarInsn(ALOAD, position);
        }
    }

    private static final String P_JAVA_INVOCATION_HELPER = p(JavaInvocationHelper.class);

    private static void implementStubMethod(ClassWriter cw, String className, Class type, Method m) {
//         System.err.println("should implement stub method: " + m);
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, m.getName(), sig(m), null, null);
        Class retType = m.getReturnType();
        mv.visitCode();

        if(!type.isInterface()) {
            mv.visitVarInsn(ALOAD, 0);
            mv.visitLdcInsn(m.getName());
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "hasProxyMethod", "(Lioke/lang/java/IokeJavaIntegrated;Ljava/lang/String;)Z");
            mv.visitInsn(ICONST_0);
            Label els = new Label();
            mv.visitJumpInsn(IF_ICMPNE, els);

            mv.visitVarInsn(ALOAD, 0);
            Class[] params = m.getParameterTypes();
            int i=1;
            for(Class pType : params) {
                loadParameter(mv, pType, i++);
            }

            mv.visitMethodInsn(INVOKESPECIAL, p(type), m.getName(), sig(m));

            if(retType == Void.TYPE) {
                mv.visitInsn(RETURN);
            } else if(retType == Byte.TYPE || retType == Integer.TYPE || retType == Short.TYPE || retType == Character.TYPE || retType == Boolean.TYPE) {
                mv.visitInsn(IRETURN);
            } else if(retType == Long.TYPE) {
                mv.visitInsn(LRETURN);
            } else if(retType == Float.TYPE) {
                mv.visitInsn(FRETURN);
            } else if(retType == Double.TYPE) {
                mv.visitInsn(DRETURN);
            } else {
                mv.visitInsn(ARETURN);
            }

            mv.visitLabel(els);
        }

        mv.visitVarInsn(ALOAD, 0);
        Class[] params = m.getParameterTypes();
        int i=1;
        mv.visitIntInsn(BIPUSH, params.length);
        mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
        for(Class pType : params) {
            mv.visitInsn(DUP);
            mv.visitIntInsn(BIPUSH, i-1);
            loadParameterWithConversion(mv, pType, i++);
            mv.visitInsn(AASTORE);
        }

        mv.visitLdcInsn(m.getName());

        if(retType == Void.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "voidInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)V");
            mv.visitInsn(RETURN);
        } else if(retType == Byte.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "byteInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)B");
            mv.visitInsn(IRETURN);
        } else if(retType == Integer.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "intInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)I");
            mv.visitInsn(IRETURN);
        } else if(retType == Short.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "shortInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)S");
            mv.visitInsn(IRETURN);
        } else if(retType == Character.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "charInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)C");
            mv.visitInsn(IRETURN);
        } else if(retType == Boolean.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "booleanInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)Z");
            mv.visitInsn(IRETURN);
        } else if(retType == Long.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "longInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)J");
            mv.visitInsn(LRETURN);
        } else if(retType == Float.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "floatInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)F");
            mv.visitInsn(FRETURN);
        } else if(retType == Double.TYPE) {
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "doubleInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;)D");
            mv.visitInsn(DRETURN);
        } else {
            mv.visitLdcInsn(retType.getName());
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
            mv.visitMethodInsn(INVOKESTATIC, P_JAVA_INVOCATION_HELPER, "objectInvocation", "(Lioke/lang/java/IokeJavaIntegrated;[Ljava/lang/Object;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;");
            mv.visitTypeInsn(CHECKCAST, p(retType));
            mv.visitInsn(ARETURN);
        }

        mv.visitMaxs(1,1);
        mv.visitEnd();
    }

    private static String sig(Method m) {
        return Type.getMethodDescriptor(m);
    }

    private static String p(String name) {
        return name.replaceAll("\\.", "/");
    }

    private static String p(Class type) {
        return type.getName().replaceAll("\\.", "/");
    }

    private static final Map<String, String> NAMES = new ConcurrentHashMap<String, String>();

    private static synchronized String findFirstUnusedNameFor(Class[] types) {
        Class mainType = null;
        for(Class type : types) {
            if(!type.isInterface()) {
                mainType = type;
                break;
            }
        }
        if(mainType == null) {
            mainType = types[0];
        }

        int number = 0;
        String baseName = "ioke.syn." + mainType.getName() + "$ioke$";
        String current = baseName + (number++);

        while(NAMES.containsKey(current)) {
            current = baseName + (number++);
        }

        NAMES.put(current, "dummy");

        return current;
    }
}// JavaIntegration
TOP

Related Classes of ioke.lang.java.JavaIntegration

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.