Example usage for org.objectweb.asm MethodVisitor visitLabel

List of usage examples for org.objectweb.asm MethodVisitor visitLabel

Introduction

In this page you can find the example usage for org.objectweb.asm MethodVisitor visitLabel.

Prototype

public void visitLabel(final Label label) 

Source Link

Document

Visits a label.

Usage

From source file:kilim.analysis.MethodWeaver.java

License:Open Source License

void genGetCurrentTask(MethodVisitor mv, BasicBlock bb) {
    mv.visitLabel(bb.startLabel);
    loadVar(mv, TOBJECT, getFiberVar());
    mv.visitFieldInsn(GETFIELD, FIBER_CLASS, "task", Constants.D_TASK);
}

From source file:kilim.analysis.MethodWeaver.java

License:Open Source License

/**
 * //from  w ww . java  2  s .c  o m
 * Say there are two invocations to two pausable methods obj.f(int)
 * (virtual) and fs(double) (a static call) ; load fiber from last arg, and
 * save it in a fresh register ; lest it gets stomped on. This is because we
 * only patch locally, and don't change the other instructions.
 * 
 * <pre>
 *     aload lastVar
 *     dup
 *     astore fiberVar 
 *     switch (fiber.pc) { 
 *       default: 0: START 
 *       1: F_PASS_DOWN 
 *       2: FS_PASS_DOWN 
 *     }
 * </pre>
 */
private void genPrelude(MethodVisitor mv) {
    assert isPausable : "MethodWeaver.genPrelude called for nonPausable method";
    MethodFlow mf = methodFlow;
    // load fiber from last var
    int lastVar = getFiberArgVar();

    mv.visitVarInsn(ALOAD, lastVar);
    if (lastVar < fiberVar) {
        if (callWeavers.size() > 0) {
            mv.visitInsn(DUP); // for storing into fiberVar
        }
        mv.visitVarInsn(ASTORE, getFiberVar());
    }

    if (callWeavers.size() == 0) {
        // Can happen if Task.getCurrentTask() is the only pausable method
        // call. We don't need the rest of the prelude.
        return;
    }

    mv.visitFieldInsn(GETFIELD, FIBER_CLASS, "pc", D_INT);
    // The prelude doesn't need more than two words in the stack.
    // The callweaver gen* methods may need more. 
    ensureMaxStack(2);

    // switch stmt
    Label startLabel = mf.getOrCreateLabelAtPos(0);
    Label errLabel = new Label();

    Label[] labels = new Label[callWeavers.size() + 1];
    labels[0] = startLabel;
    for (int i = 0; i < callWeavers.size(); i++) {
        labels[i + 1] = new Label();
    }
    // TODO       mv.visitTableSwitchInsn(0, callWeavers.size(), startLabel, labels);
    mv.visitTableSwitchInsn(0, callWeavers.size(), errLabel, labels);

    mv.visitLabel(errLabel);
    mv.visitMethodInsn(INVOKESTATIC, FIBER_CLASS, "wrongPC", "()V");
    // Generate pass through down code, one for each pausable method
    // invocation
    int last = callWeavers.size() - 1;
    for (int i = 0; i <= last; i++) {
        CallWeaver cw = callWeavers.get(i);
        mv.visitLabel(labels[i + 1]);
        cw.genRewind(mv);
    }
    mv.visitLabel(startLabel);
}

From source file:kilim.analysis.MethodWeaver.java

License:Open Source License

/**
 * Generate code for only those catch blocks that are reachable
 * from one or more pausable blocks. fiber.pc tells us which
 * nested call possibly caused an exception, fiber.status tells us
 * whether there is any state that needs to be restored, and
 * fiber.curState gives us access to that state. 
 * /*  w  ww  . ja v a  2s.  co  m*/
 * ; Figure out which pausable method could have caused this.
 * 
 * switch (fiber.upEx()) {
 *    0: goto NORMAL_EXCEPTION_HANDLING;
 *    2: goto RESTORE_F
 * }
 * RESTORE_F:
 *   if (fiber.curStatus == HAS_STATE) {
 *      restore variables from the state. don't restore stack
 *      goto NORMAL_EXCEPTION_HANDLING
 *   }
 * ... other RESTOREs
 * 
 * NORMAL_EXCEPTION_HANDLING:
 */
private void genException(MethodVisitor mv, BasicBlock bb, List<CallWeaver> cwList) {
    mv.visitLabel(bb.startLabel);
    Label resumeLabel = new Label();
    VMType.loadVar(mv, VMType.TOBJECT, getFiberVar());
    mv.visitMethodInsn(INVOKEVIRTUAL, FIBER_CLASS, "upEx", "()I");
    // fiber.pc is on stack
    Label[] labels = new Label[cwList.size()];
    int[] keys = new int[cwList.size()];
    for (int i = 0; i < cwList.size(); i++) {
        labels[i] = new Label();
        keys[i] = callWeavers.indexOf(cwList.get(i)) + 1;
    }

    mv.visitLookupSwitchInsn(resumeLabel, keys, labels);
    int i = 0;
    for (CallWeaver cw : cwList) {
        if (i > 0) {
            // This is the jump (to normal exception handling) for the previous
            // switch case.
            mv.visitJumpInsn(GOTO, resumeLabel);
        }
        mv.visitLabel(labels[i]);
        cw.genRestoreEx(mv, labels[i]);
        i++;
    }

    // Consume the first instruction because we have already consumed the
    // corresponding label. (The standard visitInstructions code does a 
    // visitLabel before visiting the instruction itself)
    mv.visitLabel(resumeLabel);
    bb.getInstruction(bb.startPos).accept(mv);
}

From source file:kr.debop4j.core.reflect.FieldAccess.java

License:Apache License

static private void insertSetObject(ClassWriter cw, String classNameInternal, List<Field> fields) {
    int maxStack = 6;
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "set", "(Ljava/lang/Object;ILjava/lang/Object;)V", null,
            null);/*from  www  .  j  av  a 2  s  .com*/
    mv.visitCode();
    mv.visitVarInsn(ILOAD, 2);

    if (!fields.isEmpty()) {
        maxStack--;
        Label[] labels = new Label[fields.size()];
        for (int i = 0, n = labels.length; i < n; i++)
            labels[i] = new Label();
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

        for (int i = 0, n = labels.length; i < n; i++) {
            Field field = fields.get(i);
            Type fieldType = Type.getType(field.getType());

            mv.visitLabel(labels[i]);
            mv.visitFrame(F_SAME, 0, null, 0, null);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, classNameInternal);
            mv.visitVarInsn(ALOAD, 3);

            switch (fieldType.getSort()) {
            case Type.BOOLEAN:
                mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
                break;
            case Type.BYTE:
                mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
                break;
            case Type.CHAR:
                mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
                break;
            case Type.SHORT:
                mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
                break;
            case Type.INT:
                mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
                break;
            case Type.FLOAT:
                mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
                break;
            case Type.LONG:
                mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
                break;
            case Type.DOUBLE:
                mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
                break;
            case Type.ARRAY:
                mv.visitTypeInsn(CHECKCAST, fieldType.getDescriptor());
                break;
            case Type.OBJECT:
                mv.visitTypeInsn(CHECKCAST, fieldType.getInternalName());
                break;
            default:
            }

            mv.visitFieldInsn(PUTFIELD, classNameInternal, field.getName(), fieldType.getDescriptor());
            mv.visitInsn(RETURN);
        }

        mv.visitLabel(defaultLabel);
        mv.visitFrame(F_SAME, 0, null, 0, null);
    }
    mv = insertThrowExceptionForFieldNotFound(mv);
    mv.visitMaxs(maxStack, 4);
    mv.visitEnd();
}

From source file:kr.debop4j.core.reflect.FieldAccess.java

License:Apache License

static private void insertGetObject(ClassWriter cw, String classNameInternal, List<Field> fields) {
    int maxStack = 6;
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "get", "(Ljava/lang/Object;I)Ljava/lang/Object;", null, null);
    mv.visitCode();// w  w w  . j  a v  a  2s  . c  om
    mv.visitVarInsn(ILOAD, 2);

    if (!fields.isEmpty()) {
        maxStack--;
        Label[] labels = new Label[fields.size()];
        for (int i = 0, n = labels.length; i < n; i++)
            labels[i] = new Label();
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

        for (int i = 0, n = labels.length; i < n; i++) {
            Field field = fields.get(i);

            mv.visitLabel(labels[i]);
            mv.visitFrame(F_SAME, 0, null, 0, null);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitTypeInsn(CHECKCAST, classNameInternal);
            mv.visitFieldInsn(GETFIELD, classNameInternal, field.getName(),
                    Type.getDescriptor(field.getType()));

            Type fieldType = Type.getType(field.getType());

            switch (fieldType.getSort()) {
            case Type.BOOLEAN:
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
                break;
            case Type.BYTE:
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
                break;
            case Type.CHAR:
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
                break;
            case Type.SHORT:
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
                break;
            case Type.INT:
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
                break;
            case Type.FLOAT:
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
                break;
            case Type.LONG:
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
                break;
            case Type.DOUBLE:
                mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
                break;
            default:
            }

            mv.visitInsn(ARETURN);
        }

        mv.visitLabel(defaultLabel);
        mv.visitFrame(F_SAME, 0, null, 0, null);
    }
    insertThrowExceptionForFieldNotFound(mv);
    mv.visitMaxs(maxStack, 3);
    mv.visitEnd();
}

From source file:kr.debop4j.core.reflect.FieldAccess.java

License:Apache License

static private void insertGetString(ClassWriter cw, String classNameInternal, List<Field> fields) {
    int maxStack = 6;
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getString", "(Ljava/lang/Object;I)Ljava/lang/String;", null,
            null);//  ww w  . j  ava2s  .  com
    mv.visitCode();
    mv.visitVarInsn(ILOAD, 2);

    if (!fields.isEmpty()) {
        maxStack--;
        Label[] labels = new Label[fields.size()];
        Label labelForInvalidTypes = new Label();
        boolean hasAnyBadTypeLabel = false;
        for (int i = 0, n = labels.length; i < n; i++) {
            if (fields.get(i).getType().equals(String.class))
                labels[i] = new Label();
            else {
                labels[i] = labelForInvalidTypes;
                hasAnyBadTypeLabel = true;
            }
        }
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

        for (int i = 0, n = labels.length; i < n; i++) {
            if (!labels[i].equals(labelForInvalidTypes)) {
                mv.visitLabel(labels[i]);
                mv.visitFrame(F_SAME, 0, null, 0, null);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitTypeInsn(CHECKCAST, classNameInternal);
                mv.visitFieldInsn(GETFIELD, classNameInternal, fields.get(i).getName(), "Ljava/lang/String;");
                mv.visitInsn(ARETURN);
            }
        }
        // Rest of fields: different type
        if (hasAnyBadTypeLabel) {
            mv.visitLabel(labelForInvalidTypes);
            mv.visitFrame(F_SAME, 0, null, 0, null);
            insertThrowExceptionForFieldType(mv, "String");
        }
        // Default: field not found
        mv.visitLabel(defaultLabel);
        mv.visitFrame(F_SAME, 0, null, 0, null);
    }
    insertThrowExceptionForFieldNotFound(mv);
    mv.visitMaxs(maxStack, 3);
    mv.visitEnd();
}

From source file:kr.debop4j.core.reflect.FieldAccess.java

License:Apache License

static private void insertSetPrimitive(ClassWriter cw, String classNameInternal, List<Field> fields,
        Type primitiveType) {//from   w w  w  . ja  v a 2  s  .  c om
    int maxStack = 6;
    int maxLocals = 4; // See correction below for LLOAD and DLOAD
    final String setterMethodName;
    final String typeNameInternal = primitiveType.getDescriptor();
    final int loadValueInstruction;
    switch (primitiveType.getSort()) {
    case Type.BOOLEAN:
        setterMethodName = "setBoolean";
        loadValueInstruction = ILOAD;
        break;
    case Type.BYTE:
        setterMethodName = "setByte";
        loadValueInstruction = ILOAD;
        break;
    case Type.CHAR:
        setterMethodName = "setChar";
        loadValueInstruction = ILOAD;
        break;
    case Type.SHORT:
        setterMethodName = "setShort";
        loadValueInstruction = ILOAD;
        break;
    case Type.INT:
        setterMethodName = "setInt";
        loadValueInstruction = ILOAD;
        break;
    case Type.FLOAT:
        setterMethodName = "setFloat";
        loadValueInstruction = FLOAD;
        break;
    case Type.LONG:
        setterMethodName = "setLong";
        loadValueInstruction = LLOAD;
        maxLocals++; // (LLOAD and DLOAD actually load two slots)
        break;
    case Type.DOUBLE:
        setterMethodName = "setDouble";
        loadValueInstruction = DLOAD; // (LLOAD and DLOAD actually load two slots)
        maxLocals++;
        break;
    default:
        setterMethodName = "set";
        loadValueInstruction = ALOAD;
        break;
    }
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, setterMethodName,
            "(Ljava/lang/Object;I" + typeNameInternal + ")V", null, null);
    mv.visitCode();
    mv.visitVarInsn(ILOAD, 2);

    if (!fields.isEmpty()) {
        maxStack--;
        Label[] labels = new Label[fields.size()];
        Label labelForInvalidTypes = new Label();
        boolean hasAnyBadTypeLabel = false;
        for (int i = 0, n = labels.length; i < n; i++) {
            if (Type.getType(fields.get(i).getType()).equals(primitiveType))
                labels[i] = new Label();
            else {
                labels[i] = labelForInvalidTypes;
                hasAnyBadTypeLabel = true;
            }
        }
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

        for (int i = 0, n = labels.length; i < n; i++) {
            if (!labels[i].equals(labelForInvalidTypes)) {
                mv.visitLabel(labels[i]);
                mv.visitFrame(F_SAME, 0, null, 0, null);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitTypeInsn(CHECKCAST, classNameInternal);
                mv.visitVarInsn(loadValueInstruction, 3);
                mv.visitFieldInsn(PUTFIELD, classNameInternal, fields.get(i).getName(), typeNameInternal);
                mv.visitInsn(RETURN);
            }
        }
        // Rest of fields: different type
        if (hasAnyBadTypeLabel) {
            mv.visitLabel(labelForInvalidTypes);
            mv.visitFrame(F_SAME, 0, null, 0, null);
            insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
        }
        // Default: field not found
        mv.visitLabel(defaultLabel);
        mv.visitFrame(F_SAME, 0, null, 0, null);
    }
    mv = insertThrowExceptionForFieldNotFound(mv);
    mv.visitMaxs(maxStack, maxLocals);
    mv.visitEnd();
}

From source file:kr.debop4j.core.reflect.FieldAccess.java

License:Apache License

static private void insertGetPrimitive(ClassWriter cw, String classNameInternal, List<Field> fields,
        Type primitiveType) {/*w w w .j  a  v a2  s .co m*/
    int maxStack = 6;
    final String getterMethodName;
    final String typeNameInternal = primitiveType.getDescriptor();
    final int returnValueInstruction;
    switch (primitiveType.getSort()) {
    case Type.BOOLEAN:
        getterMethodName = "getBoolean";
        returnValueInstruction = IRETURN;
        break;
    case Type.BYTE:
        getterMethodName = "getByte";
        returnValueInstruction = IRETURN;
        break;
    case Type.CHAR:
        getterMethodName = "getChar";
        returnValueInstruction = IRETURN;
        break;
    case Type.SHORT:
        getterMethodName = "getShort";
        returnValueInstruction = IRETURN;
        break;
    case Type.INT:
        getterMethodName = "getInt";
        returnValueInstruction = IRETURN;
        break;
    case Type.FLOAT:
        getterMethodName = "getFloat";
        returnValueInstruction = FRETURN;
        break;
    case Type.LONG:
        getterMethodName = "getLong";
        returnValueInstruction = LRETURN;
        break;
    case Type.DOUBLE:
        getterMethodName = "getDouble";
        returnValueInstruction = DRETURN;
        break;
    default:
        getterMethodName = "get";
        returnValueInstruction = ARETURN;
        break;
    }
    MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, getterMethodName, "(Ljava/lang/Object;I)" + typeNameInternal,
            null, null);
    mv.visitCode();
    mv.visitVarInsn(ILOAD, 2);

    if (!fields.isEmpty()) {
        maxStack--;
        Label[] labels = new Label[fields.size()];
        Label labelForInvalidTypes = new Label();
        boolean hasAnyBadTypeLabel = false;
        for (int i = 0, n = labels.length; i < n; i++) {
            if (Type.getType(fields.get(i).getType()).equals(primitiveType))
                labels[i] = new Label();
            else {
                labels[i] = labelForInvalidTypes;
                hasAnyBadTypeLabel = true;
            }
        }
        Label defaultLabel = new Label();
        mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

        for (int i = 0, n = labels.length; i < n; i++) {
            Field field = fields.get(i);
            if (!labels[i].equals(labelForInvalidTypes)) {
                mv.visitLabel(labels[i]);
                mv.visitFrame(F_SAME, 0, null, 0, null);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitTypeInsn(CHECKCAST, classNameInternal);
                mv.visitFieldInsn(GETFIELD, classNameInternal, field.getName(), typeNameInternal);
                mv.visitInsn(returnValueInstruction);
            }
        }
        // Rest of fields: different type
        if (hasAnyBadTypeLabel) {
            mv.visitLabel(labelForInvalidTypes);
            mv.visitFrame(F_SAME, 0, null, 0, null);
            insertThrowExceptionForFieldType(mv, primitiveType.getClassName());
        }
        // Default: field not found
        mv.visitLabel(defaultLabel);
        mv.visitFrame(F_SAME, 0, null, 0, null);
    }
    mv = insertThrowExceptionForFieldNotFound(mv);
    mv.visitMaxs(maxStack, 3);
    mv.visitEnd();
}

From source file:kr.debop4j.core.reflect.MethodAccess.java

License:Apache License

/**
 *  ? ? ??   MethodAccess ./*from  w  ww . ja  v a2  s  . co m*/
 *
 * @param type 
 * @return the method access
 */
public static MethodAccess get(final Class type) {
    Guard.shouldNotBeNull(type, "type");

    List<Method> methods = Lists.newArrayList();
    Class nextClass = type;
    while (nextClass != Object.class) {
        Method[] declaredMethods = nextClass.getDeclaredMethods();
        for (Method method : declaredMethods) {
            int modifiers = method.getModifiers();
            if (Modifier.isStatic(modifiers))
                continue;
            if (Modifier.isPrivate(modifiers))
                continue;
            methods.add(method);
        }
        nextClass = nextClass.getSuperclass();
    }

    Class[][] parameterTypes = new Class[methods.size()][];
    String[] methodNames = new String[methods.size()];
    for (int i = 0, size = methodNames.length; i < size; i++) {
        Method method = methods.get(i);
        methodNames[i] = method.getName();
        parameterTypes[i] = method.getParameterTypes();
    }

    String className = type.getName();
    String accessClassName = className + "MethodAccess";
    if (accessClassName.startsWith("java."))
        accessClassName = ReflectConsts.BASE_PACKAGE + "." + accessClassName;

    Class accessClass;
    AccessClassLoader loader = AccessClassLoader.get(type);

    synchronized (loader) {
        try {
            accessClass = loader.loadClass(accessClassName);
        } catch (ClassNotFoundException ignored) {
            String accessClassNameInternal = accessClassName.replace('.', '/');
            String classNameInternal = className.replace('.', '/');

            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
            MethodVisitor mv;
            cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null,
                    ReflectConsts.METHOD_ACCESS_PATH, null);
            {
                mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
                mv.visitCode();
                mv.visitVarInsn(ALOAD, 0);
                mv.visitMethodInsn(INVOKESPECIAL, ReflectConsts.METHOD_ACCESS_PATH, "<init>", "()V");
                mv.visitInsn(RETURN);
                mv.visitMaxs(0, 0);
                mv.visitEnd();
            }
            {
                mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke",
                        "(Ljava/lang/Object;I[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
                mv.visitCode();

                if (!methods.isEmpty()) {
                    mv.visitVarInsn(ALOAD, 1);
                    mv.visitTypeInsn(CHECKCAST, classNameInternal);
                    mv.visitVarInsn(ASTORE, 4);

                    mv.visitVarInsn(ILOAD, 2);
                    Label[] labels = new Label[methods.size()];
                    for (int i = 0, n = labels.length; i < n; i++)
                        labels[i] = new Label();
                    Label defaultLabel = new Label();
                    mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);

                    StringBuilder buffer = new StringBuilder(128);
                    for (int i = 0, n = labels.length; i < n; i++) {
                        mv.visitLabel(labels[i]);
                        if (i == 0)
                            mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] { classNameInternal }, 0, null);
                        else
                            mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
                        mv.visitVarInsn(ALOAD, 4);

                        buffer.setLength(0);
                        buffer.append('(');

                        Method method = methods.get(i);
                        Class[] paramTypes = method.getParameterTypes();
                        for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
                            mv.visitVarInsn(ALOAD, 3);
                            mv.visitIntInsn(BIPUSH, paramIndex);
                            mv.visitInsn(AALOAD);
                            Type paramType = Type.getType(paramTypes[paramIndex]);
                            switch (paramType.getSort()) {
                            case Type.BOOLEAN:
                                mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
                                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
                                break;
                            case Type.BYTE:
                                mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
                                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
                                break;
                            case Type.CHAR:
                                mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
                                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
                                break;
                            case Type.SHORT:
                                mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
                                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
                                break;
                            case Type.INT:
                                mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
                                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
                                break;
                            case Type.FLOAT:
                                mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
                                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
                                break;
                            case Type.LONG:
                                mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
                                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
                                break;
                            case Type.DOUBLE:
                                mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
                                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
                                break;
                            case Type.ARRAY:
                                mv.visitTypeInsn(CHECKCAST, paramType.getDescriptor());
                                break;
                            case Type.OBJECT:
                                mv.visitTypeInsn(CHECKCAST, paramType.getInternalName());
                                break;
                            }
                            buffer.append(paramType.getDescriptor());
                        }

                        buffer.append(')');
                        buffer.append(Type.getDescriptor(method.getReturnType()));
                        mv.visitMethodInsn(INVOKEVIRTUAL, classNameInternal, method.getName(),
                                buffer.toString());

                        switch (Type.getType(method.getReturnType()).getSort()) {
                        case Type.VOID:
                            mv.visitInsn(ACONST_NULL);
                            break;
                        case Type.BOOLEAN:
                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf",
                                    "(Z)Ljava/lang/Boolean;");
                            break;
                        case Type.BYTE:
                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf",
                                    "(B)Ljava/lang/Byte;");
                            break;
                        case Type.CHAR:
                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf",
                                    "(C)Ljava/lang/Character;");
                            break;
                        case Type.SHORT:
                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf",
                                    "(S)Ljava/lang/Short;");
                            break;
                        case Type.INT:
                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf",
                                    "(I)Ljava/lang/Integer;");
                            break;
                        case Type.FLOAT:
                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf",
                                    "(F)Ljava/lang/Float;");
                            break;
                        case Type.LONG:
                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf",
                                    "(J)Ljava/lang/Long;");
                            break;
                        case Type.DOUBLE:
                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf",
                                    "(D)Ljava/lang/Double;");
                            break;
                        }

                        mv.visitInsn(ARETURN);
                    }

                    mv.visitLabel(defaultLabel);
                    mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
                }
                mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
                mv.visitInsn(DUP);
                mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
                mv.visitInsn(DUP);
                mv.visitLdcInsn("Method not found: ");
                mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
                mv.visitVarInsn(ILOAD, 2);
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append",
                        "(I)Ljava/lang/StringBuilder;");
                mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString",
                        "()Ljava/lang/String;");
                mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>",
                        "(Ljava/lang/String;)V");
                mv.visitInsn(ATHROW);
                mv.visitMaxs(0, 0);
                mv.visitEnd();
            }
            cw.visitEnd();
            byte[] data = cw.toByteArray();
            accessClass = loader.defineClass(accessClassName, data);
        }
    }

    try {
        MethodAccess access = (MethodAccess) accessClass.newInstance();
        access.methodNames = methodNames;
        access.parameterTypes = parameterTypes;

        return access;
    } catch (Exception ex) {
        throw new RuntimeException("Error constructing method access class=[" + accessClassName + "]", ex);
    }
}

From source file:lapin.comp.asm.ASMByteCodeGenerator.java

License:Open Source License

private void generateCall(CallableInfo ci, Env env) {
    /*//  ww  w . j  a  va  2  s. co  m
     * local variables
     * <Callable#call>
     * 0: this
     * 1: args (list of arguments)
     * 2: env
     *
     * <Callable0#call0>
     * 0: this
     * 1: env
     *
     * <Callable1#call1>
     * 0: this
     * 1: arg0
     * 2: env
     *
     * <Callable2#call2>
     * 0: this
     * 1: arg0
     * 2: arg1
     * 3: env
     *
     * ...
     *
     */
    MethodVisitor mv = _cw.visitMethod(
            ci.mi.implCallable() ? Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL : Opcodes.ACC_FINAL, ci.mi.name(),
            Type.getMethodDescriptor(ci.retType, ci.paramTypes), null, null);

    // instruction list
    int len = ci.mi.instLen();
    // label
    Label label = null;

    // generate code
    for (int i = 0; i < len; i++) {
        Object inst = ci.mi.getInst(i);
        if (Logger.tracelevelp(env))
            Logger.trace("[asm:gen]" + i + ":\t~S", Lists.list(inst), env);

        // inst is symbol
        // -> convert tag (Symbol) to label (ASMe Label object)
        if (Data.isSymbol(inst)) {
            Symbol tag = Data.symbol(inst);
            Label l = (Label) ci.labelTable.get(tag);
            if (l == null) {
                throw new NotReachedException("label is null: ~S.", Lists.list(tag));
            } else if (l != label) {
                mv.visitLabel(l);
                label = l;
                if (Logger.tracelevelp(env))
                    Logger.trace("[asm:gen]" + i + ":\ttag ~S -> label ~S", Lists.list(tag, l), env);
            } else {
                if (Logger.tracelevelp(env))
                    Logger.trace("[asm:gen]" + i + ":\ttag ~S -> label ~S" + " (dup)", Lists.list(tag, l), env);
            }
            continue;
        }

        // inst must be the form of (id <arg1> <arg2> ....)
        Object id = Lists.car(inst);
        if (id == Insts.CONST) {
            /* push const on the stack. */
            Object obj = Lists.cadr(inst);
            String val = Data.string(constTable.get(obj));
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, toInternalName(super.classInfo.classname()), val,
                    TYPE_OBJECT.getDescriptor());
        } else if (id == Insts.VAR) {
            /* push var on the stack */
            Object var = Lists.cadr(inst);
            String val = Data.string(varTable.get(var));
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, toInternalName(super.classInfo.classname()), val,
                    TYPE_SYMBOL.getDescriptor());
        } else if (id == Insts.LAMBDA_LIST) {
            /* push lambdaList on the stack */
            Object var = Lists.cadr(inst);
            /* push _ll_<i> on the stack */
            String val = Data.string(llTable.get(var));
            mv.visitVarInsn(Opcodes.ALOAD, 0);
            mv.visitFieldInsn(Opcodes.GETFIELD, toInternalName(super.classInfo.classname()), val,
                    TYPE_LAMBDA_LIST.getDescriptor());
        } else if (id == Insts.ENV_GET) {
            /* env.get */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "getInt",
                        Type.getMethodDescriptor(Type.INT_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (type.equals(double.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "getDouble",
                        Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (type.equals(char.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "getChar",
                        Type.getMethodDescriptor(Type.CHAR_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (Object.class.isAssignableFrom(type)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "get",
                        Type.getMethodDescriptor(TYPE_OBJECT, new Type[] { TYPE_SYMBOL }));
            } else {
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
        } else if (id == Insts.ENV_SET) {
            /* env.set */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "set",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.INT_TYPE }));
            } else if (type.equals(double.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "set",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.DOUBLE_TYPE }));
            } else if (type.equals(char.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "set",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.CHAR_TYPE }));
            } else if (Object.class.isAssignableFrom(type)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "set",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, TYPE_OBJECT }));
            } else {
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
        } else if (id == Insts.ENV_BIND) {
            /* env.bind */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "bind",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.INT_TYPE }));
            } else if (type.equals(double.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "bind",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.DOUBLE_TYPE }));
            } else if (type.equals(char.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "bind",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, Type.CHAR_TYPE }));
            } else if (Object.class.isAssignableFrom(type)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "bind",
                        Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { TYPE_SYMBOL, TYPE_OBJECT }));
            } else {
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
        } else if (id == Insts.ENV_UNBIND) {
            /* env.unbind */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "unbindInt",
                        Type.getMethodDescriptor(Type.INT_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (type.equals(double.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "unbindDouble",
                        Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (type.equals(char.class)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "unbindChar",
                        Type.getMethodDescriptor(Type.CHAR_TYPE, new Type[] { TYPE_SYMBOL }));
            } else if (Object.class.isAssignableFrom(type)) {
                mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "unbind",
                        Type.getMethodDescriptor(TYPE_OBJECT, new Type[] { TYPE_SYMBOL }));
            } else {
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
        } else if (id == Insts.ENV_CHILD) {
            /* env.child */
            Object oldEnvVar = Lists.cadr(inst);
            Object newEnvVar = Lists.caddr(inst);
            Object oldSlot = Lists.cadr(oldEnvVar);
            Object newSlot = Lists.cadr(newEnvVar);
            int oldLocal = Data.fixnum(ci.localTable.get(oldSlot)).intValue();
            int newLocal = Data.fixnum(ci.localTable.get(newSlot)).intValue();
            if (Logger.tracelevelp(env))
                Logger.trace("[asm:gen]" + i + ":\tenv-child: local ~S -> ~S",
                        Lists.list(Data.toFixnum(oldLocal), Data.toFixnum(newLocal)), env);
            mv.visitVarInsn(Opcodes.ALOAD, oldLocal);
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, TYPE_ENV.getInternalName(), "child",
                    Type.getMethodDescriptor(TYPE_ENV, TYPE_NO_ARGS));
            mv.visitVarInsn(Opcodes.ASTORE, newLocal);
        } else if (id == Insts.CALL) {
            /* funcall */
            int nargs = Data.fixnum(Lists.cadr(inst)).intValue();
            String className = "lapin.eval.Funcall";
            String methodName = nargs < 0 ? "funcall" : "funcall" + nargs;
            Class rType = Object.class;
            Class[] pTypes;
            if (nargs < 0) {
                pTypes = new Class[] { Function.class, Object.class, // list of args
                        Env.class };
            } else {
                pTypes = new Class[nargs + 2];
                pTypes[0] = Function.class;
                for (int j = 0; j < nargs; j++) {
                    pTypes[j + 1] = Object.class;
                }
                pTypes[nargs + 1] = Env.class;
            }

            Type retType = Type.getType(rType);
            Type[] paramTypes = new Type[pTypes.length];
            for (int j = 0; j < pTypes.length; j++)
                paramTypes[j] = Type.getType(pTypes[j]);

            mv.visitMethodInsn(Opcodes.INVOKESTATIC, toInternalName(className), methodName,
                    Type.getMethodDescriptor(retType, paramTypes));
        } else if (id == Insts.CALL_DIRECT) {
            /*
             * public class Foo
             *   extends CompiledExpr implements Callable2 {
             *  public Object call2(Object arg0, Object arg1, Env env) {
             *   ...
             *  }
             * }
             */
            MethodInfo mi = (MethodInfo) Lists.cadr(inst);
            String className = mi.classInfo().classname();
            int nargs = mi.nargs();
            boolean rest = mi.rest();
            String methodName = mi.name();
            Class rType = mi.retType();
            Class[] pTypes = mi.paramTypes();

            Type retType = Type.getType(rType);
            Type[] paramTypes = new Type[pTypes.length];
            for (int j = 0; j < pTypes.length; j++)
                paramTypes[j] = Type.getType(pTypes[j]);

            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, toInternalName(className), methodName,
                    Type.getMethodDescriptor(retType, paramTypes));
        } else if (id == Insts.COMPILED_EXPR) {
            /*
             * public class Foo extends CompiledExpr {
             *  static public Foo SELF;
             *  ...
             * }
             */
            String className = Data.string(Lists.cadr(inst));
            String fieldName = "SELF";
            String typeName = className;
            mv.visitFieldInsn(Opcodes.GETSTATIC, toInternalName(className), fieldName,
                    toTypeDescriptor(typeName));
        } else if (id == Insts.RETURN) {
            /* return */
            Class type = Data.javaClass(Lists.cadr(inst));
            if (type.equals(int.class) || type.equals(short.class) || type.equals(byte.class)
                    || type.equals(char.class)) {
                mv.visitInsn(Opcodes.IRETURN);
            } else if (type.equals(long.class)) {
                mv.visitInsn(Opcodes.LRETURN);
            } else if (type.equals(float.class)) {
                mv.visitInsn(Opcodes.FRETURN);
            } else if (type.equals(double.class)) {
                mv.visitInsn(Opcodes.DRETURN);
            } else if (type.equals(void.class)) {
                //mv.visitInsn(Opcodes.RETURN);
                throw new NotReachedException("unsupported returnType: ~S.", Lists.list(type));
            } else {
                mv.visitInsn(Opcodes.ARETURN);
            }
        } else if (id == Insts.IFEQ) {
            /* conditional jump */
            Symbol tag = Data.symbol(Lists.cadr(inst));
            Label l = (Label) ci.labelTable.get(tag);
            if (l == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tag));
            }
            mv.visitJumpInsn(Opcodes.IFEQ, l);
        } else if (id == Insts.IFNE) {
            /* conditional jump */
            Symbol tag = Data.symbol(Lists.cadr(inst));
            Label l = (Label) ci.labelTable.get(tag);
            if (l == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tag));
            }
            mv.visitJumpInsn(Opcodes.IFNE, l);
        } else if (id == Insts.GOTO) {
            /* jump */
            Symbol tag = Data.symbol(Lists.cadr(inst));
            Label l = (Label) ci.labelTable.get(tag);
            if (l == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tag));
            }
            mv.visitJumpInsn(Opcodes.GOTO, l);
        } else if (id == Insts.LOAD) {
            /* local -> stack */
            Object localVar = Lists.cadr(inst);
            Object slot = Lists.cadr(localVar);
            Class type = Data.javaClass(Lists.caddr(localVar));
            int local = Data.fixnum(ci.localTable.get(slot)).intValue();
            int op = Type.getType(type).getOpcode(Opcodes.ILOAD);
            if (Logger.tracelevelp(env))
                Logger.trace("[asm:gen]" + i + ":\tload: local=~S type=~S",
                        Lists.list(Data.toFixnum(local), type), env);
            mv.visitVarInsn(op, local);
        } else if (id == Insts.STORE) {
            /* stack -> local */
            Object localVar = Lists.cadr(inst);
            Object slot = Lists.cadr(localVar);
            Class type = Data.javaClass(Lists.caddr(localVar));
            int local = Data.fixnum(ci.localTable.get(slot)).intValue();
            int op = Type.getType(type).getOpcode(Opcodes.ISTORE);
            if (Logger.tracelevelp(env))
                Logger.trace("[asm:gen]" + i + ":\tstore: local=~S type=~S",
                        Lists.list(Data.toFixnum(local), type), env);
            mv.visitVarInsn(op, local);
        } else if (id == Insts.POP) {
            /* pop a value and discard it */
            Class type = Data.javaClass(Lists.cadr(inst));
            int op;
            switch (Classes.sizeOf(type)) {
            case 1:
                op = Opcodes.POP;
                break;
            case 2:
                op = Opcodes.POP2;
                break;
            default:
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
            mv.visitInsn(op);
        } else if (id == Insts.DUP) {
            /* peek a value and duplicate it */
            Class type = Data.javaClass(Lists.cadr(inst));
            int op;
            switch (Classes.sizeOf(type)) {
            case 1:
                op = Opcodes.DUP;
                break;
            case 2:
                op = Opcodes.DUP2;
                break;
            default:
                throw new NotReachedException("unsupported type: ~S.", Lists.list(type));
            }
            mv.visitInsn(op);
        } else if (id == Insts.PUSH) {
            /* push a constant */
            Object val = Lists.cadr(inst);
            if (Data.isJavaBoolean(val)) {
                if (Data.javaBoolean(val).booleanValue())
                    mv.visitInsn(Opcodes.ICONST_1);
                else
                    mv.visitInsn(Opcodes.ICONST_0);
            } else if (val instanceof Byte || val instanceof Short || val instanceof Integer) {
                int n = Data.javaNumber(val).intValue();
                if (n == -1)
                    mv.visitInsn(Opcodes.ICONST_M1);
                else if (n == 0)
                    mv.visitInsn(Opcodes.ICONST_0);
                else if (n == 1)
                    mv.visitInsn(Opcodes.ICONST_1);
                else if (n == 2)
                    mv.visitInsn(Opcodes.ICONST_2);
                else if (n == 3)
                    mv.visitInsn(Opcodes.ICONST_3);
                else if (n == 4)
                    mv.visitInsn(Opcodes.ICONST_4);
                else if (n == 5)
                    mv.visitInsn(Opcodes.ICONST_5);
                else if (Byte.MIN_VALUE <= n && n <= Byte.MAX_VALUE)
                    mv.visitIntInsn(Opcodes.BIPUSH, n);
                else if (Short.MIN_VALUE <= n && n <= Short.MAX_VALUE)
                    mv.visitIntInsn(Opcodes.SIPUSH, n);
                else
                    mv.visitLdcInsn(Data.toFixnum(n));
            } else if (val instanceof Long) {
                long n = Data.javaNumber(val).longValue();
                if (n == 0L)
                    mv.visitInsn(Opcodes.LCONST_0);
                else if (n == 1L)
                    mv.visitInsn(Opcodes.LCONST_1);
                else
                    mv.visitLdcInsn(val);
            } else if (val instanceof Float) {
                float n = Data.javaNumber(val).floatValue();
                if (n == 0.0f)
                    mv.visitInsn(Opcodes.FCONST_0);
                else if (n == 1.0f)
                    mv.visitInsn(Opcodes.FCONST_1);
                else if (n == 2.0f)
                    mv.visitInsn(Opcodes.FCONST_2);
                else
                    mv.visitLdcInsn(val);
            } else if (val instanceof Double) {
                double n = Data.javaNumber(val).doubleValue();
                if (n == 0.0)
                    mv.visitInsn(Opcodes.DCONST_0);
                else if (n == 1.0)
                    mv.visitInsn(Opcodes.DCONST_1);
                else
                    mv.visitLdcInsn(val);
            } else if (Data.isCharacter(val)) {
                Character c = Data.character(val);
                int n = (int) c.charValue();
                if (Byte.MIN_VALUE <= n && n <= Byte.MAX_VALUE)
                    mv.visitIntInsn(Opcodes.BIPUSH, n);
                else if (Short.MIN_VALUE <= n && n <= Short.MAX_VALUE)
                    mv.visitIntInsn(Opcodes.SIPUSH, n);
                else
                    mv.visitLdcInsn(Data.toFixnum(n));
            } else if (Data.isString(val)) {
                mv.visitLdcInsn(val);
            } else {
                throw new NotReachedException("cannot push: ~S.", Lists.list(val));
            }
        } else if (id == Insts.GET) {
            Field f = Data.javaField(Lists.cadr(inst));
            String fieldName = f.getName();
            Class c = f.getDeclaringClass();
            String className = c.getName();
            Class t = f.getType();
            String typeName = t.getName();

            boolean isStatic = Classes.isStatic(f);
            int op = isStatic ? Opcodes.GETSTATIC : Opcodes.GETFIELD;

            mv.visitFieldInsn(op, toInternalName(className), fieldName, toTypeDescriptor(typeName));
        } else if (id == Insts.PUT) {
            Field f = Data.javaField(Lists.cadr(inst));
            String fieldName = f.getName();
            Class c = f.getDeclaringClass();
            String className = c.getName();
            Class t = f.getType();
            String typeName = t.getName();

            boolean isStatic = Classes.isStatic(f);
            int op = isStatic ? Opcodes.PUTSTATIC : Opcodes.PUTFIELD;

            mv.visitFieldInsn(op, toInternalName(className), fieldName, toTypeDescriptor(typeName));
        } else if (id == Insts.INVOKE) {
            Method m = Data.javaMethod(Lists.cadr(inst));
            String methodName = m.getName();
            Class c = m.getDeclaringClass();
            String className = c.getName();
            Class rType = m.getReturnType();
            Class[] pTypes = m.getParameterTypes();
            if (rType.equals(void.class)) {
                throw new NotReachedException("unsupported returnType: ~S.", Lists.list(rType));
            }
            Type retType = Type.getType(rType);
            Type[] paramTypes = new Type[pTypes.length];
            for (int j = 0; j < pTypes.length; j++)
                paramTypes[j] = Type.getType(pTypes[j]);

            boolean isStatic = Classes.isStatic(m);
            boolean isInterface = c.isInterface();
            int op = isStatic ? Opcodes.INVOKESTATIC
                    : isInterface ? Opcodes.INVOKEINTERFACE : Opcodes.INVOKEVIRTUAL;

            mv.visitMethodInsn(op, toInternalName(className), methodName,
                    Type.getMethodDescriptor(retType, paramTypes));
        } else if (id == Insts.CHECKCAST) {
            Class c = Data.javaClass(Lists.cadr(inst));
            Type t = Type.getType(c);
            mv.visitTypeInsn(Opcodes.CHECKCAST, t.getInternalName());
        } else if (id == Insts.THROW) {
            mv.visitInsn(Opcodes.ATHROW);
        } else if (id == Insts.CATCH) {
            Symbol tagS = Data.symbol(Lists.cadr(inst));
            Symbol tagE = Data.symbol(Lists.caddr(inst));
            Symbol tagH = Data.symbol(Lists.cadddr(inst));
            String className;
            if (Lists.isEnd(Lists.cddddr(inst))) {
                className = null;
            } else {
                Class c = Data.javaClass(Lists.car(Lists.cddddr(inst)));
                className = toInternalName(c.getName());
            }
            Label labelS = (Label) ci.labelTable.get(tagS);
            if (labelS == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tagS));
            }
            Label labelE = (Label) ci.labelTable.get(tagE);
            if (labelE == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tagE));
            }
            Label labelH = (Label) ci.labelTable.get(tagH);
            if (labelH == null) {
                throw new NotReachedException("label not found: ~S.", Lists.list(tagH));
            }
            mv.visitTryCatchBlock(labelS, labelE, labelH, className);
        }
        //else if (id == Insts.CATCH_FROM ||
        //         id == Insts.CATCH_TO ||
        //         id == Insts.CATCH_HANDLER) {
        //    /* nothing emitted */
        //    continue;
        //}
        else {
            throw new NotReachedException("unknown inst: ~S.", Lists.list(inst));
        }
    }
    mv.visitMaxs(0, 0);
    mv.visitEnd();
}