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