Example #1
0
        protected internal override void VisitBlockContainer(BlockContainer container)
        {
            var oldExit      = currentExit;
            var oldContainer = currentContainer;
            var thisExit     = GetExit(container);

            currentExit      = thisExit;
            currentContainer = container;
            base.VisitBlockContainer(container);
            if (thisExit == ExitNotYetDetermined && currentExit != ExitNotYetDetermined)
            {
                // This transform determined an exit point.
                Debug.Assert(!currentExit.MatchLeave(currentContainer));
                ILInstruction inst = container;
                // traverse up to the block (we'll always find one because GetExit
                // only returns ExitNotYetDetermined if there's a block)
                while (inst.Parent.OpCode != OpCode.Block)
                {
                    inst = inst.Parent;
                }
                Block block = (Block)inst.Parent;
                block.Instructions.Add(currentExit);
            }
            else
            {
                Debug.Assert(thisExit == currentExit);
            }
            currentExit      = oldExit;
            currentContainer = oldContainer;
        }
Example #2
0
        protected internal override void VisitBlockContainer(BlockContainer container)
        {
            var oldExit           = currentExit;
            var oldContainer      = currentContainer;
            var oldPotentialExits = potentialExits;
            var thisExit          = GetExit(container);

            currentExit      = thisExit;
            currentContainer = container;
            potentialExits   = (thisExit == ExitNotYetDetermined ? new List <ILInstruction>() : null);
            base.VisitBlockContainer(container);
            if (thisExit == ExitNotYetDetermined && potentialExits.Count > 0)
            {
                // This transform determined an exit point.
                currentExit = ChooseExit(potentialExits);
                foreach (var exit in potentialExits)
                {
                    if (CompatibleExitInstruction(currentExit, exit))
                    {
                        exit.ReplaceWith(new Leave(currentContainer)
                        {
                            ILRange = exit.ILRange
                        });
                    }
                }
                Debug.Assert(!currentExit.MatchLeave(currentContainer));
                ILInstruction inst = container;
                // traverse up to the block (we'll always find one because GetExit
                // only returns ExitNotYetDetermined if there's a block)
                while (inst.Parent.OpCode != OpCode.Block)
                {
                    inst = inst.Parent;
                }
                Block block = (Block)inst.Parent;
                if (block.HasFlag(InstructionFlags.EndPointUnreachable))
                {
                    // Special case: despite replacing the exits with leave(currentContainer),
                    // we still have an unreachable endpoint.
                    // The appended currentExit instruction would not be reachable!
                    // This happens in test case ExceptionHandling.ThrowInFinally()
                    if (currentExit is Branch b)
                    {
                        blocksPotentiallyMadeUnreachable.Add(b.TargetBlock);
                    }
                }
                else
                {
                    block.Instructions.Add(currentExit);
                }
            }
            else
            {
                Debug.Assert(thisExit == currentExit);
            }
            currentExit      = oldExit;
            currentContainer = oldContainer;
            potentialExits   = oldPotentialExits;
        }
Example #3
0
        bool ShouldSwapIfTargets(ILInstruction inst1, ILInstruction inst2)
        {
            Block block1 = null, block2 = null;

            if (inst1.MatchBranch(out block1) && inst2.MatchBranch(out block2))
            {
                // prefer arranging stuff in IL order
                return(block1.ILRange.Start > block2.ILRange.Start);
            }
            BlockContainer container1, container2;

            if (inst1.MatchLeave(out container1) && container1.Parent is TryInstruction)
            {
                // 'leave tryBlock' is considered to have a later target than
                // any branch within the container, and also a later target
                // than a return instruction.
                // This is necessary to avoid "goto" statements in the
                // ExceptionHandling.ConditionalReturnInThrow test.
                if (!inst2.MatchLeave(out container2))
                {
                    container2 = block2?.Parent as BlockContainer;
                }
                return(container2 == null || container2.IsDescendantOf(container1));
            }
            if (inst1.MatchBranch(out block1) && inst2.MatchLeave(out container2) &&
                block1.IncomingEdgeCount > 1)
            {
                // if (..) goto x; leave c;
                // Unless x can be inlined, it's better to swap the order if the 'leave'
                // has a chance to turn into a 'break;' or 'return;'
                if (container2.Parent is ILFunction)
                {
                    return(true);                    // return
                }
                if (container2.EntryPoint.IncomingEdgeCount > 1)
                {
                    // break
                    return(BlockContainer.FindClosestContainer(inst2) == container2);
                }
            }
            return(false);
        }
Example #4
0
        protected internal override void VisitBlockContainer(BlockContainer container)
        {
            var oldExit           = currentExit;
            var oldContainer      = currentContainer;
            var oldPotentialExits = potentialExits;
            var thisExit          = GetExit(container);

            currentExit      = thisExit;
            currentContainer = container;
            potentialExits   = (thisExit == ExitNotYetDetermined ? new List <ILInstruction>() : null);
            base.VisitBlockContainer(container);
            if (thisExit == ExitNotYetDetermined && potentialExits.Count > 0)
            {
                // This transform determined an exit point.
                currentExit = ChooseExit(potentialExits);
                foreach (var exit in potentialExits)
                {
                    if (CompatibleExitInstruction(currentExit, exit))
                    {
                        exit.ReplaceWith(new Leave(currentContainer)
                        {
                            ILRange = exit.ILRange
                        });
                    }
                }
                Debug.Assert(!currentExit.MatchLeave(currentContainer));
                ILInstruction inst = container;
                // traverse up to the block (we'll always find one because GetExit
                // only returns ExitNotYetDetermined if there's a block)
                while (inst.Parent.OpCode != OpCode.Block)
                {
                    inst = inst.Parent;
                }
                Block block = (Block)inst.Parent;
                block.Instructions.Add(currentExit);
            }
            else
            {
                Debug.Assert(thisExit == currentExit);
            }
            currentExit      = oldExit;
            currentContainer = oldContainer;
            potentialExits   = oldPotentialExits;
        }