protected void SaveOrCheck(GroboIL il, EvaluationStack stack, GroboIL.Label label) { ESType[] labelStack; if (!il.labelStacks.TryGetValue(label, out labelStack)) { il.labelStacks.Add(label, stack.Reverse().ToArray()); Propogate(il, il.ilCode.GetLabelLineNumber(label), stack); } else { ESType[] merged; var comparisonResult = CompareStacks(stack.Reverse().ToArray(), labelStack, out merged); switch (comparisonResult) { case StacksComparisonResult.Equal: return; case StacksComparisonResult.Inconsistent: ThrowError(il, string.Format("Inconsistent stack for the label '{0}'{1}Stack #1: {2}{1}Stack #2: {3}", label.Name, Environment.NewLine, stack, new EvaluationStack(labelStack))); break; case StacksComparisonResult.Equivalent: il.labelStacks[label] = merged; Propogate(il, il.ilCode.GetLabelLineNumber(label), new EvaluationStack(merged)); break; } } }
private static void Propogate(GroboIL il, int lineNumber, EvaluationStack stack) { if (lineNumber < 0) { return; } while (true) { var comment = il.ilCode.GetComment(lineNumber); if (comment == null) { break; } var instruction = (ILCode.ILInstruction)il.ilCode.GetInstruction(lineNumber); StackMutatorCollection.Mutate(instruction.OpCode, il, instruction.Parameter, ref stack); if (comment is StackILInstructionComment) { var instructionStack = ((StackILInstructionComment)comment).Stack; ESType[] merged; var comparisonResult = CompareStacks(stack.Reverse().ToArray(), instructionStack, out merged); switch (comparisonResult) { case StacksComparisonResult.Equal: return; case StacksComparisonResult.Inconsistent: ThrowError(il, string.Format("Inconsistent stack for the line {0}{1}Stack #1: {2}{1}Stack #2: {3}", (lineNumber + 1), Environment.NewLine, stack, new EvaluationStack(instructionStack))); break; case StacksComparisonResult.Equivalent: stack = new EvaluationStack(merged); break; } } il.ilCode.SetComment(lineNumber, new StackILInstructionComment(stack.Reverse().ToArray())); ++lineNumber; } }