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

SmvTrans.java

00001 package edu.ksu.cis.bandera.smv;
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 import java.util.Hashtable;
00038 
00039 import edu.ksu.cis.bandera.bir.*;
00040 import edu.ksu.cis.bandera.checker.*;
00041 import java.util.List;
00042 
00043 /**
00044  * SmvTrans is the main class of the SMV translator, which generates
00045  * SMV source representing a transition system.
00046  * <p>
00047  * The SMV translator is invoked on a transition system as follows:
00048  * <pre>
00049  * // Parameters 
00050  * TransSystem system = ...;   // the transition system
00051  * SmvOptions options = new SmvOptions();        // Options
00052  * options.setSafety(true);          // Safety property
00053  * options.setInterleaving(true);    // Interleaving (vs. simulataneous) model
00054  * SmvTrans smv = SmvTrans.translate(sys,options);   // Generate input
00055  * smv.runSmv();   // Run nusmv
00056  * BirTrace trace = smv.parseOutput();   // Parse the output
00057  * </pre>
00058  */
00059 
00060 public class SmvTrans extends AbstractExprSwitch implements BirConstants, Checker
00061 {
00062     TransSystem system;
00063     PrintWriter out;             // Destination for translator output
00064 
00065     boolean ranVerifier;         // Was the verifier run (using runSmv())?
00066 
00067     SmvOptions options;          // Options for translation:
00068     boolean liveness;            //   liveness property (vs. safety)
00069     boolean ctlproperty;         //   ctl property (vs. deadlock)
00070     boolean interleaving;        //   interleaving model (vs. simulataneous)
00071 
00072     int indentLevel = 0;         // Indentation level in output
00073     boolean newLine = true;      // At beginning of line in output?
00074 
00075     Hashtable varTable = new Hashtable();  // Maps name (String) -> SmvVar
00076     Vector varList = new Vector();         // Holds all SmvVars
00077 
00078     Hashtable guardTable = new Hashtable();  // Maps guard Exprs -> SmvExpr
00079     // (so we don't translate a given guard expression more than once)
00080 
00081     int maxCollectionSize;  // Size of largest collection
00082     String threadType;      // SMV type for thread = "{ NoThread, T1, T2 ... }"
00083 
00084     Transformation currentTrans;        // Current trans being processed
00085     SmvExpr currentGuard;               // Guard of that trans
00086 
00087     SmvVar choiceVar;    // Choice variable (nondeterministic)
00088     SmvVar trapVar;      // Trap variable (holds trap name)
00089     SmvVar runningVar;   // Running variable (holds name of thread taking step)
00090     
00091 
00092     final static SmvLit ZERO = new SmvLit("0");
00093     final static SmvLit ONE = new SmvLit("1");
00094     final static SmvLit NOTHREAD = new SmvLit("NoThread");
00095     final static String TRAP_TYPE = 
00096     "{ None, NullPointerException, ArrayBoundsException, ClassCastException, RangeLimitException, CollectionLimitException, ArrayLimitException }";
00097 
00098     // This type controls the number of times a thread may reacquire a lock
00099     final static String LOCK_COUNT_TYPE = "0 .. 3"; 
00100 
00101     // Variables used in parsing SMV output
00102     boolean doneParsing;         // finished
00103     boolean foundFalse;         // finished
00104     boolean foundTrace;          // found a counterexample in the output
00105     int stateCount;              // Number of states in counterexample so far
00106     Location [] threadLocs;      // Current location of each thread in trace
00107     Transformation lastTrans;    // Last transform from trace
00108     Hashtable threadTable;       // Maps name of thread -> thread ID
00109 
00110     // Vars for execAndWait()
00111     static Runtime runtime = Runtime.getRuntime();
00112     static final int BUFSIZE = 50000;
00113     static byte [] buffer = new byte[BUFSIZE];
00114     SmvTrans(TransSystem system, SmvOptions options, PrintWriter out) {
00115     this.system = system;
00116     this.options = options;
00117     this.out = out;
00118     liveness = ! options.getSafety();
00119     ctlproperty = options.getProperty();
00120     interleaving = options.getInterleaving();
00121 
00122     // Build thread type
00123     ThreadVector threads = system.getThreads();
00124     threadType = "NoThread";
00125     for (int i = 0; i < threads.size(); i++) 
00126         threadType += ", " + threads.elementAt(i).getName();
00127     threadType = "{ " + threadType + " }";
00128     }
00129     // These functions define how the SMV variables are assigned names
00130 
00131     String activeVar(BirThread thread) {
00132     return thread.getName() + "_active";
00133     }
00134     /**
00135      * Add the conditional context to an N-ary AND-expression.
00136      * <p>
00137      * The context passed is an SmvCase that is part of a case tree.
00138      * The condition on every ancestor of the conext is added to the 
00139      * AND-expression.  The context can be null, in which case
00140      * nothing is added.
00141      */
00142 
00143     SmvNaryExpr addConditionalContext(SmvNaryExpr expr, SmvCase context) {
00144     while (context != null) {
00145         expr.add(context.cond);
00146         context = context.parent.outerCase;
00147     }
00148     return expr;
00149     }
00150     SmvExpr and(SmvExpr expr1, SmvExpr expr2) 
00151     {
00152     return new SmvBinaryExpr("&",expr1,expr2);
00153     }
00154     /**
00155      * Generate SMV expression that says var becomes expr in next state.
00156      * <p>
00157      * To simplify reference assignments (from one var to another),
00158      * we test to see if the var is an aggregate (which means its a reference)
00159      * and if the expr is also a variable---in which case we generate
00160      * a conjunction saying each component is equal (this avoid the
00161      * multiplication that would otherwise be generated to view
00162      * the reference as a single value).
00163      */
00164 
00165     static SmvExpr becomes(SmvVar var, SmvExpr expr) 
00166     {
00167     if (var.getComponents().size() > 0 && (expr instanceof SmvVar)) {
00168         SmvNaryExpr componentsEqual = new SmvNaryExpr("&",ONE,true);
00169         for (int i = 0; i < var.getComponents().size(); i++) 
00170         componentsEqual.add(becomes(var.getComponent(i),
00171                         ((SmvVar)expr).getComponent(i)));
00172         return componentsEqual;
00173     } else
00174         return new SmvBinaryExpr("=",new SmvNextExpr(var),expr);
00175     }
00176     String blockedVar(BirThread thread) {
00177     return thread.getName() + "_blocked";
00178     }
00179     /**
00180      * Build an expression for a given transformation.
00181      */
00182 
00183     SmvExpr buildTransExpr(Transformation trans, StateVarVector locals,
00184                SmvVar locVar) {
00185     currentTrans = trans;
00186     Expr guard = trans.getGuard();
00187 
00188     // We cache the translation of the guard expression so we 
00189     // don't need to repeat it
00190     currentGuard = (guard == null) ? ONE : translate(guard);
00191     guardTable.put(trans,currentGuard);
00192     // Start with basic transTaken expr (loc updated and guard true)
00193     SmvNaryExpr transExpr = transTakenExpr(trans);
00194 
00195     // If the trans has an assignment to a local, we process that,
00196     // else check for updates to globals
00197     AssignAction localAssign = findLocalAssign(trans);
00198     if (localAssign == null)
00199         recordGlobalVarUpdates();
00200 
00201     // If live local set specifed, use that, else assume all locals live
00202     StateVarVector liveLocals = locals;
00203     if (trans.getToLoc().getLiveVars() != null)
00204         liveLocals = trans.getToLoc().getLiveVars();
00205 
00206     // Each live local is either assigned by the trans or left unchanged
00207     for (int i = 0; i < liveLocals.size() ; i++) {
00208         StateVar local = liveLocals.elementAt(i);
00209         SmvVar localVar = getVar(local.getName());
00210         if (localAssign != null && localAssign.getLhs().equals(local)) {
00211         SmvExpr rhsExpr = translate(localAssign.getRhs());
00212         checkAssign(local,localAssign.getRhs(),localVar,rhsExpr);
00213         transExpr.add(becomes(localVar,rhsExpr));
00214         } else // local unchanged
00215         transExpr.add(becomes(localVar,localVar));
00216     }
00217 
00218     // For liveness properties, update T_idle
00219     if (liveness) {
00220         SmvVar idleVar = getVar(idleVar(trans.getFromLoc().getThread()));
00221         transExpr.add(becomes(idleVar,ZERO));
00222     }
00223 
00224     currentTrans = null;
00225     currentGuard = null;
00226     return transExpr;
00227     }
00228     public void caseAddExpr(AddExpr expr)
00229     {
00230        translateBinaryOp(expr.getOp1(), expr.getOp2(), "+");
00231     }
00232     public void caseAndExpr(AndExpr expr)
00233     {
00234        translateBinaryOp(expr.getOp1(), expr.getOp2(), "&");
00235     }
00236     /**
00237      * Build an SMV expression for a BIR array selection.
00238      */
00239 
00240     public void caseArrayExpr(ArrayExpr expr) {
00241     SmvExpr array = translate(expr.getArray());
00242     SmvExpr index = translate(expr.getIndex());
00243     int size = ((Array)expr.getArray().getType()).getSize().getValue();
00244 
00245     if (array instanceof SmvCaseExpr) { // array on heap (from Deref)
00246         Vector cases = ((SmvCaseExpr)array).collectCases(new Vector());
00247         for (int i = 0; i < cases.size(); i++) {
00248         SmvCase smvCase = (SmvCase) cases.elementAt(i);
00249         SmvVar arrayVar = (SmvVar) smvCase.expr;
00250         SmvCaseExpr elemSelect = new SmvCaseExpr();
00251         for (int j = 0; j < size; j++) {
00252             SmvLit elemNum = new SmvLit("" + j);
00253             SmvExpr elemCond = new SmvBinaryExpr("=",index,elemNum);
00254             SmvVar elem = getVar(elementVar(arrayVar.getName(),j));
00255             elemSelect.addCase(elemCond,elem);
00256         }
00257         smvCase.updateCase(elemSelect);
00258         }
00259         setResult(array);  // Leaf cases have been modified
00260 
00261     } else if (array instanceof SmvVar) { // Singleton array
00262         SmvVar arrayVar = (SmvVar) array;
00263         SmvCaseExpr elemSelect = new SmvCaseExpr();
00264         for (int j = 0; j < size; j++) {
00265         SmvLit elemNum = new SmvLit("" + j);
00266         SmvExpr elemCond = new SmvBinaryExpr("=",index,elemNum);
00267         SmvVar elem = getVar(elementVar(arrayVar.getName(),j));
00268         elemSelect.addCase(elemCond,elem);
00269         }
00270         setResult(elemSelect);
00271     } else
00272         throw new RuntimeException("Unexpected array expr: " + expr);
00273     }
00274     public void caseBoolLit(BoolLit expr)
00275     {
00276     setResult(new SmvLit(expr.getValue() ? "1" : "0"));
00277     }
00278     /**
00279      * Build an SMV expression for a choose() operation.
00280      * <p>
00281      * Given choices C0, C1, ..., CN, we generate:
00282      * <pre>
00283      *   case
00284      *     choiceVar = 0 : C0;
00285      *     choiceVar = 1 : C1;
00286      *     ...
00287      *     1 : CN;
00288      *   esac
00289      * </pre>
00290      * where choiceVar is an unconstrained variable.
00291      */
00292 
00293     public void caseChooseExpr(ChooseExpr expr)
00294     {
00295     Vector choices = expr.getChoices();
00296     SmvCaseExpr choose = new SmvCaseExpr();
00297     for (int i = 0; i < choices.size() ; i++) {
00298         SmvExpr val = translate((Expr)choices.elementAt(i));
00299         SmvExpr test = (i + 1 == choices.size()) ? ONE : 
00300         equal(choiceVar,new SmvLit("" + i));
00301         choose.addCase(test,val);
00302     }
00303     setResult(choose);
00304     }
00305     public void caseConstant(Constant expr)
00306     {
00307     setResult(new SmvLit(expr.getName()));
00308     }
00309     /**
00310      * Generate an SMV expression for a BIR dereference.
00311      */
00312 
00313     public void caseDerefExpr(DerefExpr expr) {
00314     // Can assume ref expr is simple variable
00315     SmvVar refVar = (SmvVar) translate((StateVar)expr.getTarget());
00316     SmvVar refIndexVar = refVar.getComponent(0);
00317     SmvVar instNumVar = refVar.getComponent(1);
00318     StateVarVector targets = 
00319         ((Ref)expr.getTarget().getType()).getTargets();
00320     // Build nested case expressions: outer selects collection
00321     SmvCaseExpr colSelect = new SmvCaseExpr();
00322     for (int i = 0; i < targets.size(); i++) {
00323         StateVar target = targets.elementAt(i);
00324         SmvLit refIndexVal = new SmvLit("" + refIndex(target));
00325         SmvExpr cond = equal(refIndexVar,refIndexVal);
00326 
00327         // inner selects instance of collection (unless target singleton).
00328         if (target.getType().isKind(COLLECTION)) {
00329         SmvCaseExpr instSelect = new SmvCaseExpr();
00330         int size = ((Collection)target.getType()).getSize().getValue();
00331         for (int j = 0; j < size; j++) {
00332             SmvLit instNumVal = new SmvLit("" + j);
00333             SmvExpr instCond = equal(instNumVar,instNumVal);
00334             SmvVar inst = getVar(instanceVar(target.getName(),j));
00335             instSelect.addCase(instCond,inst);
00336         }
00337         colSelect.addCase(cond,instSelect);
00338         } else {  // Singleton
00339         SmvVar singleton = getVar(target.getName());
00340         colSelect.addCase(cond,singleton);
00341         }
00342     }
00343     
00344     // Check for null reference (refIndex = 0) and set trap
00345     SmvNaryExpr couldBeTaken = transCouldBeTakenExpr(currentTrans);
00346     couldBeTaken.add(equal(refIndexVar,ZERO));
00347     trapVar.addUpdate(couldBeTaken,
00348               becomes(trapVar,new SmvLit("NullPointerException")));
00349 
00350     setResult(colSelect);
00351     }
00352     public void caseDivExpr(DivExpr expr)
00353     {
00354        translateBinaryOp(expr.getOp1(), expr.getOp2(), "/");
00355     }
00356     public void caseEqExpr(EqExpr expr)
00357     {
00358     SmvExpr expr1 = translate(expr.getOp1());
00359     SmvExpr expr2 = translate(expr.getOp2());
00360     setResult(equal(expr1,expr2));
00361     }
00362     /**
00363      * Build SMV expr to check if object is instanceof class.
00364      * <p>
00365      * We use an SMV set expression to test if the refIndex var
00366      * of the reference is "in" the set of refIndexes of
00367      * the class/interface.
00368      */
00369 
00370     public void caseInstanceOfExpr(InstanceOfExpr expr)
00371     {
00372     // This could be generalized to handle case trees
00373     // but this suffices for the current Jimple/BIRC-generated BIR.
00374     if (! (expr.getRefExpr() instanceof StateVar))
00375         throw new RuntimeException("InstanceOf must apply to var"); 
00376     SmvVar refVar = (SmvVar) translate(expr.getRefExpr());
00377     SmvVar refIndexVar = getVar(refIndexVar(refVar.getName()));
00378     StateVarVector targets = expr.getRefType().getTargets();
00379     String indexSet = "";
00380     for (int j = 0; j < targets.size(); j++) {
00381         StateVar target = targets.elementAt(j);
00382         if (j > 0) indexSet += ", ";
00383         indexSet += refIndex(target);
00384     }
00385     SmvLit set = new SmvLit("{ " + indexSet + " }");
00386     setResult(new SmvBinaryExpr("in",refIndexVar,set));
00387     }
00388     public void caseIntLit(IntLit expr)
00389     {
00390     setResult(new SmvLit("" + expr.getValue()));
00391     }
00392     public void caseLeExpr(LeExpr expr)
00393     {
00394         translateBinaryOp(expr.getOp1(), expr.getOp2(), "<=");
00395     }
00396     /**
00397      * Build SMV expr to retrieve array length.
00398      */
00399 
00400     public void caseLengthExpr(LengthExpr expr)
00401     {
00402     SmvExpr array = translate(expr.getArray());
00403     if (array instanceof SmvCaseExpr) { //  array on heap (from Deref)
00404         Vector cases = ((SmvCaseExpr)array).collectCases(new Vector());
00405         for (int i = 0; i < cases.size(); i++) {
00406         SmvCase smvCase = (SmvCase) cases.elementAt(i);
00407         SmvVar arrayVar = (SmvVar) smvCase.expr;
00408         SmvVar lengthVar = getVar(lengthVar(arrayVar.getName()));
00409         smvCase.updateCase(lengthVar);
00410         }
00411         setResult(array);  // Leaf cases have been modified
00412     } else if (array instanceof SmvVar) { // static array
00413         SmvVar arrayVar = (SmvVar) array;
00414         SmvVar lengthVar = getVar(lengthVar(arrayVar.getName()));
00415         setResult(lengthVar);
00416     } else
00417         throw new RuntimeException("Unexpected array expr: " + expr);
00418     }
00419     /**
00420      * Build an SMV expression for a lock test.
00421      */
00422 
00423     public void caseLockTest(LockTest lockTest) {
00424     BirThread thread = lockTest.getThread();
00425     SmvExpr lock = translate(lockTest.getLockExpr());
00426     Vector cases;
00427     if (lock instanceof SmvCaseExpr) {  // lock on heap (from Deref)
00428         cases = ((SmvCaseExpr)lock).collectCases(new Vector());
00429         setResult(lock);  // cases updated below
00430     } else
00431         throw new RuntimeException("Unexpected lock expr: " + lock);
00432     switch (lockTest.getOperation()) {
00433     case LOCK_AVAILABLE:
00434         for (int i = 0; i < cases.size(); i++) {
00435         SmvCase smvCase = (SmvCase) cases.elementAt(i);
00436         SmvVar lockVar = (SmvVar) smvCase.expr;
00437         SmvVar ownerVar = getVar(ownerVar(lockVar.getName()));
00438         SmvExpr free = equal(ownerVar,NOTHREAD);
00439         SmvExpr relock = equal(ownerVar,new SmvLit(thread.getName()));
00440         SmvExpr avail = new SmvBinaryExpr("|",free,relock);
00441         smvCase.updateCase(avail);
00442         }
00443         return;
00444     case HAS_LOCK:
00445         setResult(ONE);  // Not used in this translation
00446         return;
00447     case WAS_NOTIFIED:
00448         for (int i = 0; i < cases.size(); i++) {
00449         SmvCase smvCase = (SmvCase) cases.elementAt(i);
00450         SmvVar lockVar = (SmvVar) smvCase.expr;
00451         SmvVar waitVar = getVar(waitVar(lockVar.getName(),thread));
00452         smvCase.updateCase(not(waitVar));
00453         }
00454         return;     
00455     }   
00456     }
00457     public void caseLtExpr(LtExpr expr)
00458     {
00459         translateBinaryOp(expr.getOp1(), expr.getOp2(), "<");
00460     }
00461     public void caseMulExpr(MulExpr expr)
00462     {
00463        translateBinaryOp(expr.getOp1(), expr.getOp2(), "*");
00464     }
00465     public void caseNeExpr(NeExpr expr)
00466     {
00467     SmvExpr expr1 = translate(expr.getOp1());
00468     SmvExpr expr2 = translate(expr.getOp2());
00469     SmvExpr equals = equal(expr1,expr2);
00470     setResult(not(equals));
00471     }
00472     /**
00473      * Build SMV expression for array allocator.
00474      * <p>
00475      * Similar to NewExpr, but must initialize length/contents of array.
00476      */
00477 
00478     public void caseNewArrayExpr(NewArrayExpr expr)
00479     {
00480     // First, generate the case expr that gives the value of
00481     // the allocator (depending on the current values of the inuse vars)
00482     StateVar target = expr.getCollection();
00483     String collectName = target.getName();
00484     int size = ((Collection)target.getType()).getSize().getValue();
00485     int refIndex = refIndex(target);
00486     SmvExpr setLength = translate(expr.getLength());
00487     SmvCaseExpr instNum = new SmvCaseExpr();
00488     for (int i = 0; i < size; i++) {
00489         SmvVar inuse = getVar(inUseVar(collectName,i));
00490         instNum.addCase(not(inuse), refValue(refIndex,i));
00491     }
00492 
00493     // Then record the potential updates to the inuse vars
00494     // when this trans executes: inuse_i changes from 0 to 1
00495     // if this trans is executed when inuse_j = 1 for all j < i
00496     for (int i = 0; i < size; i++) {
00497         SmvNaryExpr taken = transTakenExpr(currentTrans);
00498         SmvVar inuse_i = getVar(inUseVar(collectName,i));
00499         for (int j = 0; j < i; j++) {
00500         SmvVar inuse_j = getVar(inUseVar(collectName,j));
00501         taken.add(equal(inuse_j,ONE));
00502         }
00503         taken.add(equal(inuse_i,ZERO));
00504         inuse_i.addUpdate(taken,becomes(inuse_i,ONE));
00505 
00506         // Also initialize the length and elements of the newly allocated
00507         // array
00508         SmvVar instVar = getVar(instanceVar(collectName,i));
00509         Array type = (Array) ((Collection)target.getType()).getBaseType();
00510         int maxLen = type.getSize().getValue();
00511         SmvVar lengthVar = getVar(lengthVar(instVar.getName()));
00512         lengthVar.addUpdate(taken,becomes(lengthVar,setLength));
00513         for (int j = 0; j < maxLen; j++) {
00514         SmvVar elemVar = getVar(elementVar(instVar.getName(),j));
00515         initAllComponents(elemVar,taken);
00516         }
00517     }
00518 
00519     setResult(instNum);
00520     }
00521     /**
00522      * Build SMV expression for allocator.
00523      */
00524 
00525     public void caseNewExpr(NewExpr expr)
00526     {
00527     // First, generate the case expr that gives the value of
00528     // the allocator (depending on the current values of the inuse vars):
00529     //   case 
00530     //     ! inuse0 : 0;   // actually need refValue of instance 0, not 0
00531     //     ! inuse1 : 1;
00532     //     ...
00533     //   esac
00534     StateVar target = expr.getCollection();
00535     String collectName = target.getName();
00536     int refIndex = refIndex(target);
00537     int size = ((Collection)target.getType()).getSize().getValue();
00538     SmvCaseExpr instNum = new SmvCaseExpr();
00539     for (int i = 0; i < size; i++) {
00540         SmvVar inuse = getVar(inUseVar(collectName,i));
00541         instNum.addCase(not(inuse), refValue(refIndex,i));
00542     }
00543 
00544     // Then record the potential updates to the inuse vars
00545     // when this trans executes: inuse_i changes from 0 to 1
00546     // if this trans is executed when inuse_j = 1 for all j < i
00547     for (int i = 0; i < size; i++) {
00548         SmvNaryExpr taken = transTakenExpr(currentTrans);
00549         SmvVar inuse_i = getVar(inUseVar(collectName,i));
00550         for (int j = 0; j < i; j++) {
00551         SmvVar inuse_j = getVar(inUseVar(collectName,j));
00552         taken.add(equal(inuse_j,ONE));
00553         }
00554         taken.add(equal(inuse_i,ZERO));
00555         inuse_i.addUpdate(taken,becomes(inuse_i,ONE));
00556 
00557         // Also initialize all variables in the newly allocated item
00558         SmvVar instVar = getVar(instanceVar(collectName,i));
00559         initAllComponents(instVar,taken);
00560     }
00561 
00562     setResult(instNum);
00563     }
00564     public void caseNotExpr(NotExpr expr)
00565     {
00566     translateUnaryOp(expr.getOp(),"!");
00567     }
00568     public void caseNullExpr(NullExpr expr)
00569     {
00570     setResult(ZERO);
00571     }
00572     public void caseOrExpr(OrExpr expr)
00573     {
00574        translateBinaryOp(expr.getOp1(), expr.getOp2(), "|");
00575     }
00576     /**
00577      * Build SMV expression for record field selection.
00578      */
00579 
00580     public void caseRecordExpr(RecordExpr expr) {
00581     SmvExpr record = translate(expr.getRecord());
00582     Field field = expr.getField();
00583     if (record instanceof SmvCaseExpr) {  // record on heap (from Deref)
00584         Vector cases = ((SmvCaseExpr)record).collectCases(new Vector());
00585         for (int i = 0; i < cases.size(); i++) {
00586         SmvCase smvCase = (SmvCase) cases.elementAt(i);
00587         SmvVar recVar = (SmvVar) smvCase.expr;
00588         SmvVar fieldVar = getVar(fieldVar(recVar.getName(),field));
00589         smvCase.updateCase(fieldVar);
00590         }
00591         setResult(record);  // Leaves updates
00592 
00593     } else if (record instanceof SmvVar) { // static record
00594         setResult(getVar(fieldVar(((SmvVar)record).getName(),field)));
00595     } else
00596         throw new RuntimeException("Unexpected record expr: " + expr);
00597     }
00598     public void caseRefExpr(RefExpr expr)
00599     {
00600     setResult(refValue(refIndex(expr.getTarget()),0));
00601     }
00602     public void caseRemExpr(RemExpr expr)
00603     {
00604        translateBinaryOp(expr.getOp1(), expr.getOp2(), "mod");
00605     }
00606     public void caseStateVar(StateVar expr)
00607     {
00608     setResult(getVar(expr.getName()));
00609     }
00610     public void caseSubExpr(SubExpr expr)
00611     {
00612        translateBinaryOp(expr.getOp1(), expr.getOp2(), "-");
00613     }
00614     public void caseThreadLocTest(ThreadLocTest threadLocTest) 
00615     {
00616     SmvVar threadLocVar = getVar(locVar(threadLocTest.getThread()));
00617     SmvLit locName = new SmvLit(locName(threadLocTest.getLocation()));
00618     SmvExpr testExpr = new SmvBinaryExpr("=",threadLocVar,locName);
00619     setResult(testExpr);
00620     }
00621     public void caseThreadTest(ThreadTest threadTest) {
00622     switch (threadTest.getOperation()) {
00623     case THREAD_TERMINATED:
00624         SmvVar activeVar = getVar(activeVar(threadTest.getThreadArg()));
00625         setResult(not(activeVar));
00626         return;
00627     }   
00628     }
00629     public String check() { return runSmv(); }
00630     /**
00631      * Check an assignment for ClassCastExceptions (updating trapVar).
00632      * Check an assignment for IntLimitExceptions (updating trapVar).
00633      */
00634 
00635     void checkAssign(StateVar lhs, Expr rhs, SmvVar var, SmvExpr value) {
00636     // If RHS type not subtype of LHS type
00637     if (! rhs.getType().isSubtypeOf(lhs.getType())) {
00638 
00639         // If LHS is REF type and RHS not 'null'
00640         if (lhs.getType().isKind(REF) && ! (rhs instanceof NullExpr)) {
00641 
00642         if (! (rhs instanceof StateVar))  // Should be generalized
00643             throw new RuntimeException("Can only check var to var ref assignments");
00644 
00645         // ClassCastException occurs if this transformation could
00646         // be taken and the target of the RHS is not in the
00647         // set of targets of the LHS reference type.
00648         SmvVar refIndexVar = 
00649             getVar(refIndexVar(((StateVar)rhs).getName()));
00650         SmvNaryExpr couldBeTaken = transCouldBeTakenExpr(currentTrans);
00651         SmvNaryExpr notSupClass = new SmvNaryExpr("|",ONE,true);
00652         couldBeTaken.add(notSupClass);
00653         SmvLit trap = new SmvLit("ClassCastException");
00654         StateVarVector lhsTargets = ((Ref)lhs.getType()).getTargets();
00655         StateVarVector rhsTargets = ((Ref)rhs.getType()).getTargets();
00656         for (int j = 0; j < rhsTargets.size(); j++) {
00657             StateVar target = rhsTargets.elementAt(j);
00658             if (! lhsTargets.contains(target)) {
00659             SmvLit refIndex = new SmvLit("" + refIndex(target));
00660             notSupClass.add(equal(refIndexVar,refIndex));
00661             }
00662         }
00663         trapVar.addUpdate(couldBeTaken, becomes(trapVar,trap));
00664         }
00665     }
00666     // If LHS is out of range 
00667         //if (lhs.getType().isKind(RANGE)) {
00668     //    Range range = (Range) lhs.getType();
00669     //    SmvNaryExpr couldBeTaken = transCouldBeTakenExpr(currentTrans);
00670         //    SmvExpr low = greaterThan(value,
00671         //                              new SmvLit("" + range.getFromVal()));
00672         //    SmvExpr hi = lessThan(value,
00673         //                          new SmvLit("" + range.getToVal()));
00674     //    couldBeTaken.add(not(and(hi,low)));
00675     //    SmvLit trap = new SmvLit("RangeLimitException");
00676         //    trapVar.addUpdate(couldBeTaken, becomes(trapVar,trap));
00677     //}
00678         }
00679     String countVar(String var) {
00680     return var + "_count";
00681     }
00682     static String currentDir() { return System.getProperty("user.dir"); }
00683     /**
00684      * Declare an SMV state variable
00685      * @param name of variable 
00686      * @param its SMV type (or null if it's an aggregate)
00687      * @param the BIR StateVar it represents (a part of)
00688      * @param its initial value (or null if it has none)
00689      * @param the aggregate SmvVar it is nested within (or null)
00690      * @param flag indicating whether var is constrained (has TRANS formula)
00691      * @param an SmvVar that, if false, indicates this variable is dead
00692      */
00693 
00694     public SmvVar declareVar(String name, String smvType, StateVar source, 
00695                  String initValue, SmvVar aggregate,
00696                  boolean constrained, SmvVar deadFlag) {
00697     SmvLit initVal = (initValue != null) ? new SmvLit(initValue) : null;
00698     SmvVar var = new SmvVar(name, smvType, source, initVal, 
00699                 constrained, deadFlag);
00700     if (varTable.get(name) != null) 
00701         throw new RuntimeException("Error: name conflict " + name);
00702     if (aggregate != null) {
00703         aggregate.addComponent(var);
00704         var.setAggregate(aggregate);
00705     }
00706     varList.addElement(var);
00707     varTable.put(name,var);
00708     return var;
00709     }
00710     /**
00711      * Declare all variables using SmvTypeDecl to walk down through
00712      * composite types.
00713      */
00714 
00715     void declareVariables() {
00716     SmvTypeDecl declarator = new SmvTypeDecl(this, system);
00717     StateVarVector stateVarVector = system.getStateVars();
00718 
00719     // For an interleaving model, we have a runningVar that contains
00720     // the name of the thread executing on this step
00721     if (interleaving)
00722         runningVar = declareVar("runningThread",threadType,null,null,
00723                     null,false,null);
00724 
00725     // Create location/active variables for each thread
00726     ThreadVector threadVector = system.getThreads();
00727     for (int i = 0; i < threadVector.size(); i++) {
00728         BirThread thread = threadVector.elementAt(i);
00729         LocVector threadLocVector = thread.getLocations();
00730         String locType = "";     // Enumerated location type
00731         for (int j = 0; j < threadLocVector.size(); j++) {
00732         Location loc = threadLocVector.elementAt(j);
00733         if (j > 0) locType += ", ";
00734         locType += locName(loc);
00735         }
00736         locType = "{ " + locType + " }";
00737         declareVar(locVar(thread), locType, null, 
00738                locName(thread.getStartLoc()),null,false,null);
00739 
00740         // Need active flag if not main
00741         if (! thread.isMain())
00742         declareVar(activeVar(thread),"boolean",null,"0",
00743                null,true,null);
00744 
00745         // For a liveness property, need an idle variable for each thread
00746         // that is true if the thread idles on this step
00747         if (liveness)
00748         declareVar(idleVar(thread),"boolean",null,"0",null,false,null);
00749 
00750         // Each thread also has a temp variable (to store the lock count
00751         // while waiting)
00752         declareVar(tempVar(thread), LOCK_COUNT_TYPE, 
00753                null,null,null,true,null);
00754 
00755         // Also declare locals for this thread using SmvTypeDecl switch
00756         for (int j = 0; j < stateVarVector.size(); j++) {
00757         StateVar var =  stateVarVector.elementAt(j);
00758         if (var.getThread() == thread) 
00759             var.getType().apply(declarator, var);
00760         }
00761     }
00762 
00763     // Create one or more variables for each global StateVar
00764     for (int j = 0; j < stateVarVector.size(); j++) {
00765         StateVar var =  stateVarVector.elementAt(j);
00766         if (var.getThread() == null) 
00767         var.getType().apply(declarator, var);
00768     }
00769 
00770     // Create a (unconstrained) variable for use is ChooseExpr
00771     choiceVar = 
00772         declareVar("smv_choice","0 .. 31",null,null,null,false,null);
00773 
00774     // Create a global to store the trap condition (if any)
00775     trapVar = 
00776         declareVar("smv_trap",TRAP_TYPE,null,"None",null,true,null);
00777 
00778     // Retrieve max collection size (used in deref)
00779     maxCollectionSize = declarator.getMaxCollectionSize();
00780     }
00781     public void defaultCase(Object obj)
00782     {
00783     throw new RuntimeException("Trans type not handled: " + obj);
00784     }
00785     /**
00786      * Generate DEFINE sectoin, which defines the following symbols:
00787      * <ol>
00788      * <li> MAX_COLLECT_SIZE
00789      * <li> Enumeration and constant names
00790      * <li> T_blocked for each thread T
00791      * <li> T_terminated for each thread T
00792      * </ol>
00793      */
00794 
00795     void definitions() {
00796     Vector definitions = system.getDefinitions();
00797     println("DEFINE");
00798     println("  MAX_COLLECT_SIZE := " + maxCollectionSize + ";");
00799 
00800     // BIR definitions (constants)
00801     for (int i = 0; i < definitions.size(); i++) {
00802         Definition def = (Definition) definitions.elementAt(i);
00803         if (def instanceof Constant) 
00804         println("  " + def.getName() + " := " + def.getDef() +
00805                 ";");
00806         else if (def instanceof Enumerated) {
00807         Enumerated enum = (Enumerated) def;
00808         for (int j = 0; j < enum.getEnumeratedSize(); j++) {
00809             String name = enum.getNameOf(enum.getFirstElement()+j);
00810             if (name != null)
00811             println("  " + name + " := " + 
00812                    (enum.getFirstElement()+j) + ";");
00813         }
00814         }
00815     }
00816 
00817     // Add predicates for CTL property or deadlock
00818     if (ctlproperty) {
00819         // User defined predicates
00820         Vector preds = system.getPredicates();
00821         for (int i = 0; i < preds.size(); i++) {
00822         Expr pred = (Expr) preds.elementAt(i);
00823         String name = system.predicateName(pred);
00824         println("  " + name + " := ");
00825         indent(2);
00826 // NOT FINISHED! Need to convert the Expr to an SMVExpr
00827 // print(applyTo(pred).getCase(normal));
00828         println("true");
00829 // printed true just to make legal SMV
00830         println(";");
00831         indent(-2);
00832         }
00833     } else {
00834         // Thread blocked/terminated expressions
00835         ThreadVector threadVector = system.getThreads();
00836         for (int i = 0; i < threadVector.size(); i++) {
00837             BirThread thread = threadVector.elementAt(i);
00838             SmvExpr blocked = threadBlockedExpr(thread);
00839             println("  " + blockedVar(thread) + " := ");
00840             indent(2);
00841             blocked.print(this);
00842             println(";");
00843             indent(-2);
00844             SmvExpr terminated = threadTerminatedExpr(thread);
00845             println("  " + terminatedVar(thread) + " := ");
00846             indent(2);
00847             terminated.print(this);
00848             println(";");
00849             indent(-2);
00850         }
00851     }
00852     println();
00853     }
00854     String elementVar(String var, int i) {
00855     return var + "_e" + i;
00856     }
00857     SmvExpr equal(SmvExpr expr1, SmvExpr expr2) 
00858     {
00859     return new SmvBinaryExpr("=",expr1,expr2);
00860     }
00861     String execAndWait(String command, boolean verbose) {
00862     try {
00863         if (verbose)
00864         System.out.println(command);
00865         Process p = runtime.exec(command);
00866         InputStream commandErr = p.getErrorStream();
00867         InputStream commandOut = p.getInputStream();
00868         int count = 0;       // total chars read
00869         int charsRead = 0;   // chars read on read
00870         int charsAvail = 0;  // chars available
00871         while ((count < BUFSIZE) && (charsRead >= 0)) {
00872         charsAvail = commandErr.available();
00873         if (charsAvail > 0) 
00874             count += commandErr.read(buffer,count,charsAvail);
00875         charsRead = commandOut.read(buffer,count,BUFSIZE - count);
00876         if (charsRead > 0)
00877             count += charsRead;
00878         }
00879         p.waitFor();
00880         String output = new String(buffer,0,count);
00881         if (verbose && count > 0)
00882         System.out.println(output);
00883         return output;
00884     }
00885     catch (Exception e) {
00886         throw new RuntimeException("exec of command '" + command
00887                        + "' was aborted: \n" + e);
00888     }
00889     }
00890     /**
00891      * Generate FAIRNESS clause for each thread T of the form:
00892      * <pre>
00893      * ! T_idle | T_blocked | T_terminated
00894      * </pre>
00895      */
00896 
00897     void fairness() {
00898     ThreadVector threadVector = system.getThreads();
00899     for (int i = 0; i < threadVector.size(); i++) {
00900         BirThread thread = threadVector.elementAt(i);
00901         SmvNaryExpr expr = new SmvNaryExpr("|",ZERO,true);
00902         expr.add(not(getVar(idleVar(thread))));
00903         expr.add(new SmvVar(blockedVar(thread)));
00904         expr.add(new SmvVar(terminatedVar(thread)));
00905         println("FAIRNESS  -- " + thread.getName());
00906         expr.print(this);
00907         println();
00908     }
00909     }
00910     String fieldVar(String var, Field type) {
00911     return var + "_" + type.getName();
00912     }
00913     /**
00914      * Finds an assignment to a local variable in the transformation (or
00915      * returns null if not found).
00916      */
00917 
00918     AssignAction findLocalAssign(Transformation trans) {
00919     if (trans.getActions().size() > 1)
00920         throw new RuntimeException("Multiple actions on transformation: " + trans);
00921     if (trans.getActions().size() == 0)
00922         return null;
00923     Action action = trans.getActions().elementAt(0);
00924     if (action.isAssignAction()) {
00925         AssignAction assign = (AssignAction) action;
00926         if (assign.getLhs() instanceof StateVar) {
00927         StateVar var = (StateVar) assign.getLhs();
00928         if (var.getThread() != null)
00929             return assign;
00930         }
00931     } 
00932     return null;
00933     }
00934 /**
00935  * getCounterExample method comment.
00936  */
00937 public List getCounterExample() {
00938     return null;
00939 }
00940     TransSystem getSystem() { return system; }
00941     String getThreadType() { return threadType; }
00942     /**
00943      * Get SmvVar with given name.
00944      */
00945 
00946     SmvVar getVar(String name) { 
00947     return (SmvVar) varTable.get(name); 
00948     }
00949     SmvExpr greaterThan(SmvExpr expr1, SmvExpr expr2) 
00950     {
00951     return new SmvBinaryExpr(">=",expr1,expr2);
00952     }
00953     /**
00954      * Generate SMV header
00955      */
00956 
00957     void header() {
00958     println("--  SMV for transition system: " 
00959             + system.getName());
00960     println();
00961     println("MODULE main");
00962     }
00963     String idleVar(BirThread thread) {
00964     return thread.getName() + "_idle";
00965     }
00966     void indent(int delta) {
00967     indentLevel += delta;
00968     }
00969     /**
00970      * Generate INIT formula that sets each non-aggregate variable
00971      * with an initial value to that value.
00972      */
00973 
00974     void init() {
00975     println("INIT");
00976     SmvNaryExpr expr = new SmvNaryExpr("&", ONE, false);
00977     for (int i = 0; i < varList.size(); i++) {
00978         SmvVar var = (SmvVar)varList.elementAt(i);
00979         // If not aggregate and is initially allocated
00980         if (var.getType() != null && var.getDeadFlag() == null) {
00981         SmvLit initVal = var.getInitValue();
00982         // And has an initial value
00983         if (initVal != null)
00984             expr.add(equal(var,initVal));
00985         }
00986     }
00987     expr.print(this);
00988     println();  
00989     }
00990     /**
00991      * Initialize all components in an SmvVar if indicated condition is true.
00992      */
00993 
00994     void initAllComponents(SmvVar var, SmvExpr cond) {
00995     Vector components = var.getComponents();
00996     // If aggregate, initialize all components
00997     if (components.size() > 0) {
00998         for (int i = 0; i < components.size(); i++)
00999         initAllComponents((SmvVar)components.elementAt(i),cond);
01000     } else {
01001         // Else if simple var and has init value, make conditional update
01002         if (var.getInitValue() != null) {
01003         var.addUpdate(cond,becomes(var,var.getInitValue()));
01004         }
01005     }
01006     }
01007     String instanceVar(String var, int i) {
01008     return var + "_i" + i;
01009     }
01010     String instNumVar(String var) {
01011     return var + "_instNum";
01012     }
01013     String inUseVar(String var, int i) {
01014     return var + "_inuse" + i;
01015     }
01016     String lengthVar(String var) {
01017     return var + "_length";
01018     }
01019     SmvExpr lessThan(SmvExpr expr1, SmvExpr expr2) 
01020     {
01021     return new SmvBinaryExpr("<=",expr1,expr2);
01022     }
01023     /**
01024      * Name of location.
01025      */
01026 
01027     String locName(Location loc) {
01028     return "loc" + loc.getId();
01029     }
01030     String locVar(BirThread thread) {
01031     return thread.getName() + "_loc";
01032     }
01033     SmvExpr minus1(SmvExpr expr) 
01034     {
01035     return new SmvBinaryExpr("-",expr,ONE);
01036     }
01037     SmvExpr not(SmvExpr expr)
01038     {
01039     if (expr instanceof SmvUnaryExpr &&
01040         ((SmvUnaryExpr)expr).operator.equals("!"))
01041         return ((SmvUnaryExpr)expr).op;
01042     else
01043         return new SmvUnaryExpr("!",expr);
01044     }
01045     SmvExpr or(SmvExpr expr1, SmvExpr expr2) 
01046     {
01047     return new SmvBinaryExpr("|",expr1,expr2);
01048     }
01049     String ownerVar(String var) {
01050     return var + "_owner";
01051     }
01052     static int parseInt(String s) {
01053     try {
01054         int result = Integer.parseInt(s);
01055         return result;
01056     } catch (NumberFormatException e) {
01057         throw new RuntimeException("Integer didn't parse: " + s);
01058     }
01059     }
01060     /** 
01061      * Parse one line of the SMV output file, updating the trace.
01062      */
01063 
01064     void parseLine(String line, BirTrace trace) {
01065     if (!doneParsing) {
01066 
01067         // Look for "is true" or "is false" to see if verifier finished
01068         if (line.indexOf("is true") >= 0) {
01069           if (foundFalse) {
01070             foundTrace = false;
01071           } else {
01072         trace.setVerified(true);
01073         doneParsing = true;
01074         return;
01075           }
01076         }
01077         if (line.indexOf("is false") >= 0) {
01078           if (foundFalse) {
01079             foundTrace = false;
01080           } else {
01081         trace.setVerified(false);
01082         foundTrace = true;
01083         foundFalse = true;
01084         return;
01085           }
01086         }
01087 
01088         if (foundTrace) {
01089         if (line.startsWith("State"))
01090             stateCount += 1;
01091 
01092         // Look for update to thread loc variable
01093         if (stateCount > 1 && line.indexOf("_loc =") >= 0) 
01094             parseThreadStep(line, trace);
01095 
01096         // Look for update to trap variable
01097         if (stateCount > 1 && line.startsWith("smv_trap =")) 
01098             parseTrap(line, trace);
01099         }
01100     }
01101     }
01102     /**
01103      * Parse the output of SMV and interpret it as either a violation 
01104      * (sequence of transformations) or as a error-free analysis.
01105      * <p>
01106      * @return a BirTrace 
01107      */
01108 
01109     public BirTrace parseOutput() {
01110     if (! ranVerifier) 
01111         throw new RuntimeException("Did not run verifier on input");
01112     try {
01113         BirTrace trace = new BirTrace(system);
01114             File smvFile = new File(currentDir(),
01115                     system.getName() + ".smv");
01116         if (! smvFile.exists())
01117         throw new RuntimeException("Cannot find SMV output: \n" 
01118                        + smvFile);
01119         prepareParse();
01120         BufferedReader reader = 
01121         new BufferedReader(new FileReader(smvFile));
01122         String line = reader.readLine();
01123         while (line != null) {
01124         parseLine(line,trace);
01125         line = reader.readLine();
01126         }
01127         reader.close();
01128         trace.done();
01129         return trace;
01130         } catch(IOException e) {
01131             throw new RuntimeException("Error parsing SMV output: \n" + e);
01132         } 
01133     }
01134     /**
01135      * Parse line containing update to thread location.
01136      * <p>
01137      * Find transformation taken and add to trace.
01138      * Line of form:
01139      * <pre>
01140      * threadName_loc = locXXX
01141      * </pre>
01142      * where XXX is a number.
01143      */
01144 
01145     void parseThreadStep(String line, BirTrace trace) {
01146     int end = line.indexOf("_loc =");
01147     String threadName = line.substring(0,end);
01148     Integer threadNum = (Integer) threadTable.get(threadName);
01149     if (threadNum == null)   // wasn't a thread after all
01150         return;
01151 
01152     // Fetch current and next location of this thread
01153     Location fromLoc = threadLocs[threadNum.intValue()];
01154     int locPos = 3 + line.indexOf("loc",end + 5);
01155     int locId = parseInt(line.substring(locPos));
01156     Location toLoc = system.getLocation(locId);
01157     
01158     // Use these locations to find the transformation
01159     TransVector outTrans = fromLoc.getOutTrans();
01160     for (int i = 0; i < outTrans.size(); i++) {
01161         if (outTrans.elementAt(i).getToLoc() == toLoc) {
01162         threadLocs[threadNum.intValue()] = toLoc;
01163         lastTrans = outTrans.elementAt(i);
01164         trace.addTrans(lastTrans);
01165         return;
01166         }
01167     }
01168     throw new RuntimeException("Error parsing SMV output: can't find trans for " + threadName + " from location " + fromLoc + " to " + toLoc);
01169     }
01170     /**
01171      * Parse line updating trap variable---record trap name.
01172      */
01173 
01174     void parseTrap(String line, BirTrace trace) {
01175     int end = line.indexOf("=");
01176     String trapName = line.substring(end + 2);
01177     trace.setTrap(trapName,lastTrans,0);
01178     }
01179     SmvExpr plus1(SmvExpr expr) 
01180     {
01181     return new SmvBinaryExpr("+",expr,ONE);
01182     }
01183     /** 
01184      * Prepare to parse SMV output file
01185      */
01186 
01187     void prepareParse() {
01188     doneParsing = false;
01189     foundFalse = false;
01190     foundTrace = false;
01191     stateCount = 0;
01192     ThreadVector threads = system.getThreads();
01193     threadLocs = new Location[threads.size()];
01194     threadTable = new Hashtable();
01195     for (int i = 0; i < threadLocs.length; i++) {
01196         BirThread thread = threads.elementAt(i);
01197         threadTable.put(thread.getName(), new Integer(i));
01198         threadLocs[i] = thread.getStartLoc();
01199     }
01200     }
01201     /**
01202      * Support for printing things nicely indented.
01203      */
01204 
01205     void print(String s) {
01206     if (newLine) {           // at start of line---indent
01207         for (int i = 0; i < indentLevel; i++)
01208         out.print("  ");
01209         newLine = false;
01210     }
01211     out.print(s);
01212     }
01213     void println() {
01214     if (! newLine) {
01215         out.println();
01216         newLine = true;
01217     }
01218     }
01219     void println(String s) {
01220     print(s);
01221     println();
01222     }
01223     /**
01224      * Print variable declarations
01225      * <p>
01226      * Aggregate variables (e.g., arrays, records, collections, refs)
01227      * have a null type and are printed as comments.
01228      */
01229 
01230     void printVariableDecls() {
01231     println("VAR");
01232     for (int i = 0; i < varList.size(); i++) {
01233         SmvVar var = (SmvVar)varList.elementAt(i);
01234         if (var.getType() != null) 
01235         println("  " + var + " : " + var.getType() + ";");
01236         else {  // Is aggregate
01237         String comment = "";   // Print refIndex if array/rec/collect
01238         StateVar source = var.getSource();
01239         if (source != null 
01240             && source.getType().isKind(COLLECTION|ARRAY|RECORD)) 
01241             comment = "(refIndex = " + refIndex(source) + ")";
01242         println("  -- Aggregate: " + var + " " + comment);
01243         }
01244     }
01245     println();
01246     }
01247     void property() {
01248     indent(2);
01249     // Catch any exceptions as violations
01250     println("INVARSPEC");
01251     println("smv_trap = None");
01252 
01253     indent(-2);
01254     if (ctlproperty) {
01255         println("SPEC");
01256         // Read in the file 
01257             File ctlFile = new File(currentDir(),
01258                                     system.getName() + ".smv.ctl");
01259             if (! ctlFile.exists())
01260                 throw new RuntimeException("Cannot find CTL file: " +
01261                                            ctlFile.getAbsolutePath());
01262             if (! ctlFile.canRead())
01263                 throw new RuntimeException("Cannot read CTL file: " +
01264                                            ctlFile.getAbsolutePath());
01265         try {
01266             BufferedReader in = 
01267             new BufferedReader(new FileReader(ctlFile));
01268                String line;
01269            indent(2);
01270                while((line = in.readLine()) != null) 
01271                   println(line);
01272                in.close();
01273         } catch (IOException e) {
01274         }
01275         indent(-2);
01276     } else {
01277         // Deadlock is an invariant stating that
01278         //   All threads are either blocked or terminated and
01279         //   at least one thread has not terminated
01280         indent(2);
01281         println("INVARSPEC");
01282             ThreadVector threadVector = system.getThreads();
01283         indent(2);
01284         println("!(");
01285         indent(2);
01286         println("(");
01287         indent(2);
01288             for (int i = 0; i < threadVector.size(); i++) {
01289                 BirThread thread = threadVector.elementAt(i);
01290         if (i < threadVector.size()-1)
01291                     println("(" + blockedVar(thread) + " | " + 
01292                                   terminatedVar(thread) + ") &");
01293                 else
01294                     println("(" + blockedVar(thread) + " | " + 
01295                                   terminatedVar(thread) + ")");
01296             }
01297         indent(-2);
01298         println(") & (");
01299         indent(2);
01300             for (int i = 0; i < threadVector.size(); i++) {
01301                 BirThread thread = threadVector.elementAt(i);
01302         if (i < threadVector.size()-1)
01303                     println("!" + terminatedVar(thread) + " |");
01304                 else
01305                     println("!" + terminatedVar(thread));
01306             }
01307         indent(-2);
01308         println(")");
01309         indent(-2);
01310         println(")");
01311         indent(-2);
01312     }
01313     }
01314     /**
01315      * Records updates to globals made by an assignment.
01316      * <p>
01317      * If the LHS may reference more than one variable
01318      * (e.g., contains a pointer deref or array indexing)
01319      * then the LHS expression will be an SmvCase whose
01320      * leaves are all the possible updated variables.
01321      * In this case, we recurse through all cases of
01322      * the tree until we reach a leaf (SmvVar).
01323      * When an SmvVar is finally reached, we add a conditional
01324      * update to that variable to the value given by the RHS expression
01325      * on that condition that the current trans is taken *and*
01326      * the specific case context is true (i.e., all conditions
01327      * for all cases we're contained in are true).
01328      */
01329 
01330     void recordGlobalVarAssignments(SmvExpr lhs, 
01331                     SmvExpr rhs, SmvCase context) {
01332     if (lhs instanceof SmvVar) {
01333         SmvVar global = (SmvVar) lhs;
01334         SmvNaryExpr taken = transTakenExpr(currentTrans);
01335         addConditionalContext(taken,context);
01336         global.addUpdate(taken,becomes(global,rhs));
01337             //if (lhs.getType().isKind(RANGE)) {
01338         //  Range range = (Range) lhs.getType();
01339         //  SmvNaryExpr couldBeTaken = transCouldBeTakenExpr(currentTrans);
01340             //  SmvExpr low = greaterThan(rhs,
01341             //                            new SmvLit("" + range.getFromVal()));
01342             //  SmvExpr hi = lessThan(rhs,
01343             //                        new SmvLit("" + range.getToVal()));
01344         //  couldBeTaken.add(not(and(hi,low)));
01345         //  SmvLit trap = new SmvLit("RangeLimitException");
01346             //  trapVar.addUpdate(couldBeTaken, becomes(trapVar,trap));
01347       //}
01348     } else if (lhs instanceof SmvCaseExpr) {
01349         Vector cases = ((SmvCaseExpr)lhs).getCases();
01350         for (int i = 0; i < cases.size(); i++) {
01351         SmvCase smvCase = (SmvCase)cases.elementAt(i);
01352         recordGlobalVarAssignments(smvCase.expr,rhs,smvCase);
01353         }
01354     } else
01355         throw new RuntimeException("Unknown LHS of assignment");
01356     }
01357     /**
01358      * Records updates to global variables made by the current trans.
01359      */
01360 
01361     void recordGlobalVarUpdates() {
01362     if (currentTrans.getActions().size() == 0)
01363         return;
01364     Action action = currentTrans.getActions().elementAt(0);
01365     if (action.isAssignAction()) {
01366         AssignAction assign = (AssignAction) action;
01367         SmvExpr lhs = translate(assign.getLhs());
01368         SmvExpr rhs = translate(assign.getRhs());
01369         recordGlobalVarAssignments(lhs,rhs,null);
01370     } else if (action.isThreadAction(ANY)) {
01371         recordThreadStatusUpdates((ThreadAction)action);
01372     } else if  (action.isLockAction(ANY)) {
01373         recordLockStatusUpdates((LockAction)action);
01374     } 
01375     }
01376     /**
01377      * Record updates to the lock variables by a lock action.
01378      */
01379 
01380     void recordLockStatusUpdates(LockAction action) {
01381     ThreadVector threads = system.getThreads();
01382     BirThread currentThread = action.getThread();
01383     SmvLit currentThreadLit = new SmvLit(currentThread.getName());
01384 
01385     // We're assuming the lock is on the heap
01386     SmvCaseExpr lockExpr = (SmvCaseExpr) translate(action.getLockExpr());
01387     Vector cases = lockExpr.collectCases(new Vector());
01388 
01389     // For each leaf (which is a lock)
01390     for (int i = 0; i < cases.size(); i++) {
01391 
01392         // Prepare the condition for the updates we'll make
01393         SmvNaryExpr taken = transTakenExpr(currentTrans);
01394         SmvCase smvCase = (SmvCase)cases.elementAt(i);
01395         addConditionalContext(taken,smvCase);
01396 
01397         // Grab all the relevant variables
01398         SmvVar lockVar = (SmvVar) smvCase.expr;
01399         SmvVar ownerVar = getVar(ownerVar(lockVar.getName()));
01400         SmvVar countVar = getVar(countVar(lockVar.getName()));
01401         SmvVar waitVar = getVar(waitVar(lockVar.getName(),currentThread));
01402         SmvVar tempVar = getVar(tempVar(currentThread));
01403         SmvExpr update;
01404         SmvNaryExpr sum;
01405         SmvNaryExpr nextSum;
01406 
01407         switch (action.getOperation()) {
01408         case LOCK:
01409         // Update the owner var to be the current thread 
01410         update = becomes(ownerVar,currentThreadLit);
01411         ownerVar.addUpdate(taken,update);
01412         // Update the count var to be 0 if lock currently free
01413         // (owner = NOTHREAD), else increment it 
01414         update = or(and(equal(ownerVar,NOTHREAD),
01415                 becomes(countVar,ZERO)),
01416                 and(equal(ownerVar,currentThreadLit),
01417                 becomes(countVar,plus1(countVar))));
01418         countVar.addUpdate(taken,update);
01419         break;
01420 
01421         case UNLOCK:
01422         // Update the owner var to be NOTHREAD if the count is 0,
01423         // else leave it unchanged (should be currentThreadLit)
01424         update = or(and(equal(countVar,ZERO),
01425                 becomes(ownerVar,NOTHREAD)),
01426                 and(not(equal(countVar,ZERO)),
01427                 becomes(ownerVar,currentThreadLit)));
01428         ownerVar.addUpdate(taken,update);
01429         // If the count var is 0, leave the next value unconstrained
01430         // (var is dead), else decrement it
01431         update = or(equal(countVar,ZERO),
01432                 and(not(equal(countVar,ZERO)),
01433                 becomes(countVar,minus1(countVar))));
01434         countVar.addUpdate(taken,update);
01435         break;
01436 
01437         case WAIT:
01438         // Store the current lock count in the thread's temp var
01439         update = becomes(tempVar,countVar);
01440         tempVar.addUpdate(taken,update);
01441         // Release the lock by setting owner var to NOTHREAD
01442         update = becomes(ownerVar,NOTHREAD);
01443         ownerVar.addUpdate(taken,update);
01444         // Unconstrain the count var (now dead)
01445         countVar.addUpdate(taken,ONE); 
01446         // Set the wait var for this thread to 1
01447         update = becomes(waitVar,ONE);
01448         waitVar.addUpdate(taken,update);
01449         break;
01450 
01451         case UNWAIT: 
01452         // Restore the count from the thread's temp var
01453         update = becomes(countVar,tempVar);
01454         countVar.addUpdate(taken,update);
01455         // Unconstrain the temp var (now dead)
01456         tempVar.addUpdate(taken,ONE); 
01457         // Set owner to currentThread
01458         update = becomes(ownerVar,currentThreadLit);
01459         ownerVar.addUpdate(taken,update);
01460         break;
01461 
01462         case NOTIFY: 
01463         // Keep sums of wait vars for *other* threads on this lock 
01464         // (both current and next states).  
01465         sum = new SmvNaryExpr("+",ZERO,true);
01466         nextSum = new SmvNaryExpr("+",ZERO,true);
01467         for (int j = 0; j < threads.size(); j++) {
01468             BirThread thread = threads.elementAt(j);
01469             if (thread != currentThread) {
01470             SmvVar otherWaitVar = 
01471                 getVar(waitVar(lockVar.getName(),thread));
01472             sum.add(otherWaitVar);
01473             SmvExpr nextOtherWaitVar = 
01474                 new SmvNextExpr(otherWaitVar);
01475             nextSum.add(nextOtherWaitVar);
01476             // For each other thread, constrain the next value of
01477             // its wait var to be less than its current value
01478             // (i.e., can change from 1 to 0 or stay at 0)
01479             update = lessThan(nextOtherWaitVar,otherWaitVar);
01480             otherWaitVar.addUpdate(taken,update);
01481             }
01482         }
01483         // For the thread executing notify (whose wait var must be 0)
01484         // keep its wait var at 0 *and* constrain the sums of
01485         // the other wait vars to satisfy one of the following
01486         // two conditions:
01487         //  (1) Sum of current wait vars is zero (i.e., no thread
01488         //     is waiting on this lock, so notify does nothing)
01489         //  (2) Sum of current wair vars is one greater than
01490         //     the sum of the next wait vars (i.e., exactly one
01491         //     wait var for some waiting thread changed from 1 to 0)
01492         update = and(becomes(waitVar,ZERO),
01493                  or(equal(sum,ZERO),
01494                 equal(nextSum,minus1(sum))));
01495         waitVar.addUpdate(taken,update);
01496         break;
01497 
01498         case NOTIFYALL: 
01499         // Set all wait vars for other threads to 0
01500         for (int j = 0; j < threads.size(); j++) {
01501             BirThread thread = threads.elementAt(j);
01502             if (thread != currentThread) {
01503             SmvVar otherWaitVar =
01504                 getVar(waitVar(lockVar.getName(),thread));
01505             update = becomes(otherWaitVar,ZERO);
01506             otherWaitVar.addUpdate(taken,update);
01507             }
01508         }
01509         break;
01510         }
01511     }
01512     }
01513     /**
01514      * Records updates to the status of the threads.
01515      * <p>
01516      * A start action for a thread changes its T_active var to 1.
01517      */
01518 
01519     void recordThreadStatusUpdates(ThreadAction action) {
01520     if (action.isThreadAction(START)) {
01521         BirThread thread = action.getThreadArg();
01522         SmvNaryExpr taken = transTakenExpr(currentTrans);
01523         SmvVar active = getVar(activeVar(thread));
01524         active.addUpdate(taken,becomes(active,ONE));
01525     }
01526     }
01527     /**
01528      * Return the refIndex of a BIR state variable (i.e., its position
01529      * in the universal reference type refAny).
01530      */
01531 
01532     int refIndex(StateVar target) {
01533     return 1 + system.refAnyType().getTargets().indexOf(target);
01534     }
01535     String refIndexVar(String var) {
01536     return var + "_refIndex";
01537     }
01538     /**
01539      * Build SMV reference value from refIndex and instNum values.
01540      */
01541 
01542     SmvLit refValue(int refIndex, int instNum) {
01543     return new SmvLit("(" + refIndex + " * MAX_COLLECT_SIZE + " 
01544               + instNum + ")");
01545     }
01546     /**
01547      * Run SMV translator, generate each part of the output in turn.
01548      */
01549 
01550     SmvTrans run() {
01551     header();
01552     stateVariables();
01553     init();
01554     transitions();
01555     if (liveness)
01556         fairness();
01557     definitions();
01558     property();
01559     return this;
01560     }
01561     /**
01562      * Run SMV.
01563      * <p>
01564      * The translator must have been executed for the transition system
01565      * (the file NAME.trans must exist and contain the translated input).
01566      * @return the output of SMV (as a String)
01567      */
01568 
01569     public String runSmv() {
01570     try {
01571             File sourceFile = new File(currentDir(),
01572                        system.getName() + ".trans");
01573         if (! sourceFile.exists())
01574         throw new RuntimeException("Cannot find SMV input file: " +
01575                        sourceFile.getName());
01576         ranVerifier = true;
01577         String output = execAndWait("nusmv " + options.runOptions() + sourceFile.getName(), true);
01578         // Write output to file
01579         File outFile = new File(currentDir(), 
01580                     system.getName() + ".smv");
01581             FileOutputStream streamOut = new FileOutputStream(outFile);
01582             PrintWriter writerOut = new PrintWriter(streamOut);
01583         writerOut.print(output);
01584         writerOut.close();
01585 System.out.println("Parsing output and printing BIR trace");
01586 parseOutput().print(true);
01587         return output;
01588         } catch(Exception e) {
01589             throw new RuntimeException("Could not produce SMV file (" + e + ")");
01590         }   
01591     }
01592     /**
01593      * Generate SMV variables
01594      */
01595 
01596     void stateVariables() {
01597     declareVariables();
01598     printVariableDecls();
01599     }
01600     String tempVar(BirThread thread) {
01601     return thread.getName() + "_temp";
01602     }
01603     String terminatedVar(BirThread thread) {
01604     return thread.getName() + "_terminated";
01605     }
01606     /**
01607      * Build an expression that is true if the thread is blocked.
01608      * <p>
01609      * The thread is blocked if it is in a location and the guards
01610      * for all transforms out of that location are false.  If
01611      * there are no transforms out of the location, the thread
01612      * is considered terminated, not blocked.
01613      */
01614 
01615     SmvExpr threadBlockedExpr(BirThread thread) {
01616     LocVector locations = thread.getLocations();
01617     SmvVar locVar = getVar(locVar(thread));
01618     SmvNaryExpr blocked = new SmvNaryExpr("|",ZERO,true);
01619     for (int i = 0; i < locations.size(); i++) {
01620         SmvLit locLabel = new SmvLit(locName(locations.elementAt(i)));
01621 
01622         // Build expression for being blocked at this location
01623         SmvNaryExpr blockedAtLoc = new SmvNaryExpr("&",ONE,true);
01624         TransVector transitions = locations.elementAt(i).getOutTrans();
01625         for (int j = 0; j < transitions.size(); j++) {
01626         SmvExpr guard = 
01627             (SmvExpr) guardTable.get(transitions.elementAt(j));
01628         if (guard != null && ! guard.equals(ONE)) {
01629             // Nontrivial guard: can block if it is false
01630             blockedAtLoc.add(not(guard));
01631         } else {
01632             // True or missing guard: cannot block in this location
01633             blockedAtLoc = null;
01634             break;
01635         }
01636         }
01637         // If we didn't find any transforms with true/missing guards
01638         // and we found at least one transform, then we can block here
01639         if (blockedAtLoc != null && blockedAtLoc.size() > 0)
01640         blocked.add(and(equal(locVar,locLabel),blockedAtLoc));
01641     }
01642     return blocked;
01643     }
01644     /**
01645      * Build expression that is true if a thread is terminated.
01646      * <p>
01647      * A thread is terminated if it is in a location with no
01648      * out transformations.
01649      */
01650 
01651     SmvExpr threadTerminatedExpr(BirThread thread) {
01652     LocVector locations = thread.getLocations();
01653     SmvVar locVar = getVar(locVar(thread));
01654     SmvNaryExpr terminated = new SmvNaryExpr("|",ZERO,true);
01655     for (int i = 0; i < locations.size(); i++) {
01656         SmvLit locLabel = new SmvLit(locName(locations.elementAt(i)));
01657         if (locations.elementAt(i).getOutTrans().size() == 0) 
01658         terminated.add(equal(locVar,locLabel));
01659     }
01660     return terminated;
01661     }
01662     /**
01663      * Generate an expression that is true if a transformation could be taken.
01664      * <p>
01665      * Similar to transTakenExpr, except we do not require the location
01666      * be updated or the thread be running.
01667      */
01668 
01669     SmvNaryExpr transCouldBeTakenExpr(Transformation trans) {
01670     SmvVar locVar = getVar(locVar(trans.getFromLoc().getThread()));
01671     SmvLit fromLoc = new SmvLit(locName(trans.getFromLoc()));
01672     SmvNaryExpr taken = new SmvNaryExpr("&",ONE,true);
01673     taken.add(equal(locVar,fromLoc));
01674     if (currentGuard != null && ! currentGuard.equals(ONE))
01675         taken.add(currentGuard);
01676     BirThread thread = trans.getFromLoc().getThread();
01677     if (! thread.isMain() 
01678         && trans.getFromLoc().equals(thread.getStartLoc())) {
01679         SmvVar active = getVar(activeVar(trans.getFromLoc().getThread()));
01680         taken.add(equal(active,ONE));
01681     }
01682     return taken;
01683     }
01684     /**
01685      * Generate a TRANS formula for each thread and global variable.
01686      */
01687 
01688     void transitions() {
01689     // Generate TRANS for each thread
01690     ThreadVector threadVector = system.getThreads();
01691     for (int i = 0; i < threadVector.size(); i++) {
01692         BirThread thread = threadVector.elementAt(i);
01693         SmvExpr expr = translateThread(thread);
01694         println("TRANS  -- " + thread.getName());
01695         expr.print(this);
01696         println();
01697     }
01698 
01699     // Generate TRANS for each constrained global
01700     for (int i = 0; i < varList.size(); i++) {
01701         SmvVar var = (SmvVar) varList.elementAt(i);
01702         if (var.isConstrained()) {
01703         SmvExpr expr = translateGlobal(var);
01704         println("TRANS  -- " + var);
01705         expr.print(this);       
01706         println();
01707         }
01708     }
01709     println();
01710     }
01711     /**
01712      * Translate a BIR expression to an SmvExpr
01713      */
01714 
01715     SmvExpr translate(Expr expr) {
01716     expr.apply(this);
01717     return (SmvExpr) getResult();
01718     }
01719     /**
01720      * Generate SMV source representing a transition system.
01721      * <p>
01722      * The SMV input is written to a file NAME.trans where NAME
01723      * is the name of the transition system.  A set of
01724      * options can be provided in a SmvOptions object.
01725      * @param system the transition system
01726      * @param options the SMV verifier options
01727      * @return the SmvTrans control object
01728      */
01729 
01730     public static SmvTrans translate(TransSystem system, 
01731                      SmvOptions options) {
01732     try {
01733             File sourceFile = new File(currentDir(),
01734                        system.getName() + ".trans");
01735 
01736             FileOutputStream streamOut = new FileOutputStream(sourceFile);
01737             PrintWriter writerOut = new PrintWriter(streamOut);
01738         SmvTrans result = translate(system, options, writerOut);
01739             writerOut.close();
01740         return result;
01741         } catch(IOException e) {
01742             throw new RuntimeException("Could not produce SMV file: " + e);
01743         }
01744     }
01745     /**
01746      * Generate SMV source representing a transition system.
01747      * <p>
01748      * As above, but the SMV is written to the PrintWriter provided.
01749      * @param system the transition system
01750      * @param out the PrintWriter to write the SMV to
01751      * @return the SmvTrans control object
01752      */
01753 
01754     public static SmvTrans translate(TransSystem system, SmvOptions options,
01755                      PrintWriter out) {
01756     return (new SmvTrans(system,options,out)).run();
01757     }
01758     void translateBinaryOp(Expr e1, Expr e2, String op) {
01759     setResult(new SmvBinaryExpr(op,translate(e1),translate(e2)));
01760     }
01761     /**
01762      * Return update expression for global variable (most work done in SmvVar).
01763      */
01764 
01765     SmvExpr translateGlobal(SmvVar var) {
01766     SmvExpr updateExpr = var.getUpdateExpr();
01767     return updateExpr;
01768     }
01769     /**
01770      * Build the TRANS expression for a thread.
01771      */
01772 
01773     SmvExpr translateThread(BirThread thread) {
01774     StateVarVector locals = system.getLocalStateVars(thread);
01775     SmvNaryExpr threadExpr = new SmvNaryExpr("|",ZERO,true);
01776     SmvNaryExpr skipExpr = new SmvNaryExpr("&",ONE,true);
01777     SmvVar locVar = getVar(locVar(thread));
01778 
01779     // Build skip expression (thread does not take step)
01780     skipExpr.add(becomes(locVar,locVar));
01781     for (int i = 0; i < locals.size(); i++) {
01782         SmvVar var = getVar(locals.elementAt(i).getName());
01783         skipExpr.add(becomes(var,var));
01784     }
01785     if (liveness) {  // For liveness properties, set T_idle
01786         SmvVar idleVar = getVar(idleVar(thread));
01787         skipExpr.add(becomes(idleVar,ONE));
01788     }
01789     // idle is one possible action for the thread
01790     threadExpr.add(skipExpr);
01791 
01792     // For each transformation in the thread, generate a disjunct
01793     LocVector locs = thread.getLocations();
01794     for (int i = 0; i < locs.size(); i++) {
01795         TransVector transVector = locs.elementAt(i).getOutTrans();
01796         for (int j = 0; j < transVector.size(); j++) {
01797         SmvExpr transExpr = buildTransExpr(transVector.elementAt(j),
01798                            locals, locVar);
01799         threadExpr.add(transExpr);
01800         }
01801     }
01802 
01803     return threadExpr;
01804     }
01805     void translateUnaryOp(Expr e, String op) {
01806     setResult(new SmvUnaryExpr(op,translate(e)));
01807     }
01808     /**
01809      * Build an expression that is true if a given transformation is taken.
01810      */
01811 
01812     SmvNaryExpr transTakenExpr(Transformation trans) {
01813     SmvVar locVar = getVar(locVar(trans.getFromLoc().getThread()));
01814     SmvLit fromLoc = new SmvLit(locName(trans.getFromLoc()));
01815     SmvLit toLoc = new SmvLit(locName(trans.getToLoc()));
01816     SmvNaryExpr taken = new SmvNaryExpr("&",ONE,true);
01817     // Location goes from fromLoc to toLoc
01818     taken.add(equal(locVar,fromLoc));
01819     taken.add(becomes(locVar,toLoc));
01820     // If interleaving model, this trans in the thread that's running
01821     if (interleaving) {
01822         BirThread thread = trans.getFromLoc().getThread();
01823         taken.add(equal(runningVar,new SmvLit(thread.getName())));
01824     }
01825     BirThread thread = trans.getFromLoc().getThread();
01826     // If not a main thread, the thread has been started
01827     if (! thread.isMain() 
01828         && trans.getFromLoc().equals(thread.getStartLoc())) {
01829         SmvVar active = getVar(activeVar(trans.getFromLoc().getThread()));
01830         taken.add(equal(active,ONE));
01831     }
01832     // If the guard is present and nontrivial, it must be true
01833     if (currentGuard != null && ! currentGuard.equals(ONE))
01834         taken.add(currentGuard);
01835     return taken;
01836     }
01837     String waitVar(String var, BirThread thread) {
01838     return var + "_wait_" + thread.getName();
01839     }
01840 }

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