Exemplo n.º 1
0
    internal override void AnalyseFlow()
    {
        switch (flowAnalysis)
        {
        case 0:
            break;

        case 1:
            return;

        default:
            throw new Exception("recursive call detected in '"
                                + Name + "'");
        }
        flowAnalysis = 2;
        int n = Code.Length;

        int[] sa = new int[n];
        for (int i = 0; i < n; i++)
        {
            sa[i] = Int32.MinValue;
        }
        sa[0] = 0;
        int[] toExplore = new int[n];
        int   tX = 0, tY = 0;
        int   off = 0;

        int exitSA = Int32.MinValue;
        int mds    = 0;
        int mrs    = 0;

        int maxDepth = 0;

        for (;;)
        {
            Opcode op  = Code[off];
            bool   mft = op.MayFallThrough;
            int    c   = sa[off];
            int    a;
            if (op is OpcodeCall)
            {
                Word w = op.GetReference(TC);
                w.AnalyseFlow();
                SType se = w.StackEffect;
                if (!se.IsKnown)
                {
                    throw new Exception(string.Format(
                                            "call from '{0}' to '{1}'"
                                            + " with unknown stack effect",
                                            Name, w.Name));
                }
                if (se.NoExit)
                {
                    mft = false;
                    a   = 0;
                }
                else
                {
                    a = se.DataOut - se.DataIn;
                }
                mds      = Math.Max(mds, c + w.MaxDataStack);
                mrs      = Math.Max(mrs, w.MaxReturnStack);
                maxDepth = Math.Min(maxDepth, c - se.DataIn);
            }
            else if (op is OpcodeRet)
            {
                if (exitSA == Int32.MinValue)
                {
                    exitSA = c;
                }
                else if (exitSA != c)
                {
                    throw new Exception(string.Format(
                                            "'{0}': exit stack action"
                                            + " mismatch: {1} / {2}"
                                            + " (offset {3})",
                                            Name, exitSA, c, off));
                }
                a = 0;
            }
            else
            {
                a   = op.StackAction;
                mds = Math.Max(mds, c + a);
            }
            c       += a;
            maxDepth = Math.Min(maxDepth, c);

            int j = op.JumpDisp;
            if (j != 0)
            {
                j += off + 1;
                toExplore[tY++] = j;
                MergeSA(sa, j, c);
            }
            off++;
            if (!mft || !MergeSA(sa, off, c))
            {
                if (tX < tY)
                {
                    off = toExplore[tX++];
                }
                else
                {
                    break;
                }
            }
        }

        maxDataStack   = mds;
        maxReturnStack = 1 + NumLocals + mrs;

        /*
         * TODO: see about this warning. Usage of a 'fail'
         * word (that does not exit) within a 'case..endcase'
         * structure will make an unreachable opcode. In a future
         * version we might want to automatically remove dead
         * opcodes.
         * for (int i = 0; i < n; i ++) {
         *      if (sa[i] == Int32.MinValue) {
         *              Console.WriteLine("warning: word '{0}',"
         + " offset {1}: unreachable opcode",
         +                      Name, i);
         +              continue;
         +      }
         + }
         */

        SType computed;

        if (exitSA == Int32.MinValue)
        {
            computed = new SType(-maxDepth, -1);
        }
        else
        {
            computed = new SType(-maxDepth, -maxDepth + exitSA);
        }

        if (StackEffect.IsKnown)
        {
            if (!computed.IsSubOf(StackEffect))
            {
                throw new Exception(string.Format(
                                        "word '{0}':"
                                        + " computed stack effect {1}"
                                        + " does not match declared {2}",
                                        Name, computed.ToString(),
                                        StackEffect.ToString()));
            }
        }
        else
        {
            StackEffect = computed;
        }

        flowAnalysis = 1;
    }