KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sourceforge > groboutils > codecoverage > v2 > compiler > ModifiedTargeters


1 /*
2  * @(#)ModifiedTargeters.java
3  *
4  * Copyright (C) 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.compiler;
28
29 import java.util.HashMap JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.LinkedList JavaDoc;
33 import java.util.List JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.Set JavaDoc;
36
37 import org.apache.bcel.generic.BranchInstruction;
38 import org.apache.bcel.generic.CodeExceptionGen;
39 import org.apache.bcel.generic.InstructionHandle;
40 import org.apache.bcel.generic.InstructionTargeter;
41 import org.apache.bcel.generic.LineNumberGen;
42 import org.apache.bcel.generic.LocalVariableGen;
43 import org.apache.bcel.generic.MethodGen;
44 import org.apache.bcel.generic.ObjectType;
45
46
47 /**
48  * Keeps track of different target types, and updates them according to
49  * the changes in the instructions.
50  * <p>
51  * This class exists due to a bug in the CodeException mod code in BCEL.
52  *
53  * @author Matt Albrecht <a HREF="mailto:groboclown@users.sourceforge.net">groboclown@users.sourceforge.net</a>
54  * @version $Date: 2004/04/15 05:48:25 $
55  * @since Jan 21, 2004, 2002
56  */

57 class ModifiedTargeters
58 {
59     private static final org.apache.log4j.Logger LOG =
60         org.apache.log4j.Logger.getLogger( ModifiedTargeters.class );
61     private MethodGen methGen;
62     private Map JavaDoc startToCodeException = new HashMap JavaDoc();
63     /* no longer needed
64     private Map endToCodeException = new HashMap();
65     */

66     private Map JavaDoc handlerToCodeException = new HashMap JavaDoc();
67     private List JavaDoc myCegs = new LinkedList JavaDoc();
68     private InstructionHandle lastInstruction;
69     
70     private static class MyCEG
71     {
72         private InstructionHandle origStartPC;
73         private InstructionHandle newStartPC;
74         
75         private InstructionHandle origEndPC;
76         private InstructionHandle newEndPC;
77         
78         private InstructionHandle origHandlerPC;
79         private InstructionHandle newHandlerPC;
80         
81         private ObjectType type;
82         
83         public MyCEG( InstructionHandle s, InstructionHandle e,
84                 InstructionHandle h, ObjectType t )
85         {
86             this.type = t;
87             this.origStartPC = s;
88             this.origEndPC = e;
89             this.origHandlerPC = h;
90             
91             if (t == null)
92             {
93                 LOG.debug( ">> Found null object type in CodeExceptionGen" );
94             }
95         }
96         
97         
98         public CodeExceptionGen addCodeException( MethodGen mg )
99         {
100             InstructionHandle sp = this.newStartPC;
101             InstructionHandle ep = this.newEndPC;
102             InstructionHandle hp = this.newHandlerPC;
103             
104             if (sp == null)
105             {
106                 sp = this.origStartPC;
107             }
108             if (ep == null)
109             {
110                 ep = this.origEndPC;
111             }
112             if (hp == null)
113             {
114                 hp = this.origHandlerPC;
115             }
116             LOG.debug( "Changing exception handler for type "+this.type+
117                 ": moved from (start = "+this.origStartPC+
118                 ", end = "+this.origEndPC+", handler = "+this.origHandlerPC+
119                 ") to (start = "+sp+", end = "+ep+", handler = "+hp+")" );
120             return mg.addExceptionHandler( sp, ep, hp, this.type );
121         }
122         
123         
124         public void setStartPC( InstructionHandle h )
125         {
126             if (this.newStartPC == null)
127             {
128                 LOG.debug( "Updating internal start PC for exception "+
129                     this.type+" to point to "+h );
130                 this.newStartPC = h;
131             }
132         }
133         
134         /* no longer supported
135         public void setEndPC( InstructionHandle h )
136         {
137             LOG.debug( "Updating internal end PC for exception "+
138                 this.type+" to point to "+h );
139             this.newEndPC = h;
140         }
141         */

142         
143         
144         public void setHandlerPC( InstructionHandle h )
145         {
146             if (this.newHandlerPC == null)
147             {
148                 LOG.debug( "Updating internal handler PC for exception "+
149                     this.type+" to point to "+h );
150                 this.newHandlerPC = h;
151             }
152         }
153     }
154     
155     /**
156      */

157     ModifiedTargeters( MethodGen mg )
158     {
159         if (mg == null)
160         {
161             throw new IllegalArgumentException JavaDoc("no null args");
162         }
163         this.methGen = mg;
164         
165         // setup the maps...
166
CodeExceptionGen ceg[] = mg.getExceptionHandlers();
167         for (int i = 0; i < ceg.length; ++i)
168         {
169             MyCEG ceg2 = new MyCEG( ceg[i].getStartPC(), ceg[i].getEndPC(),
170                 ceg[i].getHandlerPC(), ceg[i].getCatchType() );
171             this.myCegs.add( ceg2 );
172             putList( this.startToCodeException, ceg2.origStartPC, ceg2 );
173             /* no longer supported
174             putList( this.endToCodeException, ceg2.origEndPC, ceg2 );
175             */

176             putList( this.handlerToCodeException, ceg2.origHandlerPC, ceg2 );
177         }
178         
179         // discover the last instruction in the method
180
Iterator JavaDoc list = mg.getInstructionList().iterator();
181         while (list.hasNext())
182         {
183             this.lastInstruction = (InstructionHandle)list.next();
184         }
185     }
186     
187     
188     
189     
190     /**
191      * Inserted a probe into the list. "Inserting" means it goes before the
192      * instruction that's being probed, so the "end" parts of targeters don't
193      * need to be updated...
194      */

195     public void insertProbe( InstructionHandle instr, InstructionHandle probe )
196     {
197         // the original point that was being updated may not be what was
198
// last referenced for updating handlers.
199
// HOWEVER, the way probes are added is by always inserting them
200
// before the code that needs to be probed. That means, adding
201
// probe A will redirect targeters to A, then adding probe B
202
// will put B after A but before the instructions, so the targeters
203
// MUST NOT be updated, otherwise probe A will not be targeted
204
// correctly.
205

206         
207         InstructionTargeter [] its = instr.getTargeters();
208         if (its != null)
209         {
210             for (int j = 0; j < its.length; j++)
211             {
212                 LOG.debug( "Found for instruction "+instr+" targeter "+
213                     its[j] );
214                 
215                 // don't call updateTargeters, as that is faulty, and doesn't
216
// match what's really going on. Also, that technique was
217
// wrong when dealing with multiple probes added to the same
218
// instruction, multiple times.
219

220                 if (its[j] instanceof LineNumberGen)
221                 {
222                     LOG.debug( "Updating line number to point to probe "+
223                         probe );
224                     ((LineNumberGen)its[j]).setInstruction( probe );
225                 }
226                 else
227                 if (its[j] instanceof LocalVariableGen)
228                 {
229                     // this definitely needs to be separated out, so that
230
// if start and end are the same instruction, the end
231
// doesn't point to the new probe only.
232
if (instr.equals( ((LocalVariableGen)its[j]).getStart() ))
233                     {
234                         LOG.debug(
235                             "Updating local variable start to point to probe "+
236                             probe );
237                         ((LocalVariableGen)its[j]).setStart( probe );
238                     }
239                 }
240                 else
241                 if (its[j] instanceof CodeExceptionGen)
242                 {
243                     // ignore - we'll handle this separately
244
LOG.debug( "Ignoring CodeExceptionGen" );
245                 }
246                 else
247                 if (its[j] instanceof BranchInstruction)
248                 {
249                     // here we need to perform an update, so that the
250
// "Select" table can correctly be updated.
251
LOG.debug( "Updating branch instruction to point to probe "+
252                         probe );
253                     ((BranchInstruction)its[j]).updateTarget(
254                         instr, probe );
255                 }
256                 else
257                 {
258                     throw new IllegalStateException JavaDoc(
259                         "Unexpected targeter type (" +
260                         its[j].getClass().getName() +
261                         ") for instruction " + instr );
262                 }
263             }
264         }
265         
266         // if the inserted probe points to the start of a code exception,
267
// then redirect the code exception to the probe.
268
Iterator JavaDoc iter = getList( this.startToCodeException, instr );
269         while (iter.hasNext())
270         {
271             MyCEG mceg = (MyCEG)iter.next();
272             mceg.setStartPC( probe );
273         }
274         
275         // if the inserted probe points to the start of an exception handler,
276
// then redirect the code exception.
277
iter = getList( this.handlerToCodeException, instr );
278         while (iter.hasNext())
279         {
280             MyCEG mceg = (MyCEG)iter.next();
281             mceg.setHandlerPC( probe );
282         }
283     }
284     
285     
286     /*
287      * Here, we only need to update the end probes. Note that the last
288      * instruction in the method will change with these added probes.
289      *
290      * WARNING!!!! This should probably be pulled out, as it's very dangerous
291      * to add a probe at the end of a method - it will occur after
292      * any returns!
293     public void appendProbe( InstructionHandle probe )
294     {
295         // get new last instruction
296         InstructionHandle lastProbe = probe;
297         while (lastProbe.getNext() != null)
298         {
299             lastProbe = lastProbe.getNext();
300         }
301         
302         
303         InstructionTargeter [] its = this.lastInstruction.getTargeters();
304         if (its != null)
305         {
306             for (int j = 0; j < its.length; j++)
307             {
308                 // don't call updateTargeters, as that is faulty, and doesn't
309                 // match what's really going on. Also, that technique was
310                 // wrong when dealing with multiple probes added to the same
311                 // instruction, multiple times.
312                 
313                 if (its[j] instanceof LineNumberGen)
314                 {
315                     // don't do anything
316                 }
317                 else
318                 if (its[j] instanceof LocalVariableGen)
319                 {
320                     // this definitely needs to be separated out, so that
321                     // if start and end are the same instruction, the start
322                     // doesn't point to the new probe only.
323                     if (this.lastInstruction.equals(
324                         ((LocalVariableGen)its[j]).getEnd() ))
325                     {
326                         ((LocalVariableGen)its[j]).setEnd( lastProbe );
327                     }
328                 }
329                 else
330                 if (its[j] instanceof CodeExceptionGen)
331                 {
332                     // ignore - we'll handle this separately
333                 }
334                 else
335                 if (its[j] instanceof BranchInstruction)
336                 {
337                     // don't do anything
338                 }
339                 else
340                 {
341                     throw new IllegalStateException(
342                         "Unexpected targeter type (" +
343                         its[j].getClass().getName() +
344                         ") for instruction " + this.lastInstruction );
345                 }
346             }
347         }
348         
349         // if the inserted probe points to the start of a code exception,
350         // then redirect the code exception to the probe.
351         Iterator iter = getList( this.endToCodeException, this.lastInstruction );
352         while (iter.hasNext())
353         {
354             MyCEG mceg = (MyCEG)iter.next();
355             mceg.setEndPC( lastProbe );
356         }
357         
358         // update the last instruction pointer
359         this.lastInstruction = lastProbe;
360     }
361      */

362     
363     
364     /**
365      * Updates the targeters after a series of insert and appends.
366      * Note that the targeters might be updated during the inserts and
367      * appends.
368      */

369     public void update()
370     {
371         this.methGen.removeExceptionHandlers();
372         Iterator JavaDoc iter = this.myCegs.iterator();
373         while (iter.hasNext())
374         {
375             ((MyCEG)iter.next()).addCodeException( this.methGen );
376         }
377     }
378     
379     
380     private void putList( Map JavaDoc map, Object JavaDoc key, Object JavaDoc value )
381     {
382         Set JavaDoc s = (Set JavaDoc)map.get( key );
383         if (s == null)
384         {
385             s = new HashSet JavaDoc();
386             map.put( key, s );
387         }
388         s.add( value );
389     }
390     
391     
392     /**
393      * Never returns null.
394      */

395     private Iterator JavaDoc getList( Map JavaDoc map, Object JavaDoc key )
396     {
397         Set JavaDoc s = (Set JavaDoc)map.get( key );
398         if (s == null)
399         {
400             s = new HashSet JavaDoc();
401         }
402         return s.iterator();
403     }
404 }
405
406
Popular Tags