public int LabelCount(ILLabel l)
 {
     return(labelGlobalRefCount[l]);
 }
Example #2
0
        /// <summary>
        /// Group input into a set of blocks that can be later arbitraliby schufled.
        /// The method adds necessary branches to make control flow between blocks
        /// explicit and thus order independent.
        /// </summary>
        public static void SplitToBasicBlocks(ILBlock block)
        {
            int           nextLabelIndex = 0;
            List <ILNode> basicBlocks    = new List <ILNode>();

            ILLabel entryLabel = block.Body.FirstOrDefault() as ILLabel ?? new ILLabel()
            {
                Name = "Block_" + (nextLabelIndex++)
            };
            ILBasicBlock basicBlock = new ILBasicBlock();

            basicBlocks.Add(basicBlock);
            basicBlock.Body.Add(entryLabel);
            block.EntryGoto = new ILExpression(GMCode.B, entryLabel);

            if (block.Body.Count > 0)
            {
                if (block.Body[0] != entryLabel)
                {
                    basicBlock.Body.Add(block.Body[0]);
                }
                for (int i = 1; i < block.Body.Count; i++)
                {
                    ILNode lastNode = block.Body[i - 1];
                    ILNode currNode = block.Body[i];

                    // Start a new basic block if necessary
                    if (currNode is ILLabel ||
                        lastNode.IsConditionalControlFlow() ||
                        lastNode.IsUnconditionalControlFlow())
                    {
                        // Try to reuse the label
                        ILLabel label = currNode as ILLabel ?? new ILLabel()
                        {
                            Name = "Block_" + (nextLabelIndex++).ToString()
                        };

                        // Terminate the last block
                        if (!lastNode.IsUnconditionalControlFlow())
                        {
                            // Explicit branch from one block to other
                            basicBlock.Body.Add(new ILExpression(GMCode.B, label));
                        }

                        // Start the new block
                        basicBlock = new ILBasicBlock();
                        basicBlocks.Add(basicBlock);
                        basicBlock.Body.Add(label);

                        // Add the node to the basic block
                        if (currNode != label)
                        {
                            basicBlock.Body.Add(currNode);
                        }
                    }
                    else
                    {
                        basicBlock.Body.Add(currNode);
                    }
                }
            }

            block.Body = basicBlocks;
            return;
        }
        public bool SimplifyShortCircuit(IList <ILNode> body, ILBasicBlock head, int pos)
        {
            Debug.Assert(body.Contains(head));
            // Debug.Assert((head.Body[0] as ILLabel).Name != "Block_54");
            ILExpression condExpr;
            ILLabel      trueLabel;
            ILLabel      falseLabel;

            // Ok, since we have not changed out all the Bf's to Bt like in ILSpy, we have to do them seperately
            // as I am getting bugs in my wahhoo about it
            if ((head.MatchLastAndBr(GMCode.Bf, out falseLabel, out condExpr, out trueLabel) ||
                 head.MatchLastAndBr(GMCode.Bt, out trueLabel, out condExpr, out falseLabel)) &&
                condExpr.Code != GMCode.Pop // its a terrtery so ignore it?
                )                           // I saw this too
            {
                GMCode code = (head.Body[head.Body.Count - 2] as ILExpression).Code;
                for (int pass = 0; pass < 2; pass++)
                {
                    // On the second pass, swap labels and negate expression of the first branch
                    // It is slightly ugly, but much better then copy-pasting this whole block
                    ILLabel nextLabel   = (pass == 0) ? trueLabel : falseLabel;
                    ILLabel otherLablel = (pass == 0) ? falseLabel : trueLabel;
                    bool    negate      = (pass == 1);
                    negate = GMCode.Bt == code ? !negate : negate;
                    ILBasicBlock nextBasicBlock = labelToBasicBlock[nextLabel];
                    ILExpression nextCondExpr;
                    ILLabel      nextTrueLablel;
                    ILLabel      nextFalseLabel;
                    if (body.Contains(nextBasicBlock) &&
                        nextBasicBlock != head &&
                        labelGlobalRefCount[(ILLabel)nextBasicBlock.Body.First()] == 1 &&
                        (nextBasicBlock.MatchSingleAndBr(GMCode.Bf, out nextFalseLabel, out nextCondExpr, out nextTrueLablel) ||
                         nextBasicBlock.MatchSingleAndBr(GMCode.Bt, out nextTrueLablel, out nextCondExpr, out nextFalseLabel)) &&
                        nextCondExpr.Code != GMCode.Pop && // ugh
                        (otherLablel == nextFalseLabel || otherLablel == nextTrueLablel))
                    {
                        //     Debug.Assert(nextCondExpr.Arguments.Count != 2);
                        // Create short cicuit branch
                        ILExpression logicExpr;
                        if (otherLablel == nextFalseLabel)
                        {
                            logicExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicAnd, negate ? new ILExpression(GMCode.Not, null, condExpr) : condExpr, nextCondExpr);
                        }
                        else
                        {
                            logicExpr = MakeLeftAssociativeShortCircuit(GMCode.LogicOr, negate ? condExpr : new ILExpression(GMCode.Not, null, condExpr), nextCondExpr);
                        }
                        //   head.Body.RemoveTail(GMCode.Bf, GMCode.B);
                        head.Body.RemoveRange(head.Body.Count - 2, 2);
                        head.Body.Add(new ILExpression(GMCode.Bf, nextFalseLabel, logicExpr));
                        head.Body.Add(new ILExpression(GMCode.B, nextTrueLablel));

                        // Remove the inlined branch from scope
                        body.RemoveOrThrow(nextBasicBlock);

                        return(true);
                    }
                }
            }

            return(false);
        }
 public ILBasicBlock LabelToBasicBlock(ILLabel l)
 {
     return(labelToBasicBlock[l]);
 }
Example #5
0
 public static bool MatchLastAndBr <T>(this ILBasicBlock bb, GMCode code, out T operand, out IList <ILExpression> args, out ILLabel brLabel)
 {
     if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out operand, out args) &&
         bb.Body.LastOrDefault().Match(GMCode.B, out brLabel))
     {
         return(true);
     }
     operand = default(T);
     args    = null;
     brLabel = null;
     return(false);
 }
Example #6
0
        public static bool MatchCaseBlock(this ILBasicBlock bb, out ILExpression caseCondition, out ILLabel caseLabel, out ILLabel nextCase)
        {
            int          dupType = 0;
            ILExpression pushSeq;
            ILExpression btExpresion;

            if (bb.Body.Count == 6 &&
                bb.Body[0] is ILLabel &&
                bb.Body[1].Match(GMCode.Dup, out dupType) &&
                dupType == 0 &&
                bb.Body[2].Match(GMCode.Push, out caseCondition) &&
                bb.Body[3].Match(GMCode.Seq) &&
                bb.MatchLastAndBr(GMCode.Bt, out caseLabel, out btExpresion, out nextCase)
                )
            {
                return(true);
            }
            caseCondition = default(ILExpression);
            caseLabel     = nextCase = default(ILLabel);
            return(false);
        }
Example #7
0
 public static bool MatchSingleAndBr <T>(this ILBasicBlock bb, GMCode code, out T operand, out ILExpression arg, out ILLabel brLabel)
 {
     {
         if (bb.Body.Count == 3 &&
             bb.Body[0] is ILLabel &&
             bb.Body[1].Match(code, out operand, out arg) &&
             bb.Body[2].Match(GMCode.B, out brLabel))
         {
             return(true);
         }
     }
     operand = default(T);
     arg     = null;
     brLabel = null;
     return(false);
 }
Example #8
0
 public static bool MatchLastAndBr(this ILBasicBlock bb, GMCode code, out ILExpression arg, out ILLabel brLabel)
 {
     if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out arg) &&
         bb.Body.LastOrDefault().Match(GMCode.B, out brLabel))
     {
         return(true);
     }
     arg     = default(ILExpression);
     brLabel = null;
     return(false);
 }
Example #9
0
        public static bool MatchSingleAndBr(this ILBasicBlock bb, GMCode code, out ILExpression arg, out ILLabel brLabel)
        {
            object filler;

            return(bb.MatchSingleAndBr <object>(code, out filler, out arg, out brLabel));
        }
Example #10
0
        List <ILNode> BuildPreAst()
        { // Just convert instructions to ast streight
            List <ILNode>             nodes        = new List <ILNode>();
            Dictionary <int, ILLabel> labels       = new Dictionary <int, ILLabel>();
            Func <Label, ILLabel>     ConvertLabel = (Label l) =>
            {
                ILLabel lookup;
                if (labels.TryGetValue(l.Address, out lookup))
                {
                    return(lookup);
                }
                lookup = new ILLabel()
                {
                    Name = l.ToString(), UserData = l
                };
                labels.Add(l.Address, lookup);
                return(lookup);
            };

            foreach (var i in _method.Values)
            {
                //      Debug.Assert(nodes.Count != 236);
                GMCode code    = i.Code;
                object operand = i.Operand;
                int    extra   = i.Extra;
                if (i.Label != null)
                {
                    nodes.Add(ConvertLabel(i.Label));
                }
                ILExpression expr = null;
                switch (code)
                {
                case GMCode.Conv:
                    continue;     // ignore all Conv for now

                case GMCode.Call:
                    // Since we have to resolve calls seperately and need
                    expr       = new ILExpression(GMCode.Call, operand as string);
                    expr.Extra = extra;     // need to know how many arguments we have
                    break;

                case GMCode.Popz:
                    expr = new ILExpression(code, null);
                    break;

                case GMCode.Pop:     // var define, so lets define it
                    expr       = new ILExpression(GMCode.Pop, BuildVar((int)operand, extra));
                    expr.Extra = extra;
                    break;

                case GMCode.Push:
                    if (i.Types[0] != GM_Type.Var)
                    {
                        expr = new ILExpression(GMCode.Push, OperandToIValue(operand, i.Types[0]));    // simple constant
                    }
                    else
                    {
                        expr = new ILExpression(GMCode.Push, BuildVar((int)operand, extra));      // try to figure out the var);
                    }
                    expr.Extra = extra;
                    break;

                case GMCode.Pushenv:     // the asembler converted the positions to labels at the end of the push/pop enviroments
                    expr = new ILExpression(GMCode.Pushenv, ConvertLabel(i.Operand as Label));
                    break;

                case GMCode.Popenv:
                    expr = new ILExpression(GMCode.B, ConvertLabel(i.Operand as Label));
                    break;

                case GMCode.B:
                    expr = new ILExpression(GMCode.B, ConvertLabel(i.Operand as Label));
                    break;

                case GMCode.Ret:
                    expr = new ILExpression(code, null, new ILExpression(GMCode.Pop, null));
                    break;

                case GMCode.Bt:
                case GMCode.Bf:
                    expr = new ILExpression(code, ConvertLabel(i.Operand as Label), new ILExpression(GMCode.Pop, null));
                    break;

                case GMCode.Dup:
                    expr = new ILExpression(code, extra);     // save the extra value for dups incase its dup eveything or just one
                                                              //      HackDebug(i, _method.Values);
                    break;

                case GMCode.Exit:
                    expr = new ILExpression(code, null);
                    break;

                default:
                    expr = new ILExpression(code, null);
                    break;
                }
                expr.ILRanges.Add(new ILRange(i.Address, i.Address));
                nodes.Add(expr);
            }
            return(nodes);
        }
Example #11
0
        void TestAndFixWierdLoop(List <ILNode> body, ILBasicBlock head, int pos)
        {
            object       uvalue1;
            ILValue      value2;
            ILLabel      endLoop;
            ILLabel      startLoop;
            ILExpression filler;
            //Debug.Assert((head.Body[0] as ILLabel).Name != "L36");
            // Wierd one here.  I ran accross this a few times and I think this is generated code
            // for events.  Basicly, it pushes a constant on the stack and uses a repeat loop
            // however since I am not doing ANY kind of real stack/temporary analysis.  I would have
            // to rewrite and add a bunch of code to get that to work and right now its only a few functions
            // Its easyer to build a while loop out of it and let the decompiler handle it rather than
            // build a more robust stack anilizer
            // ugh have to make a new block for it too, meh
            int headLen = head.Body.Count;

            if (head.MatchAt(headLen - 6, GMCode.Push, out uvalue1) &&
                head.MatchAt(headLen - 5, GMCode.Dup) &&
                head.MatchAt(headLen - 4, GMCode.Push, out value2) &&

                head.MatchAt(headLen - 3, GMCode.Sle) &&
                head.MatchLastAndBr(GMCode.Bt, out endLoop, out filler, out startLoop))
            {
                // ok, lets rewrite the head so it makes sence
                ILLabel       newLoopStart = NewJunkLoop();
                ILVariable    genVar       = NewGeneratedVar();
                List <ILNode> newHead      = new List <ILNode>();
                for (int ii = 0; ii <= headLen - 7; ii++)
                {
                    newHead.Add(head.Body[ii]);                                       // add the front of it including the sub part
                }
                newHead.Add(new ILExpression(GMCode.Push, uvalue1));
                newHead.Add(new ILExpression(GMCode.Pop, genVar));
                newHead.Add(new ILExpression(GMCode.B, newLoopStart));
                ILBasicBlock newLoopBlock = new ILBasicBlock();
                newLoopBlock.Body.Add(newLoopStart);
                newLoopBlock.Body.Add(new ILExpression(GMCode.Push, genVar));
                newLoopBlock.Body.Add(new ILExpression(GMCode.Push, new ILValue(0)));

                newLoopBlock.Body.Add(new ILExpression(GMCode.Sgt, null));
                newLoopBlock.Body.Add(new ILExpression(GMCode.Bf, endLoop, new ILExpression(GMCode.Pop, null)));
                newLoopBlock.Body.Add(new ILExpression(GMCode.B, startLoop));
                head.Body = newHead;
                body.Add(newLoopBlock);
                // Now the hard part, we have to find the end bit
                for (int j = pos; j < body.Count; j++)
                {
                    ILBasicBlock bj = body[j] as ILBasicBlock;
                    ILLabel      testEnd, testStart;
                    ILValue      subPart;
                    int          len = bj.Body.Count;
                    //    Debug.Assert((bj.Body[0] as ILLabel).Name != "L114");
                    if (bj.MatchLastAndBr(GMCode.Bt, out testStart, out filler, out testEnd) &&
                        testEnd == endLoop && testStart == startLoop &&
                        bj.MatchAt(len - 3, GMCode.Dup) &&
                        bj.MatchAt(len - 4, GMCode.Sub) &&
                        bj.MatchAt(len - 5, GMCode.Push, out subPart)
                        )
                    {
                        List <ILNode> list2 = new List <ILNode>();
                        for (int ii = 0; ii <= len - 6; ii++)
                        {
                            list2.Add(bj.Body[ii]);                                   // add the front of it including the sub part
                        }
                        list2.Add(new ILExpression(GMCode.Push, genVar));
                        list2.Add(bj.Body[len - 5]);                         // add the sub part
                        list2.Add(bj.Body[len - 4]);                         // add the sub part
                        list2.Add(new ILExpression(GMCode.Pop, genVar));     // assign it
                        list2.Add(new ILExpression(GMCode.B, newLoopStart)); // branch back to the start
                        bj.Body = list2;                                     // replace
                        break;                                               // all done, let it continue
                    }
                }
                //  Debug.Assert(false); // coudln't find the end block
            }
        }
Example #12
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));
        }
Example #13
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());
        }