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); }