visitMethod() now looks like: visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions); String clazz = className.replace('.', '/'); String field = "__" + name + "RecursionCount"; // field++ mv.visitVarInsn(ALOAD, 0); mv.visitInsn(DUP); mv.visitFieldInsn(GETFIELD, clazz, field, "I"); mv.visitInsn(ICONST_1); mv.visitInsn(IADD); mv.visitFieldInsn(PUTFIELD, clazz, field, "I"); // if (field > MAX_COUNT) mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, clazz, field, "I"); mv.visitIntInsn(BIPUSH, MAX_COUNT); Label l0 = new Label(); mv.visitJumpInsn(IF_ICMPLE, l0); mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); mv.visitLdcInsn("Recursion limit exceeded for " + name); mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); // Executes '(field)--', since the code added to the end of the method will // not be reached. mv.visitVarInsn(ALOAD, 0); mv.visitInsn(DUP); mv.visitFieldInsn(GETFIELD, clazz, field, "I"); mv.visitInsn(ICONST_1); mv.visitInsn(ISUB); mv.visitFieldInsn(PUTFIELD, clazz, field, "I"); // return null for Object return types mv.visitInsn(ACONST_NULL); mv.visitInsn(ARETURN); // if recursion count is under the max, the jump from above lands here mv.visitLabel(l0); mv = new RecursionLimiterMethodAdapter(mv, clazz, field); return mv; } class RecursionLimiterMethodAdapter extends MethodAdapter implements Opcodes { private String className; private String field; public RecursionLimiterMethodAdapter(MethodVisitor mv, String className, String field) { super(mv); this.className = className; this.field = field; } public void visitInsn(int opcode) { if ((opcode >= IRETURN) && (opcode <= RETURN)) { mv.visitVarInsn(ALOAD, 0); mv.visitInsn(DUP); mv.visitFieldInsn(GETFIELD, className, field, "I"); mv.visitInsn(ICONST_1); mv.visitInsn(ISUB); mv.visitFieldInsn(PUTFIELD, className, field, "I"); } super.visitInsn(opcode); } }