/// <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 }
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; }