public void printLanguageSemantics() { Console.WriteLine("-------------------------------------------------------------"); Console.WriteLine("Language Extensions:"); Console.WriteLine("Thread spawn : \"async call n := foo(...)\" \t Returns thread id"); LanguageSemantics.print(); Console.WriteLine("-------------------------------------------------------------"); }
public override Procedure VisitProcedure(Procedure node) { // Make sure not to visit the same Procedure twice if (allProcs.Contains(node.Name)) { return(node); } allProcs.Add(node.Name); if (node.Name.Equals(mainProcName)) { mainProcExists = true; /* * // Check if this guy takes input parameters * if (node.InParams.Length != 0) * { * throw new InvalidProg("main procedure " + node.Name + " has input paramters"); * } * * if (node.OutParams.Length != 0) * { * Console.WriteLine("Warning: output parameters of the main procedure will be ignored"); * } */ } // Keep record of all modified globals foreach (IdentifierExpr ie in node.Modifies) { GlobalVariable g = (GlobalVariable)ie.Decl; if (g == null) { continue; } if (!modifiedGlobals.ContainsKey(g.Name)) { modifiedGlobals.Add(g.Name, g); } } // No need to go down into a procedure //node.Modifies = this.VisitIdentifierExprSeq(node.Modifies); //node.InParams = this.VisitVariableSeq(node.InParams); //node.OutParams = this.VisitVariableSeq(node.OutParams); if (node.Name == LanguageSemantics.getThreadIDName() || node.Name == LanguageSemantics.getChildThreadIDName()) { Debug.Assert(node.OutParams.Count == 1); if (node.OutParams[0].TypedIdent.Type.IsBv) { threadIdType = node.OutParams[0].TypedIdent.Type; } } return(node); }
public InstrumentationPolicy(int K, HashSet <string> glob, HashSet <string> procsWithImpl, HashSet <string> asyncProcs, HashSet <Tuple <string, string> > recursiveProcs, ConcurrencyMode mode) { executionContextBound = K; globalsToInstrument = glob; this.procsWithImpl = procsWithImpl; this.asyncProcs = asyncProcs; this.recursiveProcs = recursiveProcs; this.mode = mode; atomicBeginProcName = LanguageSemantics.atomicBeginProcName(); atomicEndProcName = LanguageSemantics.atomicEndProcName(); assertNotReachableName = LanguageSemantics.assertNotReachableName(); getThreadIDName = LanguageSemantics.getThreadIDName(); }
public override CBAProgram runCBAPass(CBAProgram p) { if (p.mode == ConcurrencyMode.FixedContext) { InstrumentationConfig.addRaiseException = false; } // Step1: Gather program information pinfo = new ProgramInfo(p.mainProcName, p, LanguageSemantics.assertNotReachableName()); TidArithmetic.reset(); if (pinfo.threadIdType.IsBv) { TidArithmetic.useIntArithmetic = false; p.AddTopLevelDeclaration(TidArithmetic.getBvAdd()); p.AddTopLevelDeclaration(TidArithmetic.getBvGt()); } else { TidArithmetic.useIntArithmetic = true; } // Step2: Set up a variable manager vmgr = new VariableManager(pinfo); // Step3: Set up the instrumentation policy // The globals not to instrument are: // -- ones not modified by any procedure // -- ones not shared // -- ones to treat as thread-local HashSet <string> globalsToInstrument = new HashSet <string>(); foreach (var g in pinfo.declaredGlobals) { string name = g.Key; if (!pinfo.modifiedGlobals.ContainsKey(name)) { continue; } if (!LanguageSemantics.isShared(name)) { continue; } if (pinfo.threadLocalGlobals.ContainsKey(name)) { continue; } globalsToInstrument.Add(name); } var rprocs = findRecursiveProcs(p); //foreach (var be in rprocs) Console.WriteLine("{0} -> {1}", be.Item1, be.Item2); policy = new InstrumentationPolicy(p.contextBound, globalsToInstrument, pinfo.procsWithImplementation, pinfo.asyncProcs, rprocs, p.mode); //policy.print(Log.getWriter(Log.Debug)); // Step4: Split program declarations based on the instrumentation policy // skipping this step (not needed for basic CBA reduction) // Step5: Carry out the K-split instrumentation inst = new Instrumenter(policy, vmgr, pinfo, tinfo_instrument); List <Declaration> newDecls = inst.instrument(p.TopLevelDeclarations.ToList()); foreach (var trp in inst.blocksWithFixedK) { blockExecutionContextMap.Add(trp.fst + "::" + trp.snd, trp.trd); } // Step6: Instrument main with initialization and the Checker Implementation mainProcImpl = BoogieUtil.findProcedureImpl(newDecls, p.mainProcName); inst.instrumentGivenMainImpl(mainProcImpl); // Step7: Instrument Async calls bool instrumentedAsync = false; InstrumentAsyncCalls ainst = new InstrumentAsyncCalls(vmgr, pinfo, tinfo_async); foreach (var decl in newDecls) { if (decl is Implementation) { ainst.VisitImplementation(decl as Implementation); instrumentedAsync = instrumentedAsync || ainst.hasAsync; } } if (!instrumentedAsync) { Log.WriteLine(Log.Debug, "Warning: Did not find any async call"); } // Step8: Set entrypoint mainProcImpl.AddAttribute("entrypoint"); // Step9: Add new variable declarations newDecls.AddRange(vmgr.getNewDeclarations(policy.executionContextBound)); newDecls.AddRange(BoogieAstFactory.newDecls); BoogieAstFactory.newDecls.Clear(); // Thats it. Program ret = new Program(); ret.TopLevelDeclarations = newDecls; if (InstrumentationConfig.printInstrumented) { // Re-resolve ret ProgTransformation.PersistentProgram tprog = new ProgTransformation.PersistentProgram(ret); var instrumented = tprog.getProgram(); // Re-do the modsets -- make them as concise as possible. BoogieUtil.DoModSetAnalysis(instrumented); // Temporary fix for Boogie's bug while inlining calls // that have don't care expressions. RewriteCallDontCares rdc = new RewriteCallDontCares(); rdc.VisitProgram(instrumented); BoogieUtil.PrintProgram(instrumented, InstrumentationConfig.instrumentedFile); throw new NormalExit("Printed " + InstrumentationConfig.instrumentedFile); } // Resolve the program (Do not typecheck because that does inlining). //BoogieUtil.PrintProgram(ret, "instrumented.bpl"); //ret = BoogieUtil.ReadAndOnlyResolve("instrumented.bpl"); if (p.mode == ConcurrencyMode.FixedContext) { InstrumentationConfig.addRaiseException = true; } p = new CBAProgram(ret, p.mainProcName, p.contextBound); return(p); }
// Return the set of all procedures that can trasitively reach // an assertion, or another procedure's requires private HashSet <string> procsWithAssertions(Program program) { // Build a call graph and mark procedures with assertions in them Dictionary <string, HashSet <string> > callSucc = new Dictionary <string, HashSet <string> >(); Dictionary <string, HashSet <string> > callPred = new Dictionary <string, HashSet <string> >(); HashSet <string> hasAssert = new HashSet <string>(); foreach (var decl in program.TopLevelDeclarations) { if (decl is Implementation) { var impl = decl as Implementation; callSucc.Add(impl.Name, new HashSet <string>()); foreach (var block in impl.Blocks) { foreach (var cmd in block.Cmds) { if (cmd is AssertCmd) { hasAssert.Add(impl.Name); } if (cmd is CallCmd) { var ccmd = cmd as CallCmd; callSucc[impl.Name].Add(ccmd.Proc.Name); if (LanguageSemantics.assertNotReachableName() == ccmd.Proc.Name) { hasAssert.Add(impl.Name); } } } } } } // Build the predecessor map foreach (var kvp in callSucc) { if (!callPred.ContainsKey(kvp.Key)) { callPred.Add(kvp.Key, new HashSet <string>()); } foreach (var tgt in kvp.Value) { if (!callPred.ContainsKey(tgt)) { callPred.Add(tgt, new HashSet <string>()); } callPred[tgt].Add(kvp.Key); } } // Requires become asserts on the caller. // (No need to bother about ensures because if we're not interested // in a procedure, then we don't care about verifying its ensures either) foreach (var decl in program.TopLevelDeclarations) { if (decl is Procedure) { var proc = decl as Procedure; foreach (Requires re in proc.Requires) { if (re.Free) { continue; } if (!callPred.ContainsKey(proc.Name)) { continue; } foreach (var pred in callPred[proc.Name]) { hasAssert.Add(pred); } } } } // Now propagate hasAssert to all its predecessors var done = false; while (!done) { var newproc = new HashSet <string>(); foreach (var proc in hasAssert) { foreach (var pred in callPred[proc]) { newproc.Add(pred); } } if (newproc.Any(x => !hasAssert.Contains(x))) { hasAssert.UnionWith(newproc); } else { done = true; } } return(hasAssert); }
public override CBAProgram runCBAPass(CBAProgram p) { if (!aggressive) { return(null); } var procsWithAsserts = procsWithAssertions(p); HashSet <string> procsToDelete = new HashSet <string>(); // Gather the set of procedures to delete foreach (Declaration d in p.TopLevelDeclarations) { if (d is Procedure) { var proc = d as Procedure; if (proc.Name.Equals(p.mainProcName)) { continue; } if (procsWithAsserts.Contains(proc.Name)) { continue; } if (proc.OutParams.Count > 0) { continue; } var modifiesShared = false; foreach (IdentifierExpr ie in proc.Modifies) { if (LanguageSemantics.isShared(ie.Decl.Name)) { modifiesShared = true; break; } } if (!modifiesShared) { procsToDelete.Add(proc.Name); } } } // Delete the implementations CBAProgram ret = new CBAProgram(new Program(), p.mainProcName, p.contextBound); foreach (Declaration d in p.TopLevelDeclarations) { if (d is Implementation) { Implementation impl = d as Implementation; if (procsToDelete.Contains(impl.Name) && !BoogieUtil.hasAssert(impl)) { Log.WriteLine(Log.Debug, "Deleting " + impl.Name); continue; } ret.AddTopLevelDeclaration(d); } else { ret.AddTopLevelDeclaration(d); } } Log.WriteLine(Log.Debug, "Empty Mod Sets: Deleted " + (p.TopLevelDeclarations.Count() - ret.TopLevelDeclarations.Count()).ToString() + " implementations"); return(ret); }
// -- There should be no ensures and requires on shared globals // -- For ensures and requires on non-shared globals, they should be "free" // -- One cannot use "old" versions of shared globals private static void checkProc(Procedure proc, HashSet <string> procsWithImpl, HashSet <string> procsNotCalled) { VarsUsed used = new VarsUsed(); foreach (Requires re in proc.Requires) { used.reset(); used.Visit(re.Condition); if (used.globalsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Requires has a shared global"); } if (used.oldVarsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Requires has an \"old\" shared global"); } if (used.globalsUsed.Count == 0) { continue; } // We dont care about requires on pros that are not called if (procsNotCalled.Contains(proc.Name)) { continue; } if (re.Free == false) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("A non-free requires has a non-shared global (not yet supported)"); } } foreach (Ensures re in proc.Ensures) { used.reset(); used.Visit(re.Condition); if (used.globalsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Ensures has a shared global"); } if (used.oldVarsUsed.Any(v => LanguageSemantics.isShared(v))) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("Ensures has an \"old\" shared global"); } /* * if (used.globalsUsed.Count == 0) * { * continue; * } */ // "Ensures" in procs without implementation are considered free if (re.Free == false && procsWithImpl.Contains(proc.Name)) { re.Emit(new TokenTextWriter(Console.Out), 0); throw new InvalidInput("A non-free ensures is not yet supported"); } } }