/// <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;
    }
Esempio n. 2
0
		public IStronglyConnectedComponent SccForBlock (CfgBlock block)
		{
			if (this.sccMap == null)
			{
				this.sccMap = new Hashtable();
				foreach (StronglyConnectedComponent/*<CfgBlock>*/ scc in this.sccs)
				{
					foreach (CfgBlock iblock in scc.Nodes)
					{
						this.sccMap[iblock] = scc;
					}
				}
			}
			return (StronglyConnectedComponent) this.sccMap[(block)];
		}
 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 Cci.Block ConvertBlock (CfgBlock block) { return (block); }
    /// <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>
    /// 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;
    }
 private IDataFlowState PendingState (CfgBlock block) 
 {
   return(pendingStates[block.Index]);
 }
Esempio n. 9
0
 public SwitchContinuation(BlockList targets, CfgBlock defaulttarget) {
   this.targets = targets;
   this.defaulttarget = defaulttarget;
 }
 private IDataFlowState DoneState (CfgBlock block) 
 {
   return(doneStates[block.Index]);
 }
 /// <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
   );
Esempio n. 12
0
		/// <summary>
		/// Invariant: whenever during the traversal, we find that we need to start a new block
		/// (because we reach a block that could be the target of a branch),
		/// we have to take the new_stats StatementList and if non-empty, create a new block from it
		/// and put it onto the new_blocks list. new_stats is then initialized with a new empty list.
		/// 
		/// We also have to update the orig2newblock map, using the current_oldBlock as the key and the
		/// newly created block as the target. If we update the map, we null out the current_oldBlock.
		/// </summary>
		private void EndStatementList() 
		{
			if (this.new_stats.Count != 0) 
			{
				// create block from statements
				CfgBlock b = new CfgBlock(this.new_stats);

				// add block to block list
				this.new_blocks.Add(b);

				// create new statement list for upcoming statements
				this.new_stats = new StatementList();

				// update map
				UpdateBlockMap(ref this.current_oldBlock, b);
			}
		}
Esempio n. 13
0
		/// <summary>
		/// Can be called to recursively flatten a block from the following places:
		/// 1. From within a block on a nested block
		/// 2. From within a BlockExpression
		/// 3. From the top-level method body block
		/// 
		/// Because of 2 and 3, we may have a pending list of statements in new_stats that belong
		/// to the previous block. Thus we first need to end that block, then start the new one.
		/// 
		/// Furthermore, since the old block could be a branch target, we also must update the 
		/// orig2newBlock map once we generated the first block within this flattening.
		/// 
		/// Every block expansion starts with a call to FlattenBlock
		///  The FlattenBlock stack activation frame keeps track of the prior current_oldBlock 
		///  and stores the new current oldBlock.
		///  At the end of FlattenBlock, the prior_oldBlock is mapped to the same new block
		///  as the oldBlock on which FlattenBlock was called.
		///  
		///  POST: this.current_oldBlock == null.
		/// </summary>
		/// <param name="block"></param>
		private void FlattenBlock (Block block) 
		{
			// This definitely starts a new block. If the statement list contains any statements, 
			// finish that block.
			EndStatementList();

			// stack the prior oldBlock (this must be done AFTER we call EndStatementList !)
			Block prior_oldBlock = this.current_oldBlock;

			// set the block we are processing as the current old block
			this.current_oldBlock = block;

      StatementList sl = block.Statements;

			// we deal with an empty block on exit of this method.
			try 
			{
				if (sl != null) 
				{
					for (int i = 0; i<sl.Count; i++)
					{
						Statement stmt = sl[i];

            if (stmt == null) continue;

						Block nested = stmt as Block;

						if (nested != null) 
						{
							FlattenBlock(nested);
						}
						else 
						{
							// Statement to be added to current statement sequence.
							Statement newstat = (Statement)this.Visit(stmt);
              if (newstat != null) {
                // null indicates statement was omitted (e.g. branch false)
                if (newstat.SourceContext.Document == null){
                  // MB: Guarantee that every statement coming out of flattener has some kind of source context
                  // REVIEW: It is possible that if newstat happens to be shared (i.e., *not* a copy)
                  // then this will cause more sequence points to be defined in the PDB file than otherwise
                  // which could degrade the debugging experience.
                  newstat.SourceContext = this.current_source_context;
                }
                this.new_stats.Add(newstat);
                if (StatementEndsBlock(newstat)) {
                  EndStatementList();
                }
              }
						}
					} // end for
				} // end if sl != null
			}
			finally 
			{
				// we have to do 2 things here:
				//
				// 1. end the block (there could be outstanding statements that need to be emitted)
				// 2. if we still have this.current_oldBlock != null, then the block contained no statements and we have to insert an empty block
				// 3. if prior_oldBlock is not null, we have to map it to the same new block as the block we processed in this call.
				//
				// The order of these operations is important! Because we side effect this.current_oldBlock and this.orig2newBlock map, these
				// steps CANNOT be reordered.

				// Do 1.
				EndStatementList(); 

				// Do 2. 
				if (this.current_oldBlock != null) {
					// Debug.Assert (sl == null || sl.Length == 0); // too strict. Fires if sl contains null statements.

					// create empty block
					CfgBlock newBlock = new CfgBlock(new StatementList(0));
					// add to block list
					this.new_blocks.Add(newBlock);
					// update map
					this.UpdateBlockMap(ref this.current_oldBlock, newBlock);
				}

				// Do 3.
				if (prior_oldBlock != null) 
				{
					CfgBlock newBlock = (CfgBlock) this.orig2newBlocks[block.UniqueKey];

					this.orig2newBlocks[prior_oldBlock.UniqueKey] = newBlock;
				}
			}
		}
Esempio n. 14
0
 public StraightContinuation (CfgBlock target) {
   this.target = target;
 }
Esempio n. 15
0
 internal StackElem(CfgBlock node) {
   this.node = node;
   this.nextChild = 0;
 }
Esempio n. 16
0
    /// <summary>
    /// CFG pretty-printer.  For each block, this method
    /// calls <c>pre_printer</c>c(if non-null),
    /// prints the normal/excp. successors,
    /// the code of the block, the normal/excp. predecessors and finally calls
    /// <c>post_printer</c>.  A useful use of the pre and post printers is the
    /// debugging of a flow-sensitive analysis.
    /// </summary>
    /// <param name="tw">Where to print.</param>
    public void Display(
      TextWriter tw, 
      CfgBlock[] blocks,
      DGetBlockInfo get_pre_block_info, 
      DGetBlockInfo get_post_block_info, 
      DGetStatInfo get_stat_info
      ) {
      Hashtable b2id = new Hashtable();
      for(int i = 0; i < blocks.Length; i++)
        b2id[blocks[i]] = i;
      for(int i = 0; i < blocks.Length; i++) {
        CfgBlock block = blocks[i];
        tw.WriteLine("BLOCK " + (block is ISpecialBlock ? "*" : "") + CodePrinter.b2s(block, b2id));
        if (get_pre_block_info != null)
          tw.WriteLine(get_pre_block_info(block));
        print_block_array(" Normal pred:      ", NormalPred(block), b2id, tw);
        print_block_array(" Protected blocks: ", ExcpPred(block), b2id, tw);
        if (ExcpPred(block).Length != 0) {
          ExceptionHandler eh = HandlerThatStartsAtBlock(block);
          if (eh != null)
            tw.WriteLine(" Handler {0} [{1},{2})",
              eh.HandlerType,
              CodePrinter.b2s(eh.HandlerStartBlock, b2id),
              CodePrinter.b2s(eh.BlockAfterHandlerEnd, b2id));
        }
        CodePrinter.PrintBlock(tw, block, get_stat_info, b2id);
        print_block_array(" Normal succ:      ", NormalSucc(block), b2id, tw);
        print_block_array(" Excp succ:        ", this.ExcpSucc(block), b2id, tw);
        print_block(" Handler:          ", ExceptionHandler(block), b2id, tw);
        print_block_list(" Finallies:        ", (FList)b2_enclosing_finally[block], b2id, tw);
        ExceptionHandler ceh = (ExceptionHandler)b2_containing_handler[block];
        if (ceh != null) print_block(" Containing handler", ceh.HandlerStartBlock, b2id, tw);

        if (get_post_block_info != null)
          tw.WriteLine(get_post_block_info(block));
        tw.WriteLine();
      }
      tw.WriteLine("Entry      = " + CodePrinter.b2s(Entry, b2id));
      tw.WriteLine("NormalExit = " + CodePrinter.b2s(NormalExit, b2id));
      tw.WriteLine("ExcptExit  = " + CodePrinter.b2s(ExceptionExit, b2id));
      tw.WriteLine("Exit       = " + CodePrinter.b2s(Exit, b2id));
    }
    /// <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 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>
 /// 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;
   }
 }
 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>
    /// 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;
    }
    /// <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;
    }
Esempio n. 24
0
 public IfContinuation(CfgBlock truetarget, CfgBlock falsetarget) {
   this.truetarget = truetarget;
   this.falsetarget = falsetarget;
 }
    /// <summary>
    /// Returns null, if result of Join is the same as atMerge.
    /// </summary>
    public static ExposureState Join(ExposureState atMerge, ExposureState incoming, CfgBlock joinPoint) {

      bool unchanged;
      IEGraph merged = atMerge.egraph.Join(incoming.egraph, joinPoint, out unchanged);

      TypeNode currentException = (atMerge.currentException != null)?
        ((incoming.currentException != null)? CciHelper.LeastCommonAncestor(atMerge.currentException, incoming.currentException) : null) : null;

      if (atMerge.currentException != currentException || !unchanged) {
        return new ExposureState(merged, currentException, atMerge.typeSystem);
      }
      return null;
    }
 public void Enqueue(CfgBlock b) 
 {
   this.Add(b);
 }
    /// <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>
    /// 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>
    /// 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;
      } 
    }