Example usage for org.objectweb.asm.tree AbstractInsnNode getOpcode

List of usage examples for org.objectweb.asm.tree AbstractInsnNode getOpcode

Introduction

In this page you can find the example usage for org.objectweb.asm.tree AbstractInsnNode getOpcode.

Prototype

public int getOpcode() 

Source Link

Document

Returns the opcode of this instruction.

Usage

From source file:org.spongepowered.despector.ast.io.insn.OpcodeDecompiler.java

License:Open Source License

private void handleIntermediate(AbstractInsnNode next) {
    if (next instanceof JumpInsnNode) {
        if (next.getOpcode() == GOTO) {
            if (!this.stack.isEmpty()) {
                intermediate_stack = true;
                this.intermediates.add(new IntermediateStackValue(this.stack.pop()));
            }/*from  w ww.j  a v a  2  s  .c  om*/
            this.intermediates.add(new IntermediateGoto((JumpInsnNode) next));
        } else if (next.getOpcode() == IF_ACMPEQ || next.getOpcode() == IF_ACMPNE
                || next.getOpcode() == IF_ICMPEQ || next.getOpcode() == IF_ICMPGE
                || next.getOpcode() == IF_ICMPGT || next.getOpcode() == IF_ICMPLE
                || next.getOpcode() == IF_ICMPLT || next.getOpcode() == IF_ICMPNE) {
            Instruction right = this.stack.pop();
            Instruction left = this.stack.pop();
            this.intermediates.add(new IntermediateCompareJump((JumpInsnNode) next, left, right));
        } else {
            Instruction condition = this.stack.pop();
            this.intermediates.add(new IntermediateConditionalJump((JumpInsnNode) next, condition));
        }
    } else if (next instanceof TableSwitchInsnNode) {
        this.intermediates.add(new IntermediateTableSwitch((TableSwitchInsnNode) next, this.stack.pop()));
    } else if (next instanceof LookupSwitchInsnNode) {
        this.intermediates.add(new IntermediateLookupSwitch((LookupSwitchInsnNode) next, this.stack.pop()));
    } else if (next instanceof LineNumberNode) {
    } else if (next instanceof LabelNode) {
        this.intermediates.add(new IntermediateLabel((LabelNode) next));
    } else if (next instanceof FrameNode) {
        if (!this.stack.isEmpty()) {
            this.intermediates.add(this.intermediates.size() - 1, new IntermediateStackValue(this.stack.pop()));
            this.stack.push(new DummyInstruction());
            intermediate_stack = false;
        }
        this.intermediates.add(new IntermediateFrame((FrameNode) next));
    } else {
        if (intermediate_stack && !this.stack.isEmpty() && next.getOpcode() >= IRETURN
                && next.getOpcode() <= ARETURN) {
            this.intermediates.add(this.intermediates.size() - 1, new IntermediateStackValue(this.stack.pop()));
            this.stack.push(new DummyInstruction());
            intermediate_stack = false;
        }
        OpHandler handle = handlers[next.getOpcode()];
        if (handle == null) {
            System.err.println("Unsupported opcode " + next.getOpcode());
            throw new IllegalStateException();
        }
        handle.handle(this, next);
    }
}

From source file:org.spongepowered.granite.launch.transformers.AccessTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {
    if (bytes == null || !this.modifiers.containsKey(transformedName)) {
        return bytes;
    }/*from  w w  w .ja v  a  2 s.c  o m*/

    ClassNode classNode = new ClassNode();
    ClassReader reader = new ClassReader(bytes);
    reader.accept(classNode, 0);

    for (Modifier m : this.modifiers.get(transformedName)) {
        if (m.isClass) { // Class
            classNode.access = m.transform(classNode.access);
        } else if (m.desc == null) { // Field
            for (FieldNode fieldNode : classNode.fields) {
                if (m.wildcard || fieldNode.name.equals(m.name)) {
                    fieldNode.access = m.transform(fieldNode.access);
                    if (!m.wildcard) {
                        break;
                    }
                }
            }
        } else {
            List<MethodNode> overridable = null;

            for (MethodNode methodNode : classNode.methods) {
                if (m.wildcard || (methodNode.name.equals(m.name) && methodNode.desc.equals(m.desc))) {
                    boolean wasPrivate = (methodNode.access & ACC_PRIVATE) != 0;
                    methodNode.access = m.transform(methodNode.access);

                    // Constructors always use INVOKESPECIAL
                    // if we changed from private to something else we need to replace all INVOKESPECIAL calls to this method with INVOKEVIRTUAL
                    // so that overridden methods will be called. Only need to scan this class, because obviously the method was private.
                    if (!methodNode.name.equals("<init>") && wasPrivate
                            && (methodNode.access & ACC_PRIVATE) == 0) {
                        if (overridable == null) {
                            overridable = new ArrayList<>(3);
                        }

                        overridable.add(methodNode);
                    }

                    if (!m.wildcard) {
                        break;
                    }
                }
            }

            if (overridable != null) {
                for (MethodNode methodNode : classNode.methods) {
                    for (Iterator<AbstractInsnNode> itr = methodNode.instructions.iterator(); itr.hasNext();) {
                        AbstractInsnNode insn = itr.next();
                        if (insn.getOpcode() == INVOKESPECIAL) {
                            MethodInsnNode mInsn = (MethodInsnNode) insn;
                            for (MethodNode replace : overridable) {
                                if (replace.name.equals(mInsn.name) && replace.desc.equals(mInsn.desc)) {
                                    mInsn.setOpcode(INVOKEVIRTUAL);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    ClassWriter writer = new ClassWriter(0);
    classNode.accept(writer);
    return writer.toByteArray();
}

From source file:org.spongepowered.lantern.launch.AccessTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {
    if (bytes == null || !this.modifiers.containsKey(transformedName)) {
        return bytes;
    }//from w  ww.j  a v a  2 s  . c  o  m

    ClassNode classNode = new ClassNode();
    ClassReader reader = new ClassReader(bytes);
    reader.accept(classNode, 0);

    for (Modifier m : this.modifiers.get(transformedName)) {
        if (m.isClass) { // Class
            classNode.access = m.transform(classNode.access);
        } else if (m.desc == null) { // Field
            for (FieldNode fieldNode : classNode.fields) {
                if (m.wildcard || fieldNode.name.equals(m.name)) {
                    fieldNode.access = m.transform(fieldNode.access);
                    if (!m.wildcard) {
                        break;
                    }
                }
            }
        } else {
            List<MethodNode> overridable = null;

            for (MethodNode methodNode : classNode.methods) {
                if (m.wildcard || (methodNode.name.equals(m.name) && methodNode.desc.equals(m.desc))) {
                    boolean wasPrivate = (methodNode.access & ACC_PRIVATE) != 0;
                    methodNode.access = m.transform(methodNode.access);

                    // Constructors always use INVOKESPECIAL
                    // if we changed from private to something else we need to replace all INVOKESPECIAL calls to this method with INVOKEVIRTUAL
                    // so that overridden methods will be called. Only need to scan this class, because obviously the method was private.
                    if (!methodNode.name.equals("<init>") && wasPrivate
                            && (methodNode.access & ACC_PRIVATE) == 0) {
                        if (overridable == null) {
                            overridable = Lists.newArrayListWithExpectedSize(3);
                        }

                        overridable.add(methodNode);
                    }

                    if (!m.wildcard) {
                        break;
                    }
                }
            }

            if (overridable != null) {
                for (MethodNode methodNode : classNode.methods) {
                    for (Iterator<AbstractInsnNode> itr = methodNode.instructions.iterator(); itr.hasNext();) {
                        AbstractInsnNode insn = itr.next();
                        if (insn.getOpcode() == INVOKESPECIAL) {
                            MethodInsnNode mInsn = (MethodInsnNode) insn;
                            for (MethodNode replace : overridable) {
                                if (replace.name.equals(mInsn.name) && replace.desc.equals(mInsn.desc)) {
                                    mInsn.setOpcode(INVOKEVIRTUAL);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    ClassWriter writer = new ClassWriter(0);
    classNode.accept(writer);
    return writer.toByteArray();
}

From source file:org.spongepowered.lwts.transformer.AccessTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {
    if (this.modifiers == null) {
        this.modifiers = this.processor.build();
        this.processor = null;
    }//from w  ww. j  av  a  2s . co m

    if (bytes == null || !this.modifiers.containsKey(transformedName)) {
        return bytes;
    }

    ClassNode classNode = new ClassNode();
    ClassReader reader = new ClassReader(bytes);
    reader.accept(classNode, 0);

    for (Modifier m : this.modifiers.get(transformedName)) {
        if (m.isClass) { // Class
            classNode.access = m.transform(classNode.access);
        } else if (m.desc == null) { // Field
            for (FieldNode fieldNode : classNode.fields) {
                if (m.wildcard || fieldNode.name.equals(m.name)) {
                    fieldNode.access = m.transform(fieldNode.access);
                    if (!m.wildcard) {
                        break;
                    }
                }
            }
        } else {
            List<MethodNode> overridable = null;

            for (MethodNode methodNode : classNode.methods) {
                if (m.wildcard || (methodNode.name.equals(m.name) && methodNode.desc.equals(m.desc))) {
                    boolean wasPrivate = (methodNode.access & ACC_PRIVATE) != 0;
                    methodNode.access = m.transform(methodNode.access);

                    // Constructors always use INVOKESPECIAL
                    // if we changed from private to something else we need to replace all INVOKESPECIAL calls to this method with INVOKEVIRTUAL
                    // so that overridden methods will be called. Only need to scan this class, because obviously the method was private.
                    if (!methodNode.name.equals("<init>") && wasPrivate
                            && (methodNode.access & ACC_PRIVATE) == 0) {
                        if (overridable == null) {
                            overridable = Lists.newArrayListWithExpectedSize(3);
                        }

                        overridable.add(methodNode);
                    }

                    if (!m.wildcard) {
                        break;
                    }
                }
            }

            if (overridable != null) {
                for (MethodNode methodNode : classNode.methods) {
                    for (Iterator<AbstractInsnNode> itr = methodNode.instructions.iterator(); itr.hasNext();) {
                        AbstractInsnNode insn = itr.next();
                        if (insn.getOpcode() == INVOKESPECIAL) {
                            MethodInsnNode mInsn = (MethodInsnNode) insn;
                            for (MethodNode replace : overridable) {
                                if (replace.name.equals(mInsn.name) && replace.desc.equals(mInsn.desc)) {
                                    mInsn.setOpcode(INVOKEVIRTUAL);
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    ClassWriter writer = new ClassWriter(0);
    classNode.accept(writer);
    return writer.toByteArray();
}

From source file:org.spongepowered.mod.asm.transformers.BaseEventTransformer.java

License:MIT License

@Override
public byte[] transform(String name, String transformedName, byte[] bytes) {

    if (bytes == null || name == null) {
        return bytes;
    }/*from  w ww  .ja  v  a  2 s .  c o m*/

    try {
        ClassReader cr = new ClassReader(bytes);
        ClassNode classNode = new ClassNode();
        cr.accept(classNode, 0);

        String parentName = classNode.superName.replace('/', '.');

        Class<?> parent = this.getClass().getClassLoader().loadClass(parentName);

        // Skip classes that do not implement SpongeAPI Event, or extend other classes
        // This implies that there will be issues with custom event classes that extend a superclass that does not fit these conditions itself
        // However, this is a fairly fundamental JVM limitation
        if ((!Object.class.equals(parent.getSuperclass())) || (!Event.class.isAssignableFrom(parent))) {
            return bytes;
        }

        // Add forwarding methods
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createGetGameMethod());
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createGetSimpleNameMethod());
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createIsCancellableMethod());
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createIsCancelledMethod());
        ASMHelper.addAndReplaceMethod(classNode, EventTransformer.createSetCancelledMethod());

        // Change super-class
        classNode.superName = "net/minecraftforge/fml/common/eventhandler/Event";

        // Replace super() call in constructor so that it points to the new super-class
        MethodNode method = ASMHelper.findMethod(classNode, "<init>", "()V");

        ListIterator<AbstractInsnNode> instructions = method.instructions.iterator();

        while (instructions.hasNext()) {
            AbstractInsnNode insn = instructions.next();
            if (insn.getOpcode() == Opcodes.INVOKESPECIAL) {
                MethodInsnNode methodInsn = new MethodInsnNode(Opcodes.INVOKESPECIAL, classNode.superName,
                        "<init>", "()V", false);
                instructions.remove();
                instructions.add(methodInsn);
                break;
            }
        }

        ClassWriter cw = new ClassWriter(cr, COMPUTE_MAXS | COMPUTE_FRAMES);
        classNode.accept(cw);
        return cw.toByteArray();
    } catch (Throwable t) {
        t.printStackTrace();
        return bytes;
    }
}

From source file:org.spongepowered.mod.asm.transformers.MixinTransformer.java

License:MIT License

/**
 * Handles appending instructions from the source method to the target method
 * /*  ww w  .jav  a  2s . com*/
 * @param targetClass
 * @param targetMethodName
 * @param sourceMethod
 */
private void appendInsns(ClassNode targetClass, String targetMethodName, MethodNode sourceMethod) {
    if (Type.getReturnType(sourceMethod.desc) != Type.VOID_TYPE) {
        throw new IllegalArgumentException("Attempted to merge insns into a method which does not return void");
    }

    if (targetMethodName == null || targetMethodName.length() == 0) {
        targetMethodName = sourceMethod.name;
    }

    for (MethodNode method : targetClass.methods) {
        if ((targetMethodName.equals(method.name)) && sourceMethod.desc.equals(method.desc)) {
            AbstractInsnNode returnNode = null;
            Iterator<AbstractInsnNode> findReturnIter = method.instructions.iterator();
            while (findReturnIter.hasNext()) {
                AbstractInsnNode insn = findReturnIter.next();
                if (insn.getOpcode() == Opcodes.RETURN) {
                    returnNode = insn;
                    break;
                }
            }

            Iterator<AbstractInsnNode> injectIter = sourceMethod.instructions.iterator();
            while (injectIter.hasNext()) {
                AbstractInsnNode insn = injectIter.next();
                if (!(insn instanceof LineNumberNode) && insn.getOpcode() != Opcodes.RETURN) {
                    method.instructions.insertBefore(returnNode, insn);
                }
            }
        }
    }
}

From source file:org.spoofax.interpreter.adapter.asm.ASMFactory.java

License:LGPL

public static IStrategoTerm wrap(AbstractInsnNode node) {
    if (node == null)
        return None.INSTANCE;
    switch (node.getType()) {
    case AbstractInsnNode.FIELD_INSN:
        return wrap((FieldInsnNode) node);
    case AbstractInsnNode.FRAME:
        return wrap((FrameNode) node);
    case AbstractInsnNode.IINC_INSN:
        return wrap((IincInsnNode) node);
    case AbstractInsnNode.INSN:
        return wrap((InsnNode) node);
    case AbstractInsnNode.INT_INSN:
        return wrap((IntInsnNode) node);
    case AbstractInsnNode.INVOKE_DYNAMIC_INSN:
        throw new NotImplementedException();
    case AbstractInsnNode.JUMP_INSN:
        return wrap((JumpInsnNode) node);
    case AbstractInsnNode.LABEL:
        return wrap((LabelNode) node);
    case AbstractInsnNode.LDC_INSN:
        return wrap((LdcInsnNode) node);
    case AbstractInsnNode.LINE:
        return wrap((LineNumberNode) node);
    case AbstractInsnNode.LOOKUPSWITCH_INSN:
        return wrap((LookupSwitchInsnNode) node);
    case AbstractInsnNode.METHOD_INSN:
        return wrap((MethodInsnNode) node);
    case AbstractInsnNode.MULTIANEWARRAY_INSN:
        return wrap((MultiANewArrayInsnNode) node);
    case AbstractInsnNode.TABLESWITCH_INSN:
        return wrap((TableSwitchInsnNode) node);
    case AbstractInsnNode.TYPE_INSN:
        return wrap((TypeInsnNode) node);
    case AbstractInsnNode.VAR_INSN:
        return wrap((VarInsnNode) node);
    case -1://from  w ww.  j  a  va  2 s  .co  m
        System.err.println("Bogus " + node.getClass().getName());
        return None.INSTANCE;
    default:
        throw new IllegalArgumentException(
                "Unknown type " + node.getOpcode() + " for " + node.getClass().getName());
    }
}

From source file:org.springsource.loaded.TypeDiffComputer.java

License:Apache License

/**
 * Determine if there any differences between the methods supplied. A MethodDelta object is built to record any differences and
 * stored against the type delta./*w w  w.  j av  a  2s.c  om*/
 * 
 * @param oMethod 'old' method
 * @param nMethod 'new' method
 * @param td the type delta where changes are currently being accumulated
 */
private static void computeAnyMethodDifferences(MethodNode oMethod, MethodNode nMethod, TypeDelta td) {
    MethodDelta md = new MethodDelta(oMethod.name, oMethod.desc);
    if (oMethod.access != nMethod.access) {
        md.setAccessChanged(oMethod.access, nMethod.access);
    }
    // TODO annotations
    InsnList oInstructions = oMethod.instructions;
    InsnList nInstructions = nMethod.instructions;
    if (oInstructions.size() != nInstructions.size()) {
        md.setInstructionsChanged(oInstructions.toArray(), nInstructions.toArray());
    } else {
        // TODO Just interested in constructors right now - should add others
        if (oMethod.name.charAt(0) == '<') {
            String oInvokeSpecialDescriptor = null;
            String nInvokeSpecialDescriptor = null;
            int oUninitCount = 0;
            int nUninitCount = 0;
            boolean codeChange = false;
            for (int i = 0, max = oInstructions.size(); i < max; i++) {
                AbstractInsnNode oInstruction = oInstructions.get(i);
                AbstractInsnNode nInstruction = nInstructions.get(i);
                if (!codeChange) {
                    if (!sameInstruction(oInstruction, nInstruction)) {
                        codeChange = true;
                    }

                }
                if (oInstruction.getType() == AbstractInsnNode.TYPE_INSN) {
                    if (oInstruction.getOpcode() == Opcodes.NEW) {
                        oUninitCount++;
                    }
                }
                if (nInstruction.getType() == AbstractInsnNode.TYPE_INSN) {
                    if (nInstruction.getOpcode() == Opcodes.NEW) {
                        nUninitCount++;
                    }
                }
                if (oInstruction.getType() == AbstractInsnNode.METHOD_INSN) {
                    MethodInsnNode mi = (MethodInsnNode) oInstruction;
                    if (mi.getOpcode() == INVOKESPECIAL && mi.name.equals("<init>")) {
                        if (oUninitCount == 0) {
                            // this is the one!
                            oInvokeSpecialDescriptor = mi.desc;
                        } else {
                            oUninitCount--;
                        }
                    }
                }
                if (nInstruction.getType() == AbstractInsnNode.METHOD_INSN) {
                    MethodInsnNode mi = (MethodInsnNode) nInstruction;
                    if (mi.getOpcode() == INVOKESPECIAL && mi.name.equals("<init>")) {
                        if (nUninitCount == 0) {
                            // this is the one!
                            nInvokeSpecialDescriptor = mi.desc;
                        } else {
                            nUninitCount--;
                        }
                    }
                }
            }
            // Has the invokespecial changed?
            if (oInvokeSpecialDescriptor == null) {
                if (nInvokeSpecialDescriptor != null) {
                    md.setInvokespecialChanged(oInvokeSpecialDescriptor, nInvokeSpecialDescriptor);
                }
            } else {
                if (!oInvokeSpecialDescriptor.equals(nInvokeSpecialDescriptor)) {
                    md.setInvokespecialChanged(oInvokeSpecialDescriptor, nInvokeSpecialDescriptor);
                }
            }
            if (codeChange) {
                md.setCodeChanged(oInstructions.toArray(), nInstructions.toArray());
            }
        }
    }
    if (md.hasAnyChanges()) {
        // it needs recording
        td.addChangedMethod(md);
    }

}

From source file:org.springsource.loaded.TypeDiffComputer.java

License:Apache License

private static boolean sameInstruction(AbstractInsnNode o, AbstractInsnNode n) {
    if (o.getType() != o.getType() || o.getOpcode() != n.getOpcode()) {
        return false;
    }/*from w  ww .  j  a v  a 2 s.c o  m*/
    switch (o.getType()) {
    case (AbstractInsnNode.INSN): // 0
        if (!sameInsnNode(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.INT_INSN): // 1
        if (!sameIntInsnNode(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.VAR_INSN): // 2
        if (!sameVarInsn(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.TYPE_INSN):// 3
        if (!sameTypeInsn(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.FIELD_INSN): // 4
        if (!sameFieldInsn(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.METHOD_INSN): // 5
        if (!sameMethodInsnNode(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.JUMP_INSN): // 6
        if (!sameJumpInsnNode(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.LABEL): // 7
        if (!sameLabelNode(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.LDC_INSN): // 8
        if (!sameLdcInsnNode(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.IINC_INSN): // 9
        if (!sameIincInsn(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.TABLESWITCH_INSN): // 10
        if (!sameTableSwitchInsn(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.LOOKUPSWITCH_INSN): // 11
        if (!sameLookupSwitchInsn(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.MULTIANEWARRAY_INSN): // 12
        if (!sameMultiANewArrayInsn(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.FRAME): // 13
        if (!sameFrameInsn(o, n)) {
            return false;
        }
        break;
    case (AbstractInsnNode.LINE): // 14
        if (!sameLineNumberNode(o, n)) {
            return false;
        }
        break;
    default:
        throw new IllegalStateException("nyi " + o.getType());
    }
    return true;
}

From source file:pku.sei.checkedcoverage.tracer.instrumentation.PauseTracingInstrumenter.java

License:Creative Commons License

@SuppressWarnings("unchecked")
public void transformMethod(final MethodNode method, final ListIterator<MethodNode> methodIt,
        final String className) {
    if ((method.access & ACC_ABSTRACT) != 0 || (method.access & ACC_NATIVE) != 0)
        return;//from   www.j a  v  a2s.co  m

    int tracerLocalVarIndex = (method.access & Opcodes.ACC_STATIC) == 0 ? 1 : 0;
    for (final Type t : Type.getArgumentTypes(method.desc))
        tracerLocalVarIndex += t.getSize();

    // increment number of local variables by one (for the threadtracer)
    ++method.maxLocals;

    // and increment all local variable indexes after the new one by one
    for (final Object o : method.localVariables) {
        final LocalVariableNode localVar = (LocalVariableNode) o;
        if (localVar.index >= tracerLocalVarIndex)
            ++localVar.index;
    }
    final LabelNode l0 = new LabelNode();
    final LabelNode l1 = new LabelNode();

    final ListIterator<AbstractInsnNode> insnIt = method.instructions.iterator();

    insnIt.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(Tracer.class), "getInstance",
            "()L" + Type.getInternalName(Tracer.class) + ";"));
    insnIt.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(Tracer.class), "getThreadTracer",
            "()L" + Type.getInternalName(ThreadTracer.class) + ";"));
    insnIt.add(new InsnNode(DUP));
    insnIt.add(new VarInsnNode(ASTORE, tracerLocalVarIndex));
    insnIt.add(new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class), "pauseTracing",
            "()V"));
    insnIt.add(l0);

    while (insnIt.hasNext()) {
        final AbstractInsnNode insn = insnIt.next();
        switch (insn.getType()) {
        case AbstractInsnNode.INSN:
            switch (insn.getOpcode()) {
            case IRETURN:
            case LRETURN:
            case FRETURN:
            case DRETURN:
            case ARETURN:
            case RETURN:
                insnIt.previous();
                insnIt.add(new VarInsnNode(ALOAD, tracerLocalVarIndex));
                insnIt.add(new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class),
                        "resumeTracing", "()V"));
                insnIt.next();
            }
            break;
        case AbstractInsnNode.IINC_INSN:
            if (((IincInsnNode) insn).var >= tracerLocalVarIndex)
                ++((IincInsnNode) insn).var;
            break;
        case AbstractInsnNode.VAR_INSN:
            if (((VarInsnNode) insn).var >= tracerLocalVarIndex)
                ++((VarInsnNode) insn).var;
            break;
        default:
            break;
        }
    }

    method.instructions.add(l1);

    method.instructions.add(new VarInsnNode(ALOAD, tracerLocalVarIndex));
    method.instructions.add(new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class),
            "resumeTracing", "()V"));
    method.instructions.add(new InsnNode(ATHROW));

    method.tryCatchBlocks.add(new TryCatchBlockNode(l0, l1, l1, null));

    // finally: create a copy of the method that gets the ThreadTracer as argument
    if (!"<clinit>".equals(method.name) && this.tracer.wasRedefined(className)) {
        final Type[] oldMethodArguments = Type.getArgumentTypes(method.desc);
        final Type[] newMethodArguments = Arrays.copyOf(oldMethodArguments, oldMethodArguments.length + 1);
        newMethodArguments[oldMethodArguments.length] = Type.getType(ThreadTracer.class);
        final String newMethodDesc = Type.getMethodDescriptor(Type.getReturnType(method.desc),
                newMethodArguments);
        final MethodNode newMethod = new MethodNode(method.access, method.name, newMethodDesc, method.signature,
                (String[]) method.exceptions.toArray(new String[method.exceptions.size()]));
        methodIt.add(newMethod);

        final Map<LabelNode, LabelNode> newMethodLabels = LazyMap.decorate(new HashMap<LabelNode, LabelNode>(),
                new Factory() {
                    public Object create() {
                        return new LabelNode();
                    }
                });

        // copy the local variables information to the new method
        for (final Object o : method.localVariables) {
            final LocalVariableNode lv = (LocalVariableNode) o;
            newMethod.localVariables.add(new LocalVariableNode(lv.name, lv.desc, lv.signature,
                    newMethodLabels.get(lv.start), newMethodLabels.get(lv.end), lv.index));
        }

        newMethod.maxLocals = method.maxLocals;
        newMethod.maxStack = method.maxStack;

        // copy the try-catch-blocks
        for (final Object o : method.tryCatchBlocks) {
            final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
            newMethod.tryCatchBlocks.add(new TryCatchBlockNode(newMethodLabels.get(tcb.start),
                    newMethodLabels.get(tcb.end), newMethodLabels.get(tcb.handler), tcb.type));
        }

        // skip the first 4 instructions, replace them with this:
        newMethod.instructions.add(new VarInsnNode(ALOAD, tracerLocalVarIndex));
        final Iterator<AbstractInsnNode> oldInsnIt = method.instructions.iterator(4);
        // and add all the other instructions
        while (oldInsnIt.hasNext()) {
            final AbstractInsnNode insn = oldInsnIt.next();
            newMethod.instructions.add(insn.clone(newMethodLabels));
        }
    }
}