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

JPFLTLCompiler.java

00001 package edu.ksu.cis.bandera.specification;
00002 
00003 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
00004  * Bandera, a Java(TM) analysis and transformation toolkit           *
00005  * Copyright (C) 2001   Roby Joehanes (robbyjo@cis.ksu.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 /**
00036  * Visitor class to compile pattern for JPF.
00037  * Creation date: (8/10/01 6:12:38 PM)
00038  * @author: Roby Joehanes
00039  */
00040 import java.util.*;
00041 import java.lang.reflect.*;
00042 import java.io.*;
00043 import ca.mcgill.sable.soot.*;
00044 import edu.ksu.cis.bandera.specification.analysis.*;
00045 import edu.ksu.cis.bandera.specification.datastructure.*;
00046 import edu.ksu.cis.bandera.specification.node.*;
00047 import edu.ksu.cis.bandera.specification.pattern.*;
00048 import edu.ksu.cis.bandera.specification.pattern.datastructure.*;
00049 import edu.ksu.cis.bandera.specification.predicate.node.PPropositionDefinition;
00050 import edu.ksu.cis.bandera.specification.predicate.datastructure.*;
00051 import edu.ksu.cis.bandera.annotation.*;
00052 import edu.ksu.cis.bandera.jext.*;
00053 import edu.ksu.cis.bandera.jjjc.*;
00054 import edu.ksu.cis.bandera.util.*;
00055 import gov.nasa.arc.ase.jpf.tools.*;
00056 
00057 public class JPFLTLCompiler extends DepthFirstAdapter {
00058     private String tempDir = ".";
00059     private TemporalLogicProperty tlp;
00060     private Hashtable ptab;
00061     private List qList;
00062     private Pattern pattern;
00063     private Iterator patternParamIterator;
00064     private String currentValue = null;
00065     private Hashtable patternNodeTable = new Hashtable();
00066     private Hashtable patternNameTable = new Hashtable();
00067     private boolean useConstraint;
00068 /**
00069  * 
00070  * @param dir java.lang.String To denote output directory where JPF java predicate should be placed
00071  * @param tl edu.ksu.cis.bandera.specification.datastructure.TemporalLogicProperty The currently active temporal logic property
00072  * @param q java.util.List The list of quantified variables available.
00073  */
00074 public JPFLTLCompiler(String dir, TemporalLogicProperty tl, List q)
00075 {
00076     if (dir != null) tempDir = dir;
00077     if (tl == null) throw new RuntimeException("Temporal Logic Property may NOT be null!!");
00078     tlp = tl; qList = q;
00079 }
00080 public void caseABinaryExp(ABinaryExp node)
00081 {
00082     node.getLeft().apply(this);
00083     String leftValue = currentValue;
00084     node.getRight().apply(this);
00085     String rightValue = currentValue;
00086 
00087     PBinOp binOp = node.getBinOp();
00088     if (binOp instanceof AAndBinOp) {
00089         currentValue = "(" + leftValue + " /\\ " + rightValue + ")";
00090     } else if (binOp instanceof AOrBinOp) {
00091         currentValue = "(" + leftValue + " \\/ " + rightValue + ")";
00092     } else {
00093         currentValue = "(" + leftValue + " -> " + rightValue + ")";
00094     }
00095 }
00096 public void caseAComplementExp(AComplementExp node)
00097 {
00098     node.getExp().apply(this);
00099     if (currentValue == null) currentValue = "(0 != 0)";
00100     currentValue = "!"+currentValue;
00101 }
00102 public void caseAExpWord(AExpWord node) {
00103     node.getExp().apply(this);
00104 
00105     try {
00106         String id = (String) patternParamIterator.next();
00107         if (currentValue == null) currentValue = "(0 == 0)";
00108         patternNameTable.put(id, currentValue);
00109     } catch (Exception e)
00110     {
00111         System.out.println("WARNING: Unexpected pattern end!");
00112     }
00113 }
00114 public void caseAPredicateExp(APredicateExp node) {
00115     String temp = (String) patternNodeTable.get(node);
00116 
00117     if (temp == null)
00118     {
00119         System.out.println("WARNING: Pattern table of "+node+" yields null!");
00120         temp = "(0 == 0)"; // Injects bogus value
00121     }
00122     currentValue = temp;
00123 }
00124 public void compile()
00125 {
00126     try {
00127     String classpath = System.getProperty("java.class.path");
00128     ptab = tlp.getPredicatesTable();
00129     pattern = PatternSaverLoader.getPattern(tlp.getPatternName(), tlp.getPatternScope());
00130     patternParamIterator = pattern.getParametersOccurenceOrder().iterator();
00131     LinkedList processedPreds = new LinkedList();
00132 
00133     // Iterate through the predicate table
00134     for (Enumeration e = ptab.keys(); e.hasMoreElements(); )
00135     {
00136         APredicateExp n = (APredicateExp) e.nextElement();
00137 
00138         // We get the expression and its string representation
00139         Predicate pred = (Predicate) ptab.get(n);
00140 
00141         // Get the declaring class
00142         String className = pred.getType().getFullyQualifiedName();
00143         Class theClass = null;
00144         try {
00145             theClass = FileClassLoader.load(className);
00146         } catch (Exception exx)
00147         {
00148             throw new RuntimeException("Can't find class " + className);
00149         }
00150         java.lang.reflect.Method theMethod = null;
00151         Annotation ann = pred.getAnnotation();
00152 
00153         // Does this predicate defined above a method?
00154         if (ann instanceof MethodDeclarationAnnotation)
00155         {
00156             theMethod = getMatchedMethod(theClass, ((MethodDeclarationAnnotation) ann).getSootMethod());
00157             if (theMethod == null) throw new RuntimeException("Method not found!");
00158         }
00159         // So, at this point we get the class and the corresponding method.
00160 
00161         // Resolve Java predicate naming
00162         PPropositionDefinition node = (PPropositionDefinition) pred.getNode();
00163         String predFileName = className;
00164         if (theMethod != null) predFileName += ("$"+theMethod.getName());
00165         predFileName += ("$" + node.getId().getText());
00166 
00167         // Is this predicate have been processed? (to avoid rewriting files)
00168         if (!processedPreds.contains(predFileName))
00169         {
00170             try {
00171                 // Call JPF's BSL translator
00172                 node.apply(new Translation(theClass, theMethod, tempDir));
00173 
00174                 // Compile it
00175                 BanderaUtil.runJavac(classpath, tempDir + File.separator + predFileName + ".java");
00176 
00177                 // Mark this as already processed
00178                 processedPreds.add(predFileName);
00179             } catch (Exception exx)
00180             {
00181                 throw new RuntimeException("Error: " + exx.getMessage());
00182             }
00183         }
00184 
00185         // We then have to inject the correct parameter. (if any)
00186         if (n.getArgs() != null)
00187         {
00188             Hashtable qtab = tlp.getQuantifiersTable();
00189             String params = "";
00190 
00191             PArgs predArg;
00192 
00193             do {
00194                 predArg = n.getArgs();
00195 
00196                 String argId;
00197                 if (predArg instanceof AArgsArgs)
00198                 {
00199                     AArgsArgs multiArgs = (AArgsArgs) predArg;
00200                     predArg = multiArgs.getArgs();
00201                     argId = multiArgs.getId().toString();
00202                 } else if (predArg instanceof AIdArgs)
00203                 {
00204                     AIdArgs singleArg = (AIdArgs) predArg;
00205                     argId = singleArg.getId().toString();
00206                 } else {
00207                     throw new RuntimeException("Unknown predicate parameter: "+predArg);
00208                 }
00209 
00210                 try {
00211                     QuantifiedVariable qv = (QuantifiedVariable) qtab.get(argId.trim());
00212                     //argId = qv.getType().toString()+".quantification$"+qv.getName();  // No!! We can't do this!
00213                     argId = getQualifiedNameForQv(qv.getName());  // Because the quantified variable may be placed in different class
00214                     // Warning: This translation assumes qv.getName() always returns simple name, not fully qualified one.
00215                 } catch (Exception exx)
00216                 {
00217                     exx.printStackTrace();
00218                     throw new RuntimeException("Parameter "+argId+" is not in the table:\n"+exx.getMessage());
00219                 }
00220                 if (!"".equals(params)) params = argId + ", "+ params; else params = argId;
00221             } while (predArg instanceof AArgsArgs);
00222         
00223             // Put the name subtitution inside the table
00224             System.out.println(predFileName + "(" + params + ") added");
00225             patternNodeTable.put(n, "\"" + predFileName + "(" + params + ")\"");
00226         } else
00227         {
00228             // If there are no parameters, then we simply put the predicate file name.
00229             patternNodeTable.put(n, "\"" + predFileName + "\"");
00230         }
00231     }
00232 
00233     // Up to this point, all .java files needed for JPF predicate
00234     // evaluation is setup and compiled. We have already had the pattern node symbols table.
00235     // Then we need to setup pattern name subtitution table: i.e. S->foo, P->baz
00236     // This can be achieved by visiting the predicate AST node (no other way)
00237     tlp.getNode().apply(this);
00238 
00239     // Then we need to check whether we have quantified variables
00240     if (qList != null && qList.size() > 0) // Yes, so we need to build "Select.java" appropriately
00241     {
00242         String lineSep = System.getProperty("line.separator");
00243 
00244         StringBuffer selectbuf = new StringBuffer();
00245         
00246         // Stamp out the preamble
00247         selectbuf.append("import gov.nasa.arc.ase.jpf.jvm.State;" + lineSep);
00248         selectbuf.append("import gov.nasa.arc.ase.jpf.jvm.Reference;" + lineSep);
00249         selectbuf.append("import gov.nasa.arc.ase.jpf.jvm.Thread;" + lineSep + lineSep);
00250         selectbuf.append("public class Selected {" + lineSep);
00251         selectbuf.append("     public static boolean evaluate(State state, Reference _this) {" + lineSep);
00252         selectbuf.append("          return _this != null");
00253 
00254 /*      for (Iterator qi = qList.iterator(); qi.hasNext(); )
00255         {
00256             QuantifierClassPair qcp = (QuantifierClassPair) qi.next();
00257             selectbuf.append("state.getClass(\""+qcp.getClassName()+"\").getObjectField(\""+
00258                 qcp.getFieldName()+"\") != null");
00259         
00260             if (qi.hasNext())
00261                 selectbuf.append(" &&" + lineSep + "                      ");
00262         }
00263 */
00264         // Setup the epilogue
00265         selectbuf.append(";" + lineSep);
00266 /*      selectbuf.append("          } catch (Exception e) {" + lineSep);
00267         selectbuf.append("               return false;" + lineSep);
00268         selectbuf.append("          }"+lineSep);
00269 */
00270         selectbuf.append("     }"+lineSep);
00271         selectbuf.append("}" + lineSep);
00272 
00273         // Prepare the file to dump the output
00274         String completeName = tempDir + File.separator + "Selected.java";
00275         System.out.println(completeName);
00276         
00277         try {
00278             PrintStream javaPrint = new PrintStream(new FileOutputStream(new File(completeName)));
00279             javaPrint.print(selectbuf.toString());
00280             javaPrint.close();
00281 
00282             // Then compile that file
00283             BanderaUtil.runJavac(classpath, completeName);
00284         } catch (IOException ex)
00285         {
00286             throw new RuntimeException("Cannot create file '" + completeName + "'");
00287         }
00288     }
00289     } catch (Exception suckers)
00290     {
00291         suckers.printStackTrace();
00292     }
00293 }
00294 public String getFormula(String mapping)
00295 {
00296     if ("LTL".equalsIgnoreCase(mapping))
00297         return getLTLFormula();
00298 
00299 
00300     throw new RuntimeException("Mapping to " + mapping + " is currently not supported");
00301 }
00302 private String getLTLFormula()
00303 {
00304     // Build our LTL formula
00305     String ltlFormula;
00306     
00307     try {
00308         ltlFormula = pattern.expandMapping("ltl", patternNameTable);
00309     } catch (Exception e)
00310     {
00311         throw new RuntimeException("Pattern mapping not supported!\nTable:\n"+patternNameTable);
00312     }
00313 
00314     // If we have quantified variables, we need to modify the
00315     // LTL Formula into the form:
00316     // (!Selected U (Selected && Predicate)) || [] (!Selected)
00317     if (qList != null && qList.size() > 0)
00318     {
00319         StringBuffer sel = new StringBuffer();
00320         for (Iterator qi = qList.iterator(); qi.hasNext(); )
00321         {
00322             QuantifierClassPair qcp = (QuantifierClassPair) qi.next();
00323             sel.append("Selected("+qcp.getClassName()+"."+qcp.getFieldName()+")");
00324 
00325             if (qi.hasNext()) sel.append(" && ");
00326         }
00327         String selected = "\"" + sel.toString() + "\"";
00328         ltlFormula = "(!"+selected+" U ("+selected+" /\\ (" + ltlFormula + "))) \\/ []!"+selected;
00329     }
00330 
00331     // Notice that JPF's LTL format is incompatible to ours. So convert it first
00332     int lastpos = 0;
00333 
00334     // convert the && -> /\
00335     do {
00336         lastpos = ltlFormula.indexOf("&&", lastpos);
00337         if (lastpos != -1)
00338             ltlFormula = ltlFormula.substring(0,lastpos) + "/\\" + ltlFormula.substring(lastpos+2);
00339     } while (lastpos != -1);
00340 
00341     lastpos = 0;
00342 
00343     // convert the || -> \/
00344     do {
00345         lastpos = ltlFormula.indexOf("||", lastpos);
00346         if (lastpos != -1)
00347             ltlFormula = ltlFormula.substring(0,lastpos) + "\\/" + ltlFormula.substring(lastpos+2);
00348     } while (lastpos != -1);
00349 
00350     // At this point, our LTL formula is ready to go!
00351     return ltlFormula;
00352 }
00353 private Method getMatchedMethod(Class theClass, SootMethod sm)
00354 {
00355     Method[] methods = theClass.getDeclaredMethods();
00356 
00357     int max = methods.length;
00358     String name = sm.getName();
00359     if (name == null) throw new RuntimeException("Error! Bogus Soot Method!");
00360 
00361     for (int i = 0; i < max; i++)
00362     {
00363         Method m = methods[i];
00364         if (!name.equals(m.getName())) continue; // Not the same name
00365         Class[] params = m.getParameterTypes();
00366         int maxParams = params.length;
00367         if (sm.getParameterCount() != maxParams) continue; // Not the same number of params
00368         boolean found = true;
00369 
00370         for (int j = 0; j < maxParams; j++)
00371         {
00372             Class p1 = params[j];
00373             String sig = getTypeString(p1);
00374             Type t1 = sm.getParameterType(i);
00375             if (!sig.equals(t1.toString().trim()))
00376             {
00377                 found = false; break;
00378             }
00379         }
00380         if (found) return m;
00381     }
00382 
00383     return null;
00384 }
00385     private String getQualifiedNameForQv(String v)
00386     {
00387         for (Iterator i = qList.iterator(); i.hasNext(); )
00388         {
00389             QuantifierClassPair qcp = (QuantifierClassPair) i.next();
00390             if (qcp.getFieldName().equals("quantification$"+v))
00391                 return qcp.toString();
00392         }
00393         return null;
00394     }
00395     private String getTypeString(Class c)
00396     {
00397         if (c.isArray()) return getTypeString(c.getComponentType())+"[]";
00398         return c.getName();
00399     }
00400 }

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