public WhilePCNode(ArmadaPC i_pc, NextRoutine i_nextRoutineWhenTrue, NextRoutine i_nextRoutineWhenFalse, PCNode i_successorWhenTrue, PCNode i_successorWhenFalse) : base(i_pc) { nextRoutineWhenTrue = i_nextRoutineWhenTrue; nextRoutineWhenFalse = i_nextRoutineWhenFalse; successorWhenTrue = i_successorWhenTrue; successorWhenFalse = i_successorWhenFalse; }
public bool IsNonyieldingPC(ArmadaPC pc) { if (pc == null) { return(false); } var method = allMethodsInfo.LookupMethod(pc.methodName); return(method == null ? false : method.IsNonyieldingPC(pc)); }
public string GetStoreBufferEntry(string val_new, ArmadaPC pc) { var loc = GetStoreBufferLocation(); if (loc == null) { return(null); } return($"Armada_StoreBufferEntry({loc}, {AH.GetPrimitiveValueConstructorName(type)}({val_new}), {pc.ToString()})"); }
public string GetNameForPC(ArmadaPC pc) { string labelStr = GetLabelForPC(pc); if (labelStr != null) { return(labelStr); } return(pc.instructionCount.ToString()); }
public ArmadaPC GenerateOnePC() { int pcVal = numPCs; ++numPCs; var pc = new ArmadaPC(symbols, method.Name, pcVal); symbols.AssociateLabelWithPC(pcVal.ToString(), pc); return(pc); }
private bool AdjacentPC(ArmadaPC lhs, ArmadaPC rhs) { if (lhs.methodName == null || rhs.methodName == null) { Console.WriteLine("Invalid PC"); return(false); } return(lhs.methodName == rhs.methodName && lhs.instructionCount + 1 == rhs.instructionCount); }
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 EnablingConstraintCollector GetEnablingConstraintCollector(ArmadaPC pc) { if (constraints.ContainsKey(pc)) { return(constraints[pc]); } else { return(null); } }
public string GetLabelForPC(ArmadaPC pc) { if (pcToLabelMap.ContainsKey(pc)) { return(pcToLabelMap[pc]); } else { return(null); } }
public void AssociateLabelWithPC(string labelStr, ArmadaPC pc) { var fullLabelStr = pc.methodName + "_" + labelStr; if (methodAndLabelToPCMap.ContainsKey(fullLabelStr)) { AH.PrintError(prog, $"ERROR: More than one label named {labelStr} in method {pc.methodName}"); } methodAndLabelToPCMap[fullLabelStr] = pc; pcToLabelMap[pc] = labelStr; }
public MethodInfo(Program i_prog, ArmadaSymbolTable i_symbols, Method i_method) { prog = i_prog; symbols = i_symbols; method = i_method; numPCs = 0; constraints = new Dictionary <ArmadaPC, EnablingConstraintCollector>(); returnPC = null; nonyieldingPCs = new HashSet <ArmadaPC>(); parsedBody = null; atomicCallsAndReturns = false; }
private ArmadaPC GetRoot(ArmadaPC key, Dictionary <ArmadaPC, ArmadaPC> unionFind) { if (unionFind.ContainsKey(key)) { unionFind[key] = GetRoot(unionFind[key], unionFind); } else { return(key); } return(unionFind[key]); }
public void AddEnablingConstraint(Program prog, ArmadaPC pc, Expression e) { if (!constraints.ContainsKey(pc)) { constraints[pc] = new EnablingConstraintCollector(prog); } var constraintCollector = constraints[pc]; var context = new EnablingConstraintResolutionContext(constraintCollector, method.Name, symbols); var rvalue = context.ResolveAsRValue(e); constraintCollector.AddConjunct(rvalue.UndefinedBehaviorAvoidance); constraintCollector.AddConjunct(rvalue.Val); }
private static PCNode GeneratePCStructureForMethodWithNoBody(ArmadaSymbolTable symbols, MethodInfo methodInfo, HashSet <ArmadaPC> loopHeads) { Method method = methodInfo.method; var startPC = new ArmadaPC(symbols, method.Name, 0); var midPC = new ArmadaPC(symbols, method.Name, 1); var endPC = new ArmadaPC(symbols, method.Name, 2); PCNode endNode = new ReturningPCNode(endPC); PCNode loopRestartNode = new LoopRestartPCNode(midPC); PCNode midNode = new WhilePCNode(midPC, method.externContinueNextRoutine, method.externEndNextRoutine, loopRestartNode, endNode); PCNode startNode = new NormalPCNode(startPC, method.externStartNextRoutine, midNode); loopHeads.Add(midPC); return(new StartingPCNode(startPC, startNode)); }
public NextRoutine(Program i_prog, ArmadaSymbolTable i_symbols, NextType i_nextType, MethodInfo i_methodInfo, ArmadaStatement i_armadaStatement, Statement i_stmt, ArmadaPC i_startPC, ArmadaPC i_endPC, List <NextFormal> i_formals, string i_nameSuffix, bool i_undefinedBehavior, bool i_stopping) { prog = i_prog; symbols = i_symbols; nextType = i_nextType; methodInfo = i_methodInfo; armadaStatement = i_armadaStatement; stmt = i_stmt; startPC = i_startPC; endPC = i_endPC; formals = new List <NextFormal>(i_formals); nameSuffix = i_nameSuffix; undefinedBehavior = i_undefinedBehavior; stopping = i_stopping; }
public NextRoutineConstructor(Program i_prog, ArmadaSymbolTable i_symbols, NextType i_nextType, MethodInfo i_methodInfo, ArmadaStatement i_armadaStatement, Statement i_stmt, ArmadaPC i_startPC, ArmadaPC i_endPC) { prog = i_prog; symbols = i_symbols; nextType = i_nextType; validDefinedStepBuilder = new PredicateBuilder(i_prog, true); validUndefinedStepBuilder = new PredicateBuilder(i_prog, false); getNextStateBuilder = new ExpressionBuilder(i_prog); methodInfo = i_methodInfo; method = methodInfo == null ? null : methodInfo.method; armadaStatement = i_armadaStatement; stmt = i_stmt; startPC = i_startPC; endPC = i_endPC; formals = new List <NextFormal>(); valid = true; hasUndefinedBehaviorAvoidanceConstraint = false; definedBehaviorNextRoutine = null; undefinedBehaviorNextRoutine = null; s = ReserveVariableName("s"); entry = ReserveVariableName("entry"); tid = ReserveVariableName("tid"); t = ReserveVariableName("t"); locv = ReserveVariableName("locv"); if (startPC != null) { AddConjunct($"{t}.pc.{startPC}?"); AddConjunct($"{t}.top.Armada_StackFrame_{startPC.methodName}?"); if (methodInfo != null) { var constraints = methodInfo.GetEnablingConstraintCollector(startPC); if (constraints != null && !constraints.Empty) { AddConjunct($"Armada_EnablingConditions_{startPC}(s, tid)"); } } AddConjunct("Armada_UniversalStepConstraint(s, tid)"); } }
/////////////////////////////////////////////////////////////////////// // PC TYPES /////////////////////////////////////////////////////////////////////// public PCAtomicType GetPCAtomicType(ArmadaPC pc) { if (pc == null) { return(PCAtomicType.Yielding); } if (recurrentPCs.Contains(pc)) { return(PCAtomicType.Recurrent); } if (nonyieldingPCs.Contains(pc)) { return(PCAtomicType.Nonyielding); } else { return(PCAtomicType.Yielding); } }
public void ParseMethodBody(ArmadaSymbolTable symbols) { var parse = new ParseInfo(prog, symbols, this); parsedBody = ArmadaStatement.ParseStatement(parse, method.Body); var startPC = GenerateOnePC(); returnPC = parsedBody.AssignPCs(startPC); ArmadaStatement.ComputeNonyieldingPCs(parsedBody, nonyieldingPCs); symbols.AssociateLabelWithPC("Start", startPC); symbols.AssociateLabelWithPC("End", returnPC); foreach (var statement in parsedBody) { statement.AssociateLabelsWithPCs(); statement.GenerateEnablingConstraints(); } }
/////////////////////////////////////////////////////////////////////// // FINDING RECURRENT PCS /////////////////////////////////////////////////////////////////////// /// <summary> /// In CheckForFiniteNonyieldingPathBetween, we only care about /// paths that reach end before visiting any other node twice /// (since if it visits another node twice, it's potentially /// infinite). So, we keep track of nodes we've already visited /// and don't visit them again. /// </summary> private bool CheckForFiniteNonyieldingPathBetween(ArmadaPC start, ArmadaPC end, HashSet <ArmadaPC> alreadyVisited) { if (start == null || end == null) { return(false); } if (!nonyieldingPCs.Contains(start)) { return(false); } List <NextRoutine> nextRoutines; if (!pcToNextRoutines.TryGetValue(start, out nextRoutines)) { return(false); } foreach (var nextRoutine in nextRoutines) { var nextPC = nextRoutine.endPC; if (nextPC.Equals(end)) { return(true); } if (alreadyVisited.Contains(nextPC)) { continue; } alreadyVisited.Add(nextPC); if (CheckForFiniteNonyieldingPathBetween(nextPC, end, alreadyVisited)) { return(true); } alreadyVisited.Remove(nextPC); } return(false); }
public string UpdateTotalStateWithStoreBufferEntry(ResolutionContext context, IConstraintCollector constraintCollector, string val_new, ArmadaPC pc) { if (NoTSO()) { return(UpdateTotalStateLocationDirectly(context, constraintCollector, val_new)); } if (!AH.IsPrimitiveType(type)) { context.Fail(tok, "Can't do TSO write to non-primitive type; try using ::= instead of :="); return(null); } var entry = GetStoreBufferEntry(val_new, pc); if (entry == null) { context.Fail(tok, "Can't do a TSO write to that location; try using ::= instead of :="); return(null); } return($"Armada_AppendToThreadStoreBuffer({context.GetLValueState()}, {context.tid}, {entry})"); }
private bool DoesNonyieldingPathBetweenPCsExist(ArmadaPC start, ArmadaPC end) { var alreadyVisited = new HashSet <ArmadaPC>(); return(CheckForFiniteNonyieldingPathBetween(start, end, alreadyVisited)); }
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 IEnumerable <AtomicPathPrefix> RootPathPrefixesByPC(ArmadaPC pc) { return(rootPathPrefixesByPC[pc]); }
//////////////////////////////////////////////////////////////////////// /// PC map //////////////////////////////////////////////////////////////////////// bool MakePCMap() { startPC = pgp.symbolsLow.GetPCForMethodAndLabel(strategy.StartLabel.val); if (startPC == null) { AH.PrintError(pgp.prog, $"You specified a start label for combining of {strategy.StartLabel.val}, but that label doesn't exist in level {pgp.mLow.Name}. Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main."); return(false); } endPC = pgp.symbolsLow.GetPCForMethodAndLabel(strategy.EndLabel.val); if (endPC == null) { AH.PrintError(pgp.prog, $"You specified an end label for combining of {strategy.EndLabel.val}, but that label doesn't exist in level {pgp.mLow.Name}. Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main."); return(false); } if (endPC.methodName != startPC.methodName) { AH.PrintError(pgp.prog, $"The start and end labels you provided for combining aren't from the same method in {pgp.mLow.Name}. The start label {strategy.StartLabel.val} is in method {startPC.methodName} and the end label {strategy.EndLabel.val} is in method {endPC.methodName}."); return(false); } if (endPC.instructionCount <= startPC.instructionCount) { AH.PrintError(pgp.prog, $"The end label you provided for combining ({strategy.EndLabel.val}) isn't after the start label you provided for combining ({strategy.StartLabel.val})."); return(false); } singlePC = pgp.symbolsHigh.GetPCForMethodAndLabel(strategy.SingleLabel.val); if (singlePC == null) { AH.PrintError(pgp.prog, $"You specified a single label for combining of {strategy.SingleLabel.val}, but that label doesn't exist in level {pgp.mHigh.Name}. Remember to prefix label names with the method name and an underscore, e.g., use main_lb1 if you have label lb1: in method main."); return(false); } if (singlePC.methodName != startPC.methodName) { AH.PrintError(pgp.prog, $"The start and end labels you provided for combining aren't from the same method as the single label you provided. That is, {strategy.StartLabel.val} and {strategy.EndLabel.val} are both from method {startPC.methodName}, but the single label {strategy.SingleLabel.val} is from method {singlePC.methodName}."); return(false); } if (singlePC.instructionCount != startPC.instructionCount) { AH.PrintError(pgp.prog, $"The start label you provided isn't at the same position in its method as the single label you provided. That is, {strategy.StartLabel.val} is preceded by {startPC.instructionCount} instructions in {pgp.mLow.Name}, but {strategy.SingleLabel.val} is preceded by {singlePC.instructionCount} instructions in {pgp.mHigh.Name}."); return(false); } pcMap = new Dictionary <ArmadaPC, ArmadaPC>(); var pcs = new List <ArmadaPC>(); pgp.symbolsLow.AllMethods.AppendAllPCs(pcs); foreach (var pc in pcs) { if (pc.methodName != startPC.methodName) { pcMap[pc] = pc.CloneWithNewSymbolTable(pgp.symbolsHigh); } else if (pc.instructionCount < startPC.instructionCount) { pcMap[pc] = pc.CloneWithNewSymbolTable(pgp.symbolsHigh); } else if (pc.instructionCount == startPC.instructionCount) { pcMap[pc] = singlePC; } else if (pc.instructionCount <= endPC.instructionCount) { pcMap[pc] = new ArmadaPC(pgp.symbolsHigh, pc.methodName, singlePC.instructionCount + 1); } else { pcMap[pc] = new ArmadaPC(pgp.symbolsHigh, pc.methodName, pc.instructionCount + startPC.instructionCount - endPC.instructionCount); } } ExtendPCMapWithExternalAndStructsMethods(); GenerateNextRoutineMap(false); return(true); }
public NormalPCInfo(ArmadaPC pc) : base(pc) { }
public ForkSitePCInfo(ArmadaPC pc) : base(pc) { }
public CallSitePCInfo(ArmadaPC pc) : base(pc) { }
public ReturnSitePCInfo(ArmadaPC pc) : base(pc) { }
public ReturningPCNode(ArmadaPC i_pc) : base(i_pc) { }
public LoopRestartPCNode(ArmadaPC i_pc) : base(i_pc) { }