예제 #1
0
		public void RemoveGotos(ILBlock method)
		{
			// Build the navigation data
			parent[method] = null;
			foreach (ILNode node in method.GetSelfAndChildrenRecursive<ILNode>()) {
				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;
				foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive<ILExpression>(e => e.Code == ILCode.Br || e.Code == ILCode.Leave)) {
					modified |= TrySimplifyGoto(gotoExpr);
				}
			} while(modified);
			
			RemoveRedundantCode(method);
		}
예제 #2
0
        public void Optimize(ILBlock method)
        {
            foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
                SplitToMovableBlocks(block);
            }

            foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().Where(b => !(b is ILMoveableBlock)).ToList()) {
                ControlFlowGraph graph;
                graph = BuildGraph(block.Body, block.EntryPoint);
                graph.ComputeDominance();
                graph.ComputeDominanceFrontier();
                block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, true);
            }

            foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().Where(b => !(b is ILMoveableBlock)).ToList()) {
                ControlFlowGraph graph;
                graph = BuildGraph(block.Body, block.EntryPoint);
                graph.ComputeDominance();
                graph.ComputeDominanceFrontier();
                block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint);
            }

            // OrderNodes(method);
            FlattenNestedMovableBlocks(method);
            SimpleGotoRemoval(method);
            RemoveDeadLabels(method);
        }
예제 #3
0
        public static void Transform(ILBlock method)
        {
            // TODO: move this somewhere else
            // Eliminate 'dups':
            foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
                for (int i = 0; i < expr.Arguments.Count; i++) {
                    if (expr.Arguments[i].Code == ILCode.Dup)
                        expr.Arguments[i] = expr.Arguments[i].Arguments[0];
                }
            }

            var newArrPattern = new StoreToVariable(new ILExpression(ILCode.Newarr, ILExpression.AnyOperand, new ILExpression(ILCode.Ldc_I4, ILExpression.AnyOperand)));
            var arg1 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true };
            var arg2 = new StoreToVariable(new LoadFromVariable(newArrPattern)) { MustBeGenerated = true };
            var initializeArrayPattern = new ILCall(
                "System.Runtime.CompilerServices.RuntimeHelpers", "InitializeArray",
                new LoadFromVariable(arg1), new ILExpression(ILCode.Ldtoken, ILExpression.AnyOperand));
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
                for (int i = block.Body.Count - 1; i >= 0; i--) {
                    if (!newArrPattern.Match(block.Body[i]))
                        continue;
                    ILExpression newArrInst = ((ILExpression)block.Body[i]).Arguments[0];
                    int arrayLength = (int)newArrInst.Arguments[0].Operand;
                    if (arrayLength == 0)
                        continue;
                    if (arg1.Match(block.Body.ElementAtOrDefault(i + 1)) && arg2.Match(block.Body.ElementAtOrDefault(i + 2))) {
                        if (initializeArrayPattern.Match(block.Body.ElementAtOrDefault(i + 3))) {
                            if (HandleStaticallyInitializedArray(arg2, block, i, newArrInst, arrayLength)) {
                                i -= ILInlining.InlineInto(block, i + 1, method) - 1;
                            }
                            continue;
                        }
                    }
                    if (i + 1 + arrayLength > block.Body.Count)
                        continue;
                    List<ILExpression> operands = new List<ILExpression>();
                    for (int j = 0; j < arrayLength; j++) {
                        ILExpression expr = block.Body[i + 1 + j] as ILExpression;
                        if (expr == null || !IsStoreToArray(expr.Code))
                            break;
                        if (!(expr.Arguments[0].Code == ILCode.Ldloc && expr.Arguments[0].Operand == newArrPattern.LastVariable))
                            break;
                        if (!(expr.Arguments[1].Code == ILCode.Ldc_I4 && (int)expr.Arguments[1].Operand == j))
                            break;
                        operands.Add(expr.Arguments[2]);
                    }
                    if (operands.Count == arrayLength) {
                        ((ILExpression)block.Body[i]).Arguments[0] = new ILExpression(
                            ILCode.InitArray, newArrInst.Operand, operands.ToArray());
                        block.Body.RemoveRange(i + 1, arrayLength);
                        i -= ILInlining.InlineInto(block, i + 1, method) - 1;
                    }
                }
            }
        }
예제 #4
0
		public SimpleControlFlow(DecompilerContext context, ILBlock method)
		{
			this.context = context;
			this.typeSystem = context.CurrentMethod.Module.TypeSystem;
			
			foreach(ILLabel target in method.GetSelfAndChildrenRecursive<ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets())) {
				labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1;
			}
			foreach(ILBasicBlock bb in method.GetSelfAndChildrenRecursive<ILBasicBlock>()) {
				foreach(ILLabel label in bb.GetChildren().OfType<ILLabel>()) {
					labelToBasicBlock[label] = bb;
				}
			}
		}
예제 #5
0
		public BlockStatement CreateMethodBody()
		{
			if (methodDef.Body == null) return null;
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILBlock ilMethod = new ILBlock();
			ILAstBuilder astBuilder = new ILAstBuilder();
			ilMethod.Body = astBuilder.Build(methodDef, true);
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILAstOptimizer bodyGraph = new ILAstOptimizer();
			bodyGraph.Optimize(context, ilMethod);
			context.CancellationToken.ThrowIfCancellationRequested();
			
			var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable).Where(v => v != null && !v.IsGenerated).Distinct();
			NameVariables.AssignNamesToVariables(methodDef.Parameters.Select(p => p.Name), allVariables, ilMethod);
			
			context.CancellationToken.ThrowIfCancellationRequested();
			Ast.BlockStatement astBlock = TransformBlock(ilMethod);
			CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
			foreach (ILVariable v in localVariablesToDefine) {
				DeclareVariableInSmallestScope.DeclareVariable(astBlock, AstBuilder.ConvertType(v.Type), v.Name);
			}
			
			return astBlock;
		}
예제 #6
0
		public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
		{
			if (!method.HasBody) {
				return;
			}
			
			ILAstBuilder astBuilder = new ILAstBuilder();
			ILBlock ilMethod = new ILBlock();
			ilMethod.Body = astBuilder.Build(method, inlineVariables);
			
			if (abortBeforeStep != null) {
				DecompilerContext context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method };
				new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value);
			}
			
			var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
				.Where(v => v != null && !v.IsParameter).Distinct();
			foreach (ILVariable v in allVariables) {
				output.WriteDefinition(v.Name, v);
				if (v.Type != null) {
					output.Write(" : ");
					if (v.IsPinned)
						output.Write("pinned ");
					v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
				}
				output.WriteLine();
			}
			output.WriteLine();
			
			foreach (ILNode node in ilMethod.Body) {
				node.WriteTo(output);
				output.WriteLine();
			}
		}
예제 #7
0
		public override void DecompileMethod(MethodDef method, ITextOutput output, DecompilationOptions options)
		{
			WriteComment(output, "Method: ");
			output.WriteDefinition(IdentifierEscaper.Escape(method.FullName), method, TextTokenType.Comment, false);
			output.WriteLine();

			if (!method.HasBody) {
				return;
			}
			
			StartKeywordBlock(output, ".body", method);

			ILAstBuilder astBuilder = new ILAstBuilder();
			ILBlock ilMethod = new ILBlock();
			DecompilerContext context = new DecompilerContext(method.Module) { CurrentType = method.DeclaringType, CurrentMethod = method };
			ilMethod.Body = astBuilder.Build(method, inlineVariables, context);
			
			if (abortBeforeStep != null) {
				new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value);
			}
			
			if (context.CurrentMethodIsAsync) {
				output.Write("async", TextTokenType.Keyword);
				output.Write('/', TextTokenType.Operator);
				output.WriteLine("await", TextTokenType.Keyword);
			}
			
			var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
				.Where(v => v != null && !v.IsParameter).Distinct();
			foreach (ILVariable v in allVariables) {
				output.WriteDefinition(IdentifierEscaper.Escape(v.Name), v, v.IsParameter ? TextTokenType.Parameter : TextTokenType.Local);
				if (v.Type != null) {
					output.WriteSpace();
					output.Write(':', TextTokenType.Operator);
					output.WriteSpace();
					if (v.IsPinned) {
						output.Write("pinned", TextTokenType.Keyword);
						output.WriteSpace();
					}
					v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
				}
				if (v.IsGenerated) {
					output.WriteSpace();
					output.Write('[', TextTokenType.Operator);
					output.Write("generated", TextTokenType.Keyword);
					output.Write(']', TextTokenType.Operator);
				}
				output.WriteLine();
			}
			
			var memberMapping = new MemberMapping(method);
			foreach (ILNode node in ilMethod.Body) {
				node.WriteTo(output, memberMapping);
				if (!node.WritesNewLine)
					output.WriteLine();
			}
			output.AddDebugSymbols(memberMapping);
			EndKeywordBlock(output);
		}
예제 #8
0
 public static void AssignNamesToVariables(IEnumerable<string> existingNames, IEnumerable<ILVariable> variables, ILBlock methodBody)
 {
     NameVariables nv = new NameVariables();
     nv.AddExistingNames(existingNames);
     foreach (ILVariable varDef in variables) {
         nv.AssignNameToVariable(varDef, methodBody.GetSelfAndChildrenRecursive<ILExpression>());
     }
 }
예제 #9
0
        public void Optimize(DecompilerContext context, ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None)
        {
            if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return;
            foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
                SplitToBasicBlocks(block);
            }

            OptimizeShortCircuits(method);

            if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return;
            foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
                ControlFlowGraph graph;
                graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand);
                graph.ComputeDominance(context.CancellationToken);
                graph.ComputeDominanceFrontier();
                block.Body = FindLoops(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint, false);
            }

            if (abortBeforeStep == ILAstOptimizationStep.FindConditions) return;
            foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
                ControlFlowGraph graph;
                graph = BuildGraph(block.Body, (ILLabel)block.EntryGoto.Operand);
                // TODO: Fix
                if (graph == null)
                    continue;
                graph.ComputeDominance(context.CancellationToken);
                graph.ComputeDominanceFrontier();
                block.Body = FindConditions(new HashSet<ControlFlowNode>(graph.Nodes.Skip(3)), graph.EntryPoint);
            }

            if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return;
            FlattenBasicBlocks(method);

            if (abortBeforeStep == ILAstOptimizationStep.SimpleGotoRemoval) return;
            SimpleGotoRemoval(method);

            if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return;
            RemoveDeadLabels(method);

            if (abortBeforeStep == ILAstOptimizationStep.HandleArrayInitializers) return;
            ArrayInitializers.Transform(method);

            if (abortBeforeStep == ILAstOptimizationStep.TypeInference) return;
            TypeAnalysis.Run(context, method);
        }
예제 #10
0
		public static void RemoveRedundantCode(ILBlock method)
		{
			// Remove dead lables and nops
			HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(method.GetSelfAndChildrenRecursive<ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()));
			foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
				block.Body = block.Body.Where(n => !n.Match(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList();
			}
			
			// Remove redundant continue
			foreach(ILWhileLoop loop in method.GetSelfAndChildrenRecursive<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.GetSelfAndChildrenRecursive<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.Where(cb => cb.Values == null).SingleOrDefault();
				// 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
			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);
			}
		}
예제 #11
0
        public void RemoveGotos(ILBlock method)
        {
            // Build the navigation data
            parent[method] = null;
            foreach (ILNode node in method.GetSelfAndChildrenRecursive<ILNode>())
            {
                ILNode previousChild = null;
                foreach (ILNode child in node.GetChildren())
                {
                    ILExpression e = child as ILExpression;
                    if (e != null && (e.Operand is ILValue || e.Operand is ILVariable)) continue; // This should fix alot of issues
                     if (child is ILValue || child is ILVariable) continue; // we want to skip these.
                    // Added them as nodes so I don't have to dick with them latter with another AST
                    if (parent.ContainsKey(child))
                    { // this throws on one single file and I don't know why the hell it does
                        // its on obj_screen_Step_2  not sure why but its on an expression, so I am putting 
                        // a hack to skip expressions that don't have any gotos in it.  Meh
                        // debug, where the f**k is it
                        var nodes = parent.Keys.Where(x => x == 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;
                foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive<ILExpression>(e => e.Code == GMCode.B))
                {
                    modified |= TrySimplifyGoto(gotoExpr);
                }
            } while (modified);

            RemoveRedundantCode(method);
        }
예제 #12
0
		public static void RemoveRedundantCode(ILBlock method)
		{
			// Remove dead lables and nops
			HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(method.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.GetBranchTargets()));
			foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
				block.Body = block.Body.Where(n => !n.Match(ILCode.Nop) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList();
			}
			
			// Remove redundant continue
			foreach(ILWhileLoop loop in method.GetSelfAndChildrenRecursive<ILWhileLoop>()) {
				var body = loop.BodyBlock.Body;
				if (body.Count > 0 && body.Last().Match(ILCode.LoopContinue)) {
					body.RemoveAt(body.Count - 1);
				}
			}
			
			// Remove redundant return
			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);
			}
		}
예제 #13
0
		public void RemoveGotos(ILBlock method)
		{
			// Build the navigation data
			parent[method] = null;
			foreach (ILNode node in method.GetSelfAndChildrenRecursive<ILNode>()) {
				ILNode previousChild = null;
				foreach (ILNode child in node.GetChildren()) {
					Debug.Assert(!parent.ContainsKey(child));
					parent[child] = node;
					if (previousChild != null)
						nextSibling[previousChild] = child;
					previousChild = child;
				}
				if (previousChild != null)
					nextSibling[previousChild] = null;
			}
			
			// Simplify gotos
			foreach (ILExpression gotoExpr in method.GetSelfAndChildrenRecursive<ILExpression>().Where(e => e.Code == ILCode.Br || e.Code == ILCode.Leave)) {
				TrySimplifyGoto(gotoExpr);
			}
			
			RemoveRedundantCode(method);
		}
예제 #14
0
        public void Initialize(DecompilerContext context, ILBlock method)
        {
            this.labelGlobalRefCount.Clear();
            this.labelToBasicBlock.Clear();
            this.context = context;
            this.corLib = context.CurrentMethod.Module.CorLibTypes;

            foreach (var e in method.GetSelfAndChildrenRecursive<ILExpression>(List_ILExpression, e => e.IsBranch())) {
                foreach (var target in e.GetBranchTargets())
                    labelGlobalRefCount[target] = labelGlobalRefCount.GetOrDefault(target) + 1;
            }
            foreach(ILBasicBlock bb in method.GetSelfAndChildrenRecursive<ILBasicBlock>(List_ILBasicBlock)) {
                int index = 0;
                for (;;) {
                    var node = bb.GetNext(ref index);
                    if (node == null)
                        break;
                    var label = node as ILLabel;
                    if (label == null)
                        continue;
                    labelToBasicBlock[label] = bb;
                }
            }
        }
예제 #15
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;
		}
예제 #16
0
		public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters)
		{
			if (methodDef.Body == null) return null;
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILBlock ilMethod = new ILBlock();
			ILAstBuilder astBuilder = new ILAstBuilder();
			ilMethod.Body = astBuilder.Build(methodDef, true);
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILAstOptimizer bodyGraph = new ILAstOptimizer();
			bodyGraph.Optimize(context, ilMethod);
			context.CancellationToken.ThrowIfCancellationRequested();
			
			var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
				.Where(v => v != null && !v.IsParameter).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.CancellationToken.ThrowIfCancellationRequested();
			Ast.BlockStatement astBlock = TransformBlock(ilMethod);
			CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
			
			Statement insertionPoint = astBlock.Statements.FirstOrDefault();
			foreach (ILVariable v in localVariablesToDefine) {
				var newVarDecl = new VariableDeclarationStatement(AstBuilder.ConvertType(v.Type), v.Name);
				astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
			}
			
			return astBlock;
		}
예제 #17
0
파일: GotoRemoval.cs 프로젝트: n017/dnSpy
        public static void RemoveRedundantCode(ILBlock method, DecompilerContext context)
        {
            // Remove dead lables and nops
            HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(method.GetSelfAndChildrenRecursive<ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()));
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
                var newBody = new List<ILNode>(block.Body.Count);
                for (int i = 0; i < block.Body.Count; i++) {
                    var node = block.Body[i];
                    if (node.Match(ILCode.Nop))
                        Utils.NopMergeILRanges(block, newBody, i);
                    else if (node is ILLabel && !liveLabels.Contains((ILLabel)node))
                        Utils.LabelMergeILRanges(block, newBody, i);
                    else
                        newBody.Add(node);
                }
                block.Body = newBody;
            }

            // Remove redundant continue
            foreach(ILWhileLoop loop in method.GetSelfAndChildrenRecursive<ILWhileLoop>()) {
                var body = loop.BodyBlock.Body;
                if (body.Count > 0 && body.Last().Match(ILCode.LoopContinue)) {
                    body[body.Count - 1].AddSelfAndChildrenRecursiveILRanges(loop.EndILRanges);
                    body.RemoveAt(body.Count - 1);
                }
            }

            // Remove redundant break at the end of case
            // Remove redundant case blocks altogether
            foreach(ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive<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))
                        {
                            var prev = ilCase.Body[count - 2];
                            ilCase.Body[count - 1].AddSelfAndChildrenRecursiveILRanges(prev.EndILRanges);
                            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))) {
                    for (int i = ilSwitch.CaseBlocks.Count - 1; i >= 0; i--) {
                        var caseBlock = ilSwitch.CaseBlocks[i];
                        if (caseBlock.Body.Count != 1 || !caseBlock.Body.Single().Match(ILCode.LoopOrSwitchBreak))
                            continue;
                        caseBlock.Body[0].AddSelfAndChildrenRecursiveILRanges(ilSwitch.EndILRanges);
                        ilSwitch.CaseBlocks.RemoveAt(i);
                    }
                }
            }

            // 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[method.Body.Count - 1].AddSelfAndChildrenRecursiveILRanges(method.EndILRanges);
                method.Body.RemoveAt(method.Body.Count - 1);
            }

            // Remove unreachable return statements
            bool modified = false;
            foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>()) {
                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[i + 1].AddSelfAndChildrenRecursiveILRanges(block.EndILRanges);
                        block.Body.RemoveAt(i+1);
                    } else {
                        i++;
                    }
                }
            }
            if (modified) {
                // More removals might be possible
                var gr = context.Cache.GetGotoRemoval();
                try {
                    gr.RemoveGotos(method);
                }
                finally {
                    context.Cache.Return(gr);
                }
            }
        }
예제 #18
0
		Dictionary<int, Action<XamlContext, XElement>> ExtractConnectionId(XamlContext ctx, MethodDef method) {
			var context = new DecompilerContext(method.Module) {
				CurrentType = method.DeclaringType,
				CurrentMethod = method,
				CancellationToken = ctx.CancellationToken
			};
			var body = new ILBlock(new ILAstBuilder().Build(method, true, context));
			new ILAstOptimizer().Optimize(context, body);

			var sw = body.GetSelfAndChildrenRecursive<ILSwitch>().FirstOrDefault();
			if (sw == null)
				return null;

			var connIds = new Dictionary<int, Action<XamlContext, XElement>>();
			foreach (var cas in sw.CaseBlocks) {
				if (cas.Values == null)
					continue;

				Action<XamlContext, XElement> cb = null;
				foreach (var node in cas.Body) {
					var expr = node as ILExpression;
					if (expr == null)
						continue;

					switch (expr.Code) {
						case ILCode.Stfld:
							cb += new FieldAssignment { FieldName = ((IField)expr.Operand).Name }.Callback;
							break;

						case ILCode.Call:
						case ILCode.Callvirt:
							var operand = (IMethod)expr.Operand;
							if (operand.Name == "AddHandler" && operand.DeclaringType.FullName == "System.Windows.UIElement") {
								// Attached event
								var re = expr.Arguments[1];
								var ctor = expr.Arguments[2];
								var reField = re.Operand as IField;

								if (re.Code != ILCode.Ldsfld || ctor.Code != ILCode.Newobj ||
								    ctor.Arguments.Count != 2 || ctor.Arguments[1].Code != ILCode.Ldftn) {
									cb += new Error { Msg = "Attached event '" + reField.Name + "'." }.Callback;
									break;
								}
								var handler = (IMethod)ctor.Arguments[1].Operand;
								string evName = reField.Name;
								if (evName.EndsWith("Event"))
									evName = evName.Substring(0, evName.Length - 5);

								cb += new EventAttachment {
									AttachedType = reField.DeclaringType.ResolveTypeDefThrow(),
									EventName = evName,
									MethodName = handler.Name
								}.Callback;
							}
							else {
								// CLR event
								var add = operand.ResolveMethodDefThrow();
								var ev = add.DeclaringType.Events.FirstOrDefault(e => e.AddMethod == add);

								var ctor = expr.Arguments[1];
								if (ev == null || ctor.Code != ILCode.Newobj ||
								    ctor.Arguments.Count != 2 || ctor.Arguments[1].Code != ILCode.Ldftn) {
									cb += new Error { Msg = "Attached event '" + add.Name + "'." }.Callback;
									break;
								}
								var handler = (IMethod)ctor.Arguments[1].Operand;

								cb += new EventAttachment {
									EventName = ev.Name,
									MethodName = handler.Name
								}.Callback;
							}
							break;
					}
				}

				if (cb != null) {
					foreach (var id in cas.Values)
						connIds[id] = cb;
				}
			}

			return connIds.Count == 0 ? null : connIds;
		}
예제 #19
0
 void UpdateLabelRefCounts(ILBlock method)
 {
     labelRefCount = new Dictionary<ILLabel, int>();
     foreach(ILLabel target in method.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.GetBranchTargets())) {
         if (!labelRefCount.ContainsKey(target))
             labelRefCount[target] = 0;
         labelRefCount[target]++;
     }
 }
예제 #20
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:
                        case ILCode.Cle:
                        case ILCode.Cle_Un:
                        case ILCode.Cge:
                        case ILCode.Cge_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);
            }
        }
예제 #21
0
 void SimpleGotoRemoval(ILBlock ast)
 {
     // TODO: Assign IL ranges from br to something else
     var blocks = ast.GetSelfAndChildrenRecursive<ILBlock>().ToList();
     foreach(ILBlock block in blocks) {
         for (int i = 0; i < block.Body.Count; i++) {
             ILExpression expr = block.Body[i] as ILExpression;
             // Uncoditional branch
             if (expr != null && (expr.OpCode == OpCodes.Br || expr.OpCode == OpCodes.Br_S)) {
                 // Check that branch is followed by its label (allow multiple labels)
                 for (int j = i + 1; j < block.Body.Count; j++) {
                     ILLabel label = block.Body[j] as ILLabel;
                     if (label == null)
                         break;  // Can not optimize
                     if (expr.Operand == label) {
                         block.Body.RemoveAt(i);
                         break;  // Branch removed
                     }
                 }
             }
         }
     }
 }
예제 #22
0
        /*

        public enum ShortCircuitOperator
        {
            LeftAndRight,
            LeftOrRight,
            NotLeftAndRight,
            NotLeftOrRight,
        }

        static bool TryOptimizeShortCircuit(Node head)
        {
            if ((head is BasicBlock) &&
                (head as BasicBlock).BranchBasicBlock != null &&
                (head as BasicBlock).FallThroughBasicBlock != null) {
                head.Parent.MergeChilds<SimpleBranch>(head);
                return true;
            }

            Branch top = head as Branch;
            if (top == null) return false;

            Branch left = head.FloatUpToNeighbours(top.TrueSuccessor) as Branch;
            Branch right = head.FloatUpToNeighbours(top.FalseSuccessor) as Branch;

            // A & B
            if (left != null &&
                left.Predecessors.Count == 1 &&
                left.FalseSuccessor == top.FalseSuccessor) {
                ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left);
                scBranch.Operator = ShortCircuitOperator.LeftAndRight;
                return true;
            }

            // ~A | B
            if (left != null &&
                left.Predecessors.Count == 1 &&
                left.TrueSuccessor == top.FalseSuccessor) {
                ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left);
                scBranch.Operator = ShortCircuitOperator.NotLeftOrRight;
                return true;
            }

            // A | B
            if (right != null &&
                right.Predecessors.Count == 1 &&
                right.TrueSuccessor == top.TrueSuccessor) {
                ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right);
                scBranch.Operator = ShortCircuitOperator.LeftOrRight;
                return true;
            }

            // ~A & B
            if (right != null &&
                right.Predecessors.Count == 1 &&
                right.FalseSuccessor == top.TrueSuccessor) {
                ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right);
                scBranch.Operator = ShortCircuitOperator.NotLeftAndRight;
                return true;
            }

            return false;
        }

        */
        void OrderNodes(ILBlock ast)
        {
            // Order movable nodes
            var blocks = ast.GetSelfAndChildrenRecursive<ILBlock>().Where(b => !(b is ILMoveableBlock)).ToList();
            ILMoveableBlock first = new ILMoveableBlock() { OriginalOrder = -1 };
            foreach(ILBlock block in blocks) {
                block.Body = block.Body.OrderBy(n => (n.GetSelfAndChildrenRecursive<ILMoveableBlock>().FirstOrDefault() ?? first).OriginalOrder).ToList();
            }
        }
예제 #23
0
        List <(IList <int> connIds, List <ILNode> nodes)> GetCaseBlocks(ILBlock method)
        {
            var list = new List <(IList <int>, List <ILNode>)>();
            var body = method.Body;

            if (body.Count == 0)
            {
                return(list);
            }

            var sw = method.GetSelfAndChildrenRecursive <ILSwitch>().FirstOrDefault();

            if (sw is not null)
            {
                foreach (var lbl in sw.CaseBlocks)
                {
                    if (lbl.Values is null)
                    {
                        continue;
                    }
                    list.Add((lbl.Values, lbl.Body));
                }
                return(list);
            }
            else
            {
                int pos = 0;
                for (;;)
                {
                    if (pos >= body.Count)
                    {
                        return(null);
                    }
                    var cond = body[pos] as ILCondition;
                    if (cond is null)
                    {
                        if (!body[pos].Match(ILCode.Stfld, out IField field, out var ldthis, out var ldci4) || !ldthis.MatchThis() || !ldci4.MatchLdcI4(1))
                        {
                            return(null);
                        }
                        return(list);
                    }
                    pos++;
                    if (cond.TrueBlock is null || cond.FalseBlock is null)
                    {
                        return(null);
                    }

                    bool isEq     = true;
                    var  condExpr = cond.Condition;
                    for (;;)
                    {
                        if (!condExpr.Match(ILCode.LogicNot, out ILExpression expr))
                        {
                            break;
                        }
                        isEq     = !isEq;
                        condExpr = expr;
                    }
                    if (condExpr.Code != ILCode.Ceq && condExpr.Code != ILCode.Cne)
                    {
                        return(null);
                    }
                    if (condExpr.Arguments.Count != 2)
                    {
                        return(null);
                    }
                    if (!condExpr.Arguments[0].Match(ILCode.Ldloc, out ILVariable v) || v.OriginalParameter?.Index != 1)
                    {
                        return(null);
                    }
                    if (!condExpr.Arguments[1].Match(ILCode.Ldc_I4, out int val))
                    {
                        return(null);
                    }
                    if (condExpr.Code == ILCode.Cne)
                    {
                        isEq ^= true;
                    }

                    if (isEq)
                    {
                        list.Add((new[] { val }, cond.TrueBlock.Body));
                        if (cond.FalseBlock.Body.Count != 0)
                        {
                            body = cond.FalseBlock.Body;
                            pos  = 0;
                        }
                    }
                    else
                    {
                        if (cond.FalseBlock.Body.Count != 0)
                        {
                            list.Add((new[] { val }, cond.FalseBlock.Body));
                            if (cond.TrueBlock.Body.Count != 0)
                            {
                                body = cond.TrueBlock.Body;
                                pos  = 0;
                            }
                        }
                        else
                        {
                            list.Add((new[] { val }, body.Skip(pos).ToList()));
                            return(list);
                        }
                    }
                }
            }
        }
예제 #24
0
        public override void Decompile(MethodDef method, IDecompilerOutput output, DecompilationContext ctx)
        {
            WriteCommentBegin(output, true);
            output.Write("Method: ", BoxedTextColor.Comment);
            output.Write(IdentifierEscaper.Escape(method.FullName), method, DecompilerReferenceFlags.Definition, BoxedTextColor.Comment);
            WriteCommentEnd(output, true);
            output.WriteLine();

            if (!method.HasBody)
            {
                return;
            }

            var bodyInfo = StartKeywordBlock(output, ".body", method);

            ILAstBuilder      astBuilder = new ILAstBuilder();
            ILBlock           ilMethod   = new ILBlock(CodeBracesRangeFlags.MethodBraces);
            DecompilerContext context    = new DecompilerContext(settingsVersion, method.Module, MetadataTextColorProvider)
            {
                CurrentType      = method.DeclaringType,
                CurrentMethod    = method,
                CalculateILSpans = ctx.CalculateILSpans,
            };

            ilMethod.Body = astBuilder.Build(method, inlineVariables, context);

            var                  stateMachineKind = StateMachineKind.None;
            MethodDef?           inlinedMethod    = null;
            AsyncMethodDebugInfo?asyncInfo        = null;
            string?              compilerName     = null;

            if (!(abortBeforeStep is null))
            {
                var optimizer = new ILAstOptimizer();
                optimizer.Optimize(context, ilMethod, out stateMachineKind, out inlinedMethod, out asyncInfo, abortBeforeStep.Value);
                compilerName = optimizer.CompilerName;
            }

            if (context.CurrentMethodIsYieldReturn)
            {
                output.Write("yield", BoxedTextColor.Keyword);
                output.Write(" ", BoxedTextColor.Text);
                output.WriteLine("return", BoxedTextColor.Keyword);
            }
            if (context.CurrentMethodIsAsync)
            {
                output.Write("async", BoxedTextColor.Keyword);
                output.Write("/", BoxedTextColor.Punctuation);
                output.WriteLine("await", BoxedTextColor.Keyword);
            }

            var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable)
                               .Where(v => !(v is null) && !v.IsParameter).Distinct();

            foreach (ILVariable v in allVariables)
            {
                output.Write(IdentifierEscaper.Escape(v.Name), v.GetTextReferenceObject(), DecompilerReferenceFlags.Local | DecompilerReferenceFlags.Definition, v.IsParameter ? BoxedTextColor.Parameter : BoxedTextColor.Local);
                if (!(v.Type is null))
                {
                    output.Write(" ", BoxedTextColor.Text);
                    output.Write(":", BoxedTextColor.Punctuation);
                    output.Write(" ", BoxedTextColor.Text);
                    if (v.IsPinned)
                    {
                        output.Write("pinned", BoxedTextColor.Keyword);
                        output.Write(" ", BoxedTextColor.Text);
                    }
                    v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
                }
                if (v.GeneratedByDecompiler)
                {
                    output.Write(" ", BoxedTextColor.Text);
                    var start = output.NextPosition;
                    output.Write("[", BoxedTextColor.Punctuation);
                    output.Write("generated", BoxedTextColor.Keyword);
                    var end = output.NextPosition;
                    output.Write("]", BoxedTextColor.Punctuation);
                    output.AddBracePair(new TextSpan(start, 1), new TextSpan(end, 1), CodeBracesRangeFlags.SquareBrackets);
                }
                output.WriteLine();
            }

            var localVariables = new HashSet <ILVariable>(GetVariables(ilMethod));
            var builder        = new MethodDebugInfoBuilder(settingsVersion, stateMachineKind, inlinedMethod ?? method, !(inlinedMethod is null) ? method : null, CreateSourceLocals(localVariables), CreateSourceParameters(localVariables), asyncInfo);

            builder.CompilerName = compilerName;
            foreach (ILNode node in ilMethod.Body)
            {
                node.WriteTo(output, builder);
                if (!node.WritesNewLine)
                {
                    output.WriteLine();
                }
            }
            output.AddDebugInfo(builder.Create());
            EndKeywordBlock(output, bodyInfo, CodeBracesRangeFlags.MethodBraces, addLineSeparator: true);
        }
예제 #25
0
        bool BeforeConditionsDebugSainityCheck(ILBlock method)
        {
            HashSet <ILBasicBlock>   badblocks = new HashSet <ILBasicBlock>();
            Dictionary <GMCode, int> badCodes  = new Dictionary <GMCode, int>();

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                foreach (ILBasicBlock bb in block.GetSelfAndChildrenRecursive <ILBasicBlock>())
                {
                    foreach (ILExpression expr in bb.GetSelfAndChildrenRecursive <ILExpression>())
                    {
                        if (expr.Operand is UnresolvedVar)
                        {
                            if (!badCodes.ContainsKey(expr.Code))
                            {
                                badCodes[expr.Code] = 0;
                            }
                            badCodes[expr.Code]++;
                            badblocks.Add(bb);
                        }
                        else if (expr.Code == GMCode.Dup || expr.Code == GMCode.Push || expr.Code == GMCode.Popz || expr.Code == GMCode.CallUnresolved)
                        {
                            if (!badCodes.ContainsKey(expr.Code))
                            {
                                badCodes[expr.Code] = 0;
                            }
                            badCodes[expr.Code]++;
                            badblocks.Add(bb);
                        }
                        else if ((expr.Code == GMCode.Bt || expr.Code == GMCode.Bf) && expr.Arguments.Count == 0)
                        {
                            if (!badCodes.ContainsKey(expr.Code))
                            {
                                badCodes[expr.Code] = 0;
                            }
                            badCodes[expr.Code]++;
                            badblocks.Add(bb);
                        }
                    }
                }
            }

            if (badblocks.Count > 0)
            {
                ControlFlowLabelMap map       = new ControlFlowLabelMap(method, error);
                ILBlock             badmethod = new ILBlock();
                error.DebugSave(method, "bad_block_dump.txt");
                //  HashSet<ILBasicBlock> callies = new HashSet<ILBasicBlock>();
                try
                {
                    foreach (var bb in badblocks.ToList())
                    {
                        badblocks.UnionWith(bb.GetChildren()
                                            .OfType <ILExpression>()
                                            .Where(x => x.Operand is ILLabel)
                                            .Select(x => x.Operand as ILLabel)
                                            .Select(x => map.LabelToBasicBlock(x)));

                        var p = map.LabelToParrents(bb.EntryLabel());
                        p.Add(bb.GotoLabel());

                        //  Debug.Assert(p.Count == 1);
                        badblocks.UnionWith(p.Select(x => map.LabelToBasicBlock(x)));
                        //  badblocks.Add(map.LabelToBasicBlock(p[0]));
                    }
                    badmethod.Body = badblocks.OrderBy(b => b.GotoLabelName()).Select(b => (ILNode)b).ToList();
                } catch (Exception e)
                {
                    // we cannot build a map, so just copy bad blocks
                    error.Error("Cannot build a map of the method, probery missing Label Exception: {0}", e.Message);
                    badmethod.Body = method.Body;
                }


                string dfilename = error.MakeDebugFileName("bad_blocks.txt");

                using (StreamWriter sw = new StreamWriter(dfilename))
                {
                    sw.WriteLine("Time : {0}", DateTime.Now);
                    sw.WriteLine("Filename: {0}", dfilename);
                    sw.WriteLine("Code File: {0}", error.CodeName);
                    foreach (var kp in badCodes)
                    {
                        sw.WriteLine("Code: \"{0}\" Count: {1}", kp.Key, kp.Value);
                    }
                    sw.WriteLine();
                    sw.WriteLine(badmethod.ToString());
                }
                error.Message("Saved '{0}'", dfilename);
                error.FatalError("Before graph sanity check failed, look at bad_block_dump.txt");
                return(true);
            }
            return(false);
        }
예제 #26
0
        public ILBlock Build(ILBlock method, Dictionary <string, ILVariable> locals, ErrorContext error)
        {
            if (method == null)
            {
                throw new ArgumentNullException("method");
            }
            if (error == null)
            {
                throw new ArgumentNullException("error");
            }
            if (locals == null)
            {
                throw new ArgumentNullException("locals");
            }
            this.error  = error;
            this.locals = locals;
            error.CheckDebugThenSave(method, "raw.txt", true);
            // Not sure I need this pass now
            // WE doo now, This converts popenv to either breaks or branchs.   This is needed
            // as if you return from a pushenv, a popenv break is called
            FixAllPushesAndPopenv(method.Body); // makes sure all pushes have no operands and are all expressions for latter matches


            Optimize.RemoveRedundantCode(method);

            foreach (var block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                Optimize.SplitToBasicBlocks(block, true);
            }
            error.CheckDebugThenSave(method, "basic_blocks.txt");

            bool modified   = false;
            bool debug_once = true;

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                do
                {
                    modified = false;

                    do     // Does all the internal things to a blocks for other passes to be easyer
                    {
                        modified  = false;
                        modified |= block.RunOptimization(MatchVariablePush);      // checks pushes for instance or indexs for vars
                        modified |= block.RunOptimization(SimpleAssignments);
                        modified |= block.RunOptimization(AssignValueTo);
                        modified |= block.RunOptimization(ComplexAssignments);    // basicly self increment, this SHOULDN'T cross block boundrys
                        modified |= block.RunOptimization(SimplifyBranches);      // Any resolved pushes are put into a branch argument
                        modified |= block.RunOptimization(CombineCall);           // Any resolved pushes are put into a branch argument
                        modified |= block.RunOptimization(CombineExpressions);
                        modified |= block.RunOptimization(FixTempReturnValues);
                    } while (modified);
                    if (Context.Debug)
                    {
                        if (debug_once)
                        {
                            error.CheckDebugThenSave(method, "basic_blocks_resolved.txt"); debug_once = false;
                        }
                    }



                    //  modified |= block.RunOptimization(new SimpleControlFlow(method,error).DetectSwitch);
                    //       modified |= block.RunOptimization(new SimpleControlFlow(method, error).DetectSwitchAndConvertToBranches);
                    modified |= block.RunOptimization(new SimpleControlFlow(method, error).DetectSwitch_GenerateSwitch);

                    modified |= block.RunOptimization(MultiDimenionArray);

                    modified |= block.RunOptimization(Optimize.SimplifyBoolTypes);
                    modified |= block.RunOptimization(Optimize.SimplifyLogicNot);

                    modified |= block.RunOptimization(PushEnviromentFix); // match all with's with expressions
                    modified |= block.RunOptimization(new SimpleControlFlow(method, error).SimplifyShortCircuit);
                    modified |= block.RunOptimization(new SimpleControlFlow(method, error).SimplifyTernaryOperator);
                    modified |= block.RunOptimization(new SimpleControlFlow(method, error).MatchRepeatStructure);



                    modified |= block.RunOptimization(new SimpleControlFlow(method, error).JoinBasicBlocks);
                    // somewhere, so bug, is leaving an empty block, I think because of switches
                    // It screws up the flatten block check for some reason
                    modified |= block.RunOptimization(new SimpleControlFlow(method, error).RemoveRedundentBlocks);
                    // want to run this at the end to fix return stuff
                } while (modified);
            }
            error.CheckDebugThenSave(method, "before_loops.txt");
            if (BeforeConditionsDebugSainityCheck(method))
            {
                return(null);                                           // sainity check, evething must be ready for this
            }
            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                new LoopsAndConditions(error).FindLoops(block);
            }

            error.CheckDebugThenSave(method, "before_conditions.txt");

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                new LoopsAndConditions(error).FindConditions(block);
            }

            error.CheckDebugThenSave(method, "before_flatten.txt");
            FlattenBasicBlocks(method);
            error.CheckDebugThenSave(method, "before_gotos.txt");

            Optimize.RemoveRedundantCode(method);
            new GotoRemoval().RemoveGotos(method);

            error.CheckDebugThenSave(method, "before_if.txt");

            // This is cleaned up in ILSpy latter when its converted to another ast structure, but I clean it up here
            // cause I don't convert it and mabye not converting all bt's to bf's dosn't
            //   FixIfStatements(method);



            Optimize.RemoveRedundantCode(method);
            new GotoRemoval().RemoveGotos(method);

            error.CheckDebugThenSave(method, "final.txt");
            if (AfterLoopsAndConditions(method))
            {
                return(null);                                 // another sanity check
            }
            return(method);
        }
예제 #27
0
		public override void Decompile(MethodDef method, IDecompilerOutput output, DecompilationContext ctx) {
			WriteCommentBegin(output, true);
			output.Write("Method: ", BoxedTextColor.Comment);
			output.Write(IdentifierEscaper.Escape(method.FullName), method, DecompilerReferenceFlags.Definition, BoxedTextColor.Comment);
			WriteCommentEnd(output, true);
			output.WriteLine();

			if (!method.HasBody) {
				return;
			}

			StartKeywordBlock(output, ".body", method);

			ILAstBuilder astBuilder = new ILAstBuilder();
			ILBlock ilMethod = new ILBlock();
			DecompilerContext context = new DecompilerContext(method.Module, MetadataTextColorProvider) { CurrentType = method.DeclaringType, CurrentMethod = method };
			ilMethod.Body = astBuilder.Build(method, inlineVariables, context);

			if (abortBeforeStep != null) {
				new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value);
			}

			if (context.CurrentMethodIsAsync) {
				output.Write("async", BoxedTextColor.Keyword);
				output.Write("/", BoxedTextColor.Punctuation);
				output.WriteLine("await", BoxedTextColor.Keyword);
			}

			var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
				.Where(v => v != null && !v.IsParameter).Distinct();
			foreach (ILVariable v in allVariables) {
				output.Write(IdentifierEscaper.Escape(v.Name), v, DecompilerReferenceFlags.Local | DecompilerReferenceFlags.Definition, v.IsParameter ? BoxedTextColor.Parameter : BoxedTextColor.Local);
				if (v.Type != null) {
					output.Write(" ", BoxedTextColor.Text);
					output.Write(":", BoxedTextColor.Punctuation);
					output.Write(" ", BoxedTextColor.Text);
					if (v.IsPinned) {
						output.Write("pinned", BoxedTextColor.Keyword);
						output.Write(" ", BoxedTextColor.Text);
					}
					v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
				}
				if (v.GeneratedByDecompiler) {
					output.Write(" ", BoxedTextColor.Text);
					output.Write("[", BoxedTextColor.Punctuation);
					output.Write("generated", BoxedTextColor.Keyword);
					output.Write("]", BoxedTextColor.Punctuation);
				}
				output.WriteLine();
			}

			var builder = new MethodDebugInfoBuilder(method);
			foreach (ILNode node in ilMethod.Body) {
				node.WriteTo(output, builder);
				if (!node.WritesNewLine)
					output.WriteLine();
			}
			output.AddDebugInfo(builder.Create());
			EndKeywordBlock(output);
		}
예제 #28
0
		/// <summary>
		/// Clears the type inference data on the method.
		/// </summary>
		public static void Reset(ILBlock method, List<ILExpression> list_ILExpression)
		{
			foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>(list_ILExpression)) {
				expr.InferredType = null;
				expr.ExpectedType = null;
				ILVariable v = expr.Operand as ILVariable;
				if (v != null && v.GeneratedByDecompiler)
					v.Type = null;
			}
		}
예제 #29
0
        public override void Decompile(MethodDef method, IDecompilerOutput output, DecompilationContext ctx)
        {
            WriteCommentBegin(output, true);
            output.Write("Method: ", BoxedTextColor.Comment);
            output.Write(IdentifierEscaper.Escape(method.FullName), method, DecompilerReferenceFlags.Definition, BoxedTextColor.Comment);
            WriteCommentEnd(output, true);
            output.WriteLine();

            if (!method.HasBody)
            {
                return;
            }

            var bodyInfo = StartKeywordBlock(output, ".body", method);

            ILAstBuilder      astBuilder = new ILAstBuilder();
            ILBlock           ilMethod   = new ILBlock(CodeBracesRangeFlags.MethodBraces);
            DecompilerContext context    = new DecompilerContext(method.Module, MetadataTextColorProvider)
            {
                CurrentType       = method.DeclaringType,
                CurrentMethod     = method,
                CalculateBinSpans = ctx.CalculateBinSpans,
            };

            ilMethod.Body = astBuilder.Build(method, inlineVariables, context);

            if (abortBeforeStep != null)
            {
                new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value);
            }

            if (context.CurrentMethodIsYieldReturn)
            {
                output.Write("yield", BoxedTextColor.Keyword);
                output.Write(" ", BoxedTextColor.Text);
                output.WriteLine("return", BoxedTextColor.Keyword);
            }
            if (context.CurrentMethodIsAsync)
            {
                output.Write("async", BoxedTextColor.Keyword);
                output.Write("/", BoxedTextColor.Punctuation);
                output.WriteLine("await", BoxedTextColor.Keyword);
            }

            var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable)
                               .Where(v => v != null && !v.IsParameter).Distinct();

            foreach (ILVariable v in allVariables)
            {
                output.Write(IdentifierEscaper.Escape(v.Name), (object)v.OriginalVariable ?? (object)v.OriginalParameter ?? v.Id, DecompilerReferenceFlags.Local | DecompilerReferenceFlags.Definition, v.IsParameter ? BoxedTextColor.Parameter : BoxedTextColor.Local);
                if (v.Type != null)
                {
                    output.Write(" ", BoxedTextColor.Text);
                    output.Write(":", BoxedTextColor.Punctuation);
                    output.Write(" ", BoxedTextColor.Text);
                    if (v.IsPinned)
                    {
                        output.Write("pinned", BoxedTextColor.Keyword);
                        output.Write(" ", BoxedTextColor.Text);
                    }
                    v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
                }
                if (v.GeneratedByDecompiler)
                {
                    output.Write(" ", BoxedTextColor.Text);
                    var start = output.NextPosition;
                    output.Write("[", BoxedTextColor.Punctuation);
                    output.Write("generated", BoxedTextColor.Keyword);
                    var end = output.NextPosition;
                    output.Write("]", BoxedTextColor.Punctuation);
                    output.AddBracePair(new TextSpan(start, 1), new TextSpan(end, 1), CodeBracesRangeFlags.SquareBrackets);
                }
                output.WriteLine();
            }

            var builder = new MethodDebugInfoBuilder(method);

            foreach (ILNode node in ilMethod.Body)
            {
                node.WriteTo(output, builder);
                if (!node.WritesNewLine)
                {
                    output.WriteLine();
                }
            }
            output.AddDebugInfo(builder.Create());
            EndKeywordBlock(output, bodyInfo, CodeBracesRangeFlags.MethodBraces, addLineSeparator: true);
        }
예제 #30
0
        void OptimizeShortCircuits(ILBlock method)
        {
            AnalyseLabels(method);

            foreach(ILBlock block in method.GetSelfAndChildrenRecursive<ILBlock>().ToList()) {
                bool modified;
                do {
                    modified = false;
                    for (int i = 0; i < block.Body.Count;) {
                        if (TrySimplifyShortCircuit(block.Body, (ILBasicBlock)block.Body[i])) {
                            modified = true;
                        } else {
                            i++;
                        }
                    }
                } while(modified);
            }
        }
예제 #31
0
        public static void RemoveRedundantCode(ILBlock method)
        {
            // Remove dead lables and nops and any popzs left
            HashSet <ILLabel> liveLabels = new HashSet <ILLabel>(method.GetSelfAndChildrenRecursive <ILExpression>(e => e.IsBranch()).SelectMany(e => e.GetBranchTargets()));

            foreach (ILBlock block in method.GetSelfAndChildrenRecursive <ILBlock>())
            {
                block.Body = block.Body.Where(n => !n.Match(GMCode.BadOp) && !(n is ILLabel && !liveLabels.Contains((ILLabel)n))).ToList();
            }

            // Remove redundant continue
            foreach (ILWhileLoop loop in method.GetSelfAndChildrenRecursive <ILWhileLoop>())
            {
                var body = loop.Body.Body;
                if (body.Count > 0 && body.Last().Match(GMCode.LoopContinue))
                {
                    body.RemoveAt(body.Count - 1);
                }
            }
            // Remove redundant continue
            foreach (ILWithStatement with in method.GetSelfAndChildrenRecursive <ILWithStatement>())
            {
                var body = with.Body.Body;
                if (body.Count > 0 && body.Last().Match(GMCode.LoopContinue))
                {
                    body.RemoveAt(body.Count - 1);
                }
            }
            // Remove redundant break at the end of case
            // Remove redundant case blocks altogether
            foreach (ILSwitch ilSwitch in method.GetSelfAndChildrenRecursive <ILSwitch>())
            {
                foreach (ILBlock ilCase in ilSwitch.Cases)
                {
                    Debug.Assert(ilCase.EntryGoto == null);

                    int count = ilCase.Body.Count;
                    if (count >= 2)
                    {
                        if (ilCase.Body[count - 2].IsUnconditionalControlFlow() &&
                            ilCase.Body[count - 1].Match(GMCode.LoopOrSwitchBreak))
                        {
                            ilCase.Body.RemoveAt(count - 1);
                        }
                    }
                }
                // fix case block


                var defaultCase = ilSwitch.Default ?? ilSwitch.Cases.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(GMCode.LoopOrSwitchBreak)))
                {
                    foreach (var c in ilSwitch.Cases.Where(b => b.Body.Count == 1 && b.Body.Single().Match(GMCode.LoopOrSwitchBreak)).ToList())
                    {
                        ilSwitch.Cases.Remove(c);
                    }
                }
            }

            // Remove redundant return at the end of method
            if (method.Body.Count > 0 && (method.Body.Last().Match(GMCode.Ret) || method.Body.Last().Match(GMCode.Exit)) && ((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.GetSelfAndChildrenRecursive <ILBlock>())
            {
                for (int i = 0; i < block.Body.Count - 1;)
                {
                    if (block.Body[i].IsUnconditionalControlFlow() && (block.Body[i + 1].Match(GMCode.Ret) || block.Body[i + 1].Match(GMCode.Exit)))
                    {
                        modified = true;
                        block.Body.RemoveAt(i + 1);
                    }
                    else
                    {
                        i++;
                    }
                }
            }
            // Remove empty falseBlocks
            foreach (ILCondition condition in method.GetSelfAndChildrenRecursive <ILCondition>().Where(x => x.FalseBlock != null && x.FalseBlock.Body.Count == 0))
            {
                condition.FalseBlock = null;
                modified             = true;
            }

            if (modified)
            {
                // More removals might be possible
                new GotoRemoval().RemoveGotos(method);
            }
        }
예제 #32
0
 void RemoveDeadLabels(ILBlock ast)
 {
     HashSet<ILLabel> liveLabels = new HashSet<ILLabel>(ast.GetSelfAndChildrenRecursive<ILExpression>().SelectMany(e => e.GetBranchTargets()));
     var blocks = ast.GetSelfAndChildrenRecursive<ILBlock>().ToList();
     foreach(ILBlock block in blocks) {
         for (int i = 0; i < block.Body.Count;) {
             ILLabel label = block.Body[i] as ILLabel;
             if (label != null && !liveLabels.Contains(label)) {
                 block.Body.RemoveAt(i);
             } else {
                 i++;
             }
         }
     }
 }
예제 #33
0
        public override void Decompile(MethodDef method, ITextOutput output, DecompilationContext ctx)
        {
            WriteCommentBegin(output, true);
            output.Write("Method: ", TextTokenKind.Comment);
            output.WriteDefinition(IdentifierEscaper.Escape(method.FullName), method, TextTokenKind.Comment, false);
            WriteCommentEnd(output, true);
            output.WriteLine();

            if (!method.HasBody)
            {
                return;
            }

            StartKeywordBlock(output, ".body", method);

            ILAstBuilder      astBuilder = new ILAstBuilder();
            ILBlock           ilMethod   = new ILBlock();
            DecompilerContext context    = new DecompilerContext(method.Module)
            {
                CurrentType = method.DeclaringType, CurrentMethod = method
            };

            ilMethod.Body = astBuilder.Build(method, inlineVariables, context);

            if (abortBeforeStep != null)
            {
                new ILAstOptimizer().Optimize(context, ilMethod, abortBeforeStep.Value);
            }

            if (context.CurrentMethodIsAsync)
            {
                output.Write("async", TextTokenKind.Keyword);
                output.Write("/", TextTokenKind.Operator);
                output.WriteLine("await", TextTokenKind.Keyword);
            }

            var allVariables = ilMethod.GetSelfAndChildrenRecursive <ILExpression>().Select(e => e.Operand as ILVariable)
                               .Where(v => v != null && !v.IsParameter).Distinct();

            foreach (ILVariable v in allVariables)
            {
                output.WriteDefinition(IdentifierEscaper.Escape(v.Name), v, v.IsParameter ? TextTokenKind.Parameter : TextTokenKind.Local);
                if (v.Type != null)
                {
                    output.WriteSpace();
                    output.Write(":", TextTokenKind.Operator);
                    output.WriteSpace();
                    if (v.IsPinned)
                    {
                        output.Write("pinned", TextTokenKind.Keyword);
                        output.WriteSpace();
                    }
                    v.Type.WriteTo(output, ILNameSyntax.ShortTypeName);
                }
                if (v.GeneratedByDecompiler)
                {
                    output.WriteSpace();
                    output.Write("[", TextTokenKind.Operator);
                    output.Write("generated", TextTokenKind.Keyword);
                    output.Write("]", TextTokenKind.Operator);
                }
                output.WriteLine();
            }

            var memberMapping = new MemberMapping(method);

            foreach (ILNode node in ilMethod.Body)
            {
                node.WriteTo(output, memberMapping);
                if (!node.WritesNewLine)
                {
                    output.WriteLine();
                }
            }
            output.AddDebugSymbols(memberMapping);
            EndKeywordBlock(output);
        }
예제 #34
0
		public BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters,
		                                       ConcurrentDictionary<int, IEnumerable<ILVariable>> localVariables)
		{
			if (methodDef.Body == null) return null;
			
			if (localVariables == null)
				throw new ArgumentException("localVariables must be instantiated");
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILBlock ilMethod = new ILBlock();
			ILAstBuilder astBuilder = new ILAstBuilder();
			ilMethod.Body = astBuilder.Build(methodDef, true);
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILAstOptimizer bodyGraph = new ILAstOptimizer();
			bodyGraph.Optimize(context, ilMethod);
			context.CancellationToken.ThrowIfCancellationRequested();
			
			var allVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
				.Where(v => v != null && !v.IsParameter).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.CancellationToken.ThrowIfCancellationRequested();
			Ast.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.AddOrUpdate(token, allVariables, (key, oldValue) => allVariables);
			
			return astBlock;
		}
예제 #35
0
        internal JSFunctionExpression TranslateMethodExpression(DecompilerContext context, MethodReference method, MethodDefinition methodDef)
        {
            var oldMethod = context.CurrentMethod;
            try {
                if (method == null)
                    throw new ArgumentNullException("method");
                if (methodDef == null)
                    throw new ArgumentNullException("methodDef");

                var methodInfo = TypeInfoProvider.GetMemberInformation<JSIL.Internal.MethodInfo>(methodDef);

                var identifier = new QualifiedMemberIdentifier(
                    methodInfo.DeclaringType.Identifier, methodInfo.Identifier
                );
                JSFunctionExpression function = null;

                if (FunctionCache.TryGetExpression(identifier, out function))
                    return function;

                if (methodInfo.IsExternal) {
                    FunctionCache.CreateNull(methodInfo, method, identifier);
                    return null;
                }

                var bodyDef = methodDef;
                if (methodInfo.IsFromProxy && methodInfo.Member.HasBody)
                    bodyDef = methodInfo.Member;

                var pr = new ProgressReporter();

                context.CurrentMethod = methodDef;
                if ((methodDef.Body.Instructions.Count > LargeMethodThreshold) && (this.DecompilingMethod != null))
                    this.DecompilingMethod(method.FullName, pr);

                ILBlock ilb;
                var decompiler = new ILAstBuilder();
                var optimizer = new ILAstOptimizer();

                try {
                    ilb = new ILBlock(decompiler.Build(bodyDef, true));
                    optimizer.Optimize(context, ilb);
                } catch (Exception exception) {
                    if (CouldNotDecompileMethod != null)
                        CouldNotDecompileMethod(bodyDef.FullName, exception);

                    FunctionCache.CreateNull(methodInfo, method, identifier);
                    pr.OnFinished();
                    return null;
                }

                var allVariables = ilb.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
                    .Where(v => v != null && !v.IsParameter).Distinct();

                foreach (var v in allVariables) {
                    if (ILBlockTranslator.IsIgnoredType(v.Type)) {
                        FunctionCache.CreateNull(methodInfo, method, identifier);
                        pr.OnFinished();
                        return null;
                    }
                }

                NameVariables.AssignNamesToVariables(context, decompiler.Parameters, allVariables, ilb);

                var translator = new ILBlockTranslator(
                    this, context, method, methodDef,
                    ilb, decompiler.Parameters, allVariables
                );
                var body = translator.Translate();

                if (body == null) {
                    FunctionCache.CreateNull(methodInfo, method, identifier);
                    pr.OnFinished();
                    return null;
                }

                var parameters = from p in translator.ParameterNames select translator.Variables[p];

                if (method.HasGenericParameters) {
                    var type = new TypeReference("System", "Type", context.CurrentModule.TypeSystem.Object.Module, context.CurrentModule.TypeSystem.Object.Scope);
                    parameters = (from gp in method.GenericParameters select new JSVariable(gp.Name, type, method)).Concat(parameters);
                }

                function = FunctionCache.Create(
                    methodInfo, methodDef, method, identifier,
                    translator, parameters, body
                );

                pr.OnFinished();
                return function;
            } finally {
                context.CurrentMethod = oldMethod;
            }
        }
예제 #36
0
        Dictionary <int, Action <XamlContext, XElement> > ExtractConnectionId(XamlContext ctx, MethodDef method)
        {
            var context = new DecompilerContext(method.Module)
            {
                CurrentType       = method.DeclaringType,
                CurrentMethod     = method,
                CancellationToken = ctx.CancellationToken
            };
            var body = new ILBlock(new ILAstBuilder().Build(method, true, context));

            new ILAstOptimizer().Optimize(context, body);

            var sw = body.GetSelfAndChildrenRecursive <ILSwitch>().FirstOrDefault();

            if (sw == null)
            {
                return(null);
            }

            var connIds = new Dictionary <int, Action <XamlContext, XElement> >();

            foreach (var cas in sw.CaseBlocks)
            {
                if (cas.Values == null)
                {
                    continue;
                }

                Action <XamlContext, XElement> cb = null;
                foreach (var node in cas.Body)
                {
                    var expr = node as ILExpression;
                    if (expr == null)
                    {
                        continue;
                    }

                    switch (expr.Code)
                    {
                    case ILCode.Stfld:
                        cb += new FieldAssignment {
                            FieldName = ((IField)expr.Operand).Name
                        }.Callback;
                        break;

                    case ILCode.Call:
                    case ILCode.Callvirt:
                        var operand = (IMethod)expr.Operand;
                        if (operand.Name == "AddHandler" && operand.DeclaringType.FullName == "System.Windows.UIElement")
                        {
                            // Attached event
                            var re      = expr.Arguments[1];
                            var ctor    = expr.Arguments[2];
                            var reField = re.Operand as IField;

                            if (re.Code != ILCode.Ldsfld || ctor.Code != ILCode.Newobj ||
                                ctor.Arguments.Count != 2 || ctor.Arguments[1].Code != ILCode.Ldftn)
                            {
                                cb += new Error {
                                    Msg = string.Format(dnSpy_BamlDecompiler_Resources.Error_AttachedEvent, reField.Name)
                                }.Callback;
                                break;
                            }
                            var    handler = (IMethod)ctor.Arguments[1].Operand;
                            string evName  = reField.Name;
                            if (evName.EndsWith("Event"))
                            {
                                evName = evName.Substring(0, evName.Length - 5);
                            }

                            cb += new EventAttachment {
                                AttachedType = reField.DeclaringType.ResolveTypeDefThrow(),
                                EventName    = evName,
                                MethodName   = handler.Name
                            }.Callback;
                        }
                        else
                        {
                            // CLR event
                            var add = operand.ResolveMethodDefThrow();
                            var ev  = add.DeclaringType.Events.FirstOrDefault(e => e.AddMethod == add);

                            var ctor = expr.Arguments[1];
                            if (ev == null || ctor.Code != ILCode.Newobj ||
                                ctor.Arguments.Count != 2 || ctor.Arguments[1].Code != ILCode.Ldftn)
                            {
                                cb += new Error {
                                    Msg = string.Format(dnSpy_BamlDecompiler_Resources.Error_AttachedEvent, add.Name)
                                }.Callback;
                                break;
                            }
                            var handler = (IMethod)ctor.Arguments[1].Operand;

                            cb += new EventAttachment {
                                EventName  = ev.Name,
                                MethodName = handler.Name
                            }.Callback;
                        }
                        break;
                    }
                }

                if (cb != null)
                {
                    foreach (var id in cas.Values)
                    {
                        connIds[id] = cb;
                    }
                }
            }

            return(connIds.Count == 0 ? null : connIds);
        }
예제 #37
0
		BlockStatement CreateMethodBody(IEnumerable<ParameterDeclaration> parameters, out MemberMapping mm)
		{
			if (methodDef.Body == null) {
				mm = null;
				return null;
			}
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILBlock ilMethod = new ILBlock();
			ILAstBuilder astBuilder = new ILAstBuilder();
			ilMethod.Body = astBuilder.Build(methodDef, true, context);
			
			context.CancellationToken.ThrowIfCancellationRequested();
			ILAstOptimizer bodyGraph = new ILAstOptimizer();
			bodyGraph.Optimize(context, ilMethod);
			context.CancellationToken.ThrowIfCancellationRequested();
			
			var localVariables = ilMethod.GetSelfAndChildrenRecursive<ILExpression>().Select(e => e.Operand as ILVariable)
				.Where(v => v != null && !v.IsParameter).Distinct();
			Debug.Assert(context.CurrentMethod == methodDef);
			NameVariables.AssignNamesToVariables(context, astBuilder.Parameters, localVariables, ilMethod);
			
			if (parameters != null) {
				foreach (var pair in (from p in parameters
				                      join v in astBuilder.Parameters on p.Annotation<Parameter>() equals v.OriginalParameter
				                      select new { p, v.Name }))
				{
					pair.p.NameToken = Identifier.Create(pair.Name).WithAnnotation(TextTokenType.Parameter);
				}
			}
			
			context.CancellationToken.ThrowIfCancellationRequested();
			Ast.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").WithAnnotation(TextTokenType.Keyword);
				else
					type = AstBuilder.ConvertType(v.Type);
				var newVarDecl = new VariableDeclarationStatement(v.IsParameter ? TextTokenType.Parameter : TextTokenType.Local, type, v.Name);
				newVarDecl.Variables.Single().AddAnnotation(v);
				astBlock.Statements.InsertBefore(insertionPoint, newVarDecl);
			}
			
			mm = new MemberMapping(methodDef) { LocalVariables = localVariables.ToList() };
			
			return astBlock;
		}
		/// <summary>
		/// Clears the type inference data on the method.
		/// </summary>
		public static void Reset(ILBlock method)
		{
			foreach (ILExpression expr in method.GetSelfAndChildrenRecursive<ILExpression>()) {
				expr.InferredType = null;
				expr.ExpectedType = null;
				ILVariable v = expr.Operand as ILVariable;
				if (v != null && v.IsGenerated)
					v.Type = null;
			}
		}
예제 #39
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:
                            case ILCode.Cle:
                            case ILCode.Cle_Un:
                            case ILCode.Cge:
                            case ILCode.Cge_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;
            }
        }