public static LambdaExpression Decompile(this Delegate @delegate)
        {
            var expression = Decompile(@delegate.Method);

            if (@delegate.Method.IsStatic)
            {
                return(expression);
            }

            var visitor = new ReplaceExpressionVisitor(new Dictionary <Expression, Expression>
            {
                { expression.Parameters[0], Expression.Constant(@delegate.Target) }
            });
            var transformed = visitor.Visit(expression.Body);

            return(Expression.Lambda(transformed, expression.Parameters.Skip(1)));
        }
Esempio n. 2
0
        Expression Process()
        {
            ProcessorState state = null;
            while(states.Count > 0)
            {
                state = states.Peek();

                if(state.RunNext != null)
                {
                    state.RunNext();
                    state.RunNext = null;
                }

                if(state.Instruction != null && state.Instruction != state.Last)
                {
                    Debug.WriteLine(state.Instruction);

                    if (state.Instruction.OpCode == OpCodes.Nop || state.Instruction.OpCode == OpCodes.Break)
                    {
                        //do nothing;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldtoken)
                    {
                        var runtimeHandle = GetRuntimeHandle(state.Instruction.Operand);
                        state.Stack.Push(Expression.Constant(runtimeHandle));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldarg_0)
                    {
                        LdArg(state, 0);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldarg_1)
                    {
                        LdArg(state, 1);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldarg_2)
                    {
                        LdArg(state, 2);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldarg_3)
                    {
                        LdArg(state, 3);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldarg_S || state.Instruction.OpCode == OpCodes.Ldarg || state.Instruction.OpCode == OpCodes.Ldarga || state.Instruction.OpCode == OpCodes.Ldarga_S)
                    {
                        var operand = (ParameterInfo) state.Instruction.Operand;
                        state.Stack.Push(state.Args.Single(x => ((ParameterExpression) x.Expression).Name == operand.Name));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldlen)
                    {
                        var array = state.Stack.Pop();
                        state.Stack.Push(Expression.ArrayLength(array));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldelem ||
                             state.Instruction.OpCode == OpCodes.Ldelem_I ||
                             state.Instruction.OpCode == OpCodes.Ldelem_I1 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_I2 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_I4 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_I8 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_U1 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_U2 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_U4 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_R4 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_R8 ||
                             state.Instruction.OpCode == OpCodes.Ldelem_Ref)
                    {
                        var index = state.Stack.Pop();
                        var array = state.Stack.Pop();
                        state.Stack.Push(Expression.ArrayIndex(array, index));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Stloc_0)
                    {
                        StLoc(state, 0);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Stloc_1)
                    {
                        StLoc(state, 1);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Stloc_2)
                    {
                        StLoc(state, 2);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Stloc_3)
                    {
                        StLoc(state, 3);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Stloc_S ||
                             state.Instruction.OpCode == OpCodes.Stloc)
                    {
                        var operand = (LocalVariableInfo) state.Instruction.Operand;
                        StLoc(state, operand.LocalIndex);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Stelem ||
                             state.Instruction.OpCode == OpCodes.Stelem_I ||
                             state.Instruction.OpCode == OpCodes.Stelem_I1 ||
                             state.Instruction.OpCode == OpCodes.Stelem_I2 ||
                             state.Instruction.OpCode == OpCodes.Stelem_I4 ||
                             state.Instruction.OpCode == OpCodes.Stelem_I8 ||
                             state.Instruction.OpCode == OpCodes.Stelem_R4 ||
                             state.Instruction.OpCode == OpCodes.Stelem_R8 ||
                             state.Instruction.OpCode == OpCodes.Stelem_Ref)
                    {
                        StElem(state);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldnull)
                    {
                        state.Stack.Push(Expression.Constant(null));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldfld || state.Instruction.OpCode == OpCodes.Ldflda)
                    {
                        var instance = state.Stack.Pop();
                        state.Stack.Push(Expression.Field(instance, (FieldInfo) state.Instruction.Operand));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldsfld)
                    {
                        var field = (FieldInfo) state.Instruction.Operand;
                        if (IsCachedAnonymousMethodDelegate(field))
                        {
                            Address address;
                            if (state.Delegates.TryGetValue(field, out address))
                            {
                                state.Stack.Push(address);
                            }
                            else
                            {
                                state.Stack.Push(Expression.Field(null, field));
                            }
                        }
                        else
                        {
                            state.Stack.Push(Expression.Field(null, field));
                        }
                    }
                    else if (state.Instruction.OpCode == OpCodes.Stsfld)
                    {
                        var field = (FieldInfo) state.Instruction.Operand;
                        if (IsCachedAnonymousMethodDelegate(field))
                        {
                            state.Delegates[field] = state.Stack.Pop();
                        }
                        else
                        {
                            var pop = state.Stack.Pop();
                            state.Stack.Push(Expression.Assign(Expression.Field(null, field), pop));
                        }
                    }
                    else if (state.Instruction.OpCode == OpCodes.Stfld)
                    {
                        var value = state.Stack.Pop();
                        var instance = state.Stack.Pop();
                        var field = (FieldInfo)state.Instruction.Operand;
                        var newExpression = instance.Expression as NewExpression;
                        if (newExpression != null)
                        {
                            instance.Expression = Expression.MemberInit(newExpression, Expression.Bind(field, value));
                        }
                        else
                        {
                            var memberInitExpression = instance.Expression as MemberInitExpression;
                            if (memberInitExpression != null)
                            {
                                var expression = memberInitExpression.NewExpression;
                                var bindings = new List<MemberBinding>(memberInitExpression.Bindings) {Expression.Bind(field, value)};
                                instance.Expression = Expression.MemberInit(expression, bindings);
                            }
                            else
                            {
                                throw new NotImplementedException();
                            }
                        }
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldloc_0)
                    {
                        LdLoc(state, 0);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldloc_1)
                    {
                        LdLoc(state, 1);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldloc_2)
                    {
                        LdLoc(state, 2);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldloc_3)
                    {
                        LdLoc(state, 3);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldloc ||
                             state.Instruction.OpCode == OpCodes.Ldloc_S ||
                             state.Instruction.OpCode == OpCodes.Ldloca || 
                             state.Instruction.OpCode == OpCodes.Ldloca_S)
                    {
                        var operand = (LocalVariableInfo) state.Instruction.Operand;
                        LdLoc(state, operand.LocalIndex);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldstr)
                    {
                        state.Stack.Push(Expression.Constant((string) state.Instruction.Operand));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_0)
                    {
                        LdC(state, 0);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_1)
                    {
                        LdC(state, 1);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_2)
                    {
                        LdC(state, 2);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_3)
                    {
                        LdC(state, 3);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_4)
                    {
                        LdC(state, 4);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_5)
                    {
                        LdC(state, 5);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_6)
                    {
                        LdC(state, 6);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_7)
                    {
                        LdC(state, 7);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_8)
                    {
                        LdC(state, 8);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_S)
                    {
                        LdC(state, (sbyte)state.Instruction.Operand);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4_M1)
                    {
                        LdC(state, -1);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I4)
                    {
                        LdC(state, (int)state.Instruction.Operand);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_I8)
                    {
                        LdC(state, (long)state.Instruction.Operand);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_R4)
                    {
                        LdC(state, (float)state.Instruction.Operand);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldc_R8)
                    {
                        LdC(state, (double)state.Instruction.Operand);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Br_S || state.Instruction.OpCode == OpCodes.Br)
                    {
                        state.Instruction = (Instruction) state.Instruction.Operand;
                        continue;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Brfalse ||
                             state.Instruction.OpCode == OpCodes.Brfalse_S)
                    {
                        state.Instruction = ConditionalBranch(state, val => Expression.Equal(val, Default(val.Type)));
                        continue;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Brtrue ||
                             state.Instruction.OpCode == OpCodes.Brtrue_S)
                    {
                        var address = state.Stack.Peek();
                        var memberExpression = address.Expression as MemberExpression;
                        if (memberExpression != null && IsCachedAnonymousMethodDelegate(memberExpression.Member as FieldInfo))
                        {
                            state.Stack.Pop();
                        }
                        else
                        {
                            state.Instruction = ConditionalBranch(state, val => Expression.NotEqual(val, Default(val.Type)));
                            continue;
                        }
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ldftn)
                    {
                        var method = (MethodInfo) state.Instruction.Operand;
                        var decompile = method.Decompile();

                        var obj = state.Stack.Pop();
                        if (!method.IsStatic)
                        {
                            var expressions = new Dictionary<Expression, Expression>
                            {
                                {decompile.Parameters[0], obj}
                            };

                            var body = new ReplaceExpressionVisitor(expressions).Visit(decompile.Body);
                            body = TransparentIdentifierRemovingExpressionVisitor.RemoveTransparentIdentifiers(body);
                            decompile = Expression.Lambda(body, decompile.Parameters.Skip(1));
                        }

                        state.Stack.Push(decompile);
                        state.Instruction = state.Instruction.Next;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Bgt ||
                             state.Instruction.OpCode == OpCodes.Bgt_S ||
                             state.Instruction.OpCode == OpCodes.Bgt_Un ||
                             state.Instruction.OpCode == OpCodes.Bgt_Un_S)
                    {
                        var val1 = state.Stack.Pop();
                        state.Instruction = ConditionalBranch(state, val => Expression.GreaterThan(val, val1));
                        continue;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Bge ||
                             state.Instruction.OpCode == OpCodes.Bge_S ||
                             state.Instruction.OpCode == OpCodes.Bge_Un ||
                             state.Instruction.OpCode == OpCodes.Bge_Un_S)
                    {
                        var val1 = state.Stack.Pop();
                        state.Instruction = ConditionalBranch(state, val => Expression.GreaterThanOrEqual(val, val1));
                        continue;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Blt ||
                             state.Instruction.OpCode == OpCodes.Blt_S ||
                             state.Instruction.OpCode == OpCodes.Blt_Un ||
                             state.Instruction.OpCode == OpCodes.Blt_Un_S)
                    {
                        var val1 = state.Stack.Pop();
                        state.Instruction = ConditionalBranch(state, val => Expression.LessThan(val, val1));
                        continue;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ble ||
                             state.Instruction.OpCode == OpCodes.Ble_S ||
                             state.Instruction.OpCode == OpCodes.Ble_Un ||
                             state.Instruction.OpCode == OpCodes.Ble_Un_S)
                    {
                        var val1 = state.Stack.Pop();
                        state.Instruction = ConditionalBranch(state, val => Expression.LessThanOrEqual(val, val1));
                        continue;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Beq ||
                             state.Instruction.OpCode == OpCodes.Beq_S)
                    {
                        var val1 = state.Stack.Pop();
                        state.Instruction = ConditionalBranch(state, val => AdjustedBinaryExpression(val, val1, ExpressionType.Equal));
                        continue;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Bne_Un ||
                             state.Instruction.OpCode == OpCodes.Bne_Un_S)
                    {
                        var val1 = state.Stack.Pop();
                        state.Instruction = ConditionalBranch(state, val => AdjustedBinaryExpression(val, val1, ExpressionType.NotEqual));
                        continue;
                    }
                    else if (state.Instruction.OpCode == OpCodes.Dup)
                    {
                        state.Stack.Push(state.Stack.Peek());
                    }
                    else if (state.Instruction.OpCode == OpCodes.Pop)
                    {
                        state.Stack.Pop();
                    }
                    else if (state.Instruction.OpCode == OpCodes.Add)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.Add));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Add_Ovf || state.Instruction.OpCode == OpCodes.Add_Ovf_Un)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.AddChecked));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Sub)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.Subtract));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Sub_Ovf || state.Instruction.OpCode == OpCodes.Sub_Ovf_Un)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.SubtractChecked));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Mul)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.Multiply));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Mul_Ovf || state.Instruction.OpCode == OpCodes.Mul_Ovf_Un)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.MultiplyChecked));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Div || state.Instruction.OpCode == OpCodes.Div_Un)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.Divide));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Rem || state.Instruction.OpCode == OpCodes.Rem_Un)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.Modulo));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Xor)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.ExclusiveOr));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Shl)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.LeftShift));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Shr || state.Instruction.OpCode == OpCodes.Shr_Un)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.RightShift));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Neg)
                    {
                        var val = state.Stack.Pop();
                        state.Stack.Push(Expression.Negate(val));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Not)
                    {
                        var val = state.Stack.Pop();
                        state.Stack.Push(Expression.Not(val));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_I)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (int))); // Support x64?
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_I1)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (sbyte)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_I2)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (short)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_I4)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (int)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_I8)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (long)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_U)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (uint))); // Suppot x64?
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_U1)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (byte)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_U2)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (ushort)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_U4)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (uint)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_U8)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, typeof (ulong)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_I || state.Instruction.OpCode == OpCodes.Conv_Ovf_I_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (int))); // Suppot x64?
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_I1 || state.Instruction.OpCode == OpCodes.Conv_Ovf_I1_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (sbyte)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_I2 || state.Instruction.OpCode == OpCodes.Conv_Ovf_I2_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (short)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_I4 || state.Instruction.OpCode == OpCodes.Conv_Ovf_I4_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (int)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_I8 || state.Instruction.OpCode == OpCodes.Conv_Ovf_I8_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (long)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_U || state.Instruction.OpCode == OpCodes.Conv_Ovf_U_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (uint))); // Suppot x64?
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_U1 || state.Instruction.OpCode == OpCodes.Conv_Ovf_U1_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (byte)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_U2 || state.Instruction.OpCode == OpCodes.Conv_Ovf_U2_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (ushort)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_U4 || state.Instruction.OpCode == OpCodes.Conv_Ovf_U4_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (uint)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_Ovf_U8 || state.Instruction.OpCode == OpCodes.Conv_Ovf_U8_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (ulong)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_R4 || state.Instruction.OpCode == OpCodes.Conv_R_Un)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (float)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Conv_R8)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.ConvertChecked(val1, typeof (double)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Castclass)
                    {
                        var val1 = state.Stack.Pop();
                        state.Stack.Push(Expression.Convert(val1, (Type) state.Instruction.Operand));
                    }
                    else if (state.Instruction.OpCode == OpCodes.And)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(Expression.And(val2, val1));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Or)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();
                        state.Stack.Push(Expression.Or(val2, val1));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Newobj)
                    {
                        var constructor = (ConstructorInfo) state.Instruction.Operand;
                        state.Stack.Push(Expression.New(constructor, GetArguments(state, constructor)));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Initobj)
                    {
                        var address = state.Stack.Pop();
                        var type = (Type) state.Instruction.Operand;
                        address.Expression = Default(type);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Newarr)
                    {
                        var operand = (Type) state.Instruction.Operand;
                        var expression = state.Stack.Pop();
                        var size = expression.Expression as ConstantExpression;
                        if (size != null && (int) size.Value == 0) // optimization
                            state.Stack.Push(Expression.NewArrayInit(operand));
                        else
                            state.Stack.Push(Expression.NewArrayBounds(operand, expression));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Box)
                    {
                        state.Stack.Push(Box(state.Stack.Pop(), (Type) state.Instruction.Operand));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Call || state.Instruction.OpCode == OpCodes.Callvirt)
                    {
                        Call(state, (MethodInfo)state.Instruction.Operand);
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ceq)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();

                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.Equal));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Cgt || state.Instruction.OpCode == OpCodes.Cgt_Un)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();

                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.GreaterThan));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Clt || state.Instruction.OpCode == OpCodes.Clt_Un)
                    {
                        var val1 = state.Stack.Pop();
                        var val2 = state.Stack.Pop();

                        state.Stack.Push(AdjustedBinaryExpression(val2, AdjustBooleanConstant(val1, val2.Type), ExpressionType.LessThan));
                    }
                    else if (state.Instruction.OpCode == OpCodes.Isinst)
                    {
                        var val = state.Stack.Pop();
                        if (state.Instruction.Next != null && state.Instruction.Next.OpCode == OpCodes.Ldnull &&
                            state.Instruction.Next.Next != null && state.Instruction.Next.Next.OpCode == OpCodes.Cgt_Un)
                        {
                            state.Stack.Push(Expression.TypeIs(val, (Type) state.Instruction.Operand));
                            state.Instruction = state.Instruction.Next.Next;
                        }
                        else
                        {
                            state.Stack.Push(Expression.TypeAs(val, (Type) state.Instruction.Operand));
                        }
                    }
                    else if (state.Instruction.OpCode == OpCodes.Ret)
                    {
                        states.Pop();
                    }
                    else
                    {
                        Debug.WriteLine("Unhandled!!!");
                    }

                    state.Instruction = state.Instruction.Next;
                }
                else
                {
                    states.Pop();
                }
            }

            return state == null ? Expression.Empty() : state.Final();
        }