Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

TransExtractor.java

00001 package edu.ksu.cis.bandera.birc;
00002 
00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00004  * Bandera, a Java(TM) analysis and transformation toolkit           *
00005  * Copyright (C) 1998, 1999   James Corbett (corbett@hawaii.edu)     *
00006  * All rights reserved.                                              *
00007  *                                                                   *
00008  * This work was done as a project in the SAnToS Laboratory,         *
00009  * Department of Computing and Information Sciences, Kansas State    *
00010  * University, USA (http://www.cis.ksu.edu/santos).                  *
00011  * It is understood that any modification not identified as such is  *
00012  * not covered by the preceding statement.                           *
00013  *                                                                   *
00014  * This work is free software; you can redistribute it and/or        *
00015  * modify it under the terms of the GNU Library General Public       *
00016  * License as published by the Free Software Foundation; either      *
00017  * version 2 of the License, or (at your option) any later version.  *
00018  *                                                                   *
00019  * This work is distributed in the hope that it will be useful,      *
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU *
00022  * Library General Public License for more details.                  *
00023  *                                                                   *
00024  * You should have received a copy of the GNU Library General Public *
00025  * License along with this toolkit; if not, write to the             *
00026  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,      *
00027  * Boston, MA  02111-1307, USA.                                      *
00028  *                                                                   *
00029  * Java is a trademark of Sun Microsystems, Inc.                     *
00030  *                                                                   *
00031  * To submit a bug report, send a comment, or get the latest news on *
00032  * this project and other SAnToS projects, please visit the web-site *
00033  *                http://www.cis.ksu.edu/santos                      *
00034  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00035 import java.io.*;
00036 import java.util.Vector;
00037 
00038 import edu.ksu.cis.bandera.bir.TransSystem;
00039 import edu.ksu.cis.bandera.bir.ActionVector;
00040 import edu.ksu.cis.bandera.bir.Action;
00041 import edu.ksu.cis.bandera.bir.BirThread;
00042 import edu.ksu.cis.bandera.bir.BirConstants;
00043 import edu.ksu.cis.bandera.bir.LockAction;
00044 import edu.ksu.cis.bandera.bir.LockTest;
00045 import edu.ksu.cis.bandera.bir.ThreadAction;
00046 import edu.ksu.cis.bandera.bir.ThreadTest;
00047 import edu.ksu.cis.bandera.bir.PrintAction;
00048 import edu.ksu.cis.bandera.bir.AssertAction;
00049 import edu.ksu.cis.bandera.bir.Location;
00050 import edu.ksu.cis.bandera.bir.Transformation;
00051 import edu.ksu.cis.bandera.bir.AssignAction;
00052 import edu.ksu.cis.bandera.bir.StateVar;
00053 import edu.ksu.cis.bandera.bir.StateVarVector;
00054 
00055 import edu.ksu.cis.bandera.jext.*;
00056 
00057 import ca.mcgill.sable.util.*;
00058 import ca.mcgill.sable.soot.*;
00059 import ca.mcgill.sable.soot.jimple.*;
00060 
00061 /**
00062  * A Jimple statement switch that translates Jimple statements into
00063  * BIR transitions.
00064  */
00065 
00066 public class TransExtractor extends AbstractBanderaStmtSwitch
00067     implements BirConstants {
00068 
00069     TransSystem system;             // TransSystem being built
00070     LocalDefs localDefs;            // Jimple LocalDefs of thread body
00071     LiveLocals liveLocals;          // Jimple LiveLocals of thread body
00072     BirThread thread;               // BIR thread being built
00073     StmtGraph stmtGraph;            // Jimple statement graph of method
00074     SootMethod method;              // Soot method of thread being built
00075     TypeExtractor typeExtract;      // Type extractor for TransSystem
00076     PredicateSet predSet;           // Predicate set 
00077     SootClassManager classManager;
00078 
00079     public TransExtractor(TransSystem system, BirThread thread, 
00080               StmtGraph stmtGraph, LocalDefs localDefs,
00081               LiveLocals liveLocals, SootMethod method,
00082               TypeExtractor typeExtract,  PredicateSet predSet) {
00083     this.system = system;
00084     this.thread = thread;
00085     this.stmtGraph = stmtGraph;
00086     this.localDefs = localDefs;
00087     this.liveLocals = liveLocals;
00088     this.method = method;
00089     this.classManager = method.getDeclaringClass().getManager();
00090     this.typeExtract = typeExtract;
00091     this.predSet = predSet;
00092     }
00093     /**
00094      * Build an AssertAction from a Bandera.assert() statement.
00095      */
00096 
00097     AssertAction buildAssertAction(Stmt stmt, Value expr) {
00098     // Translate the assertion expression
00099     ExprExtractor extractor = 
00100         new ExprExtractor(system, stmt, localDefs, method, 
00101                   typeExtract, predSet);
00102     expr.apply(extractor);
00103     edu.ksu.cis.bandera.bir.Expr condition = 
00104         (edu.ksu.cis.bandera.bir.Expr)extractor.getResult();
00105     AssertAction action = new AssertAction(condition);
00106     return action;
00107     }
00108     /**
00109      * Create a PrintAction for a Bandera.print() call.
00110      * <p>
00111      * Note: this code is very brittle.  It scans the
00112      * Jimple looking for the arguments to Bandera.print(String s),
00113      * which are concatentated using StringBuffer calls.
00114      * Look at the Jimple to better understand the logic.
00115      */
00116 
00117     PrintAction buildPrintAction(Stmt stmt, Value stringArg) {
00118     ExprExtractor extractor = 
00119         new ExprExtractor(system, stmt, localDefs, method, 
00120                   typeExtract, predSet);
00121     PrintAction action = new PrintAction();
00122     // Argument might be simple String
00123     if (stringArg instanceof StringConstant) {
00124         stringArg.apply(extractor);
00125         action.addPrintItem(extractor.getResult());
00126         return action;
00127     } else if (! (stringArg instanceof Local)) {
00128         System.out.println("Warning: ignoring Bandera.print() call");
00129         return null;
00130     }
00131     // Otherwise argument should be a Local ref to a String
00132     // Find the statement that defines this local, which should
00133     // be a toString() call on a StringBuffer that was used
00134     // to concatenate the arguments.
00135     List defsOfUse = localDefs.getDefsOfAt((Local)stringArg, stmt);
00136     DefinitionStmt def = (DefinitionStmt) defsOfUse.get(0);
00137     InvokeExpr expr = (InvokeExpr) def.getRightOp();
00138     Local strBuf;
00139     // Loop through the StringBuffer.append() calls, adding their
00140     // arguments to the PrintAction.
00141     do {
00142         strBuf = (Local) ((VirtualInvokeExpr)expr).getBase();
00143         defsOfUse = localDefs.getDefsOfAt(strBuf, def);
00144         def = (DefinitionStmt) defsOfUse.get(0);
00145         if (! (def.getRightOp() instanceof InvokeExpr))
00146         break;
00147         expr = (InvokeExpr) def.getRightOp();
00148         expr.getArg(0).apply(extractor);
00149         action.addPrintItemFront(extractor.getResult());
00150     } while (true);
00151     // The first argument to Bandera.print() was passed to the
00152     // constructor of the StringBuffer
00153     InvokeStmt initStmt = (InvokeStmt) stmtGraph.getSuccsOf(def).get(0);
00154     SpecialInvokeExpr initExpr = 
00155         (SpecialInvokeExpr) initStmt.getInvokeExpr();
00156     initExpr.getArg(0).apply(extractor);
00157     action.addPrintItemFront(extractor.getResult());
00158     return action;
00159     }
00160     public void caseAssignStmt(AssignStmt stmt) {
00161     caseDefinitionStmt(stmt);
00162     }
00163     /**
00164      * Create a transformation for an assignment statement.
00165      */
00166 
00167     public void caseDefinitionStmt(DefinitionStmt stmt) {
00168     // Only process if type of LHS is represented
00169     if (typeRepresented(stmt.getLeftOp().getType())) {
00170         // Build expression extractor and use it to translate both sides
00171         ExprExtractor extractor = 
00172         new ExprExtractor(system,stmt, localDefs, method, 
00173                   typeExtract, predSet);
00174         stmt.getRightOp().apply(extractor);
00175         edu.ksu.cis.bandera.bir.Expr rhsExpr = 
00176         (edu.ksu.cis.bandera.bir.Expr) extractor.getResult();
00177         stmt.getLeftOp().apply(extractor);
00178         edu.ksu.cis.bandera.bir.Expr lhsExpr = 
00179         (edu.ksu.cis.bandera.bir.Expr) extractor.getResult(); 
00180 
00181         // If we see 'x = new C;' where C is a thread class,
00182         // assign the instance ref to the 'this' var for the thread.
00183         if (stmt.getRightOp() instanceof NewExpr) {
00184         RefType type = ((NewExpr)stmt.getRightOp()).getBaseType();
00185         SootClass threadClass = classManager.getClass(type.className);
00186         StateVar var = system.getVarOfKey(threadClass);
00187         if (var != null) {
00188             AssignAction setThis = new AssignAction(var,lhsExpr);
00189             Location loc = makeLocation();
00190             makeTrans(locationOfStmt(stmt), loc, null,
00191                   new AssignAction(lhsExpr,rhsExpr), 
00192                   getLiveVars(stmt), stmt,extractor);
00193             makeTrans(loc,  locationOfNextStmt(stmt), null,
00194                   new AssignAction(var,lhsExpr), 
00195                   getLiveVars(stmt), stmt,extractor);
00196             return;
00197         }
00198         }
00199         // Normal case
00200         makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), null,
00201               new AssignAction(lhsExpr,rhsExpr), getLiveVars(stmt),
00202               stmt,extractor);
00203 
00204     }
00205     else  // Type not represented---just add trivial transformation
00206         makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), null,
00207               null, getLiveVars(stmt), stmt, null);
00208     }
00209     /**
00210      * Create transformation for enter monitor statement.
00211      * <p>
00212      * Note: we actually create two transformatios.  The first
00213      * has the lockAvailable guard and the lock action.  The second,
00214      * has the hasLock guard.
00215      */
00216 
00217     public void caseEnterMonitorStmt(EnterMonitorStmt stmt) {
00218     // Translate monitor expression
00219     ExprExtractor extractor = 
00220         new ExprExtractor(system, stmt, localDefs, method, typeExtract,
00221                   predSet);
00222     stmt.getOp().apply(extractor);
00223     edu.ksu.cis.bandera.bir.Expr lockRef = 
00224         (edu.ksu.cis.bandera.bir.Expr)extractor.getResult();
00225     edu.ksu.cis.bandera.bir.Expr lock =  getLockFieldExpr(lockRef);
00226     Location loc = makeLocation();
00227     StateVarVector liveVars = getLiveVars(stmt);
00228     makeTrans(locationOfStmt(stmt), loc, 
00229           new LockTest(lock, LOCK_AVAILABLE, thread),
00230           new LockAction(lock, LOCK, thread),liveVars,stmt,extractor);
00231     makeTrans(loc, locationOfNextStmt(stmt),
00232           new LockTest(lock, HAS_LOCK, thread), 
00233           null, liveVars, stmt, extractor);
00234     }
00235     /**
00236      * Create a transformation for exit monitor statement.
00237      */
00238 
00239     public void caseExitMonitorStmt(ExitMonitorStmt stmt) {
00240     ExprExtractor extractor =
00241         new ExprExtractor(system, stmt, localDefs, method, 
00242                   typeExtract, predSet);
00243     stmt.getOp().apply(extractor);
00244     edu.ksu.cis.bandera.bir.Expr lockRef = 
00245         (edu.ksu.cis.bandera.bir.Expr)extractor.getResult();
00246     edu.ksu.cis.bandera.bir.Expr lock =  getLockFieldExpr(lockRef);
00247     makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), null,
00248           new LockAction(lock, UNLOCK, thread), getLiveVars(stmt), 
00249           stmt, extractor);
00250     }
00251     /**
00252      * Create transformation for goto statement.
00253      */
00254 
00255     public void caseGotoStmt(GotoStmt stmt) {
00256     makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), null, null,
00257           getLiveVars(stmt), stmt, null);
00258     }
00259     public void caseIdentityStmt(IdentityStmt stmt) {
00260     caseDefinitionStmt(stmt);
00261     }
00262     /**
00263      * Create transformations for IF statement.
00264      */
00265 
00266     public void caseIfStmt(IfStmt stmt) {
00267     ExprExtractor extractor =
00268         new ExprExtractor(system, stmt, localDefs, method, 
00269                   typeExtract, predSet);
00270     stmt.getCondition().apply(extractor);
00271     edu.ksu.cis.bandera.bir.Expr condition = 
00272         (edu.ksu.cis.bandera.bir.Expr) extractor.getResult();
00273     edu.ksu.cis.bandera.bir.Expr notCondition =
00274         new edu.ksu.cis.bandera.bir.NotExpr(condition);
00275     StateVarVector liveVars = getLiveVars(stmt);
00276     Iterator stmtIt = stmtGraph.getSuccsOf(stmt).iterator();
00277     // Use null PrintAction on branches so 
00278     //  1) Transformations won't be trivial (and collapsed by Reducer)
00279     //  2) We can record the IfStmt as the source of the action
00280     //     so it will show up in the counterexample display
00281     PrintAction action = new PrintAction();
00282     while (stmtIt.hasNext()) {
00283         Stmt nextStmt = (Stmt) stmtIt.next();
00284         if (nextStmt == stmt.getTarget())
00285         makeTrans(locationOfStmt(stmt), locationOfStmt(nextStmt),
00286               condition, action, liveVars, stmt, extractor);
00287         else
00288         makeTrans(locationOfStmt(stmt), locationOfStmt(nextStmt),
00289               notCondition, action, liveVars, stmt, extractor);
00290     }       
00291     }
00292     /**
00293      * Create transformation for method invokation.
00294      * <p>
00295      * Most methods should have been inlined.  Here, we handle
00296      * only special cases (e.g., wait(), notify(), assert()).
00297      */
00298 
00299     public void caseInvokeStmt(InvokeStmt stmt) {
00300     Action action = null;
00301 
00302     // For virtual invocations, look for lock and thread operations
00303     if (stmt.getInvokeExpr() instanceof VirtualInvokeExpr) {
00304         VirtualInvokeExpr expr = (VirtualInvokeExpr)stmt.getInvokeExpr();
00305         String methodName = expr.getMethod().getName();
00306         int opCode = LockAction.operationCode(methodName);
00307         if (opCode != INVALID) {
00308         lockOperation(stmt, expr, opCode);
00309         return;
00310         }
00311         SootClass sClass = expr.getMethod().getDeclaringClass();
00312         if (sClass.getName().equals("java.lang.Thread")) {
00313         opCode = ThreadAction.operationCode(methodName);
00314         if (opCode != INVALID) {
00315             threadOperation(stmt,expr,opCode);
00316             return;
00317         }
00318         }
00319     }
00320 
00321     // For static invocations, look for:
00322     //  Bandera.print
00323     //  Bandera.assert
00324     if (stmt.getInvokeExpr() instanceof StaticInvokeExpr) {
00325         StaticInvokeExpr expr = (StaticInvokeExpr) stmt.getInvokeExpr();
00326         String methodName = expr.getMethod().getName();
00327         // We still accept the old static syntax for thread ops
00328         int opCode = ThreadAction.operationCode(methodName);
00329         if (opCode != INVALID) {
00330         oldThreadOperation(stmt, expr, opCode);
00331         return;
00332         }
00333         String className = expr.getMethod().getDeclaringClass().getName();
00334         if (className.equals("Bandera"))
00335         if (methodName.equals("print")) 
00336             action = buildPrintAction(stmt,expr.getArg(0));
00337         else if (methodName.equals("assert")) 
00338             action = buildAssertAction(stmt,expr.getArg(0));
00339     }
00340 
00341     // if we're not suppose to ignore this method call, issue a warning
00342     if (! ignoringMethodCall((InvokeExpr)stmt.getInvokeExpr())) 
00343         System.out.println("Warning: ignoring method call: " + stmt);
00344 
00345     makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), null,
00346           action, getLiveVars(stmt), stmt, null);
00347     }
00348     /**
00349      * Create transformations for a lookup swicth statement.
00350      */
00351 
00352     public void caseLookupSwitchStmt(LookupSwitchStmt stmt) {
00353     ExprExtractor extractor =
00354         new ExprExtractor(system, stmt, localDefs, method, 
00355                   typeExtract, predSet);
00356     stmt.getKey().apply(extractor);
00357     edu.ksu.cis.bandera.bir.Expr key = 
00358         (edu.ksu.cis.bandera.bir.Expr) extractor.getResult();
00359     edu.ksu.cis.bandera.bir.Expr otherwise = null;
00360     StateVarVector liveVars = getLiveVars(stmt);
00361     // Use null print action (for same reasons as in IF statement)
00362     PrintAction action = new PrintAction();
00363     for (int i = 0; i < stmt.getTargetCount(); i++) {
00364         // Make equality test for this target
00365         edu.ksu.cis.bandera.bir.Expr match = 
00366         matchCase(key, stmt.getLookupValue(i));
00367         otherwise = (otherwise == null) ? match :
00368         new edu.ksu.cis.bandera.bir.OrExpr(match,otherwise);
00369         // Branch to target i if test is true
00370         makeTrans(locationOfStmt(stmt), locationOfStmt(stmt.getTarget(i)),
00371               match, action, liveVars, stmt, extractor);
00372     }
00373     // Branch to default target if none of equality tests were true
00374     makeTrans(locationOfStmt(stmt), 
00375           locationOfStmt(stmt.getDefaultTarget()),
00376           new edu.ksu.cis.bandera.bir.NotExpr(otherwise), action,
00377           liveVars, stmt, extractor);
00378     }
00379     public void caseNopStmt(NopStmt stmt) {
00380     makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), null, null,
00381           getLiveVars(stmt), stmt, null);
00382     }
00383     /**
00384      * Create transformations for table switch statement.
00385      */
00386 
00387     public void caseTableSwitchStmt(TableSwitchStmt stmt) {
00388     ExprExtractor extractor =
00389         new ExprExtractor(system, stmt, localDefs, method, 
00390                   typeExtract, predSet);
00391     stmt.getKey().apply(extractor);
00392     edu.ksu.cis.bandera.bir.Expr key = 
00393         (edu.ksu.cis.bandera.bir.Expr) extractor.getResult();
00394     StateVarVector liveVars = getLiveVars(stmt);
00395     // Use null print action (for same reasons as in IF statement)
00396     PrintAction action = new PrintAction();
00397     for (int i = stmt.getLowIndex(); i <= stmt.getHighIndex(); i++) 
00398         // Branch to target i 
00399         makeTrans(locationOfStmt(stmt), 
00400               locationOfStmt(stmt.getTarget(i - stmt.getLowIndex())),
00401               matchCase(key, i), action, liveVars, stmt, extractor);
00402     // Branch to default if key value outside range
00403     edu.ksu.cis.bandera.bir.Expr lowIndex, tooLow, highIndex, tooHigh;
00404     lowIndex = new edu.ksu.cis.bandera.bir.IntLit(stmt.getLowIndex());
00405     highIndex = new edu.ksu.cis.bandera.bir.IntLit(stmt.getHighIndex());
00406     tooLow = new edu.ksu.cis.bandera.bir.LtExpr(key, lowIndex);
00407     tooHigh = new edu.ksu.cis.bandera.bir.LtExpr(highIndex, key);
00408     makeTrans(locationOfStmt(stmt), 
00409           locationOfStmt(stmt.getDefaultTarget()),
00410           new edu.ksu.cis.bandera.bir.OrExpr(tooLow,tooHigh), action,
00411           liveVars, stmt, extractor);
00412     }
00413     // public void caseThrowStmt(ThrowStmt stmt) {}
00414     // public void caseRetStmt(RetStmt stmt) {}
00415     // public void caseReturnStmt(ReturnStmt stmt) {}
00416     // public void caseReturnVoidStmt(ReturnVoidStmt stmt) {}
00417 
00418     public void defaultCase(Object o) {
00419     throw new RuntimeException("Unhandled statement type: " + o);
00420     }
00421     /**
00422      * Get the locals live before a Stmt.
00423      */
00424 
00425     StateVarVector getLiveVars(Stmt stmt) {
00426     StateVarVector liveVars = new StateVarVector(10);
00427     List liveList = liveLocals.getLiveLocalsBefore(stmt);
00428     Iterator liveIt = liveList.iterator();
00429     while (liveIt.hasNext()) {
00430         Local local = (Local) liveIt.next();
00431         if (typeRepresented(local.getType())) {
00432         String key = ExprExtractor.localKey(method, local);
00433         StateVar var = system.getVarOfKey(key);
00434         liveVars.addElement(var);
00435         }
00436     }
00437     return liveVars;
00438     }
00439     /**
00440      * Get the BIR expression for the lock field of a record.
00441      * <p>
00442      * In Jimple, the argument to a lock operation is simply a reference
00443      * to an object---the lock is implicitly part of that object.
00444      * In BIR, locks are explicit fields of records.   Here,
00445      * we take a BIR expression that is a reference to a record
00446      * (the translation of the Jimple expression naming the locked
00447      * object) and we convert it to a BIR expression for the lock
00448      * field of that record by dereferencing and selecting the
00449      * special field BIRLock.  
00450      */
00451 
00452     edu.ksu.cis.bandera.bir.Expr getLockFieldExpr(edu.ksu.cis.bandera.bir.Expr lockRef) {
00453     edu.ksu.cis.bandera.bir.Ref refType = 
00454         (edu.ksu.cis.bandera.bir.Ref)lockRef.getType();
00455     edu.ksu.cis.bandera.bir.Record recType = 
00456         (edu.ksu.cis.bandera.bir.Record)refType.getTargetType();
00457     edu.ksu.cis.bandera.bir.Field lockField = recType.getField("BIRLock");
00458     edu.ksu.cis.bandera.bir.Expr rec = 
00459         new edu.ksu.cis.bandera.bir.DerefExpr(lockRef);
00460     return new edu.ksu.cis.bandera.bir.RecordExpr(rec,lockField);
00461     }
00462     /**
00463      * Test if method call should be ignored.
00464      */
00465 
00466     boolean ignoringMethodCall(InvokeExpr expr) {
00467     String className = expr.getMethod().getDeclaringClass().getName();
00468     if (className.equals("java.io.PrintStream")
00469         || className.equals("java.lang.String")
00470         || className.equals("java.lang.StringBuffer") 
00471         || className.equals("Bandera") )
00472         return true;
00473     return false;
00474     }
00475     /**
00476      * Get location of Jimple Stmt that follows a given statement.
00477      * <p>
00478      * The Stmt must have at most one successor.  
00479      */
00480 
00481     Location locationOfNextStmt(Stmt stmt) {
00482     List successors = stmtGraph.getSuccsOf(stmt);
00483     if (successors.size() > 1) 
00484         throw new RuntimeException("No unique successor to " + stmt);
00485     if (successors.size() == 1) {
00486         Stmt nextStmt = (Stmt) successors.get(0);
00487         Location loc = system.locationOfKey(nextStmt, thread);
00488         // If the next statement is return, then this is the end
00489         // of the thread body, so mark all locals as dead.
00490         if (nextStmt instanceof ReturnVoidStmt)
00491         loc.setLiveVars(new StateVarVector());
00492         return loc;
00493     }
00494     else { // no successors---just make a new location.
00495         Location endLoc = makeLocation();
00496         endLoc.setLiveVars(new StateVarVector());
00497         return endLoc;
00498     }
00499     }
00500     /**
00501      * Get location associated with Jimple Stmt (created if it doesn't exist)
00502      */
00503 
00504     Location locationOfStmt(Unit stmt) {
00505     return system.locationOfKey(stmt, thread);
00506     }
00507     /**
00508      * Build transformations for a lock operation (either wait() or notify()).
00509      */
00510 
00511     void lockOperation(Stmt stmt, VirtualInvokeExpr expr, int opCode) {
00512     // First translate the ref expr that designates the lock object
00513     ExprExtractor extractor = 
00514         new ExprExtractor(system, stmt, localDefs, method, 
00515                   typeExtract, predSet);
00516     expr.getBase().apply(extractor);
00517     edu.ksu.cis.bandera.bir.Expr lockRef = 
00518         (edu.ksu.cis.bandera.bir.Expr)extractor.getResult();
00519     edu.ksu.cis.bandera.bir.Expr lock =  getLockFieldExpr(lockRef);
00520     StateVarVector liveVars = getLiveVars(stmt);
00521     if (opCode == WAIT) {
00522         // For wait(), we make two transformations: a WAIT, then
00523         // an UNWAIT guarded by lockAvailable and wasNotified tests.
00524         Location loc = makeLocation();
00525         makeTrans(locationOfStmt(stmt), loc, null,
00526               new LockAction(lock, WAIT, thread), 
00527               liveVars, stmt, extractor);
00528         LockTest e1 = new LockTest(lock, LOCK_AVAILABLE, thread);
00529         LockTest e2 = new LockTest(lock, WAS_NOTIFIED, thread);
00530         makeTrans(loc, locationOfNextStmt(stmt), 
00531               new edu.ksu.cis.bandera.bir.AndExpr(e1, e2),
00532               new LockAction(lock, UNWAIT, thread),liveVars,null,null);
00533     }
00534     else // notify, notifyAll
00535         makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), null,
00536               new LockAction(lock, opCode, thread), 
00537               liveVars, stmt, extractor);
00538     }
00539     /**
00540      * Create a new location.
00541      */
00542 
00543     Location makeLocation() {
00544     return system.locationOfKey(null, thread);
00545     }
00546     /**
00547      * Make transformation from one location to another with a given
00548      * guard and action.
00549      * <p>
00550      * This is used to create all transformations and is straightforward
00551      * except for handling observable Stmts, some of which might translate
00552      * (by default) to trivial transformations that would then be collapsed
00553      * away by the Reducer.  To prevent this, we test if either the
00554      * Stmt itself is observable (via a ThreadLocTest) or if the Stmt
00555      * contains some expression that is observable (e.g., by reference
00556      * to a global).  If so, we make sure there exists an action to
00557      * mark observable by inserting an empty PrintAction.   
00558      * For thread location tests, we add an extra location just
00559      * after the Stmt---the test will be true at that location
00560      * (note: in this case, two transformations are added).
00561      */
00562 
00563     Transformation makeTrans(Location fromLoc, Location toLoc, 
00564                  edu.ksu.cis.bandera.bir.Expr guard, Action action,
00565                  StateVarVector liveVars, Stmt stmt, 
00566                  ExprExtractor extractor) {
00567     Transformation trans;
00568 
00569     // For observable Stmt, make sure we have action to mark observable
00570     if (observableLoc(stmt) || observableValue(extractor)) {
00571         if (action == null)
00572         action = new PrintAction();  // Null action
00573         action.setObservable(true);
00574     }
00575 
00576     // For statement in location test, add an extra location just after.
00577     // Location test will be true here.
00578     if (observableLoc(stmt)) {
00579         Location afterLoc = makeLocation();
00580         trans = fromLoc.addTrans(afterLoc,guard, new ActionVector(action));
00581         afterLoc.addTrans(toLoc, null, new ActionVector());
00582         // Register this location with the predicate set
00583         predSet.addPredicateLocation(stmt,afterLoc);
00584     } else
00585         trans = fromLoc.addTrans(toLoc, guard, new ActionVector(action));
00586 
00587     // Set live variables and source
00588     fromLoc.setLiveVars(liveVars);
00589     if (stmt != null && action != null)
00590         system.setSource(action, stmt);
00591     return trans;
00592     }
00593     /**
00594      * Generate an BIR equality test for a switch key value to be equal to
00595      * an integer constant.
00596      */
00597 
00598      edu.ksu.cis.bandera.bir.Expr matchCase(edu.ksu.cis.bandera.bir.Expr key, 
00599                         int value) {
00600      edu.ksu.cis.bandera.bir.Expr val = 
00601          new edu.ksu.cis.bandera.bir.IntLit(value);
00602      return new edu.ksu.cis.bandera.bir.EqExpr(key, val);
00603     }
00604     /**
00605      * Check if Stmt is observable (appears in a ThreadLocTest).
00606      */
00607 
00608     boolean observableLoc(Unit stmt) {
00609     return (stmt != null) &&  predSet.isObservable(stmt);
00610     }
00611     /**
00612      * Check if some value extracted from an expression is observable.
00613      */
00614 
00615     boolean observableValue(ExprExtractor extractor) {
00616     return (extractor != null) &&  extractor.isObservable();
00617     }
00618     /**
00619      * This method was used when thread operations were static.
00620      */
00621 
00622     void oldThreadOperation(Stmt stmt, StaticInvokeExpr expr, int opCode) {
00623     SootMethod method = 
00624         expr.getMethod().getDeclaringClass().getMethod("run");
00625     BirThread threadArg = system.threadOfKey(method);
00626     ThreadAction action = new ThreadAction(threadArg,opCode,thread);
00627     StateVarVector liveVars = getLiveVars(stmt);
00628     if (opCode == JOIN) {
00629         Location loc = makeLocation();
00630         makeTrans(locationOfStmt(stmt), loc, null, action, liveVars,
00631               stmt, null);
00632         ThreadTest test = 
00633         new ThreadTest(threadArg, THREAD_TERMINATED, thread);
00634         makeTrans(loc, locationOfNextStmt(stmt), test,null,
00635               liveVars,stmt,null);
00636     }
00637     else 
00638         makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), 
00639               null, action, liveVars, stmt,null);
00640     }
00641     /**
00642      * Construct the transformations for a thread operation (e.g., start()).
00643      * <p>
00644      * Note: this code is very brittle.  The Jimple is expected to be
00645      * in a certain form so that the class defining the thread can be
00646      * found statically.
00647      */
00648 
00649     void threadOperation(Stmt stmt, VirtualInvokeExpr expr, int opCode) {
00650     // For a virtual invoke of the form x.start(), find the
00651     // statement defining x and look at the RHS---it should
00652     // be an allocator for a Thread class (or subclass).
00653     Local runnableLocal = (Local) expr.getBase();
00654     List defsOfUse = localDefs.getDefsOfAt(runnableLocal, stmt);
00655     DefinitionStmt def = (DefinitionStmt) defsOfUse.get(0);
00656 
00657     // May be a chain of assignments through locals
00658     while ( def.getRightOp() instanceof Local ) {
00659       defsOfUse = localDefs.getDefsOfAt((Local)def.getRightOp(), def);
00660       def = (DefinitionStmt) defsOfUse.get(0);
00661         }
00662 
00663     NewExpr alloc = (NewExpr) def.getRightOp();
00664     SootClass threadClass = 
00665         classManager.getClass(alloc.getBaseType().className);
00666 
00667     // If the user has subclassed Thread, then the threadClass
00668     // contains the run() method that defines the thread body.
00669     // However, if the user simply implemented Runnable, then
00670     // the Runnable object passed to the Thread constructor
00671     // contains the run() method and is the class we want.
00672     if (threadClass.getName().equals("java.lang.Thread")) {
00673         // The thread we started is an instance of Thread, so
00674         // we need to find the Runnable object passed to the constructor.
00675         // The argument will be a Local, so find the definition of that
00676         // local, the RHS of which should be an allocator for the
00677         // class we're looking for.
00678         InvokeStmt init = (InvokeStmt) stmtGraph.getSuccsOf(def).get(0);
00679         runnableLocal = (Local)
00680         ((SpecialInvokeExpr)init.getInvokeExpr()).getArg(0);
00681         defsOfUse = localDefs.getDefsOfAt(runnableLocal, init);
00682         def = (DefinitionStmt) defsOfUse.get(0);
00683         alloc = (NewExpr) def.getRightOp();
00684         threadClass = classManager.getClass(alloc.getBaseType().className);
00685     }
00686 
00687     // Find the run method, and from it, we can retrieve the BIR thread
00688     SootMethod runMethod = threadClass.getMethod("run");
00689     BirThread threadArg = system.threadOfKey(runMethod);
00690     ThreadAction threadOp = new ThreadAction(threadArg,opCode,thread);
00691     if (threadArg != null) {
00692         makeTrans(locationOfStmt(stmt), locationOfNextStmt(stmt), 
00693               null, threadOp, getLiveVars(stmt), stmt, null);
00694         return;
00695     }
00696     throw new RuntimeException("Unknown thread operation pattern: " + stmt);
00697     }
00698     /**
00699      * Return true if type represented.
00700      */
00701 
00702     public boolean typeRepresented(Type sootType) {
00703     sootType.apply(typeExtract);
00704     edu.ksu.cis.bandera.bir.Type type = 
00705         (edu.ksu.cis.bandera.bir.Type) typeExtract.getResult();
00706     return (type != null) ;
00707     }
00708 }

Generated at Thu Feb 7 06:57:55 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001