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; }