Esempio n. 1
0
        public void TestMoveTo()
        {
            var stack = CreateOrderedStack(3);
            var other = new EvaluationStack(new ReferenceCounter());

            stack.MoveTo(other, 0);

            Assert.AreEqual(3, stack.Count);
            Assert.AreEqual(0, other.Count);
            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray());

            stack.MoveTo(other, -1);

            Assert.AreEqual(0, stack.Count);
            Assert.AreEqual(3, other.Count);
            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, other.ToArray());

            // Test IEnumerable

            var enumerable = (IEnumerable)other;
            var enumerator = enumerable.GetEnumerator();

            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, GetEnumerable(enumerator).Cast <Integer>().ToArray());

            other.MoveTo(stack, 2);

            Assert.AreEqual(2, stack.Count);
            Assert.AreEqual(1, other.Count);

            CollectionAssert.AreEqual(new Integer[] { 2, 3 }, stack.ToArray());
            CollectionAssert.AreEqual(new Integer[] { 1 }, other.ToArray());
        }
Esempio n. 2
0
        private bool CheckArraySize(OpCode nextInstruction)
        {
            int size;

            switch (nextInstruction)
            {
            case OpCode.PACK:
            case OpCode.NEWARRAY:
            case OpCode.NEWSTRUCT:
            {
                if (EvaluationStack.Count == 0)
                {
                    return(false);
                }
                size = (int)EvaluationStack.Peek().GetBigInteger();
            }
            break;

            case OpCode.SETITEM:
            {
                if (EvaluationStack.Count < 3)
                {
                    return(false);
                }
                if (!(EvaluationStack.Peek(2) is Map map))
                {
                    return(true);
                }
                StackItem key = EvaluationStack.Peek(1);
                if (key is ICollection)
                {
                    return(false);
                }
                if (map.ContainsKey(key))
                {
                    return(true);
                }
                size = map.Count + 1;
            }
            break;

            case OpCode.APPEND:
            {
                if (EvaluationStack.Count < 2)
                {
                    return(false);
                }
                if (!(EvaluationStack.Peek(1) is Array array))
                {
                    return(false);
                }
                size = array.Count + 1;
            }
            break;

            default:
                return(true);
            }
            return(size <= MaxArraySize);
        }
Esempio n. 3
0
        private bool CheckArraySize()
        {
            const uint MaxArraySize = 1024;

            if (CurrentContext.InstructionPointer >= CurrentContext.Script.Length)
            {
                return(true);
            }
            OpCode opcode = CurrentContext.NextInstruction;

            switch (opcode)
            {
            case OpCode.PACK:
            case OpCode.NEWARRAY:
            {
                if (EvaluationStack.Count == 0)
                {
                    return(false);
                }
                int size = (int)EvaluationStack.Peek().GetBigInteger();
                if (size > MaxArraySize)
                {
                    return(false);
                }
                return(true);
            }

            default:
                return(true);
            }
        }
Esempio n. 4
0
 public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
 {
     var type = ((TypeILInstructionParameter)parameter).Type;
     CheckNotEmpty(il, stack, () => "In order to perform the 'ldind' instruction load an address onto the evaluation stack");
     var esType = stack.Pop();
     CheckIsAPointer(il, esType);
     var pointer = esType.ToType();
     if (pointer.IsByRef)
     {
         var elementType = pointer.GetElementType();
         if (elementType.IsValueType)
             CheckCanBeAssigned(il, type.MakeByRefType(), pointer);
         else
             CheckCanBeAssigned(il, type, elementType);
     }
     else if (pointer.IsPointer)
     {
         var elementType = pointer.GetElementType();
         if (elementType.IsValueType)
             CheckCanBeAssigned(il, type.MakePointerType(), pointer);
         else
             CheckCanBeAssigned(il, type, elementType);
     }
     else if (!type.IsPrimitive && type != typeof(object))
         ThrowError(il, $"Unable to load an instance of type '{Formatter.Format(type)}' from a pointer of type '{Formatter.Format(pointer)}' indirectly");
     stack.Push(type);
 }
Esempio n. 5
0
    static void Run(AssemblyHolder holder, string[] cmdLine)
    {
        try
        {
            EvaluationStack stack = new EvaluationStack();
            stack.Push(new ObjectReferenceValue(cmdLine));

            ParameterValues paramVals = stack.Perform_CallMethod(holder.Assembly.EntryPoint,false);

            Exception exc;
            IntVisitor.InterpretMethod(holder,holder.EntryPoint,paramVals,out exc,"");

            if (exc != null)
            {
                Console.WriteLine(
                    "-------------------------\n"+
                    "CIL interpreter catched unhandled exception:\n"+
                    exc
                    );
            }

            Console.WriteLine("-------------------------\nPress Enter...");
            Console.ReadLine();
        }
        catch (ConvertionException)
        {
            Console.WriteLine("Conversion to CFG failed !");
        }
    }
Esempio n. 6
0
        public void TestCopyTo()
        {
            var stack = CreateOrderedStack(3);
            var copy  = new EvaluationStack(new ReferenceCounter());

            Assert.ThrowsException <ArgumentOutOfRangeException>(() => stack.CopyTo(copy, -2));
            Assert.ThrowsException <ArgumentOutOfRangeException>(() => stack.CopyTo(copy, 4));

            stack.CopyTo(copy, 0);

            Assert.AreEqual(3, stack.Count);
            Assert.AreEqual(0, copy.Count);
            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray());

            stack.CopyTo(copy, -1);

            Assert.AreEqual(3, stack.Count);
            Assert.AreEqual(3, copy.Count);
            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray());

            // Test IEnumerable

            var enumerable = (IEnumerable)copy;
            var enumerator = enumerable.GetEnumerator();

            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, GetEnumerable(enumerator).Cast <Integer>().ToArray());

            copy.CopyTo(stack, 2);

            Assert.AreEqual(5, stack.Count);
            Assert.AreEqual(3, copy.Count);

            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3, 2, 3 }, stack.ToArray());
            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, copy.ToArray());
        }
Esempio n. 7
0
 public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
 {
     if (stack.Count != 0)
     {
         throw new InvalidOperationException("The evaluation stack must be empty in order to perform the 'jmp' instruction\r\n" + il.GetILCode());
     }
 }
Esempio n. 8
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            var type = ((TypeILInstructionParameter)parameter).Type;

            CheckNotEmpty(il, stack, () => "In order to perform the 'newarr' instruction a length of an array must be loaded onto the evaluation stack");
            CheckCanBeAssigned(il, typeof(int), stack.Pop());
            stack.Push(type.MakeArrayType());
        }
Esempio n. 9
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            var type = ((TypeILInstructionParameter)parameter).Type;

            CheckNotEmpty(il, stack, () => "An object must be put onto the evaluation stack in order to perform the 'unbox_any' instruction");
            CheckCanBeAssigned(il, typeof(object), stack.Pop());
            stack.Push(type);
        }
Esempio n. 10
0
        /// <summary>
        /// Assert result stack
        /// </summary>
        /// <param name="stack">Stack</param>
        /// <param name="result">Result</param>
        /// <param name="message">Message</param>
        private void AssertResult(VMUTStackItem[] result, EvaluationStack stack, string message)
        {
            AssertAreEqual(stack.Count, result == null ? 0 : result.Length, message + "Stack is different");

            for (int x = 0, max = stack.Count; x < max; x++)
            {
                AssertAreEqual(ItemToJson(stack.Peek(x)).ToString(Formatting.None), PrepareJsonItem(result[x]).ToString(Formatting.None), message + "Stack item is different");
            }
        }
Esempio n. 11
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            CheckNotEmpty(il, stack, () => "In order to perform the 'ckfinite' instruction an instance must be loaded onto the evaluation stack");
            var peek = stack.Peek();

            if (ToCLIType(peek) != CLIType.Float)
            {
                ThrowError(il, $"It is only allowed to check if value is finite for floating point values but was '{peek}'");
            }
        }
Esempio n. 12
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            CheckNotEmpty(il, stack, () => $"In order to perform the instruction 'localloc' size must be loaded onto the evaluation stack");
            var type = stack.Pop();

            if (ToCLIType(type) != CLIType.NativeInt)
            {
                ThrowError(il, $"Unable to perform the instruction 'localloc' on type '{type}'");
            }
            stack.Push(typeof(UIntPtr));
        }
Esempio n. 13
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            var labels = ((LabelsILInstructionParameter)parameter).Labels;

            CheckNotEmpty(il, stack, () => "A value must be put onto the evaluation stack in order to perform the 'switch' instruction");
            CheckNotStruct(il, stack.Pop());
            foreach (var label in labels)
            {
                SaveOrCheck(il, stack, label);
            }
        }
Esempio n. 14
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            CheckNotEmpty(il, stack, () => $"In order to perform the instruction '{opCode}' an instance must be loaded onto the evaluation stack");
            var type = stack.Pop();

            if (!Allowed(type))
            {
                ThrowError(il, $"Unable to perform the instruction '{opCode}' on type '{type}'");
            }
            stack.Push(to);
        }
Esempio n. 15
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            CheckNotEmpty(il, stack, () => "In order to perform the 'neg' operation an instance must be put onto the evaluation stack");
            var esType  = stack.Pop();
            var cliType = ToCLIType(esType);

            if (cliType != CLIType.Int32 && cliType != CLIType.Int64 && cliType != CLIType.NativeInt && cliType != CLIType.Float && cliType != CLIType.Zero)
            {
                ThrowError(il, $"Unable to perform the 'neg' operation on type '{esType}'");
            }
            stack.Push(Canonize(esType));
        }
Esempio n. 16
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            CheckNotEmpty(il, stack, () => "In order to perform the 'ldlen' instruction an array must be loaded onto the evaluation stack");
            var esType = stack.Pop();
            var array  = esType.ToType();

            if (!array.IsArray && array != typeof(Array))
            {
                ThrowError(il, string.Format("An array expected but was '{0}'", esType));
            }
            stack.Push(typeof(int));
        }
Esempio n. 17
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            var constructor    = ((ConstructorILInstructionParameter)parameter).Constructor;
            var parameterTypes = ReflectionExtensions.GetParameterTypes(constructor);

            for (var i = parameterTypes.Length - 1; i >= 0; --i)
            {
                CheckNotEmpty(il, stack, () => $"Expected exactly {parameterTypes.Length} parameters to call the constructor '{Formatter.Format(constructor)}'");
                CheckCanBeAssigned(il, parameterTypes[i], stack.Pop());
            }
            stack.Push(constructor.ReflectedType);
        }
Esempio n. 18
0
        protected virtual long GetPrice()
        {
            if (CurrentContext.InstructionPointer >= CurrentContext.Script.Length)
            {
                return(0);
            }
            OpCode opcode = CurrentContext.NextInstruction;

            if (opcode <= OpCode.PUSH16)
            {
                return(0);
            }
            switch (opcode)
            {
            case OpCode.NOP:
                return(0);

            case OpCode.APPCALL:
            case OpCode.TAILCALL:
                return(10);

            case OpCode.SYSCALL:
                return(GetPriceForSysCall());

            case OpCode.SHA1:
            case OpCode.SHA256:
                return(10);

            case OpCode.HASH160:
            case OpCode.HASH256:
                return(20);

            case OpCode.CHECKSIG:
                return(100);

            case OpCode.CHECKMULTISIG:
            {
                if (EvaluationStack.Count == 0)
                {
                    return(1);
                }
                int n = (int)EvaluationStack.Peek().GetBigInteger();
                if (n < 1)
                {
                    return(1);
                }
                return(100 * n);
            }

            default: return(1);
            }
        }
Esempio n. 19
0
        private bool CheckItemSize()
        {
            const uint MaxItemSize = 1024 * 1024;

            if (CurrentContext.InstructionPointer >= CurrentContext.Script.Length)
            {
                return(true);
            }
            OpCode opcode = CurrentContext.NextInstruction;

            switch (opcode)
            {
            case OpCode.PUSHDATA4:
            {
                if (CurrentContext.InstructionPointer + 4 >= CurrentContext.Script.Length)
                {
                    return(false);
                }
                uint length = CurrentContext.Script.ToUInt32(CurrentContext.InstructionPointer + 1);
                if (length > MaxItemSize)
                {
                    return(false);
                }
                return(true);
            }

            case OpCode.CAT:
            {
                if (EvaluationStack.Count < 2)
                {
                    return(false);
                }
                int length;
                try
                {
                    length = EvaluationStack.Peek(0).GetByteArray().Length + EvaluationStack.Peek(1).GetByteArray().Length;
                }
                catch (NotSupportedException)
                {
                    return(false);
                }
                if (length > MaxItemSize)
                {
                    return(false);
                }
                return(true);
            }

            default:
                return(true);
            }
        }
Esempio n. 20
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            CheckNotEmpty(il, stack, () => "In order to perform the 'not' operation an instance must be put onto the evaluation stack");
            var esType  = stack.Pop();
            var cliType = ToCLIType(esType);

            if (cliType != CLIType.Int32 && cliType != CLIType.Int64 && cliType != CLIType.NativeInt && cliType != CLIType.Zero)
            {
                ThrowError(il, string.Format("Unable to perform the 'not' operation on type '{0}'", esType));
            }
            // !zero = -1 -> native int
            stack.Push(cliType == CLIType.Zero ? typeof(IntPtr) : Canonize(esType));
        }
Esempio n. 21
0
        private void StartImportingBasicBlock(BasicBlock basicBlock)
        {
            _stack.Clear();

            if (basicBlock.EntryStack != null)
            {
                EvaluationStack <StackEntry> entryStack = basicBlock.EntryStack;
                int n = entryStack.Length;
                for (int i = 0; i < n; i++)
                {
                    _stack.Push(entryStack[i].Duplicate());
                }
            }
        }
Esempio n. 22
0
 public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
 {
     if (parameter is TypeILInstructionParameter)
     {
         stack.Push(typeof(RuntimeTypeHandle));
     }
     if (parameter is MethodILInstructionParameter)
     {
         stack.Push(typeof(RuntimeMethodHandle));
     }
     if (parameter is FieldILInstructionParameter)
     {
         stack.Push(typeof(RuntimeFieldHandle));
     }
 }
Esempio n. 23
0
        EvaluationStack CreateOrderedStack(int count)
        {
            var check = new Integer[count];
            var stack = new EvaluationStack(new ReferenceCounter());

            for (int x = 1; x <= count; x++)
            {
                stack.Push(x);
                check[x - 1] = x;
            }

            Assert.AreEqual(count, stack.Count);
            CollectionAssert.AreEqual(check, stack.ToArray());

            return(stack);
        }
Esempio n. 24
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            var elementType = ((TypeILInstructionParameter)parameter).Type;

            CheckNotEmpty(il, stack, () => "In order to perform the 'ldelema' instruction an index must be put onto the evaluation stack");
            CheckCanBeAssigned(il, typeof(int), stack.Pop());
            CheckNotEmpty(il, stack, () => "In order to perform the 'ldelema' instruction an array must be put onto the evaluation stack");
            var esType = stack.Pop();
            var array  = esType.ToType();

            if (!array.IsArray && array != typeof(Array))
            {
                throw new InvalidOperationException(string.Format("An array expected to perform the 'ldelema' instruction but was '{0}'", esType));
            }
            stack.Push(elementType.MakeByRefType());
        }
Esempio n. 25
0
        private bool CheckStackSize(OpCode nextInstruction)
        {
            int size = 0;

            if (nextInstruction <= OpCode.PUSH16)
            {
                size = 1;
            }
            else
            {
                switch (nextInstruction)
                {
                case OpCode.DEPTH:
                case OpCode.DUP:
                case OpCode.OVER:
                case OpCode.TUCK:
                {
                    size = 1;
                    break;
                }

                case OpCode.UNPACK:
                {
                    StackItem item = EvaluationStack.Peek();
                    if (!(item is Neo.VM.Types.Array ar))
                    {
                        return(false);
                    }

                    size = ar.Count;
                    break;
                }
                }
            }

            if (size == 0)
            {
                return(true);
            }
            size += EvaluationStack.Count + AltStack.Count;
            if (size > MaxStackSize)
            {
                return(false);
            }

            return(true);
        }
Esempio n. 26
0
        protected virtual long GetPrice(OpCode nextInstruction)
        {
            TR.Enter();
            if (nextInstruction <= OpCode.PUSH16)
            {
                return(TR.Exit(0));
            }
            switch (nextInstruction)
            {
            case OpCode.NOP:
                return(TR.Exit(0));

            case OpCode.APPCALL:
            case OpCode.TAILCALL:
                return(TR.Exit(10));

            case OpCode.SYSCALL:
                return(TR.Exit(GetPriceForSysCall()));

            case OpCode.SHA1:
            case OpCode.SHA256:
                return(TR.Exit(10));

            case OpCode.HASH160:
            case OpCode.HASH256:
                return(TR.Exit(20));

            case OpCode.CHECKSIG:
                return(TR.Exit(100));

            case OpCode.CHECKMULTISIG:
            {
                if (EvaluationStack.Count == 0)
                {
                    return(TR.Exit(1));
                }
                int n = (int)EvaluationStack.Peek().GetBigInteger();
                if (n < 1)
                {
                    return(TR.Exit(1));
                }
                return(TR.Exit(100 * n));
            }

            default: return(TR.Exit(1));
            }
        }
Esempio n. 27
0
        private bool CheckStackSize()
        {
            const uint MaxStackSize = 2 * 1024;

            if (CurrentContext.InstructionPointer >= CurrentContext.Script.Length)
            {
                return(true);
            }
            int    size   = 0;
            OpCode opcode = CurrentContext.NextInstruction;

            if (opcode <= OpCode.PUSH16)
            {
                size = 1;
            }
            else
            {
                switch (opcode)
                {
                case OpCode.DEPTH:
                case OpCode.DUP:
                case OpCode.OVER:
                case OpCode.TUCK:
                    size = 1;
                    break;

                case OpCode.UNPACK:
                    StackItem item = EvaluationStack.Peek();
                    if (!item.IsArray)
                    {
                        return(false);
                    }
                    size = item.GetArray().Length;
                    break;
                }
            }
            if (size == 0)
            {
                return(true);
            }
            size += EvaluationStack.Count + AltStack.Count;
            if (size > MaxStackSize)
            {
                return(false);
            }
            return(true);
        }
Esempio n. 28
0
        private bool CheckStackSize(OpCode nextInstruction)
        {
            TR.Enter();
            int size = 0;

            if (nextInstruction <= OpCode.PUSH16)
            {
                size = 1;
            }
            else
            {
                switch (nextInstruction)
                {
                case OpCode.DEPTH:
                case OpCode.DUP:
                case OpCode.OVER:
                case OpCode.TUCK:
                case OpCode.NEWMAP:
                    size = 1;
                    break;

                case OpCode.UNPACK:
                    StackItem item = EvaluationStack.Peek();
                    if (item is Array array)
                    {
                        size = array.Count;
                    }
                    else
                    {
                        return(TR.Exit(false));
                    }
                    break;
                }
            }
            if (size == 0)
            {
                return(TR.Exit(true));
            }
            size += EvaluationStack.Count + AltStack.Count;
            if (size > MaxStackSize)
            {
                return(TR.Exit(false));
            }
            return(TR.Exit(true));
        }
Esempio n. 29
0
        public AnnotatedMethod GetAnnotatedMethod(MethodBase sMethod)
        {
            AnnotatedMethod aMethod = this.aMethods[sMethod] as AnnotatedMethod;
            if (aMethod == null)
            {
                ParameterInfo[] parms = sMethod.GetParameters();
                EvaluationStack stack = new EvaluationStack();
                if (! sMethod.IsStatic)
                    stack.Push(new ReferenceBTValue(BTType.Dynamic));
                for (int i = 0; i < parms.Length; i++)
                    stack.Push(new ReferenceBTValue(BTType.Dynamic));
                ParameterValues paramVals = stack.Perform_CallMethod(sMethod, false);
                ReferenceBTValue ret = ReferenceBTValue.NewReferenceBTValue(Annotation.GetReturnType(sMethod), BTType.Dynamic);
                this.aMethods[sMethod] = aMethod = new AnnotatedMethod(paramVals, ret);
            }

            return aMethod;
        }
Esempio n. 30
0
        public void TestInsertPeek()
        {
            var stack = new EvaluationStack(new ReferenceCounter());

            stack.Insert(0, 3);
            stack.Insert(1, 1);
            stack.Insert(1, 2);

            Assert.ThrowsException <InvalidOperationException>(() => stack.Insert(4, 2));

            Assert.AreEqual(3, stack.Count);
            CollectionAssert.AreEqual(new Integer[] { 1, 2, 3 }, stack.ToArray());

            Assert.AreEqual(3, stack.Peek(0));
            Assert.AreEqual(2, stack.Peek(1));
            Assert.AreEqual(1, stack.Peek(-1));

            Assert.ThrowsException <InvalidOperationException>(() => stack.Peek(-4));
        }
Esempio n. 31
0
        public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
        {
            CheckNotEmpty(il, stack, () => $"Expected two arguments for the operation '{opCode}'");
            var right = stack.Pop();

            CheckNotEmpty(il, stack, () => $"Expected two arguments for the operation '{opCode}'");
            var left = stack.Pop();

            if (!IsAllowed(ToCLIType(left), ToCLIType(right)))
            {
                ThrowError(il, $"Cannot perform the instruction '{opCode}' on types '{left}' and '{right}'");
            }
            var result = Canonize(GetResultType(Canonize(left), Canonize(right)));

            if (result != typeof(void))
            {
                stack.Push(result);
            }
            PostAction(il, parameter, ref stack);
        }
Esempio n. 32
0
        private bool CheckStackSize(OpCode nextInstruction)
        {
            int size = 0;

            if (nextInstruction <= OpCode.PUSH16)
            {
                size = 1;
            }
            else
            {
                switch (nextInstruction)
                {
                case OpCode.DEPTH:
                case OpCode.DUP:
                case OpCode.OVER:
                case OpCode.TUCK:
                    size = 1;
                    break;

                case OpCode.UNPACK:
                    StackItem item = EvaluationStack.Peek();
                    if (!item.IsArray)
                    {
                        return(false);
                    }
                    size = item.GetArray().Length;
                    break;
                }
            }
            if (size == 0)
            {
                return(true);
            }
            size += EvaluationStack.Count + AltStack.Count;
            if (size > MaxStackSize)
            {
                return(false);
            }
            return(true);
        }
Esempio n. 33
0
        private void ImportFallthrough(BasicBlock next)
        {
            EvaluationStack<StackEntry> entryStack = next.EntryStack;

            if (entryStack != null)
            {
                if (entryStack.Length != _stack.Length)
                    throw new InvalidProgramException();

                for (int i = 0; i < entryStack.Length; i++)
                {
                    // TODO: Do we need to allow conversions?
                    if (entryStack[i].Kind != _stack[i].Kind)
                        throw new InvalidProgramException();

                    if (entryStack[i].Kind == StackValueKind.ValueType)
                    {
                        if (entryStack[i].Type != _stack[i].Type)
                            throw new InvalidProgramException();
                    }
                }
            }
            else
            {
                if (_stack.Length > 0)
                {
                    entryStack = new EvaluationStack<StackEntry>(_stack.Length);

                    for (int i = 0; i < _stack.Length; i++)
                    {
                        entryStack.Push(NewSpillSlot(_stack[i]));
                    }
                }
                next.EntryStack = entryStack;
            }

            if (entryStack != null)
            {
                for (int i = 0; i < entryStack.Length; i++)
                {
                    AppendLine();
                    Append(entryStack[i]);
                    Append(" = ");
                    Append(_stack[i]);
                    AppendSemicolon();
                }
            }

            MarkBasicBlock(next);
        }