bool TransformArrayInitializers(List<ILNode> body, ILExpression expr, int pos)
		{
			ILVariable v, v3;
			ILExpression newarrExpr;
			TypeReference elementType;
			ILExpression lengthExpr;
			int arrayLength;
			if (expr.Match(ILCode.Stloc, out v, out newarrExpr) &&
			    newarrExpr.Match(ILCode.Newarr, out elementType, out lengthExpr) &&
			    lengthExpr.Match(ILCode.Ldc_I4, out arrayLength) &&
			    arrayLength > 0) {
				ILExpression[] newArr;
				int initArrayPos;

				if (ForwardScanInitializeArrayRuntimeHelper(body, pos + 1, v, elementType, arrayLength, out newArr, out initArrayPos)) {
                    var arrayType = new ArrayType(
                        elementType,
                        new[] { new ArrayDimension(0, arrayLength) });

					body[pos] = new ILExpression(ILCode.Stloc, v, new ILExpression(ILCode.InitArray, arrayType, newArr));
					body.RemoveAt(initArrayPos);
				}

				// Put in a limit so that we don't consume too much memory if the code allocates a huge array
				// and populates it extremely sparsly. However, 255 "null" elements in a row actually occur in the Mono C# compiler!
				const int maxConsecutiveDefaultValueExpressions = 300;
				List<ILExpression> operands = new List<ILExpression>();
				int numberOfInstructionsToRemove = 0;
				for (int j = pos + 1; j < body.Count; j++) {
					ILExpression nextExpr = body[j] as ILExpression;
					int arrayPos;
					if (nextExpr != null &&
					    nextExpr.Code.IsStoreToArray() &&
					    nextExpr.Arguments[0].Match(ILCode.Ldloc, out v3) &&
					    v == v3 &&
					    nextExpr.Arguments[1].Match(ILCode.Ldc_I4, out arrayPos) &&
					    arrayPos >= operands.Count &&
					    arrayPos <= operands.Count + maxConsecutiveDefaultValueExpressions) {
						while (operands.Count < arrayPos)
							operands.Add(new ILExpression(ILCode.DefaultValue, elementType));
						operands.Add(nextExpr.Arguments[2]);
						numberOfInstructionsToRemove++;
					} else {
						break;
					}
				}
				if (operands.Count == arrayLength) {
                    var arrayType = new ArrayType(
                        elementType,
                        new[] { new ArrayDimension(0, arrayLength) });

					expr.Arguments[0] = new ILExpression(ILCode.InitArray, arrayType, operands);
					body.RemoveRange(pos + 1, numberOfInstructionsToRemove);

					new ILInlining(method).InlineIfPossible(body, ref pos);
					return true;
				}
			}
			return false;
		}
예제 #2
0
				public virtual bool Match(PatternMatcher pm, ILExpression e)
				{
					if (e.Arguments.Count != this.Arguments.Length || e.Prefixes != null) return false;
					for (int i = 0; i < this.Arguments.Length; i++)
						if (!this.Arguments[i].Match(pm, e.Arguments[i])) return false;
					return true;
				}
예제 #3
0
		static ILExpression EliminateDups(ILExpression expr)
		{
			if (expr.Code == ILCode.Dup)
				return expr.Arguments.Single();
			else
				return expr;
		}
		static bool TransformDecimalCtorToConstant(ILExpression expr)
		{
			IMethod r;
			List<ILExpression> args;
			if (expr.Match(ILCode.Newobj, out r, out args) &&
			    r.DeclaringType.Namespace == "System" &&
			    r.DeclaringType.Name == "Decimal")
			{
				if (args.Count == 1) {
					int val;
					if (args[0].Match(ILCode.Ldc_I4, out val)) {
						expr.Code = ILCode.Ldc_Decimal;
						expr.Operand = new decimal(val);
						expr.InferredType = r.DeclaringType.ToTypeSig();
						expr.Arguments.Clear();
						return true;
					}
				} else if (args.Count == 5) {
					int lo, mid, hi, isNegative, scale;
					if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) &&
					    expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) &&
					    expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) &&
					    expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) &&
					    expr.Arguments[4].Match(ILCode.Ldc_I4, out scale))
					{
						expr.Code = ILCode.Ldc_Decimal;
						expr.Operand = new decimal(lo, mid, hi, isNegative != 0, (byte)scale);
						expr.InferredType = r.DeclaringType.ToTypeSig();
						expr.Arguments.Clear();
						return true;
					}
				}
			}
			return false;
		}
예제 #5
0
    protected override ILExpression VisitExpression(ILExpression expression)
    {
        if (expression.Code == ILCode.Stloc)
        {
            var variable = (ILVariable)expression.Operand;

            if (variable.Type.HasInterface("System.IDisposable"))
            {
                var key = Tuple.Create(variable, currentScope);

                if (starts.Keys.Any(k => k.Item1 == variable && k.Item2 != currentScope))
                {
                    LogTo.Warning("Method {0}: Using cannot be added because reassigning a variable in a condition is not supported.", method);
                }
                else
                {
                    if (starts.ContainsKey(key))
                    {
                        UsingRanges.Add(new ILRange { From = starts[key], To = expression.FirstILOffset() });
                        starts.Remove(key);
                    }

                    if (!currentTrys.Contains(expression.LastILOffset()))
                        starts.Add(key, expression.LastILOffset());
                }
            }
        }
        if (expression.Code == ILCode.Ret && currentScope > 1)
        {
            EarlyReturns.Add(expression.FirstILOffset());
        }

        return base.VisitExpression(expression);
    }
예제 #6
0
		static ILExpression HandleDecimalConstants(ILExpression expr)
		{
			if (expr.Code == ILCode.Newobj) {
				MethodReference r = (MethodReference)expr.Operand;
				if (r.DeclaringType.Name == "Decimal" && r.DeclaringType.Namespace == "System") {
					if (expr.Arguments.Count == 1) {
						int? val = GetI4Constant(expr.Arguments[0]);
						if (val != null) {
							expr.Arguments.Clear();
							expr.Code = ILCode.Ldc_Decimal;
							expr.Operand = new decimal(val.Value);
							expr.InferredType = r.DeclaringType;
						}
					} else if (expr.Arguments.Count == 5) {
						int? lo = GetI4Constant(expr.Arguments[0]);
						int? mid = GetI4Constant(expr.Arguments[1]);
						int? hi = GetI4Constant(expr.Arguments[2]);
						int? isNegative = GetI4Constant(expr.Arguments[3]);
						int? scale = GetI4Constant(expr.Arguments[4]);
						if (lo != null && mid != null && hi != null && isNegative != null && scale != null) {
							expr.Arguments.Clear();
							expr.Code = ILCode.Ldc_Decimal;
							expr.Operand = new decimal(lo.Value, mid.Value, hi.Value, isNegative.Value != 0, (byte)scale);
							expr.InferredType = r.DeclaringType;
						}
					}
				}
			}
			return expr;
		}
예제 #7
0
 protected ILExpression CreateLabeledExpression(GMCode code)
 {
     int absolute = GMCodeUtil.getBranchOffset(CurrentRaw) + CurrentPC;
     ILExpression e = new ILExpression(code, GetLabel(absolute));
     e.Extra = (int)(CurrentRaw & 0xFFFF);
     e.ILRanges.Add(new ILRange(CurrentPC, CurrentPC));
     return e;
 }
예제 #8
0
			public bool SimplifyLiftedOperators(ILExpression expr)
			{
				if (Simplify(expr)) return true;

				bool modified = false;
				foreach (var a in expr.Arguments)
					modified |= SimplifyLiftedOperators(a);
				return modified;
			}
예제 #9
0
        /// <summary>
        /// Finds individual instructions within the block that represent higher level concepts related to dynamic call sites.
        /// This enables FindDynamicCallSites to locate and transform call sites in a single pass.
        /// </summary>
        public bool AnalyzeInstructions(List<ILNode> body, ILExpression expr, int pos) {
            bool result = false;

            var newInstruction = AnalyzeInstruction(expr, ref result);
            if (newInstruction != expr)
                body[pos] = newInstruction;

            return result;
        }
예제 #10
0
        bool SimplifyLiftedOperators(List<ILNode> body, ILExpression expr, int pos)
        {
            if (!new PatternMatcher(typeSystem).SimplifyLiftedOperators(expr)) return false;

            var inlining = new ILInlining(method);
            while (--pos >= 0 && inlining.InlineIfPossible(body, ref pos)) ;

            return true;
        }
예제 #11
0
		bool SimplifyLiftedOperators(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos)
		{
			if (!GetPatternMatcher(corLib).SimplifyLiftedOperators(expr)) return false;

			var inlining = GetILInlining(method);
			while (--pos >= 0 && inlining.InlineIfPossible(block, body, ref pos)) ;

			return true;
		}
예제 #12
0
파일: Pattern.cs 프로젝트: hlesesne/ILSpy
		public override bool Match(ILNode other)
		{
			ILExpression expr = other as ILExpression;
			if (expr != null && expr.Code == ILCode.Stloc && (!MustBeGenerated || ((ILVariable)expr.Operand).IsGenerated) && Match(this.Arguments, expr.Arguments)) {
				this.LastMatch = expr;
				return true;
			} else {
				return false;
			}
		}
		static bool TypeConversionSimplifications(List<ILNode> body, ILExpression expr, int pos)
		{
			bool modified = false;
			modified |= TransformDecimalCtorToConstant(expr);
			modified |= SimplifyLdcI4ConvI8(expr);
			modified |= RemoveConvIFromArrayCreation(expr);
			foreach(ILExpression arg in expr.Arguments) {
				modified |= TypeConversionSimplifications(null, arg, -1);
			}
			return modified;
		}
		static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos)
		{
			bool modified = false;
			expr = SimplifyLdObjAndStObj(expr, ref modified);
			if (modified && body != null)
				body[pos] = expr;
			for (int i = 0; i < expr.Arguments.Count; i++) {
				expr.Arguments[i] = SimplifyLdObjAndStObj(expr.Arguments[i], ref modified);
				modified |= SimplifyLdObjAndStObj(null, expr.Arguments[i], -1);
			}
			return modified;
		}
		static bool SimplifyLdcI4ConvI8(ILExpression expr)
		{
			ILExpression ldc;
			int val;
			if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) {
				expr.Code = ILCode.Ldc_I8;
				expr.Operand = (long)val;
				expr.Arguments.Clear();
				return true;
			}
			return false;
		}
예제 #16
0
 public ParameterDeclarationAnnotation(ILExpression expr)
 {
     Debug.Assert(expr.Code == ILCode.ExpressionTreeParameterDeclarations);
     for (int i = 0; i < expr.Arguments.Count - 1; i++) {
         ILExpression p = expr.Arguments[i];
         // p looks like this:
         //   stloc(v, call(Expression::Parameter, call(Type::GetTypeFromHandle, ldtoken(...)), ldstr(...)))
         ILVariable v = (ILVariable)p.Operand;
         TypeReference typeRef = (TypeReference)p.Arguments[0].Arguments[0].Arguments[0].Operand;
         string name = (string)p.Arguments[0].Arguments[1].Operand;
         Parameters.Add(new ParameterDeclaration(AstBuilder.ConvertType(typeRef), name).WithAnnotation(v));
     }
 }
예제 #17
0
		static bool SimplifyLdcI4ConvI8(ILExpression expr)
		{
			ILExpression ldc;
			int val;
			if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) {
				expr.Code = ILCode.Ldc_I8;
				expr.Operand = (long)val;
				foreach (var arg in expr.Arguments)
					expr.ILRanges.AddRange(arg.GetSelfAndChildrenRecursiveILRanges());
				expr.Arguments.Clear();
				return true;
			}
			return false;
		}
예제 #18
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;
		}
예제 #19
0
		bool SimplifyLdcI4ConvI8(ILExpression expr)
		{
			ILExpression ldc;
			int val;
			if (expr.Match(ILCode.Conv_I8, out ldc) && ldc.Match(ILCode.Ldc_I4, out val)) {
				expr.Code = ILCode.Ldc_I8;
				expr.Operand = (long)val;
				if (context.CalculateILRanges) {
					foreach (var arg in expr.Arguments)
						arg.AddSelfAndChildrenRecursiveILRanges(expr.ILRanges);
				}
				expr.Arguments.Clear();
				return true;
			}
			return false;
		}
예제 #20
0
 static bool CanBeRepresentedAsCompoundAssignment(ILExpression expr)
 {
     switch (expr.Code) {
         case ILCode.Add:
         case ILCode.Add_Ovf:
         case ILCode.Add_Ovf_Un:
         case ILCode.Sub:
         case ILCode.Sub_Ovf:
         case ILCode.Sub_Ovf_Un:
         case ILCode.Mul:
         case ILCode.Mul_Ovf:
         case ILCode.Mul_Ovf_Un:
         case ILCode.Div:
         case ILCode.Div_Un:
         case ILCode.Rem:
         case ILCode.Rem_Un:
         case ILCode.And:
         case ILCode.Or:
         case ILCode.Xor:
         case ILCode.Shl:
         case ILCode.Shr:
         case ILCode.Shr_Un:
             return true;
         case ILCode.Call:
             var m = expr.Operand as IMethod;
             if (m == null || m.MethodSig == null || m.MethodSig.HasThis || expr.Arguments.Count != 2) return false;
             switch (m.Name) {
                 case "op_Addition":
                 case "op_Subtraction":
                 case "op_Multiply":
                 case "op_Division":
                 case "op_Modulus":
                 case "op_BitwiseAnd":
                 case "op_BitwiseOr":
                 case "op_ExclusiveOr":
                 case "op_LeftShift":
                 case "op_RightShift":
                     return true;
                 default:
                     return false;
             }
         default:
             return false;
     }
 }
예제 #21
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;
		}
예제 #22
0
		bool TransformDecimalCtorToConstant(ILExpression expr)
		{
			IMethod r;
			List<ILExpression> args;
			if (expr.Match(ILCode.Newobj, out r, out args) &&
				r.DeclaringType.Compare(systemString, decimalString))
			{
				if (args.Count == 1) {
					int val;
					if (args[0].Match(ILCode.Ldc_I4, out val)) {
						expr.Code = ILCode.Ldc_Decimal;
						expr.Operand = new decimal(val);
						expr.InferredType = r.DeclaringType.ToTypeSig();
						if (context.CalculateILRanges) {
							foreach (var arg in expr.Arguments)
								arg.AddSelfAndChildrenRecursiveILRanges(expr.ILRanges);
						}
						expr.Arguments.Clear();
						return true;
					}
				} else if (args.Count == 5) {
					int lo, mid, hi, isNegative, scale;
					if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) &&
					    expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) &&
					    expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) &&
					    expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) &&
					    expr.Arguments[4].Match(ILCode.Ldc_I4, out scale))
					{
						expr.Code = ILCode.Ldc_Decimal;
						expr.Operand = new decimal(lo, mid, hi, isNegative != 0, (byte)scale);
						expr.InferredType = r.DeclaringType.ToTypeSig();
						if (context.CalculateILRanges) {
							foreach (var arg in expr.Arguments)
								arg.AddSelfAndChildrenRecursiveILRanges(expr.ILRanges);
						}
						expr.Arguments.Clear();
						return true;
					}
				}
			}
			return false;
		}
		static bool TransformDecimalCtorToConstant(List<ILNode> body, ILExpression expr, int pos)
		{
			MethodReference r;
			List<ILExpression> args;
			if (expr.Match(ILCode.Newobj, out r, out args) &&
			    r.DeclaringType.Namespace == "System" &&
			    r.DeclaringType.Name == "Decimal")
			{
				if (args.Count == 1) {
					int val;
					if (args[0].Match(ILCode.Ldc_I4, out val)) {
						expr.Code = ILCode.Ldc_Decimal;
						expr.Operand = new decimal(val);
						expr.InferredType = r.DeclaringType;
						expr.Arguments.Clear();
						return true;
					}
				} else if (args.Count == 5) {
					int lo, mid, hi, isNegative, scale;
					if (expr.Arguments[0].Match(ILCode.Ldc_I4, out lo) &&
					    expr.Arguments[1].Match(ILCode.Ldc_I4, out mid) &&
					    expr.Arguments[2].Match(ILCode.Ldc_I4, out hi) &&
					    expr.Arguments[3].Match(ILCode.Ldc_I4, out isNegative) &&
					    expr.Arguments[4].Match(ILCode.Ldc_I4, out scale))
					{
						expr.Code = ILCode.Ldc_Decimal;
						expr.Operand = new decimal(lo, mid, hi, isNegative != 0, (byte)scale);
						expr.InferredType = r.DeclaringType;
						expr.Arguments.Clear();
						return true;
					}
				}
			}
			bool modified = false;
			foreach(ILExpression arg in expr.Arguments) {
				modified |= TransformDecimalCtorToConstant(null, arg, -1);
			}
			return modified;
		}
예제 #24
0
		static ILExpression SimplifyLdObjAndStObj(ILExpression expr, ref bool modified)
		{
			if (expr.Code == ILCode.Initobj) {
				expr.Code = ILCode.Stobj;
				expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
				modified = true;
			}
			ILExpression arg, arg2;
			TypeReference type;
			ILCode? newCode = null;
			if (expr.Match(ILCode.Stobj, out type, out arg, out arg2)) {
				switch (arg.Code) {
						case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break;
						case ILCode.Ldloca:  newCode = ILCode.Stloc; break;
						case ILCode.Ldflda:  newCode = ILCode.Stfld; break;
						case ILCode.Ldsflda: newCode = ILCode.Stsfld; break;
				}
			} else if (expr.Match(ILCode.Ldobj, out type, out arg)) {
				switch (arg.Code) {
						case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break;
						case ILCode.Ldloca:  newCode = ILCode.Ldloc; break;
						case ILCode.Ldflda:  newCode = ILCode.Ldfld; break;
						case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break;
				}
			}
			if (newCode != null) {
				arg.Code = newCode.Value;
				if (expr.Code == ILCode.Stobj) {
					arg.InferredType = expr.InferredType;
					arg.ExpectedType = expr.ExpectedType;
					arg.Arguments.Add(arg2);
				}
				arg.ILRanges.AddRange(expr.ILRanges);
				modified = true;
				return arg;
			} else {
				return expr;
			}
		}
예제 #25
0
		static bool SimplifyLdObjAndStObj(List<ILNode> body, ILExpression expr, int pos)
		{
			bool modified = false;
			if (expr.Code == ILCode.Initobj) {
				expr.Code = ILCode.Stobj;
				expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
				modified = true;
			}
			ILExpression arg, arg2;
			TypeReference type;
			ILCode? newCode = null;
			if (expr.Match(ILCode.Stobj, out type, out arg, out arg2)) {
				switch (arg.Code) {
						case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break;
						case ILCode.Ldloca:  newCode = ILCode.Stloc; break;
						case ILCode.Ldflda:  newCode = ILCode.Stfld; break;
						case ILCode.Ldsflda: newCode = ILCode.Stsfld; break;
				}
			} else if (expr.Match(ILCode.Ldobj, out type, out arg)) {
				switch (arg.Code) {
						case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break;
						case ILCode.Ldloca:  newCode = ILCode.Ldloc; break;
						case ILCode.Ldflda:  newCode = ILCode.Ldfld; break;
						case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break;
				}
			}
			if (newCode != null) {
				arg.Code = newCode.Value;
				if (expr.Code == ILCode.Stobj)
					arg.Arguments.Add(arg2);
				arg.ILRanges.AddRange(expr.ILRanges);
				body[pos] = arg;
				modified = true;
			}
			return modified;
		}
        bool MakeCompoundAssignment(ILExpression expr)
        {
            // stelem.any(T, ldloc(array), ldloc(pos), <OP>(ldelem.any(T, ldloc(array), ldloc(pos)), <RIGHT>))
            // or
            // stobj(T, ldloc(ptr), <OP>(ldobj(T, ldloc(ptr)), <RIGHT>))
            ILCode expectedLdelemCode;

            switch (expr.Code)
            {
            case ILCode.Stelem_Any:
                expectedLdelemCode = ILCode.Ldelem_Any;
                break;

            case ILCode.Stfld:
                expectedLdelemCode = ILCode.Ldfld;
                break;

            case ILCode.Stobj:
                expectedLdelemCode = ILCode.Ldobj;
                break;

            case ILCode.CallSetter:
                expectedLdelemCode = ILCode.CallGetter;
                break;

            case ILCode.CallvirtSetter:
                expectedLdelemCode = ILCode.CallvirtGetter;
                break;

            default:
                return(false);
            }

            // all arguments except the last (so either array+pos, or ptr):
            bool hasGeneratedVar = false;

            for (int i = 0; i < expr.Arguments.Count - 1; i++)
            {
                ILVariable inputVar;
                if (!expr.Arguments[i].Match(ILCode.Ldloc, out inputVar))
                {
                    return(false);
                }
                hasGeneratedVar |= inputVar.IsGenerated;
            }
            // At least one of the variables must be generated; otherwise we just keep the expanded form.
            // We do this because we want compound assignments to be represented in ILAst only when strictly necessary;
            // other compound assignments will be introduced by ReplaceMethodCallsWithOperator
            // (which uses a reversible transformation, see ReplaceMethodCallsWithOperator.RestoreOriginalAssignOperatorAnnotation)
            if (!hasGeneratedVar)
            {
                return(false);
            }

            ILExpression op = expr.Arguments.Last();

            if (!CanBeRepresentedAsCompoundAssignment(op.Code))
            {
                return(false);
            }
            ILExpression ldelem = op.Arguments[0];

            if (ldelem.Code != expectedLdelemCode)
            {
                return(false);
            }
            Debug.Assert(ldelem.Arguments.Count == expr.Arguments.Count - 1);
            for (int i = 0; i < ldelem.Arguments.Count; i++)
            {
                if (!ldelem.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand))
                {
                    return(false);
                }
            }
            expr.Code    = ILCode.CompoundAssignment;
            expr.Operand = null;
            expr.Arguments.RemoveRange(0, ldelem.Arguments.Count);
            // result is "CompoundAssignment(<OP>(ldelem.any(...), <RIGHT>))"
            return(true);
        }
        bool IntroducePostIncrementForVariables(List <ILNode> body, ILExpression expr, int pos)
        {
            // Works for variables and static fields/properties

            // expr = ldloc(i)
            // stloc(i, add(expr, ldc.i4(1)))
            // ->
            // expr = postincrement(1, ldloca(i))
            ILVariable   exprVar;
            ILExpression exprInit;

            if (!(expr.Match(ILCode.Stloc, out exprVar, out exprInit) && exprVar.IsGenerated))
            {
                return(false);
            }

            //The next expression
            ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;

            if (nextExpr == null)
            {
                return(false);
            }

            ILCode loadInstruction   = exprInit.Code;
            ILCode storeInstruction  = nextExpr.Code;
            bool   recombineVariable = false;

            // We only recognise local variables, static fields, and static getters with no arguments
            switch (loadInstruction)
            {
            case ILCode.Ldloc:
                //Must be a matching store type
                if (storeInstruction != ILCode.Stloc)
                {
                    return(false);
                }
                ILVariable loadVar  = (ILVariable)exprInit.Operand;
                ILVariable storeVar = (ILVariable)nextExpr.Operand;
                if (loadVar != storeVar)
                {
                    if (loadVar.OriginalVariable != null && loadVar.OriginalVariable == storeVar.OriginalVariable)
                    {
                        recombineVariable = true;
                    }
                    else
                    {
                        return(false);
                    }
                }
                break;

            case ILCode.Ldsfld:
                if (storeInstruction != ILCode.Stsfld)
                {
                    return(false);
                }
                if (exprInit.Operand != nextExpr.Operand)
                {
                    return(false);
                }
                break;

            case ILCode.CallGetter:
                // non-static getters would have the 'this' argument
                if (exprInit.Arguments.Count != 0)
                {
                    return(false);
                }
                if (storeInstruction != ILCode.CallSetter)
                {
                    return(false);
                }
                if (!IsGetterSetterPair(exprInit.Operand, nextExpr.Operand))
                {
                    return(false);
                }
                break;

            default:
                return(false);
            }

            ILExpression addExpr = nextExpr.Arguments[0];

            int    incrementAmount;
            ILCode incrementCode = GetIncrementCode(addExpr, out incrementAmount);

            if (!(incrementAmount != 0 && addExpr.Arguments[0].MatchLdloc(exprVar)))
            {
                return(false);
            }

            if (recombineVariable)
            {
                // Split local variable, unsplit these two instances
                // replace nextExpr.Operand with exprInit.Operand
                ReplaceVariables(method, oldVar => oldVar == nextExpr.Operand ? (ILVariable)exprInit.Operand : oldVar);
            }

            switch (loadInstruction)
            {
            case ILCode.Ldloc:
                exprInit.Code = ILCode.Ldloca;
                break;

            case ILCode.Ldsfld:
                exprInit.Code = ILCode.Ldsflda;
                break;

            case ILCode.CallGetter:
                exprInit = new ILExpression(ILCode.AddressOf, null, exprInit);
                break;
            }
            expr.Arguments[0] = new ILExpression(incrementCode, incrementAmount, exprInit);
            body.RemoveAt(pos + 1);             // TODO ILRanges
            return(true);
        }
        ILExpression IntroducePostIncrementForInstanceFields(ILExpression expr)
        {
            // stfld(field, ldloc(instance), add(stloc(helperVar, ldfld(field, ldloc(instance))), ldc.i4(1)))
            // -> stloc(helperVar, postincrement(1, ldflda(field, ldloc(instance))))

            // Also works for array elements and pointers:

            // stelem.any(T, ldloc(instance), ldloc(pos), add(stloc(helperVar, ldelem.any(T, ldloc(instance), ldloc(pos))), ldc.i4(1)))
            // -> stloc(helperVar, postincrement(1, ldelema(ldloc(instance), ldloc(pos))))

            // stobj(T, ldloc(ptr), add(stloc(helperVar, ldobj(T, ldloc(ptr)), ldc.i4(1))))
            // -> stloc(helperVar, postIncrement(1, ldloc(ptr)))

            // callsetter(set_P, ldloc(instance), add(stloc(helperVar, callgetter(get_P, ldloc(instance))), ldc.i4(1)))
            // -> stloc(helperVar, postIncrement(1, propertyaddress. callgetter(get_P, ldloc(instance))))

            if (!(expr.Code == ILCode.Stfld || expr.Code.IsStoreToArray() || expr.Code == ILCode.Stobj || expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter))
            {
                return(null);
            }

            // Test that all arguments except the last are ldloc (1 arg for fields and pointers, 2 args for arrays)
            for (int i = 0; i < expr.Arguments.Count - 1; i++)
            {
                if (expr.Arguments[i].Code != ILCode.Ldloc)
                {
                    return(null);
                }
            }

            ILExpression addExpr = expr.Arguments[expr.Arguments.Count - 1];
            int          incrementAmount;
            ILCode       incrementCode = GetIncrementCode(addExpr, out incrementAmount);
            ILVariable   helperVar;
            ILExpression initialValue;

            if (!(incrementAmount != 0 && addExpr.Arguments[0].Match(ILCode.Stloc, out helperVar, out initialValue)))
            {
                return(null);
            }

            if (expr.Code == ILCode.Stfld)
            {
                if (initialValue.Code != ILCode.Ldfld)
                {
                    return(null);
                }
                // There might be two different FieldReference instances, so we compare the field's signatures:
                FieldReference getField = (FieldReference)initialValue.Operand;
                FieldReference setField = (FieldReference)expr.Operand;
                if (!(TypeAnalysis.IsSameType(getField.DeclaringType, setField.DeclaringType) &&
                      getField.Name == setField.Name && TypeAnalysis.IsSameType(getField.FieldType, setField.FieldType)))
                {
                    return(null);
                }
            }
            else if (expr.Code == ILCode.Stobj)
            {
                if (!(initialValue.Code == ILCode.Ldobj && initialValue.Operand == expr.Operand))
                {
                    return(null);
                }
            }
            else if (expr.Code == ILCode.CallSetter)
            {
                if (!(initialValue.Code == ILCode.CallGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand)))
                {
                    return(null);
                }
            }
            else if (expr.Code == ILCode.CallvirtSetter)
            {
                if (!(initialValue.Code == ILCode.CallvirtGetter && IsGetterSetterPair(initialValue.Operand, expr.Operand)))
                {
                    return(null);
                }
            }
            else
            {
                if (!initialValue.Code.IsLoadFromArray())
                {
                    return(null);
                }
            }
            Debug.Assert(expr.Arguments.Count - 1 == initialValue.Arguments.Count);
            for (int i = 0; i < initialValue.Arguments.Count; i++)
            {
                if (!initialValue.Arguments[i].MatchLdloc((ILVariable)expr.Arguments[i].Operand))
                {
                    return(null);
                }
            }

            ILExpression stloc = addExpr.Arguments[0];

            if (expr.Code == ILCode.Stobj)
            {
                stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue.Arguments[0]);
            }
            else if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter)
            {
                initialValue       = new ILExpression(ILCode.AddressOf, null, initialValue);
                stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue);
            }
            else
            {
                stloc.Arguments[0] = new ILExpression(ILCode.PostIncrement, incrementAmount, initialValue);
                initialValue.Code  = (expr.Code == ILCode.Stfld ? ILCode.Ldflda : ILCode.Ldelema);
            }
            // TODO: ILRanges?

            return(stloc);
        }
        static ILExpression SimplifyLdObjAndStObj(ILExpression expr, ref bool modified)
        {
            if (expr.Code == ILCode.Initobj)
            {
                expr.Code = ILCode.Stobj;
                expr.Arguments.Add(new ILExpression(ILCode.DefaultValue, expr.Operand));
                modified = true;
            }
            else if (expr.Code == ILCode.Cpobj)
            {
                expr.Code         = ILCode.Stobj;
                expr.Arguments[1] = new ILExpression(ILCode.Ldobj, expr.Operand, expr.Arguments[1]);
                modified          = true;
            }
            ILExpression  arg, arg2;
            TypeReference type;
            ILCode?       newCode = null;

            if (expr.Match(ILCode.Stobj, out type, out arg, out arg2))
            {
                switch (arg.Code)
                {
                case ILCode.Ldelema: newCode = ILCode.Stelem_Any; break;

                case ILCode.Ldloca:  newCode = ILCode.Stloc; break;

                case ILCode.Ldflda:  newCode = ILCode.Stfld; break;

                case ILCode.Ldsflda: newCode = ILCode.Stsfld; break;
                }
            }
            else if (expr.Match(ILCode.Ldobj, out type, out arg))
            {
                switch (arg.Code)
                {
                case ILCode.Ldelema: newCode = ILCode.Ldelem_Any; break;

                case ILCode.Ldloca:  newCode = ILCode.Ldloc; break;

                case ILCode.Ldflda:  newCode = ILCode.Ldfld; break;

                case ILCode.Ldsflda: newCode = ILCode.Ldsfld; break;
                }
            }
            if (newCode != null)
            {
                arg.Code = newCode.Value;
                if (expr.Code == ILCode.Stobj)
                {
                    arg.InferredType = expr.InferredType;
                    arg.ExpectedType = expr.ExpectedType;
                    arg.Arguments.Add(arg2);
                }
                arg.ILRanges.AddRange(expr.ILRanges);
                modified = true;
                return(arg);
            }
            else
            {
                return(expr);
            }
        }
예제 #30
0
        public static bool Match <T>(this ILNode node, ILCode code, out T operand, out ILExpression arg1, out ILExpression arg2)
        {
            List <ILExpression> args;

            if (node.Match(code, out operand, out args) && args.Count == 2)
            {
                arg1 = args[0];
                arg2 = args[1];
                return(true);
            }
            arg1 = null;
            arg2 = null;
            return(false);
        }
        bool HandleStringFixing(ILVariable pinnedVar, List <ILNode> body, ref int pos, ref ILExpression fixedStmtInitializer)
        {
            // fixed (stloc(pinnedVar, ldloc(text))) {
            //   var1 = var2 = conv.i(ldloc(pinnedVar))
            //   if (logicnot(logicnot(var1))) {
            //     var2 = add(var1, call(RuntimeHelpers::get_OffsetToStringData))
            //   }
            //   stloc(ptrVar, var2)
            //   ...

            if (pos >= body.Count)
            {
                return(false);
            }

            ILVariable   var1, var2;
            ILExpression varAssignment, ptrInitialization;

            if (!(body[pos].Match(ILCode.Stloc, out var1, out varAssignment) && varAssignment.Match(ILCode.Stloc, out var2, out ptrInitialization)))
            {
                return(false);
            }
            if (!(var1.IsGenerated && var2.IsGenerated))
            {
                return(false);
            }
            if (ptrInitialization.Code == ILCode.Conv_I || ptrInitialization.Code == ILCode.Conv_U)
            {
                ptrInitialization = ptrInitialization.Arguments[0];
            }
            if (!ptrInitialization.MatchLdloc(pinnedVar))
            {
                return(false);
            }

            ILCondition ifStmt = body[pos + 1] as ILCondition;

            if (!(ifStmt != null && ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 && (ifStmt.FalseBlock == null || ifStmt.FalseBlock.Body.Count == 0)))
            {
                return(false);
            }
            if (!UnpackDoubleNegation(ifStmt.Condition).MatchLdloc(var1))
            {
                return(false);
            }
            ILVariable   assignedVar;
            ILExpression assignedExpr;

            if (!(ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out assignedVar, out assignedExpr) && assignedVar == var2 && assignedExpr.Code == ILCode.Add))
            {
                return(false);
            }
            MethodReference calledMethod;

            if (!(assignedExpr.Arguments[0].MatchLdloc(var1)))
            {
                return(false);
            }
            if (!(assignedExpr.Arguments[1].Match(ILCode.Call, out calledMethod) || assignedExpr.Arguments[1].Match(ILCode.CallGetter, out calledMethod)))
            {
                return(false);
            }
            if (!(calledMethod.Name == "get_OffsetToStringData" && calledMethod.DeclaringType.FullName == "System.Runtime.CompilerServices.RuntimeHelpers"))
            {
                return(false);
            }

            ILVariable pointerVar;

            if (body[pos + 2].Match(ILCode.Stloc, out pointerVar, out assignedExpr) && assignedExpr.MatchLdloc(var2))
            {
                pos += 3;
                fixedStmtInitializer.Operand = pointerVar;
                return(true);
            }
            return(false);
        }
        void CachedDelegateInitializationWithLocal(ILBlock block, ref int i)
        {
            // if (logicnot(ldloc(v))) {
            //     stloc(v, newobj(Action::.ctor, ldloc(displayClass), ldftn(method)))
            // } else {
            // }
            // ...(..., ldloc(v), ...)

            ILCondition c = block.Body[i] as ILCondition;

            if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null)
            {
                return;
            }
            if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
            {
                return;
            }
            if (!c.Condition.Match(ILCode.LogicNot))
            {
                return;
            }
            ILExpression condition = c.Condition.Arguments.Single() as ILExpression;

            if (condition == null || condition.Code != ILCode.Ldloc)
            {
                return;
            }
            ILVariable   v     = (ILVariable)condition.Operand;
            ILExpression stloc = c.TrueBlock.Body[0] as ILExpression;

            if (!(stloc != null && stloc.Code == ILCode.Stloc && (ILVariable)stloc.Operand == v))
            {
                return;
            }
            ILExpression newObj = stloc.Arguments[0];

            if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2))
            {
                return;
            }
            if (newObj.Arguments[0].Code != ILCode.Ldloc)
            {
                return;
            }
            if (newObj.Arguments[1].Code != ILCode.Ldftn)
            {
                return;
            }
            MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule();             // method is defined in current assembly

            if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
            {
                return;
            }

            ILNode followingNode     = block.Body.ElementAtOrDefault(i + 1);
            int    ldlocOperandCount =
                followingNode
                .EnumerateSelfAndChildrenRecursive()
                .OfType <ILExpression>()
                .Count(
                    e =>
                    e.Code == ILCode.Ldloc &&
                    (ILVariable)e.Operand == v);

            if (followingNode != null && ldlocOperandCount == 1)
            {
                ILInlining inlining = new ILInlining(method);
                if (!(inlining.numLdloc.GetOrDefault(v) == 2 && inlining.numStloc.GetOrDefault(v) == 2 && inlining.numLdloca.GetOrDefault(v) == 0))
                {
                    return;
                }

                // Find the store instruction that initializes the local to null:
                foreach (ILBlock storeBlock in method.EnumerateSelfAndChildrenRecursive().OfType <ILBlock>())
                {
                    for (int j = 0; j < storeBlock.Body.Count; j++)
                    {
                        ILVariable   storedVar;
                        ILExpression storedExpr;
                        if (storeBlock.Body[j].Match(ILCode.Stloc, out storedVar, out storedExpr) && storedVar == v && storedExpr.Match(ILCode.Ldnull))
                        {
                            // Remove the instruction
                            storeBlock.Body.RemoveAt(j);
                            if (storeBlock == block && j < i)
                            {
                                i--;
                            }
                            break;
                        }
                    }
                }

                block.Body[i] = stloc;                 // remove the 'if (v==null)'
                inlining      = new ILInlining(method);
                inlining.InlineIfPossible(block.Body, ref i);
            }
        }
        void CachedDelegateInitializationWithField(ILBlock block, ref int i)
        {
            // if (logicnot(ldsfld(field))) {
            //     stsfld(field, newobj(Action::.ctor, ldnull(), ldftn(method)))
            // } else {
            // }
            // ...(..., ldsfld(field), ...)

            ILCondition c = block.Body[i] as ILCondition;

            if (c == null || c.Condition == null && c.TrueBlock == null || c.FalseBlock == null)
            {
                return;
            }
            if (!(c.TrueBlock.Body.Count == 1 && c.FalseBlock.Body.Count == 0))
            {
                return;
            }
            if (!c.Condition.Match(ILCode.LogicNot))
            {
                return;
            }
            ILExpression condition = c.Condition.Arguments.Single() as ILExpression;

            if (condition == null || condition.Code != ILCode.Ldsfld)
            {
                return;
            }
            FieldDefinition field = ((FieldReference)condition.Operand).ResolveWithinSameModule();             // field is defined in current assembly

            if (field == null || !field.IsCompilerGeneratedOrIsInCompilerGeneratedClass())
            {
                return;
            }
            ILExpression stsfld = c.TrueBlock.Body[0] as ILExpression;

            if (!(stsfld != null && stsfld.Code == ILCode.Stsfld && ((FieldReference)stsfld.Operand).ResolveWithinSameModule() == field))
            {
                return;
            }
            ILExpression newObj = stsfld.Arguments[0];

            if (!(newObj.Code == ILCode.Newobj && newObj.Arguments.Count == 2))
            {
                return;
            }
            if (newObj.Arguments[0].Code != ILCode.Ldnull)
            {
                return;
            }
            if (newObj.Arguments[1].Code != ILCode.Ldftn)
            {
                return;
            }
            MethodDefinition anonymousMethod = ((MethodReference)newObj.Arguments[1].Operand).ResolveWithinSameModule();             // method is defined in current assembly

            if (!AstServices.Transforms.DelegateConstruction.IsAnonymousMethod(context, anonymousMethod))
            {
                return;
            }

            ILNode followingNode = block.Body.ElementAtOrDefault(i + 1);

            int ldfldResolvingWithinSameMethodCount =
                followingNode
                .EnumerateSelfAndChildrenRecursive()
                .OfType <ILExpression>()
                .Count(
                    e =>
                    e.Code == ILCode.Ldsfld &&
                    ((FieldReference)e.Operand).ResolveWithinSameModule() == field);

            if (followingNode != null && ldfldResolvingWithinSameMethodCount == 1)
            {
                foreach (ILExpression parent in followingNode.EnumerateSelfAndChildrenRecursive().OfType <ILExpression>())
                {
                    for (int j = 0; j < parent.Arguments.Count; j++)
                    {
                        if (parent.Arguments[j].Code == ILCode.Ldsfld && ((FieldReference)parent.Arguments[j].Operand).ResolveWithinSameModule() == field)
                        {
                            parent.Arguments[j] = newObj;
                            block.Body.RemoveAt(i);
                            i -= new ILInlining(method).InlineInto(block.Body, i, aggressive: false);
                            return;
                        }
                    }
                }
            }
        }
예제 #34
0
        public static bool MatchStloc(this ILNode node, ILVariable expectedVar, out ILExpression expr)
        {
            ILVariable v;

            return(node.Match(ILCode.Stloc, out v, out expr) && v == expectedVar);
        }
예제 #35
0
        public static bool Match(this ILNode node, ILCode code)
        {
            ILExpression expr = node as ILExpression;

            return(expr != null && expr.Prefixes == null && expr.Code == code);
        }
예제 #36
0
        List <ILNode> ConvertToAst(List <ByteCode> body, HashSet <ExceptionHandler> ehs)
        {
            List <ILNode> ast = new List <ILNode>();

            while (ehs.Any())
            {
                ILTryCatchBlock tryCatchBlock = new ILTryCatchBlock();

                // Find the first and widest scope
                int tryStart = ehs.Min(eh => eh.TryStart.Offset);
                int tryEnd   = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset);
                var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).OrderBy(eh => eh.TryStart.Offset).ToList();

                // Remember that any part of the body migt have been removed due to unreachability

                // Cut all instructions up to the try block
                {
                    int tryStartIdx = 0;
                    while (tryStartIdx < body.Count && body[tryStartIdx].Offset < tryStart)
                    {
                        tryStartIdx++;
                    }
                    ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx)));
                }

                // Cut the try block
                {
                    HashSet <ExceptionHandler> nestedEHs = new HashSet <ExceptionHandler>(ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)));
                    ehs.ExceptWith(nestedEHs);
                    int tryEndIdx = 0;
                    while (tryEndIdx < body.Count && body[tryEndIdx].Offset < tryEnd)
                    {
                        tryEndIdx++;
                    }
                    tryCatchBlock.TryBlock = new ILBlock(ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs));
                }

                // Cut all handlers
                tryCatchBlock.CatchBlocks = new List <ILTryCatchBlock.CatchBlock>();
                foreach (ExceptionHandler eh in handlers)
                {
                    int handlerEndOffset = eh.HandlerEnd == null ? methodDef.Body.CodeSize : eh.HandlerEnd.Offset;
                    int startIdx         = 0;
                    while (startIdx < body.Count && body[startIdx].Offset < eh.HandlerStart.Offset)
                    {
                        startIdx++;
                    }
                    int endIdx = 0;
                    while (endIdx < body.Count && body[endIdx].Offset < handlerEndOffset)
                    {
                        endIdx++;
                    }
                    HashSet <ExceptionHandler> nestedEHs = new HashSet <ExceptionHandler>(ehs.Where(e => (eh.HandlerStart.Offset <= e.TryStart.Offset && e.TryEnd.Offset < handlerEndOffset) || (eh.HandlerStart.Offset < e.TryStart.Offset && e.TryEnd.Offset <= handlerEndOffset)));
                    ehs.ExceptWith(nestedEHs);
                    List <ILNode> handlerAst = ConvertToAst(body.CutRange(startIdx, endIdx - startIdx), nestedEHs);
                    if (eh.HandlerType == ExceptionHandlerType.Catch)
                    {
                        ILTryCatchBlock.CatchBlock catchBlock = new ILTryCatchBlock.CatchBlock()
                        {
                            ExceptionType = eh.CatchType,
                            Body          = handlerAst
                        };
                        // Handle the automatically pushed exception on the stack
                        ByteCode ldexception = ldexceptions[eh];
                        if (ldexception.StoreTo == null || ldexception.StoreTo.Count == 0)
                        {
                            // Exception is not used
                            catchBlock.ExceptionVariable = null;
                        }
                        else if (ldexception.StoreTo.Count == 1)
                        {
                            ILExpression first = catchBlock.Body[0] as ILExpression;
                            if (first != null &&
                                first.Code == ILCode.Pop &&
                                first.Arguments[0].Code == ILCode.Ldloc &&
                                first.Arguments[0].Operand == ldexception.StoreTo[0])
                            {
                                // The exception is just poped - optimize it all away;
                                if (context.Settings.AlwaysGenerateExceptionVariableForCatchBlocks)
                                {
                                    catchBlock.ExceptionVariable = new ILVariable()
                                    {
                                        Name = "ex_" + eh.HandlerStart.Offset.ToString("X2"), IsGenerated = true
                                    }
                                }
                                ;
                                else
                                {
                                    catchBlock.ExceptionVariable = null;
                                }
                                catchBlock.Body.RemoveAt(0);
                            }
                            else
                            {
                                catchBlock.ExceptionVariable = ldexception.StoreTo[0];
                            }
                        }
                        else
                        {
                            ILVariable exTemp = new ILVariable()
                            {
                                Name = "ex_" + eh.HandlerStart.Offset.ToString("X2"), IsGenerated = true
                            };
                            catchBlock.ExceptionVariable = exTemp;
                            foreach (ILVariable storeTo in ldexception.StoreTo)
                            {
                                catchBlock.Body.Insert(0, new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, exTemp)));
                            }
                        }
                        tryCatchBlock.CatchBlocks.Add(catchBlock);
                    }
                    else if (eh.HandlerType == ExceptionHandlerType.Finally)
                    {
                        tryCatchBlock.FinallyBlock = new ILBlock(handlerAst);
                    }
                    else if (eh.HandlerType == ExceptionHandlerType.Fault)
                    {
                        tryCatchBlock.FaultBlock = new ILBlock(handlerAst);
                    }
                    else
                    {
                        // TODO: ExceptionHandlerType.Filter
                    }
                }

                ehs.ExceptWith(handlers);

                ast.Add(tryCatchBlock);
            }

            // Add whatever is left
            ast.AddRange(ConvertToAst(body));

            return(ast);
        }
예제 #37
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)
            {
                ILRange ilRange = new ILRange()
                {
                    From = byteCode.Offset, To = byteCode.EndOffset
                };

                if (byteCode.StackBefore == null)
                {
                    // Unreachable code
                    continue;
                }

                ILExpression expr = new ILExpression(byteCode.Code, byteCode.Operand);
                expr.ILRanges.Add(ilRange);
                if (byteCode.Prefixes != null && byteCode.Prefixes.Length > 0)
                {
                    ILExpressionPrefix[] prefixes = new ILExpressionPrefix[byteCode.Prefixes.Length];
                    for (int i = 0; i < prefixes.Length; i++)
                    {
                        prefixes[i] = new ILExpressionPrefix((ILCode)byteCode.Prefixes[i].OpCode.Code, byteCode.Prefixes[i].Operand);
                    }
                    expr.Prefixes = prefixes;
                }

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

                // Reference arguments using temporary variables
                int popCount = byteCode.PopCount ?? byteCode.StackBefore.Length;
                for (int i = byteCode.StackBefore.Length - popCount; i < byteCode.StackBefore.Length; i++)
                {
                    StackSlot slot = byteCode.StackBefore[i];
                    expr.Arguments.Add(new ILExpression(ILCode.Ldloc, slot.LoadFrom));
                }

                // 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(ILCode.Stloc, byteCode.StoreTo[0], expr));
                }
                else
                {
                    ILVariable tmpVar = new ILVariable()
                    {
                        Name = "expr_" + byteCode.Offset.ToString("X2"), IsGenerated = true
                    };
                    ast.Add(new ILExpression(ILCode.Stloc, tmpVar, expr));
                    foreach (ILVariable storeTo in byteCode.StoreTo.AsEnumerable().Reverse())
                    {
                        ast.Add(new ILExpression(ILCode.Stloc, storeTo, new ILExpression(ILCode.Ldloc, tmpVar)));
                    }
                }
            }

            return(ast);
        }
예제 #38
0
        public List <ILNode> Build(File.Code code, ErrorContext error = null)
        {
            if (code == null)
            {
                throw new ArgumentNullException("code");
            }
            Stream stream = code.Data;

            if (stream == null)
            {
                throw new ArgumentNullException("code.Data");
            }
            if (!stream.CanRead)
            {
                throw new ArgumentException("Must be readable", "code_stream");
            }
            if (!stream.CanSeek)
            {
                throw new ArgumentException("Must be seekable", "code_stream");
            }
            if (stream.Length == 0)
            {
                return(new List <ILNode>());                   // empty stream
            }
            StartingOffset  = code.CodePosition;
            Error           = error ?? new ErrorContext(code.Name);
            labels          = new Dictionary <int, ILLabel>(); // cause they are all the same
            stream.Position = 0;
            r         = new BinaryReader(stream);
            CurrentPC = 0;
            List <ILNode>         list           = new List <ILNode>();
            Dictionary <int, int> pcToExpressoin = new Dictionary <int, int>();

            Start(list);
            while (stream.Position < stream.Length)
            {
                CurrentPC  = (int)stream.Position / 4;
                CurrentRaw = r.ReadUInt32();
                ILExpression e = CreateExpression(list);
                if (e != null)
                {
                    /*
                     * // hack here cause of issues
                     * if (e.Code == GMCode.Conv)
                     * {
                     *  var prev = list.Last.Value as ILExpression;
                     *  Debug.Assert(prev.Code != GMCode.Pop);
                     *  prev.ILRanges.Add(new ILRange(CurrentPC, CurrentPC));
                     *  prev.Types = e.Types; // don't add it
                     * }
                     * else
                     */
                    pcToExpressoin.Add(CurrentPC, list.Count);
                    list.Add(e);
                }
            }
            CurrentPC  = (int)stream.Position / 4;
            CurrentRaw = 0;
            if (labelExists(CurrentPC)) // this is in case we do have a jump but we need to exit clean
            {
                pcToExpressoin.Add(CurrentPC, list.Count);
                list.Add(CreateExpression(GMCode.Exit, null)); // make sure we got an exit as the last code
                // we HAVE to have an exit
            }
            else
            {
                ILExpression last = list.Last() as ILExpression;
                if (last.Code != GMCode.Ret && last.Code != GMCode.Exit)
                {
                    pcToExpressoin.Add(CurrentPC, list.Count);
                    list.Add(CreateExpression(GMCode.Exit, null)); // make sure we got an exit as the last code
                }
            }

            foreach (var l in labels)
            {
                int n;
                if (pcToExpressoin.TryGetValue(l.Key, out n))
                {
                    list[n].UserData = l.Value;
                }
            }
            var rlist = new List <ILNode>();

            for (int i = 0; i < list.Count; i++)
            {
                ILExpression e = list[i] as ILExpression;
                if (e != null)
                {
                    if (e.UserData != null)
                    {
                        rlist.Add(e.UserData as ILLabel); e.UserData = null;
                    }
                    if (e.Code == GMCode.Conv)
                    {
                        ILExpression ne = list[i + 1] as ILExpression;
                        ne.ILRanges.AddRange(e.ILRanges);
                        ne.Types = e.Types;
                        continue; // skip
                    }
                }
                rlist.Add(list[i]);
            }
            Finish(rlist);

            return(rlist);
        }
		void RunInference(ILExpression expr)
		{
			bool anyArgumentIsMissingExpectedType = expr.Arguments.Any(a => a.ExpectedType == null);
			if (expr.InferredType == null || anyArgumentIsMissingExpectedType)
				InferTypeForExpression(expr, expr.ExpectedType, forceInferChildren: anyArgumentIsMissingExpectedType);
			foreach (var arg in expr.Arguments) {
				if (arg.Code != ILCode.Stloc) {
					RunInference(arg);
				}
			}
		}
        bool MakeAssignmentExpression(List <ILNode> body, ILExpression expr, int pos)
        {
            // exprVar = ...
            // stloc(v, exprVar)
            // ->
            // exprVar = stloc(v, ...))
            ILVariable   exprVar;
            ILExpression initializer;

            if (!(expr.Match(ILCode.Stloc, out exprVar, out initializer) && exprVar.IsGenerated))
            {
                return(false);
            }
            ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
            ILVariable   v;
            ILExpression stLocArg;

            if (nextExpr.Match(ILCode.Stloc, out v, out stLocArg) && stLocArg.MatchLdloc(exprVar))
            {
                ILExpression store2 = body.ElementAtOrDefault(pos + 2) as ILExpression;
                if (StoreCanBeConvertedToAssignment(store2, exprVar))
                {
                    // expr_44 = ...
                    // stloc(v1, expr_44)
                    // anystore(v2, expr_44)
                    // ->
                    // stloc(v1, anystore(v2, ...))
                    ILInlining inlining = new ILInlining(method);
                    if (inlining.numLdloc.GetOrDefault(exprVar) == 2 && inlining.numStloc.GetOrDefault(exprVar) == 1)
                    {
                        body.RemoveAt(pos + 2);                     // remove store2
                        body.RemoveAt(pos);                         // remove expr = ...
                        nextExpr.Arguments[0] = store2;
                        store2.Arguments[store2.Arguments.Count - 1] = initializer;

                        inlining.InlineIfPossible(body, ref pos);

                        return(true);
                    }
                }

                body.RemoveAt(pos + 1);                 // remove stloc
                nextExpr.Arguments[0] = initializer;
                ((ILExpression)body[pos]).Arguments[0] = nextExpr;
                return(true);
            }
            else if ((nextExpr.Code == ILCode.Stsfld || nextExpr.Code == ILCode.CallSetter || nextExpr.Code == ILCode.CallvirtSetter) && nextExpr.Arguments.Count == 1)
            {
                // exprVar = ...
                // stsfld(fld, exprVar)
                // ->
                // exprVar = stsfld(fld, ...))
                if (nextExpr.Arguments[0].MatchLdloc(exprVar))
                {
                    body.RemoveAt(pos + 1);                     // remove stsfld
                    nextExpr.Arguments[0] = initializer;
                    ((ILExpression)body[pos]).Arguments[0] = nextExpr;
                    return(true);
                }
            }
            return(false);
        }
예제 #41
0
        string GenerateNameForVariable(ILVariable variable, ILBlock methodBody)
        {
            string proposedName = null;

            if (variable.Type == context.CurrentType.Module.TypeSystem.Int32)
            {
                // test whether the variable might be a loop counter
                bool isLoopCounter = false;
                foreach (ILWhileLoop loop in methodBody.GetSelfAndChildrenRecursive <ILWhileLoop>())
                {
                    ILExpression expr = loop.Condition;
                    while (expr != null && expr.Code == ILCode.LogicNot)
                    {
                        expr = expr.Arguments[0];
                    }
                    if (expr != null)
                    {
                        switch (expr.Code)
                        {
                        case ILCode.Clt:
                        case ILCode.Clt_Un:
                        case ILCode.Cgt:
                        case ILCode.Cgt_Un:
                            ILVariable loadVar;
                            if (expr.Arguments[0].Match(ILCode.Ldloc, out loadVar) && loadVar == variable)
                            {
                                isLoopCounter = true;
                            }
                            break;
                        }
                    }
                }
                if (isLoopCounter)
                {
                    // For loop variables, use i,j,k,l,m,n
                    for (char c = 'i'; c <= maxLoopVariableName; c++)
                    {
                        if (!typeNames.ContainsKey(c.ToString()))
                        {
                            proposedName = c.ToString();
                            break;
                        }
                    }
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                var proposedNameForStores =
                    (from expr in methodBody.GetSelfAndChildrenRecursive <ILExpression>()
                     where expr.Code == ILCode.Stloc && expr.Operand == variable
                     select GetNameFromExpression(expr.Arguments.Single())
                    ).Except(fieldNamesInCurrentType).ToList();
                if (proposedNameForStores.Count == 1)
                {
                    proposedName = proposedNameForStores[0];
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                var proposedNameForLoads =
                    (from expr in methodBody.GetSelfAndChildrenRecursive <ILExpression>()
                     from i in Enumerable.Range(0, expr.Arguments.Count)
                     let arg = expr.Arguments[i]
                               where arg.Code == ILCode.Ldloc && arg.Operand == variable
                               select GetNameForArgument(expr, i)
                    ).Except(fieldNamesInCurrentType).ToList();
                if (proposedNameForLoads.Count == 1)
                {
                    proposedName = proposedNameForLoads[0];
                }
            }
            if (string.IsNullOrEmpty(proposedName))
            {
                proposedName = GetNameByType(variable.Type);
            }

            // remove any numbers from the proposed name
            int number;

            proposedName = SplitName(proposedName, out number);

            if (!typeNames.ContainsKey(proposedName))
            {
                typeNames.Add(proposedName, 0);
            }
            int count = ++typeNames[proposedName];

            if (count > 1)
            {
                return(proposedName + count.ToString());
            }
            else
            {
                return(proposedName);
            }
        }
예제 #42
0
 public static bool MatchLastAndBr <T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel)
 {
     if (bb.Body.ElementAtOrDefault(bb.Body.Count - 2).Match(code, out operand, out arg) &&
         bb.Body.LastOrDefault().Match(ILCode.Br, out brLabel))
     {
         return(true);
     }
     operand = default(T);
     arg     = null;
     brLabel = null;
     return(false);
 }
		TypeReference DoInferTypeForExpression(ILExpression expr, TypeReference expectedType, bool forceInferChildren = false)
		{
			switch (expr.Code) {
					#region Logical operators
				case ILCode.LogicNot:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
					}
					return typeSystem.Boolean;
				case ILCode.LogicAnd:
				case ILCode.LogicOr:
					// if Operand is set the logic and/or expression is a custom operator
					// we can deal with it the same as a normal invocation.
					if (expr.Operand != null)
						goto case ILCode.Call;
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
						InferTypeForExpression(expr.Arguments[1], typeSystem.Boolean);
					}
					return typeSystem.Boolean;
				case ILCode.TernaryOp:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], typeSystem.Boolean);
					}
					return InferBinaryArguments(expr.Arguments[1], expr.Arguments[2], expectedType, forceInferChildren);
				case ILCode.NullCoalescing:
					return InferBinaryArguments(expr.Arguments[0], expr.Arguments[1], expectedType, forceInferChildren);
					#endregion
					#region Variable load/store
				case ILCode.Stloc:
					{
						ILVariable v = (ILVariable)expr.Operand;
						if (forceInferChildren) {
							// do not use 'expectedType' in here!
							InferTypeForExpression(expr.Arguments.Single(), v.Type);
						}
						return v.Type;
					}
				case ILCode.Ldloc:
					{
						ILVariable v = (ILVariable)expr.Operand;
						if (v.Type == null && singleLoadVariables.Contains(v)) {
							v.Type = expectedType;
						}
						return v.Type;
					}
				case ILCode.Ldloca:
					{
						ILVariable v = (ILVariable)expr.Operand;
						if (v.Type != null)
							return new ByReferenceType(v.Type);
						else
							return null;
					}
					#endregion
					#region Call / NewObj
				case ILCode.Call:
				case ILCode.Callvirt:
				case ILCode.CallGetter:
				case ILCode.CallvirtGetter:
				case ILCode.CallSetter:
				case ILCode.CallvirtSetter:
					{
						MethodReference method = (MethodReference)expr.Operand;
						if (forceInferChildren) {
							for (int i = 0; i < expr.Arguments.Count; i++) {
								if (i == 0 && method.HasThis) {
									InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(method.DeclaringType, expr.GetPrefix(ILCode.Constrained)));
								} else {
									InferTypeForExpression(expr.Arguments[i], SubstituteTypeArgs(method.Parameters[method.HasThis ? i - 1 : i].ParameterType, method));
								}
							}
						}
						if (expr.Code == ILCode.CallSetter || expr.Code == ILCode.CallvirtSetter) {
							return SubstituteTypeArgs(method.Parameters.Last().ParameterType, method);
						} else {
							return SubstituteTypeArgs(method.ReturnType, method);
						}
					}
				case ILCode.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;
					}
				case ILCode.InitObject:
				case ILCode.InitCollection:
					return InferTypeForExpression(expr.Arguments[0], expectedType);
				case ILCode.InitializedObject:
					// expectedType should always be known due to the parent method call / property setter
					Debug.Assert(expectedType != null);
					return expectedType;
					#endregion
					#region Load/Store Fields
				case ILCode.Ldfld:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
					}
					return GetFieldType((FieldReference)expr.Operand);
				case ILCode.Ldsfld:
					return GetFieldType((FieldReference)expr.Operand);
				case ILCode.Ldflda:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
					}
					return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
				case ILCode.Ldsflda:
					return new ByReferenceType(GetFieldType((FieldReference)expr.Operand));
				case ILCode.Stfld:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], MakeRefIfValueType(((FieldReference)expr.Operand).DeclaringType, expr.GetPrefix(ILCode.Constrained)));
						InferTypeForExpression(expr.Arguments[1], GetFieldType((FieldReference)expr.Operand));
					}
					return GetFieldType((FieldReference)expr.Operand);
				case ILCode.Stsfld:
					if (forceInferChildren)
						InferTypeForExpression(expr.Arguments[0], GetFieldType((FieldReference)expr.Operand));
					return GetFieldType((FieldReference)expr.Operand);
					#endregion
					#region Reference/Pointer instructions
				case ILCode.Ldind_Ref:
					return UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
				case ILCode.Stind_Ref:
					if (forceInferChildren) {
						TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
						InferTypeForExpression(expr.Arguments[1], elementType);
					}
					return null;
				case ILCode.Ldobj:
					{
						TypeReference type = (TypeReference)expr.Operand;
						var argType = InferTypeForExpression(expr.Arguments[0], null);
						if (argType is PointerType || argType is ByReferenceType) {
							var elementType = ((TypeSpecification)argType).ElementType;
							int infoAmount = GetInformationAmount(elementType);
							if (infoAmount == 1 && GetInformationAmount(type) == 8) {
								// A bool can be loaded from both bytes and sbytes.
								type = elementType;
							}
							if (infoAmount >= 8 && infoAmount <= 64 && infoAmount == GetInformationAmount(type)) {
								// An integer can be loaded as another integer of the same size.
								// For integers smaller than 32 bit, the signs must match (as loading performs sign extension)
								bool? elementTypeIsSigned = IsSigned(elementType);
								bool? typeIsSigned = IsSigned(type);
								if (elementTypeIsSigned != null && typeIsSigned != null) {
									if (infoAmount >= 32 || elementTypeIsSigned == typeIsSigned)
										type = elementType;
								}
							}
						}
						if (argType is PointerType)
							InferTypeForExpression(expr.Arguments[0], new PointerType(type));
						else
							InferTypeForExpression(expr.Arguments[0], new ByReferenceType(type));
						return type;
					}
				case ILCode.Stobj:
					{
						TypeReference operandType = (TypeReference)expr.Operand;
						TypeReference pointerType = InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType));
						TypeReference elementType;
						if (pointerType is PointerType)
							elementType = ((PointerType)pointerType).ElementType;
						else if (pointerType is ByReferenceType)
							elementType = ((ByReferenceType)pointerType).ElementType;
						else
							elementType = null;
						if (elementType != null) {
							// An integer can be stored in any other integer of the same size.
							int infoAmount = GetInformationAmount(elementType);
							if (infoAmount == 1 && GetInformationAmount(operandType) == 8)
								operandType = elementType;
							else if (infoAmount == GetInformationAmount(operandType) && IsSigned(elementType) != null && IsSigned(operandType) != null)
								operandType = elementType;
						}
						if (forceInferChildren) {
							if (pointerType is PointerType)
								InferTypeForExpression(expr.Arguments[0], new PointerType(operandType));
							else if (!IsSameType(operandType, expr.Operand as TypeReference))
								InferTypeForExpression(expr.Arguments[0], new ByReferenceType(operandType));
							InferTypeForExpression(expr.Arguments[1], operandType);
						}
						return operandType;
					}
				case ILCode.Initobj:
					return null;
				case ILCode.DefaultValue:
					return (TypeReference)expr.Operand;
				case ILCode.Localloc:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], typeSystem.Int32);
					}
					if (expectedType is PointerType)
						return expectedType;
					else
						return typeSystem.IntPtr;
				case ILCode.Sizeof:
					return typeSystem.Int32;
				case ILCode.PostIncrement:
				case ILCode.PostIncrement_Ovf:
				case ILCode.PostIncrement_Ovf_Un:
					{
						TypeReference elementType = UnpackPointer(InferTypeForExpression(expr.Arguments[0], null));
						if (forceInferChildren && elementType != null) {
							// Assign expected type to the child expression
							InferTypeForExpression(expr.Arguments[0], new ByReferenceType(elementType));
						}
						return elementType;
					}
				case ILCode.Mkrefany:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], (TypeReference)expr.Operand);
					}
					return typeSystem.TypedReference;
				case ILCode.Refanytype:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
					}
					return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true);
				case ILCode.Refanyval:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], typeSystem.TypedReference);
					}
					return new ByReferenceType((TypeReference)expr.Operand);
				case ILCode.AddressOf:
					{
						TypeReference t = InferTypeForExpression(expr.Arguments[0], UnpackPointer(expectedType));
						return t != null ? new ByReferenceType(t) : null;
					}
				case ILCode.ValueOf:
					return GetNullableTypeArgument(InferTypeForExpression(expr.Arguments[0], CreateNullableType(expectedType)));
				case ILCode.NullableOf:
					return CreateNullableType(InferTypeForExpression(expr.Arguments[0], GetNullableTypeArgument(expectedType)));
					#endregion
					#region Arithmetic instructions
				case ILCode.Not: // bitwise complement
				case ILCode.Neg:
					return InferTypeForExpression(expr.Arguments.Single(), expectedType);
				case ILCode.Add:
					return InferArgumentsInAddition(expr, null, expectedType);
				case ILCode.Sub:
					return InferArgumentsInSubtraction(expr, null, expectedType);
				case ILCode.Mul:
				case ILCode.Or:
				case ILCode.And:
				case ILCode.Xor:
					return InferArgumentsInBinaryOperator(expr, null, expectedType);
				case ILCode.Add_Ovf:
					return InferArgumentsInAddition(expr, true, expectedType);
				case ILCode.Sub_Ovf:
					return InferArgumentsInSubtraction(expr, true, expectedType);
				case ILCode.Mul_Ovf:
				case ILCode.Div:
				case ILCode.Rem:
					return InferArgumentsInBinaryOperator(expr, true, expectedType);
				case ILCode.Add_Ovf_Un:
					return InferArgumentsInAddition(expr, false, expectedType);
				case ILCode.Sub_Ovf_Un:
					return InferArgumentsInSubtraction(expr, false, expectedType);
				case ILCode.Mul_Ovf_Un:
				case ILCode.Div_Un:
				case ILCode.Rem_Un:
					return InferArgumentsInBinaryOperator(expr, false, expectedType);
				case ILCode.Shl:
					if (forceInferChildren)
						InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
					if (expectedType != null && (
						expectedType.MetadataType == MetadataType.Int32 || expectedType.MetadataType == MetadataType.UInt32 ||
						expectedType.MetadataType == MetadataType.Int64 || expectedType.MetadataType == MetadataType.UInt64)
					   )
						return NumericPromotion(InferTypeForExpression(expr.Arguments[0], expectedType));
					else
						return NumericPromotion(InferTypeForExpression(expr.Arguments[0], null));
				case ILCode.Shr:
				case ILCode.Shr_Un:
					{
						if (forceInferChildren)
							InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
						TypeReference type = NumericPromotion(InferTypeForExpression(expr.Arguments[0], null));
						TypeReference expectedInputType = null;
						switch (type.MetadataType) {
							case MetadataType.Int32:
								if (expr.Code == ILCode.Shr_Un)
									expectedInputType = typeSystem.UInt32;
								break;
							case MetadataType.UInt32:
								if (expr.Code == ILCode.Shr)
									expectedInputType = typeSystem.Int32;
								break;
							case MetadataType.Int64:
								if (expr.Code == ILCode.Shr_Un)
									expectedInputType = typeSystem.UInt64;
								break;
							case MetadataType.UInt64:
								if (expr.Code == ILCode.Shr)
									expectedInputType = typeSystem.UInt64;
								break;
						}
						if (expectedInputType != null) {
							InferTypeForExpression(expr.Arguments[0], expectedInputType);
							return expectedInputType;
						} else {
							return type;
						}
					}
				case ILCode.CompoundAssignment:
					{
						var op = expr.Arguments[0];
						if (op.Code == ILCode.NullableOf) op = op.Arguments[0].Arguments[0];
						var varType = InferTypeForExpression(op.Arguments[0], null);
						if (forceInferChildren) {
							InferTypeForExpression(expr.Arguments[0], varType);
						}
						return varType;
					}
					#endregion
					#region Constant loading instructions
				case ILCode.Ldnull:
					return typeSystem.Object;
				case ILCode.Ldstr:
					return typeSystem.String;
				case ILCode.Ldftn:
				case ILCode.Ldvirtftn:
					return typeSystem.IntPtr;
				case ILCode.Ldc_I4:
					if (IsBoolean(expectedType) && ((int)expr.Operand == 0 || (int)expr.Operand == 1))
						return typeSystem.Boolean;
					if (expectedType is PointerType && (int)expr.Operand == 0)
						return expectedType;
					if (IsIntegerOrEnum(expectedType) && OperandFitsInType(expectedType, (int)expr.Operand))
						return expectedType;
					else
						return typeSystem.Int32;
				case ILCode.Ldc_I8:
					if (expectedType is PointerType && (long)expr.Operand == 0)
						return expectedType;
					if (IsIntegerOrEnum(expectedType) && GetInformationAmount(expectedType) >= NativeInt)
						return expectedType;
					else
						return typeSystem.Int64;
				case ILCode.Ldc_R4:
					return typeSystem.Single;
				case ILCode.Ldc_R8:
					return typeSystem.Double;
				case ILCode.Ldc_Decimal:
					return new TypeReference("System", "Decimal", module, module.TypeSystem.Corlib, true);
				case ILCode.Ldtoken:
					if (expr.Operand is TypeReference)
						return new TypeReference("System", "RuntimeTypeHandle", module, module.TypeSystem.Corlib, true);
					else if (expr.Operand is FieldReference)
						return new TypeReference("System", "RuntimeFieldHandle", module, module.TypeSystem.Corlib, true);
					else
						return new TypeReference("System", "RuntimeMethodHandle", module, module.TypeSystem.Corlib, true);
				case ILCode.Arglist:
					return new TypeReference("System", "RuntimeArgumentHandle", module, module.TypeSystem.Corlib, true);
					#endregion
					#region Array instructions
				case ILCode.Newarr:
					if (forceInferChildren) {
						var lengthType = InferTypeForExpression(expr.Arguments.Single(), null);
						if (lengthType == typeSystem.IntPtr) {
							lengthType = typeSystem.Int64;
						} else if (lengthType == typeSystem.UIntPtr) {
							lengthType = typeSystem.UInt64;
						} else if (lengthType != typeSystem.UInt32 && lengthType != typeSystem.Int64 && lengthType != typeSystem.UInt64) {
							lengthType = typeSystem.Int32;
						}
						if (forceInferChildren) {
							InferTypeForExpression(expr.Arguments.Single(), lengthType);
						}
					}
					return new ArrayType((TypeReference)expr.Operand);
				case ILCode.InitArray:
					var operandAsArrayType = (ArrayType)expr.Operand;
					if (forceInferChildren)
					{
						foreach (ILExpression arg in expr.Arguments)
							InferTypeForExpression(arg, operandAsArrayType.ElementType);
					}
					return operandAsArrayType;
				case ILCode.Ldlen:
					return typeSystem.Int32;
				case ILCode.Ldelem_U1:
				case ILCode.Ldelem_U2:
				case ILCode.Ldelem_U4:
				case ILCode.Ldelem_I1:
				case ILCode.Ldelem_I2:
				case ILCode.Ldelem_I4:
				case ILCode.Ldelem_I8:
				case ILCode.Ldelem_R4:
				case ILCode.Ldelem_R8:
				case ILCode.Ldelem_I:
				case ILCode.Ldelem_Ref:
					{
						ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
						if (forceInferChildren) {
							InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
						}
						return arrayType != null ? arrayType.ElementType : null;
					}
				case ILCode.Ldelem_Any:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
					}
					return (TypeReference)expr.Operand;
				case ILCode.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 ILCode.Stelem_I:
				case ILCode.Stelem_I1:
				case ILCode.Stelem_I2:
				case ILCode.Stelem_I4:
				case ILCode.Stelem_I8:
				case ILCode.Stelem_R4:
				case ILCode.Stelem_R8:
				case ILCode.Stelem_Ref:
				case ILCode.Stelem_Any:
					{
						ArrayType arrayType = InferTypeForExpression(expr.Arguments[0], null) as ArrayType;
						if (forceInferChildren) {
							InferTypeForExpression(expr.Arguments[1], typeSystem.Int32);
							if (arrayType != null) {
								InferTypeForExpression(expr.Arguments[2], arrayType.ElementType);
							}
						}
						return arrayType != null ? arrayType.ElementType : null;
					}
					#endregion
					#region Conversion instructions
				case ILCode.Conv_I1:
				case ILCode.Conv_Ovf_I1:
				case ILCode.Conv_Ovf_I1_Un:
					return HandleConversion(8, true, expr.Arguments[0], expectedType, typeSystem.SByte);
				case ILCode.Conv_I2:
				case ILCode.Conv_Ovf_I2:
				case ILCode.Conv_Ovf_I2_Un:
					return HandleConversion(16, true, expr.Arguments[0], expectedType, typeSystem.Int16);
				case ILCode.Conv_I4:
				case ILCode.Conv_Ovf_I4:
				case ILCode.Conv_Ovf_I4_Un:
					return HandleConversion(32, true, expr.Arguments[0], expectedType, typeSystem.Int32);
				case ILCode.Conv_I8:
				case ILCode.Conv_Ovf_I8:
				case ILCode.Conv_Ovf_I8_Un:
					return HandleConversion(64, true, expr.Arguments[0], expectedType, typeSystem.Int64);
				case ILCode.Conv_U1:
				case ILCode.Conv_Ovf_U1:
				case ILCode.Conv_Ovf_U1_Un:
					return HandleConversion(8, false, expr.Arguments[0], expectedType, typeSystem.Byte);
				case ILCode.Conv_U2:
				case ILCode.Conv_Ovf_U2:
				case ILCode.Conv_Ovf_U2_Un:
					return HandleConversion(16, false, expr.Arguments[0], expectedType, typeSystem.UInt16);
				case ILCode.Conv_U4:
				case ILCode.Conv_Ovf_U4:
				case ILCode.Conv_Ovf_U4_Un:
					return HandleConversion(32, false, expr.Arguments[0], expectedType, typeSystem.UInt32);
				case ILCode.Conv_U8:
				case ILCode.Conv_Ovf_U8:
				case ILCode.Conv_Ovf_U8_Un:
					return HandleConversion(64, false, expr.Arguments[0], expectedType, typeSystem.UInt64);
				case ILCode.Conv_I:
				case ILCode.Conv_Ovf_I:
				case ILCode.Conv_Ovf_I_Un:
					return HandleConversion(NativeInt, true, expr.Arguments[0], expectedType, typeSystem.IntPtr);
				case ILCode.Conv_U:
				case ILCode.Conv_Ovf_U:
				case ILCode.Conv_Ovf_U_Un:
					return HandleConversion(NativeInt, false, expr.Arguments[0], expectedType, typeSystem.UIntPtr);
				case ILCode.Conv_R4:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], typeSystem.Single);
					}
					return typeSystem.Single;
				case ILCode.Conv_R8:
					if (forceInferChildren) {
						InferTypeForExpression(expr.Arguments[0], typeSystem.Double);
					}
					return typeSystem.Double;
				case ILCode.Conv_R_Un:
					return (expectedType != null  && expectedType.MetadataType == MetadataType.Single) ? typeSystem.Single : typeSystem.Double;
				case ILCode.Castclass:
				case ILCode.Unbox_Any:
					return (TypeReference)expr.Operand;
				case ILCode.Unbox:
					return new ByReferenceType((TypeReference)expr.Operand);
				case ILCode.Isinst:
					{
						// isinst performs the equivalent of a cast only for reference types;
						// value types still need to be unboxed after an isinst instruction
						TypeReference tr = (TypeReference)expr.Operand;
						return tr.IsValueType ? typeSystem.Object : tr;
					}
				case ILCode.Box:
					{
						var tr = (TypeReference)expr.Operand;
						if (forceInferChildren)
							InferTypeForExpression(expr.Arguments.Single(), tr);
						return tr.IsValueType ? typeSystem.Object : tr;
					}
					#endregion
					#region Comparison instructions
				case ILCode.Ceq:
				case ILCode.Cne:
					if (forceInferChildren)
						InferArgumentsInBinaryOperator(expr, null, null);
					return typeSystem.Boolean;
				case ILCode.Clt:
				case ILCode.Cgt:
				case ILCode.Cle:
				case ILCode.Cge:
					if (forceInferChildren)
						InferArgumentsInBinaryOperator(expr, true, null);
					return typeSystem.Boolean;
				case ILCode.Clt_Un:
				case ILCode.Cgt_Un:
				case ILCode.Cle_Un:
				case ILCode.Cge_Un:
					if (forceInferChildren)
						InferArgumentsInBinaryOperator(expr, false, null);
					return typeSystem.Boolean;
					#endregion
					#region Branch instructions
				case ILCode.Brtrue:
					if (forceInferChildren)
						InferTypeForExpression(expr.Arguments.Single(), typeSystem.Boolean);
					return null;
				case ILCode.Br:
				case ILCode.Leave:
				case ILCode.Endfinally:
				case ILCode.Switch:
				case ILCode.Throw:
				case ILCode.Rethrow:
				case ILCode.LoopOrSwitchBreak:
				case ILCode.LoopContinue:
				case ILCode.YieldBreak:
					return null;
				case ILCode.Ret:
					if (forceInferChildren && expr.Arguments.Count == 1) {
						TypeReference returnType = context.CurrentMethod.ReturnType;
						if (context.CurrentMethodIsAsync && returnType != null && returnType.Namespace == "System.Threading.Tasks") {
							if (returnType.Name == "Task") {
								returnType = typeSystem.Void;
							} else if (returnType.Name == "Task`1" && returnType.IsGenericInstance) {
								returnType = ((GenericInstanceType)returnType).GenericArguments[0];
							}
						}
						InferTypeForExpression(expr.Arguments[0], returnType);
					}
					return null;
				case ILCode.YieldReturn:
					if (forceInferChildren) {
						GenericInstanceType genericType = context.CurrentMethod.ReturnType as GenericInstanceType;
						if (genericType != null) { // IEnumerable<T> or IEnumerator<T>
							InferTypeForExpression(expr.Arguments[0], genericType.GenericArguments[0]);
						} else { // non-generic IEnumerable or IEnumerator
							InferTypeForExpression(expr.Arguments[0], typeSystem.Object);
						}
					}
					return null;
				case ILCode.Await:
					{
						TypeReference taskType = InferTypeForExpression(expr.Arguments[0], null);
						if (taskType.Name == "Task`1" && taskType.IsGenericInstance && taskType.Namespace == "System.Threading.Tasks") {
							return ((GenericInstanceType)taskType).GenericArguments[0];
						}
						return null;
					}
					#endregion
				case ILCode.Pop:
					return null;
				case ILCode.Wrap:
				case ILCode.Dup:
					{
						var arg = expr.Arguments.Single();
						return arg.ExpectedType = InferTypeForExpression(arg, expectedType);
					}
				default:
					Debug.WriteLine("Type Inference: Can't handle " + expr.Code.GetName());
					return null;
			}
		}
		void FindNestedAssignments(ILExpression expr, ExpressionToInfer parent)
		{
			foreach (ILExpression arg in expr.Arguments) {
				if (arg.Code == ILCode.Stloc) {
					ExpressionToInfer expressionToInfer = new ExpressionToInfer();
					expressionToInfer.Expression = arg;
					allExpressions.Add(expressionToInfer);
					FindNestedAssignments(arg, expressionToInfer);
					ILVariable v = (ILVariable)arg.Operand;
					if (v.Type == null) {
						assignmentExpressions[v].Add(expressionToInfer);
						// the instruction that consumes the stloc result is handled as if it was reading the variable
						parent.Dependencies.Add(v);
					}
				} else {
					ILVariable v;
					if (arg.Match(ILCode.Ldloc, out v) && v.Type == null) {
						parent.Dependencies.Add(v);
					}
					FindNestedAssignments(arg, parent);
				}
			}
		}
예제 #45
0
 public static bool MatchSingleAndBr <T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg, out ILLabel brLabel)
 {
     if (bb.Body.Count == 3 &&
         bb.Body[0] is ILLabel &&
         bb.Body[1].Match(code, out operand, out arg) &&
         bb.Body[2].Match(ILCode.Br, out brLabel))
     {
         return(true);
     }
     operand = default(T);
     arg     = null;
     brLabel = null;
     return(false);
 }
		/// <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)
		{
			if (expectedType != null && !IsSameType(expr.ExpectedType, expectedType)) {
				expr.ExpectedType = expectedType;
				if (expr.Code != ILCode.Stloc) // stloc is special case and never gets re-evaluated
					forceInferChildren = true;
			}
			if (forceInferChildren || expr.InferredType == null)
				expr.InferredType = DoInferTypeForExpression(expr, expectedType, forceInferChildren);
			return expr.InferredType;
		}
예제 #47
0
 public static bool MatchSingle <T>(this ILBasicBlock bb, ILCode code, out T operand, out ILExpression arg)
 {
     if (bb.Body.Count == 2 &&
         bb.Body[0] is ILLabel &&
         bb.Body[1].Match(code, out operand, out arg))
     {
         return(true);
     }
     operand = default(T);
     arg     = null;
     return(false);
 }
		TypeReference HandleConversion(int targetBitSize, bool targetSigned, ILExpression arg, TypeReference expectedType, TypeReference targetType)
		{
			if (targetBitSize >= NativeInt && expectedType is PointerType) {
				InferTypeForExpression(arg, expectedType);
				return expectedType;
			}
			TypeReference argType = InferTypeForExpression(arg, null);
			if (targetBitSize >= NativeInt && argType is ByReferenceType) {
				// conv instructions on managed references mean that the GC should stop tracking them, so they become pointers:
				PointerType ptrType = new PointerType(((ByReferenceType)argType).ElementType);
				InferTypeForExpression(arg, ptrType);
				return ptrType;
			} else if (targetBitSize >= NativeInt && argType is PointerType) {
				return argType;
			}
			TypeReference resultType = (GetInformationAmount(expectedType) == targetBitSize && IsSigned(expectedType) == targetSigned) ? expectedType : targetType;
			arg.ExpectedType = resultType; // store the expected type in the argument so that AstMethodBodyBuilder will insert a cast
			return resultType;
		}
        bool MatchFixedInitializer(List <ILNode> body, int i, out ILVariable pinnedVar, out ILExpression initValue, out int nextPos)
        {
            if (body[i].Match(ILCode.Stloc, out pinnedVar, out initValue) && pinnedVar.IsPinned && !IsNullOrZero(initValue))
            {
                initValue = (ILExpression)body[i];
                nextPos   = i + 1;
                HandleStringFixing(pinnedVar, body, ref nextPos, ref initValue);
                return(true);
            }
            ILCondition  ifStmt = body[i] as ILCondition;
            ILExpression arrayLoadingExpr;

            if (ifStmt != null && MatchFixedArrayInitializerCondition(ifStmt.Condition, out arrayLoadingExpr))
            {
                ILVariable   arrayVariable = (ILVariable)arrayLoadingExpr.Operand;
                ILExpression trueValue;
                if (ifStmt.TrueBlock != null && ifStmt.TrueBlock.Body.Count == 1 &&
                    ifStmt.TrueBlock.Body[0].Match(ILCode.Stloc, out pinnedVar, out trueValue) &&
                    pinnedVar.IsPinned && IsNullOrZero(trueValue))
                {
                    if (ifStmt.FalseBlock != null && ifStmt.FalseBlock.Body.Count == 1 && ifStmt.FalseBlock.Body[0] is ILFixedStatement)
                    {
                        ILFixedStatement fixedStmt = (ILFixedStatement)ifStmt.FalseBlock.Body[0];
                        ILVariable       stlocVar;
                        ILExpression     falseValue;
                        if (fixedStmt.Initializers.Count == 1 && fixedStmt.BodyBlock.Body.Count == 0 &&
                            fixedStmt.Initializers[0].Match(ILCode.Stloc, out stlocVar, out falseValue) && stlocVar == pinnedVar)
                        {
                            ILVariable loadedVariable;
                            if (falseValue.Code == ILCode.Ldelema &&
                                falseValue.Arguments[0].Match(ILCode.Ldloc, out loadedVariable) && loadedVariable == arrayVariable &&
                                IsNullOrZero(falseValue.Arguments[1]))
                            {
                                // OK, we detected the pattern for fixing an array.
                                // Now check whether the loading expression was a store ot a temp. var
                                // that can be eliminated.
                                if (arrayLoadingExpr.Code == ILCode.Stloc)
                                {
                                    ILInlining inlining = new ILInlining(method);
                                    if (inlining.numLdloc.GetOrDefault(arrayVariable) == 2 &&
                                        inlining.numStloc.GetOrDefault(arrayVariable) == 1 && inlining.numLdloca.GetOrDefault(arrayVariable) == 0)
                                    {
                                        arrayLoadingExpr = arrayLoadingExpr.Arguments[0];
                                    }
                                }
                                initValue = new ILExpression(ILCode.Stloc, pinnedVar, arrayLoadingExpr);
                                nextPos   = i + 1;
                                return(true);
                            }
                        }
                    }
                }
            }
            initValue = null;
            nextPos   = -1;
            return(false);
        }