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

BirState.java

00001 package edu.ksu.cis.bandera.bir;
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 ca.mcgill.sable.util.*;
00036 
00037 import java.util.*;
00038 
00039 /**
00040  * A BirState represents a state of a BIR transition system in a trace.
00041  * <p>
00042  * The main parts of the state are:
00043  * <ul>
00044  * <li> A "state vector": 
00045  *    a Literal array storing the value of all state variables 
00046  *    which are laid out as they might be in a compiler.
00047  * <li> A Location array storing the current location of each thread.
00048  * <li> A boolean array indicating whether each thread is active.
00049  * </ul>
00050  * The interface Literal is implemented by a collection of classes
00051  * that represent values of non-composite types (BoolLit, IntLit,
00052  * LockLit, RefLit).  These objects are the contents of the state
00053  * vector.
00054  * <p>
00055  * This class is a BIR expression switch---it translates a BIR expression
00056  * into either a Literal value (the r-value of the expression in this state)
00057  * or an Integer (the address in the state vector of the l-value of
00058  * the expression in this state).   The rules are:
00059  * <ul>
00060  * <li> Any expression with an array or record value always evaluates
00061  *   to the Integer address of that object in the state vector.
00062  * <li> If the LHS flag is set, then any expression will evaluate
00063  *  to the Integer address of that entity in the state vector
00064  *  (in this case, it is an error if the expression is not an l-value).
00065  *  This flag is set to true only while evaluating the left-hand-side of
00066  *  an assignment (since we want the address to update).
00067  * <li> Otherwise, the expression evaluates to a Literal representing
00068  *  the r-value of the expression in this state.
00069  * </ul>
00070  */
00071 
00072 public class BirState extends AbstractExprSwitch 
00073     implements Cloneable, BirConstants {
00074 
00075     TransSystem system;
00076     Literal [] store;            // StateVar values
00077     Location [] location;        // Thread Locations
00078     boolean [] threadActive;     // Thread status (active or inactive)
00079 
00080     boolean lhs = false;         // Translating LHS of assign
00081     int choice;                  // choice for nondeterministic actions
00082     String output = "";          // Output from Bandera.print() stamenets
00083 
00084     BirState(TransSystem system) {
00085     this.system = system;
00086     }
00087     public void applyAction(Action action, int choice) {
00088     this.choice = choice;
00089     action.apply(this);
00090     }
00091     public void caseAddExpr(AddExpr expr)
00092     {
00093     expr.getOp1().apply(this);
00094     ConstExpr op1 = (ConstExpr) getResult();
00095     expr.getOp2().apply(this);
00096     ConstExpr op2 = (ConstExpr) getResult();
00097     setResult(new IntLit(op1.getValue() + op2.getValue()));
00098     }
00099     public void caseAndExpr(AndExpr expr)
00100     {
00101     expr.getOp1().apply(this);
00102     BoolLit op1 = (BoolLit) getResult();
00103     expr.getOp2().apply(this);
00104     BoolLit op2 = (BoolLit) getResult();
00105     setResult(new BoolLit(op1.getValue() && op2.getValue()));
00106     }
00107     public void caseArrayExpr(ArrayExpr expr)
00108     {
00109     boolean saveLhs = lhs;
00110     // Even if we're in LHS mode, eval index in normal mode
00111     // (the index could be a constant, which doesn't have an address)
00112     lhs = false;  
00113     expr.getIndex().apply(this);
00114     ConstExpr index = (ConstExpr) getResult();
00115     lhs = saveLhs;                           // restore mode
00116     expr.getArray().apply(this);
00117     Integer offset = (Integer) getResult();
00118     int address = offset.intValue() + index.getValue() + 1; 
00119     // add 1 to address for length (which is stored in first slot)
00120     if (lhs || expr.getType().isKind(ARRAY|RECORD)) 
00121         setResult(new Integer(address));
00122     else
00123         setResult(store[address]);  
00124     }
00125     public void caseAssertAction(AssertAction assertAction) {
00126     // Assertions do not modify the state
00127     }
00128     /**
00129      * Execute assignment.
00130      */
00131 
00132     public void caseAssignAction(AssignAction assign) 
00133     {
00134     assign.getRhs().apply(this);
00135     Literal val = (Literal) getResult();
00136     lhs = true;
00137     assign.getLhs().apply(this);
00138     Integer index = (Integer) getResult();
00139     lhs = false;
00140     store[index.intValue()] = val;
00141     }
00142     public void caseBoolLit(BoolLit expr)
00143     {
00144         setResult(expr);
00145     }
00146     public void caseChooseExpr(ChooseExpr expr)
00147     {
00148     // Use choice from trace to compute value 
00149     setResult(expr.getChoice(choice));
00150     }
00151     public void caseConstant(Constant expr)
00152     {
00153         setResult(expr);
00154     }
00155     public void caseDerefExpr(DerefExpr expr)
00156     {
00157     // Even if we're in LHS mode, eval ref expr in normal mode
00158     // (it could be null, which has no address)
00159     boolean saveLhs = lhs;
00160     lhs = false;
00161     expr.getTarget().apply(this);
00162     RefLit ref = (RefLit) getResult();
00163     lhs = saveLhs;
00164     int address = ref.getCollection().getOffset();
00165     if (ref.getCollection().getType().isKind(COLLECTION)) 
00166         address += ref.getIndex() * expr.getType().getExtent();
00167     if (lhs || expr.getType().isKind(ARRAY|RECORD)) 
00168         setResult(new Integer(address));
00169     else
00170         setResult(store[address]);  
00171     }
00172     public void caseDivExpr(DivExpr expr)
00173     {
00174     expr.getOp1().apply(this);
00175     ConstExpr op1 = (ConstExpr) getResult();
00176     expr.getOp2().apply(this);
00177     ConstExpr op2 = (ConstExpr) getResult();
00178     setResult(new IntLit(op1.getValue() / op2.getValue()));
00179     }
00180     public void caseEqExpr(EqExpr expr)
00181     {
00182     expr.getOp1().apply(this);
00183     ConstExpr op1 = (ConstExpr) getResult();
00184     expr.getOp2().apply(this);
00185     ConstExpr op2 = (ConstExpr) getResult();
00186     setResult(new BoolLit(op1.getValue() == op2.getValue()));
00187     }
00188     public void caseInstanceOfExpr(InstanceOfExpr expr)
00189     {
00190     expr.getRefExpr().apply(this);
00191     if (getResult() instanceof NullExpr)
00192         // null is an instanceof any ref type
00193         setResult(new BoolLit(true));
00194     else {
00195         StateVar collection = ((RefLit)getResult()).getCollection();
00196         StateVarVector targets = expr.getRefType().getTargets();
00197         setResult(new BoolLit(targets.indexOf(collection) >= 0));
00198     }
00199     }
00200     public void caseIntLit(IntLit expr)
00201     {
00202         setResult(expr);
00203     }
00204     public void caseLeExpr(LeExpr expr)
00205     {
00206     expr.getOp1().apply(this);
00207     ConstExpr op1 = (ConstExpr) getResult();
00208     expr.getOp2().apply(this);
00209     ConstExpr op2 = (ConstExpr) getResult();
00210     setResult(new BoolLit(op1.getValue() <= op2.getValue()));
00211     }
00212     public void caseLengthExpr(LengthExpr expr)
00213     {
00214     expr.getArray().apply(this);
00215     Integer offset = (Integer) getResult();
00216     setResult(store[offset.intValue()]);
00217     }
00218     public void caseLockAction(LockAction lockAction) 
00219     {
00220     lhs = true;
00221     lockAction.getLockExpr().apply(this);
00222     Integer index = (Integer) getResult();
00223     lhs = false;
00224     LockLit lock = (LockLit) store[index.intValue()];
00225     int operation = lockAction.getOperation();
00226     BirThread thread = lockAction.getThread();
00227     store[index.intValue()] = lock.nextState(operation,thread,choice);
00228     }
00229     public void caseLockTest(LockTest lockTest) 
00230     {
00231     lockTest.getLockExpr().apply(this);
00232     LockLit lock = (LockLit) getResult();
00233     setResult(new BoolLit(lock.queryState(lockTest.getOperation(),
00234                           lockTest.getThread())));
00235     }
00236     public void caseLtExpr(LtExpr expr)
00237     {
00238     expr.getOp1().apply(this);
00239     ConstExpr op1 = (ConstExpr) getResult();
00240     expr.getOp2().apply(this);
00241     ConstExpr op2 = (ConstExpr) getResult();
00242     setResult(new BoolLit(op1.getValue() < op2.getValue()));
00243     }
00244     public void caseMulExpr(MulExpr expr)
00245     {
00246     expr.getOp1().apply(this);
00247     ConstExpr op1 = (ConstExpr) getResult();
00248     expr.getOp2().apply(this);
00249     ConstExpr op2 = (ConstExpr) getResult();
00250     setResult(new IntLit(op1.getValue() * op2.getValue()));
00251     }
00252     public void caseNeExpr(NeExpr expr)
00253     {
00254     expr.getOp1().apply(this);
00255     ConstExpr op1 = (ConstExpr) getResult();
00256     expr.getOp2().apply(this);
00257     ConstExpr op2 = (ConstExpr) getResult();
00258     setResult(new BoolLit(op1.getValue() != op2.getValue()));
00259     }
00260     public void caseNewArrayExpr(NewArrayExpr expr)
00261     {
00262     StateVar target = expr.getCollection();
00263     Type type = ((Collection)target.getType()).getBaseType();
00264     BirTypeInit initializer = new BirTypeInit(this);
00265     // Use length computed from trace
00266     int length = target.getActualBaseTypeSize();
00267     int address = target.getOffset() + choice * length;
00268     // Set length field
00269     store[address] = new IntLit(length);
00270     type.apply(initializer,new Integer(address));
00271     setResult(new RefLit(target,choice));
00272     }
00273     public void caseNewExpr(NewExpr expr)
00274     {
00275     StateVar target = expr.getCollection();
00276     Type type = ((Collection)target.getType()).getBaseType();
00277     // Make sure to initialize new object
00278     BirTypeInit initializer = new BirTypeInit(this);
00279     int address = target.getOffset() + choice * type.getExtent();
00280     type.apply(initializer,new Integer(address));
00281     setResult(new RefLit(target,choice));
00282     }
00283     public void caseNotExpr(NotExpr expr)
00284     {
00285     expr.getOp().apply(this);
00286     BoolLit op = (BoolLit) getResult();
00287     setResult(new BoolLit(! op.getValue()));
00288     }
00289     public void caseNullExpr(NullExpr expr)
00290     {
00291     setResult(expr);
00292     }
00293     public void caseOrExpr(OrExpr expr)
00294     {
00295     expr.getOp1().apply(this);
00296     BoolLit op1 = (BoolLit) getResult();
00297     expr.getOp2().apply(this);
00298     BoolLit op2 = (BoolLit) getResult();
00299     setResult(new BoolLit(op1.getValue() || op2.getValue()));
00300     }
00301     public void casePrintAction(PrintAction printAction) 
00302     {
00303     // Dump the output of Bandera.print() to the 'output' string
00304     Vector printItems = printAction.getPrintItems();
00305     for (int i = 0; i < printItems.size(); i++) {
00306         Object item = printItems.elementAt(i);
00307         if (item instanceof String)
00308         output += item;
00309         else {
00310         ((Expr)item).apply(this);
00311         output += getResult().toString();
00312         }
00313     }
00314     output += "\n";
00315     }
00316     public void caseRecordExpr(RecordExpr expr)
00317     {
00318     expr.getRecord().apply(this);
00319     Integer offset = (Integer) getResult();
00320     int address = offset.intValue() + expr.getField().getOffset();
00321     if (lhs || expr.getType().isKind(ARRAY|RECORD)) 
00322         setResult(new Integer(address));
00323     else
00324         setResult(store[address]);  
00325     }
00326     public void caseRefExpr(RefExpr expr)
00327     {
00328     setResult(new RefLit(expr.getTarget(),0));
00329     }
00330     public void caseRemExpr(RemExpr expr)
00331     {
00332     expr.getOp1().apply(this);
00333     ConstExpr op1 = (ConstExpr) getResult();
00334     expr.getOp2().apply(this);
00335     ConstExpr op2 = (ConstExpr) getResult();
00336     setResult(new IntLit(op1.getValue() % op2.getValue()));
00337     }
00338     public void caseStateVar(StateVar expr)
00339     {
00340     if (lhs || expr.getType().isKind(ARRAY|RECORD|COLLECTION)) 
00341         setResult(new Integer(expr.getOffset()));
00342     else
00343         setResult(store[expr.getOffset()]);
00344     }
00345     public void caseSubExpr(SubExpr expr)
00346     {
00347     expr.getOp1().apply(this);
00348     ConstExpr op1 = (ConstExpr) getResult();
00349     expr.getOp2().apply(this);
00350     ConstExpr op2 = (ConstExpr) getResult();
00351     setResult(new IntLit(op1.getValue() - op2.getValue()));
00352     }
00353     public void caseThreadAction(ThreadAction threadAction) 
00354     {
00355     if (threadAction.isStart()) 
00356         threadActive[threadAction.getThreadArg().getId()] = true;
00357     else if (threadAction.isExit())
00358         threadActive[threadAction.getThread().getId()] = false;
00359     }
00360     public void caseThreadLocTest(ThreadLocTest threadLocTest) 
00361     {
00362     setResult(new BoolLit(location[threadLocTest.getThread().getId()]
00363                   == threadLocTest.getLocation()));
00364     }
00365     public void caseThreadTest(ThreadTest threadTest) 
00366     {
00367     boolean done = ! threadActive[threadTest.getThreadArg().getId()];
00368     setResult(new BoolLit(done));
00369     }
00370     /**
00371      * Update thread location once all transformation actions have completed.
00372      */
00373 
00374     public void completeTrans(Transformation trans) {
00375     Location toLoc = trans.getToLoc();
00376     location[toLoc.getThread().getId()] = toLoc;
00377     }
00378     /**
00379      * Make a copy of this state
00380      */
00381 
00382     public BirState copy() {
00383     BirState result = new BirState(system);
00384     result.store = (Literal []) store.clone();
00385     result.location = (Location []) location.clone();
00386     result.threadActive = (boolean []) threadActive.clone();
00387     result.output = output;
00388     return result;
00389     }
00390     public void defaultCase(Object obj)
00391     {
00392     throw new RuntimeException("Forgot to handle case: " + obj);
00393     }
00394     public String exprValue(Expr expr) {
00395     expr.apply(this);
00396     if (expr.getType().isKind(ARRAY|RECORD))
00397         return "Object";
00398     else 
00399         return getResult().toString();
00400     }
00401     public String getOutput() { return output; }
00402     public Literal [] getStore() { return store; }
00403     public TransSystem getSystem() { return system; }
00404     /**
00405      * Build the initial state of a BIR transition system.
00406      */
00407 
00408     public static BirState initialState(TransSystem system, 
00409                     TransVector transVector,
00410                     Vector choiceVector) {
00411     int stateSize = 
00412         setActualSizesFromTrace(system,transVector,choiceVector);
00413     BirState state = new BirState(system);
00414     state.location = new Location[system.getThreads().size()];
00415     state.threadActive = new boolean[system.getThreads().size()];
00416     state.store = new Literal[stateSize];
00417 
00418     // Initialize each state variable using BIR type initializer
00419     BirTypeInit initializer = new BirTypeInit(state);
00420     StateVarVector vars = system.getStateVars();
00421     for (int i = 0; i < vars.size(); i++) {
00422         StateVar var = vars.elementAt(i);
00423         var.getType().apply(initializer,var);
00424     }
00425 
00426     // Initialize thread loc and active vars
00427     ThreadVector threads = system.getThreads();
00428     for (int i = 0; i < threads.size(); i++) {
00429         BirThread thread = threads.elementAt(i);
00430         state.location[thread.getId()] = thread.getStartLoc();
00431         state.threadActive[thread.getId()] = thread.isMain();
00432     }
00433 
00434     return state;
00435     }
00436     public boolean isActive(BirThread thread) { 
00437     return threadActive[thread.getId()];
00438     }
00439     public void print() {
00440     System.out.println("STATE");
00441     for (int i = 0; i < store.length; i++)
00442         System.out.print(store[i] + " ");
00443     System.out.println();
00444     ThreadVector threads = system.getThreads();
00445     for (int i = 0; i < threads.size(); i++) {
00446         BirThread thread = threads.elementAt(i);
00447         if (threadActive[thread.getId()])
00448         System.out.println("    " + thread.getName() + " at " +
00449                    location[thread.getId()].getLabel());
00450     }
00451     BirTypePrint printer = new BirTypePrint(this);
00452     StateVarVector vars = system.getStateVars();
00453     for (int i = 0; i < vars.size(); i++) {
00454         StateVar var = vars.elementAt(i);
00455         System.out.print("    " + var.getName() + " = ");
00456         var.getType().apply(printer,var);
00457         System.out.println();
00458     }   
00459     }
00460     /**
00461      * Given the trace, compute the size of the state vector (which
00462      * holds the values of all state variables).
00463      * <p>
00464      * This used to be done statically given the collection
00465      * bounds in the BIR, but with dynamic verifiers like dSPIN
00466      * (which ignore these bounds), we don't know how many
00467      * collection elements are allocated until we see the trace.
00468      * <p>
00469      * We also set the choice for each Allocator action to indicate
00470      * the index into the collection of the instance that was allocated 
00471      * (this is just a count of the number allocated so far).  
00472      * Note that for NewArrayExpr, the choice that comes in is
00473      * the actual length---we reset it to the instance index
00474      * (the max length for the collection is computed and stored
00475      * in the collection).
00476      */
00477     public static int setActualSizesFromTrace(TransSystem system, 
00478                           TransVector transVector,
00479                           Vector choiceVector) {
00480     // Count number of allocator calls in trace for each collection
00481     // Also, for arrays, calculate max size of array in each collection
00482     StateVarVector vars = system.getStateVars();
00483     StateVarVector targets = system.refAnyType().getTargets();
00484     int numAlloc [] = new int[targets.size()]; 
00485     int maxArrayLength [] = new int[targets.size()]; 
00486 
00487     for (int i = 0; i < transVector.size(); i++) {
00488         ActionVector actions = transVector.elementAt(i).getActions();
00489         int choices [] = (int []) choiceVector.elementAt(i);
00490         for (int j = 0; j < actions.size(); j++) {
00491         Action action = actions.elementAt(j);
00492         if (action.isAssignAction()) {
00493             Expr rhs = ((AssignAction)action).getRhs();
00494 
00495             // When we see an allocator, find the target and
00496             // update the instance count.  For arrays,
00497             // also update the max array size.
00498             if (rhs instanceof Allocator) {
00499             int targetNum = 
00500                 targets.indexOf(((Allocator)rhs).getCollection());
00501             if (rhs instanceof NewArrayExpr) {
00502                 int arrayLength = choices[j];
00503                 if (arrayLength > maxArrayLength[targetNum])
00504                 maxArrayLength[targetNum] = arrayLength;
00505             }
00506             // Set choice for alloc action to # of instance alloced
00507             choices[j] = numAlloc[targetNum];
00508             numAlloc[targetNum] += 1;
00509             }
00510         }
00511         }
00512     }
00513 
00514     // Now assign each variable an offset, using the allocator counts
00515     // to determine the size of collections.  Note that we use the 
00516     // term "extent" to denote the number of memory slots needed
00517     // by a variable, while "size" denotes the number of components
00518     // (e.g., array or collection elements).
00519     int currentStateSize = 0;
00520     for (int i = 0; i < vars.size(); i++) {
00521         StateVar var = vars.elementAt(i);
00522         var.setOffset(currentStateSize);
00523         int varExtent = 0;
00524         if (var.getType().isKind(COLLECTION)) {
00525         int targetNum = targets.indexOf(var);
00526         int numItems = numAlloc[targetNum];
00527         var.setActualSize(numItems);
00528         Type baseType = ((Collection)var.getType()).getBaseType();
00529         int itemExtent = baseType.getExtent();
00530         if (baseType.isKind(ARRAY)) {
00531             int elementExtent = 
00532             ((Array)baseType).getBaseType().getExtent();
00533             int arraySize = maxArrayLength[targetNum];
00534             var.setActualBaseTypeSize(arraySize);
00535             itemExtent = 1 + arraySize * elementExtent;
00536             // Extra 1 for length field  
00537         }
00538         var.setActualBaseTypeExtent(itemExtent);
00539         // Extent of collection depends on # items and their extent
00540         varExtent = numItems * itemExtent;
00541         }
00542         else  // Extent of normal variable is just extent of its type
00543         varExtent = var.getType().getExtent();
00544         currentStateSize += varExtent;
00545         System.out.println(" Var " + var + " extent = " + varExtent);
00546     }
00547     return currentStateSize;
00548     }
00549 }

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