public void RemoveGotos(ILBlock method)
		{
			// Build the navigation data
			parent[method] = null;
			foreach (ILNode node in method.EnumerateSelfAndChildrenRecursive()) {
				ILNode previousChild = null;
				foreach (ILNode child in node.GetChildren()) {
					if (parent.ContainsKey(child))
						throw new Exception("The following expression is linked from several locations: " + child.ToString());
					parent[child] = node;
					if (previousChild != null)
						nextSibling[previousChild] = child;
					previousChild = child;
				}
				if (previousChild != null)
					nextSibling[previousChild] = null;
			}
			
			// Simplify gotos
			bool modified;
			do {
				modified = false;
                var gotos =
                    from e in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>()
                    where e.Code == ILCode.Br || e.Code == ILCode.Leave
                    select e;

                foreach (ILExpression gotoExpr in gotos)
                {
					modified |= TrySimplifyGoto(gotoExpr);
				}
			} while(modified);
			
			RemoveRedundantCode(method);
		}
		public SimpleControlFlow(DecompilerContext context, ILBlock method)
		{
			this.context = context;
			this.typeSystem = context.CurrentMethod.Module.TypeSystem;

            var labelTargets =
                from e in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>()
                where e.IsBranch()
                from t in e.GetBranchTargets()
                select t;
			
			foreach(ILLabel target in labelTargets) {
				labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1;
			}

            var basicBlocks = method.EnumerateSelfAndChildrenRecursive().OfType<ILBasicBlock>();

			foreach(ILBasicBlock bb in basicBlocks) {
				foreach(ILLabel label in bb.GetChildren().OfType<ILLabel>()) {
					labelToBasicBlock[label] = bb;
				}
			}
		}
		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.EnumerateSelfAndChildrenRecursive().OfType<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.EnumerateSelfAndChildrenRecursive().OfType<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.EnumerateSelfAndChildrenRecursive().OfType<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;
			}
		}
예제 #4
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.EnumerateSelfAndChildrenRecursive().OfType <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.EnumerateSelfAndChildrenRecursive().OfType <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.EnumerateSelfAndChildrenRecursive().OfType <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);
            }
        }
		public static void RemoveRedundantCode(ILBlock method)
		{
			// Remove dead lables and nops
			var liveLabels = new HashSet<ILLabel>(
                from e in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>()
                where e.IsBranch()
                from t in e.GetBranchTargets()
                select t);

			foreach(ILBlock block in method.EnumerateSelfAndChildrenRecursive().OfType<ILBlock>()) {
                var liveBlockNodes =
                    from n in block.Body
                    where !n.Match(ILCode.Nop) &&
                    !(n is ILLabel
                        && !liveLabels.Contains((ILLabel)n))
                    select n;

				block.Body = liveBlockNodes.ToList();
			}
			
			// Remove redundant continue
			foreach(ILWhileLoop loop in method.EnumerateSelfAndChildrenRecursive().OfType<ILWhileLoop>()) {
				var body = loop.BodyBlock.Body;
				if (body.Count > 0 && body.Last().Match(ILCode.LoopContinue)) {
					body.RemoveAt(body.Count - 1);
				}
			}
			
			// Remove redundant break at the end of case
			// Remove redundant case blocks altogether
			foreach(ILSwitch ilSwitch in method.EnumerateSelfAndChildrenRecursive().OfType<ILSwitch>()) {
				foreach(ILBlock ilCase in ilSwitch.CaseBlocks) {
					Debug.Assert(ilCase.EntryGoto == null);
					
					int count = ilCase.Body.Count;
					if (count >= 2) {
						if (ilCase.Body[count - 2].IsUnconditionalControlFlow() &&
						    ilCase.Body[count - 1].Match(ILCode.LoopOrSwitchBreak)) 
						{
							ilCase.Body.RemoveAt(count - 1);
						}
					}
				}
				
				var defaultCase = ilSwitch.CaseBlocks.SingleOrDefault(cb => cb.Values == null);
				// If there is no default block, remove empty case blocks
				if (defaultCase == null || (defaultCase.Body.Count == 1 && defaultCase.Body.Single().Match(ILCode.LoopOrSwitchBreak))) {
					ilSwitch.CaseBlocks.RemoveAll(b => b.Body.Count == 1 && b.Body.Single().Match(ILCode.LoopOrSwitchBreak));
				}
			}
			
			// Remove redundant return at the end of method
			if (method.Body.Count > 0 && method.Body.Last().Match(ILCode.Ret) && ((ILExpression)method.Body.Last()).Arguments.Count == 0) {
				method.Body.RemoveAt(method.Body.Count - 1);
			}
			
			// Remove unreachable return statements
			bool modified = false;
			foreach(ILBlock block in method.EnumerateSelfAndChildrenRecursive().OfType<ILBlock>().ToList()) {
				for (int i = 0; i < block.Body.Count - 1;) {
					if (block.Body[i].IsUnconditionalControlFlow() && block.Body[i+1].Match(ILCode.Ret)) {
						modified = true;
						block.Body.RemoveAt(i+1);
					} else {
						i++;
					}
				}
			}
			if (modified) {
				// More removals might be possible
				new GotoRemoval().RemoveGotos(method);
			}
		}
		public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters,
		                                       /*Concurrent*/Dictionary<int, IEnumerable<ILVariable>> localVariables)
		{
			if (methodDef.Body == null) return null;
			
			if (localVariables == null)
				throw new ArgumentException("localVariables must be instantiated");
			
			context.VerifyProgress();
			ILBlock ilMethod = new ILBlock();
            var astBuilder = ILMethodAstBuilder.Build(methodDef, true);
			ilMethod.Body = astBuilder.Nodes.ToList();
			
			context.VerifyProgress();
			ILAstOptimizer bodyGraph = new ILAstOptimizer();
			bodyGraph.Optimize(context, ilMethod);
			context.VerifyProgress();
			
			var allVariables =
                (from e in ilMethod.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>()
                let v = e.Operand as ILVariable
                where v!=null && !v.IsParameter
                select v).Distinct();
			Debug.Assert(context.CurrentMethod == methodDef);
			NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, allVariables, ilMethod);
			
			if (parameters != null) {
				foreach (var pair in (from p in parameters
				                      join v in astBuilder.Parameters on p.Annotation<ParameterDefinition>() equals v.OriginalParameter
				                      select new { p, v.Name }))
				{
					pair.p.Name = pair.Name;
				}
			}
			
			context.VerifyProgress();
			BlockStatement astBlock = TransformBlock(ilMethod);
			CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
			
			Statement insertionPoint = astBlock.Statements.FirstOrDefault();
			foreach (ILVariable v in localVariablesToDefine) {
				AstType type;
				if (v.Type.ContainsAnonymousType())
					type = new SimpleType("var");
				else
					type = AstBuilder.ConvertType(v.Type);
				var newVarDecl = new VariableDeclarationStatement(type, v.Name);
				astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
			}
			
			// store the variables - used for debugger
			int token = methodDef.MetadataToken.ToInt32();
			localVariables[token] = allVariables;
			
			return astBlock;
		}
		/// <summary>
		/// Clears the type inference data on the method.
		/// </summary>
		public static void Reset(ILBlock method)
		{
			foreach (ILExpression expr in method.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>()) {
				expr.InferredType = null;
				expr.ExpectedType = null;
				ILVariable v = expr.Operand as ILVariable;
				if (v != null && v.IsGenerated)
					v.Type = null;
			}
		}