Beispiel #1
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;
		}
Beispiel #2
0
		static bool TypeConversionSimplifications(ILBlockBase block, 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(block, null, arg, -1);
			}
			return modified;
		}
Beispiel #3
0
		public static void LabelMergeILRanges(ILBlockBase block, List<ILNode> newBody, int instrIndexToRemove)
		{
			var body = block.Body;
			ILNode prevNode = null, nextNode = null;
			if (newBody.Count > 0)
				prevNode = newBody[newBody.Count - 1];
			if (instrIndexToRemove + 1 < body.Count)
				nextNode = body[instrIndexToRemove + 1];

			AddILRangesTryNextFirst(body[instrIndexToRemove], prevNode, nextNode, block);
		}
Beispiel #4
0
		public static void AddILRangesTryPreviousFirst(ILNode prev, ILNode next, ILBlockBase block, IEnumerable<ILRange> ilRanges)
		{
			if (prev != null && prev.SafeToAddToEndILRanges)
				prev.EndILRanges.AddRange(ilRanges);
			else if (next != null)
				next.ILRanges.AddRange(ilRanges);
			else if (prev != null)
				block.EndILRanges.AddRange(ilRanges);
			else
				block.ILRanges.AddRange(ilRanges);
		}
Beispiel #5
0
 public static void AddILRangesToInstruction(ILNode nodeToAddTo, ILNode prev, ILNode next, ILBlockBase block, ILNode removed)
 {
     Debug.Assert(nodeToAddTo == prev || nodeToAddTo == next || nodeToAddTo == block);
     if (nodeToAddTo != null) {
         if (nodeToAddTo == prev && prev.SafeToAddToEndILRanges) {
             removed.AddSelfAndChildrenRecursiveILRanges(prev.EndILRanges);
             return;
         }
         else if (nodeToAddTo != null && nodeToAddTo == next) {
             removed.AddSelfAndChildrenRecursiveILRanges(next.ILRanges);
             return;
         }
     }
     AddILRangesTryNextFirst(prev, next, block, removed);
 }
Beispiel #6
0
        public static void AddILRanges(ILBlockBase block, List<ILNode> body, int removedIndex, IEnumerable<ILRange> ilRanges)
        {
            var prev = removedIndex - 1 >= 0 ? body[removedIndex - 1] : null;
            var next = removedIndex + 1 < body.Count ? body[removedIndex + 1] : null;

            ILNode node = null;
            if (node == null && next is ILExpression)
                node = next;
            if (node == null && prev is ILExpression)
                node = prev;
            if (node == null && next is ILLabel)
                node = next;
            if (node == null && prev is ILLabel)
                node = prev;
            if (node == null)
                node = next ?? prev;	// Using next before prev should work better

            AddILRangesToInstruction(node, prev, next, block, ilRanges);
        }
Beispiel #7
0
        /// <summary>
        /// Adds the removed instruction's ILRanges to the next or previous instruction
        /// </summary>
        /// <param name="block">The owner block</param>
        /// <param name="body">Body</param>
        /// <param name="removedIndex">Index of removed instruction</param>
        /// <param name="numRemoved">Number of removed instructions</param>
        public static void AddILRanges(ILBlockBase block, List<ILNode> body, int removedIndex, int numRemoved)
        {
            var prev = removedIndex - 1 >= 0 ? body[removedIndex - 1] : null;
            var next = removedIndex + numRemoved < body.Count ? body[removedIndex + numRemoved] : null;

            ILNode node = null;
            if (node == null && next is ILExpression)
                node = next;
            if (node == null && prev is ILExpression)
                node = prev;
            if (node == null && next is ILLabel)
                node = next;
            if (node == null && prev is ILLabel)
                node = prev;
            if (node == null)
                node = next ?? prev;	// Using next before prev should work better

            for (int i = 0; i < numRemoved; i++)
                AddILRangesToInstruction(node, prev, next, block, body[removedIndex + i]);
        }
Beispiel #8
0
		public static void NopMergeILRanges(ILBlockBase block, List<ILNode> newBody, int instrIndexToRemove)
		{
			var body = block.Body;
			ILNode prevNode = null, nextNode = null;
			ILExpression prev = null, next = null;
			if (newBody.Count > 0)
				prev = (prevNode = newBody[newBody.Count - 1]) as ILExpression;
			if (instrIndexToRemove + 1 < body.Count)
				next = (nextNode = body[instrIndexToRemove + 1]) as ILExpression;

			ILNode node = null;

			if (prev != null && prev.Prefixes == null) {
				switch (prev.Code) {
				case ILCode.Call:
				case ILCode.CallGetter:
				case ILCode.Calli:
				case ILCode.CallSetter:
				case ILCode.Callvirt:
				case ILCode.CallvirtGetter:
				case ILCode.CallvirtSetter:
					node = prev;
					break;
				}
			}

			if (next != null && next.Prefixes == null) {
				if (next.Match(ILCode.Leave))
					node = next;
			}

			if (node != null && node == prevNode)
				AddILRangesTryPreviousFirst(body[instrIndexToRemove], prevNode, nextNode, block);
			else
				AddILRangesTryNextFirst(body[instrIndexToRemove], prevNode, nextNode, block);
		}
Beispiel #9
0
		public static void AddILRangesToInstruction(ILNode nodeToAddTo, ILNode prev, ILNode next, ILBlockBase block, IEnumerable<ILRange> ilRanges)
		{
			Debug.Assert(nodeToAddTo == prev || nodeToAddTo == next || nodeToAddTo == block);
			if (nodeToAddTo != null) {
				if (nodeToAddTo == prev && prev.SafeToAddToEndILRanges) {
					prev.EndILRanges.AddRange(ilRanges);
					return;
				}
				else if (nodeToAddTo != null && nodeToAddTo == next) {
					next.ILRanges.AddRange(ilRanges);
					return;
				}
			}
			AddILRangesTryNextFirst(prev, next, block, ilRanges);
		}
Beispiel #10
0
		/// <summary>
		/// Adds the removed instruction's ILRanges to the next or previous instruction
		/// </summary>
		/// <param name="block">The owner block</param>
		/// <param name="body">Body</param>
		/// <param name="removedIndex">Index of removed instruction</param>
		public static void AddILRanges(ILBlockBase block, List<ILNode> body, int removedIndex)
		{
			AddILRanges(block, body, removedIndex, 1);
		}
Beispiel #11
0
		static bool SimplifyLogicNot(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos)
		{
			bool modified = false;
			expr = SimplifyLogicNot(expr, ref modified);
			Debug.Assert(expr == null);
			return modified;
		}
Beispiel #12
0
 public static void AddILRangesTryPreviousFirst(ILNode prev, ILNode next, ILBlockBase block, ILNode removed)
 {
     if (prev != null && prev.SafeToAddToEndILRanges)
         removed.AddSelfAndChildrenRecursiveILRanges(prev.EndILRanges);
     else if (next != null)
         removed.AddSelfAndChildrenRecursiveILRanges(next.ILRanges);
     else if (prev != null)
         removed.AddSelfAndChildrenRecursiveILRanges(block.EndILRanges);
     else
         removed.AddSelfAndChildrenRecursiveILRanges(block.ILRanges);
 }
Beispiel #13
0
		/// <summary>
		/// Aggressively inlines the stloc instruction at block.Body[pos] into the next instruction, if possible.
		/// If inlining was possible; we will continue to inline (non-aggressively) into the the combined instruction.
		/// </summary>
		/// <remarks>
		/// After the operation, pos will point to the new combined instruction.
		/// </remarks>
		public bool InlineIfPossible(ILBlockBase block, List<ILNode> body, ref int pos)
		{
			if (InlineOneIfPossible(block, body, pos, true)) {
				pos -= InlineInto(block, body, pos, false);
				return true;
			}
			return false;
		}
Beispiel #14
0
		public static void AddILRangesTryNextFirst(ILNode removed, ILNode prev, ILNode next, ILBlockBase block)
		{
			if (removed == null)
				return;
			AddILRangesTryNextFirst(prev, next, block, removed.GetSelfAndChildrenRecursiveILRanges());
		}
Beispiel #15
0
		static bool SimplifyLdObjAndStObj(ILBlockBase block, 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(block, null, expr.Arguments[i], -1);
			}
			return modified;
		}
Beispiel #16
0
		bool InlineExpressionTreeParameterDeclarations(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos)
		{
			// When there is a Expression.Lambda() call, and the parameters are declared in the
			// IL statement immediately prior to the one containing the Lambda() call,
			// using this code for the3 declaration:
			//   stloc(v, call(Expression::Parameter, call(Type::GetTypeFromHandle, ldtoken(...)), ldstr(...)))
			// and the variables v are assigned only once (in that statements), and read only in a Expression::Lambda
			// call that immediately follows the assignment statements, then we will inline those assignments
			// into the Lambda call using ILCode.ExpressionTreeParameterDeclarations.
			
			// This is sufficient to allow inlining over the expression tree construction. The remaining translation
			// of expression trees into C# will be performed by a C# AST transformer.
			
			for (int i = expr.Arguments.Count - 1; i >= 0; i--) {
				if (InlineExpressionTreeParameterDeclarations(block, body, expr.Arguments[i], pos))
					return true;
			}
			
			IMethod mr;
			ILExpression lambdaBodyExpr, parameterArray;
			if (!(expr.Match(ILCode.Call, out mr, out lambdaBodyExpr, out parameterArray) && mr.Name == "Lambda"))
				return false;
			if (!(parameterArray.Code == ILCode.InitArray && mr.DeclaringType != null && mr.DeclaringType.FullName == "System.Linq.Expressions.Expression"))
				return false;
			int firstParameterPos = pos - parameterArray.Arguments.Count;
			if (firstParameterPos < 0)
				return false;
			
			ILExpression[] parameterInitExpressions = new ILExpression[parameterArray.Arguments.Count + 1];
			for (int i = 0; i < parameterArray.Arguments.Count; i++) {
				parameterInitExpressions[i] = body[firstParameterPos + i] as ILExpression;
				if (!MatchParameterVariableAssignment(parameterInitExpressions[i]))
					return false;
				ILVariable v = (ILVariable)parameterInitExpressions[i].Operand;
				if (!parameterArray.Arguments[i].MatchLdloc(v))
					return false;
				// TODO: validate that the variable is only used here and within 'body'
			}
			
			parameterInitExpressions[parameterInitExpressions.Length - 1] = lambdaBodyExpr;
			Debug.Assert(expr.Arguments[0] == lambdaBodyExpr);
			expr.Arguments[0] = new ILExpression(ILCode.ExpressionTreeParameterDeclarations, null, parameterInitExpressions);
			
			body.RemoveRange(firstParameterPos, parameterArray.Arguments.Count);
			
			return true;
		}
Beispiel #17
0
		static bool SimplifyShiftOperators(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos)
		{
			// C# compiles "a << b" to "a << (b & 31)", so we will remove the "& 31" if possible.
			bool modified = false;
			SimplifyShiftOperators(expr, ref modified);
			return modified;
		}
Beispiel #18
0
		bool MakeAssignmentExpression(ILBlockBase block, 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.GeneratedByDecompiler))
				return false;
			ILExpression nextExpr = body.ElementAtOrDefault(pos + 1) as ILExpression;
			if (nextExpr == null)
				return false;
			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.ILRanges.AddRange(nextExpr.Arguments[0].GetSelfAndChildrenRecursiveILRanges());
						nextExpr.Arguments[0] = store2;
						store2.ILRanges.AddRange(expr.GetSelfAndChildrenRecursiveILRanges());
						store2.ILRanges.AddRange(store2.Arguments[store2.Arguments.Count - 1].GetSelfAndChildrenRecursiveILRanges());
						store2.Arguments[store2.Arguments.Count - 1] = initializer;
						
						inlining.InlineIfPossible(block, body, ref pos);
						
						return true;
					}
				}
				
				body.RemoveAt(pos + 1); // remove stloc
				nextExpr.ILRanges.AddRange(nextExpr.Arguments[0].GetSelfAndChildrenRecursiveILRanges());
				nextExpr.Arguments[0] = initializer;
				nextExpr.ILRanges.AddRange(expr.Arguments[0].GetSelfAndChildrenRecursiveILRanges());
				expr.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.ILRanges.AddRange(nextExpr.Arguments[0].GetSelfAndChildrenRecursiveILRanges());
					nextExpr.Arguments[0] = initializer;
					expr.ILRanges.AddRange(expr.Arguments[0].GetSelfAndChildrenRecursiveILRanges());
					expr.Arguments[0] = nextExpr;
					return true;
				}
			}
			return false;
		}
Beispiel #19
0
		bool MakeCompoundAssignments(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos)
		{
			bool modified = false;
			modified |= MakeCompoundAssignment(expr);
			// Static fields and local variables are not handled here - those are expressions without side effects
			// and get handled by ReplaceMethodCallsWithOperators
			// (which does a reversible transform to the short operator form, as the introduction of checked/unchecked might have to revert to the long form).
			foreach (ILExpression arg in expr.Arguments) {
				modified |= MakeCompoundAssignments(block, null, arg, -1);
			}
			if (modified && body != null)
				new ILInlining(method).InlineInto(block, body, pos, aggressive: false);
			return modified;
		}
Beispiel #20
0
		public static void AddILRangesTryPreviousFirst(List<ILNode> newBody, List<ILNode> body, int removedIndex, ILBlockBase block)
		{
			ILNode prev = newBody.Count > 0 ? newBody[newBody.Count - 1] : null;
			ILNode next = removedIndex + 1 < body.Count ? body[removedIndex + 1] : null;
			AddILRangesTryPreviousFirst(body[removedIndex], prev, next, block);
		}
Beispiel #21
0
		bool IntroducePostIncrement(ILBlockBase block, List<ILNode> body, ILExpression expr, int pos)
		{
			bool modified = IntroducePostIncrementForVariables(body, expr, pos);
			Debug.Assert(body[pos] == expr); // IntroducePostIncrementForVariables shouldn't change the expression reference
			ILExpression newExpr = IntroducePostIncrementForInstanceFields(expr);
			if (newExpr != null) {
				modified = true;
				body[pos] = newExpr;
				new ILInlining(method).InlineIfPossible(block, body, ref pos);
			}
			return modified;
		}
Beispiel #22
0
		/// <summary>
		/// Inlines instructions before pos into block.Body[pos].
		/// </summary>
		/// <returns>The number of instructions that were inlined.</returns>
		public int InlineInto(ILBlockBase block, List<ILNode> body, int pos, bool aggressive)
		{
			if (pos >= body.Count)
				return 0;
			int count = 0;
			while (--pos >= 0) {
				ILExpression expr = body[pos] as ILExpression;
				if (expr == null || expr.Code != ILCode.Stloc)
					break;
				if (InlineOneIfPossible(block, body, pos, aggressive))
					count++;
				else
					break;
			}
			return count;
		}
Beispiel #23
0
		bool IntroduceFixedStatements(ILBlockBase block, List<ILNode> body, int i)
		{
			ILExpression initValue;
			ILVariable pinnedVar;
			int initEndPos;
			if (!MatchFixedInitializer(body, i, out pinnedVar, out initValue, out initEndPos))
				return false;
			
			ILFixedStatement fixedStmt = body.ElementAtOrDefault(initEndPos) as ILFixedStatement;
			if (fixedStmt != null) {
				ILExpression expr = fixedStmt.BodyBlock.Body.LastOrDefault() as ILExpression;
				if (expr != null && expr.Code == ILCode.Stloc && expr.Operand == pinnedVar && IsNullOrZero(expr.Arguments[0])) {
					// we found a second initializer for the existing fixed statement
					fixedStmt.Initializers.Insert(0, initValue);
					for (int k = i; k < initEndPos; k++)
						initValue.ILRanges.AddRange(body[k].GetSelfAndChildrenRecursiveILRanges().ToArray());
					body.RemoveRange(i, initEndPos - i);
					Utils.AddILRanges(fixedStmt.BodyBlock, fixedStmt.BodyBlock.Body, fixedStmt.BodyBlock.Body.Count - 1);
					fixedStmt.BodyBlock.Body.RemoveAt(fixedStmt.BodyBlock.Body.Count - 1);
					if (pinnedVar.Type is ByRefSig)
						pinnedVar.Type = new PtrSig(((ByRefSig)pinnedVar.Type).Next);
					return true;
				}
			}
			
			// find where pinnedVar is reset to 0:
			int j;
			for (j = initEndPos; j < body.Count; j++) {
				ILVariable v2;
				ILExpression storedVal;
				// stloc(pinned_Var, conv.u(ldc.i4(0)))
				if (body[j].Match(ILCode.Stloc, out v2, out storedVal) && v2 == pinnedVar) {
					if (IsNullOrZero(storedVal)) {
						break;
					}
				}
			}
			// Create fixed statement from i to j
			fixedStmt = new ILFixedStatement();
			fixedStmt.Initializers.Add(initValue);
			fixedStmt.BodyBlock = new ILBlock(body.GetRange(initEndPos, j - initEndPos)); // from initEndPos to j-1 (inclusive)
			for (int k = i; k < initEndPos; k++)
				initValue.ILRanges.AddRange(body[k].GetSelfAndChildrenRecursiveILRanges().ToArray());
			body.RemoveRange(i + 1, Math.Min(j, body.Count - 1) - i); // from i+1 to j (inclusive)
			body[i] = fixedStmt;
			if (pinnedVar.Type is ByRefSig)
				pinnedVar.Type = new PtrSig(((ByRefSig)pinnedVar.Type).Next);
			
			return true;
		}
Beispiel #24
0
		/// <summary>
		/// Inlines the stloc instruction at block.Body[pos] into the next instruction, if possible.
		/// </summary>
		public bool InlineOneIfPossible(ILBlockBase block, List<ILNode> body, int pos, bool aggressive)
		{
			ILVariable v;
			ILExpression inlinedExpression;
			if (body[pos].Match(ILCode.Stloc, out v, out inlinedExpression) && !v.IsPinned) {
				if (InlineIfPossible(v, inlinedExpression, body.ElementAtOrDefault(pos+1), aggressive)) {
					// Assign the ranges of the stloc instruction:
					if (context.CalculateILRanges)
						inlinedExpression.ILRanges.AddRange(body[pos].ILRanges);
					// Remove the stloc instruction:
					body.RemoveAt(pos);
					return true;
				} else if (numLdloc.GetOrDefault(v) == 0 && numLdloca.GetOrDefault(v) == 0) {
					// The variable is never loaded
					if (inlinedExpression.HasNoSideEffects()) {
						// Remove completely
						AnalyzeNode(body[pos], -1);
						if (context.CalculateILRanges)
							Utils.AddILRanges(block, body, pos);
						body.RemoveAt(pos);
						return true;
					} else if (inlinedExpression.CanBeExpressionStatement() && v.GeneratedByDecompiler) {
						// Assign the ranges of the stloc instruction:
						if (context.CalculateILRanges)
							inlinedExpression.ILRanges.AddRange(body[pos].ILRanges);
						// Remove the stloc, but keep the inner expression
						body[pos] = inlinedExpression;
						return true;
					}
				}
			}
			return false;
		}
Beispiel #25
0
 public static void AddILRangesTryPreviousFirst(ILNode removed, ILNode prev, ILNode next, ILBlockBase block)
 {
     if (removed == null)
         return;
     AddILRangesTryPreviousFirst(prev, next, block, removed);
 }