Exemplo n.º 1
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
    }
Exemplo n.º 2
0
 public AvoidClosure (FinallyBlockDuplicator parent, ExceptionHandler eh) {
   this.parent          = parent;
   this.orig_hdlr_start = (int) parent.b2index[eh.HandlerStartBlock];
   this.orig_hdlr_end   = (int) parent.b2index[eh.BlockAfterHandlerEnd] - 1;
 }