Example #1
0
		/// <summary>
		/// Inlines 'expr' into 'next', if possible.
		/// </summary>
		public static bool InlineIfPossible(ILExpression expr, ILNode next, ILBlock method)
		{
			if (expr.Code != ILCode.Stloc)
				throw new ArgumentException("expr must be stloc");
			// ensure the variable is accessed only a single time
			if (method.GetSelfAndChildrenRecursive<ILExpression>().Count(e => e != expr && e.Operand == expr.Operand) != 1)
				return false;
			ILExpression parent;
			int pos;
			if (FindLoadInNext(next as ILExpression, (ILVariable)expr.Operand, out parent, out pos) == true) {
				parent.Arguments[pos] = expr.Arguments[0];
				return true;
			}
			return false;
		}
Example #2
0
		/// <summary>
		/// Finds the position to inline to.
		/// </summary>
		/// <returns>true = found; false = cannot continue search; null = not found</returns>
		static bool? FindLoadInNext(ILExpression expr, ILVariable v, out ILExpression parent, out int pos)
		{
			parent = null;
			pos = 0;
			if (expr == null)
				return false;
			for (int i = 0; i < expr.Arguments.Count; i++) {
				ILExpression arg = expr.Arguments[i];
				if (arg.Code == ILCode.Ldloc && arg.Operand == v) {
					parent = expr;
					pos = i;
					return true;
				}
				bool? r = FindLoadInNext(arg, v, out parent, out pos);
				if (r != null)
					return r;
			}
			return IsWithoutSideEffects(expr.Code) ? (bool?)null : false;
		}
Example #3
0
 static string GetNameFromExpression(ILExpression expr)
 {
     switch (expr.Code) {
         case ILCode.Ldfld:
             // Use the field name only if it's not a field on this (avoid confusion between local variables and fields)
             if (!(expr.Arguments[0].Code == ILCode.Ldarg && ((ParameterDefinition)expr.Arguments[0].Operand).Index < 0))
                 return ((FieldReference)expr.Operand).Name;
             break;
         case ILCode.Ldsfld:
             return ((FieldReference)expr.Operand).Name;
         case ILCode.Call:
         case ILCode.Callvirt:
             MethodReference mr = (MethodReference)expr.Operand;
             if (mr.Name.StartsWith("get_", StringComparison.Ordinal))
                 return CleanUpVariableName(mr.Name.Substring(4));
             else if (mr.Name.StartsWith("Get", StringComparison.Ordinal) && mr.Name.Length >= 4 && char.IsUpper(mr.Name[3]))
                 return CleanUpVariableName(mr.Name.Substring(3));
             break;
     }
     return null;
 }
 static bool HandleStaticallyInitializedArray(StoreToVariable arg2, ILBlock block, int i, ILExpression newArrInst, int arrayLength)
 {
     FieldDefinition field = ((ILExpression)block.Body[i + 3]).Arguments[1].Operand as FieldDefinition;
     if (field == null || field.InitialValue == null)
         return false;
     switch (TypeAnalysis.GetTypeCode(newArrInst.Operand as TypeReference)) {
         case TypeCode.Int32:
         case TypeCode.UInt32:
             if (field.InitialValue.Length == arrayLength * 4) {
                 ILExpression[] newArr = new ILExpression[arrayLength];
                 for (int j = 0; j < newArr.Length; j++) {
                     newArr[j] = new ILExpression(ILCode.Ldc_I4, BitConverter.ToInt32(field.InitialValue, j * 4));
                 }
                 block.Body[i] = new ILExpression(ILCode.Stloc, arg2.LastVariable, new ILExpression(ILCode.InitArray, newArrInst.Operand, newArr));
                 block.Body.RemoveRange(i + 1, 3);
                 return true;
             }
             break;
     }
     return false;
 }
Example #5
0
		bool TrySimplifyGoto(ILExpression gotoExpr)
		{
			Debug.Assert(gotoExpr.Code == ILCode.Br || gotoExpr.Code == ILCode.Leave);
			Debug.Assert(gotoExpr.Prefixes == null);
			Debug.Assert(gotoExpr.Operand != null);
			
			ILExpression target = Enter(gotoExpr, new HashSet<ILNode>());
			if (target == null)
				return false;
			
			if (target == Exit(gotoExpr, new HashSet<ILNode>())) {
				gotoExpr.Code = ILCode.Nop;
				gotoExpr.Operand = null;
				target.ILRanges.AddRange(gotoExpr.ILRanges);
				gotoExpr.ILRanges.Clear();
				return true;
			}
			
			ILWhileLoop loop = null;
			ILNode current = gotoExpr;
			while(loop == null && current != null) {
				current = parent[current];
				loop = current as ILWhileLoop;
			}
			
			if (loop != null && target == Exit(loop, new HashSet<ILNode>())) {
				gotoExpr.Code = ILCode.LoopBreak;
				gotoExpr.Operand = null;
				return true;
			}
			
			if (loop != null && target == Enter(loop, new HashSet<ILNode>())) {
				gotoExpr.Code = ILCode.LoopContinue;
				gotoExpr.Operand = null;
				return true;
			}
			
			return false;
		}
Example #6
0
        static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
        {
            // throw new NotImplementedException();

            OpCode opCode = byteCode.OpCode;
            object operand = byteCode.Operand;
            Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null;
            ILExpression operandAsByteCode = operand as ILExpression;
            Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
            Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
            Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;

            Ast.Statement branchCommand = null;
            if (byteCode.Operand is ILLabel) {
                branchCommand = new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
            }

            switch(opCode.Code) {
                #region Arithmetic
                    case Code.Add:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Add_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Div:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
                    case Code.Div_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
                    case Code.Mul:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Mul_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Rem:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
                    case Code.Rem_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
                    case Code.Sub:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.Sub_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.And:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2);
                    case Code.Xor:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2);
                    case Code.Shl:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2);
                    case Code.Shr:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
                    case Code.Shr_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);

                    case Code.Neg:        return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Minus);
                    case Code.Not:        return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.BitNot);
                #endregion
                #region Arrays
                    case Code.Newarr:
                        operandAsTypeRef.RankSpecifier = new int[] {0};
                        return new Ast.ArrayCreateExpression(operandAsTypeRef, new List<Expression>(new Expression[] {arg1}));

                    case Code.Ldlen: return new Ast.MemberReferenceExpression(arg1, "Length");

                    case Code.Ldelem_I:
                    case Code.Ldelem_I1:
                    case Code.Ldelem_I2:
                    case Code.Ldelem_I4:
                    case Code.Ldelem_I8:
                    case Code.Ldelem_U1:
                    case Code.Ldelem_U2:
                    case Code.Ldelem_U4:
                    case Code.Ldelem_R4:
                    case Code.Ldelem_R8:
                    case Code.Ldelem_Ref: return new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {arg2}));
                    case Code.Ldelem_Any: throw new NotImplementedException();
                    case Code.Ldelema:    return new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {arg2}));

                    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: return new Ast.AssignmentExpression(new Ast.IndexerExpression(arg1, new List<Expression>(new Expression[] {arg2})), AssignmentOperatorType.Assign, arg3);
                    case Code.Stelem_Any: throw new NotImplementedException();
                #endregion
                #region Branching
                    case Code.Br:      return branchCommand;
                    case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), branchCommand);
                    case Code.Brtrue:  return new Ast.IfElseStatement(arg1, branchCommand);
                    case Code.Beq:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand);
                    case Code.Bge:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
                    case Code.Bge_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
                    case Code.Bgt:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand);
                    case Code.Bgt_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand);
                    case Code.Ble:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand);
                    case Code.Ble_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand);
                    case Code.Blt:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
                    case Code.Blt_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
                    case Code.Bne_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand);
                #endregion
                #region Comparison
                    case Code.Ceq:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2));
                    case Code.Cgt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                    case Code.Cgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                    case Code.Clt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                    case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                #endregion
                #region Conversions
                    case Code.Conv_I:    return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO
                    case Code.Conv_I1:   return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast);
                    case Code.Conv_I2:   return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast);
                    case Code.Conv_I4:   return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast);
                    case Code.Conv_I8:   return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast);
                    case Code.Conv_U:    return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO
                    case Code.Conv_U1:   return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast);
                    case Code.Conv_U2:   return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast);
                    case Code.Conv_U4:   return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast);
                    case Code.Conv_U8:   return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast);
                    case Code.Conv_R4:   return new Ast.CastExpression(new Ast.TypeReference(typeof(float).FullName), arg1, CastType.Cast);
                    case Code.Conv_R8:   return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast);
                    case Code.Conv_R_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(double).FullName), arg1, CastType.Cast); // TODO

                    case Code.Conv_Ovf_I:  return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO
                    case Code.Conv_Ovf_I1: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_I2: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_I4: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_I8: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_U:  return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO
                    case Code.Conv_Ovf_U1: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_U2: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_U4: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_U8: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast);

                    case Code.Conv_Ovf_I_Un:  return new Ast.CastExpression(new Ast.TypeReference(typeof(int).FullName), arg1, CastType.Cast); // TODO
                    case Code.Conv_Ovf_I1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(SByte).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_I2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int16).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_I4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int32).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_I8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Int64).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_U_Un:  return new Ast.CastExpression(new Ast.TypeReference(typeof(uint).FullName), arg1, CastType.Cast); // TODO
                    case Code.Conv_Ovf_U1_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(Byte).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_U2_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt16).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_U4_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt32).FullName), arg1, CastType.Cast);
                    case Code.Conv_Ovf_U8_Un: return new Ast.CastExpression(new Ast.TypeReference(typeof(UInt64).FullName), arg1, CastType.Cast);
                #endregion
                #region Indirect
                    case Code.Ldind_I: throw new NotImplementedException();
                    case Code.Ldind_I1: throw new NotImplementedException();
                    case Code.Ldind_I2: throw new NotImplementedException();
                    case Code.Ldind_I4: throw new NotImplementedException();
                    case Code.Ldind_I8: throw new NotImplementedException();
                    case Code.Ldind_U1: throw new NotImplementedException();
                    case Code.Ldind_U2: throw new NotImplementedException();
                    case Code.Ldind_U4: throw new NotImplementedException();
                    case Code.Ldind_R4: throw new NotImplementedException();
                    case Code.Ldind_R8: throw new NotImplementedException();
                    case Code.Ldind_Ref: throw new NotImplementedException();

                    case Code.Stind_I: throw new NotImplementedException();
                    case Code.Stind_I1: throw new NotImplementedException();
                    case Code.Stind_I2: throw new NotImplementedException();
                    case Code.Stind_I4: throw new NotImplementedException();
                    case Code.Stind_I8: throw new NotImplementedException();
                    case Code.Stind_R4: throw new NotImplementedException();
                    case Code.Stind_R8: throw new NotImplementedException();
                    case Code.Stind_Ref: throw new NotImplementedException();
                #endregion
                case Code.Arglist: throw new NotImplementedException();
                case Code.Box: throw new NotImplementedException();
                case Code.Break: throw new NotImplementedException();
                case Code.Call:
                case Code.Callvirt:
                    // TODO: Diferentiate vitual and non-vitual dispach
                    Cecil.MethodReference cecilMethod = ((MethodReference)operand);
                    Ast.Expression target;
                    List<Ast.Expression> methodArgs = new List<Ast.Expression>(args);
                    if (cecilMethod.HasThis) {
                        target = methodArgs[0];
                        methodArgs.RemoveAt(0);
                    } else {
                        target = new Ast.IdentifierExpression(cecilMethod.DeclaringType.FullName);
                    }

                    // TODO: Constructors are ignored
                    if (cecilMethod.Name == ".ctor") {
                        return MakeComment("// Constructor");
                    }

                    // TODO: Hack, detect properties properly
                    if (cecilMethod.Name.StartsWith("get_")) {
                        return new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4));
                    } else if (cecilMethod.Name.StartsWith("set_")) {
                        return new Ast.AssignmentExpression(
                            new Ast.MemberReferenceExpression(target, cecilMethod.Name.Remove(0, 4)),
                            AssignmentOperatorType.Assign,
                            methodArgs[0]
                        );
                    }

                    // Multi-dimensional array acces // TODO: do properly
                    if (cecilMethod.Name == "Get") {
                        return new Ast.IndexerExpression(target, methodArgs);
                    } else if (cecilMethod.Name == "Set") {
                        Expression val = methodArgs[methodArgs.Count - 1];
                        methodArgs.RemoveAt(methodArgs.Count - 1);
                        return new Ast.AssignmentExpression(
                            new Ast.IndexerExpression(target, methodArgs),
                            AssignmentOperatorType.Assign,
                            Convert(val, ((Cecil.ArrayType)target.UserData["Type"]).ElementType)
                        );
                    }

                    // Default invocation
                    return new Ast.InvocationExpression(
                        new Ast.MemberReferenceExpression(target, cecilMethod.Name),
                        methodArgs
                    );
                case Code.Calli: throw new NotImplementedException();
                case Code.Castclass: return new Ast.CastExpression(operandAsTypeRef, arg1, CastType.Cast);
                case Code.Ckfinite: throw new NotImplementedException();
                case Code.Constrained: throw new NotImplementedException();
                case Code.Cpblk: throw new NotImplementedException();
                case Code.Cpobj: throw new NotImplementedException();
                case Code.Dup: return arg1;
                case Code.Endfilter: throw new NotImplementedException();
                case Code.Endfinally: return null;
                case Code.Initblk: throw new NotImplementedException();
                case Code.Initobj: throw new NotImplementedException();
                case Code.Isinst: return new Ast.TypeOfIsExpression(arg1, new Ast.TypeReference(((Cecil.TypeReference)operand).FullName));
                case Code.Jmp: throw new NotImplementedException();
                case Code.Ldarg:
                    if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
                        return new Ast.ThisReferenceExpression();
                    } else {
                        return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name);
                    }
                case Code.Ldarga: throw new NotImplementedException();
                case Code.Ldc_I4:
                case Code.Ldc_I8:
                case Code.Ldc_R4:
                case Code.Ldc_R8: return new Ast.PrimitiveExpression(operand, null);
                case Code.Ldfld:
                case Code.Ldsfld: {
                    if (operand is FieldDefinition) {
                        FieldDefinition field = (FieldDefinition) operand;
                        if (field.IsStatic) {
                            return new Ast.MemberReferenceExpression(
                                new Ast.IdentifierExpression(field.DeclaringType.FullName),
                                field.Name
                            );
                        } else {
                            return new Ast.MemberReferenceExpression(arg1, field.Name);
                        }
                    } else {
                        // TODO: Static accesses
                        return new Ast.MemberReferenceExpression(arg1, ((FieldReference)operand).Name);
                    }
                }
                case Code.Stfld:
                case Code.Stsfld: {
                    FieldDefinition field = (FieldDefinition) operand;
                    if (field.IsStatic) {
                        return new AssignmentExpression(
                            new Ast.MemberReferenceExpression(
                                new Ast.IdentifierExpression(field.DeclaringType.FullName),
                                field.Name
                            ),
                            AssignmentOperatorType.Assign,
                            arg1
                        );
                    } else {
                        return new AssignmentExpression(
                            new Ast.MemberReferenceExpression(arg1, field.Name),
                            AssignmentOperatorType.Assign,
                            arg2
                        );
                    }
                }
                case Code.Ldflda:
                case Code.Ldsflda: throw new NotImplementedException();
                case Code.Ldftn: throw new NotImplementedException();
                case Code.Ldloc:
                    if (operand is ILStackVariable) {
                        return new Ast.IdentifierExpression(((ILStackVariable)operand).Name);
                    } else {
                        return new Ast.IdentifierExpression(((VariableDefinition)operand).Name);
                    }
                case Code.Ldloca: throw new NotImplementedException();
                case Code.Ldnull: return new Ast.PrimitiveExpression(null, null);
                case Code.Ldobj: throw new NotImplementedException();
                case Code.Ldstr: return new Ast.PrimitiveExpression(operand, null);
                case Code.Ldtoken:
                    if (operand is Cecil.TypeReference) {
                        return new Ast.MemberReferenceExpression(
                            new Ast.TypeOfExpression(operandAsTypeRef),
                            "TypeHandle"
                        );
                    } else {
                        throw new NotImplementedException();
                    }
                case Code.Ldvirtftn: throw new NotImplementedException();
                case Code.Leave: return null;
                case Code.Localloc: throw new NotImplementedException();
                case Code.Mkrefany: throw new NotImplementedException();
                case Code.Newobj:
                    Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
                    // TODO: Ensure that the corrent overloaded constructor is called
                    if (declaringType is ArrayType) {
                        return new Ast.ArrayCreateExpression(
                            new Ast.TypeReference(((ArrayType)declaringType).ElementType.FullName, new int[] {}),
                            new List<Expression>(args)
                        );
                    }
                    return new Ast.ObjectCreateExpression(
                        new Ast.TypeReference(declaringType.FullName),
                        new List<Expression>(args)
                    );
                case Code.No: throw new NotImplementedException();
                case Code.Nop: return null;
                case Code.Or: throw new NotImplementedException();
                case Code.Pop: return arg1;
                case Code.Readonly: throw new NotImplementedException();
                case Code.Refanytype: throw new NotImplementedException();
                case Code.Refanyval: throw new NotImplementedException();
                case Code.Ret: {
                    if (methodDef.ReturnType.FullName != Constants.Void) {
                        arg1 = Convert(arg1, methodDef.ReturnType);
                        return new Ast.ReturnStatement(arg1);
                    } else {
                        return new Ast.ReturnStatement(null);
                    }
                }
                case Code.Rethrow: return new Ast.ThrowStatement(new IdentifierExpression("exception"));
                case Code.Sizeof: throw new NotImplementedException();
                case Code.Starg: throw new NotImplementedException();
                case Code.Stloc: {
                    if (operand is ILStackVariable) {
                        Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(((ILStackVariable)operand).Name, arg1));
                        astLocalVar.TypeReference = new Ast.TypeReference("var");
                        return astLocalVar;
                    }
                    VariableDefinition locVar = (VariableDefinition)operand;
                    string name = locVar.Name;
                    arg1 = Convert(arg1, locVar.VariableType);
                    if (localVarDefined.ContainsKey(name)) {
                        if (localVarDefined[name]) {
                            return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1);
                        } else {
                            Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(name, arg1));
                            astLocalVar.TypeReference = new Ast.TypeReference(localVarTypes[name].FullName);
                            localVarDefined[name] = true;
                            return astLocalVar;
                        }
                    } else {
                        return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1);
                    }
                }
                case Code.Stobj: throw new NotImplementedException();
                case Code.Switch: throw new NotImplementedException();
                case Code.Tail: throw new NotImplementedException();
                case Code.Throw: return new Ast.ThrowStatement(arg1);
                case Code.Unaligned: throw new NotImplementedException();
                case Code.Unbox: throw new NotImplementedException();
                case Code.Unbox_Any: throw new NotImplementedException();
                case Code.Volatile: throw new NotImplementedException();
                default: throw new Exception("Unknown OpCode: " + opCode);
            }
        }
Example #7
0
 static object TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
 {
     try {
         Ast.INode ret = TransformByteCode_Internal(methodDef, byteCode, args);
         if (ret is Ast.Expression) {
             ret = new ParenthesizedExpression((Ast.Expression)ret);
         }
         // ret.UserData["Type"] = byteCode.Type;
         return ret;
     } catch (NotImplementedException) {
         // Output the operand of the unknown IL code as well
         if (byteCode.Operand != null) {
             args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
         }
         return new Ast.InvocationExpression(new IdentifierExpression(byteCode.OpCode.Name), args);
     }
 }
Example #8
0
        public List<ILNode> ConvertToAst(List<Instruction> body)
        {
            List<ILNode> ast = new List<ILNode>();

            // Convert stack-based IL code to ILAst tree
            foreach(Instruction inst in body) {
                OpCode opCode  = inst.OpCode;
                object operand = inst.Operand;

                MethodBodyRocks.ExpandMacro(ref opCode, ref operand, methodDef.Body);

                ILExpression expr = new ILExpression(opCode, operand);

                // Label for this instruction
                ILLabel label;
                if (labels.TryGetValue(inst, out label)) {
                    ast.Add(label);
                }

                // Branch using labels
                if (inst.Operand is Instruction[]) {
                    List<ILLabel> newOperand = new List<ILLabel>();
                    foreach(Instruction target in (Instruction[])inst.Operand) {
                        newOperand.Add(labels[target]);
                    }
                    expr.Operand = newOperand.ToArray();
                } else if (inst.Operand is Instruction) {
                    expr.Operand = labels[(Instruction)inst.Operand];
                }

                // Reference arguments using temporary variables
                ILStack stack = stackBefore[inst];
                int popCount = inst.GetPopCount();
                if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all
                for (int i = stack.Items.Count - popCount; i < stack.Items.Count; i++) {
                    Instruction pushedBy = stack.Items[i].PushedBy;
                    if (pushedBy != null) {
                        ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "expr" + pushedBy.Offset.ToString("X2") });
                        expr.Arguments.Add(ldExpr);
                    } else {
                        ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "exception" });
                        expr.Arguments.Add(ldExpr);
                    }
                }

                // If the bytecode pushes anything store the result in temporary variable
                int pushCount = inst.GetPushCount();
                if (pushCount > 0) {
                    ILExpression stExpr = new ILExpression(OpCodes.Stloc, new ILStackVariable() { Name = "expr" + inst.Offset.ToString("X2"), RefCount = pushCount });
                    stExpr.Arguments.Add(expr);
                    expr = stExpr;
                }

                ast.Add(expr);
            }

            // Try to in-line stloc / ldloc pairs
            for(int i = 0; i < ast.Count - 1; i++) {
                if (i < 0) continue;

                ILExpression expr = ast[i] as ILExpression;
                ILExpression nextExpr = ast[i + 1] as ILExpression;

                if (expr != null && nextExpr != null && expr.OpCode.Code == Code.Stloc && expr.Operand is ILStackVariable) {

                    // If the next expression is stloc, look inside
                    if (nextExpr.OpCode.Code == Code.Stloc && nextExpr.Operand is ILStackVariable) {
                        nextExpr = nextExpr.Arguments[0];
                    }

                    // Find the use of the 'expr'
                    for(int j = 0; j < nextExpr.Arguments.Count; j++) {
                        ILExpression arg = nextExpr.Arguments[j];

                        // TODO: Check if duplicating the dup opcode has side-effects

                        if (arg.OpCode.Code == Code.Ldloc && arg.Operand is ILStackVariable) {
                            ILStackVariable stVar = (ILStackVariable)expr.Operand;
                            ILStackVariable ldVar = (ILStackVariable)arg.Operand;
                            if (stVar.Name == ldVar.Name) {
                                stVar.RefCount--;
                                if (stVar.RefCount <= 0) {
                                    ast.RemoveAt(i);
                                }
                                nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body
                                i -= 2; // Try the same index again
                                break;  // Found
                            }
                        } else {
                            break; // This argument might have side effects so we can not move the 'expr' after it.
                        }
                    }
                }
            }

            return ast;
        }
 AstNode TransformExpression(ILExpression expr)
 {
     AstNode node = TransformByteCode(expr);
     Expression astExpr = node as Expression;
     if (astExpr != null)
         return Convert(astExpr, expr.InferredType, expr.ExpectedType);
     else
         return node;
 }
        AstNode TransformByteCode(ILExpression byteCode)
        {
            ILCode opCode = byteCode.Code;
            object operand = byteCode.Operand;
            AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
            ILExpression operandAsByteCode = operand as ILExpression;

            // Do branches first because TransformExpressionArguments does not work on arguments that are branches themselfs
            // TODO:  We should probably have virtual instructions for these and not abuse branch codes as expressions
            switch(opCode) {
                    case ILCode.Br: return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
                case ILCode.Brfalse:
                case ILCode.Brtrue:
                case ILCode.Beq:
                case ILCode.Bge:
                case ILCode.Bge_Un:
                case ILCode.Bgt:
                case ILCode.Bgt_Un:
                case ILCode.Ble:
                case ILCode.Ble_Un:
                case ILCode.Blt:
                case ILCode.Blt_Un:
                case ILCode.Bne_Un:
                case ILCode.BrLogicAnd:
                case ILCode.BrLogicOr:
                    return new Ast.IfElseStatement() {
                        Condition = MakeBranchCondition(byteCode),
                        TrueStatement = new BlockStatement() {
                            new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name)
                        }
                    };
            }

            List<Ast.Expression> args = TransformExpressionArguments(byteCode);
            Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
            Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
            Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;

            switch((Code)opCode) {
                    #region Arithmetic
                    case Code.Add:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Add_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Div:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
                    case Code.Div_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
                    case Code.Mul:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Mul_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Rem:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
                    case Code.Rem_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
                    case Code.Sub:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.Sub_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.And:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2);
                    case Code.Or:         return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2);
                    case Code.Xor:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2);
                    case Code.Shl:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2);
                    case Code.Shr:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
                    case Code.Shr_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);

                    case Code.Neg:        return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1);
                    case Code.Not:        return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
                    #endregion
                    #region Arrays
                case Code.Newarr:
                case (Code)ILCode.InitArray:
                    {
                        var ace = new Ast.ArrayCreateExpression();
                        ace.Type = operandAsTypeRef;
                        ComposedType ct = operandAsTypeRef as ComposedType;
                        if (ct != null) {
                            // change "new (int[,])[10] to new int[10][,]"
                            ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
                        }
                        if (opCode == ILCode.InitArray) {
                            ace.Initializer = new ArrayInitializerExpression();
                            ace.Initializer.Elements.AddRange(args);
                        } else {
                            ace.Arguments.Add(arg1);
                        }
                        return ace;
                    }
                case Code.Ldlen:
                    return arg1.Member("Length");
                case Code.Ldelem_I:
                case Code.Ldelem_I1:
                case Code.Ldelem_I2:
                case Code.Ldelem_I4:
                case Code.Ldelem_I8:
                case Code.Ldelem_U1:
                case Code.Ldelem_U2:
                case Code.Ldelem_U4:
                case Code.Ldelem_R4:
                case Code.Ldelem_R8:
                case Code.Ldelem_Ref:
                    return arg1.Indexer(arg2);
                case Code.Ldelem_Any:
                    return InlineAssembly(byteCode, args);
                case Code.Ldelema:
                    return MakeRef(arg1.Indexer(arg2));

                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:
                case Code.Stelem_Any:
                    return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
                    #endregion
                    #region Comparison
                    case Code.Ceq:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
                    case Code.Cgt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                case Code.Cgt_Un:
                    // can also mean Inequality, when used with object references
                    {
                        TypeReference arg1Type = byteCode.Arguments[0].InferredType;
                        if (arg1Type != null && !arg1Type.IsValueType)
                            return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
                        else
                            return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                    }
                    case Code.Clt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                    case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                    #endregion
                    #region Conversions
                case Code.Conv_I1:
                case Code.Conv_I2:
                case Code.Conv_I4:
                case Code.Conv_I8:
                case Code.Conv_U1:
                case Code.Conv_U2:
                case Code.Conv_U4:
                case Code.Conv_U8:
                    return arg1; // conversion is handled by Convert() function using the info from type analysis
                    case Code.Conv_I:    return arg1.CastTo(typeof(IntPtr)); // TODO
                    case Code.Conv_U:    return arg1.CastTo(typeof(UIntPtr)); // TODO
                    case Code.Conv_R4:   return arg1.CastTo(typeof(float));
                    case Code.Conv_R8:   return arg1.CastTo(typeof(double));
                    case Code.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO

                case Code.Conv_Ovf_I1:
                case Code.Conv_Ovf_I2:
                case Code.Conv_Ovf_I4:
                case Code.Conv_Ovf_I8:
                case Code.Conv_Ovf_U1:
                case Code.Conv_Ovf_U2:
                case Code.Conv_Ovf_U4:
                case Code.Conv_Ovf_U8:
                case Code.Conv_Ovf_I1_Un:
                case Code.Conv_Ovf_I2_Un:
                case Code.Conv_Ovf_I4_Un:
                case Code.Conv_Ovf_I8_Un:
                case Code.Conv_Ovf_U1_Un:
                case Code.Conv_Ovf_U2_Un:
                case Code.Conv_Ovf_U4_Un:
                case Code.Conv_Ovf_U8_Un:
                    return arg1; // conversion was handled by Convert() function using the info from type analysis
                    case Code.Conv_Ovf_I:  return arg1.CastTo(typeof(IntPtr)); // TODO
                    case Code.Conv_Ovf_U:  return arg1.CastTo(typeof(UIntPtr));
                    case Code.Conv_Ovf_I_Un:  return arg1.CastTo(typeof(IntPtr));
                    case Code.Conv_Ovf_U_Un:  return arg1.CastTo(typeof(UIntPtr));

                case Code.Castclass:
                case Code.Unbox_Any:
                    return arg1.CastTo(operandAsTypeRef);
                case Code.Isinst:
                    return arg1.CastAs(operandAsTypeRef);
                case Code.Box:
                    return arg1;
                case Code.Unbox:
                    return InlineAssembly(byteCode, args);
                    #endregion
                    #region Indirect
                case Code.Ldind_I:
                case Code.Ldind_I1:
                case Code.Ldind_I2:
                case Code.Ldind_I4:
                case Code.Ldind_I8:
                case Code.Ldind_U1:
                case Code.Ldind_U2:
                case Code.Ldind_U4:
                case Code.Ldind_R4:
                case Code.Ldind_R8:
                case Code.Ldind_Ref:
                case Code.Ldobj:
                    if (args[0] is DirectionExpression)
                        return ((DirectionExpression)args[0]).Expression.Detach();
                    else
                        return InlineAssembly(byteCode, args);

                case Code.Stind_I:
                case Code.Stind_I1:
                case Code.Stind_I2:
                case Code.Stind_I4:
                case Code.Stind_I8:
                case Code.Stind_R4:
                case Code.Stind_R8:
                case Code.Stind_Ref:
                case Code.Stobj:
                    if (args[0] is DirectionExpression)
                        return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), args[1]);
                    else
                        return InlineAssembly(byteCode, args);
                    #endregion
                    case Code.Arglist: return InlineAssembly(byteCode, args);
                    case Code.Break: return InlineAssembly(byteCode, args);
                case Code.Call:
                    return TransformCall(false, operand, methodDef, args);
                case Code.Callvirt:
                    return TransformCall(true, operand, methodDef, args);
                case Code.Ldftn:
                    {
                        Cecil.MethodReference cecilMethod = ((MethodReference)operand);
                        var expr = new Ast.IdentifierExpression(cecilMethod.Name);
                        expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod));
                        expr.AddAnnotation(cecilMethod);
                        return new IdentifierExpression("ldftn").Invoke(expr)
                            .WithAnnotation(new Transforms.DelegateConstruction.Annotation(false));
                    }
                case Code.Ldvirtftn:
                    {
                        Cecil.MethodReference cecilMethod = ((MethodReference)operand);
                        var expr = new Ast.IdentifierExpression(cecilMethod.Name);
                        expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod));
                        expr.AddAnnotation(cecilMethod);
                        return new IdentifierExpression("ldvirtftn").Invoke(expr)
                            .WithAnnotation(new Transforms.DelegateConstruction.Annotation(true));
                    }

                    case Code.Calli: return InlineAssembly(byteCode, args);
                    case Code.Ckfinite: return InlineAssembly(byteCode, args);
                    case Code.Constrained: return InlineAssembly(byteCode, args);
                    case Code.Cpblk: return InlineAssembly(byteCode, args);
                    case Code.Cpobj: return InlineAssembly(byteCode, args);
                    case Code.Dup: return arg1;
                    case Code.Endfilter: return InlineAssembly(byteCode, args);
                    case Code.Endfinally: return null;
                    case Code.Initblk: return InlineAssembly(byteCode, args);
                case Code.Initobj:
                    if (args[0] is DirectionExpression)
                        return new AssignmentExpression(((DirectionExpression)args[0]).Expression.Detach(), new DefaultValueExpression { Type = operandAsTypeRef });
                    else
                        return InlineAssembly(byteCode, args);
                    case Code.Jmp: return InlineAssembly(byteCode, args);
                case Code.Ldarg:
                    if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
                        if (context.CurrentMethod.DeclaringType.IsValueType)
                            return MakeRef(new Ast.ThisReferenceExpression());
                        else
                            return new Ast.ThisReferenceExpression();
                    } else {
                        var expr = new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand);
                        if (((ParameterDefinition)operand).ParameterType is ByReferenceType)
                            return MakeRef(expr);
                        else
                            return expr;
                    }
                case Code.Ldarga:
                    if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
                        return MakeRef(new Ast.ThisReferenceExpression());
                    } else {
                        return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand));
                    }
                case Code.Ldc_I4:
                    return MakePrimitive((int)operand, byteCode.InferredType);
                case Code.Ldc_I8:
                case Code.Ldc_R4:
                case Code.Ldc_R8:
                    return new Ast.PrimitiveExpression(operand);
                case Code.Ldfld:
                    if (arg1 is DirectionExpression)
                        arg1 = ((DirectionExpression)arg1).Expression.Detach();
                    return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand);
                case Code.Ldsfld:
                    return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand);
                case Code.Stfld:
                    if (arg1 is DirectionExpression)
                        arg1 = ((DirectionExpression)arg1).Expression.Detach();
                    return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2);
                case Code.Stsfld:
                    return new AssignmentExpression(
                        AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand),
                        arg1);
                case Code.Ldflda:
                    return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand));
                case Code.Ldsflda:
                    return MakeRef(
                        AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand));
                case Code.Ldloc:
                    localVariablesToDefine.Add((ILVariable)operand);
                    return new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand);
                case Code.Ldloca:
                    localVariablesToDefine.Add((ILVariable)operand);
                    return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand));
                case Code.Ldnull:
                    return new Ast.NullReferenceExpression();
                    case Code.Ldstr: return new Ast.PrimitiveExpression(operand);
                case Code.Ldtoken:
                    if (operand is Cecil.TypeReference) {
                        return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle");
                    } else {
                        return InlineAssembly(byteCode, args);
                    }
                    case Code.Leave: return null;
                    case Code.Localloc: return InlineAssembly(byteCode, args);
                    case Code.Mkrefany: return InlineAssembly(byteCode, args);
                case Code.Newobj:
                    {
                        Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;

                        if (declaringType is ArrayType) {
                            ComposedType ct = AstBuilder.ConvertType((ArrayType)declaringType) as ComposedType;
                            if (ct != null && ct.ArraySpecifiers.Count >= 1) {
                                var ace = new Ast.ArrayCreateExpression();
                                ct.ArraySpecifiers.First().Remove();
                                ct.ArraySpecifiers.MoveTo(ace.AdditionalArraySpecifiers);
                                ace.Type = ct;
                                ace.Arguments.AddRange(args);
                                return ace;
                            }
                        }
                        var oce = new Ast.ObjectCreateExpression();
                        oce.Type = AstBuilder.ConvertType(declaringType);
                        oce.Arguments.AddRange(args);
                        return oce.WithAnnotation(operand);
                    }
                    case Code.No: return InlineAssembly(byteCode, args);
                    case Code.Nop: return null;
                    case Code.Pop: return arg1;
                    case Code.Readonly: return InlineAssembly(byteCode, args);
                    case Code.Refanytype: return InlineAssembly(byteCode, args);
                    case Code.Refanyval: return InlineAssembly(byteCode, args);
                    case Code.Ret: {
                        if (methodDef.ReturnType.FullName != "System.Void") {
                            return new Ast.ReturnStatement { Expression = arg1 };
                        } else {
                            return new Ast.ReturnStatement();
                        }
                    }
                    case Code.Rethrow: return new Ast.ThrowStatement();
                case Code.Sizeof:
                    return new Ast.SizeOfExpression { Type = operandAsTypeRef };
                case Code.Starg:
                    return new Ast.AssignmentExpression(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand), arg1);
                    case Code.Stloc: {
                        ILVariable locVar = (ILVariable)operand;
                        localVariablesToDefine.Add(locVar);
                        return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1);
                    }
                    case Code.Switch: return InlineAssembly(byteCode, args);
                    case Code.Tail: return InlineAssembly(byteCode, args);
                    case Code.Throw: return new Ast.ThrowStatement { Expression = arg1 };
                    case Code.Unaligned: return InlineAssembly(byteCode, args);
                    case Code.Volatile: return InlineAssembly(byteCode, args);
                    default: throw new Exception("Unknown OpCode: " + opCode);
            }
        }
        Ast.Expression MakeBranchCondition(ILExpression expr)
        {
            switch(expr.Code) {
                case ILCode.LogicNot:
                    return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(expr.Arguments[0]));
                case ILCode.BrLogicAnd:
                    return new Ast.BinaryOperatorExpression(
                        MakeBranchCondition(expr.Arguments[0]),
                        BinaryOperatorType.ConditionalAnd,
                        MakeBranchCondition(expr.Arguments[1])
                    );
                case ILCode.BrLogicOr:
                    return new Ast.BinaryOperatorExpression(
                        MakeBranchCondition(expr.Arguments[0]),
                        BinaryOperatorType.ConditionalOr,
                        MakeBranchCondition(expr.Arguments[1])
                    );
            }

            List<Ast.Expression> args = TransformExpressionArguments(expr);
            Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
            Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
            switch((Code)expr.Code) {
                case Code.Brfalse:
                    return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
                case Code.Brtrue:
                    return arg1;
                case Code.Beq:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
                case Code.Bge:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
                case Code.Bge_Un:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
                case Code.Bgt:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                case Code.Bgt_Un:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                case Code.Ble:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
                case Code.Ble_Un:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
                case Code.Blt:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                case Code.Blt_Un:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                case Code.Bne_Un:
                    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
                default:
                    throw new Exception("Bad opcode");
            }
        }
 static Expression InlineAssembly(ILExpression byteCode, List<Ast.Expression> args)
 {
     #if DEBUG
     unhandledOpcodes.AddOrUpdate(byteCode.Code, c => 1, (c, n) => n+1);
     #endif
     // Output the operand of the unknown IL code as well
     if (byteCode.Operand != null) {
         args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
     }
     return new IdentifierExpression(byteCode.Code.GetName()).Invoke(args);
 }
Example #13
0
 Ast.Statement TransformExpressionToStatement(ILExpression expr)
 {
     object codeExpr = TransformExpression(expr);
     if (codeExpr == null) {
         return null;
     } else if (codeExpr is Ast.Expression) {
         return new Ast.ExpressionStatement((Ast.Expression)codeExpr);
     } else if (codeExpr is Ast.Statement) {
         return (Ast.Statement)codeExpr;
     } else {
         throw new Exception();
     }
 }
Example #14
0
 /// <summary>
 /// Infers the C# type of <paramref name="expr"/>.
 /// </summary>
 /// <param name="expr">The expression</param>
 /// <param name="expectedType">The expected type of the expression</param>
 /// <param name="forceInferChildren">Whether direct children should be inferred even if its not necessary. (does not apply to nested children!)</param>
 /// <returns>The inferred type</returns>
 TypeReference InferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
 {
     expr.ExpectedType = expectedType;
     if (forceInferChildren || expr.InferredType == null)
         expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren);
     return expr.InferredType;
 }
Example #15
0
 object TransformExpression(ILExpression expr)
 {
     List<Ast.Expression> args = TransformExpressionArguments(expr);
     return TransformByteCode(methodDef, expr, args);
 }
Example #16
0
 TypeReference InferArgumentsInBinaryOperator(ILExpression expr, bool? isSigned)
 {
     ILExpression left = expr.Arguments[0];
     ILExpression right = expr.Arguments[1];
     TypeReference leftPreferred = DoInferTypeForExpression(left, null);
     TypeReference rightPreferred = DoInferTypeForExpression(right, null);
     if (leftPreferred == rightPreferred) {
         return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
     } else if (rightPreferred == DoInferTypeForExpression(left, rightPreferred)) {
         return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = rightPreferred;
     } else if (leftPreferred == DoInferTypeForExpression(right, leftPreferred)) {
         return left.InferredType = right.InferredType = left.ExpectedType = right.ExpectedType = leftPreferred;
     } else {
         left.ExpectedType = right.ExpectedType = TypeWithMoreInformation(leftPreferred, rightPreferred);
         left.InferredType = DoInferTypeForExpression(left, left.ExpectedType);
         right.InferredType = DoInferTypeForExpression(left, right.ExpectedType);
         return left.ExpectedType;
     }
 }
Example #17
0
 TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
 {
     switch (expr.Code) {
         case ILCode.LogicNot:
             if (forceInferChildren) {
                 InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
             }
             return typeSystem.Boolean;
         case ILCode.LogicAnd:
         case ILCode.LogicOr:
             if (forceInferChildren) {
                 InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
                 InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
             }
             return typeSystem.Boolean;
     }
     switch ((Code)expr.Code) {
             #region Variable load/store
         case Code.Stloc:
             {
                 ILVariable v = (ILVariable)expr.Operand;
                 if (forceInferChildren || v.Type == null) {
                     TypeReference t = InferTypeForExpression(expr.Arguments.Single(), ((ILVariable)expr.Operand).Type);
                     if (v.Type == null)
                         v.Type = t;
                 }
                 return v.Type;
             }
         case Code.Ldloc:
             {
                 ILVariable v = (ILVariable)expr.Operand;
                 if (v.Type == null) {
                     v.Type = expectedType;
                     // Mark the variable as inferred. This is necessary because expectedType might be null
                     // (e.g. the only use of an arg_*-Variable is a pop statement),
                     // so we can't tell from v.Type whether it was already inferred.
                     inferredVariables.Add(v);
                 }
                 return v.Type;
             }
         case Code.Starg:
             if (forceInferChildren)
                 InferTypeForExpression(expr.Arguments.Single(), ((ParameterReference)expr.Operand).ParameterType);
             return null;
         case Code.Ldarg:
             return ((ParameterReference)expr.Operand).ParameterType;
         case Code.Ldloca:
             return new ByReferenceType(((ILVariable)expr.Operand).Type);
         case Code.Ldarga:
             return new ByReferenceType(((ParameterReference)expr.Operand).ParameterType);
             #endregion
             #region Call / NewObj
         case Code.Call:
         case Code.Callvirt:
             {
                 MethodReference method = (MethodReference)expr.Operand;
                 if (forceInferChildren) {
                     for (int i = 0; i < expr.Arguments.Count; i++) {
                         if (i == 0 && method.HasThis) {
                             Instruction constraint = expr.GetPrefix(Code.Constrained);
                             if (constraint != null)
                                 InferTypeForExpression(expr.Arguments[i], new ByReferenceType((TypeReference)constraint.Operand));
                             else
                                 InferTypeForExpression(expr.Arguments[i], method.DeclaringType);
                         } else {
                             InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1: i].ParameterType, method));
                         }
                     }
                 }
                 return SubstituteTypeArgs(method.ReturnType, method);
             }
         case Code.Newobj:
             {
                 MethodReference ctor = (MethodReference)expr.Operand;
                 if (forceInferChildren) {
                     for (int i = 0; i < ctor.Parameters.Count; i++) {
                         InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(ctor.Parameters[i].ParameterType, ctor));
                     }
                 }
                 return ctor.DeclaringType;
             }
             #endregion
             #region Load/Store Fields
         case Code.Ldfld:
             if (forceInferChildren)
                 InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType);
             return GetFieldType((FieldReference)expr.Operand);
         case Code.Ldsfld:
             return GetFieldType((FieldReference)expr.Operand);
         case Code.Ldflda:
         case Code.Ldsflda:
             return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
         case Code.Stfld:
             if (forceInferChildren) {
                 InferTypeForExpression(expr.Arguments[0], ((FieldReference)expr.Operand).DeclaringType);
                 InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand));
             }
             return null;
         case Code.Stsfld:
             if (forceInferChildren)
                 InferTypeForExpression(expr.Arguments[0], GetFieldType((FieldReference)expr.Operand));
             return null;
             #endregion
             #region Reference/Pointer instructions
         case Code.Ldind_I:
         case Code.Ldind_I1:
         case Code.Ldind_I2:
         case Code.Ldind_I4:
         case Code.Ldind_I8:
         case Code.Ldind_U1:
         case Code.Ldind_U2:
         case Code.Ldind_U4:
         case Code.Ldind_R4:
         case Code.Ldind_R8:
         case Code.Ldind_Ref:
             return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
         case Code.Stind_I1:
         case Code.Stind_I2:
         case Code.Stind_I4:
         case Code.Stind_I8:
         case Code.Stind_R4:
         case Code.Stind_R8:
         case Code.Stind_I:
         case Code.Stind_Ref:
             if (forceInferChildren) {
                 TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
                 InferTypeForExpression(expr.Arguments[1], elementType);
             }
             return null;
         case Code.Ldobj:
             return (TypeReference)expr.Operand;
         case Code.Stobj:
             if (forceInferChildren) {
                 InferTypeForExpression(expr.Arguments[1], (TypeReference)expr.Operand);
             }
             return null;
         case Code.Initobj:
             return null;
         case Code.Localloc:
             return typeSystem.IntPtr;
             #endregion
             #region Arithmetic instructions
         case Code.Not: // bitwise complement
         case Code.Neg:
             return InferTypeForExpression(expr.Arguments.Single(), expectedType);
         case Code.Add:
         case Code.Sub:
         case Code.Mul:
         case Code.Or:
         case Code.And:
         case Code.Xor:
             return InferArgumentsInBinaryOperator(expr, null);
         case Code.Add_Ovf:
         case Code.Sub_Ovf:
         case Code.Mul_Ovf:
         case Code.Div:
         case Code.Rem:
             return InferArgumentsInBinaryOperator(expr, true);
         case Code.Add_Ovf_Un:
         case Code.Sub_Ovf_Un:
         case Code.Mul_Ovf_Un:
         case Code.Div_Un:
         case Code.Rem_Un:
             return InferArgumentsInBinaryOperator(expr, false);
         case Code.Shl:
         case Code.Shr:
             if (forceInferChildren)
                 InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
             return InferTypeForExpression(expr.Arguments[0], typeSystem.Int32);
         case Code.Shr_Un:
             if (forceInferChildren)
                 InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
             return InferTypeForExpression(expr.Arguments[0], typeSystem.UInt32);
             #endregion
             #region Constant loading instructions
         case Code.Ldnull:
             return typeSystem.Object;
         case Code.Ldstr:
             return typeSystem.String;
         case Code.Ldftn:
         case Code.Ldvirtftn:
             return typeSystem.IntPtr;
         case Code.Ldc_I4:
             return (IsIntegerOrEnum(expectedType) || expectedType == typeSystem.Boolean) ? expectedType : typeSystem.Int32;
         case Code.Ldc_I8:
             return (IsIntegerOrEnum(expectedType)) ? expectedType : typeSystem.Int64;
         case Code.Ldc_R4:
             return typeSystem.Single;
         case Code.Ldc_R8:
             return typeSystem.Double;
         case Code.Ldtoken:
             if (expr.Operand is TypeReference)
                 return new TypeReference("System", "RuntimeTypeHandle", module, module, true);
             else if (expr.Operand is FieldReference)
                 return new TypeReference("System", "RuntimeFieldHandle", module, module, true);
             else
                 return new TypeReference("System", "RuntimeMethodHandle", module, module, true);
         case Code.Arglist:
             return new TypeReference("System", "RuntimeArgumentHandle", module, module, true);
             #endregion
             #region Array instructions
         case Code.Newarr:
             if (forceInferChildren)
                 InferTypeForExpression(expr.Arguments.Single(), typeSystem.Int32);
             return new ArrayType((TypeReference)expr.Operand);
         case Code.Ldlen:
             return typeSystem.Int32;
         case Code.Ldelem_U1:
         case Code.Ldelem_U2:
         case Code.Ldelem_U4:
         case Code.Ldelem_I1:
         case Code.Ldelem_I2:
         case Code.Ldelem_I4:
         case Code.Ldelem_I8:
         case Code.Ldelem_I:
         case Code.Ldelem_Ref:
             {
                 ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
                 if (forceInferChildren) {
                     InferTypeForExpression(expr.Arguments[0], new ArrayType(typeSystem.Byte));
                     InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
                 }
                 return arrayType != null ? arrayType.ElementType : null;
             }
         case Code.Ldelem_Any:
             if (forceInferChildren) {
                 InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
             }
             return (TypeReference)expr.Operand;
         case Code.Ldelema:
             {
                 ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
                 if (forceInferChildren)
                     InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
                 return arrayType != null ? new ByReferenceType(arrayType.ElementType) : null;
             }
         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:
         case Code.Stelem_Any:
             if (forceInferChildren) {
                 ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
                 InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
                 if (arrayType != null) {
                     InferTypeForExpression(expr.Arguments[2], arrayType.ElementType);
                 }
             }
             return null;
             #endregion
             #region Conversion instructions
         case Code.Conv_I1:
         case Code.Conv_Ovf_I1:
             return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == true) ? expectedType : typeSystem.SByte;
         case Code.Conv_I2:
         case Code.Conv_Ovf_I2:
             return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int16;
         case Code.Conv_I4:
         case Code.Conv_Ovf_I4:
             return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int32;
         case Code.Conv_I8:
         case Code.Conv_Ovf_I8:
             return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == true) ? expectedType : typeSystem.Int64;
         case Code.Conv_U1:
         case Code.Conv_Ovf_U1:
             return (GetInformationAmount(expectedType) == 8 && IsSigned(expectedType) == false) ? expectedType : typeSystem.Byte;
         case Code.Conv_U2:
         case Code.Conv_Ovf_U2:
             return (GetInformationAmount(expectedType) == 16 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt16;
         case Code.Conv_U4:
         case Code.Conv_Ovf_U4:
             return (GetInformationAmount(expectedType) == 32 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt32;
         case Code.Conv_U8:
         case Code.Conv_Ovf_U8:
             return (GetInformationAmount(expectedType) == 64 && IsSigned(expectedType) == false) ? expectedType : typeSystem.UInt64;
         case Code.Conv_I:
         case Code.Conv_Ovf_I:
             return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == true) ? expectedType : typeSystem.IntPtr;
         case Code.Conv_U:
         case Code.Conv_Ovf_U:
             return (GetInformationAmount(expectedType) == nativeInt && IsSigned(expectedType) == false) ? expectedType : typeSystem.UIntPtr;
         case Code.Conv_R4:
             return typeSystem.Single;
         case Code.Conv_R8:
             return typeSystem.Double;
         case Code.Conv_R_Un:
             return (expectedType == typeSystem.Single) ? typeSystem.Single : typeSystem.Double;
         case Code.Castclass:
         case Code.Isinst:
         case Code.Unbox_Any:
             return (TypeReference)expr.Operand;
         case Code.Box:
             if (forceInferChildren)
                 InferTypeForExpression(expr.Arguments.Single(), (TypeReference)expr.Operand);
             return (TypeReference)expr.Operand;
             #endregion
             #region Comparison instructions
         case Code.Ceq:
             if (forceInferChildren)
                 InferArgumentsInBinaryOperator(expr, null);
             return typeSystem.Boolean;
         case Code.Clt:
         case Code.Cgt:
             if (forceInferChildren)
                 InferArgumentsInBinaryOperator(expr, true);
             return typeSystem.Boolean;
         case Code.Clt_Un:
         case Code.Cgt_Un:
             if (forceInferChildren)
                 InferArgumentsInBinaryOperator(expr, false);
             return typeSystem.Boolean;
             #endregion
             #region Branch instructions
         case Code.Beq:
         case Code.Bne_Un:
             if (forceInferChildren)
                 InferArgumentsInBinaryOperator(expr, null);
             return null;
         case Code.Brtrue:
         case Code.Brfalse:
             if (forceInferChildren)
                 InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
             return null;
         case Code.Blt:
         case Code.Ble:
         case Code.Bgt:
         case Code.Bge:
             if (forceInferChildren)
                 InferArgumentsInBinaryOperator(expr, true);
             return null;
         case Code.Blt_Un:
         case Code.Ble_Un:
         case Code.Bgt_Un:
         case Code.Bge_Un:
             if (forceInferChildren)
                 InferArgumentsInBinaryOperator(expr, false);
             return null;
         case Code.Br:
         case Code.Leave:
         case Code.Endfinally:
         case Code.Switch:
         case Code.Throw:
         case Code.Rethrow:
             return null;
         case Code.Ret:
             if (forceInferChildren && expr.Arguments.Count == 1)
                 InferTypeForExpression(expr.Arguments[0], context.CurrentMethod.ReturnType);
             return null;
             #endregion
         case Code.Pop:
             return null;
         case Code.Dup:
             return InferTypeForExpression(expr.Arguments.Single(), expectedType);
         default:
             Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName());
             return null;
     }
 }
Example #18
0
 Ast.Expression MakeBranchCondition(ILExpression expr)
 {
     List<Ast.Expression> args = TransformExpressionArguments(expr);
     Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
     Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
     switch(expr.OpCode.Code) {
         case Code.Brfalse: return new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1);
         case Code.Brtrue:  return arg1;
         case Code.Beq:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
         case Code.Bge:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
         case Code.Bge_Un:  return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2);
         case Code.Bgt:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
         case Code.Bgt_Un:  return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
         case Code.Ble:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
         case Code.Ble_Un:  return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2);
         case Code.Blt:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
         case Code.Blt_Un:  return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
         case Code.Bne_Un:  return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
         default: throw new Exception("Bad opcode");
     }
     /*
     } else if (branch is ShortCircuitBranch) {
         ShortCircuitBranch scBranch = (ShortCircuitBranch)branch;
         switch(scBranch.Operator) {
             case ShortCircuitOperator.LeftAndRight:
                 return new BinaryOperatorExpression(
                     MakeBranchCondition(scBranch.Left),
                     BinaryOperatorType.ConditionalAnd,
                     MakeBranchCondition(scBranch.Right)
                 );
             case ShortCircuitOperator.LeftOrRight:
                 return new BinaryOperatorExpression(
                     MakeBranchCondition(scBranch.Left),
                     BinaryOperatorType.ConditionalOr,
                     MakeBranchCondition(scBranch.Right)
                 );
             case ShortCircuitOperator.NotLeftAndRight:
                 return new BinaryOperatorExpression(
                     new UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(scBranch.Left)),
                     BinaryOperatorType.ConditionalAnd,
                     MakeBranchCondition(scBranch.Right)
                 );
             case ShortCircuitOperator.NotLeftOrRight:
                 return new BinaryOperatorExpression(
                     new UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(scBranch.Left)),
                     BinaryOperatorType.ConditionalOr,
                     MakeBranchCondition(scBranch.Right)
                 );
             default:
                 throw new Exception("Bad operator");
         }
     } else {
         throw new Exception("Bad type");
     }
     */
 }
Example #19
0
 AstNode TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
 {
     try {
         AstNode ret = TransformByteCode_Internal(methodDef, byteCode, args);
         // ret.UserData["Type"] = byteCode.Type;
         return ret;
     } catch (NotImplementedException) {
         // Output the operand of the unknown IL code as well
         if (byteCode.Operand != null) {
             args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
         }
         return new IdentifierExpression(byteCode.OpCode.Name).Invoke(args);
     }
 }
Example #20
0
        AstNode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
        {
            // throw new NotImplementedException();

            OpCode opCode = byteCode.OpCode;
            object operand = byteCode.Operand;
            AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
            ILExpression operandAsByteCode = operand as ILExpression;
            Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
            Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
            Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;

            BlockStatement branchCommand = null;
            if (byteCode.Operand is ILLabel) {
                branchCommand = new BlockStatement();
                branchCommand.AddStatement(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
            }

            switch(opCode.Code) {
                    #region Arithmetic
                    case Code.Add:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Add_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Div:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
                    case Code.Div_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
                    case Code.Mul:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Mul_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Rem:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
                    case Code.Rem_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
                    case Code.Sub:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.Sub_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.And:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2);
                    case Code.Or:         return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2);
                    case Code.Xor:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2);
                    case Code.Shl:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2);
                    case Code.Shr:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
                    case Code.Shr_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);

                    case Code.Neg:        return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1);
                    case Code.Not:        return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
                    #endregion
                    #region Arrays
                case Code.Newarr:
                    operandAsTypeRef = operandAsTypeRef.MakeArrayType(0);
                    return new Ast.ArrayCreateExpression {
                        Type = operandAsTypeRef,
                        Arguments = new Expression[] {arg1}
                    };

                case Code.Ldlen:
                    return arg1.Member("Length");

                case Code.Ldelem_I:
                case Code.Ldelem_I1:
                case Code.Ldelem_I2:
                case Code.Ldelem_I4:
                case Code.Ldelem_I8:
                case Code.Ldelem_U1:
                case Code.Ldelem_U2:
                case Code.Ldelem_U4:
                case Code.Ldelem_R4:
                case Code.Ldelem_R8:
                case Code.Ldelem_Ref:
                    return arg1.Indexer(arg2);
                case Code.Ldelem_Any:
                    throw new NotImplementedException();
                case Code.Ldelema:
                    return MakeRef(arg1.Indexer(arg2));

                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:
                    return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
                case Code.Stelem_Any:
                    throw new NotImplementedException();
                    #endregion
                    #region Branching
                    case Code.Br:      return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
                    case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1), branchCommand);
                    case Code.Brtrue:  return new Ast.IfElseStatement(arg1, branchCommand);
                    case Code.Beq:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand);
                    case Code.Bge:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
                    case Code.Bge_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
                    case Code.Bgt:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand);
                    case Code.Bgt_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand);
                    case Code.Ble:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand);
                    case Code.Ble_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand);
                    case Code.Blt:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
                    case Code.Blt_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
                    case Code.Bne_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand);
                    #endregion
                    #region Comparison
                    case Code.Ceq:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2));
                    case Code.Cgt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                    case Code.Cgt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                    case Code.Clt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                    case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                    #endregion
                    #region Conversions
                    case Code.Conv_I:    return arg1.CastTo(typeof(int)); // TODO
                    case Code.Conv_I1:   return arg1.CastTo(typeof(SByte));
                    case Code.Conv_I2:   return arg1.CastTo(typeof(Int16));
                    case Code.Conv_I4:   return arg1.CastTo(typeof(Int32));
                    case Code.Conv_I8:   return arg1.CastTo(typeof(Int64));
                    case Code.Conv_U:    return arg1.CastTo(typeof(uint)); // TODO
                    case Code.Conv_U1:   return arg1.CastTo(typeof(Byte));
                    case Code.Conv_U2:   return arg1.CastTo(typeof(UInt16));
                    case Code.Conv_U4:   return arg1.CastTo(typeof(UInt32));
                    case Code.Conv_U8:   return arg1.CastTo(typeof(UInt64));
                    case Code.Conv_R4:   return arg1.CastTo(typeof(float));
                    case Code.Conv_R8:   return arg1.CastTo(typeof(double));
                    case Code.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO

                    case Code.Conv_Ovf_I:  return arg1.CastTo(typeof(int));
                    case Code.Conv_Ovf_I1: return arg1.CastTo(typeof(SByte));
                    case Code.Conv_Ovf_I2: return arg1.CastTo(typeof(Int16));
                    case Code.Conv_Ovf_I4: return arg1.CastTo(typeof(Int32));
                    case Code.Conv_Ovf_I8: return arg1.CastTo(typeof(Int64));
                    case Code.Conv_Ovf_U:  return arg1.CastTo(typeof(uint));
                    case Code.Conv_Ovf_U1: return arg1.CastTo(typeof(Byte));
                    case Code.Conv_Ovf_U2: return arg1.CastTo(typeof(UInt16));
                    case Code.Conv_Ovf_U4: return arg1.CastTo(typeof(UInt32));
                    case Code.Conv_Ovf_U8: return arg1.CastTo(typeof(UInt64));

                    case Code.Conv_Ovf_I_Un:  return arg1.CastTo(typeof(int));
                    case Code.Conv_Ovf_I1_Un: return arg1.CastTo(typeof(SByte));
                    case Code.Conv_Ovf_I2_Un: return arg1.CastTo(typeof(Int16));
                    case Code.Conv_Ovf_I4_Un: return arg1.CastTo(typeof(Int32));
                    case Code.Conv_Ovf_I8_Un: return arg1.CastTo(typeof(Int64));
                    case Code.Conv_Ovf_U_Un:  return arg1.CastTo(typeof(uint));
                    case Code.Conv_Ovf_U1_Un: return arg1.CastTo(typeof(Byte));
                    case Code.Conv_Ovf_U2_Un: return arg1.CastTo(typeof(UInt16));
                    case Code.Conv_Ovf_U4_Un: return arg1.CastTo(typeof(UInt32));
                    case Code.Conv_Ovf_U8_Un: return arg1.CastTo(typeof(UInt64));
                    #endregion
                    #region Indirect
                    case Code.Ldind_I: throw new NotImplementedException();
                    case Code.Ldind_I1: throw new NotImplementedException();
                    case Code.Ldind_I2: throw new NotImplementedException();
                    case Code.Ldind_I4: throw new NotImplementedException();
                    case Code.Ldind_I8: throw new NotImplementedException();
                    case Code.Ldind_U1: throw new NotImplementedException();
                    case Code.Ldind_U2: throw new NotImplementedException();
                    case Code.Ldind_U4: throw new NotImplementedException();
                    case Code.Ldind_R4: throw new NotImplementedException();
                    case Code.Ldind_R8: throw new NotImplementedException();
                    case Code.Ldind_Ref: throw new NotImplementedException();

                    case Code.Stind_I: throw new NotImplementedException();
                    case Code.Stind_I1: throw new NotImplementedException();
                    case Code.Stind_I2: throw new NotImplementedException();
                    case Code.Stind_I4: throw new NotImplementedException();
                    case Code.Stind_I8: throw new NotImplementedException();
                    case Code.Stind_R4: throw new NotImplementedException();
                    case Code.Stind_R8: throw new NotImplementedException();
                    case Code.Stind_Ref: throw new NotImplementedException();
                    #endregion
                    case Code.Arglist: throw new NotImplementedException();
                    case Code.Box: throw new NotImplementedException();
                    case Code.Break: throw new NotImplementedException();
                case Code.Call:
                    return TransformCall(false, operand, methodDef, args);
                case Code.Callvirt:
                    return TransformCall(true, operand, methodDef, args);
                case Code.Ldftn:
                    {
                        Cecil.MethodReference cecilMethod = ((MethodReference)operand);
                        var expr = new Ast.IdentifierExpression(cecilMethod.Name);
                        expr.TypeArguments = ConvertTypeArguments(cecilMethod);
                        expr.AddAnnotation(cecilMethod);
                        return new IdentifierExpression("ldftn").Invoke(expr)
                            .WithAnnotation(new Transforms.DelegateConstruction.Annotation(false, methodDef.DeclaringType));
                    }
                case Code.Ldvirtftn:
                    {
                        Cecil.MethodReference cecilMethod = ((MethodReference)operand);
                        var expr = new Ast.IdentifierExpression(cecilMethod.Name);
                        expr.TypeArguments = ConvertTypeArguments(cecilMethod);
                        expr.AddAnnotation(cecilMethod);
                        return new IdentifierExpression("ldvirtftn").Invoke(expr)
                            .WithAnnotation(new Transforms.DelegateConstruction.Annotation(true, methodDef.DeclaringType));
                    }

                    case Code.Calli: throw new NotImplementedException();
                    case Code.Castclass: return arg1.CastTo(operandAsTypeRef);
                    case Code.Ckfinite: throw new NotImplementedException();
                    case Code.Constrained: throw new NotImplementedException();
                    case Code.Cpblk: throw new NotImplementedException();
                    case Code.Cpobj: throw new NotImplementedException();
                    case Code.Dup: return arg1;
                    case Code.Endfilter: throw new NotImplementedException();
                    case Code.Endfinally: return null;
                    case Code.Initblk: throw new NotImplementedException();
                    case Code.Initobj: throw new NotImplementedException();
                    case Code.Isinst: return arg1.IsType(AstBuilder.ConvertType((Cecil.TypeReference)operand));
                    case Code.Jmp: throw new NotImplementedException();
                case Code.Ldarg:
                    if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
                        return new Ast.ThisReferenceExpression();
                    } else {
                        return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name);
                    }
                case Code.Ldarga:
                    if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
                        return MakeRef(new Ast.ThisReferenceExpression());
                    } else {
                        return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name));
                    }
                case Code.Ldc_I4:
                case Code.Ldc_I8:
                case Code.Ldc_R4:
                case Code.Ldc_R8:
                    return new Ast.PrimitiveExpression(operand);
                case Code.Ldfld:
                    return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand);
                case Code.Ldsfld:
                    return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand);
                case Code.Stfld:
                    return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2);
                case Code.Stsfld:
                    return new AssignmentExpression(
                        AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand),
                        arg1);
                case Code.Ldflda:
                    return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand));
                case Code.Ldsflda:
                    return MakeRef(
                        AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand));
                case Code.Ldloc:
                    if (operand is ILVariable) {
                        return new Ast.IdentifierExpression(((ILVariable)operand).Name);
                    } else {
                        return new Ast.IdentifierExpression(((VariableDefinition)operand).Name);
                    }
                case Code.Ldloca:
                    if (operand is ILVariable) {
                        return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name));
                    } else {
                        return MakeRef(new Ast.IdentifierExpression(((VariableDefinition)operand).Name));
                    }
                    case Code.Ldnull: return new Ast.NullReferenceExpression();
                    case Code.Ldobj: throw new NotImplementedException();
                    case Code.Ldstr: return new Ast.PrimitiveExpression(operand);
                case Code.Ldtoken:
                    if (operand is Cecil.TypeReference) {
                        return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle");
                    } else {
                        throw new NotImplementedException();
                    }
                    case Code.Leave: return null;
                    case Code.Localloc: throw new NotImplementedException();
                    case Code.Mkrefany: throw new NotImplementedException();
                case Code.Newobj:
                    Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
                    // TODO: Ensure that the corrent overloaded constructor is called
                    if (declaringType is ArrayType) {
                        return new Ast.ArrayCreateExpression {
                            Type = AstBuilder.ConvertType((ArrayType)declaringType),
                            Arguments = args
                        };
                    }
                    return new Ast.ObjectCreateExpression {
                        Type = AstBuilder.ConvertType(declaringType),
                        Arguments = args
                    };
                    case Code.No: throw new NotImplementedException();
                    case Code.Nop: return null;
                    case Code.Pop: return arg1;
                    case Code.Readonly: throw new NotImplementedException();
                    case Code.Refanytype: throw new NotImplementedException();
                    case Code.Refanyval: throw new NotImplementedException();
                    case Code.Ret: {
                        if (methodDef.ReturnType.FullName != Constants.Void) {
                            arg1 = Convert(arg1, methodDef.ReturnType);
                            return new Ast.ReturnStatement { Expression = arg1 };
                        } else {
                            return new Ast.ReturnStatement();
                        }
                    }
                    case Code.Rethrow: return new Ast.ThrowStatement();
                    case Code.Sizeof: return new Ast.SizeOfExpression { Type = AstBuilder.ConvertType(operand as TypeReference) };
                    case Code.Starg: throw new NotImplementedException();
                    case Code.Stloc: {
                        ILVariable locVar = (ILVariable)operand;
                        if (!definedLocalVars.Contains(locVar)) {
                            definedLocalVars.Add(locVar);
                            return new Ast.VariableDeclarationStatement() {
                                Type = locVar.Type != null ? AstBuilder.ConvertType(locVar.Type) : new Ast.PrimitiveType("var"),
                                Variables = new[] { new Ast.VariableInitializer(locVar.Name, arg1) }
                            };
                        } else {
                            return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name), arg1);
                        }
                    }
                    case Code.Stobj: throw new NotImplementedException();
                    case Code.Switch: throw new NotImplementedException();
                    case Code.Tail: throw new NotImplementedException();
                    case Code.Throw: return new Ast.ThrowStatement { Expression = arg1 };
                    case Code.Unaligned: throw new NotImplementedException();
                    case Code.Unbox: throw new NotImplementedException();
                    case Code.Unbox_Any: throw new NotImplementedException();
                    case Code.Volatile: throw new NotImplementedException();
                    default: throw new Exception("Unknown OpCode: " + opCode);
            }
        }
Example #21
0
 List<Ast.Expression> TransformExpressionArguments(ILExpression expr)
 {
     List<Ast.Expression> args = new List<Ast.Expression>();
     // Args generated by nested expressions (which must be closed)
     foreach(ILExpression arg in expr.Arguments) {
         args.Add((Ast.Expression)TransformExpression(arg));
     }
     return args;
 }
Example #22
0
        AstNode TransformByteCode(ILExpression byteCode, List<Ast.Expression> args)
        {
            ILCode opCode = byteCode.Code;
            object operand = byteCode.Operand;
            AstType operandAsTypeRef = AstBuilder.ConvertType(operand as Cecil.TypeReference);
            ILExpression operandAsByteCode = operand as ILExpression;
            Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
            Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
            Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;

            BlockStatement branchCommand = null;
            if (byteCode.Operand is ILLabel) {
                branchCommand = new BlockStatement();
                branchCommand.Add(new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name));
            }

            switch((Code)opCode) {
                    #region Arithmetic
                    case Code.Add:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Add_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Add_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Add, arg2);
                    case Code.Div:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
                    case Code.Div_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Divide, arg2);
                    case Code.Mul:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Mul_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Mul_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Multiply, arg2);
                    case Code.Rem:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
                    case Code.Rem_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Modulus, arg2);
                    case Code.Sub:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.Sub_Ovf:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.Sub_Ovf_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Subtract, arg2);
                    case Code.And:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseAnd, arg2);
                    case Code.Or:         return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.BitwiseOr, arg2);
                    case Code.Xor:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ExclusiveOr, arg2);
                    case Code.Shl:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftLeft, arg2);
                    case Code.Shr:        return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);
                    case Code.Shr_Un:     return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.ShiftRight, arg2);

                    case Code.Neg:        return new Ast.UnaryOperatorExpression(UnaryOperatorType.Minus, arg1);
                    case Code.Not:        return new Ast.UnaryOperatorExpression(UnaryOperatorType.BitNot, arg1);
                    #endregion
                    #region Arrays
                case Code.Newarr:
                    {
                        var ace = new Ast.ArrayCreateExpression();
                        ace.Type = operandAsTypeRef;
                        ace.Arguments.Add(arg1);
                        return ace;
                    }
                case Code.Ldlen:
                    return arg1.Member("Length");
                case Code.Ldelem_I:
                case Code.Ldelem_I1:
                case Code.Ldelem_I2:
                case Code.Ldelem_I4:
                case Code.Ldelem_I8:
                case Code.Ldelem_U1:
                case Code.Ldelem_U2:
                case Code.Ldelem_U4:
                case Code.Ldelem_R4:
                case Code.Ldelem_R8:
                case Code.Ldelem_Ref:
                    return arg1.Indexer(arg2);
                case Code.Ldelem_Any:
                    return InlineAssembly(byteCode, args);
                case Code.Ldelema:
                    return MakeRef(arg1.Indexer(arg2));

                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:
                    return new Ast.AssignmentExpression(arg1.Indexer(arg2), arg3);
                case Code.Stelem_Any:
                    return InlineAssembly(byteCode, args);
                    #endregion
                    #region Branching
                    case Code.Br:      return new Ast.GotoStatement(((ILLabel)byteCode.Operand).Name);
                    case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(UnaryOperatorType.Not, arg1), branchCommand);
                    case Code.Brtrue:  return new Ast.IfElseStatement(arg1, branchCommand);
                    case Code.Beq:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), branchCommand);
                    case Code.Bge:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
                    case Code.Bge_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), branchCommand);
                    case Code.Bgt:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand);
                    case Code.Bgt_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), branchCommand);
                    case Code.Ble:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand);
                    case Code.Ble_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), branchCommand);
                    case Code.Blt:     return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
                    case Code.Blt_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), branchCommand);
                    case Code.Bne_Un:  return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), branchCommand);
                    #endregion
                    #region Comparison
                    case Code.Ceq:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
                    case Code.Cgt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                case Code.Cgt_Un:
                    // can also mean Inequality, when used with object references
                    {
                        TypeReference arg1Type = byteCode.Arguments[0].InferredType;
                        if (arg1Type != null && !arg1Type.IsValueType)
                            return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2);
                        else
                            return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2);
                    }
                    case Code.Clt:    return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                    case Code.Clt_Un: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2);
                    #endregion
                    #region Conversions
                case Code.Conv_I1:
                case Code.Conv_I2:
                case Code.Conv_I4:
                case Code.Conv_I8:
                case Code.Conv_U1:
                case Code.Conv_U2:
                case Code.Conv_U4:
                case Code.Conv_U8:
                    return arg1; // conversion is handled by Convert() function using the info from type analysis
                    case Code.Conv_I:    return arg1.CastTo(typeof(IntPtr)); // TODO
                    case Code.Conv_U:    return arg1.CastTo(typeof(UIntPtr)); // TODO
                    case Code.Conv_R4:   return arg1.CastTo(typeof(float));
                    case Code.Conv_R8:   return arg1.CastTo(typeof(double));
                    case Code.Conv_R_Un: return arg1.CastTo(typeof(double)); // TODO

                case Code.Conv_Ovf_I1:
                case Code.Conv_Ovf_I2:
                case Code.Conv_Ovf_I4:
                case Code.Conv_Ovf_I8:
                case Code.Conv_Ovf_U1:
                case Code.Conv_Ovf_U2:
                case Code.Conv_Ovf_U4:
                case Code.Conv_Ovf_U8:
                case Code.Conv_Ovf_I1_Un:
                case Code.Conv_Ovf_I2_Un:
                case Code.Conv_Ovf_I4_Un:
                case Code.Conv_Ovf_I8_Un:
                case Code.Conv_Ovf_U1_Un:
                case Code.Conv_Ovf_U2_Un:
                case Code.Conv_Ovf_U4_Un:
                case Code.Conv_Ovf_U8_Un:
                    return arg1; // conversion was handled by Convert() function using the info from type analysis
                    case Code.Conv_Ovf_I:  return arg1.CastTo(typeof(IntPtr)); // TODO
                    case Code.Conv_Ovf_U:  return arg1.CastTo(typeof(UIntPtr));
                    case Code.Conv_Ovf_I_Un:  return arg1.CastTo(typeof(IntPtr));
                    case Code.Conv_Ovf_U_Un:  return arg1.CastTo(typeof(UIntPtr));

                case Code.Castclass:
                case Code.Unbox_Any:
                    return arg1.CastTo(operandAsTypeRef);
                case Code.Isinst:
                    return arg1.CastAs(operandAsTypeRef);
                case Code.Box:
                    return arg1;
                case Code.Unbox:
                    return InlineAssembly(byteCode, args);
                    #endregion
                    #region Indirect
                    case Code.Ldind_I: return InlineAssembly(byteCode, args);
                    case Code.Ldind_I1: return InlineAssembly(byteCode, args);
                    case Code.Ldind_I2: return InlineAssembly(byteCode, args);
                    case Code.Ldind_I4: return InlineAssembly(byteCode, args);
                    case Code.Ldind_I8: return InlineAssembly(byteCode, args);
                    case Code.Ldind_U1: return InlineAssembly(byteCode, args);
                    case Code.Ldind_U2: return InlineAssembly(byteCode, args);
                    case Code.Ldind_U4: return InlineAssembly(byteCode, args);
                    case Code.Ldind_R4: return InlineAssembly(byteCode, args);
                    case Code.Ldind_R8: return InlineAssembly(byteCode, args);
                    case Code.Ldind_Ref: return InlineAssembly(byteCode, args);

                    case Code.Stind_I: return InlineAssembly(byteCode, args);
                    case Code.Stind_I1: return InlineAssembly(byteCode, args);
                    case Code.Stind_I2: return InlineAssembly(byteCode, args);
                    case Code.Stind_I4: return InlineAssembly(byteCode, args);
                    case Code.Stind_I8: return InlineAssembly(byteCode, args);
                    case Code.Stind_R4: return InlineAssembly(byteCode, args);
                    case Code.Stind_R8: return InlineAssembly(byteCode, args);
                    case Code.Stind_Ref: return InlineAssembly(byteCode, args);
                    #endregion
                    case Code.Arglist: return InlineAssembly(byteCode, args);
                    case Code.Break: return InlineAssembly(byteCode, args);
                case Code.Call:
                    return TransformCall(false, operand, methodDef, args);
                case Code.Callvirt:
                    return TransformCall(true, operand, methodDef, args);
                case Code.Ldftn:
                    {
                        Cecil.MethodReference cecilMethod = ((MethodReference)operand);
                        var expr = new Ast.IdentifierExpression(cecilMethod.Name);
                        expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod));
                        expr.AddAnnotation(cecilMethod);
                        return new IdentifierExpression("ldftn").Invoke(expr)
                            .WithAnnotation(new Transforms.DelegateConstruction.Annotation(false));
                    }
                case Code.Ldvirtftn:
                    {
                        Cecil.MethodReference cecilMethod = ((MethodReference)operand);
                        var expr = new Ast.IdentifierExpression(cecilMethod.Name);
                        expr.TypeArguments.AddRange(ConvertTypeArguments(cecilMethod));
                        expr.AddAnnotation(cecilMethod);
                        return new IdentifierExpression("ldvirtftn").Invoke(expr)
                            .WithAnnotation(new Transforms.DelegateConstruction.Annotation(true));
                    }

                    case Code.Calli: return InlineAssembly(byteCode, args);
                    case Code.Ckfinite: return InlineAssembly(byteCode, args);
                    case Code.Constrained: return InlineAssembly(byteCode, args);
                    case Code.Cpblk: return InlineAssembly(byteCode, args);
                    case Code.Cpobj: return InlineAssembly(byteCode, args);
                    case Code.Dup: return arg1;
                    case Code.Endfilter: return InlineAssembly(byteCode, args);
                    case Code.Endfinally: return null;
                    case Code.Initblk: return InlineAssembly(byteCode, args);
                    case Code.Initobj: return InlineAssembly(byteCode, args);
                    case Code.Jmp: return InlineAssembly(byteCode, args);
                case Code.Ldarg:
                    if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
                        return new Ast.ThisReferenceExpression();
                    } else {
                        return new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand);
                    }
                case Code.Ldarga:
                    if (methodDef.HasThis && ((ParameterDefinition)operand).Index < 0) {
                        return MakeRef(new Ast.ThisReferenceExpression());
                    } else {
                        return MakeRef(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand));
                    }
                case Code.Ldc_I4:
                    return PrimitiveExpression((int)operand, byteCode.InferredType);
                case Code.Ldc_I8:
                case Code.Ldc_R4:
                case Code.Ldc_R8:
                    return new Ast.PrimitiveExpression(operand);
                case Code.Ldfld:
                    return arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand);
                case Code.Ldsfld:
                    return AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand);
                case Code.Stfld:
                    return new AssignmentExpression(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand), arg2);
                case Code.Stsfld:
                    return new AssignmentExpression(
                        AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand),
                        arg1);
                case Code.Ldflda:
                    return MakeRef(arg1.Member(((FieldReference) operand).Name).WithAnnotation(operand));
                case Code.Ldsflda:
                    return MakeRef(
                        AstBuilder.ConvertType(((FieldReference)operand).DeclaringType)
                        .Member(((FieldReference)operand).Name).WithAnnotation(operand));
                case Code.Ldloc:
                    return new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand);
                case Code.Ldloca:
                    return MakeRef(new Ast.IdentifierExpression(((ILVariable)operand).Name).WithAnnotation(operand));
                    case Code.Ldnull: return new Ast.NullReferenceExpression();
                    case Code.Ldobj: return InlineAssembly(byteCode, args);
                    case Code.Ldstr: return new Ast.PrimitiveExpression(operand);
                case Code.Ldtoken:
                    if (operand is Cecil.TypeReference) {
                        return new Ast.TypeOfExpression { Type = operandAsTypeRef }.Member("TypeHandle");
                    } else {
                        return InlineAssembly(byteCode, args);
                    }
                    case Code.Leave: return null;
                    case Code.Localloc: return InlineAssembly(byteCode, args);
                    case Code.Mkrefany: return InlineAssembly(byteCode, args);
                case Code.Newobj:
                    {
                        Cecil.TypeReference declaringType = ((MethodReference)operand).DeclaringType;
                        // TODO: Ensure that the corrent overloaded constructor is called

                        /*if (declaringType is ArrayType) { shouldn't this be newarr?
                        return new Ast.ArrayCreateExpression {
                            Type = AstBuilder.ConvertType((ArrayType)declaringType),
                            Arguments = args
                        };
                    }*/
                        var oce = new Ast.ObjectCreateExpression();
                        oce.Type = AstBuilder.ConvertType(declaringType);
                        oce.Arguments.AddRange(args);
                        return oce.WithAnnotation(operand);
                    }
                    case Code.No: return InlineAssembly(byteCode, args);
                    case Code.Nop: return null;
                    case Code.Pop: return arg1;
                    case Code.Readonly: return InlineAssembly(byteCode, args);
                    case Code.Refanytype: return InlineAssembly(byteCode, args);
                    case Code.Refanyval: return InlineAssembly(byteCode, args);
                    case Code.Ret: {
                        if (methodDef.ReturnType.FullName != "System.Void") {
                            return new Ast.ReturnStatement { Expression = arg1 };
                        } else {
                            return new Ast.ReturnStatement();
                        }
                    }
                    case Code.Rethrow: return new Ast.ThrowStatement();
                    case Code.Sizeof: return new Ast.SizeOfExpression { Type = AstBuilder.ConvertType(operand as TypeReference) };
                case Code.Starg:
                    return new Ast.AssignmentExpression(new Ast.IdentifierExpression(((ParameterDefinition)operand).Name).WithAnnotation(operand), arg1);
                    case Code.Stloc: {
                        ILVariable locVar = (ILVariable)operand;
                        if (!localVariablesToDefine.Contains(locVar)) {
                            localVariablesToDefine.Add(locVar);
                        }
                        return new Ast.AssignmentExpression(new Ast.IdentifierExpression(locVar.Name).WithAnnotation(locVar), arg1);
                    }
                    case Code.Stobj: return InlineAssembly(byteCode, args);
                    case Code.Switch: return InlineAssembly(byteCode, args);
                    case Code.Tail: return InlineAssembly(byteCode, args);
                    case Code.Throw: return new Ast.ThrowStatement { Expression = arg1 };
                    case Code.Unaligned: return InlineAssembly(byteCode, args);
                    case Code.Volatile: return InlineAssembly(byteCode, args);
                    default: throw new Exception("Unknown OpCode: " + opCode);
            }
        }
Example #23
0
        List<ILNode> ConvertToAst(List<ByteCode> body)
        {
            List<ILNode> ast = new List<ILNode>();

            // Convert stack-based IL code to ILAst tree
            foreach(ByteCode byteCode in body) {
                OpCode opCode  = byteCode.OpCode;
                object operand = byteCode.Operand;

                MethodBodyRocks.ExpandMacro(ref opCode, ref operand, methodDef.Body);

                ILExpression expr = new ILExpression(opCode, operand);
                expr.ILRanges.Add(new ILRange() { From = byteCode.Offset, To = byteCode.EndOffset });

                // Label for this instruction
                if (byteCode.Label != null) {
                    ast.Add(byteCode.Label);
                }

                // Reference arguments using temporary variables
                int popCount = byteCode.PopCount ?? byteCode.StackBefore.Count;
                for (int i = byteCode.StackBefore.Count - popCount; i < byteCode.StackBefore.Count; i++) {
                    StackSlot slot = byteCode.StackBefore[i];
                    if (slot.PushedBy != null) {
                        ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, slot.LoadFrom);
                        expr.Arguments.Add(ldExpr);
                    } else {
                        ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILVariable() { Name = "ex", IsGenerated = true });
                        expr.Arguments.Add(ldExpr);
                    }
                }

                // Store the result to temporary variable(s) if needed
                if (byteCode.StoreTo == null || byteCode.StoreTo.Count == 0) {
                    ast.Add(expr);
                } else if (byteCode.StoreTo.Count == 1) {
                    ast.Add(new ILExpression(OpCodes.Stloc, byteCode.StoreTo[0], expr));
                } else {
                    ILVariable tmpVar = new ILVariable() { Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true };
                    ast.Add(new ILExpression(OpCodes.Stloc, tmpVar, expr));
                    foreach(ILVariable storeTo in byteCode.StoreTo) {
                        ast.Add(new ILExpression(OpCodes.Stloc, storeTo, new ILExpression(OpCodes.Ldloc, tmpVar)));
                    }
                }
            }

            // Try to in-line stloc / ldloc pairs
            for(int i = 0; i < ast.Count - 1; i++) {
                if (i < 0) continue;

                ILExpression currExpr = ast[i] as ILExpression;
                ILExpression nextExpr = ast[i + 1] as ILExpression;

                if (currExpr != null && nextExpr != null && currExpr.OpCode.Code == Code.Stloc) {

                    // If the next expression is generated stloc, look inside
                    if (nextExpr.OpCode.Code == Code.Stloc && ((ILVariable)nextExpr.Operand).IsGenerated) {
                        nextExpr = nextExpr.Arguments[0];
                    }

                    // Find the use of the 'expr'
                    for(int j = 0; j < nextExpr.Arguments.Count; j++) {
                        ILExpression arg = nextExpr.Arguments[j];

                        // We are moving the expression evaluation past the other aguments.
                        // It is ok to pass ldloc because the expression can not contain stloc and thus the ldcoc will still return the same value
                        if (arg.OpCode.Code == Code.Ldloc) {
                            bool canInline;
                            allowInline.TryGetValue((ILVariable)arg.Operand, out canInline);
                            if (arg.Operand == currExpr.Operand && canInline) {
                                // Assigne the ranges for optimized away instrustions somewhere
                                currExpr.Arguments[0].ILRanges.AddRange(currExpr.ILRanges);
                                currExpr.Arguments[0].ILRanges.AddRange(nextExpr.Arguments[j].ILRanges);
                                ast.RemoveAt(i);
                                nextExpr.Arguments[j] = currExpr.Arguments[0]; // Inline the stloc body
                                i -= 2; // Try the same index again
                                break;  // Found
                            }
                        } else {
                            break;  // Side-effects
                        }
                    }
                }
            }

            return ast;
        }
Example #24
0
 AstNode TransformExpression(ILExpression expr)
 {
     List<Ast.Expression> args = TransformExpressionArguments(expr);
     AstNode node = TransformByteCode(expr, args);
     Expression astExpr = node as Expression;
     if (astExpr != null)
         return Convert(astExpr, expr.InferredType, expr.ExpectedType);
     else
         return node;
 }