Example usage for org.objectweb.asm.tree LineNumberNode LineNumberNode

List of usage examples for org.objectweb.asm.tree LineNumberNode LineNumberNode

Introduction

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

Prototype

public LineNumberNode(final int line, final LabelNode start) 

Source Link

Document

Constructs a new LineNumberNode .

Usage

From source file:com.android.build.gradle.internal.incremental.IncrementalSupportVisitor.java

License:Apache License

/**
 * Insert Constructor specific logic({@link ConstructorRedirection} and
 * {@link ConstructorBuilder}) for constructor redirecting or
 * normal method redirecting ({@link MethodRedirection}) for other methods.
 *//*from ww w. j  av  a2 s  .  com*/
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

    access = transformAccessForInstantRun(access);

    MethodVisitor defaultVisitor = super.visitMethod(access, name, desc, signature, exceptions);
    MethodNode method = checkNotNull(getMethodByNameInClass(name, desc, classNode),
            "Method found by visitor but not in the pre-parsed class node.");

    // does the method use blacklisted APIs.
    boolean hasIncompatibleChange = InstantRunMethodVerifier
            .verifyMethod(method) != InstantRunVerifierStatus.COMPATIBLE;

    if (hasIncompatibleChange || disableRedirectionForClass || !isAccessCompatibleWithInstantRun(access)
            || name.equals(ByteCodeUtils.CLASS_INITIALIZER)) {
        return defaultVisitor;
    } else {
        ArrayList<Type> args = new ArrayList<>(Arrays.asList(Type.getArgumentTypes(desc)));
        boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
        if (!isStatic) {
            args.add(0, Type.getType(Object.class));
        }

        // Install the Jsr/Ret inliner adapter, we have had reports of code still using the
        // Jsr/Ret deprecated byte codes.
        // see https://code.google.com/p/android/issues/detail?id=220019
        JSRInlinerAdapter jsrInlinerAdapter = new JSRInlinerAdapter(defaultVisitor, access, name, desc,
                signature, exceptions);

        ISMethodVisitor mv = new ISMethodVisitor(jsrInlinerAdapter, access, name, desc);
        if (name.equals(ByteCodeUtils.CONSTRUCTOR)) {
            Constructor constructor = ConstructorBuilder.build(visitedClassName, method);
            LabelNode start = new LabelNode();
            method.instructions.insert(constructor.loadThis, start);
            if (constructor.lineForLoad != -1) {
                // Record the line number from the start of LOAD_0 for uninitialized 'this'.
                // This allows a breakpoint to be set at the line with this(...) or super(...)
                // call in the constructor.
                method.instructions.insert(constructor.loadThis,
                        new LineNumberNode(constructor.lineForLoad, start));
            }
            mv.addRedirection(new ConstructorRedirection(start, constructor, args));
        } else {
            mv.addRedirection(new MethodRedirection(new LabelNode(mv.getStartLabel()), name + "." + desc, args,
                    Type.getReturnType(desc)));
        }
        method.accept(mv);
        return null;
    }
}

From source file:com.android.build.gradle.internal2.incremental.IncrementalSupportVisitor.java

License:Apache License

/**
 * Insert Constructor specific logic({@link ConstructorRedirection} and
 * {@link ConstructorBuilder}) for constructor redirecting or
 * normal method redirecting ({@link MethodRedirection}) for other methods.
 *//*from   w w w  .  ja va 2  s  . c o  m*/
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {

    access = transformAccessForInstantRun(access);

    MethodVisitor defaultVisitor = super.visitMethod(access, name, desc, signature, exceptions);
    MethodNode method = getMethodByNameInClass(name, desc, classNode);
    // does the method use blacklisted APIs.
    boolean hasIncompatibleChange = InstantRunMethodVerifier
            .verifyMethod(method) != InstantRunVerifierStatus.COMPATIBLE;

    if (hasIncompatibleChange || disableRedirectionForClass || !isAccessCompatibleWithInstantRun(access)
            || name.equals(ByteCodeUtils.CLASS_INITIALIZER)) {
        return defaultVisitor;
    } else {
        ArrayList<Type> args = new ArrayList<Type>(Arrays.asList(Type.getArgumentTypes(desc)));
        boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
        if (!isStatic) {
            args.add(0, Type.getType(Object.class));
        }

        ISMethodVisitor mv = new ISMethodVisitor(defaultVisitor, access, name, desc);
        if (name.equals(ByteCodeUtils.CONSTRUCTOR)) {
            Constructor constructor = ConstructorBuilder.build(visitedClassName, method);
            LabelNode start = new LabelNode();
            method.instructions.insert(constructor.loadThis, start);
            if (constructor.lineForLoad != -1) {
                // Record the line number from the start of LOAD_0 for uninitialized 'this'.
                // This allows a breakpoint to be set at the line with this(...) or super(...)
                // call in the constructor.
                method.instructions.insert(constructor.loadThis,
                        new LineNumberNode(constructor.lineForLoad, start));
            }
            mv.addRedirection(new ConstructorRedirection(start, constructor, args));
        } else {
            mv.addRedirection(new MethodRedirection(new LabelNode(mv.getStartLabel()), name + "." + desc, args,
                    Type.getReturnType(desc)));
        }
        method.accept(mv);
        return null;
    }
}

From source file:com.github.fge.grappa.transform.CodeBlock.java

License:Apache License

public CodeBlock visitLineNumber(int lineNumber, LabelNode start) {
    instructionList.add(new LineNumberNode(lineNumber, start));
    return this;
}

From source file:com.offbynull.coroutines.instrumenter.asm.InstructionUtils.java

License:Open Source License

/**
 * Generates instructions for line numbers. This is useful for debugging. For example, you can put a line number of 99999 or some other
 * special number to denote that the code being executed is instrumented code. Then if a stacktrace happens, you'll know that if
 * instrumented code was immediately involved.
 * @param num line number//from  ww  w  . j  a  va 2  s .c om
 * @return instructions for a line number
 * @throws IllegalArgumentException if {@code num < 0}
 */
public static InsnList lineNumber(int num) {
    Validate.isTrue(num >= 0);

    InsnList ret = new InsnList();

    LabelNode labelNode = new LabelNode();
    ret.add(labelNode);
    ret.add(new LineNumberNode(num, labelNode));

    return ret;
}

From source file:de.sanandrew.core.manpack.transformer.TransformEntityCollision.java

License:Creative Commons License

private static byte[] transformWorld(byte[] bytes) {
    ClassNode clazz = ASMHelper.createClassNode(bytes);
    MethodNode method = ASMHelper.findMethod(clazz, ASMNames.MD_WORLD_GET_COLLIDING_BB);

    InsnList needle = new InsnList();
    LabelNode ln = new LabelNode();
    needle.add(ln);//from w w w.  jav  a 2  s . c o  m
    needle.add(new LineNumberNode(-1, ln));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 0));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 1));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 2));
    needle.add(new VarInsnNode(Opcodes.DLOAD, -1));
    needle.add(new VarInsnNode(Opcodes.DLOAD, -1));
    needle.add(new VarInsnNode(Opcodes.DLOAD, -1));
    needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_AABB_EXPAND, false));
    needle.add(
            ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_WORLD_GET_ENTITIES_EXCLUDE, false));
    needle.add(new VarInsnNode(Opcodes.ASTORE, -1));

    VarInsnNode insertPoint = (VarInsnNode) ASMHelper.findLastNodeFromNeedle(method.instructions, needle);

    InsnList injectList = new InsnList();
    injectList.add(new LabelNode());
    injectList.add(ASMHelper.getFieldInsnNode(Opcodes.GETSTATIC, ASMNames.FD_SAPUTILS_EVENT_BUS));
    injectList.add(new TypeInsnNode(Opcodes.NEW, ASMNames.CL_COLLIDING_ENTITY_CHECK_EVENT));
    injectList.add(new InsnNode(Opcodes.DUP));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 0));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, insertPoint.var));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 1));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 2));
    injectList.add(
            ASMHelper.getMethodInsnNode(Opcodes.INVOKESPECIAL, ASMNames.MD_SAP_COLLENTITYCHKEVT_INIT, false));
    injectList.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_EVENT_BUS_POST, false));
    injectList.add(new InsnNode(Opcodes.POP));

    method.instructions.insert(insertPoint, injectList);

    // insert entity-sensitive bounding box method

    needle = new InsnList();
    ln = new LabelNode();
    needle.add(ln);
    needle.add(new LineNumberNode(-1, ln));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 11));
    needle.add(new VarInsnNode(Opcodes.ILOAD, 12));
    needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEINTERFACE, ASMNames.MD_LIST_GET, true));
    needle.add(new TypeInsnNode(Opcodes.CHECKCAST, ASMNames.CL_ENTITY));
    needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_ENTITY_GET_BOUNDING_BOX, false));
    needle.add(new VarInsnNode(Opcodes.ASTORE, -1));

    insertPoint = (VarInsnNode) ASMHelper.findLastNodeFromNeedle(method.instructions, needle);

    injectList = new InsnList();
    injectList.add(new LabelNode());
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 11));
    injectList.add(new VarInsnNode(Opcodes.ILOAD, 12));
    injectList.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEINTERFACE, ASMNames.MD_LIST_GET, true));
    injectList.add(new TypeInsnNode(Opcodes.CHECKCAST, ASMNames.CL_ENTITY));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 1));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, insertPoint.var));
    injectList.add(
            ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_SAP_ENTITY_GET_BOUNDING_BOX, false));
    injectList.add(new VarInsnNode(Opcodes.ASTORE, insertPoint.var));

    method.instructions.insert(insertPoint, injectList);

    bytes = ASMHelper.createBytes(clazz, /*ClassWriter.COMPUTE_FRAMES |*/ ClassWriter.COMPUTE_MAXS);

    return bytes;
}

From source file:de.sanandrew.core.manpack.transformer.TransformEntityThrowable.java

License:Creative Commons License

private static byte[] transformLqThrowable(byte[] bytes) {
    ClassNode classNode = ASMHelper.createClassNode(bytes);

    MethodNode method = ASMHelper.getMethodNode(Opcodes.ACC_PUBLIC, ASMNames.MD_SAP_CAN_IMPACT_ON_LIQUID);

    method.visitCode();//from  w  ww. ja  v a 2 s . c  om
    Label label1 = new Label();
    method.visitLabel(label1);
    method.visitInsn(Opcodes.ICONST_0);
    method.visitInsn(Opcodes.IRETURN);
    Label label2 = new Label();
    method.visitLabel(label2);
    method.visitLocalVariable("this", ASMNames.CL_T_ENTITY_THROWABLE, null, label1, label2, 0);
    method.visitMaxs(0, 0);
    method.visitEnd();
    classNode.methods.add(method);

    method = ASMHelper.findMethod(classNode, ASMNames.MD_THROWABLE_ON_UPDATE);

    InsnList needle = new InsnList();
    needle.add(ASMHelper.getFieldInsnNode(Opcodes.GETFIELD, ASMNames.FD_THROWABLE_MOTION_Z));
    needle.add(new InsnNode(Opcodes.DADD));
    needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKESTATIC, ASMNames.MD_VEC3_CREATE_VECTOR_HELPER, false));
    needle.add(new VarInsnNode(Opcodes.ASTORE, 2));
    needle.add(new LabelNode());
    needle.add(new LineNumberNode(-1, new LabelNode()));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 0));
    needle.add(ASMHelper.getFieldInsnNode(Opcodes.GETFIELD, ASMNames.FD_THROWABLE_WORLD_OBJ));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 1));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 2));
    needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_WORLD_RAY_TRACE_BLOCKS, false));
    needle.add(new VarInsnNode(Opcodes.ASTORE, -1));

    VarInsnNode insertPoint = (VarInsnNode) ASMHelper.findLastNodeFromNeedle(method.instructions, needle);

    InsnList injectList = new InsnList();
    injectList.add(new LabelNode());
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 0));
    injectList.add(ASMHelper.getFieldInsnNode(Opcodes.GETFIELD, ASMNames.FD_THROWABLE_WORLD_OBJ));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 1));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 2));
    injectList.add(new VarInsnNode(Opcodes.ALOAD, 0));
    injectList.add(
            ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_SAP_CAN_IMPACT_ON_LIQUID, false));
    injectList.add(
            ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_WORLD_RAY_TRACE_BLOCKS_Z, false));
    injectList.add(new VarInsnNode(Opcodes.ASTORE, insertPoint.var));

    method.instructions.insert(insertPoint, injectList);

    return ASMHelper.createBytes(classNode, /*ClassWriter.COMPUTE_FRAMES |*/ ClassWriter.COMPUTE_MAXS);
}

From source file:de.sanandrew.core.manpack.transformer.TransformHorseArmor.java

License:Creative Commons License

private static void transformGetTotalArmorValue(MethodNode method) {
    InsnList needle = new InsnList();
    needle.add(new LabelNode());
    needle.add(new LineNumberNode(-1, new LabelNode()));
    needle.add(ASMHelper.getFieldInsnNode(Opcodes.GETSTATIC, ASMNames.FD_HORSE_ARMOR_VALUES));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 0));
    needle.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_HORSE_FUNC110241CB, false));

    AbstractInsnNode pointer = ASMHelper.findFirstNodeFromNeedle(method.instructions, needle);

    InsnList newInstr = new InsnList();

    newInstr.add(new LabelNode());
    newInstr.add(new VarInsnNode(Opcodes.ALOAD, 0));
    newInstr.add(//  w ww.j  a v  a  2s  . co m
            ASMHelper.getMethodInsnNode(Opcodes.INVOKESPECIAL, ASMNames.MD_SAP_GET_CUSTOM_ARMOR_ITEM, false));
    newInstr.add(new VarInsnNode(Opcodes.ASTORE, 1));
    newInstr.add(new LabelNode());
    newInstr.add(new VarInsnNode(Opcodes.ALOAD, 1));
    newInstr.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_ITEMSTACK_GET_ITEM, false));
    newInstr.add(new TypeInsnNode(Opcodes.INSTANCEOF, ASMNames.CL_ITEM_HORSE_ARMOR));
    LabelNode l2 = new LabelNode();
    newInstr.add(new JumpInsnNode(Opcodes.IFEQ, l2));
    newInstr.add(new LabelNode());
    newInstr.add(new VarInsnNode(Opcodes.ALOAD, 1));
    newInstr.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_ITEMSTACK_GET_ITEM, false));
    newInstr.add(new TypeInsnNode(Opcodes.CHECKCAST, ASMNames.CL_ITEM_HORSE_ARMOR));
    newInstr.add(new VarInsnNode(Opcodes.ALOAD, 0));
    newInstr.add(new VarInsnNode(Opcodes.ALOAD, 1));
    newInstr.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_SAP_GET_ARMOR_VALUE, false));
    newInstr.add(new InsnNode(Opcodes.IRETURN));
    newInstr.add(l2);

    method.instructions.insertBefore(pointer, newInstr);
}

From source file:de.sanandrew.core.manpack.transformer.TransformHorseArmor.java

License:Creative Commons License

private static void transformIsValidArmor(MethodNode method) {
    InsnList needle = new InsnList();
    needle.add(new LabelNode());
    needle.add(new LineNumberNode(-1, new LabelNode()));
    needle.add(new VarInsnNode(Opcodes.ALOAD, 0));
    needle.add(ASMHelper.getFieldInsnNode(Opcodes.GETSTATIC, ASMNames.FD_ITEMS_IRON_HORSE_ARMOR));
    needle.add(new JumpInsnNode(Opcodes.IF_ACMPEQ, new LabelNode()));

    AbstractInsnNode node = ASMHelper.findFirstNodeFromNeedle(method.instructions, needle);

    InsnList newInstr = new InsnList();
    newInstr.add(new LabelNode());
    newInstr.add(new VarInsnNode(Opcodes.ALOAD, 0));
    newInstr.add(new TypeInsnNode(Opcodes.INSTANCEOF, ASMNames.CL_ITEM_HORSE_ARMOR));
    LabelNode ln = new LabelNode();
    newInstr.add(new JumpInsnNode(Opcodes.IFEQ, ln));
    newInstr.add(new LabelNode());
    newInstr.add(new InsnNode(Opcodes.ICONST_1));
    newInstr.add(new InsnNode(Opcodes.IRETURN));
    newInstr.add(ln);/*from  w  w  w  .  j a  va 2  s  . com*/

    method.instructions.insertBefore(node, newInstr);
}

From source file:de.sanandrew.core.manpack.transformer.TransformHorseArmor.java

License:Creative Commons License

private static void transformInteract(MethodNode method) {

    InsnList needle = new InsnList();
    needle.add(ASMHelper.getFieldInsnNode(Opcodes.GETSTATIC, ASMNames.FD_ITEMS_DIAMOND_HORSE_ARMOR));
    needle.add(new JumpInsnNode(Opcodes.IF_ACMPNE, new LabelNode()));
    needle.add(new LabelNode());
    needle.add(new LineNumberNode(-1, new LabelNode()));
    needle.add(new InsnNode(Opcodes.ICONST_3));
    needle.add(new VarInsnNode(Opcodes.ISTORE, 4));
    needle.add(new LabelNode());
    needle.add(new LineNumberNode(-1, new LabelNode()));
    needle.add(new FrameNode(Opcodes.F_SAME, 0, null, 0, null));

    AbstractInsnNode node = ASMHelper.findLastNodeFromNeedle(method.instructions, needle);

    InsnList newInstr = new InsnList();
    newInstr.add(new LabelNode());
    newInstr.add(new VarInsnNode(Opcodes.ALOAD, 2));
    newInstr.add(ASMHelper.getMethodInsnNode(Opcodes.INVOKEVIRTUAL, ASMNames.MD_ITEMSTACK_GET_ITEM, false));
    newInstr.add(new TypeInsnNode(Opcodes.INSTANCEOF, ASMNames.CL_ITEM_HORSE_ARMOR));
    LabelNode l8 = new LabelNode();
    newInstr.add(new JumpInsnNode(Opcodes.IFEQ, l8));
    newInstr.add(new LabelNode());
    newInstr.add(new InsnNode(Opcodes.ICONST_4));
    newInstr.add(new VarInsnNode(Opcodes.ISTORE, 4));
    newInstr.add(l8);/*from  w ww.  ja  v  a 2  s .  com*/
    newInstr.add(new FrameNode(Opcodes.F_SAME, 0, null, 0, null));

    method.instructions.insert(node, newInstr);
}

From source file:de.unisb.cs.st.javaslicer.tracer.instrumentation.TracingMethodInstrumenter.java

License:Open Source License

@SuppressWarnings("unchecked")
public void transform(final ListIterator<MethodNode> methodIt) {

    // do not modify abstract or native methods
    if ((this.methodNode.access & ACC_ABSTRACT) != 0 || (this.methodNode.access & ACC_NATIVE) != 0)
        return;/*from  w ww. ja v  a 2s.co  m*/

    // check out what labels are jump targets (only these have to be traced)
    analyze(this.methodNode);

    this.instructionIterator = new FixedInstructionIterator(this.methodNode.instructions);
    // in the old method, initialize the new local variable for the threadtracer
    this.instructionIterator.add(new MethodInsnNode(INVOKESTATIC, Type.getInternalName(Tracer.class),
            "getInstance", "()L" + Type.getInternalName(Tracer.class) + ";", false));
    this.instructionIterator.add(new MethodInsnNode(INVOKEVIRTUAL, Type.getInternalName(Tracer.class),
            "getThreadTracer", "()L" + Type.getInternalName(ThreadTracer.class) + ";", false));
    this.instructionIterator.add(new InsnNode(DUP));
    this.instructionIterator.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));

    this.instructionIterator.add(new MethodInsnNode(INVOKEINTERFACE, Type.getInternalName(ThreadTracer.class),
            "isPaused", "()Z", true));
    final LabelNode noTracingLabel = new LabelNode();
    this.instructionIterator.add(new JumpInsnNode(IFNE, noTracingLabel));
    // create a copy of the (uninstrumented) instructions (later, while iterating through the instructions)
    final InsnList oldInstructions = new InsnList();
    final Map<LabelNode, LabelNode> labelCopies = new LazyLabelMap();
    // copy the try-catch-blocks
    final Object[] oldTryCatchblockNodes = this.methodNode.tryCatchBlocks.toArray();
    for (final Object o : oldTryCatchblockNodes) {
        final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        final TryCatchBlockNode newTcb = new TryCatchBlockNode(labelCopies.get(tcb.start),
                labelCopies.get(tcb.end), labelCopies.get(tcb.handler), tcb.type);
        this.methodNode.tryCatchBlocks.add(newTcb);
    }

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

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

    // store information about local variables in the ReadMethod object
    List<LocalVariable> localVariables = new ArrayList<LocalVariable>();
    for (final Object o : this.methodNode.localVariables) {
        final LocalVariableNode localVar = (LocalVariableNode) o;
        while (localVariables.size() <= localVar.index)
            localVariables.add(null);
        localVariables.set(localVar.index, new LocalVariable(localVar.index, localVar.name, localVar.desc));
    }
    this.readMethod.setLocalVariables(localVariables.toArray(new LocalVariable[localVariables.size()]));
    localVariables = null;

    // each method must start with a (dedicated) label:
    assert this.readMethod.getInstructions().isEmpty();
    traceLabel(null, InstructionType.METHODENTRY);
    assert this.readMethod.getInstructions().size() == 1
            && this.readMethod.getInstructions().get(0) instanceof LabelMarker
            && ((LabelMarker) this.readMethod.getInstructions().get(0)).isAdditionalLabel();
    this.readMethod.setMethodEntryLabel((LabelMarker) this.readMethod.getInstructions().get(0));

    // needed later:
    final LabelNode l0 = new LabelNode();
    this.instructionIterator.add(l0);

    // then, visit the instructions that were in the method before
    while (this.instructionIterator.hasNext()) {

        final AbstractInsnNode insnNode = this.instructionIterator.next();
        switch (insnNode.getType()) {
        case AbstractInsnNode.INSN:
            transformInsn((InsnNode) insnNode);
            break;
        case AbstractInsnNode.INT_INSN:
            transformIntInsn((IntInsnNode) insnNode);
            break;
        case AbstractInsnNode.VAR_INSN:
            transformVarInsn((VarInsnNode) insnNode);
            break;
        case AbstractInsnNode.TYPE_INSN:
            transformTypeInsn((TypeInsnNode) insnNode);
            break;
        case AbstractInsnNode.FIELD_INSN:
            transformFieldInsn((FieldInsnNode) insnNode);
            break;
        case AbstractInsnNode.METHOD_INSN:
            transformMethodInsn((MethodInsnNode) insnNode);
            break;
        case AbstractInsnNode.JUMP_INSN:
            transformJumpInsn((JumpInsnNode) insnNode);
            break;
        case AbstractInsnNode.LABEL:
            transformLabel((LabelNode) insnNode);
            break;
        case AbstractInsnNode.LDC_INSN:
            transformLdcInsn((LdcInsnNode) insnNode);
            break;
        case AbstractInsnNode.IINC_INSN:
            transformIincInsn((IincInsnNode) insnNode);
            break;
        case AbstractInsnNode.TABLESWITCH_INSN:
            transformTableSwitchInsn((TableSwitchInsnNode) insnNode);
            break;
        case AbstractInsnNode.LOOKUPSWITCH_INSN:
            transformLookupSwitchInsn((LookupSwitchInsnNode) insnNode);
            break;
        case AbstractInsnNode.MULTIANEWARRAY_INSN:
            transformMultiANewArrayInsn((MultiANewArrayInsnNode) insnNode);
            break;
        case AbstractInsnNode.FRAME:
            // ignore
            break;
        case AbstractInsnNode.LINE:
            // ignore
            break;
        default:
            throw new RuntimeException("Unknown instruction type " + insnNode.getType() + " ("
                    + insnNode.getClass().getSimpleName() + ")");
        }
        oldInstructions.add(insnNode.clone(labelCopies));
    }

    assert this.outstandingInitializations == 0;

    // add the (old) try-catch blocks to the readMethods
    // (can only be done down here since we use the information in the
    // labels map)
    for (final Object o : oldTryCatchblockNodes) {
        final TryCatchBlockNode tcb = (TryCatchBlockNode) o;
        this.readMethod.addTryCatchBlock(new TryCatchBlock(this.labels.get(tcb.start), this.labels.get(tcb.end),
                this.labels.get(tcb.handler), tcb.type));
    }

    final LabelNode l1 = new LabelNode();
    this.instructionIterator.add(l1);
    final int newPos = this.readMethod.getInstructions().size();
    traceLabel(null, InstructionType.METHODEXIT);
    assert this.readMethod.getInstructions().size() == newPos + 1;
    final AbstractInstruction abnormalTerminationLabel = this.readMethod.getInstructions().get(newPos);
    assert abnormalTerminationLabel instanceof LabelMarker;
    this.readMethod.setAbnormalTerminationLabel((LabelMarker) abnormalTerminationLabel);
    this.methodNode.instructions.add(new InsnNode(ATHROW));

    // add a try catch block around the method so that we can trace when this method is left
    // by a thrown exception
    this.methodNode.tryCatchBlocks.add(new TryCatchBlockNode(l0, l1, l1, null));

    // now add the code that is executed if no tracing should be performed
    this.methodNode.instructions.add(noTracingLabel);
    if (this.firstLine != -1)
        this.methodNode.instructions.add(new LineNumberNode(this.firstLine, noTracingLabel));
    this.methodNode.instructions.add(new InsnNode(ACONST_NULL));
    this.methodNode.instructions.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));
    this.methodNode.instructions.add(oldInstructions);

    // finally: create a copy of the method that gets the ThreadTracer as argument
    // this is only necessary for private methods or "<init>"
    if (this.tracer.wasRedefined(this.readMethod.getReadClass().getName())
            && (this.methodNode.access & ACC_PRIVATE) != 0) {
        final Type[] oldMethodArguments = Type.getArgumentTypes(this.methodNode.desc);
        final Type[] newMethodArguments = Arrays.copyOf(oldMethodArguments, oldMethodArguments.length + 1);
        newMethodArguments[oldMethodArguments.length] = Type.getType(ThreadTracer.class);
        final String newMethodDesc = Type.getMethodDescriptor(Type.getReturnType(this.methodNode.desc),
                newMethodArguments);
        final MethodNode newMethod = new MethodNode(this.methodNode.access, this.methodNode.name, newMethodDesc,
                this.methodNode.signature,
                (String[]) this.methodNode.exceptions.toArray(new String[this.methodNode.exceptions.size()]));
        methodIt.add(newMethod);

        int threadTracerParamPos = ((this.readMethod.getAccess() & Opcodes.ACC_STATIC) == 0 ? 1 : 0);
        for (final Type t : oldMethodArguments)
            threadTracerParamPos += t.getSize();

        final Map<LabelNode, LabelNode> newMethodLabels = new LazyLabelMap();

        // copy the local variables information to the new method
        for (final Object o : this.methodNode.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 = this.methodNode.maxLocals;
        newMethod.maxStack = this.methodNode.maxStack;

        // copy the try-catch-blocks
        for (final Object o : this.methodNode.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 6 instructions, replace them with these:
        newMethod.instructions.add(new VarInsnNode(ALOAD, threadTracerParamPos));
        newMethod.instructions.add(new InsnNode(DUP));
        newMethod.instructions.add(new VarInsnNode(ASTORE, this.tracerLocalVarIndex));
        newMethod.instructions.add(new JumpInsnNode(IFNULL, newMethodLabels.get(noTracingLabel)));
        final Iterator<AbstractInsnNode> oldInsnIt = this.methodNode.instructions.iterator(6);
        // and add all the other instructions
        while (oldInsnIt.hasNext()) {
            final AbstractInsnNode insn = oldInsnIt.next();
            newMethod.instructions.add(insn.clone(newMethodLabels));
        }
    }

    ready();
}