de.scoopgmbh.copper.instrument.BuildStackInfoAdapter.java Source code

Java tutorial

Introduction

Here is the source code for de.scoopgmbh.copper.instrument.BuildStackInfoAdapter.java

Source

/*
 * Copyright 2002-2013 SCOOP Software GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.scoopgmbh.copper.instrument;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.org.apache.bcel.internal.classfile.ClassFormatException;

import de.scoopgmbh.copper.instrument.StackInfo.ComputationalCategory;

public class BuildStackInfoAdapter extends MethodVisitor implements Opcodes, ByteCodeStackInfo {

    static final Logger logger = LoggerFactory.getLogger(BuildStackInfoAdapter.class);

    static final Type retAddressType = Type.getObjectType("ReturnAddress");

    StackInfo lastDeclaredFrame;
    StackInfo currentFrame;
    StackInfo previousFrame;
    Map<Label, StackInfo> forwardFrames = new HashMap<Label, StackInfo>();
    Map<Label, int[]> lineNumbers = new HashMap<Label, int[]>();
    List<LocalVariable> localVariables = new ArrayList<LocalVariable>();
    MethodVisitor delegate;

    public BuildStackInfoAdapter(String classType, boolean isStatic, String methodName, String arguments,
            String extendedArguments) {
        super(ASM4);
        int i = 0;
        Type[] argumentTypes = Type.getArgumentTypes(arguments);
        currentFrame = new StackInfo();
        if (!isStatic)
            currentFrame.setLocal(i++, Type.getType(classType));
        for (Type t : argumentTypes) {
            currentFrame.setLocal(i++, t);
            if (StackInfo.getCategory(t) == ComputationalCategory.CAT_2)
                i++;
        }
        lastDeclaredFrame = new StackInfo(currentFrame);
        this.delegate = new NullMethodVisitor();
    }

    public void setMethodVisitor(MethodVisitor mVisitor) {
        this.delegate = mVisitor;
    }

    @Override
    public AnnotationVisitor visitAnnotation(String arg0, boolean arg1) {
        return delegate.visitAnnotation(arg0, arg1);
    }

    @Override
    public AnnotationVisitor visitAnnotationDefault() {
        return delegate.visitAnnotationDefault();
    }

    @Override
    public void visitAttribute(Attribute arg0) {
        delegate.visitAttribute(arg0);
    }

    @Override
    public void visitCode() {
        delegate.visitCode();
    }

    @Override
    public void visitEnd() {
        delegate.visitEnd();
    }

    @Override
    public void visitFieldInsn(int arg0, String arg1, String arg2, String arg3) {
        savePreviousFrame();
        Type t = deferTypFromCanonicalName(arg3);
        switch (arg0) {
        case GETSTATIC:
            currentFrame.pushStack(t);
            break;
        case PUTSTATIC:
            currentFrame.popStackUnchecked();
            break;
        case GETFIELD:
            currentFrame.replaceStack(t);
            break;
        case PUTFIELD:
            currentFrame.popStackUnchecked();
            currentFrame.popStackUnchecked();
            break;
        default:
            logger.debug("Unhandled: ");
        }
        if (logger.isDebugEnabled())
            logger.debug("fieldInsn " + getOpCode(arg0) + " '" + arg1 + "' '" + arg2 + "' '" + arg3 + "'");
        delegate.visitFieldInsn(arg0, arg1, arg2, arg3);
    }

    @Override
    public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3, Object[] arg4) {
        savePreviousFrame();
        if (logger.isDebugEnabled())
            logger.debug("stackBefore: " + currentFrame.stack);
        if (logger.isDebugEnabled())
            logger.debug("localBefore: " + currentFrame.localsToString());
        currentFrame = new StackInfo(lastDeclaredFrame);
        switch (arg0) {
        case F_SAME: // representing frame with exactly the same locals as the previous frame and with the empty stack.
            currentFrame.stack.clear();
            break;
        case F_SAME1: //representing frame with exactly the same locals as the previous frame and with single value on the stack (nStack is 1 and stack[0] contains value for the type of the stack item).
            Type t = StackInfo.deferLocalDesc(arg4[0]);
            currentFrame.stack.clear();
            currentFrame.stack.push(t);
            break;
        case F_APPEND: // representing frame with current locals are the same as the locals in the previous frame, except that additional locals are defined (nLocal is 1, 2 or 3 and local elements contains values representing added types).
            currentFrame.appendLocals(arg1, arg2);
            break;
        case F_CHOP: //Opcodes.F_CHOP representing frame with current locals are the same as the locals in the previous frame, except that the last 1-3 locals are absent and with the empty stack (nLocals is 1, 2 or 3).
            currentFrame.removeLocals(arg1);
            currentFrame.stack.clear();
            break;
        case Opcodes.F_FULL: //representing complete frame data.
        case Opcodes.F_NEW:
            currentFrame.clearFrame();
            currentFrame.appendLocals(arg1, arg2);
            currentFrame.appendStack(arg3, arg4);
            break;
        default:
            throw new BuildStackFrameException("Unkwnon frame type " + arg0);

        }
        lastDeclaredFrame = new StackInfo(currentFrame);
        if (logger.isDebugEnabled())
            logger.debug("stack: " + currentFrame.stack);
        if (logger.isDebugEnabled())
            logger.debug("local: " + currentFrame.localsToString());
        if (logger.isDebugEnabled())
            logger.debug("frame " + getFrameType(arg0) + " '" + arg1 + "' '" + Arrays.asList(arg2) + "' '" + arg3
                    + "' '" + Arrays.asList(arg4) + "'");
        delegate.visitFrame(arg0, arg1, arg2, arg3, arg4);
    }

    @Override
    public void visitIincInsn(int arg0, int arg1) {
        savePreviousFrame();
        delegate.visitIincInsn(arg0, arg1);
    }

    @Override
    public void visitInsn(int arg0) {
        savePreviousFrame();
        switch (arg0) {
        case ICONST_0:
        case ICONST_1:
        case ICONST_2:
        case ICONST_3:
        case ICONST_4:
        case ICONST_5:
        case ICONST_M1:
            currentFrame.pushStack(Type.INT_TYPE);
            break;
        case FCONST_0:
        case FCONST_1:
        case FCONST_2:
            currentFrame.pushStack(Type.FLOAT_TYPE);
            break;
        case DCONST_0:
        case DCONST_1:
            currentFrame.pushStack(Type.DOUBLE_TYPE);
            break;
        case LCONST_0:
        case LCONST_1:
            currentFrame.pushStack(Type.LONG_TYPE);
            break;
        case ACONST_NULL:
            currentFrame.pushStack(StackInfo.AconstNullType);
            break;
        //         currentFrame.pushStack(Type.getType(Object.class)); break;
        case DUP:
            currentFrame.dupStack();
            break;
        case DUP_X1:
            currentFrame.dupX1Stack();
            break;
        case DUP_X2:
            currentFrame.dupX2Stack();
            break;
        case DUP2:
            currentFrame.dup2Stack();
            break;
        case DUP2_X1:
            currentFrame.dup2X1Stack();
            break;
        case DUP2_X2:
            currentFrame.dup2X2Stack();
            break;
        case POP:
            currentFrame.popStack();
            break;
        case POP2:
            currentFrame.pop2Stack();
            break;
        case SWAP:
            currentFrame.swapStack();
            break;
        case IADD:
        case IAND:
        case ISUB:
        case IMUL:
        case IDIV:
        case IOR:
        case ISHL:
        case ISHR:
        case IUSHR:
        case IREM:
        case IXOR:
            currentFrame.popStackChecked(Type.INT_TYPE);
        case INEG:
            currentFrame.replaceStackChecked(Type.INT_TYPE, Type.INT_TYPE);
            break;
        case LADD:
        case LAND:
        case LOR:
        case LSUB:
        case LMUL:
        case LDIV:
        case LREM:
        case LXOR:
            currentFrame.popStackChecked(Type.LONG_TYPE);
        case LNEG:
            currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.LONG_TYPE);
            break;
        case LSHL:
        case LSHR:
        case LUSHR:
            currentFrame.popStackChecked(Type.INT_TYPE);
            currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.LONG_TYPE);
            break;
        case DADD:
        case DSUB:
        case DMUL:
        case DDIV:
        case DREM:
            currentFrame.popStackChecked(Type.DOUBLE_TYPE);
        case DNEG:
            currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.DOUBLE_TYPE);
            break;
        case FADD:
        case FSUB:
        case FMUL:
        case FDIV:
        case FREM:
            currentFrame.popStackChecked(Type.FLOAT_TYPE);
        case FNEG:
            currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.FLOAT_TYPE);
            break;
        case FCMPG:
        case FCMPL:
            currentFrame.popStackChecked(Type.FLOAT_TYPE);
            currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.INT_TYPE);
            break;
        case DCMPG:
        case DCMPL:
            currentFrame.popStackChecked(Type.DOUBLE_TYPE);
            currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.INT_TYPE);
            break;
        case F2D:
            currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.DOUBLE_TYPE);
            break;
        case F2I:
            currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.INT_TYPE);
            break;
        case F2L:
            currentFrame.replaceStackChecked(Type.FLOAT_TYPE, Type.LONG_TYPE);
            break;
        case I2B:
            currentFrame.replaceStackChecked(Type.INT_TYPE, Type.BYTE_TYPE);
            break;
        case I2C:
            currentFrame.replaceStackChecked(Type.INT_TYPE, Type.CHAR_TYPE);
            break;
        case I2D:
            currentFrame.replaceStackChecked(Type.INT_TYPE, Type.DOUBLE_TYPE);
            break;
        case I2F:
            currentFrame.replaceStackChecked(Type.INT_TYPE, Type.FLOAT_TYPE);
            break;
        case I2L:
            currentFrame.replaceStackChecked(Type.INT_TYPE, Type.LONG_TYPE);
            break;
        case I2S:
            currentFrame.replaceStackChecked(Type.INT_TYPE, Type.SHORT_TYPE);
            break;
        case L2D:
            currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.DOUBLE_TYPE);
            break;
        case L2F:
            currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.FLOAT_TYPE);
            break;
        case L2I:
            currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.INT_TYPE);
            break;
        case D2F:
            currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.FLOAT_TYPE);
            break;
        case D2I:
            currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.INT_TYPE);
            break;
        case D2L:
            currentFrame.replaceStackChecked(Type.DOUBLE_TYPE, Type.LONG_TYPE);
            break;
        case LCMP:
            currentFrame.popStackChecked(Type.LONG_TYPE);
            currentFrame.replaceStackChecked(Type.LONG_TYPE, Type.INT_TYPE);
            break;
        case ARRAYLENGTH:
            currentFrame.popStack();
            currentFrame.pushStack(Type.INT_TYPE);
            break;
        case RETURN:
        case IRETURN:
        case LRETURN:
        case DRETURN:
        case FRETURN:
        case ARETURN:
            currentFrame.clearFrame();
            break;
        case ATHROW:
            Type t = currentFrame.popStack();
            currentFrame.clearStack();
            currentFrame.pushStack(t);
            break;
        case AALOAD:
            currentFrame.popStackChecked(Type.INT_TYPE);
            Type arrayType = currentFrame.popStack();
            currentFrame.pushStack(arrayType.getElementType());
            break;
        case BALOAD:
            arrayLoad(Type.BYTE_TYPE);
            break;
        case CALOAD:
            arrayLoad(Type.CHAR_TYPE);
            break;
        case DALOAD:
            arrayLoad(Type.DOUBLE_TYPE);
            break;
        case FALOAD:
            arrayLoad(Type.FLOAT_TYPE);
            break;
        case IALOAD:
            arrayLoad(Type.INT_TYPE);
            break;
        case LALOAD:
            arrayLoad(Type.LONG_TYPE);
            break;
        case SALOAD:
            arrayLoad(Type.SHORT_TYPE);
            break;
        case BASTORE:
            arrayStore(Type.BYTE_TYPE);
            break;
        case CASTORE:
            arrayStore(Type.CHAR_TYPE);
            break;
        case DASTORE:
            arrayStore(Type.DOUBLE_TYPE);
            break;
        case FASTORE:
            arrayStore(Type.FLOAT_TYPE);
            break;
        case IASTORE:
            arrayStore(Type.INT_TYPE);
            break;
        case LASTORE:
            arrayStore(Type.LONG_TYPE);
            break;
        case SASTORE:
            arrayStore(Type.SHORT_TYPE);
            break;
        case AASTORE:
            currentFrame.popStack();
            currentFrame.popStackChecked(Type.INT_TYPE);
            currentFrame.popStack();
            break;
        case MONITORENTER:
        case MONITOREXIT:
            currentFrame.popStack();
            break;
        case NOP:
            break;
        default:
            logger.debug("Unhandled: ");
        }
        if (logger.isDebugEnabled())
            logger.debug("insn " + getOpCode(arg0));
        delegate.visitInsn(arg0);
    }

    @Override
    public void visitIntInsn(int arg0, int arg1) {
        savePreviousFrame();
        switch (arg0) {
        case BIPUSH:
            currentFrame.pushStack(Type.BYTE_TYPE);
            break;
        case SIPUSH:
            currentFrame.pushStack(Type.SHORT_TYPE);
            break;
        case NEWARRAY:
            currentFrame.replaceStackChecked(Type.INT_TYPE, getArrayType(arg1));
            break;
        default:
            logger.debug("Unhandled: ");
        }
        if (logger.isDebugEnabled())
            logger.debug("intInsn " + getOpCode(arg0) + " " + arg1);
        delegate.visitIntInsn(arg0, arg1);
    }

    @Override
    public void visitJumpInsn(int arg0, Label arg1) {
        savePreviousFrame();
        switch (arg0) {
        case Opcodes.IF_ACMPEQ:
        case Opcodes.IF_ACMPNE:
        case Opcodes.IF_ICMPEQ:
        case Opcodes.IF_ICMPGE:
        case Opcodes.IF_ICMPGT:
        case Opcodes.IF_ICMPLE:
        case Opcodes.IF_ICMPLT:
        case Opcodes.IF_ICMPNE:
            currentFrame.popStack();
        case Opcodes.IFEQ:
        case Opcodes.IFGE:
        case Opcodes.IFGT:
        case Opcodes.IFLE:
        case Opcodes.IFLT:
        case Opcodes.IFNE:
        case Opcodes.IFNONNULL:
        case Opcodes.IFNULL:
            currentFrame.popStack();
        case Opcodes.GOTO:
            forwardFrames.put(arg1, new StackInfo(currentFrame));
            break;
        case Opcodes.JSR:
            currentFrame.pushStack(retAddressType);
            forwardFrames.put(arg1, new StackInfo(currentFrame));
            break;
        default:
            logger.debug("Unhandled: ");
        }
        if (logger.isDebugEnabled())
            logger.debug("jumpInsn " + getOpCode(arg0) + " " + arg1);
        delegate.visitJumpInsn(arg0, arg1);
    }

    @Override
    public void visitLabel(Label arg0) {
        savePreviousFrame();
        if (logger.isDebugEnabled())
            logger.debug("label " + arg0);
        StackInfo f = forwardFrames.get(arg0);
        if (f != null)
            currentFrame = new StackInfo(f);
        delegate.visitLabel(arg0);
    }

    @Override
    public void visitLdcInsn(Object arg0) {
        savePreviousFrame();
        if (arg0 instanceof Type)
            currentFrame.pushStack((Type) arg0);
        else if (arg0 instanceof String)
            currentFrame.pushStack(Type.getType(String.class));
        else if (arg0 instanceof Float)
            currentFrame.pushStack(Type.FLOAT_TYPE);
        else if (arg0 instanceof Double)
            currentFrame.pushStack(Type.DOUBLE_TYPE);
        else if (arg0 instanceof Integer)
            currentFrame.pushStack(Type.INT_TYPE);
        else if (arg0 instanceof Long)
            currentFrame.pushStack(Type.LONG_TYPE);
        else
            logger.debug("Unhandled: ");
        if (logger.isDebugEnabled())
            logger.debug("ldcInsn " + arg0);
        delegate.visitLdcInsn(arg0);
    }

    @Override
    public void visitLineNumber(int arg0, Label arg1) {
        getLineNumber(arg1)[0] = arg0;
        currentFrame.setLineNo(arg0);
        delegate.visitLineNumber(arg0, arg1);
    }

    @Override
    public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
        localVariables.add(new LocalVariable(name, desc, start, end, index));
        delegate.visitLocalVariable(name, desc, signature, start, end, index);
    }

    @Override
    public void visitLookupSwitchInsn(Label arg0, int[] arg1, Label[] arg2) {
        savePreviousFrame();
        if (logger.isDebugEnabled())
            logger.debug("lookupSwitchInsn " + arg0 + " " + Arrays.toString(arg1) + " " + Arrays.toString(arg2));
        delegate.visitLookupSwitchInsn(arg0, arg1, arg2);
    }

    @Override
    public void visitMaxs(int arg0, int arg1) {
        delegate.visitMaxs(arg0, arg1);
    }

    @Override
    public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) {
        savePreviousFrame();
        Type deferredReturnType = deferReturnType(arg3);
        switch (arg0) {
        case INVOKESTATIC:
            currentFrame.popStackBySignature(arg3);
            if (deferredReturnType != Type.VOID_TYPE)
                currentFrame.pushStack(deferredReturnType);
            break;
        case INVOKESPECIAL:
        case INVOKEINTERFACE:
        case INVOKEVIRTUAL:
            currentFrame.popStackBySignature(arg3);
            currentFrame.popStack();
            if (deferredReturnType != Type.VOID_TYPE)
                currentFrame.pushStack(deferredReturnType);
            break;
        default:
            logger.debug("Unhandled: ");
        }
        if (logger.isDebugEnabled())
            logger.debug("methodInsn " + getOpCode(arg0) + " " + arg1 + " " + arg2 + " " + arg3);
        delegate.visitMethodInsn(arg0, arg1, arg2, arg3);
    }

    @Override
    public void visitMultiANewArrayInsn(String arg0, int arg1) {
        savePreviousFrame();
        for (int i = 0; i < arg1; ++i)
            currentFrame.popStackChecked(Type.INT_TYPE);
        currentFrame.pushStack(Type.getObjectType(arg0));
        if (logger.isDebugEnabled())
            logger.debug("visitMultiANewArrayInsn " + arg0 + " " + arg1);
        delegate.visitMultiANewArrayInsn(arg0, arg1);
    }

    @Override
    public AnnotationVisitor visitParameterAnnotation(int arg0, String arg1, boolean arg2) {
        return delegate.visitParameterAnnotation(arg0, arg1, arg2);
    }

    @Override
    public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, Label... arg3) {
        savePreviousFrame();
        if (logger.isDebugEnabled())
            logger.debug("tableSwitchInsn " + arg0 + " " + arg1 + " " + arg2 + " " + Arrays.asList(arg3));
        delegate.visitTableSwitchInsn(arg0, arg1, arg2, arg3);
    }

    @Override
    public void visitTryCatchBlock(Label arg0, Label arg1, Label arg2, String arg3) {
        if (logger.isDebugEnabled())
            logger.debug("tryCatchBlock " + arg0 + " " + arg1 + " " + arg2 + " " + arg3);
        delegate.visitTryCatchBlock(arg0, arg1, arg2, arg3);
    }

    @Override
    public void visitTypeInsn(int arg0, String arg1) {
        savePreviousFrame();
        Type objectType = Type.getObjectType(arg1);
        switch (arg0) {
        case NEW:
            currentFrame.pushStack(objectType);
            break;
        case CHECKCAST:
            currentFrame.replaceStack(objectType);
            break;
        case ANEWARRAY:
            currentFrame.replaceStack(Type.getObjectType("[" + objectType.getDescriptor()));
            break;
        case INSTANCEOF:
            currentFrame.replaceStack(Type.INT_TYPE);
            break;
        default:
            logger.debug("Unhandled:");
        }
        if (logger.isDebugEnabled())
            logger.debug("typeInsn: " + getOpCode(arg0) + " " + arg1);
        delegate.visitTypeInsn(arg0, arg1);
    }

    @Override
    public void visitVarInsn(int arg0, int arg1) {
        savePreviousFrame();
        switch (arg0) {
        case ALOAD:
            currentFrame.pushStack(currentFrame.getLocal(arg1));
            break;
        case ASTORE:
            currentFrame.setLocal(arg1, currentFrame.popStack());
            break;
        case FLOAD:
            if (!StackInfo.compatible(currentFrame.getLocal(arg1), Type.FLOAT_TYPE))
                throw new BuildStackFrameException("FLOAD expects a float, but got " + currentFrame.getLocal(arg1));
            currentFrame.pushStack(currentFrame.getLocal(arg1));
            break;
        case FSTORE:
            currentFrame.setLocal(arg1, currentFrame.popStack());
            break;
        case ILOAD:
            if (!StackInfo.compatible(currentFrame.getLocal(arg1), Type.INT_TYPE))
                throw new BuildStackFrameException("ILOAD expects an int, but got " + currentFrame.getLocal(arg1));
            currentFrame.pushStack(Type.INT_TYPE);
            break;
        case LLOAD:
            if (!StackInfo.compatible(currentFrame.getLocal(arg1), Type.LONG_TYPE))
                throw new BuildStackFrameException("LLOAD expects a long, but got " + currentFrame.getLocal(arg1));
            currentFrame.pushStack(Type.LONG_TYPE);
            break;
        case DLOAD:
            if (!StackInfo.compatible(currentFrame.getLocal(arg1), Type.DOUBLE_TYPE))
                throw new BuildStackFrameException(
                        "DLOAD expects a double, but got " + currentFrame.getLocal(arg1));
            currentFrame.pushStack(Type.DOUBLE_TYPE);
            break;
        case ISTORE:
            if (!StackInfo.compatible(currentFrame.popStack(), Type.INT_TYPE))
                throw new BuildStackFrameException("ISTORE expects an int, but got " + currentFrame.getLocal(arg1));
            currentFrame.setLocal(arg1, Type.INT_TYPE);
            break;
        case DSTORE:
            if (!StackInfo.compatible(currentFrame.pop2Stack(), Type.DOUBLE_TYPE))
                throw new BuildStackFrameException(
                        "DSTORE expects a double, but got " + currentFrame.getLocal(arg1));
            currentFrame.setLocal(arg1, Type.DOUBLE_TYPE);
            break;
        case LSTORE:
            if (!StackInfo.compatible(currentFrame.pop2Stack(), Type.LONG_TYPE))
                throw new BuildStackFrameException("LSTORE expects a long, but got " + currentFrame.getLocal(arg1));
            currentFrame.setLocal(arg1, Type.LONG_TYPE);
            break;
        default:
            logger.debug("Unhandled:");
        }
        if (logger.isDebugEnabled())
            logger.debug("varInsn: " + getOpCode(arg0) + " " + arg1);
        delegate.visitVarInsn(arg0, arg1);
    }

    public static void main(String[] args) throws Exception {
        File basedir = new File("C:/SVN/POLZUG-Solution-1.0-trucking/projects/gui/target/classes");
        testAllClasses(basedir, basedir);

    }

    private static void testAllClasses(File baseDir, File dir)
            throws FileNotFoundException, IOException, ClassNotFoundException {
        File[] files = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return name.endsWith(".class");
            }
        });
        for (File f : files) {
            testClass(f, f.getAbsolutePath().substring(baseDir.getAbsolutePath().length() + 1).replace(".class", "")
                    .replace("\\", "."));
        }
        files = dir.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {

                return pathname.isDirectory();
            }
        });
        for (File f : files) {
            testAllClasses(baseDir, f);
        }
    }

    private static void testClass(File file, final String className) throws IOException, FileNotFoundException {
        ClassReader cr = new ClassReader(new FileInputStream(file));
        ClassWriter cw = new ClassWriter(0);
        final String cDesc = Type.getObjectType(className).getDescriptor();
        ClassVisitor cv = new ClassVisitor(ASM4, cw) {

            @Override
            public MethodVisitor visitMethod(int access, String name, String desc, String signature,
                    String[] exceptions) {
                if (logger.isDebugEnabled())
                    logger.debug("=======>" + access + " " + name + " " + desc + " " + signature);
                return new BuildStackInfoAdapter(cDesc, (access & Opcodes.ACC_STATIC) > 0, name, desc, signature);
            }

            @Override
            public void visitInnerClass(String arg0, String arg1, String arg2, int arg3) {
                if (logger.isDebugEnabled())
                    logger.debug("== VISIT INNER =======>" + arg0 + " " + arg1 + " " + arg2 + " " + arg3);
                super.visitInnerClass(arg0, arg1, arg2, arg3);
            }

        };
        cr.accept(cv, 0);
    }

    String getOpCode(int opCode) {
        for (Field f : Opcodes.class.getDeclaredFields()) {
            try {
                if (f.getName().startsWith("F_") || f.getName().startsWith("T_") || f.getName().startsWith("ACC_")
                        || f.getName().startsWith("V1_"))
                    continue;
                if (f.getInt(null) == opCode) {
                    return f.getName();
                }
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return "No Opcode for " + opCode;
    }

    String getFrameType(int frameType) {
        for (Field f : Opcodes.class.getDeclaredFields()) {
            try {
                if (!f.getName().startsWith("F_"))
                    continue;
                if (f.getInt(null) == frameType) {
                    return f.getName();
                }
            } catch (IllegalArgumentException e) {
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return "No frame type for " + frameType;
    }

    Type getArrayElementType(int type) {
        switch (type) {
        case T_BOOLEAN:
            return Type.BOOLEAN_TYPE;
        case T_BYTE:
            return Type.BYTE_TYPE;
        case T_CHAR:
            return Type.CHAR_TYPE;
        case T_DOUBLE:
            return Type.DOUBLE_TYPE;
        case T_FLOAT:
            return Type.FLOAT_TYPE;
        case T_INT:
            return Type.INT_TYPE;
        case T_LONG:
            return Type.LONG_TYPE;
        case T_SHORT:
            return Type.SHORT_TYPE;
        }
        throw new BuildStackFrameException("Illegal array type code: " + type);
    }

    Type getArrayType(int type) {
        Type t = getArrayElementType(type);
        return Type.getObjectType("[" + t.getDescriptor());
    }

    String getStackInfo(Object[] args) {
        StringBuilder sb = new StringBuilder("[");
        for (Object arg : args) {
            if (arg == null)
                sb.append("null");
            else {
                try {
                    sb.append(deferTypFromCanonicalName(arg.toString()));
                } catch (ClassFormatException ex) {
                    sb.append(arg.toString());
                }
            }
            sb.append(", ");
        }
        if (sb.length() > 1)
            sb.setLength(sb.length() - 2);
        sb.append(']');
        return sb.toString();

    }

    static Type deferTypFromCanonicalName(String name) {
        return Type.getType(name);
    }

    static Type deferReturnType(String signature) {
        return Type.getReturnType(signature);
    }

    void savePreviousFrame() {
        previousFrame = new StackInfo(currentFrame);
    }

    void arrayLoad(Type arrayType) {
        currentFrame.popStackChecked(Type.INT_TYPE);
        currentFrame.replaceStack(arrayType);
    }

    void arrayStore(Type arrayType) {
        currentFrame.popStackChecked(arrayType);
        currentFrame.popStackChecked(Type.INT_TYPE);
        currentFrame.popStack();
    }

    @Override
    public StackInfo getPreviousStackInfo() {
        return new StackInfo(previousFrame);
    }

    @Override
    public StackInfo getCurrentStackInfo() {
        return new StackInfo(currentFrame);
    }

    private int[] getLineNumber(Label l) {
        int[] lineNo = lineNumbers.get(l);
        if (lineNo == null) {
            lineNumbers.put(l, lineNo = new int[] { -1 });
        }
        return lineNo;
    }

    @Override
    public String[] getLocalNames(int lineNo, int count) {
        String[] names = new String[count];
        outerLoop: for (int index = 0; index < count; ++index) {
            names[index] = "var" + index;
            for (LocalVariable var : localVariables) {
                if (var.index == index && var.fromLine[0] <= lineNo && var.toLine[0] >= lineNo) {
                    names[index] = var.name;
                    continue outerLoop;
                }
            }
        }
        return names;
    }

    @Override
    public Type[] getLocalDescriptors(int lineNo, int count) {
        Type[] types = new Type[count];
        outerLoop: for (int index = 0; index < count; ++index) {
            for (LocalVariable var : localVariables) {
                if (var.index == index && var.fromLine[0] <= lineNo && var.toLine[0] >= lineNo) {
                    types[index] = Type.getType(var.declaredDescriptor);
                    continue outerLoop;
                }
            }
        }
        return types;
    }

    public class LocalVariable {

        public LocalVariable(String name, String declaredDescriptor, Label from, Label to, int index) {
            this.name = name;
            this.fromLine = getLineNumber(from);
            this.toLine = getLineNumber(to);
            if (this.toLine[0] == -1)
                this.toLine[0] = Integer.MAX_VALUE;
            this.index = index;
            this.declaredDescriptor = declaredDescriptor;
        }

        String name;
        int[] fromLine;
        int[] toLine;
        int index;
        String declaredDescriptor;

    }

}