Пример #1
0
        /// <summary>
        /// For an if statement with an unreachable end point and no else block,
        /// inverts to match IL order of the first statement of each branch
        /// </summary>
        private void ImproveILOrdering(Block block, IfInstruction ifInst, Block continueTarget)
        {
            if (!block.HasFlag(InstructionFlags.EndPointUnreachable) ||
                !ifInst.TrueInst.HasFlag(InstructionFlags.EndPointUnreachable) ||
                !ifInst.FalseInst.MatchNop())
            {
                return;
            }

            Debug.Assert(ifInst != block.Instructions.Last());

            var trueRangeStart  = ConditionDetection.GetStartILOffset(ifInst.TrueInst, out bool trueRangeIsEmpty);
            var falseRangeStart = ConditionDetection.GetStartILOffset(block.Instructions[block.Instructions.IndexOf(ifInst) + 1], out bool falseRangeIsEmpty);

            if (trueRangeIsEmpty || falseRangeIsEmpty || falseRangeStart >= trueRangeStart)
            {
                return;
            }

            if (block.Instructions.Last() is Leave leave && !leave.IsLeavingFunction && leave.TargetContainer.Kind == ContainerKind.Normal)
            {
                // non-keyword leave. Can't move out of the last position in the block (fall-through) without introducing goto, unless it can be replaced with a keyword (return/continue)
                if (!CanDuplicateExit(block.Instructions.Last(), continueTarget, out var keywordExit))
                {
                    return;
                }

                context.Step("Replace leave with keyword exit", ifInst.TrueInst);
                block.Instructions.Last().ReplaceWith(keywordExit.Clone());
            }

            ConditionDetection.InvertIf(block, ifInst, context);
        }
Пример #2
0
    void Start()
    {
        if (GameObject.FindGameObjectWithTag("Player") != null)
        {
            pM = GameObject.FindGameObjectWithTag("Player").GetComponent <PlayerMovement>();
        }

        sentences = new Queue <string>();

        dB = GameObject.FindGameObjectWithTag("DialogueBox").GetComponent <DialogueBox>();

        dialogueText = dB.transform.Find("Dialogue").GetComponent <TMP_Text>();
        nameText     = dB.transform.Find("Name").GetComponent <TMP_Text>();
        dialogueAnim = dB.gameObject.GetComponent <Animator>();

        yesNoBox = GameObject.FindGameObjectWithTag("YesNoBox");

        yesText = yesNoBox.transform.Find("YesButton").transform.Find("YesText").GetComponent <TMP_Text>();
        noText  = yesNoBox.transform.Find("NoButton").transform.Find("NoText").GetComponent <TMP_Text>();

        cD = this.gameObject.GetComponent <ConditionDetection>();
        fX = this.gameObject.GetComponent <Effects>();

        yesNoBox.SetActive(false);
    }
        /// <summary>
        /// Reduce Nesting in if/else statements by duplicating an exit instruction.
        /// Does not affect IL order
        /// </summary>
        private bool ReduceNesting(Block block, IfInstruction ifInst, ILInstruction exitInst)
        {
            // start tallying stats for heuristics from then and else-if blocks
            int maxStatements = 0, maxDepth = 0;

            UpdateStats(ifInst.TrueInst, ref maxStatements, ref maxDepth);

            // if (cond) { ... } exit;
            if (ifInst.FalseInst.MatchNop())
            {
                // a separate heuristic tp ShouldReduceNesting as there is visual balancing to be performed based on number of statments
                if (maxDepth < 2)
                {
                    return(false);
                }

                //   ->
                // if (!cond) exit;
                // ...; exit;
                EnsureEndPointUnreachable(ifInst.TrueInst, exitInst);
                EnsureEndPointUnreachable(block, exitInst);
                ConditionDetection.InvertIf(block, ifInst, context);
                return(true);
            }

            // else-if trees are considered as a single group from the root IfInstruction
            if (GetElseIfParent(ifInst) != null)
            {
                return(false);
            }

            // find the else block and tally stats for each else-if block
            while (Block.Unwrap(ifInst.FalseInst) is IfInstruction elseIfInst)
            {
                UpdateStats(elseIfInst.TrueInst, ref maxStatements, ref maxDepth);
                ifInst = elseIfInst;
            }

            if (!ShouldReduceNesting(ifInst.FalseInst, maxStatements, maxDepth))
            {
                return(false);
            }

            // extract the else block and insert exit points all the way up the else-if tree
            do
            {
                var elseIfInst = GetElseIfParent(ifInst);

                // if (cond) { ... } else { ... } exit;
                //   ->
                // if (cond) { ...; exit; }
                // ...; exit;
                EnsureEndPointUnreachable(ifInst.TrueInst, exitInst);
                ExtractElseBlock(ifInst);
                ifInst = elseIfInst;
            } while (ifInst != null);

            return(true);
        }
        /// <summary>
        /// For an if statement with an unreachable end point and no else block,
        /// inverts to match IL order of the first statement of each branch
        /// </summary>
        private void ImproveILOrdering(Block block, IfInstruction ifInst)
        {
            if (!block.HasFlag(InstructionFlags.EndPointUnreachable) ||
                !ifInst.TrueInst.HasFlag(InstructionFlags.EndPointUnreachable) ||
                !ifInst.FalseInst.MatchNop())
            {
                return;
            }

            Debug.Assert(ifInst != block.Instructions.Last());

            var trueRangeStart  = ConditionDetection.GetStartILOffset(ifInst.TrueInst, out bool trueRangeIsEmpty);
            var falseRangeStart = ConditionDetection.GetStartILOffset(block.Instructions[block.Instructions.IndexOf(ifInst) + 1], out bool falseRangeIsEmpty);

            if (!trueRangeIsEmpty && !falseRangeIsEmpty && falseRangeStart < trueRangeStart)
            {
                ConditionDetection.InvertIf(block, ifInst, context);
            }
        }
Пример #5
0
        bool MatchWhileLoop(BlockContainer loop, out IfInstruction condition, out Block loopBody)
        {
            // ConditionDetection favours leave inside if and branch at end of block
            // while-loop:
            // if (!loop-condition) leave loop-container
            // ...
            condition = null;
            loopBody  = null;
            if (!(loop.EntryPoint.Instructions[0] is IfInstruction ifInstruction))
            {
                return(false);
            }
            if (!ifInstruction.FalseInst.MatchNop())
            {
                return(false);
            }
            if (UsesVariableCapturedInLoop(loop, ifInstruction.Condition))
            {
                return(false);
            }

            condition = ifInstruction;
            if (!ifInstruction.TrueInst.MatchLeave(loop))
            {
                return(false);
            }

            context.Step("Transform to while (condition) loop", loop);
            loop.Kind = ContainerKind.While;
            //invert comparison
            ifInstruction.Condition = Comp.LogicNot(ifInstruction.Condition);
            ifInstruction.FalseInst = ifInstruction.TrueInst;
            //move the rest of the body into a new block
            loopBody = ConditionDetection.ExtractBlock(loop.EntryPoint, 1, loop.EntryPoint.Instructions.Count);
            loop.Blocks.Insert(1, loopBody);
            if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable))
            {
                loopBody.Instructions.Add(new Leave(loop));
            }

            ifInstruction.TrueInst = new Branch(loopBody);
            ExpressionTransforms.RunOnSingleStatement(ifInstruction, context);

            // Analyze conditions and decide whether to move some of them out of the condition block:

            /*var conditions = new List<ILInstruction>();
             * SplitConditions(condition.Condition, conditions);
             * // Break apart conditions that could be a MoveNext call followed by a Current accessor call:
             * if (MightBeHeaderOfForEach(loop, conditions)) {
             *      ifInstruction.Condition = conditions[0];
             *      foreach (var cond in conditions.Skip(1).Reverse()) {
             *              IfInstruction inst;
             *              loopBody.Instructions.Insert(0, inst = new IfInstruction(Comp.LogicNot(cond), new Leave(loop)));
             *              ExpressionTransforms.RunOnSingleStatment(inst, context);
             *      }
             * }*/

            // Invert condition and unwrap nested block, if loop ends in a break or return statement preceeded by an IfInstruction.

            /*while (loopBody.Instructions.Last() is Leave leave && loopBody.Instructions.SecondToLastOrDefault() is IfInstruction nestedIf && nestedIf.FalseInst.MatchNop()) {
             *      switch (nestedIf.TrueInst) {
             *              case Block nestedBlock:
             *                      loopBody.Instructions.RemoveAt(leave.ChildIndex);
             *                      loopBody.Instructions.AddRange(nestedBlock.Instructions);
             *                      break;
             *              case Branch br:
             *                      leave.ReplaceWith(nestedIf.TrueInst);
             *                      break;
             *              default:
             *                      return true;
             *      }
             *      nestedIf.Condition = Comp.LogicNot(nestedIf.Condition);
             *      nestedIf.TrueInst = leave;
             *      ExpressionTransforms.RunOnSingleStatment(nestedIf, context);
             *      if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable))
             *              loopBody.Instructions.Add(new Leave(loop));
             * }*/
            return(true);
        }
Пример #6
0
        bool MatchWhileLoop(BlockContainer loop, out IfInstruction condition, out Block loopBody)
        {
            // ConditionDetection favours leave inside if and branch at end of block
            // while-loop:
            // if (!loop-condition) leave loop-container
            // ...
            condition = null;
            loopBody  = loop.EntryPoint;
            if (!(loopBody.Instructions[0] is IfInstruction ifInstruction))
            {
                return(false);
            }

            if (!ifInstruction.FalseInst.MatchNop())
            {
                return(false);
            }

            if (UsesVariableCapturedInLoop(loop, ifInstruction.Condition))
            {
                return(false);
            }

            condition = ifInstruction;
            if (!ifInstruction.TrueInst.MatchLeave(loop))
            {
                // sometimes the loop-body is nested within the if
                // if (loop-condition) { loop-body }
                // leave loop-container

                if (loopBody.Instructions.Count != 2 || !loop.EntryPoint.Instructions.Last().MatchLeave(loop))
                {
                    return(false);
                }

                if (!ifInstruction.TrueInst.HasFlag(InstructionFlags.EndPointUnreachable))
                {
                    ((Block)ifInstruction.TrueInst).Instructions.Add(new Leave(loop));
                }

                ConditionDetection.InvertIf(loopBody, ifInstruction, context);
            }

            context.Step("Transform to while (condition) loop", loop);
            loop.Kind = ContainerKind.While;
            //invert comparison
            ifInstruction.Condition = Comp.LogicNot(ifInstruction.Condition);
            ifInstruction.FalseInst = ifInstruction.TrueInst;
            //move the rest of the body into a new block
            loopBody = ConditionDetection.ExtractBlock(loop.EntryPoint, 1, loop.EntryPoint.Instructions.Count);
            loop.Blocks.Insert(1, loopBody);
            if (!loopBody.HasFlag(InstructionFlags.EndPointUnreachable))
            {
                loopBody.Instructions.Add(new Leave(loop));
            }

            ifInstruction.TrueInst = new Branch(loopBody);
            ExpressionTransforms.RunOnSingleStatement(ifInstruction, context);

            // Analyze conditions and decide whether to move some of them out of the condition block:

            /*var conditions = new List<ILInstruction>();
             * SplitConditions(condition.Condition, conditions);
             * // Break apart conditions that could be a MoveNext call followed by a Current accessor call:
             * if (MightBeHeaderOfForEach(loop, conditions)) {
             *      ifInstruction.Condition = conditions[0];
             *      foreach (var cond in conditions.Skip(1).Reverse()) {
             *              IfInstruction inst;
             *              loopBody.Instructions.Insert(0, inst = new IfInstruction(Comp.LogicNot(cond), new Leave(loop)));
             *              ExpressionTransforms.RunOnSingleStatment(inst, context);
             *      }
             * }*/

            return(true);
        }
Пример #7
0
        /// <summary>
        /// Reduce Nesting in if/else statements by duplicating an exit instruction.
        /// Does not affect IL order
        /// </summary>
        private bool ReduceNesting(Block block, IfInstruction ifInst, ILInstruction exitInst)
        {
            // start tallying stats for heuristics from then and else-if blocks
            int maxStatements = 0, maxDepth = 0;

            UpdateStats(ifInst.TrueInst, ref maxStatements, ref maxDepth);

            // if (cond) { ... } exit;
            if (ifInst.FalseInst.MatchNop())
            {
                // a separate heuristic tp ShouldReduceNesting as there is visual balancing to be performed based on number of statments
                if (maxDepth < 2)
                {
                    return(false);
                }

                //   ->
                // if (!cond) exit;
                // ...; exit;
                EnsureEndPointUnreachable(ifInst.TrueInst, exitInst);
                EnsureEndPointUnreachable(block, exitInst);
                ConditionDetection.InvertIf(block, ifInst, context);
                return(true);
            }

            // else-if trees are considered as a single group from the root IfInstruction
            if (GetElseIfParent(ifInst) != null)
            {
                return(false);
            }

            // find the else block and tally stats for each else-if block
            while (Block.Unwrap(ifInst.FalseInst) is IfInstruction elseIfInst)
            {
                UpdateStats(elseIfInst.TrueInst, ref maxStatements, ref maxDepth);
                ifInst = elseIfInst;
            }

            if (!ShouldReduceNesting(ifInst.FalseInst, maxStatements, maxDepth))
            {
                return(false);
            }

            // extract the else block and insert exit points all the way up the else-if tree
            do
            {
                var elseIfInst = GetElseIfParent(ifInst);

                // if (cond) { ... } else { ... } exit;
                //   ->
                // if (cond) { ...; exit; }
                // ...; exit;
                EnsureEndPointUnreachable(ifInst.TrueInst, exitInst);
                if (ifInst.FalseInst.HasFlag(InstructionFlags.EndPointUnreachable))
                {
                    Debug.Assert(ifInst.HasFlag(InstructionFlags.EndPointUnreachable));
                    Debug.Assert(ifInst.Parent == block);
                    int removeAfter = ifInst.ChildIndex + 1;
                    if (removeAfter < block.Instructions.Count)
                    {
                        // Remove all instructions that ended up dead
                        // (this should just be exitInst itself)
                        Debug.Assert(block.Instructions.SecondToLastOrDefault() == ifInst);
                        Debug.Assert(block.Instructions.Last() == exitInst);
                        block.Instructions.RemoveRange(removeAfter, block.Instructions.Count - removeAfter);
                    }
                }
                ExtractElseBlock(ifInst);
                ifInst = elseIfInst;
            } while (ifInst != null);

            return(true);
        }