Exemplo n.º 1
0
        private void FollowControlFlowPath(Stack<IExpression> evaluationStack, Instruction instr)
        {
            Stack<IExpression> oldEvaluationStack = _evaluationStack;
            _evaluationStack = evaluationStack;
            try
            {
                CFGNodeCluster cluster;
                if (TryGetMappedCFGNodeCluster(instr, out cluster))
                {
                    return;
                }

                ExceptionHandler handler;
                CFGNode preamble = null;
                if (_handlerStarts.TryGetValue(instr, out handler))
                {
                    if (handler.Type == ExceptionHandlerType.Catch)
                    {
                        preamble = AddNewTemporaryDefinitionNode(new ExceptionExpression());
                    }

                    // TODO: Filter handler type
                }
                switch (instr.OpCode.Code)
                {
                    case Code.Add:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.Add, right));

                            break;
                        }
                    case Code.Add_Ovf:
                        {
                            // TODO: Check overflow
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.Add, right));

                            break;
                        }
                    case Code.And:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.BitwiseAnd, right));

                            break;
                        }
                    case Code.Beq:
                    case Code.Beq_S:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.ValueEquality, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionalBranchExpressionStatement conditionalBranchExpressionStatement = new ConditionalBranchExpressionStatement(StackPop());
                            CFGNode conditionalBranchExpressionStatementNode = AddNode(conditionalBranchExpressionStatement);

                            AddEdge(binaryExpressionNode, conditionalBranchExpressionStatementNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionalBranchExpressionStatementNode;

                            break;
                        }
                    case Code.Bge:
                    case Code.Bge_S:
                    case Code.Bge_Un:
                    case Code.Bge_Un_S:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.GreaterThanOrEqual, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionalBranchExpressionStatement conditionalBranchExpressionStatement = new ConditionalBranchExpressionStatement(StackPop());
                            CFGNode conditionalBranchExpressionStatementNode = AddNode(conditionalBranchExpressionStatement);

                            AddEdge(binaryExpressionNode, conditionalBranchExpressionStatementNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionalBranchExpressionStatementNode;

                            break;
                        }
                    case Code.Bgt:
                    case Code.Bgt_S:
                    case Code.Bgt_Un:
                    case Code.Bgt_Un_S:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.GreaterThan, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionalBranchExpressionStatement conditionalBranchExpressionStatement = new ConditionalBranchExpressionStatement(StackPop());
                            CFGNode conditionalBranchExpressionStatementNode = AddNode(conditionalBranchExpressionStatement);

                            AddEdge(binaryExpressionNode, conditionalBranchExpressionStatementNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionalBranchExpressionStatementNode;

                            break;
                        }
                    case Code.Ble:
                    case Code.Ble_S:
                    case Code.Ble_Un:
                    case Code.Ble_Un_S:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.LessThanOrEqual, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionalBranchExpressionStatement conditionalBranchExpressionStatement = new ConditionalBranchExpressionStatement(StackPop());
                            CFGNode conditionalBranchExpressionStatementNode = AddNode(conditionalBranchExpressionStatement);

                            AddEdge(binaryExpressionNode, conditionalBranchExpressionStatementNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionalBranchExpressionStatementNode;

                            break;
                        }
                    case Code.Blt:
                    case Code.Blt_S:
                    case Code.Blt_Un:
                    case Code.Blt_Un_S:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.LessThan, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionalBranchExpressionStatement conditionalBranchExpressionStatement = new ConditionalBranchExpressionStatement(StackPop());
                            CFGNode conditionalBranchExpressionStatementNode = AddNode(conditionalBranchExpressionStatement);

                            AddEdge(binaryExpressionNode, conditionalBranchExpressionStatementNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionalBranchExpressionStatementNode;

                            break;
                        }
                    case Code.Bne_Un:
                    case Code.Bne_Un_S:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.ValueInequality, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionalBranchExpressionStatement conditionalBranchExpressionStatement = new ConditionalBranchExpressionStatement(StackPop());
                            CFGNode conditionalBranchExpressionStatementNode = AddNode(conditionalBranchExpressionStatement);

                            AddEdge(binaryExpressionNode, conditionalBranchExpressionStatementNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionalBranchExpressionStatementNode;

                            break;
                        }
                    case Code.Box:
                        {
                            IExpression expressionToBox = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BoxExpression(expressionToBox, (TypeReference)instr.Operand));
                            break;
                        }
                    case Code.Br:
                    case Code.Br_S:
                        {
                            // front end flow control takes care of branching
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Brfalse:
                    case Code.Brfalse_S:
                        {
                            // front end flow control takes care of branching
                            cluster = (CFGNodeCluster)AddNode(new ConditionalBranchExpressionStatement(new UnaryExpression(StackPop(), UnaryOperator.BooleanNot)));
                            break;
                        }
                    case Code.Brtrue:
                    case Code.Brtrue_S:
                        {
                            // front end flow control takes care of branching
                            cluster = (CFGNodeCluster)AddNode(new ConditionalBranchExpressionStatement(StackPop()));
                            break;
                        }
                    case Code.Call:
                    case Code.Callvirt:
                        {
                            // TODO: .calli
                            MethodReference methodReference = (MethodReference)instr.Operand;
                            List<IExpression> arguments = new List<IExpression>();
                            for (int i = 0; i < methodReference.Parameters.Count; i++)
                            {
                                arguments.Add(StackPop());
                            }
                            arguments.Reverse();
                            IExpression targetExpression;
                            if (methodReference.HasThis)
                            {
                                targetExpression = StackPop();
                            }
                            else
                            {
                                ITypeReferenceExpression typeReferenceExpression = new TypeReferenceExpression(methodReference.DeclaringType);
                                targetExpression = typeReferenceExpression;
                            }
                            IMethodReferenceExpression methodReferenceExpression = new MethodReferenceExpression(targetExpression, methodReference, instr.OpCode.Name == "callvirt");
                            MethodInvokeExpression methodInvokeExpression = new MethodInvokeExpression(methodReferenceExpression);
                            foreach (IExpression argument in arguments)
                            {
                                methodInvokeExpression.Arguments.Add(argument);
                            }
                            if (CoreTypes.IsVoid(methodReference.ReturnType.ReturnType))
                            {
                                cluster = (CFGNodeCluster)AddNode(new ExpressionStatement(methodInvokeExpression));
                            }
                            else
                            {
                                cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(methodInvokeExpression);
                            }
                            break;
                        }
                    case Code.Castclass:
                        {
                            IExpression expression = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new CastExpression(expression, (TypeReference)instr.Operand));

                            break;
                        }
                    case Code.Ceq:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.ValueEquality, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionExpression conditionExpression = new ConditionExpression(StackPop(), new Int32LiteralExpression(1), new Int32LiteralExpression(0));
                            CFGNode conditionExpressionNode = AddNewTemporaryDefinitionNode(conditionExpression);

                            AddEdge(binaryExpressionNode, conditionExpressionNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionExpressionNode;

                            break;
                        }
                    case Code.Cgt:
                    case Code.Cgt_Un:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.GreaterThan, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionExpression conditionExpression = new ConditionExpression(StackPop(), new Int32LiteralExpression(1), new Int32LiteralExpression(0));
                            CFGNode conditionExpressionNode = AddNewTemporaryDefinitionNode(conditionExpression);

                            AddEdge(binaryExpressionNode, conditionExpressionNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionExpressionNode;

                            break;
                        }
                    case Code.Clt:
                    case Code.Clt_Un:
                        {
                            cluster = new CFGNodeCluster();

                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            BinaryExpression binaryExpression = new BinaryExpression(left, BinaryOperator.LessThan, right);
                            CFGNode binaryExpressionNode = AddNewTemporaryDefinitionNode(binaryExpression);
                            ConditionExpression conditionExpression = new ConditionExpression(StackPop(), new Int32LiteralExpression(1), new Int32LiteralExpression(0));
                            CFGNode conditionExpressionNode = AddNewTemporaryDefinitionNode(conditionExpression);

                            AddEdge(binaryExpressionNode, conditionExpressionNode);

                            cluster.Start = binaryExpressionNode;
                            cluster.End = conditionExpressionNode;

                            break;
                        }
                    case Code.Constrained:
                        {
                            // TODO: .constrained?
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Conv_I4:
                        {
                            IExpression expression = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new CastExpression(expression, CoreTypes.Int32));
                            break;
                        }
                    case Code.Conv_I8:
                        {
                            IExpression expression = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new CastExpression(expression, CoreTypes.Int64));
                            break;
                        }
                    case Code.Conv_R4:
                        {
                            IExpression expression = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new CastExpression(expression, CoreTypes.Single));
                            break;
                        }
                    case Code.Conv_R8:
                        {
                            IExpression expression = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new CastExpression(expression, CoreTypes.Double));
                            break;
                        }
                    case Code.Div:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.Divide, right));

                            break;
                        }
                    case Code.Dup:
                        {
                            IExpression expression = StackPop();

                            cluster = (CFGNodeCluster)AddNewFrozenDefinitionNode(expression);
                            expression = StackPop();
                            StackPush(expression);
                            StackPush(expression);

                            break;
                        }
                    case Code.Endfinally:
                        {
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Isinst:
                        {
                            IExpression expression = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new TryCastExpression(expression, (TypeReference)instr.Operand));
                            break;
                        }
                    case Code.Initobj:
                        {
                            IExpression expression = StackPop();
                            cluster = (CFGNodeCluster)AddNode(new ExpressionStatement(new ObjectInitializeExpression(expression, (TypeReference)instr.Operand)));
                            break;
                        }
                    case Code.Ldarg_0:
                        {
                            if (_body.Method.HasThis)
                            {
                                cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ThisReferenceExpression(_body.Method.DeclaringType));
                            }
                            else
                            {
                                cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArgumentReferenceExpression(_methodDefinition.Parameters[0]));
                            }
                            break;
                        }
                    case Code.Ldarg_1:
                        {
                            int index = _body.Method.HasThis ? 0 : 1;
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArgumentReferenceExpression(_methodDefinition.Parameters[index]));
                            break;
                        }
                    case Code.Ldarg_2:
                        {
                            int index = _body.Method.HasThis ? 1 : 2;
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArgumentReferenceExpression(_methodDefinition.Parameters[index]));
                            break;
                        }
                    case Code.Ldarg_3:
                        {
                            int index = _body.Method.HasThis ? 2 : 3;
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArgumentReferenceExpression(_methodDefinition.Parameters[index]));
                            break;
                        }
                    case Code.Ldarg_S:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArgumentReferenceExpression((ParameterReference)instr.Operand));
                            break;
                        }
                    case Code.Ldarga:
                    case Code.Ldarga_S:
                        {
                            // TODO: box value types?
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArgumentReferenceExpression((ParameterReference)instr.Operand));
                            break;
                        }
                    case Code.Ldc_I4:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression((Int32)instr.Operand));
                            break;
                        }
                    case Code.Ldc_I4_0:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(0));
                            break;
                        }
                    case Code.Ldc_I4_1:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(1));
                            break;
                        }
                    case Code.Ldc_I4_2:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(2));
                            break;
                        }
                    case Code.Ldc_I4_3:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(3));
                            break;
                        }
                    case Code.Ldc_I4_4:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(4));
                            break;
                        }
                    case Code.Ldc_I4_5:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(5));
                            break;
                        }
                    case Code.Ldc_I4_6:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(6));
                            break;
                        }
                    case Code.Ldc_I4_7:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(7));
                            break;
                        }
                    case Code.Ldc_I4_8:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(8));
                            break;
                        }
                    case Code.Ldc_I4_M1:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression(-1));
                            break;
                        }
                    case Code.Ldc_I4_S:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int32LiteralExpression((sbyte)instr.Operand));
                            break;
                        }
                    case Code.Ldc_I8:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Int64LiteralExpression((Int64)instr.Operand));
                            break;
                        }
                    case Code.Ldc_R4:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Float32LiteralExpression((float)instr.Operand));
                            break;
                        }
                    case Code.Ldc_R8:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new Float64LiteralExpression((double)instr.Operand));
                            break;
                        }
                    case Code.Ldelem_Any:
                    case Code.Ldelem_I:
                    case Code.Ldelem_I1:
                    case Code.Ldelem_I2:
                    case Code.Ldelem_I4:
                    case Code.Ldelem_I8:
                    case Code.Ldelem_R4:
                    case Code.Ldelem_R8:
                    case Code.Ldelem_U1:
                    case Code.Ldelem_U2:
                    case Code.Ldelem_U4:
                    case Code.Ldelem_Ref:
                        {
                            IExpression index = this.StackPop();
                            IExpression array = this.StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArrayIndexerExpression(array, index));
                            break;
                        }
                    case Code.Ldelema:
                        {
                            // TODO: box value types?
                            IExpression index = this.StackPop();
                            IExpression array = this.StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArrayIndexerExpression(array, index));
                            break;
                        }
                    case Code.Ldfld:
                        {
                            IExpression target = this.StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new FieldReferenceExpression(target, (FieldReference)instr.Operand));
                            break;
                        }
                    case Code.Ldflda:
                        {
                            // TODO: Not too sure if ldflda is the same as ldfld for us
                            IExpression target = this.StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new FieldReferenceExpression(target, (FieldReference)instr.Operand));
                            break;
                        }
                    case Code.Ldftn:
                        {
                            MethodReference methodReference = (MethodReference)instr.Operand;
                            IExpression target = new TypeReferenceExpression(methodReference.DeclaringType);
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new MethodReferenceExpression(target, methodReference));
                            break;
                        }
                    case Code.Ldind_I:
                    case Code.Ldind_I1:
                    case Code.Ldind_I2:
                    case Code.Ldind_I4:
                    case Code.Ldind_I8:
                    case Code.Ldind_R4:
                    case Code.Ldind_R8:
                    case Code.Ldind_Ref:
                    case Code.Ldind_U1:
                    case Code.Ldind_U2:
                    case Code.Ldind_U4:
                        {
                            // TODO: What is .ldind_X?
                            IExpression target = this.StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(target);
                            break;
                        }
                    case Code.Ldlen:
                        {
                            IExpression target = this.StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArrayLengthExpression(target));
                            break;
                        }
                    case Code.Ldobj:
                        {
                            // TODO: what is ldobj?
                            IExpression target = this.StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(target);
                            break;
                        }
                    case Code.Ldsfld:
                        {
                            FieldReference fieldReference = (FieldReference)instr.Operand;
                            FieldDefinition fieldDefinition = ReferenceResolver.ResolveFieldReference(fieldReference);
                            ITypeReferenceExpression target = new TypeReferenceExpression(fieldDefinition.DeclaringType);
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new FieldReferenceExpression(target, fieldReference));
                            break;
                        }
                    case Code.Ldsflda:
                        {
                            // TOOD: is ldsflda the same as ldsfld
                            FieldReference fieldReference = (FieldReference)instr.Operand;
                            FieldDefinition fieldDefinition = ReferenceResolver.ResolveFieldReference(fieldReference);
                            ITypeReferenceExpression target = new TypeReferenceExpression(fieldDefinition.DeclaringType);
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new AddressOfExpression(new FieldReferenceExpression(target, fieldReference)));
                            break;
                        }
                    case Code.Ldloc_0:
                        {
                            StackPush(new VariableReferenceExpression((VariableReference)_body.Variables[0]));
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Ldloc_1:
                        {
                            StackPush(new VariableReferenceExpression((VariableReference)_body.Variables[1]));
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Ldloc_2:
                        {
                            StackPush(new VariableReferenceExpression((VariableReference)_body.Variables[2]));
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Ldloc_3:
                        {
                            StackPush(new VariableReferenceExpression((VariableReference)_body.Variables[3]));
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Ldloc_S:
                        {
                            StackPush(new VariableReferenceExpression((VariableReference)instr.Operand));
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Ldloca_S:
                        {
                            // TODO: .ldloca?
                            StackPush(new VariableReferenceExpression((VariableReference)instr.Operand));
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Ldnull:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new NullLiteralExpression());
                            break;
                        }
                    case Code.Ldstr:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new StringLiteralExpression((string)instr.Operand));
                            break;
                        }
                    case Code.Ldtoken:
                        {
                            IExpression expression = null;

                            TypeReference typeReference = instr.Operand as TypeReference;
                            if (typeReference != null)
                            {
                                expression = new TypeReferenceExpression(typeReference);
                            }
                            else
                            {
                                FieldReference fieldReference = instr.Operand as FieldReference;
                                if (fieldReference != null)
                                {
                                    // TODO: array init broken here?
                                    Console.WriteLine("ldtoken: " + instr.Operand + "!!!!!!!!!!!!!!!!!!!!!!!!!");
                                    Console.WriteLine("!!!!!!!!!!!!!!!!!!!!!!!!!!!");
                                    expression = new FieldReferenceExpression(new TypeReferenceExpression(fieldReference.DeclaringType), fieldReference);
                                }
                                else
                                {
                                    MethodReference methodReference = instr.Operand as MethodReference;
                                    if (methodReference != null)
                                    {
                                        expression = new MethodReferenceExpression(new TypeReferenceExpression(methodReference.DeclaringType), methodReference);
                                    }
                                }
                            }

                            if (expression == null)
                            {
                                throw new CompilerException("Unable to parse .ldtoken.  Unrecognized operand: " + instr.Operand);
                            }

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(expression);
                            break;
                        }
                    case Code.Leave:
                    case Code.Leave_S:
                        {
                            // TODO: .leave? relevant to exception handling?
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Mul:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.Multiply, right));
                            break;
                        }
                    case Code.Mul_Ovf:
                        {
                            // TODO: check overflow
                            IExpression right = StackPop();
                            IExpression left = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.Multiply, right));
                            break;
                        }
                    case Code.Neg:
                        {
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new UnaryExpression(StackPop(), UnaryOperator.Negate));
                            break;
                        }
                    case Code.Newobj:
                        {
                            MethodReference methodReference = (MethodReference)instr.Operand;
                            List<IExpression> arguments = new List<IExpression>();
                            for (int i = 0; i < methodReference.Parameters.Count; i++)
                            {
                                arguments.Add(StackPop());
                            }
                            arguments.Reverse();
                            ObjectCreateExpression objectCreateExpression = new ObjectCreateExpression(methodReference);
                            foreach (IExpression argument in arguments)
                            {
                                objectCreateExpression.Arguments.Add(argument);
                            }
                            CFGNode start = AddNewTemporaryDefinitionNode(objectCreateExpression);

                            IExpression objectExpression = StackPop();

                            // now call constructor
                            IMethodReferenceExpression methodReferenceExpression = new MethodReferenceExpression(objectExpression, methodReference);
                            MethodInvokeExpression methodInvokeExpression = new MethodInvokeExpression(methodReferenceExpression);
                            foreach (IExpression argument in arguments)
                            {
                                methodInvokeExpression.Arguments.Add(argument);
                            }

                            CFGNode end = AddNode(new ExpressionStatement(methodInvokeExpression));
                            AddEdge(start, end);
                            cluster = new CFGNodeCluster(start, end);

                            StackPush(objectExpression);
                            break;
                        }
                    case Code.Newarr:
                        {
                            IExpression arrayLength = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new ArrayCreateExpression((TypeReference)instr.Operand, arrayLength));
                            break;
                        }
                    case Code.Nop:
                        {
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Or:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.BitwiseOr, right));

                            break;
                        }
                    case Code.Pop:
                        {
                            this.StackPop();
                            cluster = (CFGNodeCluster)AddNode(new NopStatement());
                            break;
                        }
                    case Code.Rem:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.Modulus, right));
                            break;
                        }
                    case Code.Ret:
                        {
                            MethodReturnStatement methodReturnStatement;
                            if (CoreTypes.IsVoid(_body.Method.ReturnType.ReturnType))
                            {
                                methodReturnStatement = new MethodReturnStatement();
                            }
                            else
                            {
                                methodReturnStatement = new MethodReturnStatement(StackPop());
                            }
                            cluster = (CFGNodeCluster)AddNode(methodReturnStatement);
                            break;
                        }
                    case Code.Shl:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.ShiftLeft, right));

                            break;
                        }
                    case Code.Shr:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.ShiftRight, right));

                            break;
                        }
                    case Code.Starg:
                    case Code.Starg_S:
                        {
                            ParameterReference parameter = (ParameterReference)instr.Operand;
                            IArgumentReferenceExpression argumentReferenceExpression = new ArgumentReferenceExpression(parameter);
                            cluster = (CFGNodeCluster)AddNode(new AssignStatement(argumentReferenceExpression, StackPop()));
                            break;
                        }
                    case Code.Stelem_Any:
                    case Code.Stelem_I:
                    case Code.Stelem_I1:
                    case Code.Stelem_I2:
                    case Code.Stelem_I4:
                    case Code.Stelem_I8:
                    case Code.Stelem_R4:
                    case Code.Stelem_R8:
                    case Code.Stelem_Ref:
                        {
                            IExpression value = this.StackPop();
                            IExpression index = this.StackPop();
                            IExpression array = this.StackPop();
                            cluster = (CFGNodeCluster)AddNode(new AssignStatement(new ArrayIndexerExpression(array, index), value));
                            break;
                        }
                    case Code.Stfld:
                        {
                            IExpression expression = this.StackPop();
                            IExpression target = this.StackPop();
                            FieldReference fieldReference = (FieldReference)instr.Operand;
                            cluster = (CFGNodeCluster)AddNode(new AssignStatement(new FieldReferenceExpression(target, fieldReference), expression));
                            break;
                        }
                    case Code.Stind_Ref:
                        {
                            // TODO: what is .stind_X?
                            IExpression value = this.StackPop();
                            IExpression address = this.StackPop();
                            cluster = (CFGNodeCluster)AddNode(new AssignStatement(address, value));
                            break;
                        }
                    case Code.Stsfld:
                        {
                            FieldReference fieldReference = (FieldReference)instr.Operand;
                            cluster = (CFGNodeCluster)AddNode(new AssignStatement(new FieldReferenceExpression(new TypeReferenceExpression(fieldReference.DeclaringType), fieldReference), StackPop()));
                            break;
                        }
                    case Code.Stloc_0:
                        {
                            IExpression expression = StackPop();
                            VariableReference variable = _body.Variables[0];
                            cluster = (CFGNodeCluster)AddNode(new Definition(variable, expression));
                            break;
                        }
                    case Code.Stloc_1:
                        {
                            IExpression expression = StackPop();
                            VariableReference variable = _body.Variables[1];
                            cluster = (CFGNodeCluster)AddNode(new Definition(variable, expression));
                            break;
                        }
                    case Code.Stloc_2:
                        {
                            IExpression expression = StackPop();
                            VariableReference variable = _body.Variables[2];
                            cluster = (CFGNodeCluster)AddNode(new Definition(variable, expression));
                            break;
                        }
                    case Code.Stloc_3:
                        {
                            IExpression expression = StackPop();
                            VariableReference variable = _body.Variables[3];
                            cluster = (CFGNodeCluster)AddNode(new Definition(variable, expression));
                            break;
                        }
                    case Code.Stloc_S:
                        {
                            IExpression expression = StackPop();
                            VariableReference variable = (VariableReference)instr.Operand;
                            cluster = (CFGNodeCluster)AddNode(new Definition(variable, expression));
                            break;
                        }
                    case Code.Stobj:
                        {
                            IExpression value = this.StackPop();
                            IExpression address = this.StackPop();
                            cluster = (CFGNodeCluster)AddNode(new AssignStatement(address, value));
                            break;
                        }
                    case Code.Sub:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.Subtract, right));

                            break;
                        }
                    case Code.Sub_Ovf:
                        {
                            // TODO: Check overflow
                            IExpression right = StackPop();
                            IExpression left = StackPop();

                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.Subtract, right));

                            break;
                        }
                    case Code.Throw:
                        {
                            IExpression expression = StackPop();
                            cluster = (CFGNodeCluster)AddNode(new ThrowExceptionStatement(expression));
                            break;
                        }
                    case Code.Unbox:
                    case Code.Unbox_Any:
                        {
                            // TODO: unbox.any?
                            IExpression expressionToBox = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new UnboxExpression(expressionToBox, (TypeReference)instr.Operand));
                            break;
                        }
                    case Code.Xor:
                        {
                            IExpression right = StackPop();
                            IExpression left = StackPop();
                            cluster = (CFGNodeCluster)AddNewTemporaryDefinitionNode(new BinaryExpression(left, BinaryOperator.BitwiseExclusiveOr, right));
                            break;
                        }
                    default:
                        {
                            throw new CompilerException("Invalid opcode: " + instr.OpCode);
                        }
                }
                Debug.Assert(cluster.Start != null);
                if (preamble != null)
                {
                    AddEdge(preamble, cluster.Start);
                    cluster.Start = preamble;
                    if (DebugSettings.FrontEndGraph)
                    {
                        new XaeiO.Compiler.Helpers.CFGRenderer(_cfg, _methodCompileInfo).Render("frontend-added-preamble.png");
                    }
                }
                MapInstruction(instr, cluster);
                Mono.Cecil.Cil.FlowControl flowControl = instr.OpCode.FlowControl;
                switch (flowControl)
                {
                    case Mono.Cecil.Cil.FlowControl.Next:
                    case Mono.Cecil.Cil.FlowControl.Call:
                        {
                            //FollowControlFlowPath(new Stack<IExpression>(_evaluationStack), instr.Next, cluster);
                            FollowControlFlowPath(_evaluationStack, instr.Next, cluster);
                            return;
                        }
                    case Mono.Cecil.Cil.FlowControl.Branch:
                        {
                            FollowControlFlowPath(_evaluationStack, (Instruction)instr.Operand, cluster);
                            return;
                        }
                    case Mono.Cecil.Cil.FlowControl.Cond_Branch:
                        {
                            Instruction instr1 = instr.Next;
                            Instruction instr2 = (Instruction)instr.Operand;
                            FollowControlFlowPath(_evaluationStack, instr1, cluster);
                            FollowControlFlowPath(_evaluationStack, instr2, cluster);
                            return;
                        }
                    case Mono.Cecil.Cil.FlowControl.Return:
                    case Mono.Cecil.Cil.FlowControl.Throw:
                        {
                            instr = null;
                            break;
                        }
                    default:
                        {
                            throw new CompilerException("Invalid FlowControl");
                        }
                }
            }
            finally
            {
                _evaluationStack = oldEvaluationStack;
            }
        }
        /// <summary>
        /// Merges multiple catch handler into one catch handler with if/then/else logic for the different exception types/filter expressions
        /// Also sets up finally blocks to rethrow the exception that caused the finally block to be executed.
        /// </summary>
        private void BuildConsolidatedCatchBlocksAndFinallyBlocks()
        {
            foreach (TryBlockInfo tryBlockInfo in _methodCompileInfo.TryBlockInfos)
            {
                // search through all the handlers of this TryBlockInfo looking for catch handlers to consolidate
                List<KeyValuePair<CFGNodeCluster, ExceptionHandler>> catchHandlersToConsolidate = new List<KeyValuePair<CFGNodeCluster, ExceptionHandler>>();
                foreach (KeyValuePair<CFGNodeCluster, ExceptionHandler> handlerInfo in tryBlockInfo.Handlers)
                {
                    if (handlerInfo.Value.Type == ExceptionHandlerType.Catch)
                    {
                        catchHandlersToConsolidate.Add(handlerInfo);
                    }
                    if (handlerInfo.Value.Type == ExceptionHandlerType.Fault || handlerInfo.Value.Type == ExceptionHandlerType.Filter)
                    {
                        throw new NotImplementedException("Fault and Filter exception handler types are not yet supported");
                    }
                }
                if (catchHandlersToConsolidate.Count > 0)
                {
                    // TODO: Save the exception type so that we can do exception handling optimizations in the future
                    CFGNodeCluster consolidatedCatchBlock = new CFGNodeCluster();

                    // create a node to start the consolidated catch block
                    // this variable will also be the node that each exception handler node points to if it's type doesn't match the thrown exception
                    CFGNode previousExceptionHandlingNode = _methodCompileInfo.CFG.AddNode();
                    previousExceptionHandlingNode.AddDebugInfo("Start consolidated catch block");
                    previousExceptionHandlingNode.FlowControl = FlowControl.Branch;
                    consolidatedCatchBlock.Start = previousExceptionHandlingNode;

                    foreach (KeyValuePair<CFGNodeCluster, ExceptionHandler> catchHandlerToConsolidate in catchHandlersToConsolidate)
                    {
                        CFGNode isExceptionTypeNode = _methodCompileInfo.CFG.AddNode();
                        isExceptionTypeNode.FlowControl = FlowControl.ConditionalBranch;
                        ICanCastExpression isExceptionTypeExpression = new CanCastExpression(new FramePropertyReferenceExpression(FrameProperty.Exception), catchHandlerToConsolidate.Value.CatchType);
                        IExpressionStatement isExceptionTypeExpressionStatement = new ConditionalBranchExpressionStatement(isExceptionTypeExpression);
                        isExceptionTypeNode.BasicBlock.Statements.Add(isExceptionTypeExpressionStatement);

                        // if the previous handler couldn't match the exception type, we try this handlers type
                        // so add an edge from the previous handlers type matching failure node, to this type matching node
                        _methodCompileInfo.CFG.AddEdge(previousExceptionHandlingNode, isExceptionTypeNode);

                        // add code to clear frame[ex] after the first node of the catch handler
                        // TODO: Is sucks that rely on the fact that the first node in a catch handler always saves the exception in a temporary variable

                        IAssignStatement clearFrameExStatement = new AssignStatement(new FramePropertyReferenceExpression(FrameProperty.Exception), new NullLiteralExpression());
                        catchHandlerToConsolidate.Key.Start.BasicBlock.Statements.Add(clearFrameExStatement);

                        // branch to the clear frame node and then to the catch handler if the type matches...
                        _methodCompileInfo.CFG.AddEdge(isExceptionTypeNode, catchHandlerToConsolidate.Key.Start, new BranchCondition(BranchConditionType.True, isExceptionTypeExpressionStatement));

                        Debug.Assert(catchHandlerToConsolidate.Key.End.SuccessorCount <= 1, _methodCompileInfo.ToString());

                        if (consolidatedCatchBlock.End == null)
                        {
                            if (catchHandlerToConsolidate.Key.End.SuccessorCount == 0)
                            {
                                consolidatedCatchBlock.End = _methodCompileInfo.CFG.AddNode();
                                consolidatedCatchBlock.End.FlowControl = FlowControl.Return;
                                consolidatedCatchBlock.End.AddDebugInfo("End consolidated catch block");

                                _methodCompileInfo.CFG.AddEdge(catchHandlerToConsolidate.Key.End, consolidatedCatchBlock.End);
                                catchHandlerToConsolidate.Key.End.FlowControl = FlowControl.Branch;
                            }
                            else
                            {
                                consolidatedCatchBlock.End = catchHandlerToConsolidate.Key.End.Successors[0];
                            }
                        }
                        else
                        {
                            if (catchHandlerToConsolidate.Key.End.SuccessorCount == 0)
                            {
                                _methodCompileInfo.CFG.AddEdge(catchHandlerToConsolidate.Key.End, consolidatedCatchBlock.End);
                                catchHandlerToConsolidate.Key.End.FlowControl = FlowControl.Branch;
                            }
                            else
                            {
                                Debug.Assert(catchHandlerToConsolidate.Key.End.Successors[0] == consolidatedCatchBlock.End);
                            }

                        }

                        // branch to the "couldn't match the exception type" node if we couldn't match the exception type
                        previousExceptionHandlingNode = _methodCompileInfo.CFG.AddNode();
                        previousExceptionHandlingNode.FlowControl = FlowControl.Branch;
                        _methodCompileInfo.CFG.AddEdge(isExceptionTypeNode, previousExceptionHandlingNode, new BranchCondition(BranchConditionType.False, isExceptionTypeExpressionStatement));

                        // add some debug info for the CFG renders
                        catchHandlerToConsolidate.Key.Start.AddDebugInfo("Catch handler start");
                        catchHandlerToConsolidate.Key.End.AddDebugInfo("Catch handler end");
                    }

                    Debug.Assert(consolidatedCatchBlock.End != null, _methodCompileInfo.ToString());

                    // create a node that will rethrow the exception if none of the exception types match
                    CFGNode rethrowExceptionNode = _methodCompileInfo.CFG.AddNode();
                    rethrowExceptionNode.BasicBlock.Statements.Add(new ThrowExceptionStatement(new FramePropertyReferenceExpression(FrameProperty.Exception)));
                    rethrowExceptionNode.FlowControl = FlowControl.Throw;

                    // if the last exception handler couldn't match the exception type, we must rethrow.
                    _methodCompileInfo.CFG.AddEdge(previousExceptionHandlingNode, rethrowExceptionNode);

                    tryBlockInfo.ConsolidatedCatchBlock = consolidatedCatchBlock;
                }

                if (tryBlockInfo.FinallyBlock != null)
                {
                    // if an exception caused this finally block to be executed, rethrow that exception at the end of the finally block
                    IBinaryExpression ifAnExceptionExistsBinaryExpression = new BinaryExpression(new FramePropertyReferenceExpression(FrameProperty.Exception), BinaryOperator.IdentityInequality, new NullLiteralExpression());
                    ConditionalBranchExpressionStatement ifAnExpressionExistsConditionalBranchExpressionStatement = new ConditionalBranchExpressionStatement(ifAnExceptionExistsBinaryExpression);

                    CFGNode ifAnExceptionExistsNode = _methodCompileInfo.CFG.AddNode(ifAnExpressionExistsConditionalBranchExpressionStatement);
                    ifAnExceptionExistsNode.FlowControl = FlowControl.ConditionalBranch;

                    CFGNode endNode = _methodCompileInfo.CFG.AddNode();

                    CFGNode anExceptionExistsNode = _methodCompileInfo.CFG.AddNode(new ThrowExceptionStatement(new FramePropertyReferenceExpression(FrameProperty.Exception)));
                    anExceptionExistsNode.FlowControl = FlowControl.Throw;
                    _methodCompileInfo.CFG.AddEdge(ifAnExceptionExistsNode, anExceptionExistsNode, new BranchCondition(BranchConditionType.True, ifAnExpressionExistsConditionalBranchExpressionStatement));

                    _methodCompileInfo.CFG.AddEdge(ifAnExceptionExistsNode, endNode, new BranchCondition(BranchConditionType.False, ifAnExpressionExistsConditionalBranchExpressionStatement));

                    // TODO: abstract this edge removal pattern out into a class
                    endNode.FlowControl = tryBlockInfo.FinallyBlock.End.FlowControl;
                    List<CFGEdge> edgesToRemove = new List<CFGEdge>();
                    foreach (CFGEdge finallyBlockOutEdge in _methodCompileInfo.CFG.OutEdges(tryBlockInfo.FinallyBlock.End))
                    {
                        _methodCompileInfo.CFG.AddEdge(endNode, finallyBlockOutEdge.Target, finallyBlockOutEdge.BranchCondition);
                        edgesToRemove.Add(finallyBlockOutEdge);
                    }
                    foreach (CFGEdge edgeToRemove in edgesToRemove)
                    {
                        _methodCompileInfo.CFG.RemoveEdge(edgeToRemove);
                    }
                    _methodCompileInfo.CFG.AddEdge(tryBlockInfo.FinallyBlock.End, ifAnExceptionExistsNode);

                    tryBlockInfo.FinallyBlock.End.FlowControl = FlowControl.Next;
                    tryBlockInfo.FinallyBlock.End = endNode;

                    tryBlockInfo.FinallyBlock.Start.AddDebugInfo("Finally start");
                    tryBlockInfo.FinallyBlock.End.AddDebugInfo("Finally end");
                }

                Debug.Assert(tryBlockInfo.FinallyBlock != null || tryBlockInfo.ConsolidatedCatchBlock != null);
            }
        }