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}