Пример #1
0
 private void BreakReduceLeaveCatch(BasicBlock root, BBLoop loop, BasicBlock breakTarget, LeaveCatchBasicBlock leavebb, Seq<BasicBlock> removed, Seq<BasicBlock> added)
 {
     if (leavebb.Target.Equals(breakTarget))
     {
         var instructions = leavebb.Block.CopyContents();
         var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Break, loop.Label)
                       { BeforeState = leavebb.Block.AfterState, AfterState = leavebb.Block.AfterState };
         instructions.Add(lci);
         var newbb = new NonReturningBasicBlock(nextBlockId++, new Instructions(leavebb.Block.BeforeState, instructions));
         root.Coalesce(leavebb, new Set<BasicBlock> { leavebb }, newbb);
         removed.Add(leavebb);
         added.Add(newbb);
     }
 }
Пример #2
0
        private BasicBlock BasicBlockFromIndex(int start, Context context)
        {
            if (start >= context.Block.Count)
                throw new InvalidOperationException("run off of end of instructions");

            var offset = context.Block[start].Offset;
            var i = start;

            Func<int, Instructions> extractInclusive = j => context.Block.Peephole(start, j - start + 1, tracer);
            Func<int, Instructions> extractExclusive = j => context.Block.Peephole(start, j - start, tracer);

            while (i < context.Block.Count)
            {
                var instruction = context.Block[i];

                if (i > start && targets.Contains(instruction.Offset))
                {
                    var jbb = new JumpBasicBlock(nextBlockId++, extractExclusive(i));
                    context.OffsetToBlock.Add(offset, jbb);
                    jbb.Target = BasicBlockFromLocalTarget(instruction.Offset, context);
                    jbb.Target.Sources.Add(jbb);
                    return jbb;
                }
                else
                {
                    switch (instruction.Flavor)
                    {
                    case InstructionFlavor.Misc:
                        {
                            var misci = (MiscInstruction)instruction;
                            switch (misci.Op)
                            {
                            case MiscOp.Throw:
                                {
                                    var nrbb = new NonReturningBasicBlock(nextBlockId++, extractInclusive(i));
                                    context.OffsetToBlock.Add(offset, nrbb);
                                    return nrbb;
                                }
                            case MiscOp.Rethrow:
                                {
                                    var handlerContext = context as HandlerContext;
                                    if (handlerContext == null ||
                                        !(handlerContext.ILHandler is CatchTryInstructionHandler))
                                        throw new InvalidOperationException("rethrow not within catch");
                                    var nrbb = new NonReturningBasicBlock(nextBlockId++, extractInclusive(i));
                                    context.OffsetToBlock.Add(offset, nrbb);
                                    return nrbb;
                                }
                            case MiscOp.Ret:
                            case MiscOp.RetVal:
                                {
                                    if (context is TryContext || context is HandlerContext)
                                        throw new InvalidOperationException("return within a try or handler block");
                                    var nrbb = new NonReturningBasicBlock(nextBlockId++, extractInclusive(i));
                                    context.OffsetToBlock.Add(offset, nrbb);
                                    return nrbb;
                                }
                            case MiscOp.Endfinally:
                                {
                                    var handlerContext = context as HandlerContext;
                                    if (handlerContext == null)
                                        throw new InvalidOperationException
                                            ("endfinally not within fault/finally block");
                                    switch (handlerContext.ILHandler.Flavor)
                                    {
                                    case HandlerFlavor.Catch:
                                    case HandlerFlavor.Filter:
                                        throw new InvalidOperationException
                                            ("endfinally not within fault/finally block");
                                    case HandlerFlavor.Fault:
                                        {
                                            var efbb = new EndFaultBasicBlock
                                                (nextBlockId++,
                                                 extractExclusive(i),
                                                 (TBBFaultHandler)handlerContext.TBBHandler);
                                            context.OffsetToBlock.Add(offset, efbb);
                                            return efbb;
                                        }
                                    case HandlerFlavor.Finally:
                                        {
                                            var efbb = new EndFinallyBasicBlock
                                                (nextBlockId++,
                                                 extractExclusive(i),
                                                 (TBBFinallyHandler)handlerContext.TBBHandler,
                                                 misci.BeforeState.Depth);
                                            context.OffsetToBlock.Add(offset, efbb);
                                            return efbb;
                                        }
                                    default:
                                        throw new ArgumentOutOfRangeException();
                                    }
                                }
                            default:
                                break;
                            }
                            break;
                        }
                    case InstructionFlavor.Branch:
                        {
                            var bri = (BranchInstruction)instruction;
                            switch (bri.Op)
                            {
                            case BranchOp.Br:
                                {
                                    var jbb = new JumpBasicBlock(nextBlockId++, extractExclusive(i));
                                    context.OffsetToBlock.Add(offset, jbb);
                                    jbb.Target = BasicBlockFromLocalTarget(bri.Target, context);
                                    jbb.Target.Sources.Add(jbb);
                                    return jbb;
                                }
                            case BranchOp.Brtrue:
                            case BranchOp.Brfalse:
                            case BranchOp.Breq:
                            case BranchOp.Brne:
                            case BranchOp.BrLt:
                            case BranchOp.BrLe:
                            case BranchOp.BrGt:
                            case BranchOp.BrGe:
                                {
                                    if (i + 1 >= context.Block.Count)
                                        throw new InvalidOperationException("run off end of instructions");
                                    var bbb = new BranchBasicBlock
                                        (nextBlockId++,
                                         extractExclusive(i),
                                         Test.FromBranchOp(bri.Op, bri.IsUnsigned, bri.Type));
                                    context.OffsetToBlock.Add(offset, bbb);
                                    bbb.Target = BasicBlockFromLocalTarget(bri.Target, context);
                                    bbb.Target.Sources.Add(bbb);
                                    bbb.Fallthrough = BasicBlockFromLocalTarget(context.Block[i + 1].Offset, context);
                                    if (!bbb.Fallthrough.Equals(bbb.Target))
                                        bbb.Fallthrough.Sources.Add(bbb);
                                    return bbb;
                                }
                            case BranchOp.Leave:
                                {
                                    var handlerPopCount = default(int);
                                    var stackPopCount = bri.BeforeState.Depth;
                                    var leftContext = default(bool);
                                    var bb = BasicBlockFromTarget
                                        (bri.Target, context, out leftContext, out handlerPopCount);
                                    if (!leftContext)
                                    {
                                        // Not leaving try or handler block, so just empty stack and branch
                                        var lbb = new LeaveBasicBlock
                                            (nextBlockId++, extractExclusive(i), stackPopCount);
                                        context.OffsetToBlock.Add(offset, lbb);
                                        lbb.Target = bb;
                                        lbb.Target.Sources.Add(lbb);
                                        return lbb;
                                    }
                                    else
                                    {
                                        var tryContext = context as TryContext;
                                        if (tryContext != null)
                                        {
                                            // Poping at least one exception handler and branching
                                            var ltbb = new LeaveTryBasicBlock
                                                (nextBlockId++,
                                                 extractExclusive(i),
                                                 tryContext.TryBasicBlock,
                                                 handlerPopCount,
                                                 stackPopCount);
                                            context.OffsetToBlock.Add(offset, ltbb);
                                            ltbb.Target = bb;
                                            ltbb.Target.Sources.Add(ltbb);
                                            return ltbb;
                                        }
                                        else
                                        {
                                            var handlerContext = context as HandlerContext;
                                            if (handlerContext != null)
                                            {
                                                switch (handlerContext.ILHandler.Flavor)
                                                {
                                                case HandlerFlavor.Catch:
                                                    {
                                                        // Poping zero or more exception handlers and branching
                                                        var lcbb = new LeaveCatchBasicBlock
                                                            (nextBlockId++,
                                                             extractExclusive(i),
                                                             (TBBCatchHandler)handlerContext.TBBHandler,
                                                             handlerPopCount,
                                                             stackPopCount);
                                                        lcbb.Target = bb;
                                                        lcbb.Target.Sources.Add(lcbb);
                                                        return lcbb;
                                                    }
                                                case HandlerFlavor.Filter:
                                                    throw new NotSupportedException("filter");
                                                case HandlerFlavor.Fault:
                                                    throw new InvalidOperationException("leaving fault block");
                                                case HandlerFlavor.Finally:
                                                    throw new InvalidOperationException("leaving finally block");
                                                default:
                                                    throw new ArgumentOutOfRangeException();
                                                }
                                            }
                                            else
                                                throw new InvalidOperationException
                                                    ("no try or handler context to leave");
                                        }
                                    }
                                }
                            default:
                                throw new ArgumentOutOfRangeException();
                            }
                        }
                    case InstructionFlavor.Switch:
                        {
                            if (i + 1 >= context.Block.Count)
                                throw new InvalidOperationException("run off end of instructions");
                            var switchi = (SwitchInstruction)instruction;
                            var sbb = new SwitchBasicBlock(nextBlockId++, extractExclusive(i));
                            context.OffsetToBlock.Add(offset, sbb);
                            var seen = new Set<BasicBlock>();
                            foreach (var t in switchi.CaseTargets)
                            {
                                var target = BasicBlockFromLocalTarget(t, context);
                                sbb.CaseTargets.Add(target);
                                if (!seen.Contains(target))
                                {
                                    target.Sources.Add(sbb);
                                    seen.Add(target);
                                }
                            }
                            sbb.Fallthrough = BasicBlockFromLocalTarget(context.Block[i + 1].Offset, context);
                            if (!seen.Contains(sbb.Fallthrough))
                                sbb.Fallthrough.Sources.Add(sbb);
                            return sbb;
                        }
                    case InstructionFlavor.Try:
                        {
                            // Try is known to be a target, thus i == start and extract(i) would yield empty
                            var tryi = (TryInstruction)instruction;
                            var parent = default(TryBasicBlock);
                            var tryContext = context as TryContext;
                            if (tryContext != null)
                                parent = tryContext.TryBasicBlock;
                            else
                            {
                                var handlerContext = context as HandlerContext;
                                if (handlerContext != null)
                                    parent = handlerContext.TryContext.TryBasicBlock;
                            }
                            var tbb = new TryBasicBlock(nextBlockId++, parent, instruction.BeforeState);
                            context.OffsetToBlock.Add(offset, tbb);
                            var subTryContext = new TryContext(tryi.Body, context, tbb);
                            tbb.Body = BasicBlockFromInstructions(subTryContext);
                            tbb.Body.Sources.Add(tbb);
                            foreach (var ilHandler in tryi.Handlers)
                            {
                                var tbbHandler = default(TBBHandler);
                                switch (ilHandler.Flavor)
                                {
                                case HandlerFlavor.Catch:
                                    {
                                        var catchh = (CatchTryInstructionHandler)ilHandler;
                                        tbbHandler = new TBBCatchHandler(tbb, catchh.Type);
                                        break;
                                    }
                                case HandlerFlavor.Filter:
                                    throw new NotSupportedException("filter blocks");
                                case HandlerFlavor.Fault:
                                    {
                                        tbbHandler = new TBBFaultHandler(tbb);
                                        break;
                                    }
                                case HandlerFlavor.Finally:
                                    {
                                        tbbHandler = new TBBFinallyHandler(tbb);
                                        break;
                                    }
                                default:
                                    throw new ArgumentOutOfRangeException();
                                }
                                var subHandlerContext = new HandlerContext
                                    (ilHandler.Body, ilHandler, subTryContext, tbbHandler);
                                tbbHandler.Body = BasicBlockFromInstructions(subHandlerContext);
                                tbbHandler.Body.Sources.Add(tbb);
                                tbb.Handlers.Add(tbbHandler);
                            }
                            return tbb;
                        }
                    default:
                        break;
                    }
                    i++;
                }
            }
            throw new InvalidOperationException("ran off of end of instructions");
        }
Пример #3
0
        private string ContinueReduceLeaveCatch(BasicBlock root, BBLoop loop, LeaveCatchBasicBlock leavebb)
        {
            if (leavebb.Target.Equals(loop.ContinueTarget) && leavebb.HandlerPopCount == 1)
            {
                var instructions = leavebb.Block.CopyContents();
                var lci = new BreakContinueInstruction(NextInstructionId--, BreakContinueOp.Continue, loop.Label)
                          { BeforeState = leavebb.Block.AfterState, AfterState = leavebb.Block.AfterState };
                instructions.Add(lci);
                var newbb = new NonReturningBasicBlock
                    (nextBlockId++, new Instructions(leavebb.Block.BeforeState, instructions));
                root.Coalesce(leavebb, new Set<BasicBlock> { leavebb }, newbb);
                return String.Format
                    ("continue from leave catch at B{0} within loop from B{1}", leavebb.Id, loop.Head.Id);
            }

            return null;
        }