public override Cmd VisitCallCmd(CallCmd node) { CallCmd callCmd = (CallCmd) base.VisitCallCmd(node); callCmd.Proc = VisitProcedure(callCmd.Proc); callCmd.callee = callCmd.Proc.Name; absyMap[callCmd] = node; return callCmd; }
public override bpl.Cmd VisitCallCmd(bpl.CallCmd node) { if (callGraph[curProc].ContainsKey(node.callee)) { callGraph[curProc][node.callee]++; } else { callGraph[curProc][node.callee] = 1; } visited[node.callee] = 0; if (con.isAsyncCall(node)) { instances[node.callee] = 0; } return(base.VisitCallCmd(node)); }
private void addMethodCalling(Bpl.Procedure proc, Bpl.Program program, Sink sink) { Bpl.Procedure callingProc = new Bpl.Procedure(Bpl.Token.NoToken, "__BOOGIE_CALL_" + proc.Name, new List <Bpl.TypeVariable>(), new List <Bpl.Variable>(), new List <Bpl.Variable>(), new List <Bpl.Requires>(), new List <Bpl.IdentifierExpr>(), new List <Bpl.Ensures>()); sink.TranslatedProgram.AddTopLevelDeclaration(callingProc); Bpl.StmtListBuilder codeBuilder = new Bpl.StmtListBuilder(); List <Bpl.Variable> localVars = new List <Bpl.Variable>(proc.InParams); List <Bpl.IdentifierExpr> identVars = new List <Bpl.IdentifierExpr>(); for (int i = 0; i < localVars.Count; i++) { identVars.Add(new Bpl.IdentifierExpr(Bpl.Token.NoToken, localVars[i])); } codeBuilder.Add(new Bpl.HavocCmd(Bpl.Token.NoToken, identVars)); // FEEDBACK TODO this is possibly too much, I'm guessing sometimes this args might well be null Bpl.Expr notNullExpr; foreach (Bpl.IdentifierExpr idExpr in identVars) { if (idExpr.Type.Equals(sink.Heap.RefType)) { notNullExpr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, idExpr, Bpl.Expr.Ident(sink.Heap.NullRef)); codeBuilder.Add(new Bpl.AssumeCmd(Bpl.Token.NoToken, notNullExpr)); } } List <Bpl.Expr> callParams = new List <Bpl.Expr>(); for (int i = 0; i < identVars.Count; i++) { callParams.Add(identVars[i]); } Bpl.CallCmd callCmd = new Bpl.CallCmd(Bpl.Token.NoToken, proc.Name, callParams, new List <Bpl.IdentifierExpr>()); codeBuilder.Add(callCmd); Bpl.Implementation impl = new Bpl.Implementation(Bpl.Token.NoToken, callingProc.Name, new List <Bpl.TypeVariable>(), new List <Bpl.Variable>(), new List <Bpl.Variable>(), localVars, codeBuilder.Collect(Bpl.Token.NoToken)); sink.TranslatedProgram.AddTopLevelDeclaration(impl); }
private void ProcessCallCmd(CallCmd originalCallCmd, CallCmd callCmd, List<Cmd> newCmds) { int enclosingProcLayerNum = moverTypeChecker.procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; Procedure originalProc = originalCallCmd.Proc; if (moverTypeChecker.procToActionInfo.ContainsKey(originalProc)) { AtomicActionInfo atomicActionInfo = moverTypeChecker.procToActionInfo[originalProc] as AtomicActionInfo; if (atomicActionInfo != null && atomicActionInfo.thisGate.Count > 0 && layerNum == enclosingProcLayerNum) { newCmds.Add(new HavocCmd(Token.NoToken, new List<IdentifierExpr>(new IdentifierExpr[] { Expr.Ident(dummyLocalVar) }))); Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); for (int i = 0; i < originalProc.InParams.Count; i++) { map[originalProc.InParams[i]] = callCmd.Ins[i]; } Substitution subst = Substituter.SubstitutionFromHashtable(map); foreach (AssertCmd assertCmd in atomicActionInfo.thisGate) { newCmds.Add(Substituter.Apply(subst, assertCmd)); } } } newCmds.Add(callCmd); }
public void AddRecordCall(string label, Bpl.Type typeBpl, Bpl.Expr valueBpl) { /* Without this, some record calls show up on the wrong source lines in * the Corral trace or don't show up at all. With it, the number of extra * blank lines in the trace increases in some cases but not in others. I * think we're better off with this line. TODO: understand how Corral * line directives are actually supposed to be used. * ~ REDACTED 2016-07-08 */ EmitSecondaryLineDirective(Bpl.Token.NoToken); var logProcedureName = sink.FindOrCreateRecordProcedure(typeBpl); var call = new Bpl.CallCmd(Bpl.Token.NoToken, logProcedureName, new List <Bpl.Expr> { valueBpl }, new List <Bpl.IdentifierExpr> { }); // This seems to be the idiom (see Bpl.Program.addUniqueCallAttr). // XXX What does the token mean? Should there be one? // ~ REDACTED 2016-06-13 call.Attributes = new Bpl.QKeyValue(Bpl.Token.NoToken, "cexpr", new List <object> { label }, call.Attributes); StmtBuilder.Add(call); }
public override Cmd VisitCallCmd(CallCmd node) { HashSet<Variable> inVars = new HashSet<Variable>(); for (int i = 0; i < node.Proc.InParams.Count; i++) { Variable formal = node.Proc.InParams[i]; string domainName = FindDomainName(formal); if (domainName == null) continue; IdentifierExpr actual = node.Ins[i] as IdentifierExpr; if (actual == null) { Error(node, string.Format("Only variable can be passed to linear parameter {0}", formal.Name)); continue; } string actualDomainName = FindDomainName(actual.Decl); if (actualDomainName == null) { Error(node, string.Format("Only a linear argument can be passed to linear parameter {0}", formal.Name)); continue; } if (domainName != actualDomainName) { Error(node, "The domains of formal and actual parameters must be the same"); continue; } if (actual.Decl is GlobalVariable) { Error(node, "Only local linear variable can be an actual input parameter of a procedure call"); continue; } if (inVars.Contains(actual.Decl)) { Error(node, string.Format("Linear variable {0} can occur only once as an input parameter", actual.Decl.Name)); continue; } inVars.Add(actual.Decl); } for (int i = 0; i < node.Proc.OutParams.Count; i++) { IdentifierExpr actual = node.Outs[i]; string actualDomainName = FindDomainName(actual.Decl); if (actualDomainName == null) continue; Variable formal = node.Proc.OutParams[i]; string domainName = FindDomainName(formal); if (domainName == null) { Error(node, "Only a linear variable can be passed to a linear parameter"); continue; } if (domainName != actualDomainName) { Error(node, "The domains of formal and actual parameters must be the same"); continue; } if (actual.Decl is GlobalVariable) { Error(node, "Only local linear variable can be actual output parameter of a procedure call"); continue; } } return base.VisitCallCmd(node); }
public override Cmd VisitCallCmd(CallCmd node) { if (currentDeclaration != null) { currentDeclaration.AddProcedureDependency(node.Proc); } return base.VisitCallCmd(node); }
public override Cmd VisitCallCmd(CallCmd node) { Contract.Ensures(Contract.Result<Cmd>() == node); for (int i = 0; i < node.Ins.Count; ++i) if (node.Ins[i] != null) this.VisitExpr(node.Ins[i]); for (int i = 0; i < node.Outs.Count; ++i) if (node.Outs[i] != null) this.VisitIdentifierExpr(node.Outs[i]); return node; }
public override Cmd VisitCallCmd(CallCmd node) { var visited = dependencies.Contains(node.Proc); if (!visited) { node.Proc = VisitProcedure(node.Proc); } return base.VisitCallCmd(node); }
public bool CallExists(CallCmd callCmd, int enclosingProcLayerNum, int layerNum) { Debug.Assert(procToAtomicProcedureInfo.ContainsKey(callCmd.Proc)); var atomicProcedureInfo = procToAtomicProcedureInfo[callCmd.Proc]; if (atomicProcedureInfo.isPure) { return pureCallLayer[callCmd] <= layerNum; } else { return enclosingProcLayerNum == layerNum; } }
void CallParams(bool isAsync, bool isFree, QKeyValue kv, IToken x, out Cmd c) { List<IdentifierExpr> ids = new List<IdentifierExpr>(); List<Expr> es = new List<Expr>(); Expr en; IToken first; IToken p; c = null; Ident(out first); if (la.kind == 10) { Get(); if (StartOf(9)) { Expression(out en); es.Add(en); while (la.kind == 13) { Get(); Expression(out en); es.Add(en); } } Expect(11); c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; } else if (la.kind == 13 || la.kind == 51) { ids.Add(new IdentifierExpr(first, first.val)); if (la.kind == 13) { Get(); Ident(out p); ids.Add(new IdentifierExpr(p, p.val)); while (la.kind == 13) { Get(); Ident(out p); ids.Add(new IdentifierExpr(p, p.val)); } } Expect(51); Ident(out first); Expect(10); if (StartOf(9)) { Expression(out en); es.Add(en); while (la.kind == 13) { Get(); Expression(out en); es.Add(en); } } Expect(11); c = new CallCmd(x, first.val, es, ids, kv); ((CallCmd) c).IsFree = isFree; ((CallCmd) c).IsAsync = isAsync; } else SynErr(112); }
// Redundant for this class; but gives a chance for other classes to // override this and implement their own inlining policy protected virtual int GetInlineCount(CallCmd callCmd, Implementation impl) { return GetInlineCount(impl); }
private void CreateStructCopyConstructor(ITypeDefinition typeDefinition) { Contract.Requires(typeDefinition.IsStruct); var proc = this.sink.FindOrCreateProcedureForStructCopy(typeDefinition); var stmtBuilder = new Bpl.StmtListBuilder(); var tok = Bpl.Token.NoToken; var o = Bpl.Expr.Ident(proc.OutParams[0]); // other := Alloc(); stmtBuilder.Add(new Bpl.CallCmd(tok, this.sink.AllocationMethodName, new List <Bpl.Expr>(), new List <Bpl.IdentifierExpr>(new Bpl.IdentifierExpr[] { o }))); // assume DynamicType(other) == DynamicType(this); stmtBuilder.Add(new Bpl.AssumeCmd(tok, Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq, this.sink.Heap.DynamicType(o), this.sink.Heap.DynamicType(Bpl.Expr.Ident(proc.InParams[0]))))); var localVars = new List <Bpl.Variable>(); foreach (var f in typeDefinition.Fields) { if (f.IsStatic) { continue; } var fExp = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(f)); var boogieType = sink.CciTypeToBoogie(f.Type); if (TranslationHelper.IsStruct(f.Type)) { // generate a call to the copy constructor to copy the contents of f var proc2 = this.sink.FindOrCreateProcedureForStructCopy(f.Type); var e = this.sink.Heap.ReadHeap(Bpl.Expr.Ident(proc.InParams[0]), fExp, AccessType.Struct, boogieType); var bplLocal = this.sink.CreateFreshLocal(f.Type); var localExpr = Bpl.Expr.Ident(bplLocal); localVars.Add(bplLocal); var cmd = new Bpl.CallCmd(tok, proc2.Name, new List <Bpl.Expr> { e, }, new List <Bpl.IdentifierExpr> { localExpr, }); stmtBuilder.Add(cmd); this.sink.Heap.WriteHeap(tok, o, fExp, localExpr, AccessType.Struct, boogieType, stmtBuilder); } else { // just generate a normal assignment to the field f var e = this.sink.Heap.ReadHeap(Bpl.Expr.Ident(proc.InParams[0]), fExp, AccessType.Struct, boogieType); this.sink.Heap.WriteHeap(tok, o, fExp, e, AccessType.Struct, boogieType, stmtBuilder); } } var lit = Bpl.Expr.Literal(1); lit.Type = Bpl.Type.Int; var args = new List <object> { lit }; var attrib = new Bpl.QKeyValue(typeDefinition.Token(), "inline", args, null); Bpl.Implementation impl = new Bpl.Implementation(Bpl.Token.NoToken, proc.Name, new List <Bpl.TypeVariable>(), proc.InParams, proc.OutParams, localVars, stmtBuilder.Collect(Bpl.Token.NoToken), attrib, new Bpl.Errors() ); impl.Proc = (Bpl.Procedure)proc; // TODO: get rid of cast this.sink.TranslatedProgram.AddTopLevelDeclaration(impl); }
public bpl.Program split(bpl.Program prog) { originalProgram = prog; ////////////////// First identify the thread entries in the program //////////////////// // A procedure is a thread entry if there is any async call to it HashSet <string> threadEntries = new HashSet <string>(); var impls = new Func <bpl.Program, IEnumerable <bpl.Implementation> >(p => from impl in p.TopLevelDeclarations where impl is bpl.Implementation select impl as bpl.Implementation); foreach (var impl in impls(originalProgram)) { var cmdsRaw = from blk in impl.Blocks select blk.Cmds; var cmds = cmdsRaw.Aggregate(new List <bpl.Cmd>(), (curCmds, nextList) => { curCmds.AddRange(nextList); return(curCmds); }); var asyncCalls = from cmd in cmds where con.isAsyncCall(cmd as bpl.Cmd) select cmd; foreach (bpl.Cmd asyncCall in asyncCalls) { threadEntries.Add((asyncCall as bpl.CallCmd).callee); } } // Finally add the entry function also as a thread entry. threadEntries.Add(con.entryFunc); //////////////// Next, identify all the procedures belonging to each thread //////////// Dictionary <string, HashSet <string> > threadToProcs = new Dictionary <string, HashSet <string> >(); // This is done in two steps. // First step: Find all non-async calls in each procedure. var procToCalls = new Dictionary <string, HashSet <string> >(); //impls = from impl in prog.TopLevelDeclarations where impl is bpl.Implementation select impl as bpl.Implementation; foreach (var impl in impls(originalProgram)) { procToCalls[impl.Name] = new HashSet <string>(); var cmdsRaw = from blk in impl.Blocks select blk.Cmds; var cmds = cmdsRaw.Aggregate(new List <bpl.Cmd>(), (curCmds, nextList) => { curCmds.AddRange(nextList); return(curCmds); }); var syncCalls = from cmd in cmds where con.isSyncCall(cmd as bpl.Cmd) select cmd; foreach (bpl.Cmd syncCall in syncCalls) { procToCalls[impl.Name].Add((syncCall as bpl.CallCmd).callee); } } // Second step: Find all procedures in each thread. foreach (var thr in threadEntries) { threadToProcs[thr] = new HashSet <string>(); } foreach (var thr in threadEntries) { findReachable(procToCalls, thr, threadToProcs[thr]); } //DEBUGGING if (dbg) { System.Console.WriteLine("Threads in the original program:"); foreach (var iter in threadToProcs) { System.Console.Write(iter.Key + ": "); foreach (var proc in iter.Value) { System.Console.Write(proc + " "); } System.Console.WriteLine(); } } // [Optional] // Remove unreachable procs. // These procedures are neither reachable from Main, nor from a thread entry. They can obviously not be called in any execution. var reachableProcs = new HashSet <string>(); foreach (var vals in threadToProcs.Values) { foreach (var proc in vals) { reachableProcs.Add(proc); } } foreach (var val in threadToProcs.Keys) { reachableProcs.Add(val); } removeUnreachable(reachableProcs); //////////////// Finally, Actually split the procedures when needed ////////////////// // For every procedure, find out how many threads contain it. We need as many copies of // that procedure. // Note: We do not want to duplicate procedures without implementation. //impls = from impl in prog.TopLevelDeclarations where impl is bpl.Implementation select impl as bpl.Implementation; var implNames = from impl in impls(originalProgram) select impl.Name; Dictionary <string, int> procCopies = new Dictionary <string, int>(); var procs = from proc in originalProgram.TopLevelDeclarations where proc is bpl.Procedure select proc as bpl.Procedure; foreach (var proc in procs) { procCopies[proc.Name] = 0; } foreach (var iter in threadToProcs) { foreach (var proc in iter.Value) { if (implNames.Contains(proc)) { procCopies[proc]++; } } } // Now duplicate // The new procedures and implementations for each thread // thread name --> (old procedure name --> new procedure) var newProcsPerThread = new Dictionary <string, Dictionary <string, bpl.Procedure> >(); // thread name --> (old procedure name --> new implementation) var newImplsPerThread = new Dictionary <string, Dictionary <string, bpl.Implementation> >(); // old name --> proc, old name --> impl var oldNameToImpl = new Dictionary <string, bpl.Implementation>(); foreach (var impl in impls(originalProgram)) { oldNameToImpl[impl.Name] = impl; } var oldNameToProc = new Dictionary <string, bpl.Procedure>(); foreach (var proc in procs) { oldNameToProc[proc.Name] = proc; } foreach (var elem in threadToProcs) { string threadName = elem.Key; newProcsPerThread[threadName] = new Dictionary <string, bpl.Procedure>(); newImplsPerThread[threadName] = new Dictionary <string, bpl.Implementation>(); foreach (var procName in elem.Value) { if (procCopies[procName] > 1) { // We will duplicate this procedure. // Make a copy of the procedure and implementation var dup = new cba.Util.FixedDuplicator(); var impl = (bpl.Implementation)dup.VisitDeclaration(oldNameToImpl[procName]); var proc = (bpl.Procedure)dup.VisitDeclaration(oldNameToProc[procName]); impl.Proc = proc; // Rename the new instances using thread id. impl.Name = con.getSplitProcName(procName); proc.Name = con.getSplitProcName(procName); var origProcAttr = con.originalProcAttr(procName); origProcAttr.Next = proc.Attributes; proc.Attributes = origProcAttr; // Also add an attribute to the definition specifying the thread. var threadAttr = con.getThreadAttr(threadName); threadAttr.Next = proc.Attributes; proc.Attributes = threadAttr; //add to duplicated procedures/impls newProcsPerThread[threadName][procName] = proc; newImplsPerThread[threadName][procName] = impl; //Add to the program originalProgram.AddTopLevelDeclaration(proc); originalProgram.AddTopLevelDeclaration(impl); var s1 = new HashSet <string>(); var s2 = new HashSet <string>(); foreach (var im in originalProgram.TopLevelDeclarations.OfType <bpl.Implementation>()) { s1.Add(im.Name); } foreach (var im in impls(originalProgram)) { s2.Add(im.Name); } // We have split away the procedure calls for one thread. procCopies[procName]--; } else if (procCopies[procName] == 1) { //We still need to rename this procedure var impl = oldNameToImpl[procName]; var proc = oldNameToProc[procName]; //rename the new instances using thread id. impl.Name = con.getSplitProcName(procName); proc.Name = con.getSplitProcName(procName); var origProcAttr = con.originalProcAttr(procName); origProcAttr.Next = proc.Attributes; proc.Attributes = origProcAttr; // Also add an attribute to the definition specifying the thread. var threadAttr = con.getThreadAttr(threadName); threadAttr.Next = proc.Attributes; proc.Attributes = threadAttr; //add to duplicated procedures/impls newProcsPerThread[threadName][procName] = proc; newImplsPerThread[threadName][procName] = impl; // We have split away the procedure calls for one thread. procCopies[procName]--; } } // Tell con that we're done with one thread. con.nextThread(); } // New re-route procedure calls as needed // First async calls. foreach (var impl in impls(originalProgram)) { foreach (var blk in impl.Blocks) { for (int i = 0; i < blk.Cmds.Count; i++) { bpl.Cmd cmd = blk.Cmds[i]; if (con.isAsyncCall(cmd)) { var callCmd = cmd as bpl.CallCmd; var newCallCmd = new bpl.CallCmd(bpl.Token.NoToken, newProcsPerThread[callCmd.callee][callCmd.callee].Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes, callCmd.IsAsync); newCallCmd.TypeParameters = callCmd.TypeParameters; newCallCmd.Proc = newProcsPerThread[callCmd.callee][callCmd.callee]; blk.Cmds[i] = newCallCmd; } } } } // Now sync calls. foreach (var elem in newImplsPerThread) { string threadName = elem.Key; var newImpls = newImplsPerThread[threadName]; foreach (var implTuple in newImpls) { var impl = implTuple.Value; foreach (var blk in impl.Blocks) { for (int i = 0; i < blk.Cmds.Count; ++i) { bpl.Cmd cmd = blk.Cmds[i]; if (con.isSyncCall(cmd) && newProcsPerThread[threadName].ContainsKey((cmd as bpl.CallCmd).callee)) { var callCmd = cmd as bpl.CallCmd; var newCallCmd = new bpl.CallCmd(bpl.Token.NoToken, newProcsPerThread[threadName][callCmd.callee].Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes, callCmd.IsAsync); newCallCmd.TypeParameters = callCmd.TypeParameters; newCallCmd.Proc = newProcsPerThread[threadName][callCmd.callee]; blk.Cmds[i] = newCallCmd; } } } } } // Finally, label the entry of each thread as thread entry. foreach (var elem in newProcsPerThread) { var proc = elem.Value[elem.Key]; var threadEntryAttr = con.getThreadEntryAttr(); threadEntryAttr.Next = proc.Attributes; proc.Attributes = threadEntryAttr; } return(originalProgram); }
private void AddYieldProcAndImpl(List<Declaration> decls) { if (yieldProc == null) return; Program program = linearTypeChecker.program; List<Variable> inputs = new List<Variable>(); foreach (string domainName in linearTypeChecker.linearDomains.Keys) { var domain = linearTypeChecker.linearDomains[domainName]; Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Type.Bool)), true); inputs.Add(f); } foreach (IdentifierExpr ie in globalMods) { Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); inputs.Add(f); } List<Block> blocks = new List<Block>(); TransferCmd transferCmd = new ReturnCmd(Token.NoToken); if (yieldCheckerProcs.Count > 0) { List<Block> blockTargets = new List<Block>(); List<String> labelTargets = new List<String>(); int labelCount = 0; foreach (Procedure proc in yieldCheckerProcs) { List<Expr> exprSeq = new List<Expr>(); foreach (Variable v in inputs) { exprSeq.Add(Expr.Ident(v)); } CallCmd callCmd = new CallCmd(Token.NoToken, proc.Name, exprSeq, new List<IdentifierExpr>()); callCmd.Proc = proc; string label = string.Format("L_{0}", labelCount++); Block block = new Block(Token.NoToken, label, new List<Cmd> { callCmd }, new ReturnCmd(Token.NoToken)); labelTargets.Add(label); blockTargets.Add(block); blocks.Add(block); } transferCmd = new GotoCmd(Token.NoToken, labelTargets, blockTargets); } blocks.Insert(0, new Block(Token.NoToken, "enter", new List<Cmd>(), transferCmd)); var yieldImpl = new Implementation(Token.NoToken, yieldProc.Name, new List<TypeVariable>(), inputs, new List<Variable>(), new List<Variable>(), blocks); yieldImpl.Proc = yieldProc; yieldImpl.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); decls.Add(yieldProc); decls.Add(yieldImpl); }
private List<List<Cmd>> CollectAndDesugarYields(Implementation impl, Dictionary<string, Variable> domainNameToInputVar, Dictionary<string, Variable> domainNameToLocalVar, Dictionary<Variable, Variable> ogOldGlobalMap) { // Collect the yield predicates and desugar yields List<List<Cmd>> yields = new List<List<Cmd>>(); List<Cmd> cmds = new List<Cmd>(); foreach (Block b in impl.Blocks) { YieldCmd yieldCmd = null; List<Cmd> newCmds = new List<Cmd>(); for (int i = 0; i < b.Cmds.Count; i++) { Cmd cmd = b.Cmds[i]; if (cmd is YieldCmd) { yieldCmd = (YieldCmd)cmd; continue; } if (yieldCmd != null) { PredicateCmd pcmd = cmd as PredicateCmd; if (pcmd == null) { DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); if (cmds.Count > 0) { yields.Add(cmds); cmds = new List<Cmd>(); } yieldCmd = null; } else { cmds.Add(pcmd); } } if (cmd is CallCmd) { CallCmd callCmd = cmd as CallCmd; if (yieldingProcs.Contains(callCmd.Proc)) { AddCallToYieldProc(callCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); } if (callCmd.IsAsync) { if (!asyncAndParallelCallDesugarings.ContainsKey(callCmd.Proc.Name)) { asyncAndParallelCallDesugarings[callCmd.Proc.Name] = new Procedure(Token.NoToken, string.Format("DummyAsyncTarget_{0}", callCmd.Proc.Name), callCmd.Proc.TypeParameters, callCmd.Proc.InParams, callCmd.Proc.OutParams, callCmd.Proc.Requires, new List<IdentifierExpr>(), new List<Ensures>()); } var dummyAsyncTargetProc = asyncAndParallelCallDesugarings[callCmd.Proc.Name]; CallCmd dummyCallCmd = new CallCmd(callCmd.tok, dummyAsyncTargetProc.Name, callCmd.Ins, callCmd.Outs, callCmd.Attributes); dummyCallCmd.Proc = dummyAsyncTargetProc; newCmds.Add(dummyCallCmd); } else { newCmds.Add(callCmd); } if (yieldingProcs.Contains(callCmd.Proc)) { HashSet<Variable> availableLinearVars = new HashSet<Variable>(AvailableLinearVars(callCmd)); linearTypeChecker.AddAvailableVars(callCmd, availableLinearVars); if (!callCmd.IsAsync && globalMods.Count > 0 && pc != null) { // assume pc || alpha(i, g); Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); assumeExpr.Type = Type.Bool; newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); } Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); } } else if (cmd is ParCallCmd) { ParCallCmd parCallCmd = cmd as ParCallCmd; AddCallToYieldProc(parCallCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); DesugarParallelCallCmd(newCmds, parCallCmd); HashSet<Variable> availableLinearVars = new HashSet<Variable>(AvailableLinearVars(parCallCmd)); linearTypeChecker.AddAvailableVars(parCallCmd, availableLinearVars); if (globalMods.Count > 0 && pc != null) { // assume pc || alpha(i, g); Expr assumeExpr = Expr.Or(Expr.Ident(pc), alpha); assumeExpr.Type = Type.Bool; newCmds.Add(new AssumeCmd(Token.NoToken, assumeExpr)); } Dictionary<string, Expr> domainNameToExpr = ComputeAvailableExprs(availableLinearVars, domainNameToInputVar); AddUpdatesToOldGlobalVars(newCmds, ogOldGlobalMap, domainNameToLocalVar, domainNameToExpr); } else { newCmds.Add(cmd); } } if (yieldCmd != null) { DesugarYield(yieldCmd, cmds, newCmds, ogOldGlobalMap, domainNameToInputVar, domainNameToLocalVar); if (cmds.Count > 0) { yields.Add(cmds); cmds = new List<Cmd>(); } } if (b.TransferCmd is ReturnCmd) { AddCallToYieldProc(b.TransferCmd.tok, newCmds, ogOldGlobalMap, domainNameToLocalVar); if (pc != null) { AssertCmd assertCmd = new AssertCmd(b.TransferCmd.tok, Expr.Ident(ok)); assertCmd.ErrorData = "Failed to execute atomic action before procedure return"; newCmds.Add(assertCmd); } } b.Cmds = newCmds; } return yields; }
private int InlineCallCmd(Block block, CallCmd callCmd, Implementation impl, List<Cmd> newCmds, List<Block> newBlocks, int lblCount) { Contract.Assume(impl != null); Contract.Assert(cce.NonNull(impl.OriginalBlocks).Count > 0); // do inline now int nextlblCount = lblCount + 1; string nextBlockLabel = block.Label + "$" + nextlblCount; // run the callback before each inline if (inlineCallback != null) { inlineCallback(impl); } // increment the counter for the procedure to be used in constructing the locals and formals NextInlinedProcLabel(impl.Proc.Name); BeginInline(impl); List<Block/*!*/>/*!*/ inlinedBlocks = CreateInlinedBlocks(callCmd, impl, nextBlockLabel); Contract.Assert(cce.NonNullElements(inlinedBlocks)); EndInline(); if (inlineDepth >= 0) { Debug.Assert(inlineDepth > 0); inlineDepth = inlineDepth - 1; } else { recursiveProcUnrollMap[impl.Name] = recursiveProcUnrollMap[impl.Name] - 1; } bool inlinedSomething = true; inlinedBlocks = DoInlineBlocks(inlinedBlocks, ref inlinedSomething); if (inlineDepth >= 0) { inlineDepth = inlineDepth + 1; } else { recursiveProcUnrollMap[impl.Name] = recursiveProcUnrollMap[impl.Name] + 1; } Block/*!*/ startBlock = inlinedBlocks[0]; Contract.Assert(startBlock != null); GotoCmd gotoCmd = new GotoCmd(Token.NoToken, new List<String> { startBlock.Label }); Block newBlock = new Block(block.tok, ((lblCount == 0) ? (block.Label) : (block.Label + "$" + lblCount)), newCmds, gotoCmd); newBlocks.Add(newBlock); newBlocks.AddRange(inlinedBlocks); return nextlblCount; }
// REVIEW: Does "thisExpr" really need to come back as an identifier? Can't it be a general expression? protected Bpl.DeclWithFormals TranslateArgumentsAndReturnProcedure(Bpl.IToken token, IMethodReference methodToCall, IMethodDefinition resolvedMethod, IExpression/*?*/ thisArg, IEnumerable<IExpression> arguments, out List<Bpl.Expr> inexpr, out List<Bpl.IdentifierExpr> outvars, out Bpl.IdentifierExpr thisExpr, out Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> toUnioned) { inexpr = new List<Bpl.Expr>(); outvars = new List<Bpl.IdentifierExpr>(); #region Create the 'this' argument for the function call thisExpr = null; if (thisArg != null) { // Special case! thisArg is going to be an AddressOf expression if the receiver is a value-type // But if the method's containing type is something that doesn't get translated as a Ref, then // the AddressOf node should be ignored. var addrOf = thisArg as IAddressOf; var boogieType = this.sink.CciTypeToBoogie(methodToCall.ContainingType); if (false && addrOf != null && boogieType != this.sink.Heap.RefType) { thisArg = addrOf.Expression; } this.Traverse(thisArg); var e = this.TranslatedExpressions.Pop(); var identifierExpr = e as Bpl.IdentifierExpr; if (identifierExpr == null) { var newLocal = Bpl.Expr.Ident(this.sink.CreateFreshLocal(methodToCall.ContainingType)); var cmd = Bpl.Cmd.SimpleAssign(token, newLocal, e); this.StmtTraverser.StmtBuilder.Add(cmd); e = newLocal; } else { } inexpr.Add(e); thisExpr = (Bpl.IdentifierExpr) e; } #endregion toUnioned = new Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>>(); IEnumerator<IParameterDefinition> penum = resolvedMethod.Parameters.GetEnumerator(); penum.MoveNext(); foreach (IExpression exp in arguments) { if (penum.Current == null) { throw new TranslationException("More arguments than parameters in method call"); } var expressionToTraverse = exp; //Bpl.Type boogieTypeOfExpression; //// Special case! exp can be an AddressOf expression if it is a value type being passed by reference. //// But since we pass reference parameters by in-out value passing, need to short-circuit the //// AddressOf node if the underlying type is not a Ref. //var addrOf = exp as IAddressOf; //if (addrOf != null) { // boogieTypeOfExpression = this.sink.CciTypeToBoogie(addrOf.Expression.Type); // if (boogieTypeOfExpression != this.sink.Heap.RefType) { // expressionToTraverse = addrOf.Expression; // } //} //boogieTypeOfExpression = this.sink.CciTypeToBoogie(expressionToTraverse.Type); this.Traverse(expressionToTraverse); Bpl.Expr e = this.TranslatedExpressions.Pop(); var currentType = penum.Current.Type; // If the argument is a struct, then make a copy of it to pass to the procedure. if (TranslationHelper.IsStruct(exp.Type)) { var proc = this.sink.FindOrCreateProcedureForStructCopy(exp.Type); var bplLocal = Bpl.Expr.Ident(this.sink.CreateFreshLocal(exp.Type)); var cmd = new Bpl.CallCmd(token, proc.Name, new List<Bpl.Expr> { e, }, new List<Bpl.IdentifierExpr> { bplLocal, }); this.StmtTraverser.StmtBuilder.Add(cmd); e = bplLocal; } if (currentType is IGenericParameterReference && this.sink.CciTypeToBoogie(currentType) == this.sink.Heap.UnionType) { inexpr.Add(sink.Heap.ToUnion(token, this.sink.CciTypeToBoogie(expressionToTraverse.Type), e, TranslationHelper.IsStruct(expressionToTraverse.Type), StmtTraverser.StmtBuilder)); } else { inexpr.Add(e); } if (penum.Current.IsByReference) { Bpl.IdentifierExpr unboxed = e as Bpl.IdentifierExpr; if (unboxed == null) { throw new TranslationException("Trying to pass a complex expression for an out or ref parameter"); } if (penum.Current.Type is IGenericParameterReference) { var boogieType = this.sink.CciTypeToBoogie(penum.Current.Type); if (boogieType == this.sink.Heap.UnionType) { Bpl.IdentifierExpr boxed = Bpl.Expr.Ident(sink.CreateFreshLocal(this.sink.Heap.UnionType)); toUnioned[unboxed] = Tuple.Create(boxed,false); outvars.Add(boxed); } else { outvars.Add(unboxed); } } else { outvars.Add(unboxed); } } penum.MoveNext(); } if (resolvedMethod.IsStatic) { List<ITypeReference> consolidatedTypeArguments = new List<ITypeReference>(); Sink.GetConsolidatedTypeArguments(consolidatedTypeArguments, methodToCall.ContainingType); foreach (ITypeReference typeReference in consolidatedTypeArguments) { inexpr.Add(this.sink.FindOrCreateTypeReferenceInCodeContext(typeReference)); } } IGenericMethodInstanceReference methodInstanceReference = methodToCall as IGenericMethodInstanceReference; if (methodInstanceReference != null) { foreach (ITypeReference typeReference in methodInstanceReference.GenericArguments) { inexpr.Add(this.sink.FindOrCreateTypeReferenceInCodeContext(typeReference)); } } var procInfo = this.sink.FindOrCreateProcedure(resolvedMethod); var translateAsFunctionCall = procInfo.Decl is Bpl.Function; if (!translateAsFunctionCall) { if (resolvedMethod.Type.ResolvedType.TypeCode != PrimitiveTypeCode.Void) { Bpl.Variable v = this.sink.CreateFreshLocal(methodToCall.ResolvedMethod.Type.ResolvedType); Bpl.IdentifierExpr unUnioned = new Bpl.IdentifierExpr(token, v); if (resolvedMethod.Type is IGenericParameterReference) { var boogieType = this.sink.CciTypeToBoogie(resolvedMethod.Type); if (boogieType == this.sink.Heap.UnionType) { Bpl.IdentifierExpr unioned = Bpl.Expr.Ident(this.sink.CreateFreshLocal(this.sink.Heap.UnionType)); toUnioned[unUnioned] = Tuple.Create(unioned, TranslationHelper.IsStruct(methodToCall.ResolvedMethod.Type.ResolvedType)); outvars.Add(unioned); } else { outvars.Add(unUnioned); } } else { outvars.Add(unUnioned); } TranslatedExpressions.Push(unUnioned); } } return procInfo.Decl; }
private Cmd InlinedRequires(CallCmd callCmd, Requires req) { Requires/*!*/ reqCopy = (Requires/*!*/)cce.NonNull(req.Clone()); if (req.Free) reqCopy.Condition = Expr.True; else reqCopy.Condition = codeCopier.CopyExpr(req.Condition); AssertCmd/*!*/ a = new AssertRequiresCmd(callCmd, reqCopy); a.ErrorDataEnhanced = reqCopy.ErrorDataEnhanced; return a; }
public override Cmd VisitCallCmd(CallCmd node) { Procedure enclosingProc = civlTypeChecker.enclosingImpl.Proc; if (!civlTypeChecker.procToAtomicProcedureInfo.ContainsKey(node.Proc)) { civlTypeChecker.Error(node, "Atomic procedure can only call an atomic procedure"); return base.VisitCallCmd(node); } var callerInfo = civlTypeChecker.procToAtomicProcedureInfo[enclosingProc]; var calleeInfo = civlTypeChecker.procToAtomicProcedureInfo[node.Proc]; if (calleeInfo.isPure) { // do nothing } else if (callerInfo.isPure) { civlTypeChecker.Error(node, "Pure procedure can only call pure procedures"); } else if (!callerInfo.layerRange.Subset(calleeInfo.layerRange)) { civlTypeChecker.Error(node, "Caller layers must be subset of callee layers"); } return base.VisitCallCmd(node); }
private Cmd InlinedEnsures(CallCmd callCmd, Ensures ens) { if (QKeyValue.FindBoolAttribute(ens.Attributes, "InlineAssume")) { return new AssumeCmd(ens.tok, codeCopier.CopyExpr(ens.Condition)); } else if (ens.Free) { return new AssumeCmd(ens.tok, Expr.True); } else { Ensures/*!*/ ensCopy = (Ensures/*!*/)cce.NonNull(ens.Clone()); ensCopy.Condition = codeCopier.CopyExpr(ens.Condition); return new AssertEnsuresCmd(ensCopy); } }
public override Cmd VisitCallCmd(CallCmd node) { int enclosingProcLayerNum = procToActionInfo[enclosingImpl.Proc].createdAtLayerNum; if (procToActionInfo.ContainsKey(node.Proc)) { ActionInfo actionInfo = procToActionInfo[node.Proc]; if (node.IsAsync && actionInfo is AtomicActionInfo) { AtomicActionInfo atomicActionInfo = actionInfo as AtomicActionInfo; if (!atomicActionInfo.IsLeftMover) { Error(node, "Target of async call must be a left mover"); } } int calleeLayerNum = procToActionInfo[node.Proc].createdAtLayerNum; if (enclosingProcLayerNum < calleeLayerNum || (enclosingProcLayerNum == calleeLayerNum && actionInfo is AtomicActionInfo)) { Error(node, "The layer of the caller must be greater than the layer of the callee"); } else if (enclosingProcLayerNum == calleeLayerNum && enclosingImpl.OutParams.Count > 0) { HashSet<Variable> outParams = new HashSet<Variable>(enclosingImpl.OutParams); foreach (var x in node.Outs) { if (x.Decl is GlobalVariable) { Error(node, "A global variable cannot be used as output argument for this call"); } else if (outParams.Contains(x.Decl)) { Error(node, "An output variable of the enclosing implementation cannot be used as output argument for this call"); } } } if (actionInfo.availableUptoLayerNum < enclosingProcLayerNum) { Error(node, "The callee is not available in the caller procedure"); } for (int i = 0; i < node.Ins.Count; i++) { Visit(node.Ins[i]); if (introducedLocalVarsUpperBound != int.MinValue) { var formal = node.Proc.InParams[i]; if (!localVarToLocalVariableInfo.ContainsKey(formal) || introducedLocalVarsUpperBound > localVarToLocalVariableInfo[formal].layer) { Error(node, "An introduced local variable is accessed but not available"); } introducedLocalVarsUpperBound = int.MinValue; } } for (int i = 0; i < node.Outs.Count; i++) { var formal = node.Proc.OutParams[i]; if (!localVarToLocalVariableInfo.ContainsKey(formal)) continue; var actual = node.Outs[i].Decl; if (localVarToLocalVariableInfo.ContainsKey(actual) && localVarToLocalVariableInfo[formal].layer <= localVarToLocalVariableInfo[actual].layer) continue; Error(node, "Formal parameter of call must be introduced no later than the actual parameter"); } return node; } else if (procToAtomicProcedureInfo.ContainsKey(node.Proc)) { var atomicProcedureInfo = procToAtomicProcedureInfo[node.Proc]; if (atomicProcedureInfo.isPure) { if (node.Outs.Count > 0) { int inferredLayer = int.MinValue; foreach (var ie in node.Outs) { if (!localVarToLocalVariableInfo.ContainsKey(ie.Decl)) continue; if (inferredLayer < localVarToLocalVariableInfo[ie.Decl].layer) { inferredLayer = localVarToLocalVariableInfo[ie.Decl].layer; } } pureCallLayer[node] = inferredLayer; if (inferredLayer != int.MinValue) { foreach (var ie in node.Outs) { if (!localVarToLocalVariableInfo.ContainsKey(ie.Decl)) { Error(node, "Output variable must be introduced"); } else if (inferredLayer != localVarToLocalVariableInfo[ie.Decl].layer) { Error(node, "All output variables must be introduced at the same layer"); } } } Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); foreach (var e in node.Ins) { Visit(e); if (inferredLayer < introducedLocalVarsUpperBound) { Error(node, "An introduced local variable is not accessible"); } introducedLocalVarsUpperBound = int.MinValue; } } else { Debug.Assert(introducedLocalVarsUpperBound == int.MinValue); int inferredLayer = int.MinValue; foreach (var e in node.Ins) { Visit(e); if (inferredLayer < introducedLocalVarsUpperBound) { inferredLayer = introducedLocalVarsUpperBound; } introducedLocalVarsUpperBound = int.MinValue; } pureCallLayer[node] = inferredLayer; } } else { if (enclosingProcLayerNum != atomicProcedureInfo.layerRange.upperLayerNum) { Error(node, "Creation layer of caller must be the upper bound of the layer range of callee"); } foreach (var ie in node.Proc.Modifies) { if (enclosingProcLayerNum != globalVarToSharedVarInfo[ie.Decl].introLayerNum) { Error(node, "Creation layer of caller must be identical to the introduction layer of modified variable"); } } foreach (var ie in node.Outs) { if (localVarToLocalVariableInfo.ContainsKey(ie.Decl) && enclosingProcLayerNum == localVarToLocalVariableInfo[ie.Decl].layer) continue; Error(node, "Output variable must be introduced at the creation layer of caller"); } } return node; } else { Error(node, "A yielding procedure can call only atomic or yielding procedures"); return node; } }
// result[0] is the entry block protected List<Block/*!*/>/*!*/ CreateInlinedBlocks(CallCmd callCmd, Implementation impl, string nextBlockLabel) { Contract.Requires(nextBlockLabel != null); Contract.Requires(impl != null); Contract.Requires(impl.Proc != null); Contract.Requires(callCmd != null); Contract.Requires(codeCopier.Subst != null); Contract.Requires(codeCopier.OldSubst != null); Contract.Ensures(cce.NonNullElements(Contract.Result<List<Block>>())); List<Block/*!*/>/*!*/ implBlocks = cce.NonNull(impl.OriginalBlocks); Contract.Assert(implBlocks.Count > 0); Procedure proc = impl.Proc; string startLabel = implBlocks[0].Label; List<Block/*!*/>/*!*/ inlinedBlocks = new List<Block/*!*/>(); // create in block List<Cmd> inCmds = new List<Cmd>(); // assign in parameters for (int i = 0; i < impl.InParams.Count; ++i) { Cmd cmd = Cmd.SimpleAssign(impl.tok, (IdentifierExpr)cce.NonNull(codeCopier.Subst)(cce.NonNull(impl.InParams[i])), cce.NonNull(callCmd.Ins[i])); inCmds.Add(cmd); } // inject requires for (int i = 0; i < proc.Requires.Count; i++) { Requires/*!*/ req = cce.NonNull(proc.Requires[i]); inCmds.Add(InlinedRequires(callCmd, req)); } List<Variable> locVars = cce.NonNull(impl.OriginalLocVars); // havoc locals and out parameters in case procedure is invoked in a loop List<IdentifierExpr> havocVars = new List<IdentifierExpr>(); foreach (Variable v in locVars) { havocVars.Add((IdentifierExpr)codeCopier.Subst(v)); } foreach (Variable v in impl.OutParams) { havocVars.Add((IdentifierExpr)codeCopier.Subst(v)); } if (havocVars.Count > 0) { inCmds.Add(new HavocCmd(Token.NoToken, havocVars)); } // add where clauses of local vars as assume for (int i = 0; i < locVars.Count; ++i) { Expr whereExpr = (cce.NonNull(locVars[i])).TypedIdent.WhereExpr; if (whereExpr != null) { whereExpr = Substituter.Apply(codeCopier.Subst, whereExpr); // FIXME we cannot overwrite it, can we?! (cce.NonNull(locVars[i])).TypedIdent.WhereExpr = whereExpr; AssumeCmd/*!*/ a = new AssumeCmd(Token.NoToken, whereExpr); Contract.Assert(a != null); inCmds.Add(a); } } // add where clauses of output params as assume for (int i = 0; i < impl.OutParams.Count; ++i) { Expr whereExpr = (cce.NonNull(impl.OutParams[i])).TypedIdent.WhereExpr; if (whereExpr != null) { whereExpr = Substituter.Apply(codeCopier.Subst, whereExpr); // FIXME likewise (cce.NonNull(impl.OutParams[i])).TypedIdent.WhereExpr = whereExpr; AssumeCmd/*!*/ a = new AssumeCmd(Token.NoToken, whereExpr); Contract.Assert(a != null); inCmds.Add(a); } } // assign modifies old values foreach (IdentifierExpr/*!*/ mie in proc.Modifies) { Contract.Assert(mie != null); Variable/*!*/ mvar = cce.NonNull(mie.Decl); AssignCmd assign = Cmd.SimpleAssign(impl.tok, (IdentifierExpr)cce.NonNull(codeCopier.OldSubst(mvar)), mie); inCmds.Add(assign); } GotoCmd inGotoCmd = new GotoCmd(callCmd.tok, new List<String> { GetInlinedProcLabel(proc.Name) + "$" + startLabel }); Block inBlock = new Block(impl.tok, GetInlinedProcLabel(proc.Name) + "$Entry", inCmds, inGotoCmd); inlinedBlocks.Add(inBlock); // inject the blocks of the implementation Block intBlock; foreach (Block block in implBlocks) { List<Cmd> copyCmds = codeCopier.CopyCmdSeq(block.Cmds); if (0 <= inlineDepth) { copyCmds = RemoveAsserts(copyCmds); } TransferCmd transferCmd = CreateInlinedTransferCmd(cce.NonNull(block.TransferCmd), GetInlinedProcLabel(proc.Name)); intBlock = new Block(block.tok, GetInlinedProcLabel(proc.Name) + "$" + block.Label, copyCmds, transferCmd); inlinedBlocks.Add(intBlock); } // create out block List<Cmd> outCmds = new List<Cmd>(); // inject ensures for (int i = 0; i < proc.Ensures.Count; i++) { Ensures/*!*/ ens = cce.NonNull(proc.Ensures[i]); outCmds.Add(InlinedEnsures(callCmd, ens)); } // assign out params for (int i = 0; i < impl.OutParams.Count; ++i) { Expr/*!*/ cout_exp = (IdentifierExpr)cce.NonNull(codeCopier.Subst(cce.NonNull(impl.OutParams[i]))); Cmd cmd = Cmd.SimpleAssign(impl.tok, cce.NonNull(callCmd.Outs[i]), cout_exp); outCmds.Add(cmd); } // create out block GotoCmd outGotoCmd = new GotoCmd(Token.NoToken, new List<String> { nextBlockLabel }); Block outBlock = new Block(impl.tok, GetInlinedProcLabel(proc.Name) + "$Return", outCmds, outGotoCmd); inlinedBlocks.Add(outBlock); return inlinedBlocks; }
public virtual Cmd VisitCallCmd(CallCmd node) { Contract.Requires(node != null); Contract.Ensures(Contract.Result<Cmd>() != null); for (int i = 0; i < node.Ins.Count; ++i) if (node.Ins[i] != null) node.Ins[i] = this.VisitExpr(cce.NonNull(node.Ins[i])); for (int i = 0; i < node.Outs.Count; ++i) if (node.Outs[i] != null) node.Outs[i] = (IdentifierExpr)this.VisitIdentifierExpr(cce.NonNull(node.Outs[i])); return node; }
/// <summary> /// Patch, to account for URIs that cannot be tracked because of current dataflow restrictions /// </summary> private void TranslateHavocCurrentURI() { // TODO move away phone related code from the translation, it would be better to have 2 or more translation phases IMethodReference havocMethod= PhoneCodeHelper.instance().getUriHavocerMethod(sink); Sink.ProcedureInfo procInfo= sink.FindOrCreateProcedure(havocMethod.ResolvedMethod); Bpl.CallCmd havocCall = new Bpl.CallCmd(Bpl.Token.NoToken, procInfo.Decl.Name, new List<Bpl.Expr>(), new List<Bpl.IdentifierExpr>()); StmtTraverser.StmtBuilder.Add(havocCall); }
public override Cmd VisitCallCmd(CallCmd node) { var result = base.VisitCallCmd(node); var oldProc = programInCachedSnapshot.FindProcedure(node.Proc.Name); if (oldProc != null && oldProc.DependencyChecksum != node.Proc.DependencyChecksum && node.AssignedAssumptionVariable == null) { var before = new List<Cmd>(); var beforePrecondtionCheck = new List<Cmd>(); var after = new List<Cmd>(); var axioms = new List<Axiom>(); Expr assumedExpr = new LiteralExpr(Token.NoToken, false); // TODO(wuestholz): Try out two alternatives: only do this for low priority implementations or not at all. var canUseSpecs = DependencyCollector.CanExpressOldSpecs(oldProc, Program); if (canUseSpecs && oldProc.SignatureEquals(node.Proc)) { var desugaring = node.Desugaring; Contract.Assert(desugaring != null); var precond = node.CheckedPrecondition(oldProc, Program, e => FunctionExtractor.Extract(e, Program, axioms)); if (precond != null) { var assume = new AssumeCmd(node.tok, precond, new QKeyValue(Token.NoToken, "precondition_previous_snapshot", new List<object>(), null)); assume.IrrelevantForChecksumComputation = true; beforePrecondtionCheck.Add(assume); } var unmods = node.UnmodifiedBefore(oldProc); var eqs = new List<Expr>(); foreach (var unmod in unmods) { var oldUnmod = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}##old##{1}", unmod.Name, FreshTemporaryVariableName), unmod.Type)); var lhs = new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, oldUnmod)); var rhs = new IdentifierExpr(Token.NoToken, unmod.Decl); var cmd = new AssignCmd(Token.NoToken, new List<AssignLhs> { lhs }, new List<Expr> { rhs }); cmd.IrrelevantForChecksumComputation = true; before.Add(cmd); var eq = LiteralExpr.Eq(new IdentifierExpr(Token.NoToken, oldUnmod), new IdentifierExpr(Token.NoToken, unmod.Decl)); eq.Type = Type.Bool; eq.TypeParameters = SimpleTypeParamInstantiation.EMPTY; eqs.Add(eq); } var mods = node.ModifiedBefore(oldProc); var oldSubst = new Dictionary<Variable, Expr>(); foreach (var mod in mods) { var oldMod = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("{0}##old##{1}", mod.Name, FreshTemporaryVariableName), mod.Type)); oldSubst[mod.Decl] = new IdentifierExpr(Token.NoToken, oldMod); var lhs = new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, oldMod)); var rhs = new IdentifierExpr(Token.NoToken, mod.Decl); var cmd = new AssignCmd(Token.NoToken, new List<AssignLhs> { lhs }, new List<Expr> { rhs }); cmd.IrrelevantForChecksumComputation = true; before.Add(cmd); } assumedExpr = node.Postcondition(oldProc, eqs, oldSubst, Program, e => FunctionExtractor.Extract(e, Program, axioms)); if (assumedExpr == null) { assumedExpr = new LiteralExpr(Token.NoToken, true); } } if (assumedExpr != null) { var lv = new LocalVariable(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("a##cached##{0}", FreshAssumptionVariableName), Type.Bool), new QKeyValue(Token.NoToken, "assumption", new List<object>(), null)); node.AssignedAssumptionVariable = lv; currentImplementation.InjectAssumptionVariable(lv, !canUseSpecs); var lhs = new SimpleAssignLhs(Token.NoToken, new IdentifierExpr(Token.NoToken, lv)); var rhs = LiteralExpr.And(new IdentifierExpr(Token.NoToken, lv), assumedExpr); var assumed = new AssignCmd(node.tok, new List<AssignLhs> { lhs }, new List<Expr> { rhs }); assumed.IrrelevantForChecksumComputation = true; after.Add(assumed); } node.ExtendDesugaring(before, beforePrecondtionCheck, after); if (CommandLineOptions.Clo.TraceCachingForTesting || CommandLineOptions.Clo.TraceCachingForBenchmarking) { using (var tokTxtWr = new TokenTextWriter("<console>", Console.Out, false, false)) { var loc = node.tok != null && node.tok != Token.NoToken ? string.Format("{0}({1},{2})", node.tok.filename, node.tok.line, node.tok.col) : "<unknown location>"; Console.Out.WriteLine("Processing call to procedure {0} in implementation {1} (at {2}):", node.Proc.Name, currentImplementation.Name, loc); foreach (var a in axioms) { Console.Out.Write(" >>> added axiom: "); a.Expr.Emit(tokTxtWr); Console.Out.WriteLine(); } foreach (var b in before) { Console.Out.Write(" >>> added before: "); b.Emit(tokTxtWr, 0); } foreach (var b in beforePrecondtionCheck) { Console.Out.Write(" >>> added before precondition check: "); b.Emit(tokTxtWr, 0); } foreach (var a in after) { Console.Out.Write(" >>> added after: "); a.Emit(tokTxtWr, 0); } } } } return result; }
/// <summary> /// Handles "instance.container := source". /// Note that instance can be null in which case the container better be /// a local, parameter, static field, or address dereference. /// </summary> private void TranslateAssignment(Bpl.IToken tok, object container, IExpression/*?*/ instance, IExpression source) { Contract.Assert(TranslatedExpressions.Count == 0); var typ = source.Type; var structCopy = TranslationHelper.IsStruct(typ) && !(source is IDefaultValue); // then a struct value of type S is being assigned: "lhs := s" // model this as the statement "call lhs := S..#copy_ctor(s)" that does the bit-wise copying Bpl.DeclWithFormals proc = null; if (structCopy) { proc = this.sink.FindOrCreateProcedureForStructCopy(typ); } Bpl.Cmd cmd; EmitLineDirective(tok); var/*?*/ local = container as ILocalDefinition; if (local != null) { Contract.Assume(instance == null); this.Traverse(source); var e = this.TranslatedExpressions.Pop(); var bplLocal = Bpl.Expr.Ident(this.sink.FindOrCreateLocalVariable(local)); if (structCopy) { cmd = new Bpl.CallCmd(tok, proc.Name, new List<Bpl.Expr>{ e, }, new List<Bpl.IdentifierExpr>{ bplLocal, }); } else { cmd = Bpl.Cmd.SimpleAssign(tok, bplLocal, e); } StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(e); // value of assignment might be needed for an enclosing expression return; } var/*?*/ parameter = container as IParameterDefinition; if (parameter != null) { Contract.Assume(instance == null); this.Traverse(source); var e = this.TranslatedExpressions.Pop(); var bplParam = Bpl.Expr.Ident(this.sink.FindParameterVariable(parameter, this.contractContext)); if (structCopy) { cmd = new Bpl.CallCmd(tok, proc.Name, new List<Bpl.Expr> { e, }, new List<Bpl.IdentifierExpr>{ bplParam }); } else { cmd = Bpl.Cmd.SimpleAssign(tok, bplParam, e); } StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(e); // value of assignment might be needed for an enclosing expression return; } var/*?*/ field = container as IFieldReference; if (field != null) { this.Traverse(source); var e = this.TranslatedExpressions.Pop(); var f = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(field)); if (instance == null) { // static fields are not kept in the heap StmtTraverser.StmtBuilder.Add(Bpl.Cmd.SimpleAssign(tok, f, e)); } else { this.Traverse(instance); var x = this.TranslatedExpressions.Pop(); var boogieType = sink.CciTypeToBoogie(field.Type); this.sink.Heap.WriteHeap(tok, x, f, e, field.ResolvedField.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, boogieType, StmtTraverser.StmtBuilder); this.TranslatedExpressions.Push(e); // value of assignment might be needed for an enclosing expression } return; } var/*?*/ arrayIndexer = container as IArrayIndexer; if (arrayIndexer != null) { this.Traverse(instance); var x = this.TranslatedExpressions.Pop(); this.Traverse(arrayIndexer.Indices); var indices_prime = this.TranslatedExpressions.Pop(); this.Traverse(source); var e = this.TranslatedExpressions.Pop(); sink.Heap.WriteHeap(Bpl.Token.NoToken, x, indices_prime, e, AccessType.Array, sink.CciTypeToBoogie(arrayIndexer.Type), StmtTraverser.StmtBuilder); this.TranslatedExpressions.Push(e); // value of assignment might be needed for an enclosing expression return; } var/*?*/ addressDereference = container as IAddressDereference; if (addressDereference != null) { var addressOf = addressDereference.Address as IAddressOf; if (addressOf != null) { var ae = addressOf.Expression; TranslateAssignment(tok, ae.Definition, ae.Instance, source); return; } var pop = addressDereference.Address as IPopValue; if (pop != null) { var popValue = this.sink.operandStack.Pop(); var identifierExpr = popValue as Bpl.IdentifierExpr; if (identifierExpr != null) { Contract.Assume(instance == null); this.Traverse(source); var e = this.TranslatedExpressions.Pop(); cmd = Bpl.Cmd.SimpleAssign(tok, identifierExpr, e); StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(e); // value of assignment might be needed for an enclosing expression return; } } var be2 = addressDereference.Address as IBoundExpression; if (be2 != null) { TranslateAssignment(tok, be2.Definition, be2.Instance, source); return; } var thisExp = addressDereference.Address as IThisReference; if (thisExp != null) { // I believe this happens only when a struct calls the default // ctor (probably only ever done in a different ctor for the // struct). The assignment actually looks like "*this := DefaultValue(S)" Contract.Assume(instance == null); this.Traverse(source); var e = this.TranslatedExpressions.Pop(); var bplLocal = Bpl.Expr.Ident(this.sink.ThisVariable); cmd = Bpl.Cmd.SimpleAssign(tok, bplLocal, e); StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(e); // value of assignment might be needed for an enclosing expression return; } } throw new TranslationException("Untranslatable assignment statement."); }
public void AddAvailableVars(CallCmd callCmd, HashSet<Variable> start) { foreach (IdentifierExpr ie in callCmd.Outs) { if (FindDomainName(ie.Decl) == null) continue; start.Add(ie.Decl); } for (int i = 0; i < callCmd.Proc.InParams.Count; i++) { IdentifierExpr ie = callCmd.Ins[i] as IdentifierExpr; if (ie == null) continue; Variable v = callCmd.Proc.InParams[i]; if (FindDomainName(v) == null) continue; if (FindLinearKind(v) == LinearKind.LINEAR_OUT) { start.Add(ie.Decl); } } }
private void VisitAssignment(ITargetExpression target, IExpression source, SourceTraverser sourceTraverser, bool treatAsStatement, bool pushTargetRValue, bool resultIsInitialTargetRValue) { Contract.Requires(target != null); Contract.Requires(source != null); Contract.Requires(sourceTraverser != null); Contract.Requires(!resultIsInitialTargetRValue || pushTargetRValue); Contract.Requires(!pushTargetRValue || source is IBinaryOperation); var tok = source.Token(); var typ = source.Type; var structCopy = TranslationHelper.IsStruct(typ) && !(source is IDefaultValue); // then a struct value of type S is being assigned: "lhs := s" // model this as the statement "call lhs := S..#copy_ctor(s)" that does the bit-wise copying Bpl.DeclWithFormals proc = null; if (structCopy) { proc = this.sink.FindOrCreateProcedureForStructCopy(typ); } object container = target.Definition; Top: ILocalDefinition/*?*/ local = container as ILocalDefinition; if (local != null) { if (source is IDefaultValue && !local.Type.ResolvedType.IsReferenceType) { // this.LoadAddressOf(local, null); // this.generator.Emit(OperationCode.Initobj, local.Type); // if (!treatAsStatement) this.LoadLocal(local); } else { Bpl.IdentifierExpr temp = null; var bplLocal = Bpl.Expr.Ident(this.sink.FindOrCreateLocalVariable(local)); if (pushTargetRValue) { this.TranslatedExpressions.Push(bplLocal); if (!treatAsStatement && resultIsInitialTargetRValue) { var loc = this.sink.CreateFreshLocal(source.Type); temp = Bpl.Expr.Ident(loc); var e3 = this.TranslatedExpressions.Pop(); var cmd3 = Bpl.Cmd.SimpleAssign(tok, temp, e3); this.StmtTraverser.StmtBuilder.Add(cmd3); this.TranslatedExpressions.Push(temp); } } sourceTraverser(source); var e = this.TranslatedExpressions.Pop(); if (temp != null) this.TranslatedExpressions.Push(temp); Bpl.Cmd cmd; if (structCopy) { cmd = new Bpl.CallCmd(tok, proc.Name, new List<Bpl.Expr> { e, }, new List<Bpl.IdentifierExpr> { bplLocal, }); } else { cmd = Bpl.Cmd.SimpleAssign(tok, bplLocal, e); } StmtTraverser.StmtBuilder.Add(cmd); if (!treatAsStatement && !resultIsInitialTargetRValue) { this.TranslatedExpressions.Push(bplLocal); } } return; } IParameterDefinition/*?*/ parameter = container as IParameterDefinition; if (parameter != null) { if (source is IDefaultValue && !parameter.Type.ResolvedType.IsReferenceType) { //this.LoadAddressOf(parameter, null); //this.generator.Emit(OperationCode.Initobj, parameter.Type); //if (!treatAsStatement) this.LoadParameter(parameter); } else { Bpl.IdentifierExpr temp = null; if (pushTargetRValue) { this.LoadParameter(parameter); if (!treatAsStatement && resultIsInitialTargetRValue) { var loc = this.sink.CreateFreshLocal(source.Type); temp = Bpl.Expr.Ident(loc); var e3 = this.TranslatedExpressions.Pop(); var cmd3 = Bpl.Cmd.SimpleAssign(tok, temp, e3); this.StmtTraverser.StmtBuilder.Add(cmd3); this.TranslatedExpressions.Push(temp); } } sourceTraverser(source); var e = this.TranslatedExpressions.Pop(); if (temp != null) this.TranslatedExpressions.Push(temp); var bplParam = Bpl.Expr.Ident(this.sink.FindParameterVariable(parameter, this.contractContext)); Bpl.Cmd cmd; if (structCopy) { cmd = new Bpl.CallCmd(tok, proc.Name, new List<Bpl.Expr> { e, bplParam, }, new List<Bpl.IdentifierExpr>()); } else { cmd = Bpl.Cmd.SimpleAssign(tok, bplParam, e); } StmtTraverser.StmtBuilder.Add(cmd); if (!treatAsStatement && !resultIsInitialTargetRValue) { this.LoadParameter(parameter); } } return; } IFieldReference/*?*/ field = container as IFieldReference; if (field != null) { var f = Bpl.Expr.Ident(this.sink.FindOrCreateFieldVariable(field)); var boogieTypeOfField = sink.CciTypeToBoogie(field.Type); if (source is IDefaultValue && !field.Type.ResolvedType.IsReferenceType) { //this.LoadAddressOf(field, target.Instance); //if (!treatAsStatement) { // this.generator.Emit(OperationCode.Dup); // this.StackSize++; //} //this.generator.Emit(OperationCode.Initobj, field.Type); //if (!treatAsStatement) // this.generator.Emit(OperationCode.Ldobj, field.Type); //else // this.StackSize--; } else { Bpl.Expr x = null; Bpl.IdentifierExpr temp = null; if (pushTargetRValue) { if (target.Instance != null) { this.Traverse(target.Instance); x = this.TranslatedExpressions.Pop(); AssertOrAssumeNonNull(tok, x); var e2 = this.sink.Heap.ReadHeap(x, f, TranslationHelper.IsStruct(field.ContainingType) ? AccessType.Struct : AccessType.Heap, boogieTypeOfField); this.TranslatedExpressions.Push(e2); } else { TranslatedExpressions.Push(f); } if (!treatAsStatement && resultIsInitialTargetRValue) { var loc = this.sink.CreateFreshLocal(source.Type); temp = Bpl.Expr.Ident(loc); var e3 = this.TranslatedExpressions.Pop(); var cmd = Bpl.Cmd.SimpleAssign(tok, temp, e3); this.StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(temp); } } sourceTraverser(source); if (!treatAsStatement && !resultIsInitialTargetRValue) { var loc = this.sink.CreateFreshLocal(source.Type); temp = Bpl.Expr.Ident(loc); var e3 = this.TranslatedExpressions.Pop(); var cmd = Bpl.Cmd.SimpleAssign(tok, temp, e3); this.StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(temp); } var e = this.TranslatedExpressions.Pop(); if (temp != null) this.TranslatedExpressions.Push(temp); if (target.Instance == null) { // static fields are not kept in the heap StmtTraverser.StmtBuilder.Add(Bpl.Cmd.SimpleAssign(tok, f, e)); } else { this.sink.Heap.WriteHeap(tok, x, f, e, field.ResolvedField.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, boogieTypeOfField, StmtTraverser.StmtBuilder); } } return; } VisitArrayIndexer: IArrayIndexer/*?*/ arrayIndexer = container as IArrayIndexer; if (arrayIndexer != null) { Contract.Assume(arrayIndexer.Indices.Count() == 1); // BUG: deal with multi-dimensional arrays if (source is IDefaultValue && !arrayIndexer.Type.ResolvedType.IsReferenceType) { // this.LoadAddressOf(arrayIndexer, target.Instance); // if (!treatAsStatement) { // this.generator.Emit(OperationCode.Dup); // this.StackSize++; // } // this.generator.Emit(OperationCode.Initobj, arrayIndexer.Type); // if (!treatAsStatement) // this.generator.Emit(OperationCode.Ldobj, arrayIndexer.Type); // else // this.StackSize--; } else { Bpl.IdentifierExpr/*?*/ temp = null; this.Traverse(arrayIndexer.IndexedObject); var arrayExpr = this.TranslatedExpressions.Peek(); this.Traverse(arrayIndexer.Indices); var indexExpr = this.TranslatedExpressions.Peek(); if (pushTargetRValue) { AssertOrAssumeNonNull(tok, arrayExpr); var e2 = this.sink.Heap.ReadHeap(arrayExpr, indexExpr, AccessType.Array, this.sink.CciTypeToBoogie(arrayIndexer.Type)); this.TranslatedExpressions.Push(e2); if (!treatAsStatement && resultIsInitialTargetRValue) { var loc = this.sink.CreateFreshLocal(source.Type); temp = Bpl.Expr.Ident(loc); var e3 = this.TranslatedExpressions.Pop(); var cmd = Bpl.Cmd.SimpleAssign(tok, temp, e3); this.StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(temp); } } sourceTraverser(source); var e = this.TranslatedExpressions.Pop(); var indices_prime = this.TranslatedExpressions.Pop(); var x = this.TranslatedExpressions.Pop(); sink.Heap.WriteHeap(Bpl.Token.NoToken, x, indices_prime, e, AccessType.Array, sink.CciTypeToBoogie(arrayIndexer.Type), StmtTraverser.StmtBuilder); if (!treatAsStatement && !resultIsInitialTargetRValue) { AssertOrAssumeNonNull(tok, arrayExpr); var e2 = this.sink.Heap.ReadHeap(arrayExpr, indexExpr, AccessType.Array, this.sink.CciTypeToBoogie(arrayIndexer.Type)); this.TranslatedExpressions.Push(e2); } else { if (temp != null) this.TranslatedExpressions.Push(temp); } } return; } IAddressDereference/*?*/ addressDereference = container as IAddressDereference; if (addressDereference != null) { var addrOf = addressDereference.Address as IAddressOf; if (addrOf != null) { var arrayIndexer2 = addrOf.Expression.Definition as IArrayIndexer; if (arrayIndexer2 != null) { container = arrayIndexer2; goto VisitArrayIndexer; } } var be = addressDereference.Address as IBoundExpression; if (be != null) { container = be.Definition; goto Top; } this.Traverse(addressDereference.Address); if (source is IDefaultValue && !addressDereference.Type.ResolvedType.IsReferenceType) { //if (!treatAsStatement) { // this.generator.Emit(OperationCode.Dup); // this.StackSize++; //} //this.generator.Emit(OperationCode.Initobj, addressDereference.Type); //if (!treatAsStatement) // this.generator.Emit(OperationCode.Ldobj, addressDereference.Type); //else // this.StackSize--; } else if (source is IAddressDereference) { //if (!treatAsStatement) { // this.generator.Emit(OperationCode.Dup); // this.StackSize++; //} //this.Traverse(((IAddressDereference)source).Address); //this.generator.Emit(OperationCode.Cpobj, addressDereference.Type); //this.StackSize -= 2; //if (!treatAsStatement) // this.generator.Emit(OperationCode.Ldobj, addressDereference.Type); } else { Bpl.IdentifierExpr/*?*/ temp = null; if (pushTargetRValue) { this.TranslatedExpressions.Push(this.TranslatedExpressions.Peek()); if (!treatAsStatement && resultIsInitialTargetRValue) { this.TranslatedExpressions.Push(this.TranslatedExpressions.Peek()); var loc = this.sink.CreateFreshLocal(source.Type); temp = Bpl.Expr.Ident(loc); var e3 = this.TranslatedExpressions.Pop(); var cmd = Bpl.Cmd.SimpleAssign(tok, temp, e3); this.StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(temp); } } sourceTraverser(source); if (!treatAsStatement && !resultIsInitialTargetRValue) { this.TranslatedExpressions.Push(this.TranslatedExpressions.Peek()); var loc = this.sink.CreateFreshLocal(source.Type); temp = Bpl.Expr.Ident(loc); var e3 = this.TranslatedExpressions.Pop(); var cmd = Bpl.Cmd.SimpleAssign(tok, temp, e3); this.StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(temp); } //this.VisitAssignmentTo(addressDereference); if (temp != null) this.TranslatedExpressions.Push(temp); } return; } IPropertyDefinition/*?*/ propertyDefinition = container as IPropertyDefinition; if (propertyDefinition != null) { Contract.Assume(propertyDefinition.Getter != null && propertyDefinition.Setter != null); if (!propertyDefinition.IsStatic) { this.Traverse(target.Instance); } Bpl.IdentifierExpr temp = null; var token = Bpl.Token.NoToken; if (pushTargetRValue) { List<Bpl.Expr> inexpr; List<Bpl.IdentifierExpr> outvars; Bpl.IdentifierExpr thisExpr; Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr, bool>> toBoxed; var proc2 = TranslateArgumentsAndReturnProcedure(token, propertyDefinition.Getter, propertyDefinition.Getter.ResolvedMethod, target.Instance, Enumerable<IExpression>.Empty, out inexpr, out outvars, out thisExpr, out toBoxed); EmitLineDirective(token); this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(token, proc2.Name, inexpr, outvars)); if (!treatAsStatement && resultIsInitialTargetRValue) { //var //this.generator.Emit(OperationCode.Dup); //this.StackSize++; //temp = new TemporaryVariable(source.Type, this.method); //this.VisitAssignmentTo(temp); } } sourceTraverser(source); if (!treatAsStatement && !resultIsInitialTargetRValue) { var e3 = this.TranslatedExpressions.Pop(); var loc = this.sink.CreateFreshLocal(source.Type); temp = Bpl.Expr.Ident(loc); var cmd = Bpl.Cmd.SimpleAssign(tok, temp, e3); this.StmtTraverser.StmtBuilder.Add(cmd); this.TranslatedExpressions.Push(temp); } var setterArgs = new List<Bpl.Expr>(); var setterArg = this.TranslatedExpressions.Pop(); if (!propertyDefinition.IsStatic) setterArgs.Add(this.TranslatedExpressions.Pop()); setterArgs.Add(setterArg); var setterProc = this.sink.FindOrCreateProcedure(propertyDefinition.Setter.ResolvedMethod); EmitLineDirective(token); this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(token, setterProc.Decl.Name, setterArgs, new List<Bpl.IdentifierExpr>())); if (temp != null) this.TranslatedExpressions.Push(temp); return; } Contract.Assume(false); }
public void DesugarParallelCallCmd(List<Cmd> newCmds, ParCallCmd parCallCmd) { List<string> parallelCalleeNames = new List<string>(); List<Expr> ins = new List<Expr>(); List<IdentifierExpr> outs = new List<IdentifierExpr>(); string procName = "og"; foreach (CallCmd callCmd in parCallCmd.CallCmds) { procName = procName + "_" + callCmd.Proc.Name; ins.AddRange(callCmd.Ins); outs.AddRange(callCmd.Outs); } Procedure proc; if (asyncAndParallelCallDesugarings.ContainsKey(procName)) { proc = asyncAndParallelCallDesugarings[procName]; } else { List<Variable> inParams = new List<Variable>(); List<Variable> outParams = new List<Variable>(); List<Requires> requiresSeq = new List<Requires>(); List<Ensures> ensuresSeq = new List<Ensures>(); int count = 0; foreach (CallCmd callCmd in parCallCmd.CallCmds) { Dictionary<Variable, Expr> map = new Dictionary<Variable, Expr>(); foreach (Variable x in callCmd.Proc.InParams) { Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), true); inParams.Add(y); map[x] = Expr.Ident(y); } foreach (Variable x in callCmd.Proc.OutParams) { Variable y = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_{0}_{1}", count, x.Name), x.TypedIdent.Type), false); outParams.Add(y); map[x] = Expr.Ident(y); } Contract.Assume(callCmd.Proc.TypeParameters.Count == 0); Substitution subst = Substituter.SubstitutionFromHashtable(map); foreach (Requires req in callCmd.Proc.Requires) { requiresSeq.Add(new Requires(req.tok, req.Free, Substituter.Apply(subst, req.Condition), null, req.Attributes)); } foreach (Ensures ens in callCmd.Proc.Ensures) { ensuresSeq.Add(new Ensures(ens.tok, ens.Free, Substituter.Apply(subst, ens.Condition), null, ens.Attributes)); } count++; } proc = new Procedure(Token.NoToken, procName, new List<TypeVariable>(), inParams, outParams, requiresSeq, globalMods, ensuresSeq); asyncAndParallelCallDesugarings[procName] = proc; } CallCmd dummyCallCmd = new CallCmd(parCallCmd.tok, proc.Name, ins, outs, parCallCmd.Attributes); dummyCallCmd.Proc = proc; newCmds.Add(dummyCallCmd); }
public override void TraverseChildren(IConversion conversion) { var tok = conversion.ValueToConvert.Token(); this.Traverse(conversion.ValueToConvert); var boogieTypeOfValue = this.sink.CciTypeToBoogie(conversion.ValueToConvert.Type); var boogieTypeToBeConvertedTo = this.sink.CciTypeToBoogie(conversion.TypeAfterConversion); if (boogieTypeOfValue == boogieTypeToBeConvertedTo && !TranslationHelper.IsStruct(conversion.ValueToConvert.Type) && !TranslationHelper.IsStruct(conversion.TypeAfterConversion)) { // then this conversion is a nop, just ignore it return; } var nameOfTypeToConvert = TypeHelper.GetTypeName(conversion.ValueToConvert.Type); var nameOfTypeToBeConvertedTo = TypeHelper.GetTypeName(conversion.TypeAfterConversion); var msg = String.Format("Can't convert '{0}' to '{1}'", nameOfTypeToConvert, nameOfTypeToBeConvertedTo); var exp = TranslatedExpressions.Pop(); if (boogieTypeOfValue == this.sink.Heap.UnionType && boogieTypeToBeConvertedTo != this.sink.Heap.RefType) { var e = this.sink.Heap.FromUnion(tok, boogieTypeToBeConvertedTo, exp, false); TranslatedExpressions.Push(e); return; } if (boogieTypeToBeConvertedTo == this.sink.Heap.UnionType) { Bpl.Expr e; if (boogieTypeOfValue == this.sink.Heap.RefType) e = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Union), new List<Bpl.Expr>(new Bpl.Expr[] {exp})); else e = this.sink.Heap.ToUnion(tok, boogieTypeOfValue, exp, false, StmtTraverser.StmtBuilder); TranslatedExpressions.Push(e); return; } if (boogieTypeToBeConvertedTo == this.sink.Heap.RefType && TranslationHelper.IsStruct(conversion.TypeAfterConversion) && boogieTypeOfValue == this.sink.Heap.RefType) { // REVIEW: This also applies to conversions from one struct type to another! TranslatedExpressions.Push(exp); return; } if (boogieTypeToBeConvertedTo == Bpl.Type.Bool) { Bpl.Expr expr; if (boogieTypeOfValue == Bpl.Type.Int) { expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, exp, Bpl.Expr.Literal(0)); } else if (boogieTypeOfValue == this.sink.Heap.RefType) { expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Bool), new List<Bpl.Expr>(new Bpl.Expr[] {exp})); } else if (boogieTypeOfValue == this.sink.Heap.RealType) { expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Real2Int), new List<Bpl.Expr>(new Bpl.Expr[] {exp})); expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, expr, Bpl.Expr.Literal(0)); } else if (boogieTypeOfValue == this.sink.Heap.UnionType) { expr = this.sink.Heap.FromUnion(tok, Bpl.Type.Bool, exp, false); } else { throw new NotImplementedException(msg); } TranslatedExpressions.Push(expr); return; } if (boogieTypeToBeConvertedTo == Bpl.Type.Int) { Bpl.Expr expr; if (boogieTypeOfValue == Bpl.Type.Bool) { expr = new Bpl.NAryExpr(tok, new Bpl.IfThenElse(tok), new List<Bpl.Expr>(new Bpl.Expr[] {exp, Bpl.Expr.Literal(1), Bpl.Expr.Literal(0)})); } else if (boogieTypeOfValue == this.sink.Heap.RefType) { expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Int), new List<Bpl.Expr>(new Bpl.Expr[] {exp})); } else if (boogieTypeOfValue == this.sink.Heap.RealType) { expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Real2Int), new List<Bpl.Expr>(new Bpl.Expr[] {exp})); } else if (boogieTypeOfValue == this.sink.Heap.UnionType) { expr = this.sink.Heap.FromUnion(Bpl.Token.NoToken, Bpl.Type.Int, exp, false); } else { throw new NotImplementedException(msg); } TranslatedExpressions.Push(expr); return; } if (boogieTypeToBeConvertedTo == this.sink.Heap.RefType) { // var a = BoxFromXXX(exp); Bpl.Variable a = this.sink.CreateFreshLocal(conversion.TypeAfterConversion); Bpl.Procedure boxOperator; if (boogieTypeOfValue == Bpl.Type.Bool) boxOperator = this.sink.Heap.BoxFromBool; else if (boogieTypeOfValue == Bpl.Type.Int) boxOperator = this.sink.Heap.BoxFromInt; else if (boogieTypeOfValue == this.sink.Heap.RealType) boxOperator = this.sink.Heap.BoxFromReal; else if (TranslationHelper.IsStruct(conversion.ValueToConvert.Type)) { // Boxing a struct implicitly makes a copy of the struct var typeOfValue = conversion.ValueToConvert.Type; var proc = this.sink.FindOrCreateProcedureForStructCopy(typeOfValue); var bplLocal = Bpl.Expr.Ident(this.sink.CreateFreshLocal(typeOfValue)); var cmd = new Bpl.CallCmd(tok, proc.Name, new List<Bpl.Expr> { exp, }, new List<Bpl.IdentifierExpr> { bplLocal, }); this.StmtTraverser.StmtBuilder.Add(cmd); TranslatedExpressions.Push(bplLocal); return; } else { if (boogieTypeOfValue != this.sink.Heap.UnionType) throw new NotImplementedException(msg); boxOperator = this.sink.Heap.BoxFromUnion; } var name = boxOperator.Name; this.StmtTraverser.StmtBuilder.Add(new Bpl.CallCmd(Bpl.Token.NoToken, name, new List<Bpl.Expr>(new Bpl.Expr[] {exp}), new List<Bpl.IdentifierExpr>(new Bpl.IdentifierExpr[] {Bpl.Expr.Ident(a)}))); TranslatedExpressions.Push(Bpl.Expr.Ident(a)); return; } if (boogieTypeToBeConvertedTo == this.sink.Heap.RealType) { Bpl.Expr expr; if (boogieTypeOfValue == Bpl.Type.Bool) { expr = new Bpl.NAryExpr(tok, new Bpl.IfThenElse(tok), new List<Bpl.Expr>(new Bpl.Expr[] {exp, Bpl.Expr.Literal(1), Bpl.Expr.Literal(0)})); expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Int2Real), new List<Bpl.Expr>(new Bpl.Expr[] {expr})); } else if (boogieTypeOfValue == Bpl.Type.Int) { expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Int2Real), new List<Bpl.Expr>(new Bpl.Expr[] {exp})); } else if (boogieTypeOfValue == this.sink.Heap.RefType) { expr = new Bpl.NAryExpr(Bpl.Token.NoToken, new Bpl.FunctionCall(this.sink.Heap.Unbox2Real), new List<Bpl.Expr>(new Bpl.Expr[] { exp })); } else if (boogieTypeOfValue == this.sink.Heap.UnionType) { expr = this.sink.Heap.FromUnion(tok, this.sink.Heap.RealType, exp, false); } else { throw new NotImplementedException(msg); } TranslatedExpressions.Push(expr); return; } //if (boogieTypeToBeConvertedTo == this.sink.Heap.UnionType) { // Bpl.Function func; // if (boogieTypeOfValue == Bpl.Type.Bool) { // func = this.sink.Heap.Bool2Union; // } // else if (boogieTypeOfValue == Bpl.Type.Int) { // func = this.sink.Heap.Int2Union; // } // else if (boogieTypeOfValue == this.sink.Heap.RefType) { // func = this.sink.Heap.Ref2Union; // } // else if (boogieTypeOfValue == this.sink.Heap.RealType) { // func = this.sink.Heap.Real2Union; // } // else { // throw new NotImplementedException(msg); // } // var boxExpr = new Bpl.NAryExpr(conversion.Token(), new Bpl.FunctionCall(func), new List<Bpl.Expr>(exp)); // TranslatedExpressions.Push(boxExpr); // return; //} }
private CallCmd CallToYieldProc(IToken tok, Dictionary<Variable, Variable> ogOldGlobalMap, Dictionary<string, Variable> domainNameToLocalVar) { List<Expr> exprSeq = new List<Expr>(); foreach (string domainName in linearTypeChecker.linearDomains.Keys) { exprSeq.Add(Expr.Ident(domainNameToLocalVar[domainName])); } foreach (IdentifierExpr ie in globalMods) { exprSeq.Add(Expr.Ident(ogOldGlobalMap[ie.Decl])); } if (yieldProc == null) { List<Variable> inputs = new List<Variable>(); foreach (string domainName in linearTypeChecker.linearDomains.Keys) { var domain = linearTypeChecker.linearDomains[domainName]; Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, "linear_" + domainName + "_in", new MapType(Token.NoToken, new List<TypeVariable>(), new List<Type> { domain.elementType }, Type.Bool)), true); inputs.Add(f); } foreach (IdentifierExpr ie in globalMods) { Formal f = new Formal(Token.NoToken, new TypedIdent(Token.NoToken, string.Format("og_global_old_{0}", ie.Decl.Name), ie.Decl.TypedIdent.Type), true); inputs.Add(f); } yieldProc = new Procedure(Token.NoToken, string.Format("og_yield_{0}", layerNum), new List<TypeVariable>(), inputs, new List<Variable>(), new List<Requires>(), new List<IdentifierExpr>(), new List<Ensures>()); yieldProc.AddAttribute("inline", new LiteralExpr(Token.NoToken, Microsoft.Basetypes.BigNum.FromInt(1))); } CallCmd yieldCallCmd = new CallCmd(Token.NoToken, yieldProc.Name, exprSeq, new List<IdentifierExpr>()); yieldCallCmd.Proc = yieldProc; return yieldCallCmd; }
/// <summary> /// /// </summary> /// <param name="methodCall"></param> /// <remarks>Stub, This one really needs comments!</remarks> public override void TraverseChildren(IMethodCall methodCall) { var resolvedMethod = ResolveUnspecializedMethodOrThrow(methodCall.MethodToCall); Bpl.IToken methodCallToken = methodCall.Token(); if (this.sink.Options.getMeHere) { // TODO: Get a method reference so this isn't a string comparison? var methodName = MemberHelper.GetMethodSignature(methodCall.MethodToCall, NameFormattingOptions.None); if (methodName.Equals("GetMeHere.GetMeHere.Assert")) { // for now, just translate it as "assert e" this.Traverse(methodCall.Arguments.First()); Bpl.Expr e = this.TranslatedExpressions.Pop(); this.StmtTraverser.StmtBuilder.Add(new Bpl.AssertCmd(methodCallToken, e)); return; } } // Handle type equality specially when it is testing against a constant, i.e., o.GetType() == typeof(T) if (IsOperator(resolvedMethod) && !IsConversionOperator(resolvedMethod) && TypeHelper.TypesAreEquivalent(resolvedMethod.ContainingType, this.sink.host.PlatformType.SystemType)) { // REVIEW: Assume the only operators on System.Type are == and != var typeToTest = methodCall.Arguments.ElementAtOrDefault(0) as ITypeOf; IMethodCall callToGetType; if (typeToTest == null) { typeToTest = methodCall.Arguments.ElementAtOrDefault(1) as ITypeOf; callToGetType = methodCall.Arguments.ElementAtOrDefault(0) as IMethodCall; } else { callToGetType = methodCall.Arguments.ElementAtOrDefault(1) as IMethodCall; } if (typeToTest != null && callToGetType != null && TypeHelper.TypesAreEquivalent(callToGetType.MethodToCall.ContainingType, this.sink.host.PlatformType.SystemObject) && MemberHelper.GetMethodSignature(callToGetType.MethodToCall).Equals("System.Object.GetType")) { IExpression objectToTest = callToGetType.ThisArgument; // generate: $TypeConstructor($DynamicType(o)) == TypeConstructorId var typeConstructorId = this.sink.FindOrDefineType(typeToTest.TypeToGet.ResolvedType).ConstructorId; Contract.Assume(typeConstructorId != null); this.Traverse(objectToTest); var e = this.TranslatedExpressions.Pop(); var exprs = new List<Bpl.Expr>(new Bpl.Expr[] {this.sink.Heap.DynamicType(e)}); Bpl.Expr typeTestExpression = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq, new Bpl.NAryExpr(methodCallToken, new Bpl.FunctionCall(sink.Heap.TypeConstructorFunction), exprs), Bpl.Expr.Ident(typeConstructorId)); if (MemberHelper.GetMethodSignature(resolvedMethod).Equals("System.Type.op_Inequality")) typeTestExpression = Bpl.Expr.Unary( methodCallToken, Bpl.UnaryOperator.Opcode.Not, typeTestExpression); this.TranslatedExpressions.Push(typeTestExpression); return; } } // Handle calls to Contract.ForAll and Contract.Exists specially (if they are to the overloads that take two ints and a predicate on ints) if (resolvedMethod.ContainingTypeDefinition.InternedKey == this.sink.host.PlatformType.SystemDiagnosticsContractsContract.InternedKey) { var methodName = resolvedMethod.Name.Value; if (methodCall.Arguments.Count() == 3 && (methodName == "ForAll" || methodName == "Exists")) { var noToken = Bpl.Token.NoToken; this.Traverse(methodCall.Arguments.ElementAt(0)); var lb = this.TranslatedExpressions.Pop(); this.Traverse(methodCall.Arguments.ElementAt(1)); var ub = this.TranslatedExpressions.Pop(); var delegateArgument = methodCall.Arguments.ElementAt(2); this.Traverse(delegateArgument); var del = this.TranslatedExpressions.Pop(); var boundVar = new Bpl.LocalVariable(noToken, new Bpl.TypedIdent(noToken, TranslationHelper.GenerateTempVarName(), Bpl.Type.Int)); var resultVar = new Bpl.LocalVariable(noToken, new Bpl.TypedIdent(noToken, TranslationHelper.GenerateTempVarName(), Bpl.Type.Bool)); var delegateType = delegateArgument.Type; var invokeMethod = delegateType.ResolvedType.GetMembersNamed(this.sink.host.NameTable.GetNameFor("Invoke"), false).First() as IMethodReference; var unspecializedInvokeMethod = Sink.Unspecialize(invokeMethod).ResolvedMethod; var invokeProcedureInfo = sink.FindOrCreateProcedure(unspecializedInvokeMethod); var ins = new List<Bpl.Expr>(); ins.Add(del); var localStmtTraverser = this.StmtTraverser.factory.MakeStatementTraverser(this.sink, this.StmtTraverser.PdbReader, this.contractContext); var secondArg = new Bpl.NAryExpr(noToken, new Bpl.FunctionCall(this.sink.Heap.Int2Union), new List<Bpl.Expr>(new Bpl.Expr[] {Bpl.Expr.Ident(boundVar)})); ins.Add(secondArg); var outs = new List<Bpl.IdentifierExpr>(); outs.Add(Bpl.Expr.Ident(resultVar)); var callCmd = new Bpl.CallCmd(noToken, invokeProcedureInfo.Decl.Name, ins, outs); var blockCmds = new List<Bpl.Cmd>(); blockCmds.Add( new Bpl.AssumeCmd(noToken, Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Eq, new Bpl.NAryExpr(noToken, new Bpl.FunctionCall(this.sink.Heap.Union2Int), new List<Bpl.Expr>(new Bpl.Expr[] {secondArg})), Bpl.Expr.Ident(boundVar)))); blockCmds.Add(callCmd); Bpl.Block block = new Bpl.Block(noToken, "A", blockCmds, new Bpl.ReturnExprCmd(noToken, Bpl.Expr.Ident(resultVar))); Bpl.Expr body = new Bpl.CodeExpr(new List<Bpl.Variable>(new Bpl.Variable[] {resultVar}), new List<Bpl.Block>{block}); Bpl.Expr antecedent = Bpl.Expr.And(Bpl.Expr.Le(lb, Bpl.Expr.Ident(boundVar)), Bpl.Expr.Lt(Bpl.Expr.Ident(boundVar), ub)); Bpl.Expr quantifier; if (methodName == "ForAll") { body = Bpl.Expr.Imp(antecedent, body); quantifier = new Bpl.ForallExpr(methodCallToken, new List<Bpl.Variable>(new Bpl.Variable[] {boundVar}), body); } else { body = Bpl.Expr.And(antecedent, body); quantifier = new Bpl.ExistsExpr(methodCallToken, new List<Bpl.Variable>(new Bpl.Variable[] {boundVar}), body); } this.TranslatedExpressions.Push(quantifier); return; } } List<Bpl.Expr> inexpr; List<Bpl.IdentifierExpr> outvars; Bpl.IdentifierExpr thisExpr; Dictionary<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> toBoxed; var proc = TranslateArgumentsAndReturnProcedure(methodCallToken, methodCall.MethodToCall, resolvedMethod, methodCall.IsStaticCall ? null : methodCall.ThisArgument, methodCall.Arguments, out inexpr, out outvars, out thisExpr, out toBoxed); string methodname = proc.Name; var translateAsFunctionCall = proc is Bpl.Function; bool isAsync = false; // this code structure is quite chaotic, and some code needs to be evaluated regardless, hence the try-finally try { if (!translateAsFunctionCall) { foreach (var a in resolvedMethod.Attributes) { if (TypeHelper.GetTypeName(a.Type).EndsWith("AsyncAttribute")) { isAsync = true; } } } var deferringCtorCall = resolvedMethod.IsConstructor && methodCall.ThisArgument is IThisReference; // REVIEW!! Ask Herman: is the above test enough? The following test is used in FindCtorCall.IsDeferringCtor, // but it doesn't work when the type is a struct S because then "this" has a type of "&S". //&& TypeHelper.TypesAreEquivalent(resolvedMethod.ContainingType, methodCall.ThisArgument.Type); if (resolvedMethod.IsConstructor && resolvedMethod.ContainingTypeDefinition.IsStruct && !deferringCtorCall) { handleStructConstructorCall(methodCall, methodCallToken, inexpr, outvars, thisExpr, proc); return; } Bpl.CallCmd call; bool isEventAdd = resolvedMethod.IsSpecialName && resolvedMethod.Name.Value.StartsWith("add_"); bool isEventRemove = resolvedMethod.IsSpecialName && resolvedMethod.Name.Value.StartsWith("remove_"); if (isEventAdd || isEventRemove) { call = translateAddRemoveCall(methodCall, resolvedMethod, methodCallToken, inexpr, outvars, thisExpr, isEventAdd); } else { if (translateAsFunctionCall) { var func = proc as Bpl.Function; var exprSeq = new List<Bpl.Expr>(); foreach (var e in inexpr) { exprSeq.Add(e); } var callFunction = new Bpl.NAryExpr(methodCallToken, new Bpl.FunctionCall(func), exprSeq); this.TranslatedExpressions.Push(callFunction); return; } else { EmitLineDirective(methodCallToken); call = new Bpl.CallCmd(methodCallToken, methodname, inexpr, outvars); call.IsAsync = isAsync; this.StmtTraverser.StmtBuilder.Add(call); } } foreach (KeyValuePair<Bpl.IdentifierExpr, Tuple<Bpl.IdentifierExpr,bool>> kv in toBoxed) { var lhs = kv.Key; var tuple = kv.Value; var rhs = tuple.Item1; Bpl.Expr fromUnion = this.sink.Heap.FromUnion(Bpl.Token.NoToken, lhs.Type, rhs, tuple.Item2); this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(lhs, fromUnion)); } if (this.sink.Options.modelExceptions == 2 || (this.sink.Options.modelExceptions == 1 && this.sink.MethodThrowsExceptions(resolvedMethod))) { Bpl.Expr expr = Bpl.Expr.Binary(Bpl.BinaryOperator.Opcode.Neq, Bpl.Expr.Ident(this.sink.Heap.ExceptionVariable), Bpl.Expr.Ident(this.sink.Heap.NullRef)); this.StmtTraverser.RaiseException(expr); } } finally { // TODO move away phone related code from the translation, it would be better to have 2 or more translation phases if (PhoneCodeHelper.instance().PhonePlugin != null) { if (PhoneCodeHelper.instance().PhoneNavigationToggled) { if (PhoneCodeHelper.instance().isNavigationCall(methodCall)) { Bpl.AssignCmd assignCmd = PhoneCodeHelper.instance().createBoogieNavigationUpdateCmd(sink); this.StmtTraverser.StmtBuilder.Add(assignCmd); } } if (PhoneCodeHelper.instance().PhoneFeedbackToggled) { if (PhoneCodeHelper.instance().isMethodKnownUIChanger(methodCall)) { Bpl.AssumeCmd assumeFalse = new Bpl.AssumeCmd(Bpl.Token.NoToken, Bpl.LiteralExpr.False); this.StmtTraverser.StmtBuilder.Add(assumeFalse); } } } } }
public override Cmd VisitCallCmd(CallCmd node) { //Contract.Requires(node != null); Contract.Ensures(Contract.Result<Cmd>() != null); CallCmd clone = (CallCmd)node.Clone(); Contract.Assert(clone != null); clone.Ins = new List<Expr>(clone.Ins); clone.Outs = new List<IdentifierExpr>(clone.Outs); return base.VisitCallCmd(clone); }
private Bpl.CallCmd translateAddRemoveCall(IMethodCall methodCall, IMethodDefinition resolvedMethod, Bpl.IToken methodCallToken, List<Bpl.Expr> inexpr, List<Bpl.IdentifierExpr> outvars, Bpl.IdentifierExpr thisExpr, bool isEventAdd) { Bpl.CallCmd call; var mName = resolvedMethod.Name.Value; var eventName = mName.Substring(mName.IndexOf('_') + 1); var eventDef = TypeHelper.GetEvent(resolvedMethod.ContainingTypeDefinition, this.sink.host.NameTable.GetNameFor(eventName)); Contract.Assert(eventDef != Dummy.Event); Bpl.Variable eventVar = this.sink.FindOrCreateEventVariable(eventDef); Bpl.Variable local = this.sink.CreateFreshLocal(eventDef.Type); if (methodCall.IsStaticCall) { this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(local), Bpl.Expr.Ident(eventVar))); inexpr.Insert(0, Bpl.Expr.Ident(local)); } else { AssertOrAssumeNonNull(methodCallToken, thisExpr); this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(local), this.sink.Heap.ReadHeap(thisExpr, Bpl.Expr.Ident(eventVar), resolvedMethod.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, local.TypedIdent.Type))); inexpr[0] = Bpl.Expr.Ident(local); } System.Diagnostics.Debug.Assert(outvars.Count == 0); outvars.Insert(0, Bpl.Expr.Ident(local)); string methodName = isEventAdd ? this.sink.DelegateAdd(eventDef.Type.ResolvedType) : this.sink.DelegateRemove(eventDef.Type.ResolvedType); call = new Bpl.CallCmd(methodCallToken, methodName, inexpr, outvars); this.StmtTraverser.StmtBuilder.Add(call); if (methodCall.IsStaticCall) { this.StmtTraverser.StmtBuilder.Add(TranslationHelper.BuildAssignCmd(Bpl.Expr.Ident(eventVar), Bpl.Expr.Ident(local))); } else { this.sink.Heap.WriteHeap(methodCallToken, thisExpr, Bpl.Expr.Ident(eventVar), Bpl.Expr.Ident(local), resolvedMethod.ContainingType.ResolvedType.IsStruct ? AccessType.Struct : AccessType.Heap, local.TypedIdent.Type, this.StmtTraverser.StmtBuilder); } return call; }