예제 #1
0
        Status ProcessExpression(List <ILNode> list, ILBasicBlock head, int pos, Stack <ILNode> stack)
        {
            ILExpression e = head.Body[pos] as ILExpression;

            if (e == null)
            {
                list.Add(head.Body[pos]);
                return(Status.NoChangeAdded);
            }
            ILValue    tempValue;
            ILVariable tempVar;

            switch (e.Code)
            {
            case GMCode.Push:
                tempValue = e.Operand as ILValue;
                tempVar   = e.Operand as ILVariable;
                if (tempValue != null)
                {
                    stack.Push(tempValue);
                }
                else if (tempVar != null)
                {
                    ProcessVar(tempVar, stack);
                    stack.Push(tempVar);
                }
                else
                {     // block comes back as a push expression
                    Debug.Assert(e.Arguments.Count > 0);
                    stack.Push(e.Arguments[0]);
                }
                return(Status.AddedToStack);

            case GMCode.Pop:     // convert to an assign
            {
                tempVar = e.Operand as ILVariable;
                Debug.Assert(tempVar != null);
                ILExpression expr = null;
                if (Dup1Seen)
                {
                    expr = NodeToExpresion(stack.Pop());                   // have to swap the assignment if a dup 1 was done
                }
                ProcessVar(tempVar, stack);
                e.Code    = GMCode.Assign;
                e.Operand = null;
                e.Arguments.Add(NodeToExpresion(tempVar));
                if (!Dup1Seen)
                {
                    expr = NodeToExpresion(stack.Pop());
                }
                e.Arguments.Add(expr);


                list.Add(e);
                return(Status.ChangedAdded);
            }

            case GMCode.Call:
            {
                if (e.Extra == -1)
                {
                    list.Add(e);
                    return(Status.NoChangeAdded);
                }         // its already resolved
                          //ILExpression call = new ILExpression(GMCode.Call, )
                          //ILCall call = new ILCall() { Name = e.Operand as string };
                          //for (int j = 0; j < e.Extra; j++) call.Arguments.Add(stack.Pop());
                if (e.Extra > 0)
                {
                    for (int j = 0; j < e.Extra; j++)
                    {
                        e.Arguments.Add(NodeToExpresion(stack.Pop()));
                    }
                }
                e.Extra = -1;
                stack.Push(e);
            }
                return(Status.AddedToStack);

            case GMCode.Popz:
            {
                if (stack.Count == 0)
                {
                    list.Add(e);
                    //  Debug.Assert(false);
                    return(Status.ChangedAdded);
                }
                else
                {
                    ILExpression call = stack.Peek() as ILExpression;
                    if (call != null && call.Code == GMCode.Call)
                    {
                        stack.Pop();
                        list.Add(call);
                        return(Status.ChangedAdded);
                    }
                    else
                    {
                        throw new Exception("popz on a non call?");          // return e; // else, ignore for switch
                    }
                }
            }

            case GMCode.Bf:
            case GMCode.Bt:
            case GMCode.Ret:
                if (stack.Count > 0)
                {
                    // Debug.Assert(stack.Count == 1);
                    e.Arguments[0] = NodeToExpresion(stack.Pop());
                    if (stack.Count > 0)
                    {
                        foreach (var n in stack)
                        {
                            list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n)));
                        }
                    }
                    list.Add(e);
                    return(Status.ChangedAdded);
                }
                else
                {
                    list.Add(e);
                    return(Status.NoChangeAdded);
                }

            case GMCode.B:
            case GMCode.Exit:
                if (stack.Count > 0)
                {
                    foreach (var n in stack)
                    {
                        list.Add(new ILExpression(GMCode.Push, null, NodeToExpresion(n)));
                    }
                }
                list.Add(e);
                return(Status.ChangedAdded);

            case GMCode.Dup:
                if ((int)e.Operand == 0)
                {
                    stack.Push(stack.Peek());     // simple case
                    return(Status.DupStack0);
                }
                else
                {
                    // this is usally on an expression that uses a var multipual times so the instance and index is copyed
                    // HOWEVER the stack may need to be swaped
                    foreach (var n in stack.Reverse().ToArray())
                    {
                        stack.Push(n);   // copy the entire stack
                    }
                    Dup1Seen = true;     // usally this is on an assignment += -= of an array or such
                    return(Status.DupStack1);
                }

            default:     // ok we handle an expression
                if (e.Code.isExpression())
                {
                    for (int j = 0; j < e.Code.GetPopDelta(); j++)
                    {
                        if (stack.Count > 0)
                        {
                            e.Arguments.Add(NodeToExpresion(stack.Pop()));
                        }
                        else
                        {
                            e.Arguments.Add(new ILExpression(GMCode.Pop, null));
                        }
                    }

                    e.Arguments.Reverse(); // till I fix it latter, sigh
                    stack.Push(e);         // push expressions back
                    return(Status.AddedToStack);
                }
                else
                {
                    list.Add(e);
                    return(Status.NoChangeAdded);
                }
            }
            throw new Exception("Shouldn't get here?");
        }
예제 #2
0
        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));
        }
예제 #3
0
        /// <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());
        }