public AtomicPathPrefix(AtomicSpec i_atomicSpec, ArmadaPC pc) { atomicSpec = i_atomicSpec; nextRoutines = new List <NextRoutine>(); tau = false; startPC = endPC = pc; startType = endType = atomicSpec.GetPCAtomicType(pc); extensions = new List <AtomicPathPrefix>(); path = null; }
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}"; } } }