KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > bcel > verifier > structurals > Subroutines


1 /*
2  * Copyright 2000-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */

17 package org.apache.bcel.verifier.structurals;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.HashSet JavaDoc;
21 import java.util.Hashtable JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.Set JavaDoc;
24 import org.apache.bcel.generic.ASTORE;
25 import org.apache.bcel.generic.ATHROW;
26 import org.apache.bcel.generic.BranchInstruction;
27 import org.apache.bcel.generic.CodeExceptionGen;
28 import org.apache.bcel.generic.GotoInstruction;
29 import org.apache.bcel.generic.IndexedInstruction;
30 import org.apache.bcel.generic.Instruction;
31 import org.apache.bcel.generic.InstructionHandle;
32 import org.apache.bcel.generic.JsrInstruction;
33 import org.apache.bcel.generic.LocalVariableInstruction;
34 import org.apache.bcel.generic.MethodGen;
35 import org.apache.bcel.generic.RET;
36 import org.apache.bcel.generic.ReturnInstruction;
37 import org.apache.bcel.generic.Select;
38 import org.apache.bcel.verifier.exc.AssertionViolatedException;
39 import org.apache.bcel.verifier.exc.StructuralCodeConstraintException;
40
41     /**
42      * Instances of this class contain information about the subroutines
43      * found in a code array of a method.
44      * This implementation considers the top-level (the instructions
45      * reachable without a JSR or JSR_W starting off from the first
46      * instruction in a code array of a method) being a special subroutine;
47      * see getTopLevel() for that.
48      * Please note that the definition of subroutines in the Java Virtual
49      * Machine Specification, Second Edition is somewhat incomplete.
50      * Therefore, JustIce uses an own, more rigid notion.
51      * Basically, a subroutine is a piece of code that starts at the target
52      * of a JSR of JSR_W instruction and ends at a corresponding RET
53      * instruction. Note also that the control flow of a subroutine
54      * may be complex and non-linear; and that subroutines may be nested.
55      * JustIce also mandates subroutines not to be protected by exception
56      * handling code (for the sake of control flow predictability).
57      * To understand JustIce's notion of subroutines, please read
58    *
59      * TODO: refer to the paper.
60      *
61      * @version $Id: Subroutines.java 386056 2006-03-15 11:31:56Z tcurdt $
62      * @author Enver Haase
63      * @see #getTopLevel()
64      */

65 public class Subroutines{
66     /**
67      * This inner class implements the Subroutine interface.
68      */

69     private class SubroutineImpl implements Subroutine{
70         /**
71          * UNSET, a symbol for an uninitialized localVariable
72          * field. This is used for the "top-level" Subroutine;
73          * i.e. no subroutine.
74          */

75         private static final int UNSET = -1;
76
77         /**
78          * The Local Variable slot where the first
79          * instruction of this subroutine (an ASTORE) stores
80          * the JsrInstruction's ReturnAddress in and
81          * the RET of this subroutine operates on.
82          */

83         private int localVariable = UNSET;
84
85         /** The instructions that belong to this subroutine. */
86         private Set JavaDoc instructions = new HashSet JavaDoc(); // Elements: InstructionHandle
87

88         /*
89          * Refer to the Subroutine interface for documentation.
90          */

91         public boolean contains(InstructionHandle inst){
92             return instructions.contains(inst);
93         }
94         
95         /**
96          * The JSR or JSR_W instructions that define this
97          * subroutine by targeting it.
98          */

99         private Set JavaDoc theJSRs = new HashSet JavaDoc();
100         
101         /**
102          * The RET instruction that leaves this subroutine.
103          */

104         private InstructionHandle theRET;
105         
106         /**
107          * Returns a String representation of this object, merely
108          * for debugging purposes.
109          * (Internal) Warning: Verbosity on a problematic subroutine may cause
110          * stack overflow errors due to recursive subSubs() calls.
111          * Don't use this, then.
112          */

113         public String JavaDoc toString(){
114             String JavaDoc ret = "Subroutine: Local variable is '"+localVariable+"', JSRs are '"+theJSRs+"', RET is '"+theRET+"', Instructions: '"+instructions.toString()+"'.";
115             
116             ret += " Accessed local variable slots: '";
117             int[] alv = getAccessedLocalsIndices();
118             for (int i=0; i<alv.length; i++){
119                 ret += alv[i]+" ";
120             }
121             ret+="'.";
122
123             ret += " Recursively (via subsub...routines) accessed local variable slots: '";
124             alv = getRecursivelyAccessedLocalsIndices();
125             for (int i=0; i<alv.length; i++){
126                 ret += alv[i]+" ";
127             }
128             ret+="'.";
129
130             return ret;
131         }
132         
133         /**
134          * Sets the leaving RET instruction. Must be invoked after all instructions are added.
135          * Must not be invoked for top-level 'subroutine'.
136          */

137         void setLeavingRET(){
138             if (localVariable == UNSET){
139                 throw new AssertionViolatedException("setLeavingRET() called for top-level 'subroutine' or forgot to set local variable first.");
140             }
141             Iterator JavaDoc iter = instructions.iterator();
142             InstructionHandle ret = null;
143             while(iter.hasNext()){
144                 InstructionHandle actual = (InstructionHandle) iter.next();
145                 if (actual.getInstruction() instanceof RET){
146                     if (ret != null){
147                         throw new StructuralCodeConstraintException("Subroutine with more then one RET detected: '"+ret+"' and '"+actual+"'.");
148                     }
149                     else{
150                         ret = actual;
151                     }
152                 }
153             }
154             if (ret == null){
155                 throw new StructuralCodeConstraintException("Subroutine without a RET detected.");
156             }
157             if (((RET) ret.getInstruction()).getIndex() != localVariable){
158                 throw new StructuralCodeConstraintException("Subroutine uses '"+ret+"' which does not match the correct local variable '"+localVariable+"'.");
159             }
160             theRET = ret;
161         }
162                 
163         /*
164          * Refer to the Subroutine interface for documentation.
165          */

166         public InstructionHandle[] getEnteringJsrInstructions(){
167             if (this == TOPLEVEL) {
168                 throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine.");
169             }
170             InstructionHandle[] jsrs = new InstructionHandle[theJSRs.size()];
171             return (InstructionHandle[]) (theJSRs.toArray(jsrs));
172         }
173     
174         /**
175          * Adds a new JSR or JSR_W that has this subroutine as its target.
176          */

177         public void addEnteringJsrInstruction(InstructionHandle jsrInst){
178             if ( (jsrInst == null) || (! (jsrInst.getInstruction() instanceof JsrInstruction))){
179                 throw new AssertionViolatedException("Expecting JsrInstruction InstructionHandle.");
180             }
181             if (localVariable == UNSET){
182                 throw new AssertionViolatedException("Set the localVariable first!");
183             }
184             else{
185                 // Something is wrong when an ASTORE is targeted that does not operate on the same local variable than the rest of the
186
// JsrInstruction-targets and the RET.
187
// (We don't know out leader here so we cannot check if we're really targeted!)
188
if (localVariable != ((ASTORE) (((JsrInstruction) jsrInst.getInstruction()).getTarget().getInstruction())).getIndex()){
189                     throw new AssertionViolatedException("Setting a wrong JsrInstruction.");
190                 }
191             }
192             theJSRs.add(jsrInst);
193         }
194
195         /*
196          * Refer to the Subroutine interface for documentation.
197          */

198         public InstructionHandle getLeavingRET(){
199             if (this == TOPLEVEL) {
200                 throw new AssertionViolatedException("getLeavingRET() called on top level pseudo-subroutine.");
201             }
202             return theRET;
203         }
204         
205         /*
206          * Refer to the Subroutine interface for documentation.
207          */

208         public InstructionHandle[] getInstructions(){
209             InstructionHandle[] ret = new InstructionHandle[instructions.size()];
210             return (InstructionHandle[]) instructions.toArray(ret);
211         }
212         
213         /*
214          * Adds an instruction to this subroutine.
215          * All instructions must have been added before invoking setLeavingRET().
216          * @see #setLeavingRET
217          */

218         void addInstruction(InstructionHandle ih){
219             if (theRET != null){
220                 throw new AssertionViolatedException("All instructions must have been added before invoking setLeavingRET().");
221             }
222             instructions.add(ih);
223         }
224
225         /* Satisfies Subroutine.getRecursivelyAccessedLocalsIndices(). */
226         public int[] getRecursivelyAccessedLocalsIndices(){
227             Set JavaDoc s = new HashSet JavaDoc();
228             int[] lvs = getAccessedLocalsIndices();
229             for (int j=0; j<lvs.length; j++){
230                 s.add(new Integer JavaDoc(lvs[j]));
231             }
232             _getRecursivelyAccessedLocalsIndicesHelper(s, this.subSubs());
233             int[] ret = new int[s.size()];
234             Iterator JavaDoc i = s.iterator();
235             int j=-1;
236             while (i.hasNext()){
237                 j++;
238                 ret[j] = ((Integer JavaDoc) i.next()).intValue();
239             }
240             return ret;
241         }
242
243         /**
244          * A recursive helper method for getRecursivelyAccessedLocalsIndices().
245          * @see #getRecursivelyAccessedLocalsIndices()
246          */

247         private void _getRecursivelyAccessedLocalsIndicesHelper(Set JavaDoc s, Subroutine[] subs){
248             for (int i=0; i<subs.length; i++){
249                 int[] lvs = subs[i].getAccessedLocalsIndices();
250                 for (int j=0; j<lvs.length; j++){
251                     s.add(new Integer JavaDoc(lvs[j]));
252                 }
253                 if(subs[i].subSubs().length != 0){
254                     _getRecursivelyAccessedLocalsIndicesHelper(s, subs[i].subSubs());
255                 }
256             }
257         }
258
259         /*
260          * Satisfies Subroutine.getAccessedLocalIndices().
261          */

262         public int[] getAccessedLocalsIndices(){
263             //TODO: Implement caching.
264
Set JavaDoc acc = new HashSet JavaDoc();
265             if (theRET == null && this != TOPLEVEL){
266                 throw new AssertionViolatedException("This subroutine object must be built up completely before calculating accessed locals.");
267             }
268             Iterator JavaDoc i = instructions.iterator();
269             while (i.hasNext()){
270                 InstructionHandle ih = (InstructionHandle) i.next();
271                 // RET is not a LocalVariableInstruction in the current version of BCEL.
272
if (ih.getInstruction() instanceof LocalVariableInstruction || ih.getInstruction() instanceof RET){
273                     int idx = ((IndexedInstruction) (ih.getInstruction())).getIndex();
274                     acc.add(new Integer JavaDoc(idx));
275                     // LONG? DOUBLE?.
276
try{
277                         // LocalVariableInstruction instances are typed without the need to look into
278
// the constant pool.
279
if (ih.getInstruction() instanceof LocalVariableInstruction){
280                             int s = ((LocalVariableInstruction) ih.getInstruction()).getType(null).getSize();
281                             if (s==2) {
282                                 acc.add(new Integer JavaDoc(idx+1));
283                             }
284                         }
285                     }
286                     catch(RuntimeException JavaDoc re){
287                         throw new AssertionViolatedException("Oops. BCEL did not like NULL as a ConstantPoolGen object.");
288                     }
289                 }
290             }
291             
292             int[] ret = new int[acc.size()];
293             i = acc.iterator();
294             int j=-1;
295             while (i.hasNext()){
296                 j++;
297                 ret[j] = ((Integer JavaDoc) i.next()).intValue();
298             }
299             return ret;
300         }
301
302         /*
303          * Satisfies Subroutine.subSubs().
304          */

305         public Subroutine[] subSubs(){
306             Set JavaDoc h = new HashSet JavaDoc();
307
308             Iterator JavaDoc i = instructions.iterator();
309             while (i.hasNext()){
310                 Instruction inst = ((InstructionHandle) i.next()).getInstruction();
311                 if (inst instanceof JsrInstruction){
312                     InstructionHandle targ = ((JsrInstruction) inst).getTarget();
313                     h.add(getSubroutine(targ));
314                 }
315             }
316             Subroutine[] ret = new Subroutine[h.size()];
317             return (Subroutine[]) h.toArray(ret);
318         }
319         
320         /*
321          * Sets the local variable slot the ASTORE that is targeted
322          * by the JsrInstructions of this subroutine operates on.
323          * This subroutine's RET operates on that same local variable
324          * slot, of course.
325          */

326         void setLocalVariable(int i){
327             if (localVariable != UNSET){
328                 throw new AssertionViolatedException("localVariable set twice.");
329             }
330             else{
331                 localVariable = i;
332             }
333         }
334         
335         /**
336          * The default constructor.
337          */

338         public SubroutineImpl(){
339         }
340
341     }// end Inner Class SubrouteImpl
342

343     //Node coloring constants
344
private static final Integer JavaDoc WHITE = new Integer JavaDoc(0);
345     private static final Integer JavaDoc GRAY = new Integer JavaDoc(1);
346     private static final Integer JavaDoc BLACK = new Integer JavaDoc(2);
347     
348     /**
349      * The Hashtable containing the subroutines found.
350      * Key: InstructionHandle of the leader of the subroutine.
351      * Elements: SubroutineImpl objects.
352      */

353     private Hashtable JavaDoc subroutines = new Hashtable JavaDoc();
354
355     /**
356      * This is referring to a special subroutine, namely the
357      * top level. This is not really a subroutine but we use
358      * it to distinguish between top level instructions and
359      * unreachable instructions.
360      */

361     public final Subroutine TOPLEVEL;
362
363     /**
364      * Constructor.
365      * @param mg A MethodGen object representing method to
366      * create the Subroutine objects of.
367      */

368     public Subroutines(MethodGen mg){
369     
370         InstructionHandle[] all = mg.getInstructionList().getInstructionHandles();
371         CodeExceptionGen[] handlers = mg.getExceptionHandlers();
372
373         // Define our "Toplevel" fake subroutine.
374
TOPLEVEL = new SubroutineImpl();
375
376         // Calculate "real" subroutines.
377
Set JavaDoc sub_leaders = new HashSet JavaDoc(); // Elements: InstructionHandle
378
for (int i=0; i<all.length; i++){
379             Instruction inst = all[i].getInstruction();
380             if (inst instanceof JsrInstruction){
381                 sub_leaders.add(((JsrInstruction) inst).getTarget());
382             }
383         }
384  
385         // Build up the database.
386
Iterator JavaDoc iter = sub_leaders.iterator();
387         while (iter.hasNext()){
388             SubroutineImpl sr = new SubroutineImpl();
389             InstructionHandle astore = (InstructionHandle) (iter.next());
390             sr.setLocalVariable( ((ASTORE) (astore.getInstruction())).getIndex() );
391             subroutines.put(astore, sr);
392         }
393
394         // Fake it a bit. We want a virtual "TopLevel" subroutine.
395
subroutines.put(all[0], TOPLEVEL);
396         sub_leaders.add(all[0]);
397
398         // Tell the subroutines about their JsrInstructions.
399
// Note that there cannot be a JSR targeting the top-level
400
// since "Jsr 0" is disallowed in Pass 3a.
401
// Instructions shared by a subroutine and the toplevel are
402
// disallowed and checked below, after the BFS.
403
for (int i=0; i<all.length; i++){
404             Instruction inst = all[i].getInstruction();
405             if (inst instanceof JsrInstruction){
406                 InstructionHandle leader = ((JsrInstruction) inst).getTarget();
407                 ((SubroutineImpl) getSubroutine(leader)).addEnteringJsrInstruction(all[i]);
408             }
409         }
410         
411         // Now do a BFS from every subroutine leader to find all the
412
// instructions that belong to a subroutine.
413
Set JavaDoc instructions_assigned = new HashSet JavaDoc(); // we don't want to assign an instruction to two or more Subroutine objects.
414

415         Hashtable JavaDoc colors = new Hashtable JavaDoc(); //Graph colouring. Key: InstructionHandle, Value: Integer .
416

417         iter = sub_leaders.iterator();
418         while (iter.hasNext()){
419             // Do some BFS with "actual" as the root of the graph.
420
InstructionHandle actual = (InstructionHandle) (iter.next());
421             // Init colors
422
for (int i=0; i<all.length; i++){
423                 colors.put(all[i], WHITE);
424             }
425             colors.put(actual, GRAY);
426             // Init Queue
427
ArrayList JavaDoc Q = new ArrayList JavaDoc();
428             Q.add(actual); // add(Obj) adds to the end, remove(0) removes from the start.
429

430             /* BFS ALGORITHM MODIFICATION: Start out with multiple "root" nodes, as exception handlers are starting points of top-level code, too. [why top-level? TODO: Refer to the special JustIce notion of subroutines.]*/
431             if (actual == all[0]){
432                 for (int j=0; j<handlers.length; j++){
433                     colors.put(handlers[j].getHandlerPC(), GRAY);
434                     Q.add(handlers[j].getHandlerPC());
435                 }
436             }
437             /* CONTINUE NORMAL BFS ALGORITHM */
438             
439             // Loop until Queue is empty
440
while (Q.size() != 0){
441                 InstructionHandle u = (InstructionHandle) Q.remove(0);
442                 InstructionHandle[] successors = getSuccessors(u);
443                 for (int i=0; i<successors.length; i++){
444                     if (((Integer JavaDoc) colors.get(successors[i])) == WHITE){
445                         colors.put(successors[i], GRAY);
446                         Q.add(successors[i]);
447                     }
448                 }
449                 colors.put(u, BLACK);
450             }
451             // BFS ended above.
452
for (int i=0; i<all.length; i++){
453                 if (colors.get(all[i]) == BLACK){
454                     ((SubroutineImpl) (actual==all[0]?getTopLevel():getSubroutine(actual))).addInstruction(all[i]);
455                     if (instructions_assigned.contains(all[i])){
456                         throw new StructuralCodeConstraintException("Instruction '"+all[i]+"' is part of more than one subroutine (or of the top level and a subroutine).");
457                     }
458                     else{
459                         instructions_assigned.add(all[i]);
460                     }
461                 }
462             }
463             if (actual != all[0]){// If we don't deal with the top-level 'subroutine'
464
((SubroutineImpl) getSubroutine(actual)).setLeavingRET();
465             }
466         }
467         
468         // Now make sure no instruction of a Subroutine is protected by exception handling code
469
// as is mandated by JustIces notion of subroutines.
470
for (int i=0; i<handlers.length; i++){
471             InstructionHandle _protected = handlers[i].getStartPC();
472             while (_protected != handlers[i].getEndPC().getNext()){// Note the inclusive/inclusive notation of "generic API" exception handlers!
473
Iterator JavaDoc subs = subroutines.values().iterator();
474                 while (subs.hasNext()){
475                     Subroutine sub = (Subroutine) subs.next();
476                     if (sub != subroutines.get(all[0])){ // We don't want to forbid top-level exception handlers.
477
if (sub.contains(_protected)){
478                             throw new StructuralCodeConstraintException("Subroutine instruction '"+_protected+"' is protected by an exception handler, '"+handlers[i]+"'. This is forbidden by the JustIce verifier due to its clear definition of subroutines.");
479                         }
480                     }
481                 }
482                 _protected = _protected.getNext();
483             }
484         }
485         
486         // Now make sure no subroutine is calling a subroutine
487
// that uses the same local variable for the RET as themselves
488
// (recursively).
489
// This includes that subroutines may not call themselves
490
// recursively, even not through intermediate calls to other
491
// subroutines.
492
noRecursiveCalls(getTopLevel(), new HashSet JavaDoc());
493
494     }
495
496     /**
497      * This (recursive) utility method makes sure that
498      * no subroutine is calling a subroutine
499      * that uses the same local variable for the RET as themselves
500      * (recursively).
501      * This includes that subroutines may not call themselves
502      * recursively, even not through intermediate calls to other
503      * subroutines.
504      *
505      * @throws StructuralCodeConstraintException if the above constraint is not satisfied.
506      */

507     private void noRecursiveCalls(Subroutine sub, Set JavaDoc set){
508         Subroutine[] subs = sub.subSubs();
509
510         for (int i=0; i<subs.length; i++){
511             int index = ((RET) (subs[i].getLeavingRET().getInstruction())).getIndex();
512             
513             if (!set.add(new Integer JavaDoc(index))){
514                 // Don't use toString() here because of possibly infinite recursive subSubs() calls then.
515
SubroutineImpl si = (SubroutineImpl) subs[i];
516                 throw new StructuralCodeConstraintException("Subroutine with local variable '"+si.localVariable+"', JSRs '"+si.theJSRs+"', RET '"+si.theRET+"' is called by a subroutine which uses the same local variable index as itself; maybe even a recursive call? JustIce's clean definition of a subroutine forbids both.");
517             }
518
519             noRecursiveCalls(subs[i], set);
520             
521             set.remove(new Integer JavaDoc(index));
522         }
523     }
524     
525     /**
526      * Returns the Subroutine object associated with the given
527      * leader (that is, the first instruction of the subroutine).
528      * You must not use this to get the top-level instructions
529      * modeled as a Subroutine object.
530      *
531      * @see #getTopLevel()
532      */

533     public Subroutine getSubroutine(InstructionHandle leader){
534         Subroutine ret = (Subroutine) subroutines.get(leader);
535         
536         if (ret == null){
537             throw new AssertionViolatedException("Subroutine requested for an InstructionHandle that is not a leader of a subroutine.");
538         }
539
540         if (ret == TOPLEVEL){
541             throw new AssertionViolatedException("TOPLEVEL special subroutine requested; use getTopLevel().");
542         }
543         
544         return ret;
545     }
546
547     /**
548      * Returns the subroutine object associated with the
549      * given instruction. This is a costly operation, you
550      * should consider using getSubroutine(InstructionHandle).
551      * Returns 'null' if the given InstructionHandle lies
552      * in so-called 'dead code', i.e. code that can never
553      * be executed.
554      *
555      * @see #getSubroutine(InstructionHandle)
556      * @see #getTopLevel()
557      */

558     public Subroutine subroutineOf(InstructionHandle any){
559         Iterator JavaDoc i = subroutines.values().iterator();
560         while (i.hasNext()){
561             Subroutine s = (Subroutine) i.next();
562             if (s.contains(any)) {
563                 return s;
564             }
565         }
566 System.err.println("DEBUG: Please verify '"+any+"' lies in dead code.");
567         return null;
568         //throw new AssertionViolatedException("No subroutine for InstructionHandle found (DEAD CODE?).");
569
}
570
571     /**
572      * For easy handling, the piece of code that is <B>not</B> a
573      * subroutine, the top-level, is also modeled as a Subroutine
574      * object.
575      * It is a special Subroutine object where <B>you must not invoke
576      * getEnteringJsrInstructions() or getLeavingRET()</B>.
577      *
578      * @see Subroutine#getEnteringJsrInstructions()
579      * @see Subroutine#getLeavingRET()
580      */

581     public Subroutine getTopLevel(){
582         return TOPLEVEL;
583     }
584     /**
585      * A utility method that calculates the successors of a given InstructionHandle
586      * <B>in the same subroutine</B>. That means, a RET does not have any successors
587      * as defined here. A JsrInstruction has its physical successor as its successor
588      * (opposed to its target) as defined here.
589      */

590     private static InstructionHandle[] getSuccessors(InstructionHandle instruction){
591         final InstructionHandle[] empty = new InstructionHandle[0];
592         final InstructionHandle[] single = new InstructionHandle[1];
593         final InstructionHandle[] pair = new InstructionHandle[2];
594         
595         Instruction inst = instruction.getInstruction();
596         
597         if (inst instanceof RET){
598             return empty;
599         }
600         
601         // Terminates method normally.
602
if (inst instanceof ReturnInstruction){
603             return empty;
604         }
605         
606         // Terminates method abnormally, because JustIce mandates
607
// subroutines not to be protected by exception handlers.
608
if (inst instanceof ATHROW){
609             return empty;
610         }
611         
612         // See method comment.
613
if (inst instanceof JsrInstruction){
614             single[0] = instruction.getNext();
615             return single;
616         }
617
618         if (inst instanceof GotoInstruction){
619             single[0] = ((GotoInstruction) inst).getTarget();
620             return single;
621         }
622
623         if (inst instanceof BranchInstruction){
624             if (inst instanceof Select){
625                 // BCEL's getTargets() returns only the non-default targets,
626
// thanks to Eli Tilevich for reporting.
627
InstructionHandle[] matchTargets = ((Select) inst).getTargets();
628                 InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1];
629                 ret[0] = ((Select) inst).getTarget();
630                 System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length);
631                 return ret;
632             }
633             else{
634                 pair[0] = instruction.getNext();
635                 pair[1] = ((BranchInstruction) inst).getTarget();
636                 return pair;
637             }
638         }
639
640         // default case: Fall through.
641
single[0] = instruction.getNext();
642         return single;
643     }
644
645     /**
646      * Returns a String representation of this object; merely for debugging puposes.
647      */

648     public String JavaDoc toString(){
649         return "---\n"+subroutines.toString()+"\n---\n";
650     }
651 }
652
Popular Tags