コード例 #1
0
ファイル: BuildFullAst.cs プロジェクト: boomboompower/GMdsam
        void CreateSwitchExpresion(ILNode condition, List <ILNode> list, List <ILNode> body, ILBasicBlock head, int pos)
        {
            // we are in a case block, check if its the first block

            List <ILBasicBlock> caseBlocks       = new List <ILBasicBlock>();
            List <ILLabel>      caseLabels       = new List <ILLabel>();
            ILExpression        switchExpression = new ILExpression(GMCode.Switch, null);

            switchExpression.Arguments.Add(NodeToExpresion(condition)); // pop the switch condition
            ILBasicBlock current = head;
            ILLabel      nextCase;
            ILLabel      caseTrue;
            ILExpression fakeArgument;

            while (current.MatchLastAndBr(GMCode.Bt, out caseTrue, out fakeArgument, out nextCase))
            {
                ILNode operand;
                if (!current.MatchAt(current.Body.Count - 4, GMCode.Push, out operand))
                {
                    throw new Exception("fix");
                }
                if (!(operand is ILValue))
                {
                    throw new Exception("Can only handle constants right now");
                }
                switchExpression.Arguments.Add(new ILExpression(GMCode.Case, caseTrue, NodeToExpresion(operand)));
                caseLabels.Add(caseTrue);
                body.Remove(current);
                current = labelToBasicBlock[nextCase];
            }
            body.Insert(pos, head);

            var lastBlock = current;


            ILLabel fallLabel;

            if (!lastBlock.MatchSingle(GMCode.B, out fallLabel))
            {
                throw new Exception("fix");
            }
            current = labelToBasicBlock[fallLabel];
            if (!current.MatchAt(1, GMCode.Popz))
            { // has a default case
              // Side note, the LoopAndConditions figures out if we have a default case by checking
              // if the ending branch is linked to all the other case branches
              // so we don't need to do anything here
              // All this code is JUST for finding that popz that pops the condition out of the switch
              // if you don't care about it, you could just search though all the expresions and remove any and all
              // popz's  I am beggining to think this is the right way to do it as I don't see any other uses
              // of popz's
              //  Debug.Assert(false);
                BuildNextBlockData(); // build block chain, we need this for default and mabye case lookups
                                      // ok, this is why we DON'T want to remove redundent code as there is this empty
                                      // useless goto RIGHt after this that has the link to the finale case
                ILLabel nextBlockLabel = lastBlock.Body.First() as ILLabel;
                var     uselessBlock   = this.labelToNextBlock[nextBlockLabel];
                ILLabel newFallLabel;
                if (!uselessBlock.MatchSingle(GMCode.B, out newFallLabel))
                {
                    throw new Exception("fix");
                }
                current = labelToBasicBlock[newFallLabel];

                if (!current.MatchAt(1, GMCode.Popz))
                {
                    throw new Exception("I have no idea where the popz is for this switch");
                }
            }
            current.Body.RemoveAt(1);
            ILLabel lastBlockLabel = lastBlock.Body.First() as ILLabel;

            if (this.labelGlobalRefCount[lastBlockLabel] == 1)
            {
                body.Remove(lastBlockLabel);
            }
            switchExpression.Operand = caseLabels.ToArray();

            list.Add(switchExpression);
            list.Add(new ILExpression(GMCode.B, fallLabel));
        }
コード例 #2
0
        public static bool Match(this ILNode node, GMCode code)
        {
            ILExpression expr = node as ILExpression;

            return(expr != null && expr.Code == code);
        }
コード例 #3
0
ファイル: GotoRemoval.cs プロジェクト: boomboompower/GMdsam
        /// <summary>
        /// Get the first expression to be excecuted if the instruction pointer is at the start of the given node.
        /// Try blocks may not be entered in any way.  If possible, the try block is returned as the node to be executed.
        /// </summary>
        ILNode Enter(ILNode node, HashSet <ILNode> visitedNodes)
        {
            if (node == null)
            {
                throw new ArgumentNullException();
            }

            if (!visitedNodes.Add(node))
            {
                return(null);  // Infinite loop
            }
            ILLabel label = node as ILLabel;

            if (label != null)
            {
                return(Exit(label, visitedNodes));
            }

            ILExpression expr = node as ILExpression;

            if (expr != null)
            {
                if (expr.Code == GMCode.B)
                {
                    ILLabel target = (ILLabel)expr.Operand;
                    // Early exit - same try-block
                    if (GetParents(expr).OfType <ILTryCatchBlock>().FirstOrDefault() == GetParents(target).OfType <ILTryCatchBlock>().FirstOrDefault())
                    {
                        return(Enter(target, visitedNodes));
                    }
                    // Make sure we are not entering any try-block
                    var srcTryBlocks = GetParents(expr).OfType <ILTryCatchBlock>().Reverse().ToList();
                    var dstTryBlocks = GetParents(target).OfType <ILTryCatchBlock>().Reverse().ToList();
                    // Skip blocks that we are already in
                    int i = 0;
                    while (i < srcTryBlocks.Count && i < dstTryBlocks.Count && srcTryBlocks[i] == dstTryBlocks[i])
                    {
                        i++;
                    }
                    if (i == dstTryBlocks.Count)
                    {
                        return(Enter(target, visitedNodes));
                    }
                    else
                    {
                        ILTryCatchBlock dstTryBlock = dstTryBlocks[i];
                        // Check that the goto points to the start
                        ILTryCatchBlock current = dstTryBlock;
                        while (current != null)
                        {
                            foreach (ILNode n in current.TryBlock.Body)
                            {
                                if (n is ILLabel)
                                {
                                    if (n == target)
                                    {
                                        return(dstTryBlock);
                                    }
                                }
                                else if (!n.Match(GMCode.BadOp))
                                {
                                    current = n as ILTryCatchBlock;
                                    break;
                                }
                            }
                        }
                        return(null);
                    }
                }
                else if (expr.Code == GMCode.BadOp)
                {
                    return(Exit(expr, visitedNodes));
                }
                else if (expr.Code == GMCode.LoopOrSwitchBreak)
                {
                    ILNode breakBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILSwitch || n is ILWithStatement);
                    return(Exit(breakBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else if (expr.Code == GMCode.LoopContinue)
                {
                    ILNode continueBlock = GetParents(expr).First(n => n is ILWhileLoop || n is ILWithStatement);
                    return(Enter(continueBlock, new HashSet <ILNode>()
                    {
                        expr
                    }));
                }
                else
                {
                    return(expr);
                }
            }

            ILBlock block = node as ILBlock;

            if (block != null)
            {
                if (block.EntryGoto != null)
                {
                    return(Enter(block.EntryGoto, visitedNodes));
                }
                else if (block.Body.Count > 0)
                {
                    return(Enter(block.Body[0], visitedNodes));
                }
                else
                {
                    return(Exit(block, visitedNodes));
                }
            }

            ILCondition cond = node as ILCondition;

            if (cond != null)
            {
                return(cond.Condition);
            }
            ILWithStatement with = node as ILWithStatement;

            if (with != null)
            {
                if (with.Enviroment != null)
                {
                    return(with.Enviroment);
                }
                else
                {
                    return(Enter(with.Body, visitedNodes));
                }
            }

            ILWhileLoop loop = node as ILWhileLoop;

            if (loop != null)
            {
                if (loop.Condition != null)
                {
                    return(loop.Condition);
                }
                else
                {
                    return(Enter(loop.BodyBlock, visitedNodes));
                }
            }

            ILTryCatchBlock tryCatch = node as ILTryCatchBlock;

            if (tryCatch != null)
            {
                return(tryCatch);
            }

            ILSwitch ilSwitch = node as ILSwitch;

            if (ilSwitch != null)
            {
                return(ilSwitch.Condition);
            }

            throw new NotSupportedException(node.GetType().ToString());
        }