001/* 002 * Cobertura - http://cobertura.sourceforge.net/ 003 * 004 * Copyright (C) 2011 Piotr Tabor 005 * 006 * Note: This file is dual licensed under the GPL and the Apache 007 * Source License (so that it can be used from both the main 008 * Cobertura classes and the ant tasks). 009 * 010 * Cobertura is free software; you can redistribute it and/or modify 011 * it under the terms of the GNU General Public License as published 012 * by the Free Software Foundation; either version 2 of the License, 013 * or (at your option) any later version. 014 * 015 * Cobertura is distributed in the hope that it will be useful, but 016 * WITHOUT ANY WARRANTY; without even the implied warranty of 017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 018 * General Public License for more details. 019 * 020 * You should have received a copy of the GNU General Public License 021 * along with Cobertura; if not, write to the Free Software 022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 023 * USA 024 */ 025 026package net.sourceforge.cobertura.instrument; 027 028import java.util.Collections; 029import java.util.LinkedList; 030import java.util.List; 031 032import org.objectweb.asm.Label; 033import org.objectweb.asm.MethodVisitor; 034import org.objectweb.asm.Opcodes; 035import org.objectweb.asm.tree.AbstractInsnNode; 036import org.objectweb.asm.tree.FieldInsnNode; 037import org.objectweb.asm.tree.FrameNode; 038import org.objectweb.asm.tree.IincInsnNode; 039import org.objectweb.asm.tree.InsnNode; 040import org.objectweb.asm.tree.IntInsnNode; 041import org.objectweb.asm.tree.JumpInsnNode; 042import org.objectweb.asm.tree.LabelNode; 043import org.objectweb.asm.tree.LdcInsnNode; 044import org.objectweb.asm.tree.LineNumberNode; 045import org.objectweb.asm.tree.LookupSwitchInsnNode; 046import org.objectweb.asm.tree.MethodInsnNode; 047import org.objectweb.asm.tree.MultiANewArrayInsnNode; 048import org.objectweb.asm.tree.TableSwitchInsnNode; 049import org.objectweb.asm.tree.TypeInsnNode; 050import org.objectweb.asm.tree.VarInsnNode; 051 052/** 053 * A message adapter that keeps list of last N events. 054 * 055 * @author piotr.tabor@gmail.com. 056 */ 057public class HistoryMethodAdapter extends MethodVisitor { 058 059 private final LinkedList<AbstractInsnNode> backlog = new LinkedList<AbstractInsnNode>(); 060 private final int eventsToTrace; 061 062 public HistoryMethodAdapter(MethodVisitor mv, int eventsToTrace) { 063 super(Opcodes.ASM4, mv); 064 this.eventsToTrace = eventsToTrace; 065 } 066 067 public List<AbstractInsnNode> backlog() { 068 return Collections.unmodifiableList(backlog); 069 } 070 071 private void appendToBacklog(AbstractInsnNode node) { 072 if (backlog.size() >= eventsToTrace) { 073 backlog.removeFirst(); 074 } 075 backlog.addLast(node); 076 } 077 078 @Override 079 public void visitFieldInsn(int arg0, String arg1, String arg2, String arg3) { 080 super.visitFieldInsn(arg0, arg1, arg2, arg3); 081 appendToBacklog(new FieldInsnNode(arg0, arg1, arg2, arg3)); 082 } 083 084 @Override 085 public void visitFrame(int arg0, int arg1, Object[] arg2, int arg3, 086 Object[] arg4) { 087 super.visitFrame(arg0, arg1, arg2, arg3, arg4); 088 appendToBacklog(new FrameNode(arg0, arg1, arg2, arg3, arg4)); 089 } 090 091 @Override 092 public void visitIincInsn(int arg0, int arg1) { 093 super.visitIincInsn(arg0, arg1); 094 appendToBacklog(new IincInsnNode(arg0, arg1)); 095 } 096 097 @Override 098 public void visitInsn(int arg0) { 099 super.visitInsn(arg0); 100 appendToBacklog(new InsnNode(arg0)); 101 } 102 103 @Override 104 public void visitIntInsn(int arg0, int arg1) { 105 super.visitIntInsn(arg0, arg1); 106 appendToBacklog(new IntInsnNode(arg0, arg1)); 107 } 108 109 @Override 110 public void visitJumpInsn(int arg0, Label arg1) { 111 super.visitJumpInsn(arg0, arg1); 112 appendToBacklog( 113 new JumpInsnNode(arg0, 114 new LabelNode(arg1))); 115 } 116 117 @Override 118 public void visitLabel(Label arg0) { 119 super.visitLabel(arg0); 120 appendToBacklog(new LabelNode(arg0)); 121 } 122 123 @Override 124 public void visitLdcInsn(Object arg0) { 125 super.visitLdcInsn(arg0); 126 appendToBacklog(new LdcInsnNode(arg0)); 127 } 128 129 @Override 130 public void visitLineNumber(int arg0, Label arg1) { 131 super.visitLineNumber(arg0, arg1); 132 appendToBacklog(new LineNumberNode(arg0, new LabelNode(arg1))); 133 } 134 135 @Override 136 public void visitLookupSwitchInsn(Label arg0, int[] arg1, Label[] arg2) { 137 super.visitLookupSwitchInsn(arg0, arg1, arg2); 138 LabelNode nodes[] = new LabelNode[arg2.length]; 139 for(int i = 0; i < arg2.length; i++) { 140 nodes[i] = new LabelNode(arg2[i]); 141 } 142 appendToBacklog(new LookupSwitchInsnNode(new LabelNode(arg0), arg1, nodes)); 143 } 144 145 @Override 146 public void visitMethodInsn(int arg0, String arg1, String arg2, String arg3) { 147 super.visitMethodInsn(arg0, arg1, arg2, arg3); 148 appendToBacklog(new MethodInsnNode(arg0, arg1, arg2, arg3)); 149 } 150 151 @Override 152 public void visitMultiANewArrayInsn(String arg0, int arg1) { 153 super.visitMultiANewArrayInsn(arg0, arg1); 154 appendToBacklog(new MultiANewArrayInsnNode(arg0, arg1)); 155 } 156 157 @Override 158 public void visitTableSwitchInsn(int arg0, int arg1, Label arg2, 159 Label[] arg3) { 160 super.visitTableSwitchInsn(arg0, arg1, arg2, arg3); 161 LabelNode nodes[] = new LabelNode[arg3.length]; 162 for(int i = 0; i < arg3.length; i++) { 163 nodes[i] = new LabelNode(arg3[i]); 164 } 165 appendToBacklog(new TableSwitchInsnNode(arg0, arg1, new LabelNode(arg2), nodes)); 166 } 167 168 @Override 169 public void visitTypeInsn(int arg0, String arg1) { 170 super.visitTypeInsn(arg0, arg1); 171 appendToBacklog(new TypeInsnNode(arg0, arg1)); 172 } 173 174 @Override 175 public void visitVarInsn(int arg0, int arg1) { 176 super.visitVarInsn(arg0, arg1); 177 appendToBacklog(new VarInsnNode(arg0, arg1)); 178 } 179}