public MoveNextDriver(IMethodDriver <Local, Parameter, Method, Field, Property, Event, Type, Attribute, Assembly, Expression, Variable, ILogOptions> driver) { this.driver = driver; MoveNextStateAnalyzer preAnalyzer = new MoveNextStateAnalyzer(); stateInfo = preAnalyzer.AnalyzeMoveNext("MoveNext", driver); // If we are not able if (stateInfo.OrderedVisibleStates == null || stateInfo.OrderedVisibleStates.Count() == 0) { stateInfo = null; } }
/// <summary> /// Given the state machine information, return the set of entry points for the slices that /// do not correspond to "state". The entry point of a slice refers to program point for the case /// statements in the switch (this.__state) statement in a MoveNext method. /// </summary> /// <param name="info"></param> /// <param name="state"></param> /// <returns></returns> Set <APC> GetStateEntriesOtherThan(StateMachineInformation <Local> info, int state) { Set <APC> result = new Set <APC>(); foreach (int s in info.StateSliceEntries.Keys) { if (s == state) { continue; } var set = info.StateSliceEntries[s]; result = result | set; } return(result); }
/// <summary> /// Given an underlying analysis and generator for a bottom value, this method computes a mapping between a state of /// the iterator and fixpoint information computed by the underlying analysis for the slice that corresponds to that /// state. /// /// The analysis runs the underlying analyzer on state 0, the initial state, first. The state from the return point /// of this state will be the current value of the invariant candidate. /// Then for every continuing state (the state from which a new item is generated for the ienumerable result), we map /// the current invariant candidate and map it to the entry of the method, and run the underlying analysis for that /// state. Running the underlying analysis for a particular state requires a set of program points, which are the entry /// points of other slices. The underlying analysis will mark those program points as unreachable. The exit abstract /// state will become the current invariant candidate. This process finishes when a fixedpoint is reached. /// </summary> /// <typeparam name="MyDomain">The domain of the underlying analysis.</typeparam> /// <param name="analysis">The underlying analysis.</param> /// <param name="bv">A delegate that generates a bottom value for MyDomain.</param> /// <returns></returns> public FunctionalMap <int, IMethodAnalysisFixPoint <Variable> > Analyze <MyDomain>( IMoveNextOnePassAnalysis <Local, Parameter, Method, Field, Property, Type, Expression, Attribute, Assembly, MyDomain, Variable> analysis, StateGenerator <MyDomain> bv) { // Use a pre-analysis to collect information regarding the state machine. MoveNextStateAnalyzer preAnalyzer = new MoveNextStateAnalyzer(); StateMachineInformation <Local> stateInfo = preAnalyzer.AnalyzeMoveNext("MoveNext", driver); // If we are not able if (stateInfo.OrderedVisibleStates == null || stateInfo.OrderedVisibleStates.Count() == 0) { throw new ArgumentException("Argument error with MoveNext method: Cannot analyze the state machine."); } // Fix point computation: fixpoint of the iterator analysis is a mapping: answers. bool fixedpointReached = false; MyDomain d = default(MyDomain), oldd = default(MyDomain); FunctionalMap <int, IMethodAnalysisFixPoint <Variable> > answers = FunctionalMap <int, IMethodAnalysisFixPoint <Variable> > .Empty; MyDomain invariantCandidate = default(MyDomain); Converter <Variable, int> key = driver.KeyNumber; int pass = 0; while (!fixedpointReached) { fixedpointReached = true; // Going through every state of the state machine, if the final states changes at least once // then fixpoint is not reached. foreach (int state in stateInfo.OrderedVisibleStates) { // The initial state is only analyzed once. if (state < 0) { continue; } if (state == 0 && pass > 0) { continue; } // Initial value for one pass, either TOP, if we analyze it for the first time // or the invariantCandidate. if (invariantCandidate == null || invariantCandidate.Equals(default(MyDomain))) { d = analysis.GetInitialValue(key); } else { d = analysis.MutableVersion(invariantCandidate); } // Call the underlying analysis for one pass Set <APC> cutOffPCs = GetStateEntriesOtherThan(stateInfo, state); driver.CreateForwardForIterator(analysis, bv, cutOffPCs)(d); // Getting the state from the return point of the most recent pass, map it // to the entry point, and join it with the current invariant candidate IFunctionalMap <Variable, FList <Variable> > mapping = GetFieldMapping(driver); var fakeEdge = new Pair <APC, APC>(driver.CFG.NormalExit, driver.CFG.Entry); MyDomain returnState = analysis.ReturnState; MyDomain newState = analysis.ParallelAssign(fakeEdge, mapping, returnState); bool changed = false; if (invariantCandidate != null && !invariantCandidate.Equals(default(MyDomain))) { oldd = invariantCandidate; // TODO: use a more sophisticated widenning strategy. bool toWiden = (pass > 2) ? true : false; d = analysis.Join(fakeEdge, newState, oldd, out changed, toWiden); if (changed) { invariantCandidate = d; } } else { changed = true; invariantCandidate = newState; } if (changed) { fixedpointReached = false; } // Fill the result table with the most recent fixpoint information. answers = (FunctionalMap <int, IMethodAnalysisFixPoint <Variable> >)answers.Add(state, analysis.ExtractResult()); analysis = analysis.Duplicate(); } pass++; } return(answers); }