Exemple #1
0
      public FinallyBlockDuplicator (
        ControlFlowGraph cfg, 
        Method method, 
        IList/*<Block>*/ new_blocks,
        Hashtable/*<Block,Block>*/ block2next, 
        NormalFlowBlockNavigator nfbnav,
        IList/*<ExceptionHandler>*/ all_ehs
        ) {
        this.dupVisitor = new DupVisitor(method.DeclaringType.DeclaringModule, method.DeclaringType);
        this.cfg        = cfg;
        this.method     = method;
        this.new_blocks = new_blocks;
        this.block2next = block2next;
        this.bnav       = new UnionGraphNavigator(nfbnav, new ControlFlowGraph.ExcpFlowBlockNavigator(cfg));
        this.allExceptionHandlers    = all_ehs;

        // init the block -> index map
        this.b2index = new Hashtable();
        StatementList blocks = method.Body.Statements;
        for(int i = 0; i < blocks.Count; i++) {
          b2index[(Block) blocks[i]] = i;
        }

        // init the exception handler -> last block map
        this.lastHandledBlock = new Hashtable();
        foreach (ExceptionHandler eh in this.allExceptionHandlers) {
          if (eh.HandlerType != NodeType.Finally && eh.HandlerType != NodeType.FaultHandler) { continue; } 
          this.lastHandledBlock[eh] = LastBlockInsideHandler(eh);
        }

        // 2. deal with the "leave" instructions
        TreatLeaveInstructions ();

        // 3. The original finally / fault handlers should be turned into catch handlers
        ConvertFinallyHandlerIntoCatchHandler();
      }
Exemple #2
0
 private HashSet/*<Block>*/ filter_blocks (Method method, NormalFlowBlockNavigator nfbnav) {
   HashSet/*<Block>*/ blocksToKill = new HashSet();
   /* We no longer remove the filter blocks.
   ExceptionHandlerList ehs = method.ExceptionHandlers;
   for (int i=0; i<ehs.Length; i++)
     if (ehs[i].HandlerType == NodeType.Filter)
       add_block_plus_succ_to_set(blocksToKill, ehs[i].FilterExpression, nfbnav);
   */
   return blocksToKill;
 }
Exemple #3
0
    /// <summary>
    /// Constructs the Control Flow Graph for <c>method</c>.
    /// If the code for <c>method</c> is unavailable, throw an <c>UnavailableCodeException</c>
    /// (a constructor cannot return an error code).  If the code for <c>method</c> is empty
    /// (abstract method), thrown a <c>NoCodeException</c>.  Otherwise, examine the CciHelper
    /// representation of the method code and construct the CFG.
    /// </summary>
    /// <param name="method">Method whose CFG will be constructed.</param>
    /// <param name="duplicateFinallyBlocks">If <c>true</c>, the finally blocks will be duplicated and you'll obtain a real
    /// CFG.  Otherwise, you'll have to manually deal with the finally blocks that are traversed by each
    /// "leave" instruction.  HIGHLY RECOMMENDED!</param>
    /// <param name="eliminateEvaluationStack">If <c>true</c>, <c>StackRemovalTransf.Process</c> will be called
    /// to remove the stack manipulating operations. See more commends in the class
    /// <c>StackRemovalTransf</c>. RECOMMENDED!</param>
    /// <param name="constantFoldBranches">When <c>true</c>, use constant folding 
    /// to prune infeasible branches.</param>
    public ControlFlowGraph (Method method, bool duplicateFinallyBlocks, bool eliminateEvaluationStack, bool expandAllocations, bool constantFoldBranches) {
      StatementList blocks = method.Body.Statements;
      if (blocks == null)
        throw new UnavailableCodeException(method);
      if (blocks.Count == 0)
        throw new NoCodeException(method);

      this.originalMethod = method; // Hold onto the original because MakeFlat modifies the method
      // COMMENT NEXT LINE IF YOU HAVE PROBLEMS!
      method = CodeFlattener.MakeFlat(method, expandAllocations, constantFoldBranches, out codeMap);
      this.method = method; // useful for debugging

      // reload blocks, since MakeFlat changed this.
      blocks = method.Body.Statements;


      //Console.WriteLine("Before removing last block...\n");
      //CodePrinter.PrintMethod(Console.Out, method);

      /*
      Block lastblock = (Block)blocks[blocks.Length-1];
      if (lastblock.Statements.Length==0) 
      {
        // dummy block, remove it.
        StatementList oldblocks = blocks;

        blocks = new StatementList(oldblocks.Length-1);
        for (int i=0;i<oldblocks.Length-1; i++) 
        {
          blocks.Add(oldblocks[i]);
        }
        method.Body.Statements = blocks;
      }
      */

      // Debug code with code printer.
      //Console.WriteLine("Before code flattening...\n");
      //CodePrinter.PrintMethod(Console.Out, method);

      CreateEntryAndExitBlocks(method, blocks);

      // 0. build map block2next that gives the fall-through successor of each block
      b2next = new Hashtable();
      for(int i = 0; i < blocks.Count-1; i++) {
        b2next[blocks[i]] = blocks[i+1];
      }
      // add fall through from special entry to real entry block
      b2next[this.Entry] = blocks[0];

      NormalFlowBlockNavigator nfbnav = new NormalFlowBlockNavigator(this, this.b2next);

      HashSet/*<Block>*/ filterblocks = filter_blocks(method,nfbnav);

      IList/*<ExceptionHandler>*/ all_ehs;
      // 1. for each block, find the array of relevant handlers
      // (order consistent with the order of the Exception Handlers)
      bool has_finally = BuildExceptionalFlow(method, blocks, out all_ehs, filterblocks); // SIDE EFFECT: build b2e_succ map

      IList new_blocks = new ArrayList();
      if (has_finally && duplicateFinallyBlocks) {
        // 2. eliminate finallies
        if (FINALLY_CLONE_DEBUG) {
          this.b2cloning_leave = new Hashtable();
        }

        FinallyBlockDuplicator fdc = new FinallyBlockDuplicator(this, method, new_blocks, this.b2next, nfbnav, all_ehs);

        if (FINALLY_CLONE_DEBUG) {
          this.copy2orig = fdc.copy2orig;
        }
      }

      // 3. add catch statements to all handlers
      AddCatchStatements(all_ehs, new_blocks);

      // 4. build the collection all_blocks;
      BuildAllBlockCollection(method, new_blocks, filterblocks, nfbnav);

      // 4a. fixup back jumps in handlers going to the handler head. They must go to the
      //     immediately succeeding block to skip the new "catch" instruction.
      FixupJumpsToHandlerHead();

      // 5. build the map block b -> blocks protected by the handler that starts at b;
      BuildHandlerPredecessorMap();

      // 6. build the normal flow
      BuildNormalFlow(all_blocks, nfbnav, (CfgBlock) blocks[0]);

      // 7. build continuation map
      BuildContinuationMap(all_blocks);

#if DEBUGxxx
      Console.WriteLine();
      Console.WriteLine("=================================================================");
      Console.WriteLine();
      this.Display(Console.Out);
#endif

      if (eliminateEvaluationStack) {
        // sets the stack depth of each block as a side effect.
        StackRemovalTransformation.Process(this);
      }

#if DEBUG_EXPENSIVE
			this.TestInvariants();
			this.Seal();
#endif
    }
Exemple #4
0
    private void BuildNormalFlow (
      CfgBlock[] blocks, 
      NormalFlowBlockNavigator nfbnav, 
      CfgBlock real_entry
      ) {
      IMutableRelation/*<Block,Block>*/ n_succ = new BlockRelation();

      foreach(Block block in blocks) {
        if (block is ISpecialBlock) continue;
        n_succ.AddAll(block, nfbnav.NextNodes(block));
      }
      // common sense rules
      n_succ.Add(entry_point, real_entry);
      n_succ.Add(normal_exit_point, exit_point);
      n_succ.Add(excp_exit_point, exit_point);

      IRelation/*<Block,Block>*/ n_pred = n_succ.Reverse();
      b2n_succ = Relation.Compact(n_succ, typeof(CfgBlock));
      b2n_pred = Relation.Compact(n_pred, typeof(CfgBlock));
    }
Exemple #5
0
    // build the array all_blocks: the original blocks + the block clones (if any) + special blocks
    private void BuildAllBlockCollection (
      Method method, 
      IList/*<CfgBlock>*/ new_blocks, 
      ISet/*<CfgBlock>*/ filterblocks,
      NormalFlowBlockNavigator nfnav
      ) {
      IMutableSet reach = new HashSet();
      FindReachable(reach, (CfgBlock)method.Body.Statements[0], nfnav);

      int nb_blocks = reach.Count + 2; // entry and exit
      if (!reach.Contains(this.normal_exit_point)) {
        nb_blocks++;
      }
      if (!reach.Contains(this.excp_exit_point)) {
        nb_blocks++;
      }

      CfgBlock[] all_blocks;
      this.all_blocks = all_blocks = new CfgBlock[nb_blocks];

      int index = 0;

      AddBlock(this.entry_point, all_blocks, ref index);

      foreach (CfgBlock block in reach) {
        AddBlock(block, all_blocks, ref index);
      }

#if false
      int nb_blocks = method.Body.Statements.Count - filterblocks.Count + 4;

      nb_blocks += new_blocks.Count;

      CfgBlock[] all_blocks;
      this.all_blocks = all_blocks = new CfgBlock[nb_blocks];
      StatementList blocks = method.Body.Statements;
      int index = 0;

      AddBlock(this.entry_point, all_blocks, ref index);
      for(int i = 0 ; i < blocks.Count; i++) {
        if ( ! filterblocks.Contains(blocks[i])) {
          AddBlock((CfgBlock)blocks[i], all_blocks, ref index);
        }
      }
      if (new_blocks != null) {
        // adding the block clones to all_blocks
        foreach(CfgBlock block in new_blocks) {
          AddBlock(block, all_blocks, ref index);
        }
      }
#endif

      // adding the three special blocks
      if (!reach.Contains(this.normal_exit_point)) {
        AddBlock(this.normal_exit_point, all_blocks, ref index);
      }
      if (!reach.Contains(this.excp_exit_point)) {
        AddBlock(this.excp_exit_point, all_blocks, ref index);
      }
      AddBlock(this.exit_point, all_blocks, ref index);
    }
Exemple #6
0
 private void FindReachable(IMutableSet reach, CfgBlock current, NormalFlowBlockNavigator nfnav) {
   if (reach.Contains(current)) return;
   reach.Add(current);
   foreach (CfgBlock next in nfnav.NextNodes(current)) {
     FindReachable(reach, next, nfnav);
   }
   // also follow exceptional path
   CfgBlock handler = (CfgBlock)this.b2exception_handler[current];
   if (handler != null) {
     FindReachable(reach, handler, nfnav);
   }
 }