/////////////////////////////////////////////////////////////////////// // MAKING ATOMIC STEPS /////////////////////////////////////////////////////////////////////// private void DetermineAtomicPaths() { allPCs = new List <ArmadaPC>(); symbols.AllMethods.AppendAllPCs(allPCs); var tauPathPrefix = new AtomicPathPrefix(this, new List <NextRoutine> { symbols.TauNextRoutine }, true, null); tauPath = new AtomicPath(tauPathPrefix); atomicPaths = new List <AtomicPath> { tauPath }; rootPathPrefixesByPC = new Dictionary <ArmadaPC, List <AtomicPathPrefix> >(); foreach (var startPC in allPCs) { rootPathPrefixesByPC[startPC] = new List <AtomicPathPrefix>(); if (GetPCAtomicType(startPC) != PCAtomicType.Nonyielding) { List <NextRoutine> nextRoutines; if (pcToNextRoutines.TryGetValue(startPC, out nextRoutines)) { foreach (var nextRoutine in nextRoutines) { var rootAtomicPathPrefix = new AtomicPathPrefix(this, new List <NextRoutine> { nextRoutine }, false, null); rootPathPrefixesByPC[startPC].Add(rootAtomicPathPrefix); PopulateAtomicPathPrefix(rootAtomicPathPrefix); } } } } }
/////////////////////////////////////////////////////////////////////// // SEARCHING FOR AN ATOMIC PATH /////////////////////////////////////////////////////////////////////// public AtomicPathPrefix FindAtomicPathPrefixByNextRoutines(List <NextRoutine> nextRoutines) { if (nextRoutines.Count == 0) { return(null); } var firstRoutine = nextRoutines[0]; if (firstRoutine.nextType == NextType.Tau) { return(null); } AtomicPathPrefix pathPrefix = null; foreach (var nextRoutine in nextRoutines) { var children = (pathPrefix == null ? rootPathPrefixesByPC[firstRoutine.startPC] : pathPrefix.Extensions); pathPrefix = children.FirstOrDefault(p => p.LastNextRoutine == nextRoutine); if (pathPrefix == null) { return(null); } } return(pathPrefix); }
public AtomicPath FindAtomicPathByPCs(List <ArmadaPC> pcs, bool stopping) { if (pcs.Count == 0) { return(null); } AtomicPathPrefix pathPrefix = null; for (var i = 1; i < pcs.Count; ++i) { var pc = pcs[i]; var children = (i == 1) ? rootPathPrefixesByPC[pcs[0]] : pathPrefix.Extensions; var findStopping = stopping && (i == pcs.Count - 1); if (pc == null) { pathPrefix = children.FirstOrDefault(p => p.LastNextRoutine.endPC == null && p.Stopping == findStopping); } else { pathPrefix = children.FirstOrDefault(p => pc.Equals(p.LastNextRoutine.endPC) && p.Stopping == findStopping); } if (pathPrefix == null) { return(null); } } return(pathPrefix.PathVal); }
private void PopulateAtomicPathPrefix(AtomicPathPrefix pathPrefix) { var currentPC = pathPrefix.EndPC; if (pathPrefix.Stopping || currentPC == null || GetPCAtomicType(currentPC) != PCAtomicType.Nonyielding) { pathPrefix.PathVal = new AtomicPath(pathPrefix); atomicPaths.Add(pathPrefix.PathVal); return; } List <NextRoutine> subsequentRoutines; if (pcToNextRoutines.TryGetValue(currentPC, out subsequentRoutines)) { foreach (var subsequentRoutine in subsequentRoutines) { var childNextRoutines = new List <NextRoutine>(pathPrefix.NextRoutines); childNextRoutines.Add(subsequentRoutine); var childPathPrefix = new AtomicPathPrefix(this, childNextRoutines, false, pathPrefix); PopulateAtomicPathPrefix(childPathPrefix); } } }
public AtomicPathPrefix(AtomicSpec i_atomicSpec, List <NextRoutine> i_nextRoutines, bool i_tau, AtomicPathPrefix parent) { atomicSpec = i_atomicSpec; nextRoutines = new List <NextRoutine>(i_nextRoutines); tau = i_tau; startPC = nextRoutines[0].startPC; endPC = nextRoutines[nextRoutines.Count - 1].endPC; startType = atomicSpec.GetPCAtomicType(startPC); endType = nextRoutines[nextRoutines.Count - 1].Stopping ? PCAtomicType.Stopping : atomicSpec.GetPCAtomicType(endPC); extensions = new List <AtomicPathPrefix>(); path = null; if (parent != null) { parent.AddExtension(this); } if (tau) { name = "Tau"; } else { name = UndefinedBehavior ? "UB_" : ""; name += $"From_{startPC.methodName}_{startPC.Name}"; // It's possible for two atomic paths to have the same start // and end PCs. But, every path has to have a distinct name, // so we sometimes have to name a path with more than just the // start and end PCs. // // One way for two atomic paths with the same start and end // PCs to differ is via returning to different PCs. For // instance, consider the following code: // // method {:atomic} A { // S1; // label L: // S2; // } // // method B { // atomic { // A(); // A(); // A(); // } // } // // Here, there are two ways to get from label L to label L: // (1) by returning from B's first call to A and then making // B's second call to A, and (2) by returning from B's second // call to A and then making B's third call to A. So, to make // sure such paths have different names, we include in the // name every returned-to PC in a step other than the last one // in the path. // // Another way for two atomic paths with the same start and // end PCs to differ is via branch outcomes. For instance, // consider the following code: // // atomic { // if P { // S1; // } // S2; // } // // Here, there are two ways to get from the beginning to the // end: via the true branch of the if (passing through // statement S1) or via the false branch. So we distinguish // the names of such paths by the branch outcomes. bool justBranched = false; for (var i = 0; i < nextRoutines.Count; ++i) { var nextRoutine = nextRoutines[i]; if (i < nextRoutines.Count - 1 && nextRoutine.nextType == NextType.Return) { var returnToPC = nextRoutine.endPC; name += $"_Via_{returnToPC.methodName}_{returnToPC.Name}"; justBranched = false; } bool branchOutcome; if (nextRoutine.TryGetBranchOutcome(out branchOutcome)) { if (!justBranched) { name += "_"; } name += (branchOutcome ? "T" : "F"); justBranched = true; } } if (endPC == null) { name += "_to_exit"; } else { name += $"_To_{endPC.methodName}_{endPC.Name}"; } } }
public AtomicPath(AtomicPathPrefix i_pathPrefix) { pathPrefix = i_pathPrefix; stopping = i_pathPrefix.Stopping; name = pathPrefix.Name; }
public void AddExtension(AtomicPathPrefix other) { extensions.Add(other); }