KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > groboutils > codecoverage > v2 > module > BytecodeLineUtil


1 /*
2  * @(#)BytecodeLineUtil.java
3  *
4  * Copyright (C) 2003-2004 Matt Albrecht
5  * groboclown@users.sourceforge.net
6  * http://groboutils.sourceforge.net
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24  * DEALINGS IN THE SOFTWARE.
25  */

26
27 package net.sourceforge.groboutils.codecoverage.v2.module;
28
29
30 import java.util.Arrays JavaDoc;
31 import java.util.Comparator JavaDoc;
32
33 import net.sourceforge.groboutils.codecoverage.v2.IAnalysisMetaData;
34 import net.sourceforge.groboutils.codecoverage.v2.IMethodCode;
35
36 import org.apache.bcel.classfile.LineNumber;
37 import org.apache.bcel.classfile.LineNumberTable;
38 import org.apache.bcel.classfile.Method;
39 import org.apache.bcel.generic.InstructionHandle;
40 import org.apache.bcel.generic.InstructionList;
41
42
43 /**
44  * Helper that processes bytecode instructions and line-numbering
45  *
46  * @author Matt Albrecht <a HREF="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
47  * @author Juergen Kindler <a HREF="mailto:jkindler@freenet.de">jkindler@freenet.de</a>
48  * @version $Date: 2004/04/15 05:48:26 $
49  * @since February 18, 2003
50  * @see IAnalysisMetaData
51  */

52 public class BytecodeLineUtil
53 {
54     private int[] instructionPos; // bytecode postion for instruction index
55
private int[] instructionLine; // linenumber for instruction index
56
private InstructionHandle[] handles;
57     
58     private static final LineNumberComparator LINENUMBER_COMPARATOR =
59         new LineNumberComparator();
60     
61     /**
62      * Helper for sorting a line number table by program counter
63      *
64      * @author Juergen Kindler <a HREF="mailto:jkindler@freenet.de">jkindler@freenet.de</a>
65      */

66     private static class LineNumberComparator implements Comparator JavaDoc
67     {
68         /**
69          * Compares the PC of two LineNumber objects.
70          * Other objects will lead to a ClassCastException.
71          *
72          * @param o1 an <code>Object</code> value
73          * @param o2 an <code>Object</code> value
74          * @return an <code>int</code> value
75          */

76         public int compare(Object JavaDoc o1, Object JavaDoc o2)
77         {
78             return ((LineNumber) o1).getStartPC() -
79                 ((LineNumber) o2).getStartPC();
80         }
81     
82     
83         /**
84          * Compares equality of comparator objects.
85          * Returns that objects of same class as this one to be equal to this.
86          *
87          * @param o an <code>Object</code> value
88          * @return a <code>boolean</code> value
89          */

90         public boolean equals(Object JavaDoc o)
91         {
92             return (o != null) ? (this.getClass() == o.getClass()) : false;
93         }
94     }
95     
96     
97     /**
98      *
99      */

100     public BytecodeLineUtil( Method m )
101     {
102         if (m == null)
103         {
104             throw new IllegalArgumentException JavaDoc("no null args.");
105         }
106         initialize( m );
107     }
108     
109     
110     public BytecodeLineUtil( IMethodCode m )
111     {
112         if (m == null)
113         {
114             throw new IllegalArgumentException JavaDoc("no null args.");
115         }
116         initialize( m.getOriginalMethod() );
117     }
118     
119     
120     public InstructionHandle[] getHandles()
121     {
122         return this.handles;
123     }
124     
125     
126     public int getLineNumber( InstructionHandle ih )
127     {
128         if (ih == null)
129         {
130             throw new IllegalArgumentException JavaDoc("no null args.");
131         }
132         return getLineNumberForBytecodePos( ih.getPosition() );
133     }
134     
135     
136     public int getLineNumberForBytecodePos( int bytecodePos )
137     {
138         int instrPos = getInstructionPosForBytecodePos( bytecodePos );
139         return getLineNumberForInstructionPos( instrPos );
140     }
141     
142     
143     public int getLineNumberForInstructionPos( int instrPos )
144     {
145         if (instrPos >= 0 && instrPos < this.instructionLine.length)
146         {
147             return this.instructionLine[ instrPos ];
148         }
149         //else
150
return -1;
151     }
152     
153     
154     public int getInstructionPosForBytecodePos( int bytecodePos )
155     {
156         // this method needs to account for the virtual instructions at the
157
// end of a method.
158

159         int len = this.instructionPos.length;
160         if (len == 0)
161         {
162             return 0;
163         }
164         for (int i = 0; i < len; ++i)
165         {
166             if (this.instructionPos[i] == bytecodePos)
167             {
168                 return i;
169             }
170         }
171         if (len >= 1 && this.instructionPos[ len - 1 ] < bytecodePos )
172         {
173             return len;
174         }
175         
176         throw new IllegalStateException JavaDoc( "Unknown bytecode position "+
177             bytecodePos );
178     }
179     
180     
181     
182     
183     //-----------------------------------------------------------------------
184

185     
186     protected void initialize( Method m )
187     {
188         if (m == null)
189         {
190             throw new IllegalArgumentException JavaDoc("no null args.");
191         }
192         LineNumberTable lnt = m.getLineNumberTable();
193         LineNumber[] lines = sort( lnt );
194         this.instructionPos = getInstructionPositions( m );
195         this.instructionLine = getInstructionLines( lines,
196             this.instructionPos );
197     }
198     
199     
200     private LineNumber[] sort( LineNumberTable lnt )
201     {
202         if (lnt == null)
203         {
204             return new LineNumber[0];
205         }
206         LineNumber[] lines = lnt.getLineNumberTable();
207         if (lines == null)
208         {
209             return new LineNumber[0];
210         }
211         
212         Arrays.sort( lines, LINENUMBER_COMPARATOR );
213         return lines;
214     }
215     
216     
217     private int[] getInstructionPositions( Method m )
218     {
219         InstructionList il = new InstructionList( m.getCode().getCode() );
220         il.setPositions();
221         this.handles = il.getInstructionHandles();
222         
223         int instructionCount = handles.length;
224         int instructionPos[] = new int[ instructionCount ];
225         
226         // find the positions of the instructions in the bytecode
227
for (int i = 0; i < instructionCount; ++i)
228         {
229             instructionPos[i] = this.handles[i].getPosition();
230         }
231         return instructionPos;
232     }
233     
234     
235     private int[] getInstructionLines( LineNumber lines[], int bytePos[] )
236     {
237         int out[] = new int[ bytePos.length ];
238         for (int bIndex = 0; bIndex < bytePos.length; ++bIndex)
239         {
240             out[bIndex] = getLinenoForBytePos( lines, bytePos[ bIndex ] );
241         }
242         return out;
243     }
244     
245     
246     private int getLinenoForBytePos( LineNumber lines[], int bytePos )
247     {
248         if (lines.length <= 0)
249         {
250             return -1;
251         }
252         
253         for (int i = 1; i < lines.length; ++i)
254         {
255             if (bytePos < lines[ i ].getStartPC())
256             {
257                 return lines[i - 1].getLineNumber();
258             }
259         }
260         return lines[ lines.length - 1 ].getLineNumber();
261     }
262 }
263
264
Popular Tags