KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > Body


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 1997-1999 Raja Vallee-Rai
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */

19
20 /*
21  * Modified by the Sable Research Group and others 1997-1999.
22  * See the 'credits' file distributed with Soot for the complete list of
23  * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
24  */

25
26
27
28
29
30 package soot;
31
32 import soot.tagkit.*;
33 import soot.baf.*;
34 import soot.jimple.*;
35 import soot.toolkits.graph.*;
36 import soot.*;
37 import soot.util.*;
38 import java.util.*;
39 import java.io.*;
40 import soot.toolkits.scalar.*;
41 import soot.toolkits.exceptions.*;
42 import soot.options.*;
43
44
45 /**
46  * Abstract base class that models the body (code attribute) of a Java method.
47  * Classes that implement an Intermediate Representation for a method body should subclass it.
48  * In particular the classes GrimpBody, JimpleBody and BafBody all extend this
49  * class. This class provides methods that are common to any IR, such as methods
50  * to get the body's units (statements), traps, and locals.
51  *
52  * @see soot.grimp.GrimpBody
53  * @see soot.jimple.JimpleBody
54  * @see soot.baf.BafBody
55  */

56 public abstract class Body extends AbstractHost implements Serializable
57 {
58     /** The method associated with this Body. */
59     protected transient SootMethod method = null;
60
61     /** The chain of locals for this Body. */
62     protected Chain localChain = new HashChain();
63
64     /** The chain of traps for this Body. */
65     protected Chain trapChain = new HashChain();
66
67     /** The chain of units for this Body. */
68     protected PatchingChain unitChain = new PatchingChain(new HashChain());
69
70     /** Creates a deep copy of this Body. */
71     abstract public Object JavaDoc clone();
72
73     /** Creates a Body associated to the given method. Used by subclasses during initialization.
74      * Creation of a Body is triggered by e.g. Jimple.v().newBody(options).
75      */

76     protected Body(SootMethod m)
77     {
78         this.method = m;
79     }
80
81     /** Creates an extremely empty Body. The Body is not associated to any method. */
82     protected Body()
83     {
84     }
85
86     /**
87      * Returns the method associated with this Body.
88      * @return the method that owns this body.
89      */

90     public SootMethod getMethod()
91     {
92         if(method == null)
93             throw new RuntimeException JavaDoc("no method associated w/ body");
94         return method;
95     }
96
97
98     /**
99      * Sets the method associated with this Body.
100      * @param method the method that owns this body.
101      *
102      */

103     public void setMethod(SootMethod method)
104     {
105         this.method = method;
106     }
107
108     /** Returns the number of locals declared in this body. */
109     public int getLocalCount()
110     {
111         return localChain.size();
112     }
113
114     /** Copies the contents of the given Body into this one. */
115     public Map importBodyContentsFrom(Body b)
116     {
117         HashMap bindings = new HashMap();
118
119         Iterator it = b.getUnits().iterator();
120
121         // Clone units in body's statement list
122
while(it.hasNext()) {
123             Unit original = (Unit) it.next();
124             Unit copy = (Unit) original.clone();
125
126             copy.addAllTagsOf(original);
127
128             // Add cloned unit to our unitChain.
129
unitChain.addLast(copy);
130
131             // Build old <-> new map to be able to patch up references to other units
132
// within the cloned units. (these are still refering to the original
133
// unit objects).
134
bindings.put(original, copy);
135         }
136
137         // Clone trap units.
138
it = b.getTraps().iterator();
139         while(it.hasNext()) {
140             Trap original = (Trap) it.next();
141             Trap copy = (Trap) original.clone();
142
143             // Add cloned unit to our trap list.
144
trapChain.addLast(copy);
145
146             // Store old <-> new mapping.
147
bindings.put(original, copy);
148         }
149
150
151         // Clone local units.
152
it = b.getLocals().iterator();
153         while(it.hasNext()) {
154             Value original = (Value) it.next();
155             Value copy = (Value) original.clone();
156
157             // Add cloned unit to our trap list.
158
localChain.addLast(copy);
159
160             // Build old <-> new mapping.
161
bindings.put(original, copy);
162         }
163
164
165
166         // Patch up references within units using our (old <-> new) map.
167
it = getAllUnitBoxes().iterator();
168         while(it.hasNext()) {
169             UnitBox box = (UnitBox) it.next();
170             Unit newObject, oldObject = box.getUnit();
171
172             // if we have a reference to an old object, replace it
173
// it's clone.
174
if( (newObject = (Unit) bindings.get(oldObject)) != null )
175                 box.setUnit(newObject);
176
177         }
178
179
180
181         // backpatching all local variables.
182
it = getUseBoxes().iterator();
183         while(it.hasNext()) {
184             ValueBox vb = (ValueBox) it.next();
185             if(vb.getValue() instanceof Local)
186                 vb.setValue((Value) bindings.get(vb.getValue()));
187         }
188         it = getDefBoxes().iterator();
189         while(it.hasNext()) {
190             ValueBox vb = (ValueBox) it.next();
191             if(vb.getValue() instanceof Local)
192                 vb.setValue((Value) bindings.get(vb.getValue()));
193         }
194         return bindings;
195     }
196
197     /** Verifies a few sanity conditions on the contents on this body. */
198     public void validate()
199     {
200         //System.out.println("body: "+this.getUnits());
201
validateLocals();
202         validateTraps();
203         validateUnitBoxes();
204         if (Options.v().debug() || Options.v().validate()) {
205             validateUses();
206             validateValueBoxes();
207             checkInit();
208             checkTypes();
209             checkLocals();
210         }
211     }
212
213     /** Verifies that a ValueBox is not used in more than one place. */
214     public void validateValueBoxes()
215     {
216         List l = getUseAndDefBoxes();
217         for( int i = 0; i < l.size(); i++ ) {
218             for( int j = 0; j < l.size(); j++ ) {
219                 if( i == j ) continue;
220                 if( l.get(i) == l.get(j) ) {
221                     System.err.println("Aliased value box : "+l.get(i)+" in "+getMethod());
222                     for( Iterator uIt = getUnits().iterator(); uIt.hasNext(); ) {
223                         final Unit u = (Unit) uIt.next();
224                         System.err.println(""+u);
225                     }
226                     throw new RuntimeException JavaDoc("Aliased value box : "+l.get(i)+" in "+getMethod());
227                 }
228             }
229         }
230     }
231
232     /** Verifies that each Local of getUseAndDefBoxes() is in this body's locals Chain. */
233     public void validateLocals()
234     {
235         Iterator it;
236         it = getUseBoxes().iterator();
237         while(it.hasNext()){
238             validateLocal( (ValueBox) it.next() );
239         }
240         it = getDefBoxes().iterator();
241         while(it.hasNext()){
242             validateLocal( (ValueBox) it.next() );
243         }
244     }
245     private void validateLocal( ValueBox vb ) {
246         Value value;
247         if( (value = vb.getValue()) instanceof Local) {
248             //System.out.println("localChain: "+localChain);
249
if(!localChain.contains(value))
250                 throw new RuntimeException JavaDoc("Local not in chain : "+value+" in "+getMethod());
251         }
252     }
253
254     /** Verifies that the begin, end and handler units of each trap are in this body. */
255     public void validateTraps()
256     {
257         Iterator it = getTraps().iterator();
258         while (it.hasNext())
259         {
260             Trap t = (Trap)it.next();
261             if (!unitChain.contains(t.getBeginUnit()))
262                 throw new RuntimeException JavaDoc("begin not in chain"+" in "+getMethod());
263
264             if (!unitChain.contains(t.getEndUnit()))
265                 throw new RuntimeException JavaDoc("end not in chain"+" in "+getMethod());
266
267             if (!unitChain.contains(t.getHandlerUnit()))
268                 throw new RuntimeException JavaDoc("handler not in chain"+" in "+getMethod());
269         }
270     }
271
272     /** Verifies that the UnitBoxes of this Body all point to a Unit contained within this body. */
273     public void validateUnitBoxes()
274     {
275         Iterator it = getAllUnitBoxes().iterator();
276         while (it.hasNext())
277         {
278             UnitBox ub = (UnitBox)it.next();
279             if (!unitChain.contains(ub.getUnit()))
280                 throw new RuntimeException JavaDoc
281                     ("Unitbox points outside unitChain! to unit : "+ub.getUnit()+" in "+getMethod());
282         }
283     }
284
285     /** Verifies that each use in this Body has a def. */
286     public void validateUses()
287     {
288         UnitGraph g = new ExceptionalUnitGraph(this);
289         LocalDefs ld = new SmartLocalDefs(g, new SimpleLiveLocals(g));
290
291         Iterator unitsIt = getUnits().iterator();
292         while (unitsIt.hasNext())
293         {
294             Unit u = (Unit) unitsIt.next();
295             Iterator useBoxIt = u.getUseBoxes().iterator();
296             while (useBoxIt.hasNext())
297             {
298                 Value v = ((ValueBox)useBoxIt.next()).getValue();
299                 if (v instanceof Local)
300                 {
301                     // This throws an exception if there is
302
// no def already; we check anyhow.
303
List l = ld.getDefsOfAt((Local)v, u);
304                     if (l.size() == 0){
305                         for( Iterator uuIt = getUnits().iterator(); uuIt.hasNext(); ) {
306                             final Unit uu = (Unit) uuIt.next();
307                             System.err.println(""+uu);
308                         }
309                         throw new RuntimeException JavaDoc("no defs for value: "+v+"!"+" in "+getMethod());
310                     }
311                 }
312             }
313         }
314     }
315
316     /** Returns a backed chain of the locals declared in this Body. */
317     public Chain getLocals() {return localChain;}
318
319     /** Returns a backed view of the traps found in this Body. */
320     public Chain getTraps() {return trapChain;}
321
322     /** Return LHS of the first identity stmt assigning from \@this. **/
323     public Local getThisLocal()
324     {
325         Iterator unitsIt = getUnits().iterator();
326
327         while (unitsIt.hasNext())
328         {
329             Stmt s = (Stmt)unitsIt.next();
330             if (s instanceof IdentityStmt &&
331                 ((IdentityStmt)s).getRightOp() instanceof ThisRef)
332                 return (Local)(((IdentityStmt)s).getLeftOp());
333         }
334
335         throw new RuntimeException JavaDoc("couldn't find identityref!"+" in "+getMethod());
336     }
337
338     /** Return LHS of the first identity stmt assigning from \@parameter i. **/
339     public Local getParameterLocal(int i)
340     {
341         Iterator unitsIt = getUnits().iterator();
342         while (unitsIt.hasNext())
343         {
344             Stmt s = (Stmt)unitsIt.next();
345             if (s instanceof IdentityStmt &&
346                 ((IdentityStmt)s).getRightOp() instanceof ParameterRef)
347             {
348                 IdentityStmt is = (IdentityStmt)s;
349                 ParameterRef pr = (ParameterRef)is.getRightOp();
350                 if (pr.getIndex() == i)
351                     return (Local)is.getLeftOp();
352             }
353         }
354
355         throw new RuntimeException JavaDoc("couldn't find parameterref!"+" in "+getMethod());
356     }
357
358     /**
359      * Returns the Chain of Units that make up this body. The units are
360      * returned as a PatchingChain. The client can then manipulate the chain,
361      * adding and removing units, and the changes will be reflected in the body.
362      * Since a PatchingChain is returned the client need <i>not</i> worry about removing exception
363      * boundary units or otherwise corrupting the chain.
364      *
365      * @return the units in this Body
366      *
367      * @see PatchingChain
368      * @see Unit
369      */

370     public PatchingChain getUnits()
371     {
372         return unitChain;
373     }
374
375     /**
376      * Returns the result of iterating through all Units in this body
377      * and querying them for their UnitBoxes. All UnitBoxes thus
378      * found are returned. Branching Units and statements which use
379      * PhiExpr will have UnitBoxes; a UnitBox contains a Unit that is
380      * either a target of a branch or is being used as a pointer to
381      * the end of a CFG block.
382      *
383      * <p> This method is typically used for pointer patching, eg when
384      * the unit chain is cloned.
385      *
386      * @return A list of all the UnitBoxes held by this body's units.
387      * @see UnitBox
388      * @see #getUnitBoxes(boolean)
389      * @see Unit#getUnitBoxes()
390      * @see soot.shimple.PhiExpr#getUnitBoxes()
391      **/

392     public List getAllUnitBoxes()
393     {
394         ArrayList unitBoxList = new ArrayList();
395         {
396             Iterator it = unitChain.iterator();
397             while(it.hasNext()) {
398                 Unit item = (Unit) it.next();
399                 unitBoxList.addAll(item.getUnitBoxes());
400             }
401         }
402
403         {
404             Iterator it = trapChain.iterator();
405             while(it.hasNext()) {
406                 Trap item = (Trap) it.next();
407                 unitBoxList.addAll(item.getUnitBoxes());
408             }
409         }
410
411         {
412             Iterator it = getTags().iterator();
413             while(it.hasNext()) {
414                 Tag t = (Tag) it.next();
415                 if( t instanceof CodeAttribute)
416                     unitBoxList.addAll(((CodeAttribute) t).getUnitBoxes());
417             }
418         }
419
420         return unitBoxList;
421     }
422
423     /**
424      * If branchTarget is true, returns the result of iterating
425      * through all branching Units in this body and querying them for
426      * their UnitBoxes. These UnitBoxes contain Units that are the
427      * target of a branch. This is useful for, say, labeling blocks
428      * or updating the targets of branching statements.
429      *
430      * <p> If branchTarget is false, returns the result of iterating
431      * through the non-branching Units in this body and querying them
432      * for their UnitBoxes. Any such UnitBoxes (typically from
433      * PhiExpr) contain a Unit that indicates the end of a CFG block.
434      *
435      * @return a list of all the UnitBoxes held by this body's
436      * branching units.
437      *
438      * @see UnitBox
439      * @see #getAllUnitBoxes()
440      * @see Unit#getUnitBoxes()
441      * @see soot.shimple.PhiExpr#getUnitBoxes()
442      **/

443     public List getUnitBoxes(boolean branchTarget)
444     {
445         ArrayList unitBoxList = new ArrayList();
446         {
447             Iterator it = unitChain.iterator();
448             while(it.hasNext()) {
449                 Unit item = (Unit) it.next();
450                 if(branchTarget){
451                     if(item.branches())
452                         unitBoxList.addAll(item.getUnitBoxes());
453                 }
454                 else{
455                     if(!item.branches())
456                         unitBoxList.addAll(item.getUnitBoxes());
457                 }
458             }
459         }
460
461         {
462             Iterator it = trapChain.iterator();
463             while(it.hasNext()) {
464                 Trap item = (Trap) it.next();
465                 unitBoxList.addAll(item.getUnitBoxes());
466             }
467         }
468
469         {
470             Iterator it = getTags().iterator();
471             while(it.hasNext()) {
472                 Tag t = (Tag) it.next();
473                 if( t instanceof CodeAttribute)
474                     unitBoxList.addAll(((CodeAttribute) t).getUnitBoxes());
475             }
476         }
477
478         return unitBoxList;
479     }
480
481
482     /**
483      * Returns the result of iterating through all Units in this
484      * body and querying them for ValueBoxes used.
485      * All of the ValueBoxes found are then returned as a List.
486      *
487      * @return a list of all the ValueBoxes for the Values used this body's units.
488      *
489      * @see Value
490      * @see Unit#getUseBoxes
491      * @see ValueBox
492      * @see Value
493      *
494      */

495     public List getUseBoxes()
496     {
497         ArrayList useBoxList = new ArrayList();
498
499         Iterator it = unitChain.iterator();
500         while(it.hasNext()) {
501             Unit item = (Unit) it.next();
502             useBoxList.addAll(item.getUseBoxes());
503         }
504         return useBoxList;
505     }
506
507
508     /**
509      * Returns the result of iterating through all Units in this
510      * body and querying them for ValueBoxes defined.
511      * All of the ValueBoxes found are then returned as a List.
512      *
513      * @return a list of all the ValueBoxes for Values defined by this body's units.
514      *
515      * @see Value
516      * @see Unit#getDefBoxes
517      * @see ValueBox
518      * @see Value
519      */

520     public List getDefBoxes()
521     {
522         ArrayList defBoxList = new ArrayList();
523
524         Iterator it = unitChain.iterator();
525         while(it.hasNext()) {
526             Unit item = (Unit) it.next();
527             defBoxList.addAll(item.getDefBoxes());
528         }
529         return defBoxList;
530     }
531
532      /**
533      * Returns a list of boxes corresponding to Values
534      * either used or defined in any unit of this Body.
535      *
536      * @return a list of ValueBoxes for held by the body's Units.
537      *
538      * @see Value
539      * @see Unit#getUseAndDefBoxes
540      * @see ValueBox
541      * @see Value
542      */

543     public List getUseAndDefBoxes()
544     {
545         ArrayList useAndDefBoxList = new ArrayList();
546
547         Iterator it = unitChain.iterator();
548         while(it.hasNext()) {
549             Unit item = (Unit) it.next();
550             useAndDefBoxList.addAll(item.getUseBoxes());
551             useAndDefBoxList.addAll(item.getDefBoxes());
552         }
553         return useAndDefBoxList;
554     }
555
556     private void checkLocals() {
557     Chain locals=getLocals();
558
559     Iterator it=locals.iterator();
560     while(it.hasNext()) {
561         Local l=(Local) it.next();
562         if(l.getType() instanceof VoidType)
563         throw new RuntimeException JavaDoc("Local "+l+" in "+method+" defined with void type");
564     }
565     }
566
567     private void checkTypes() {
568     Chain units=getUnits();
569
570     Iterator it=units.iterator();
571     while(it.hasNext()) {
572         Stmt stmt=(Stmt) (it.next());
573         InvokeExpr iexpr=null;
574
575         String JavaDoc errorSuffix=" at "+stmt+" in "+getMethod();
576
577         if(stmt instanceof DefinitionStmt) {
578         DefinitionStmt astmt=(DefinitionStmt) stmt;
579                 if( !(astmt.getRightOp() instanceof CaughtExceptionRef ) ) {
580                     Type leftType=Type.toMachineType(astmt.getLeftOp().getType());
581                     Type rightType=Type.toMachineType(astmt.getRightOp().getType());
582
583                     checkCopy(leftType,rightType,errorSuffix);
584                     if(astmt.getRightOp() instanceof InvokeExpr)
585                         iexpr=(InvokeExpr) (astmt.getRightOp());
586                 }
587         }
588
589         if(stmt instanceof InvokeStmt) iexpr=((InvokeStmt) stmt).getInvokeExpr();
590
591         if(iexpr!=null) {
592         SootMethodRef called=iexpr.getMethodRef();
593
594         if(iexpr instanceof InstanceInvokeExpr) {
595             InstanceInvokeExpr iiexpr=(InstanceInvokeExpr) iexpr;
596             checkCopy(called.declaringClass().getType(),
597                   iiexpr.getBase().getType(),
598                   " in receiver of call"+errorSuffix);
599         }
600
601         if(called.parameterTypes().size() != iexpr.getArgCount())
602             throw new RuntimeException JavaDoc("Warning: Argument count doesn't match up with signature in call"+errorSuffix+" in "+getMethod());
603         else
604             for(int i=0;i<iexpr.getArgCount();i++)
605             checkCopy(Type.toMachineType(called.parameterType(i)),
606                   Type.toMachineType(iexpr.getArg(i).getType()),
607                   " in argument "+i+" of call"+errorSuffix);
608         }
609     }
610     }
611
612     private void checkCopy(Type leftType,Type rightType,String JavaDoc errorSuffix) {
613     if(leftType instanceof PrimType || rightType instanceof PrimType) {
614         if(leftType instanceof IntType && rightType instanceof IntType) return;
615         if(leftType instanceof LongType && rightType instanceof LongType) return;
616         if(leftType instanceof FloatType && rightType instanceof FloatType) return;
617         if(leftType instanceof DoubleType && rightType instanceof DoubleType) return;
618         throw new RuntimeException JavaDoc("Warning: Bad use of primitive type"+errorSuffix+" in "+getMethod());
619     }
620
621     if(rightType instanceof NullType) return;
622     if(leftType instanceof RefType &&
623        ((RefType) leftType).getClassName().equals("java.lang.Object")) return;
624     
625     if(leftType instanceof ArrayType || rightType instanceof ArrayType) {
626         if(leftType instanceof ArrayType && rightType instanceof ArrayType) return;
627
628         throw new RuntimeException JavaDoc("Warning: Bad use of array type"+errorSuffix+" in "+getMethod());
629     }
630
631     if(leftType instanceof RefType && rightType instanceof RefType) {
632         SootClass leftClass=((RefType) leftType).getSootClass();
633         SootClass rightClass=((RefType) rightType).getSootClass();
634         
635         if(leftClass.isInterface()) {
636         if(rightClass.isInterface()) {
637             if(!(leftClass.getName().equals(rightClass.getName()) ||
638              Scene.v().getActiveHierarchy().isInterfaceSubinterfaceOf(rightClass,leftClass)))
639             throw new RuntimeException JavaDoc("Warning: Bad use of interface type"+errorSuffix+" in "+getMethod());
640         } else {
641             // No quick way to check this for now.
642
}
643         } else {
644         if(rightClass.isInterface()) {
645             throw new RuntimeException JavaDoc("Warning: trying to use interface type where non-Object class expected"
646                        +errorSuffix+" in "+getMethod());
647         } else {
648             if(!Scene.v().getActiveHierarchy().isClassSubclassOfIncluding(rightClass,leftClass))
649             throw new RuntimeException JavaDoc("Warning: Bad use of class type"+errorSuffix+" in "+getMethod());
650         }
651         }
652         return;
653     }
654     throw new RuntimeException JavaDoc("Warning: Bad types"+errorSuffix+" in "+getMethod());
655     }
656
657     public void checkInit() {
658     Chain units=getUnits();
659         ExceptionalUnitGraph g = new ExceptionalUnitGraph
660         (this, PedanticThrowAnalysis.v(), false);
661
662     // FIXME: Work around for bug in soot
663
Scene.v().releaseActiveHierarchy();
664
665         InitAnalysis analysis=new InitAnalysis(g);
666     Iterator it=units.iterator();
667     while(it.hasNext()) {
668         Stmt s=(Stmt) (it.next());
669         FlowSet init=(FlowSet) analysis.getFlowBefore(s);
670         List uses=s.getUseBoxes();
671         Iterator usesIt=uses.iterator();
672         while(usesIt.hasNext()) {
673         Value v=((ValueBox) (usesIt.next())).getValue();
674         if(v instanceof Local) {
675             Local l=(Local) v;
676             if(!init.contains(l))
677             throw new RuntimeException JavaDoc("Warning: Local variable "+l
678                        +" not definitely defined at "+s
679                        +" in "+method);
680         }
681         }
682     }
683     }
684 }
685
686
687
688
689
690
691
692
693
Popular Tags