/// <summary> /// It visits an individual statement. It is called from VisitBlock. /// /// It calls NonNullInstructionVisitor /// </summary> /// <param name="block"></param> /// <param name="statement"></param> /// <param name="dfstate"></param> /// <returns></returns> protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { // For debug purpose if (Analyzer.Debug) { try{ Analyzer.WriteLine("\n:::" + new SampleInstructionVisitor().Visit(statement, null) + " ::: " + statement.SourceContext.SourceText); }catch (Exception e) { Analyzer.WriteLine("Print error: " + statement + ": " + e.Message); } } IDataFlowState result = null; try{ result = (IDataFlowState)(iVisitor.Visit(statement, dfstate)); }catch (Exception e) { typeSystem.HandleError(statement, Cci.Error.InternalCompilerError, ":NonNull:" + e.Message); Console.WriteLine(e.StackTrace); } if (result != null && Analyzer.Debug) { result.Dump(); } return(result); }
/// <summary> /// It split exceptions for current handler and the next chained handler. /// /// It will: /// /// If the exception is completely intercepted by current handler, the /// exception will be consumed. /// /// If the exception caught but not completely, both current handler and /// the next handler will take the states. /// /// If the exception is irrelevant to current caught, the next handler /// will take over the state. Current handler is then bypassed. /// </summary> /// <param name="handler"></param> /// <param name="currentHandlerState"></param> /// <param name="nextHandlerState"></param> protected override void SplitExceptions(CfgBlock handler, ref IDataFlowState currentHandlerState, out IDataFlowState nextHandlerState) { Debug.Assert(currentHandlerState != null, "Internal error in NonNull Analysis"); ExposureState state = (ExposureState)currentHandlerState; if (handler == null || handler.Length == 0) { nextHandlerState = null; return; } if (handler[0] is Unwind) { nextHandlerState = null; currentHandlerState = null; return; } Debug.Assert(handler[0] is Catch, "Exception Handler does not starts with Catch"); Debug.Assert(state.currentException != null, "No current exception to handle"); Catch c = (Catch)handler[0]; if (handler.ExceptionHandler != null && !state.currentException.IsAssignableTo(c.Type)) { nextHandlerState = state;; } else { nextHandlerState = null; } // Compute what trickles through to the next handler // and what sticks to this handler. if (state.currentException.IsAssignableTo(c.Type)) { // everything sticks nextHandlerState = null; } else if (c.Type.IsAssignableTo(state.currentException)) { // c sticks, rest goes to next handler nextHandlerState = state; // copy state to modify the currentException state = new ExposureState(state); state.currentException = c.Type; currentHandlerState = state; } else { // nothing stick all goes to next handler nextHandlerState = state; currentHandlerState = null; } return; }
/// <summary> /// Merge the new pending state with the old pending states. /// </summary> /// <returns>merged pending state</returns> private IDataFlowState JoinWithPendingState(CfgBlock prev, CfgBlock block, IDataFlowState newState) { if (Tracing) { Console.WriteLine("JoinWithPendingState: block {0} -> {1}", (prev).UniqueKey, (block).UniqueKey); } IDataFlowState pending = PendingState(block); // note, we call Merge even if old is null. bool changed; bool precise; if (Tracing) { SourceContext sc = (block).SourceContext; if (sc.Document == null && block.Length > 0) { sc = ((Statement)block[0]).SourceContext; } Console.WriteLine("Join with pending state at line {0}", sc.StartLine); } IDataFlowState merged = this.Merge(prev, block, pending, newState, out changed, out precise); if (Tracing) { Console.WriteLine("Join changed {0}", changed); } return(merged); }
/// <summary> /// Compute the join of two data flow states at the given block. /// </summary> /// <param name="previous">Predecessor block for this new state</param> /// <param name="joinPoint">Block at which join is computed</param> /// <param name="atMerge">Old state at this block. Can be null, in which case the incoming state /// is the first non-bottom state. In this case, the method must set changed /// <c>resultDiffersFromPreviousMerge</c> to true.</param> /// <param name="incoming">New data flow state flowing to this block.</param> /// <param name="resultDiffersFromPreviousMerge">Boolean for fix point. If the state after /// the merge is equal to the old <c>atMerge</c> state, set to false, otherwise set to true.</param> /// <param name="mergeIsPrecise">can be set to true if the merged result state strictly contains only /// information representing either the atMerge or the incoming state, but no extra approximation. If /// this information cannot be determined by the merge, it must return false. True can only be returned /// if result is truly precise.</param> /// <returns>The new merged state.</returns> protected abstract IDataFlowState Merge( CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise );
private void SetPendingState(CfgBlock block, IDataFlowState pending) { pendingStates[block.Index] = pending; if (Tracing) { Console.WriteLine("SetPendingState: block {0}", (block).UniqueKey); } }
/// <summary> /// Like PendingState returns the pending state for the given block, but /// it also sets the pending state for this block to null. /// </summary> /// <returns>old pending state</returns> private IDataFlowState PopPendingState(CfgBlock block) { IDataFlowState pending = pendingStates[block.Index]; pendingStates[block.Index] = null; if (Tracing) { Console.WriteLine("PopPendingState: block {0}", (block).UniqueKey); } return(pending); }
protected override IDataFlowState Merge(CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise) { resultDiffersFromPreviousMerge = false; mergeIsPrecise = true; if (atMerge == null) { resultDiffersFromPreviousMerge = true; } atMerge = incoming; return(atMerge); }
/// <summary> /// Add the given state to the pending states of the target block. If /// the block is enabled (by the pending edge count optimization), add the /// block to the worklist. /// /// Inv: DoneState => PendingState /\ PendingState != null => InQueue /// /// Cases: /// 1. Done => new, nothing to do /// 2. Done |_| new is precise. Pend' = Pend |_| new, Done' = Done |_| new /// 3. Done |_| new is imprecise. Pend' = Done |_| new, Done' = Done |_| new /// </summary> public void PushState( CfgBlock currentBlock, CfgBlock nextBlock, IDataFlowState state ) { if (Tracing) { Console.WriteLine("PushState: block {0} -> {1}", (currentBlock).UniqueKey, (nextBlock).UniqueKey); } // state == null signals that branch is infeasible if (state == null) { return; } bool precise; // Add state to done state IDataFlowState stillPending = this.StateToReanalyzeBlock(currentBlock, nextBlock, state, out precise); if (stillPending == null) { if (Tracing) { Console.WriteLine("PushState: block {0} no new information for pending state.", (nextBlock).UniqueKey); } return; } if (precise) { // join stillPending to old pending. stillPending = this.JoinWithPendingState(currentBlock, nextBlock, stillPending); } this.SetPendingState(nextBlock, stillPending); // when dequeued, the pending state is what the block needs to be analyzed under. // joinWorkItems.Enqueue(nextBlock); if (Tracing) { Console.WriteLine("PushState: block {0} put on work queue.", (nextBlock).UniqueKey); } }
/// <summary> /// Default per block visitor. Called from Run. /// /// It calls VisitStatement on each statement in a block. /// /// The result of this method is used as the state for all normal control flow successors. /// To push state onto an exception handler, use the PushExceptionState method. Furthermore, for /// conditional branches, different states can be pushed onto the true and false branches directly /// by calling PushPending. In that case, null should be returned from the method in order to avoid pushing /// the returned state onto both true and false targets again. /// </summary> protected virtual IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) { IDataFlowState currentState = stateOnEntry; for (int i = 0; i < block.Length; i++) { if (currentState == null) { return(null); } currentState = this.VisitStatement(block, (Statement)block[i], currentState); } return(currentState); }
protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { // For debug purpose try{ Analyzer.WriteLine(new SampleInstructionVisitor().Visit(statement,null)+" ::: " +statement.SourceContext.SourceText); }catch(Exception){ Analyzer.WriteLine("Print error: "+statement); } IDataFlowState result=null; try{ result =(IDataFlowState)(iVisitor.Visit(statement,dfstate)); }catch(ModifiesException e){ typeSystem.HandleError(statement,System.Compiler.Error.Warning,":"+e.Message); }catch(Exception e){ typeSystem.HandleError(statement,System.Compiler.Error.Warning,":CFG1:"+e.Message); } Analyzer.WriteLine(dfstate); return dfstate; }
protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) { Debug.Assert(block!=null); currentBlock=block; Analyzer.Write("---------block: "+block.UniqueId+";"); Analyzer.Write(" Exit:"); foreach (CfgBlock b in block.NormalSuccessors) Analyzer.Write(b.UniqueId+";"); if (block.UniqueSuccessor!=null) Analyzer.Write(" FallThrough: "+block.UniqueSuccessor+";"); if (block.ExceptionHandler!=null) Analyzer.Write(" ExHandler: "+block.ExceptionHandler.UniqueId+";"); Analyzer.WriteLine(""); NonNullables newState=new NonNullables(stateOnEntry); if (block.ExceptionHandler!=null) this.PushExceptionState(block,newState); return base.VisitBlock (block, newState); }
protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) { IDataFlowState resultState = stateOnEntry; IDataFlowState newState = new MyState(); if (block.ExceptionHandler != null) { this.PushExceptionState(block, newState); } resultState = base.VisitBlock(block, newState); if (block.UniqueId == cfg.NormalExit.UniqueId) { } if (block.UniqueId == cfg.ExceptionExit.UniqueId) { } return(resultState); }
/// <summary> /// Starts the analysis at the first instruction of the given block /// </summary> protected virtual void Run(ControlFlowGraph cfg, CfgBlock startBlock, IDataFlowState startState) { this.Reinitialize(cfg); pendingStates[startBlock.Index] = startState; joinWorkItems.Enqueue(startBlock); while (joinWorkItems.Count > 0) { //joinWorkItems.Dump(); CfgBlock currentBlock = joinWorkItems.Dequeue(); if (Analyzer.Debug) { Console.WriteLine("\n*** Working on block {0} [{1} statements, line {2}]\n", ((currentBlock).UniqueKey), currentBlock.Length, (currentBlock.Length == 0)? -1 : ((Statement)currentBlock[0]).SourceContext.StartLine); } // Flow the current state through the block. IDataFlowState currentState = PopPendingState(currentBlock); currentState = VisitBlock(currentBlock, currentState); // NOTE: VisitBlock may have explicitly pushed states onto some successors. In that case // it should return null to avoid this code pushing the same state onto all successors. if (currentState != null) { foreach (CfgBlock succ in currentBlock.NormalSuccessors) { PushState(currentBlock, succ, currentState); } } } //while }
/// <summary> /// Push the given state onto the handler of the block. /// This causes call-backs to SplitException in order to correctly distribute /// the exception state among different nested handlers. /// </summary> /// <param name="currentBlock">Block from which exception escapes</param> /// <param name="state">state on exception flow</param> public void PushExceptionState( CfgBlock currentBlock, IDataFlowState state ) { IDataFlowState currentHandlerState = state; CfgBlock currentHandler = currentBlock; IDataFlowState nextHandlerState; while (currentHandlerState != null) { Debug.Assert(currentHandler.ExceptionHandler != null, String.Format("block {0} does not have an exception handler", (currentHandler).UniqueKey)); currentHandler = currentHandler.ExceptionHandler; if (Tracing) { Console.WriteLine("PushExceptionState (in loop): block {0} -> {1}", (currentBlock).UniqueKey, (currentHandler).UniqueKey); } SplitExceptions(currentHandler, ref currentHandlerState, out nextHandlerState); /// We allow SplitExceptions to make decisions about not propagating any exceptions /// Debug.Assert(currentHandlerState != null || nextHandlerState != null); if (currentHandlerState != null) { PushState(currentBlock, currentHandler, currentHandlerState); } currentHandlerState = nextHandlerState; } }
/// <summary> /// Implementation of visit Block. It is called from run. /// /// It calls VisitStatement. /// </summary> /// <param name="block"></param> /// <param name="stateOnEntry"></param> /// <returns></returns> protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) { Debug.Assert(block != null); currBlock = block; Analyzer.Write("---------block: " + block.UniqueId + ";"); Analyzer.Write(" Exit:"); foreach (CfgBlock b in block.NormalSuccessors) { Analyzer.Write(b.UniqueId + ";"); } if (block.UniqueSuccessor != null) { Analyzer.Write(" FallThrough: " + block.UniqueSuccessor + ";"); } if (block.ExceptionHandler != null) { Analyzer.Write(" ExHandler: " + block.ExceptionHandler.UniqueId + ";"); } Analyzer.WriteLine(""); ExposureState newState; if (stateOnEntry == null) { newState = new ExposureState(typeSystem); } else { newState = new ExposureState((ExposureState)stateOnEntry); } // if (block.ExceptionHandler!=null) // this.PushExceptionState(block,newState); return(base.VisitBlock(block, newState)); }
/// <summary> /// Starts the analysis at the first instruction of the given block /// </summary> protected virtual void Run (ControlFlowGraph cfg, CfgBlock startBlock, IDataFlowState startState) { this.Reinitialize(cfg); pendingStates[startBlock.Index] = startState; joinWorkItems.Enqueue(startBlock); while (joinWorkItems.Count > 0) { //joinWorkItems.Dump(); CfgBlock currentBlock = joinWorkItems.Dequeue(); if (Analyzer.Debug) { Console.WriteLine("\n*** Working on block {0} [{1} statements, line {2}]\n", ((currentBlock).UniqueKey), currentBlock.Length, (currentBlock.Length == 0)? -1 : ((Statement)currentBlock[0]).SourceContext.StartLine); } // Flow the current state through the block. IDataFlowState currentState = PopPendingState(currentBlock); currentState = VisitBlock(currentBlock, currentState); // NOTE: VisitBlock may have explicitly pushed states onto some successors. In that case // it should return null to avoid this code pushing the same state onto all successors. if (currentState != null) { foreach (CfgBlock succ in currentBlock.NormalSuccessors) { PushState(currentBlock, succ, currentState); } } } //while }
/// <summary> /// Visit the statement. It calls the instruction visitor to perform the transfer function /// </summary> /// <param name="block"></param> /// <param name="statement"></param> /// <param name="dfstate"></param> /// <returns></returns> protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { PointsToAndWriteEffects ptwe = (PointsToAndWriteEffects)dfstate; // PointsToAndWriteEffects ptweOld = new PointsToAndWriteEffects(ptwe); IDataFlowState res = base.VisitStatement(block, statement, dfstate); return res; }
/// <summary> /// Compute the Dataflow analysis for the given method /// Returns true if the method is pure /// </summary> /// <param name="method"></param> /// <returns></returns> public bool ComputePointsToStateFor(Method method) { // Get or compute the CFG ControlFlowGraph cfg = pointsToStateAnalysys.GetCFG(method); //if (PointsToAnalysis.debug) // CodePrinter.PrintMethod(method); PointsToState initialState = this.pointsToStateAnalysys.Factory.NewElement(method); // If we can compute de CFG and the method is not unsafe // We compute the dataflow analysis if (cfg != null && !PointsToAnalysis.IsUnsafe(method)) { ComputeBeforeDataflow(method); this.Run(cfg, initialState); if (exitState == null) { if (PointsToAnalysis.debug) Console.WriteLine("Method {0} exitState NULL", method.GetFullUnmangledNameWithTypeParameters()); } // FIX PointsToState PointsToStateAtExit = (PointsToState)exitState; ComputeAfterDataflow(method); return true; } else { exitState = null; return false; } }
/// <summary> /// Merge the two states for current block. /// </summary> /// <param name="previous"></param> /// <param name="joinPoint"></param> /// <param name="atMerge"></param> /// <param name="incoming"></param> /// <param name="resultDiffersFromPreviousMerge"></param> /// <param name="mergeIsPrecise"></param> /// <returns></returns> protected override IDataFlowState Merge(CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise) { mergeIsPrecise = false; // No new states; if (incoming == null) { resultDiffersFromPreviousMerge = false; return(atMerge); } // Initialize states if (atMerge == null) { resultDiffersFromPreviousMerge = true; return(incoming); } if (Analyzer.Debug) { Console.WriteLine("Merge at Block {0}-----------------", (joinPoint).UniqueKey); Console.WriteLine(" State at merge"); atMerge.Dump(); Console.WriteLine(" Incoming"); incoming.Dump(); } // Merge the two. ExposureState newState = ExposureState.Join((ExposureState)atMerge, (ExposureState)incoming, joinPoint); if (newState != null) { if (Analyzer.Debug) { Console.WriteLine("\n Merged State"); newState.Dump(); } resultDiffersFromPreviousMerge = true; return(newState); } if (Analyzer.Debug) { Console.WriteLine("Merged state same as old."); } resultDiffersFromPreviousMerge = false; return(atMerge); }
protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) { //if (IsInstrumentationCode(block)) // return stateOnEntry; return(base.VisitBlock(block, stateOnEntry)); }
/// <summary> /// Splits the exceptions into the ones that this handler will handle and the ones that should /// <code>currentHandlerState</code> and <code>nextHandlerState</code> cannot both be null. /// On exit, if <code>currentHandlerState</code> is null, <code>handler</code> handles no exceptions, /// and if <code>nextHandlerState</code> is null, <code>handler</code> handles all the exceptions in /// the initial exception set of <code>currentHandlerState</code>. /// </summary> // go on to the next handler. currentHandlerState and next protected abstract void SplitExceptions( CfgBlock handler, ref IDataFlowState currentHandlerState, out IDataFlowState nextHandlerState );
/// <summary> /// Default per statement visitor called from the default VisitBlock. /// Does identity transformation. Subclasses either override this method /// if the default block handling is sufficient, or they override the Visit method for blocks. /// /// The result of this method is used as the state for all normal control flow successors. /// To push state onto an exception handler, use the PushExceptionState method. Furthermore, for /// conditional branches, different states can be pushed onto the true and false branches directly /// by calling PushPending. In that case, null should be returned from the method in order to avoid pushing /// the returned state onto both true and false targets again. /// </summary> protected virtual IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { // simple case analysis to distinguish throws switch (statement.NodeType) { case NodeType.Throw: case NodeType.Rethrow: { PushExceptionState(block, dfstate); return(null); } default: return(dfstate); } }
/// <summary> /// It visits an individual statement. It is called from VisitBlock. /// /// It calls NonNullInstructionVisitor /// </summary> /// <param name="block"></param> /// <param name="statement"></param> /// <param name="dfstate"></param> /// <returns></returns> protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { // For debug purpose if (Analyzer.Debug) { try{ Analyzer.WriteLine("\n:::"+new SampleInstructionVisitor().Visit(statement,null)+" ::: " +statement.SourceContext.SourceText); }catch(Exception e){ Analyzer.WriteLine("Print error: "+statement+": "+e.Message); } } IDataFlowState result=null; try{ result =(IDataFlowState)(iVisitor.Visit(statement,dfstate)); }catch(Exception e){ typeSystem.HandleError(statement,Cci.Error.InternalCompilerError,":NonNull:"+e.Message); Console.WriteLine(e.StackTrace); } if (result != null && Analyzer.Debug){ result.Dump(); } return result; }
/// <summary> /// Implementation of visit Block. It is called from run. /// /// It calls VisitStatement. /// </summary> /// <param name="block"></param> /// <param name="stateOnEntry"></param> /// <returns></returns> protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) { Debug.Assert(block!=null); currBlock=block; Analyzer.Write("---------block: "+block.UniqueId+";"); Analyzer.Write(" Exit:"); foreach (CfgBlock b in block.NormalSuccessors) Analyzer.Write(b.UniqueId+";"); if (block.UniqueSuccessor!=null) Analyzer.Write(" FallThrough: "+block.UniqueSuccessor+";"); if (block.ExceptionHandler!=null) Analyzer.Write(" ExHandler: "+block.ExceptionHandler.UniqueId+";"); Analyzer.WriteLine(""); ExposureState newState; if(stateOnEntry==null) newState=new ExposureState(typeSystem); else newState=new ExposureState((ExposureState)stateOnEntry); // if (block.ExceptionHandler!=null) // this.PushExceptionState(block,newState); return base.VisitBlock (block, newState); }
/// <summary> /// Merge the two states for current block. /// </summary> /// <param name="previous"></param> /// <param name="joinPoint"></param> /// <param name="atMerge"></param> /// <param name="incoming"></param> /// <param name="resultDiffersFromPreviousMerge"></param> /// <param name="mergeIsPrecise"></param> /// <returns></returns> protected override IDataFlowState Merge(CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise) { mergeIsPrecise = false; // No new states; if(incoming==null) { resultDiffersFromPreviousMerge = false; return atMerge; } // Initialize states if(atMerge==null){ resultDiffersFromPreviousMerge = true; return incoming; } if (Analyzer.Debug) { Console.WriteLine("Merge at Block {0}-----------------", (joinPoint).UniqueKey); Console.WriteLine(" State at merge"); atMerge.Dump(); Console.WriteLine(" Incoming"); incoming.Dump(); } // Merge the two. ExposureState newState = ExposureState.Join((ExposureState)atMerge, (ExposureState)incoming, joinPoint); if (newState != null) { if (Analyzer.Debug) { Console.WriteLine("\n Merged State"); newState.Dump(); } resultDiffersFromPreviousMerge = true; return newState; } if (Analyzer.Debug) { Console.WriteLine("Merged state same as old."); } resultDiffersFromPreviousMerge = false; return atMerge; }
private void SetPendingState (CfgBlock block, IDataFlowState pending) { pendingStates[block.Index] = pending; if (Tracing) { Console.WriteLine("SetPendingState: block {0}", (block).UniqueKey); } }
/// <summary> /// Splits the exceptions into the ones that this handler will handle and the ones that should /// <code>currentHandlerState</code> and <code>nextHandlerState</code> cannot both be null. /// On exit, if <code>currentHandlerState</code> is null, <code>handler</code> handles no exceptions, /// and if <code>nextHandlerState</code> is null, <code>handler</code> handles all the exceptions in /// the initial exception set of <code>currentHandlerState</code>. /// </summary> // go on to the next handler. currentHandlerState and next protected abstract void SplitExceptions ( CfgBlock handler, ref IDataFlowState currentHandlerState, out IDataFlowState nextHandlerState );
/// <summary> /// Compute the join of two data flow states at the given block. /// </summary> /// <param name="previous">Predecessor block for this new state</param> /// <param name="joinPoint">Block at which join is computed</param> /// <param name="atMerge">Old state at this block. Can be null, in which case the incoming state /// is the first non-bottom state. In this case, the method must set changed /// <c>resultDiffersFromPreviousMerge</c> to true.</param> /// <param name="incoming">New data flow state flowing to this block.</param> /// <param name="resultDiffersFromPreviousMerge">Boolean for fix point. If the state after /// the merge is equal to the old <c>atMerge</c> state, set to false, otherwise set to true.</param> /// <param name="mergeIsPrecise">can be set to true if the merged result state strictly contains only /// information representing either the atMerge or the incoming state, but no extra approximation. If /// this information cannot be determined by the merge, it must return false. True can only be returned /// if result is truly precise.</param> /// <returns>The new merged state.</returns> protected abstract IDataFlowState Merge ( CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise );
/// <summary> /// Default per statement visitor called from the default VisitBlock. /// Does identity transformation. Subclasses either override this method /// if the default block handling is sufficient, or they override the Visit method for blocks. /// /// The result of this method is used as the state for all normal control flow successors. /// To push state onto an exception handler, use the PushExceptionState method. Furthermore, for /// conditional branches, different states can be pushed onto the true and false branches directly /// by calling PushPending. In that case, null should be returned from the method in order to avoid pushing /// the returned state onto both true and false targets again. /// </summary> protected virtual IDataFlowState VisitStatement (CfgBlock block, Statement statement, IDataFlowState dfstate) { // simple case analysis to distinguish throws switch (statement.NodeType) { case NodeType.Throw: case NodeType.Rethrow: { PushExceptionState(block, dfstate); return null; } default: return dfstate; } }
/// <summary> /// Default per block visitor. Called from Run. /// /// It calls VisitStatement on each statement in a block. /// /// The result of this method is used as the state for all normal control flow successors. /// To push state onto an exception handler, use the PushExceptionState method. Furthermore, for /// conditional branches, different states can be pushed onto the true and false branches directly /// by calling PushPending. In that case, null should be returned from the method in order to avoid pushing /// the returned state onto both true and false targets again. /// </summary> protected virtual IDataFlowState VisitBlock (CfgBlock block, IDataFlowState stateOnEntry) { IDataFlowState currentState = stateOnEntry; for (int i=0; i<block.Length; i++) { if (currentState == null) return null; currentState = this.VisitStatement(block, (Statement)block[i], currentState); } return currentState; }
/// <summary> /// Merge two cState /// </summary> /// <param name="previous"></param> /// <param name="joinPoint"></param> /// <param name="atMerge"></param> /// <param name="incoming"></param> /// <param name="resultDiffersFromPreviousMerge"></param> /// <param name="mergeIsPrecise"></param> /// <returns></returns> protected override IDataFlowState Merge(CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise) { resultDiffersFromPreviousMerge = false; mergeIsPrecise = false; // No new states; if (incoming == null) return atMerge; // Initialize states if (atMerge == null) { resultDiffersFromPreviousMerge = true; return incoming; } //if (((PointsToState )atMerge).Equals(incoming)) // return atMerge; if (((PointsToState)atMerge).Includes((PointsToState)incoming)) return atMerge; // Merge the two. PointsToState newState = ((PointsToState)atMerge).Copy(); newState.Join((PointsToState)incoming); //if( newState.Method.FullName.StartsWith("System.Runtime.Remoting.Lifetime.Lease.ProcessNextSponsor")) //{ // PointsToState oldResult = (PointsToState)incoming; // PointsToState newResult = newState; // Console.Out.WriteLine("DIFERENCE a vs b"); // oldResult.PointsToGraph.DumpDifference(newResult.PointsToGraph); // Console.Out.WriteLine("DIFERENCE b vs a"); // newResult.PointsToGraph.DumpDifference(oldResult.PointsToGraph); //} resultDiffersFromPreviousMerge = true; return newState; }
/// <summary> /// It split exceptions for current handler and the next chained handler. /// /// It will: /// /// If the exception is completely intercepted by current handler, the /// exception will be consumed. /// /// If the exception caught but not completely, both current handler and /// the next handler will take the states. /// /// If the exception is irrelevant to current caught, the next handler /// will take over the state. Current handler is then bypassed. /// </summary> /// <param name="handler"></param> /// <param name="currentHandlerState"></param> /// <param name="nextHandlerState"></param> protected override void SplitExceptions(CfgBlock handler, ref IDataFlowState currentHandlerState, out IDataFlowState nextHandlerState) { Debug.Assert(currentHandlerState!=null,"Internal error in NonNull Analysis"); ExposureState state = (ExposureState)currentHandlerState; if(handler==null || handler.Length==0){ nextHandlerState=null; return; } if(handler[0] is Unwind){ nextHandlerState=null; currentHandlerState=null; return; } Debug.Assert(handler[0] is Catch, "Exception Handler does not starts with Catch"); Debug.Assert(state.currentException!=null,"No current exception to handle"); Catch c=(Catch)handler[0]; if(handler.ExceptionHandler!=null && !state.currentException.IsAssignableTo(c.Type)) { nextHandlerState = state;; } else { nextHandlerState=null; } // Compute what trickles through to the next handler // and what sticks to this handler. if(state.currentException.IsAssignableTo(c.Type)) { // everything sticks nextHandlerState = null; } else if (c.Type.IsAssignableTo(state.currentException)) { // c sticks, rest goes to next handler nextHandlerState = state; // copy state to modify the currentException state = new ExposureState(state); state.currentException = c.Type; currentHandlerState = state; }else { // nothing stick all goes to next handler nextHandlerState = state; currentHandlerState = null; } return; }
/// <summary> /// Visit the statement. It calls the instruction visitor to perform the transfer function /// </summary> /// <param name="block"></param> /// <param name="statement"></param> /// <param name="dfstate"></param> /// <returns></returns> protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { if (PointsToAnalysis.debug) { Console.Out.WriteLine("Before: {0} ({1}) {2}", CodePrinter.StatementToString(statement), statement.SourceContext.StartLine, statement.GetType()); dfstate.Dump(); } PointsToState currentState = dfstate as PointsToState; /* if (PointsToAnalysis.IsCompilerGenerated(currentState.Method)) if (!this.pointsToStateAnalysys.enclosingState.ContainsKey(currentState.Method.DeclaringType)) return currentState; */ if (PointsToAnalysis.verbose) { iterationsCounter++; if (iterationsCounter % 5000 == 0) { Console.Out.WriteLine("Counter: {3} {4} {0} ({1}) {2}", CodePrinter.StatementToString(statement), statement.SourceContext.StartLine, statement.GetType(), iterationsCounter, currentState.Method.FullName); dfstate.Dump(); } } //if (CodePrinter.StatementToString(statement).Contains("return value := this.f")) // System.Diagnostics.Debugger.Break(); IDataFlowState result = (IDataFlowState)currentState; // For Debug... if (currentState.Method.Name.Name.Equals("Push")) { } // If there are too many calls to non analyzable methods // starts to ignore the statements // if (!pointsToStateAnalysys.BoogieMode || currentState.CallsToNonAnalyzable.Count < pointsToStateAnalysys.maxCallToNonAnalyzable) if (HasToVisit(currentState)) result = (IDataFlowState)(iVisitor.Visit(statement, dfstate)); if (PointsToAnalysis.debug) { Console.Out.WriteLine("After: {0} ({1})", CodePrinter.StatementToString(statement), statement.SourceContext.StartLine); dfstate.Dump(); } //return dfstate; return result; }
/// <summary> /// Merge the new pending state with the old pending states. /// </summary> /// <returns>merged pending state</returns> private IDataFlowState JoinWithPendingState (CfgBlock prev, CfgBlock block, IDataFlowState newState) { if (Tracing) { Console.WriteLine("JoinWithPendingState: block {0} -> {1}", (prev).UniqueKey, (block).UniqueKey); } IDataFlowState pending = PendingState(block); // note, we call Merge even if old is null. bool changed; bool precise; if (Tracing) { SourceContext sc = (block).SourceContext; if (sc.Document == null && block.Length > 0) { sc = ((Statement)block[0]).SourceContext; } Console.WriteLine("Join with pending state at line {0}", sc.StartLine); } IDataFlowState merged = this.Merge(prev, block, pending, newState, out changed, out precise); if (Tracing) { Console.WriteLine("Join changed {0}", changed); } return merged; }
// Visit the block in the CFG protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) { IDataFlowState resultState = stateOnEntry; Debug.Assert(block != null); currBlock = block; Analyzer.Write("---------block: " + block.UniqueId + ";"); Analyzer.Write(" Exit:"); foreach (CfgBlock b in block.NormalSuccessors) Analyzer.Write(b.UniqueId + ";"); if (block.UniqueSuccessor != null) Analyzer.Write(" FallThrough: " + block.UniqueSuccessor + ";"); if (block.ExceptionHandler != null) Analyzer.Write(" ExHandler: " + block.ExceptionHandler.UniqueId + ";"); Analyzer.WriteLine(""); PointsToState newState = ((PointsToState)stateOnEntry).Copy(); // If there are too many calls to non analyzable methods // starts to ignore the statements //if (!pointsToStateAnalysys.BoogieMode || // newState.CallsToNonAnalyzable.Count < pointsToStateAnalysys.maxCallToNonAnalyzable) if (HasToVisit(newState)) { if (block.ExceptionHandler != null) this.PushExceptionState(block, newState); resultState = base.VisitBlock(block, newState); } if (block.UniqueId == cfg.NormalExit.UniqueId) { exitState = resultState; } if (block.UniqueId == cfg.ExceptionExit.UniqueId) { exitState = resultState; } return resultState; }
/// <summary> /// Record the incoming status's sets of created and committed NN Arrays. /// </summary> /// <param name="block"></param> /// <param name="statement"></param> /// <param name="dfstate"></param> /// <returns></returns> protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { //IDataFlowState result = base.VisitStatement(block, statement, dfstate); table[statement.UniqueKey] = (dfstate as NNArrayStatus).CreatedButNotInitedArrays(); tableCommitted[statement.UniqueKey] = (dfstate as NNArrayStatus).CommittedArrays(); IDataFlowState result = null; //try { result = (IDataFlowState)(iVisitor.Visit(statement, dfstate)); if (Analyzer.Debug && result != null) { result.Dump(); } //} //catch (Exception e) { // this.TypeSystem.HandleError(statement, Error.InternalCompilerError, "NNArray Pre Analysis " + e.Message); //} return result; }
protected override IDataFlowState Merge(CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise) { if (nonNullInfo != null) { INonNullState nns = nonNullInfo.OnEdge(previous, joinPoint); if (nns == null && atMerge != null) { incoming = null; } } return(base.Merge(previous, joinPoint, atMerge, incoming, out resultDiffersFromPreviousMerge, out mergeIsPrecise)); }
/// <summary> /// Push the given state onto the handler of the block. /// This causes call-backs to SplitException in order to correctly distribute /// the exception state among different nested handlers. /// </summary> /// <param name="currentBlock">Block from which exception escapes</param> /// <param name="state">state on exception flow</param> public void PushExceptionState ( CfgBlock currentBlock, IDataFlowState state ) { IDataFlowState currentHandlerState = state; CfgBlock currentHandler = currentBlock; IDataFlowState nextHandlerState; while (currentHandlerState != null) { Debug.Assert(currentHandler.ExceptionHandler != null, String.Format("block {0} does not have an exception handler", (currentHandler).UniqueKey)); currentHandler = currentHandler.ExceptionHandler; if (Tracing) { Console.WriteLine("PushExceptionState (in loop): block {0} -> {1}", (currentBlock).UniqueKey, (currentHandler).UniqueKey); } SplitExceptions(currentHandler, ref currentHandlerState, out nextHandlerState); /// We allow SplitExceptions to make decisions about not propagating any exceptions /// Debug.Assert(currentHandlerState != null || nextHandlerState != null); if (currentHandlerState != null) { PushState(currentBlock, currentHandler, currentHandlerState); } currentHandlerState = nextHandlerState; } }
/// <summary> /// Starts the analysis from the entry block of the CFG /// </summary> protected virtual void Run(ControlFlowGraph cfg, IDataFlowState startState) { this.Run(cfg, cfg.Entry, startState); }
protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { // For debug purpose if (Analyzer.Debug) { try { Analyzer.WriteLine(new SampleInstructionVisitor().Visit(statement, null) + " ::: " + statement.SourceContext.SourceText); } catch (Exception) { Analyzer.WriteLine("Print error: " + statement); } } IDataFlowState result=null; try{ result =(IDataFlowState)(iVisitor.Visit(statement,dfstate)); if (Analyzer.Debug && result != null) { result.Dump(); } }catch(Exception e){ typeSystem.HandleError(statement,Error.InternalCompilerError,"Definite Assignement: "+e.Message); } return result; }
/// <summary> /// Merge two PtWe /// </summary> /// <param name="previous"></param> /// <param name="joinPoint"></param> /// <param name="atMerge"></param> /// <param name="incoming"></param> /// <param name="resultDiffersFromPreviousMerge"></param> /// <param name="mergeIsPrecise"></param> /// <returns></returns> protected override IDataFlowState Merge(CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise) { return base.Merge(previous,joinPoint,atMerge,incoming,out resultDiffersFromPreviousMerge, out mergeIsPrecise); }
protected override void Run(ControlFlowGraph cfg, IDataFlowState startState) { base.Run(cfg, startState); }
protected override void SplitExceptions(CfgBlock handler, ref IDataFlowState currentHandlerState, out IDataFlowState nextHandlerState) { nextHandlerState = null; }
/// <summary> /// Starts the analysis from the entry block of the CFG /// </summary> protected virtual void Run (ControlFlowGraph cfg, IDataFlowState startState) { this.Run(cfg, cfg.Entry, startState); }
/// <summary> /// Visit the statement. It calls the instruction visitor to perform the transfer function /// </summary> /// <param name="block"></param> /// <param name="statement"></param> /// <param name="dfstate"></param> /// <returns></returns> protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { IDataFlowState result = (IDataFlowState)(iVisitor.Visit(statement, dfstate)); return(result); }
/// <summary> /// Add the given state to the pending states of the target block. If /// the block is enabled (by the pending edge count optimization), add the /// block to the worklist. /// /// Inv: DoneState => PendingState /\ PendingState != null => InQueue /// /// Cases: /// 1. Done => new, nothing to do /// 2. Done |_| new is precise. Pend' = Pend |_| new, Done' = Done |_| new /// 3. Done |_| new is imprecise. Pend' = Done |_| new, Done' = Done |_| new /// </summary> public void PushState ( CfgBlock currentBlock, CfgBlock nextBlock, IDataFlowState state ) { if (Tracing) { Console.WriteLine("PushState: block {0} -> {1}", (currentBlock).UniqueKey, (nextBlock).UniqueKey); } // state == null signals that branch is infeasible if (state == null) { return; } bool precise; // Add state to done state IDataFlowState stillPending = this.StateToReanalyzeBlock(currentBlock, nextBlock, state, out precise); if (stillPending == null) { if (Tracing) { Console.WriteLine("PushState: block {0} no new information for pending state.", (nextBlock).UniqueKey); } return; } if (precise) { // join stillPending to old pending. stillPending = this.JoinWithPendingState(currentBlock, nextBlock, stillPending); } this.SetPendingState (nextBlock, stillPending); // when dequeued, the pending state is what the block needs to be analyzed under. // joinWorkItems.Enqueue(nextBlock); if (Tracing) { Console.WriteLine("PushState: block {0} put on work queue.", (nextBlock).UniqueKey); } }
/// <summary> /// merge the two state atMerge and incoming. /// </summary> /// <param name="previous"></param> /// <param name="joinPoint"></param> /// <param name="atMerge"></param> /// <param name="incoming"></param> /// <param name="resultDiffersFromPreviousMerge"></param> /// <param name="mergeIsPrecise"></param> /// <returns></returns> protected override IDataFlowState Merge(CfgBlock previous, CfgBlock joinPoint, IDataFlowState atMerge, IDataFlowState incoming, out bool resultDiffersFromPreviousMerge, out bool mergeIsPrecise) { resultDiffersFromPreviousMerge = false; mergeIsPrecise = false; // No new states; if (incoming == null) return atMerge; // Initialize states if (atMerge == null) { resultDiffersFromPreviousMerge = true; // //((NNArrayStatus)incoming).FilterStackAndTemporaryLocals(joinPoint.StackDepth); return incoming; } if (Analyzer.Debug ) { Console.WriteLine("Array Reachable Def merge at block {0}", (joinPoint).UniqueKey); Console.WriteLine("atMerge:\n---------"); atMerge.Dump(); Console.WriteLine("incoming:\n---------"); incoming.Dump(); } // Merge the two. NNArrayStatus newState = NNArrayStatus.Merge((NNArrayStatus)atMerge, (NNArrayStatus)incoming, joinPoint); if (newState == null) { if (Analyzer.Debug) { Console.WriteLine("result UNchanged"); } return atMerge; } resultDiffersFromPreviousMerge = true; if (Analyzer.Debug) { Console.WriteLine("Result of merge\n---------"); newState.Dump(); } return newState; }
// Exception management internal void PushExceptionWrapper(IDataFlowState state) { this.PushExceptionState(currBlock, state); }
protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState state) { Debug.Assert(block != null); NNArrayStatus onEntry = (NNArrayStatus)state; currBlock = block; if (Analyzer.Debug) { Analyzer.Write("---------block: " + block.UniqueId + ";"); Analyzer.Write(" Exit:"); foreach (CfgBlock b in block.NormalSuccessors) Analyzer.Write(b.UniqueId + ";"); if (block.UniqueSuccessor != null) Analyzer.Write(" FallThrough: " + block.UniqueSuccessor + ";"); if (block.ExceptionHandler != null) Analyzer.Write(" ExHandler: " + block.ExceptionHandler.UniqueId + ";"); Analyzer.WriteLine(""); state.Dump(); } if (block.ExceptionHandler != null) { NNArrayStatus exnState = onEntry; onEntry = new NNArrayStatus(onEntry); // Copy state, since common ancestor cannot be modified any longer PushExceptionState(block, exnState); } NNArrayStatus resultState = (NNArrayStatus)base.VisitBlock(block, onEntry); if (block.UniqueId == cfg.NormalExit.UniqueId) { exitState = resultState; } if (resultState == null) { return null; } return new NNArrayStatus(resultState); }
/// <summary> /// Checks if a block needs to be reanalyzed and under what state. /// /// Updates the doneState of this block to reflect the pending state /// </summary> /// <returns>null if no reanalysis necessary, the DFS state if the merge is precise, /// the merged state if the merge is imprecise /// </returns> private IDataFlowState StateToReanalyzeBlock (CfgBlock prev, CfgBlock block, IDataFlowState pending, out bool preciseMerge) { IDataFlowState done = DoneState(block); // note, we call Merge even if old is null. bool changed; if (Tracing) { Console.WriteLine("StateToReanalyzeBlock: block {0} -> {1}", (prev).UniqueKey, (block).UniqueKey); SourceContext sc = (block).SourceContext; if (sc.Document == null && block.Length > 0) { sc = ((Statement)block[0]).SourceContext; } Console.WriteLine("StateToReanalyzeBlock at line {0}", sc.StartLine); } IDataFlowState merged = this.Merge(prev, block, done, pending, out changed, out preciseMerge); if (merged != null) doneStates[block.Index] = merged; if ( ! changed ) { if (Tracing) { Console.WriteLine("Done State"); done.Dump(); Console.WriteLine("Pending State"); pending.Dump(); Console.WriteLine("StateToReanalyzeBlock result UNchanged"); } return null; } if ( preciseMerge ) return pending; if (Tracing) { Console.WriteLine("StateToReanalyzeBlock result CHANGED"); if (done == null) { Console.WriteLine("no done state yet"); } else { Console.WriteLine("Done State"); done.Dump(); } Console.WriteLine("Pending State"); pending.Dump(); Console.WriteLine("Merged State"); merged.Dump(); } return merged; }
protected override void SplitExceptions(CfgBlock handler, ref IDataFlowState currentHandlerState, out IDataFlowState nextHandlerState) { nextHandlerState = null; return; }
/// <summary> /// Checks if a block needs to be reanalyzed and under what state. /// /// Updates the doneState of this block to reflect the pending state /// </summary> /// <returns>null if no reanalysis necessary, the DFS state if the merge is precise, /// the merged state if the merge is imprecise /// </returns> private IDataFlowState StateToReanalyzeBlock(CfgBlock prev, CfgBlock block, IDataFlowState pending, out bool preciseMerge) { IDataFlowState done = DoneState(block); // note, we call Merge even if old is null. bool changed; if (Tracing) { Console.WriteLine("StateToReanalyzeBlock: block {0} -> {1}", (prev).UniqueKey, (block).UniqueKey); SourceContext sc = (block).SourceContext; if (sc.Document == null && block.Length > 0) { sc = ((Statement)block[0]).SourceContext; } Console.WriteLine("StateToReanalyzeBlock at line {0}", sc.StartLine); } IDataFlowState merged = this.Merge(prev, block, done, pending, out changed, out preciseMerge); if (merged != null) { doneStates[block.Index] = merged; } if (!changed) { if (Tracing) { Console.WriteLine("Done State"); done.Dump(); Console.WriteLine("Pending State"); pending.Dump(); Console.WriteLine("StateToReanalyzeBlock result UNchanged"); } return(null); } if (preciseMerge) { return(pending); } if (Tracing) { Console.WriteLine("StateToReanalyzeBlock result CHANGED"); if (done == null) { Console.WriteLine("no done state yet"); } else { Console.WriteLine("Done State"); done.Dump(); } Console.WriteLine("Pending State"); pending.Dump(); Console.WriteLine("Merged State"); merged.Dump(); } return(merged); }