Esempio n. 1
0
        /// <summary>
        /// Checks if an exit is a duplicable keyword exit (return; break; continue;)
        /// </summary>
        private bool CanDuplicateExit(ILInstruction exit, Block continueTarget, out ILInstruction keywordExit)
        {
            keywordExit = exit;
            if (exit != null && exit.MatchBranch(continueTarget))
            {
                return(true);                 // keyword is continue
            }
            if (!(exit is Leave leave && leave.Value.MatchNop()))
            {
                return(false);                // don't duplicate valued returns
            }
            if (leave.IsLeavingFunction || leave.TargetContainer.Kind != ContainerKind.Normal)
            {
                return(true);                // keyword is return || break
            }
            // leave from a try/pinned/lock etc, check if the target (the instruction following the target container) is duplicable, if so, set keywordExit to that
            ILInstruction leavingInst = leave.TargetContainer;

            Debug.Assert(!leavingInst.HasFlag(InstructionFlags.EndPointUnreachable));
            while (!(leavingInst.Parent is Block b) || leavingInst == b.Instructions.Last())
            {
                if (leavingInst.Parent is TryFinally tryFinally)
                {
                    if (leavingInst.SlotInfo == TryFinally.FinallyBlockSlot)                       // cannot duplicate leaves from finally containers
                    {
                        Debug.Assert(leave.TargetContainer == tryFinally.FinallyBlock);            //finally cannot have control flow
                        return(false);
                    }
                    if (tryFinally.HasFlag(InstructionFlags.EndPointUnreachable))                       // finally block changes return value/throws an exception? Yikes. Lets leave it alone
                    {
                        Debug.Assert(tryFinally.FinallyBlock.HasFlag(InstructionFlags.EndPointUnreachable));
                        return(false);
                    }
                }
                else if (leavingInst.Parent is TryFault tryFault && leavingInst.SlotInfo == TryFault.FaultBlockSlot)                   // cannot duplicate leaves from fault containers either
                {
                    Debug.Assert(leave.TargetContainer == tryFault.FaultBlock);
                    return(false);
                }

                leavingInst = leavingInst.Parent;
                Debug.Assert(!leavingInst.HasFlag(InstructionFlags.EndPointUnreachable));
                Debug.Assert(!(leavingInst is ILFunction));
            }

            var block      = (Block)leavingInst.Parent;
            var targetInst = block.Instructions[block.Instructions.IndexOf(leavingInst) + 1];

            return(CanDuplicateExit(targetInst, continueTarget, out keywordExit));
        }
Esempio n. 2
0
        static bool Inst2MightWriteToVariableReadByInst1(ILInstruction inst1, ILInstruction inst2)
        {
            if (!inst1.HasFlag(InstructionFlags.MayReadLocals))
            {
                // quick exit if inst1 doesn't read any variables
                return(false);
            }
            var variables = inst1.Descendants.OfType <LdLoc>().Select(load => load.Variable).ToHashSet();

            if (inst2.HasFlag(InstructionFlags.SideEffect) && variables.Any(v => v.AddressCount > 0))
            {
                // If inst2 might have indirect writes, we cannot reorder with any loads of variables that have their address taken.
                return(true);
            }
            foreach (var inst in inst2.Descendants)
            {
                if (inst.HasDirectFlag(InstructionFlags.MayWriteLocals))
                {
                    ILVariable v = ((IInstructionWithVariableOperand)inst).Variable;
                    if (variables.Contains(v))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Esempio n. 3
0
        /// <summary>
        /// Ensures the end point of a block is unreachable by duplicating and appending the [exit] instruction following the end point
        /// </summary>
        /// <param name="inst">The instruction/block of interest</param>
        /// <param name="fallthroughExit">The next instruction to be executed (provided inst does not exit)</param>
        private void EnsureEndPointUnreachable(ILInstruction inst, ILInstruction fallthroughExit)
        {
            if (!(inst is Block block))
            {
                Debug.Assert(inst.HasFlag(InstructionFlags.EndPointUnreachable));
                return;
            }

            if (!block.HasFlag(InstructionFlags.EndPointUnreachable))
            {
                context.Step("Duplicate block exit", fallthroughExit);
                block.Instructions.Add(fallthroughExit.Clone());
            }
        }