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

9
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

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

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

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

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

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

36
ICSharpCode.Decompiler/ILAst/ILAstTypes.cs

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

22
ILSpy/CSharpLanguage.cs

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

Loading…
Cancel
Save