Browse Source

Add cancellation support to the decompiler.

pull/37/head
Daniel Grunwald 15 years ago
parent
commit
016b54563f
  1. 16
      ICSharpCode.Decompiler/Ast/AstBuilder.cs
  2. 9
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  3. 8
      ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs
  4. 16
      ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs
  5. 36
      ICSharpCode.Decompiler/ILAst/ILAstTypes.cs
  6. 22
      ILSpy/CSharpLanguage.cs

16
ICSharpCode.Decompiler/Ast/AstBuilder.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
@ -12,6 +13,7 @@ namespace Decompiler
{ {
public class AstBuilder public class AstBuilder
{ {
public CancellationToken CancellationToken { get; set; }
CompilationUnit astCompileUnit = new CompilationUnit(); CompilationUnit astCompileUnit = new CompilationUnit();
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>();
@ -22,7 +24,7 @@ namespace Decompiler
public void GenerateCode(ITextOutput output, Predicate<IAstVisitor<object, object>> transformAbortCondition) public void GenerateCode(ITextOutput output, Predicate<IAstVisitor<object, object>> transformAbortCondition)
{ {
Transforms.TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition); Transforms.TransformationPipeline.RunTransformationsUntil(astCompileUnit, transformAbortCondition, this.CancellationToken);
astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null); astCompileUnit.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }, null);
var outputFormatter = new TextOutputFormatter(output); var outputFormatter = new TextOutputFormatter(output);
@ -412,7 +414,7 @@ namespace Decompiler
astMethod.Parameters = MakeParameters(methodDef.Parameters); astMethod.Parameters = MakeParameters(methodDef.Parameters);
if (!methodDef.DeclaringType.IsInterface) { if (!methodDef.DeclaringType.IsInterface) {
astMethod.Modifiers = ConvertModifiers(methodDef); astMethod.Modifiers = ConvertModifiers(methodDef);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, this.CancellationToken);
} }
return astMethod; return astMethod;
} }
@ -426,7 +428,7 @@ namespace Decompiler
astMethod.Modifiers &= ~Modifiers.VisibilityMask; astMethod.Modifiers &= ~Modifiers.VisibilityMask;
} }
astMethod.Parameters = MakeParameters(methodDef.Parameters); astMethod.Parameters = MakeParameters(methodDef.Parameters);
astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef); astMethod.Body = AstMethodBodyBuilder.CreateMethodBody(methodDef, this.CancellationToken);
return astMethod; return astMethod;
} }
@ -438,12 +440,12 @@ namespace Decompiler
astProp.ReturnType = ConvertType(propDef.PropertyType, propDef); astProp.ReturnType = ConvertType(propDef.PropertyType, propDef);
if (propDef.GetMethod != null) { if (propDef.GetMethod != null) {
astProp.Getter = new Accessor { astProp.Getter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod) Body = AstMethodBodyBuilder.CreateMethodBody(propDef.GetMethod, this.CancellationToken)
}; };
} }
if (propDef.SetMethod != null) { if (propDef.SetMethod != null) {
astProp.Setter = new Accessor { astProp.Setter = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod) Body = AstMethodBodyBuilder.CreateMethodBody(propDef.SetMethod, this.CancellationToken)
}; };
} }
return astProp; return astProp;
@ -457,12 +459,12 @@ namespace Decompiler
astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod); astEvent.Modifiers = ConvertModifiers(eventDef.AddMethod);
if (eventDef.AddMethod != null) { if (eventDef.AddMethod != null) {
astEvent.AddAccessor = new Accessor { astEvent.AddAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod) Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.AddMethod, this.CancellationToken)
}; };
} }
if (eventDef.RemoveMethod != null) { if (eventDef.RemoveMethod != null) {
astEvent.RemoveAccessor = new Accessor { astEvent.RemoveAccessor = new Accessor {
Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod) Body = AstMethodBodyBuilder.CreateMethodBody(eventDef.RemoveMethod, this.CancellationToken)
}; };
} }
return astEvent; return astEvent;

9
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading;
using Ast = ICSharpCode.NRefactory.CSharp; using Ast = ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
@ -15,11 +16,13 @@ namespace Decompiler
public class AstMethodBodyBuilder public class AstMethodBodyBuilder
{ {
MethodDefinition methodDef; MethodDefinition methodDef;
CancellationToken cancellationToken;
HashSet<ILVariable> definedLocalVars = new HashSet<ILVariable>(); HashSet<ILVariable> definedLocalVars = new HashSet<ILVariable>();
public static BlockStatement CreateMethodBody(MethodDefinition methodDef) public static BlockStatement CreateMethodBody(MethodDefinition methodDef, CancellationToken cancellationToken)
{ {
AstMethodBodyBuilder builder = new AstMethodBodyBuilder(); AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
builder.cancellationToken = cancellationToken;
builder.methodDef = methodDef; builder.methodDef = methodDef;
if (Debugger.IsAttached) { if (Debugger.IsAttached) {
return builder.CreateMethodBody(); return builder.CreateMethodBody();
@ -55,12 +58,15 @@ namespace Decompiler
{ {
if (methodDef.Body == null) return null; if (methodDef.Body == null) return null;
cancellationToken.ThrowIfCancellationRequested();
ILBlock ilMethod = new ILBlock(); ILBlock ilMethod = new ILBlock();
ILAstBuilder astBuilder = new ILAstBuilder(); ILAstBuilder astBuilder = new ILAstBuilder();
ilMethod.Body = astBuilder.Build(methodDef, true); ilMethod.Body = astBuilder.Build(methodDef, true);
cancellationToken.ThrowIfCancellationRequested();
ILAstOptimizer bodyGraph = new ILAstOptimizer(); ILAstOptimizer bodyGraph = new ILAstOptimizer();
bodyGraph.Optimize(ilMethod); bodyGraph.Optimize(ilMethod);
cancellationToken.ThrowIfCancellationRequested();
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"}); List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"});
Dictionary<string, int> typeNames = new Dictionary<string, int>(); Dictionary<string, int> typeNames = new Dictionary<string, int>();
@ -102,6 +108,7 @@ namespace Decompiler
// astBlock.Children.Add(astLocalVar); // astBlock.Children.Add(astLocalVar);
} }
cancellationToken.ThrowIfCancellationRequested();
Ast.BlockStatement astBlock = TransformBlock(ilMethod); Ast.BlockStatement astBlock = TransformBlock(ilMethod);
CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments CommentStatement.ReplaceAll(astBlock); // convert CommentStatements to Comments
return astBlock; return astBlock;

8
ICSharpCode.Decompiler/Ast/Transforms/DelegateConstruction.cs

@ -3,6 +3,8 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using Mono.Cecil; using Mono.Cecil;
@ -15,6 +17,8 @@ namespace Decompiler.Transforms
/// </summary> /// </summary>
public class DelegateConstruction : DepthFirstAstVisitor<object, object> public class DelegateConstruction : DepthFirstAstVisitor<object, object>
{ {
public CancellationToken CancellationToken { get; set; }
internal sealed class Annotation internal sealed class Annotation
{ {
/// <summary> /// <summary>
@ -107,8 +111,8 @@ namespace Decompiler.Transforms
} }
// Decompile the anonymous method: // Decompile the anonymous method:
BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method); BlockStatement body = AstMethodBodyBuilder.CreateMethodBody(method, this.CancellationToken);
TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction); TransformationPipeline.RunTransformationsUntil(body, v => v is DelegateConstruction, this.CancellationToken);
body.AcceptVisitor(this, null); body.AcceptVisitor(this, null);
AnonymousMethodExpression ame = new AnonymousMethodExpression(); AnonymousMethodExpression ame = new AnonymousMethodExpression();

16
ICSharpCode.Decompiler/Ast/Transforms/TransformationPipeline.cs

@ -2,31 +2,28 @@
// This code is distributed under MIT X11 license (for details please see \doc\license.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt)
using System; using System;
using System.Threading;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
namespace Decompiler.Transforms namespace Decompiler.Transforms
{ {
public static class TransformationPipeline public static class TransformationPipeline
{ {
public static IAstVisitor<object, object>[] CreatePipeline() public static IAstVisitor<object, object>[] CreatePipeline(CancellationToken cancellationToken)
{ {
return new IAstVisitor<object, object>[] { return new IAstVisitor<object, object>[] {
new DelegateConstruction(), new DelegateConstruction() { CancellationToken = cancellationToken },
new ConvertConstructorCallIntoInitializer(), new ConvertConstructorCallIntoInitializer(),
new ReplaceMethodCallsWithOperators() new ReplaceMethodCallsWithOperators()
}; };
} }
public static void RunTransformations(AstNode node) public static void RunTransformationsUntil(AstNode node, Predicate<IAstVisitor<object, object>> abortCondition, CancellationToken cancellationToken)
{
RunTransformationsUntil(node, null);
}
public static void RunTransformationsUntil(AstNode node, Predicate<IAstVisitor<object, object>> abortCondition)
{ {
if (node == null) if (node == null)
return; return;
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
cancellationToken.ThrowIfCancellationRequested();
if (Options.ReduceAstJumps) { if (Options.ReduceAstJumps) {
node.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); node.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null);
node.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); node.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null);
@ -40,7 +37,8 @@ namespace Decompiler.Transforms
} }
} }
foreach (var visitor in CreatePipeline()) { foreach (var visitor in CreatePipeline(cancellationToken)) {
cancellationToken.ThrowIfCancellationRequested();
if (abortCondition != null && abortCondition(visitor)) if (abortCondition != null && abortCondition(visitor))
return; return;
node.AcceptVisitor(visitor, null); node.AcceptVisitor(visitor, null);

36
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

@ -3,9 +3,11 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Decompiler.ControlFlow; using Decompiler.ControlFlow;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Disassembler; using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.NRefactory.Utils;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
using Cecil = Mono.Cecil; using Cecil = Mono.Cecil;
@ -16,31 +18,7 @@ namespace Decompiler
{ {
public IEnumerable<T> GetSelfAndChildrenRecursive<T>() where T: ILNode public IEnumerable<T> GetSelfAndChildrenRecursive<T>() where T: ILNode
{ {
if (this is T) return TreeTraversal.PreOrder(this, c => c != null ? c.GetChildren() : null).OfType<T>();
yield return (T)this;
Stack<IEnumerator<ILNode>> stack = new Stack<IEnumerator<ILNode>>();
try {
stack.Push(GetChildren().GetEnumerator());
while (stack.Count > 0) {
while (stack.Peek().MoveNext()) {
ILNode element = stack.Peek().Current;
if (element != null) {
if (element is T)
yield return (T)element;
IEnumerable<ILNode> children = element.GetChildren();
if (children != null) {
stack.Push(children.GetEnumerator());
}
}
}
stack.Pop().Dispose();
}
} finally {
while (stack.Count > 0) {
stack.Pop().Dispose();
}
}
} }
public virtual IEnumerable<ILNode> GetChildren() public virtual IEnumerable<ILNode> GetChildren()
@ -115,7 +93,9 @@ namespace Decompiler
output.Write("catch "); output.Write("catch ");
output.WriteReference(ExceptionType.FullName, ExceptionType); output.WriteReference(ExceptionType.FullName, ExceptionType);
output.WriteLine(" {"); output.WriteLine(" {");
output.Indent();
base.WriteTo(output); base.WriteTo(output);
output.Unindent();
output.WriteLine("}"); output.WriteLine("}");
} }
} }
@ -137,14 +117,18 @@ namespace Decompiler
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.WriteLine(".try {"); output.WriteLine(".try {");
output.Indent();
TryBlock.WriteTo(output); TryBlock.WriteTo(output);
output.Unindent();
output.WriteLine("}"); output.WriteLine("}");
foreach (CatchBlock block in CatchBlocks) { foreach (CatchBlock block in CatchBlocks) {
block.WriteTo(output); block.WriteTo(output);
} }
if (FinallyBlock != null) { if (FinallyBlock != null) {
output.WriteLine("finally {"); output.WriteLine("finally {");
output.Indent();
FinallyBlock.WriteTo(output); FinallyBlock.WriteTo(output);
output.Unindent();
output.WriteLine("}"); output.WriteLine("}");
} }
} }
@ -250,7 +234,7 @@ namespace Decompiler
first = false; first = false;
} }
foreach (ILExpression arg in this.Arguments) { foreach (ILExpression arg in this.Arguments) {
if (!first) output.Write(','); if (!first) output.Write(", ");
arg.WriteTo(output); arg.WriteTo(output);
first = false; first = false;
} }

22
ILSpy/CSharpLanguage.cs

@ -20,6 +20,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading;
using Decompiler; using Decompiler;
using Decompiler.Transforms; using Decompiler.Transforms;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
@ -34,7 +35,7 @@ namespace ICSharpCode.ILSpy
public class CSharpLanguage : Language public class CSharpLanguage : Language
{ {
string name = "C#"; string name = "C#";
Predicate<IAstVisitor<object, object>> transformAbortCondition; Predicate<IAstVisitor<object, object>> transformAbortCondition = null;
public CSharpLanguage() public CSharpLanguage()
{ {
@ -44,7 +45,7 @@ namespace ICSharpCode.ILSpy
internal static IEnumerable<CSharpLanguage> GetDebugLanguages() internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{ {
string lastTransformName = "no transforms"; string lastTransformName = "no transforms";
foreach (Type _transformType in TransformationPipeline.CreatePipeline().Select(v => v.GetType()).Distinct()) { foreach (Type _transformType in TransformationPipeline.CreatePipeline(CancellationToken.None).Select(v => v.GetType()).Distinct()) {
Type transformType = _transformType; // copy for lambda Type transformType = _transformType; // copy for lambda
yield return new CSharpLanguage { yield return new CSharpLanguage {
transformAbortCondition = v => transformType.IsInstanceOfType(v), transformAbortCondition = v => transformType.IsInstanceOfType(v),
@ -68,35 +69,35 @@ namespace ICSharpCode.ILSpy
public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options);
codeDomBuilder.AddMethod(method); codeDomBuilder.AddMethod(method);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options) public override void DecompileProperty(PropertyDefinition property, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options);
codeDomBuilder.AddProperty(property); codeDomBuilder.AddProperty(property);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options) public override void DecompileField(FieldDefinition field, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options);
codeDomBuilder.AddField(field); codeDomBuilder.AddField(field);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options) public override void DecompileEvent(EventDefinition ev, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options);
codeDomBuilder.AddEvent(ev); codeDomBuilder.AddEvent(ev);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options) public override void DecompileType(TypeDefinition type, ITextOutput output, DecompilationOptions options)
{ {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options);
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
} }
@ -105,7 +106,7 @@ namespace ICSharpCode.ILSpy
{ {
if (options.FullDecompilation) { if (options.FullDecompilation) {
foreach (TypeDefinition type in assembly.MainModule.Types) { foreach (TypeDefinition type in assembly.MainModule.Types) {
AstBuilder codeDomBuilder = new AstBuilder(); AstBuilder codeDomBuilder = CreateAstBuilder(options);
codeDomBuilder.AddType(type); codeDomBuilder.AddType(type);
codeDomBuilder.GenerateCode(output, transformAbortCondition); codeDomBuilder.GenerateCode(output, transformAbortCondition);
output.WriteLine(); output.WriteLine();
@ -115,6 +116,11 @@ namespace ICSharpCode.ILSpy
} }
} }
AstBuilder CreateAstBuilder(DecompilationOptions options)
{
return new AstBuilder { CancellationToken = options.CancellationToken };
}
public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes) public override string TypeToString(TypeReference type, bool includeNamespace, ICustomAttributeProvider typeAttributes)
{ {
AstType astType = AstBuilder.ConvertType(type, typeAttributes); AstType astType = AstBuilder.ConvertType(type, typeAttributes);

Loading…
Cancel
Save