예제 #1
0
        public static FlowGraph Create(MethodIL il)
        {
            HashSet <int> bbStarts = GetBasicBlockStarts(il);

            List <BasicBlock> bbs = new List <BasicBlock>();

            void AddBB(int start, int count)
            {
                if (count > 0)
                {
                    bbs.Add(new BasicBlock(start, count));
                }
            }

            int prevStart = 0;

            foreach (int ofs in bbStarts.OrderBy(o => o))
            {
                AddBB(prevStart, ofs - prevStart);
                prevStart = ofs;
            }

            AddBB(prevStart, il.GetILBytes().Length - prevStart);

            FlowGraph fg = new FlowGraph(bbs);

            // We know where each basic block starts now. Proceed by linking them together.
            ILReader reader = new ILReader(il.GetILBytes());

            foreach (BasicBlock bb in bbs)
            {
                reader.Seek(bb.Start);
                while (reader.HasNext)
                {
                    Debug.Assert(fg.Lookup(reader.Offset) == bb);
                    ILOpcode opc = reader.ReadILOpcode();
                    if (opc.IsBranch())
                    {
                        int tar = reader.ReadBranchDestination(opc);
                        bb.Targets.Add(fg.Lookup(tar));
                        if (!opc.IsUnconditionalBranch())
                        {
                            bb.Targets.Add(fg.Lookup(reader.Offset));
                        }

                        break;
                    }

                    if (opc == ILOpcode.switch_)
                    {
                        uint numCases = reader.ReadILUInt32();
                        int  jmpBase  = reader.Offset + checked ((int)(numCases * 4));
                        bb.Targets.Add(fg.Lookup(jmpBase));

                        for (uint i = 0; i < numCases; i++)
                        {
                            int caseOfs = jmpBase + (int)reader.ReadILUInt32();
                            bb.Targets.Add(fg.Lookup(caseOfs));
                        }

                        break;
                    }

                    if (opc == ILOpcode.ret || opc == ILOpcode.endfinally || opc == ILOpcode.endfilter || opc == ILOpcode.throw_ || opc == ILOpcode.rethrow)
                    {
                        break;
                    }

                    reader.Skip(opc);
                    // Check fall through
                    if (reader.HasNext)
                    {
                        BasicBlock nextBB = fg.Lookup(reader.Offset);
                        if (nextBB != bb)
                        {
                            // Falling through
                            bb.Targets.Add(nextBB);
                            break;
                        }
                    }
                }
            }

            foreach (BasicBlock bb in bbs)
            {
                foreach (BasicBlock tar in bb.Targets)
                {
                    tar.Sources.Add(bb);
                }
            }

            return(fg);
        }