mirror of https://github.com/icsharpcode/ILSpy.git
24 changed files with 3237 additions and 3189 deletions
@ -1,316 +1,316 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using System.IO; |
using System.IO; |
||||||
using System.Linq; |
using System.Linq; |
||||||
using Ast = ICSharpCode.NRefactory.Ast; |
using Ast = ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.PrettyPrinter; |
using ICSharpCode.NRefactory.PrettyPrinter; |
||||||
using Mono.Cecil; |
using Mono.Cecil; |
||||||
using Mono.Cecil.Cil; |
using Mono.Cecil.Cil; |
||||||
|
|
||||||
namespace Decompiler |
namespace Decompiler |
||||||
{ |
{ |
||||||
public class AstBuilder |
public class AstBuilder |
||||||
{ |
{ |
||||||
CompilationUnit astCompileUnit = new CompilationUnit(); |
CompilationUnit astCompileUnit = new CompilationUnit(); |
||||||
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); |
Dictionary<string, NamespaceDeclaration> astNamespaces = new Dictionary<string, NamespaceDeclaration>(); |
||||||
|
|
||||||
public string GenerateCode() |
public string GenerateCode() |
||||||
{ |
{ |
||||||
CSharpOutputVisitor csOutVisitor = new CSharpOutputVisitor(); |
CSharpOutputVisitor csOutVisitor = new CSharpOutputVisitor(); |
||||||
|
|
||||||
for (int i = 0; i < 4; i++) { |
for (int i = 0; i < 4; i++) { |
||||||
if (Options.ReduceAstJumps) { |
if (Options.ReduceAstJumps) { |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveGotos(), null); |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveDeadLabels(), null); |
||||||
} |
} |
||||||
if (Options.ReduceAstLoops) { |
if (Options.ReduceAstLoops) { |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); |
||||||
} |
} |
||||||
if (Options.ReduceAstOther) { |
if (Options.ReduceAstOther) { |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveEmptyElseBody(), null); |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.PushNegation(), null); |
||||||
} |
} |
||||||
} |
} |
||||||
if (Options.ReduceAstOther) { |
if (Options.ReduceAstOther) { |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.RemoveParenthesis(), null); |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.SimplifyTypeReferences(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.SimplifyTypeReferences(), null); |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.Idioms(), null); |
||||||
} |
} |
||||||
if (Options.ReduceAstLoops) { |
if (Options.ReduceAstLoops) { |
||||||
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); |
astCompileUnit.AcceptVisitor(new Transforms.Ast.RestoreLoop(), null); |
||||||
} |
} |
||||||
|
|
||||||
astCompileUnit.AcceptVisitor(csOutVisitor, null); |
astCompileUnit.AcceptVisitor(csOutVisitor, null); |
||||||
|
|
||||||
string code = csOutVisitor.Text; |
string code = csOutVisitor.Text; |
||||||
for(int i = 10; i >= 0; i--) { |
for(int i = 10; i >= 0; i--) { |
||||||
code = code.Replace("\r\n" + new string('\t', i) + "else {", " else {"); |
code = code.Replace("\r\n" + new string('\t', i) + "else {", " else {"); |
||||||
} |
} |
||||||
code = code.Replace("\t", " "); |
code = code.Replace("\t", " "); |
||||||
code = code.Replace("\"/***", ""); |
code = code.Replace("\"/***", ""); |
||||||
code = code.Replace("***/\";", ""); |
code = code.Replace("***/\";", ""); |
||||||
|
|
||||||
// Post processing commands
|
// Post processing commands
|
||||||
while(true) { |
while(true) { |
||||||
int endIndex = code.IndexOf("[JoinLine]") + "[JoinLine]".Length; |
int endIndex = code.IndexOf("[JoinLine]") + "[JoinLine]".Length; |
||||||
if (endIndex != -1) { |
if (endIndex != -1) { |
||||||
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); |
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); |
||||||
if (startIndex != -1) { |
if (startIndex != -1) { |
||||||
code = code.Remove(startIndex, endIndex - startIndex); |
code = code.Remove(startIndex, endIndex - startIndex); |
||||||
continue; |
continue; |
||||||
} |
} |
||||||
} |
} |
||||||
break; |
break; |
||||||
} |
} |
||||||
while(true) { |
while(true) { |
||||||
int endIndex = code.IndexOf("[Tab]"); |
int endIndex = code.IndexOf("[Tab]"); |
||||||
if (endIndex != -1) { |
if (endIndex != -1) { |
||||||
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); |
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex); |
||||||
if (startIndex != -1) { |
if (startIndex != -1) { |
||||||
code = code.Remove(endIndex, "[Tab]".Length); |
code = code.Remove(endIndex, "[Tab]".Length); |
||||||
code = code.Insert(endIndex, new string(' ', Math.Max(0, 40 - endIndex + startIndex))); |
code = code.Insert(endIndex, new string(' ', Math.Max(0, 40 - endIndex + startIndex))); |
||||||
continue; |
continue; |
||||||
} |
} |
||||||
} |
} |
||||||
break; |
break; |
||||||
} |
} |
||||||
|
|
||||||
return code; |
return code; |
||||||
} |
} |
||||||
|
|
||||||
public void AddAssembly(AssemblyDefinition assemblyDefinition) |
public void AddAssembly(AssemblyDefinition assemblyDefinition) |
||||||
{ |
{ |
||||||
Ast.UsingDeclaration astUsing = new Ast.UsingDeclaration("System"); |
Ast.UsingDeclaration astUsing = new Ast.UsingDeclaration("System"); |
||||||
astCompileUnit.Children.Add(astUsing); |
astCompileUnit.Children.Add(astUsing); |
||||||
|
|
||||||
foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { |
foreach(TypeDefinition typeDef in assemblyDefinition.MainModule.Types) { |
||||||
// Skip nested types - they will be added by the parent type
|
// Skip nested types - they will be added by the parent type
|
||||||
if (typeDef.DeclaringType != null) continue; |
if (typeDef.DeclaringType != null) continue; |
||||||
// Skip the <Module> class
|
// Skip the <Module> class
|
||||||
if (typeDef.Name == "<Module>") continue; |
if (typeDef.Name == "<Module>") continue; |
||||||
|
|
||||||
AddType(typeDef); |
AddType(typeDef); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
NamespaceDeclaration GetCodeNamespace(string name) |
NamespaceDeclaration GetCodeNamespace(string name) |
||||||
{ |
{ |
||||||
if (string.IsNullOrEmpty(name)) { |
if (string.IsNullOrEmpty(name)) { |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
if (astNamespaces.ContainsKey(name)) { |
if (astNamespaces.ContainsKey(name)) { |
||||||
return astNamespaces[name]; |
return astNamespaces[name]; |
||||||
} else { |
} else { |
||||||
// Create the namespace
|
// Create the namespace
|
||||||
NamespaceDeclaration astNamespace = new NamespaceDeclaration(name); |
NamespaceDeclaration astNamespace = new NamespaceDeclaration(name); |
||||||
astCompileUnit.Children.Add(astNamespace); |
astCompileUnit.Children.Add(astNamespace); |
||||||
astNamespaces[name] = astNamespace; |
astNamespaces[name] = astNamespace; |
||||||
return astNamespace; |
return astNamespace; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public void AddType(TypeDefinition typeDef) |
public void AddType(TypeDefinition typeDef) |
||||||
{ |
{ |
||||||
if (!string.IsNullOrEmpty(Options.TypeFilter) && typeDef.Name != Options.TypeFilter) return; |
if (!string.IsNullOrEmpty(Options.TypeFilter) && typeDef.Name != Options.TypeFilter) return; |
||||||
|
|
||||||
TypeDeclaration astType = CreateType(typeDef); |
TypeDeclaration astType = CreateType(typeDef); |
||||||
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); |
NamespaceDeclaration astNS = GetCodeNamespace(typeDef.Namespace); |
||||||
if (astNS != null) { |
if (astNS != null) { |
||||||
astNS.Children.Add(astType); |
astNS.Children.Add(astType); |
||||||
} else { |
} else { |
||||||
astCompileUnit.Children.Add(astType); |
astCompileUnit.Children.Add(astType); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public TypeDeclaration CreateType(TypeDefinition typeDef) |
public TypeDeclaration CreateType(TypeDefinition typeDef) |
||||||
{ |
{ |
||||||
TypeDeclaration astType = new TypeDeclaration(ConvertModifiers(typeDef), new List<AttributeSection>()); |
TypeDeclaration astType = new TypeDeclaration(ConvertModifiers(typeDef), new List<AttributeSection>()); |
||||||
astType.Name = typeDef.Name; |
astType.Name = typeDef.Name; |
||||||
|
|
||||||
if (typeDef.IsEnum) { // NB: Enum is value type
|
if (typeDef.IsEnum) { // NB: Enum is value type
|
||||||
astType.Type = ClassType.Enum; |
astType.Type = ClassType.Enum; |
||||||
} else if (typeDef.IsValueType) { |
} else if (typeDef.IsValueType) { |
||||||
astType.Type = ClassType.Struct; |
astType.Type = ClassType.Struct; |
||||||
} else if (typeDef.IsInterface) { |
} else if (typeDef.IsInterface) { |
||||||
astType.Type = ClassType.Interface; |
astType.Type = ClassType.Interface; |
||||||
} else { |
} else { |
||||||
astType.Type = ClassType.Class; |
astType.Type = ClassType.Class; |
||||||
} |
} |
||||||
|
|
||||||
// Nested types
|
// Nested types
|
||||||
foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) { |
foreach(TypeDefinition nestedTypeDef in typeDef.NestedTypes) { |
||||||
astType.Children.Add(CreateType(nestedTypeDef)); |
astType.Children.Add(CreateType(nestedTypeDef)); |
||||||
} |
} |
||||||
|
|
||||||
// Base type
|
// Base type
|
||||||
if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) { |
if (typeDef.BaseType != null && !typeDef.IsValueType && typeDef.BaseType.FullName != Constants.Object) { |
||||||
astType.BaseTypes.Add(new Ast.TypeReference(typeDef.BaseType.FullName)); |
astType.BaseTypes.Add(new Ast.TypeReference(typeDef.BaseType.FullName)); |
||||||
} |
} |
||||||
|
|
||||||
AddTypeMembers(astType, typeDef); |
AddTypeMembers(astType, typeDef); |
||||||
|
|
||||||
return astType; |
return astType; |
||||||
} |
} |
||||||
|
|
||||||
Modifiers ConvertModifiers(TypeDefinition typeDef) |
Modifiers ConvertModifiers(TypeDefinition typeDef) |
||||||
{ |
{ |
||||||
return |
return |
||||||
(typeDef.IsNestedPrivate ? Modifiers.Private : Modifiers.None) | |
(typeDef.IsNestedPrivate ? Modifiers.Private : Modifiers.None) | |
||||||
(typeDef.IsNestedFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access
|
(typeDef.IsNestedFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access
|
||||||
(typeDef.IsNestedAssembly ? Modifiers.Internal : Modifiers.None) | |
(typeDef.IsNestedAssembly ? Modifiers.Internal : Modifiers.None) | |
||||||
(typeDef.IsNestedFamily ? Modifiers.Protected : Modifiers.None) | |
(typeDef.IsNestedFamily ? Modifiers.Protected : Modifiers.None) | |
||||||
(typeDef.IsNestedFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
(typeDef.IsNestedFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
||||||
(typeDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
(typeDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
||||||
(typeDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); |
(typeDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); |
||||||
} |
} |
||||||
|
|
||||||
Modifiers ConvertModifiers(FieldDefinition fieldDef) |
Modifiers ConvertModifiers(FieldDefinition fieldDef) |
||||||
{ |
{ |
||||||
return |
return |
||||||
(fieldDef.IsPrivate ? Modifiers.Private : Modifiers.None) | |
(fieldDef.IsPrivate ? Modifiers.Private : Modifiers.None) | |
||||||
(fieldDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access
|
(fieldDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access
|
||||||
(fieldDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | |
(fieldDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | |
||||||
(fieldDef.IsFamily ? Modifiers.Protected : Modifiers.None) | |
(fieldDef.IsFamily ? Modifiers.Protected : Modifiers.None) | |
||||||
(fieldDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
(fieldDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
||||||
(fieldDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
(fieldDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
||||||
(fieldDef.IsLiteral ? Modifiers.Const : Modifiers.None) | |
(fieldDef.IsLiteral ? Modifiers.Const : Modifiers.None) | |
||||||
(fieldDef.IsStatic ? Modifiers.Static : Modifiers.None); |
(fieldDef.IsStatic ? Modifiers.Static : Modifiers.None); |
||||||
} |
} |
||||||
|
|
||||||
Modifiers ConvertModifiers(MethodDefinition methodDef) |
Modifiers ConvertModifiers(MethodDefinition methodDef) |
||||||
{ |
{ |
||||||
return |
return |
||||||
(methodDef.IsCompilerControlled ? Modifiers.None : Modifiers.None) | |
(methodDef.IsCompilerControlled ? Modifiers.None : Modifiers.None) | |
||||||
(methodDef.IsPrivate ? Modifiers.Private : Modifiers.None) | |
(methodDef.IsPrivate ? Modifiers.Private : Modifiers.None) | |
||||||
(methodDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access
|
(methodDef.IsFamilyAndAssembly ? Modifiers.Protected : Modifiers.None) | // TODO: Extended access
|
||||||
(methodDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | |
(methodDef.IsAssembly ? Modifiers.Internal : Modifiers.None) | |
||||||
(methodDef.IsFamily ? Modifiers.Protected : Modifiers.None) | |
(methodDef.IsFamily ? Modifiers.Protected : Modifiers.None) | |
||||||
(methodDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
(methodDef.IsFamilyOrAssembly ? Modifiers.Protected | Modifiers.Internal : Modifiers.None) | |
||||||
(methodDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
(methodDef.IsPublic ? Modifiers.Public : Modifiers.None) | |
||||||
(methodDef.IsStatic ? Modifiers.Static : Modifiers.None) | |
(methodDef.IsStatic ? Modifiers.Static : Modifiers.None) | |
||||||
(methodDef.IsVirtual ? Modifiers.Virtual : Modifiers.None) | |
(methodDef.IsVirtual ? Modifiers.Virtual : Modifiers.None) | |
||||||
(methodDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); |
(methodDef.IsAbstract ? Modifiers.Abstract : Modifiers.None); |
||||||
} |
} |
||||||
|
|
||||||
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) |
void AddTypeMembers(TypeDeclaration astType, TypeDefinition typeDef) |
||||||
{ |
{ |
||||||
// Add fields
|
// Add fields
|
||||||
foreach(FieldDefinition fieldDef in typeDef.Fields) { |
foreach(FieldDefinition fieldDef in typeDef.Fields) { |
||||||
Ast.FieldDeclaration astField = new Ast.FieldDeclaration(new List<AttributeSection>()); |
Ast.FieldDeclaration astField = new Ast.FieldDeclaration(new List<AttributeSection>()); |
||||||
astField.Fields.Add(new Ast.VariableDeclaration(fieldDef.Name)); |
astField.Fields.Add(new Ast.VariableDeclaration(fieldDef.Name)); |
||||||
astField.TypeReference = new Ast.TypeReference(fieldDef.FieldType.FullName); |
astField.TypeReference = new Ast.TypeReference(fieldDef.FieldType.FullName); |
||||||
astField.Modifier = ConvertModifiers(fieldDef); |
astField.Modifier = ConvertModifiers(fieldDef); |
||||||
|
|
||||||
astType.Children.Add(astField); |
astType.Children.Add(astField); |
||||||
} |
} |
||||||
|
|
||||||
if (typeDef.Fields.Count > 0) { |
if (typeDef.Fields.Count > 0) { |
||||||
astType.Children.Add(new IdentifierExpression("\r\n")); |
astType.Children.Add(new IdentifierExpression("\r\n")); |
||||||
} |
} |
||||||
|
|
||||||
// Add events
|
// Add events
|
||||||
foreach(EventDefinition eventDef in typeDef.Events) { |
foreach(EventDefinition eventDef in typeDef.Events) { |
||||||
Ast.EventDeclaration astEvent = new Ast.EventDeclaration(); |
Ast.EventDeclaration astEvent = new Ast.EventDeclaration(); |
||||||
astEvent.Name = eventDef.Name; |
astEvent.Name = eventDef.Name; |
||||||
astEvent.TypeReference = new Ast.TypeReference(eventDef.EventType.FullName); |
astEvent.TypeReference = new Ast.TypeReference(eventDef.EventType.FullName); |
||||||
astEvent.Modifier = ConvertModifiers(eventDef.AddMethod); |
astEvent.Modifier = ConvertModifiers(eventDef.AddMethod); |
||||||
|
|
||||||
astType.Children.Add(astEvent); |
astType.Children.Add(astEvent); |
||||||
} |
} |
||||||
|
|
||||||
if (typeDef.Events.Count > 0) { |
if (typeDef.Events.Count > 0) { |
||||||
astType.Children.Add(new IdentifierExpression("\r\n")); |
astType.Children.Add(new IdentifierExpression("\r\n")); |
||||||
} |
} |
||||||
|
|
||||||
// Add properties
|
// Add properties
|
||||||
foreach(PropertyDefinition propDef in typeDef.Properties) { |
foreach(PropertyDefinition propDef in typeDef.Properties) { |
||||||
Ast.PropertyDeclaration astProp = new Ast.PropertyDeclaration( |
Ast.PropertyDeclaration astProp = new Ast.PropertyDeclaration( |
||||||
ConvertModifiers(propDef.GetMethod), |
ConvertModifiers(propDef.GetMethod), |
||||||
new List<AttributeSection>(), |
new List<AttributeSection>(), |
||||||
propDef.Name, |
propDef.Name, |
||||||
new List<ParameterDeclarationExpression>() |
new List<ParameterDeclarationExpression>() |
||||||
); |
); |
||||||
astProp.TypeReference = new Ast.TypeReference(propDef.PropertyType.FullName); |
astProp.TypeReference = new Ast.TypeReference(propDef.PropertyType.FullName); |
||||||
|
|
||||||
if (propDef.GetMethod != null) { |
if (propDef.GetMethod != null) { |
||||||
astProp.GetRegion = new PropertyGetRegion( |
astProp.GetRegion = new PropertyGetRegion( |
||||||
AstMetodBodyBuilder.CreateMetodBody(propDef.GetMethod), |
AstMetodBodyBuilder.CreateMetodBody(propDef.GetMethod), |
||||||
new List<AttributeSection>() |
new List<AttributeSection>() |
||||||
); |
); |
||||||
} |
} |
||||||
if (propDef.SetMethod != null) { |
if (propDef.SetMethod != null) { |
||||||
astProp.SetRegion = new PropertySetRegion( |
astProp.SetRegion = new PropertySetRegion( |
||||||
AstMetodBodyBuilder.CreateMetodBody(propDef.SetMethod), |
AstMetodBodyBuilder.CreateMetodBody(propDef.SetMethod), |
||||||
new List<AttributeSection>() |
new List<AttributeSection>() |
||||||
); |
); |
||||||
} |
} |
||||||
|
|
||||||
astType.Children.Add(astProp); |
astType.Children.Add(astProp); |
||||||
} |
} |
||||||
|
|
||||||
if (typeDef.Properties.Count > 0) { |
if (typeDef.Properties.Count > 0) { |
||||||
astType.Children.Add(new IdentifierExpression("\r\n")); |
astType.Children.Add(new IdentifierExpression("\r\n")); |
||||||
} |
} |
||||||
|
|
||||||
// Add constructors
|
// Add constructors
|
||||||
foreach(MethodDefinition methodDef in typeDef.Methods) { |
foreach(MethodDefinition methodDef in typeDef.Methods) { |
||||||
if (!methodDef.IsConstructor) continue; |
if (!methodDef.IsConstructor) continue; |
||||||
|
|
||||||
Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration( |
Ast.ConstructorDeclaration astMethod = new Ast.ConstructorDeclaration( |
||||||
methodDef.Name, |
methodDef.Name, |
||||||
ConvertModifiers(methodDef), |
ConvertModifiers(methodDef), |
||||||
new List<ParameterDeclarationExpression>(MakeParameters(methodDef.Parameters)), |
new List<ParameterDeclarationExpression>(MakeParameters(methodDef.Parameters)), |
||||||
new List<AttributeSection>() |
new List<AttributeSection>() |
||||||
); |
); |
||||||
|
|
||||||
astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); |
astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); |
||||||
|
|
||||||
astType.Children.Add(astMethod); |
astType.Children.Add(astMethod); |
||||||
astType.Children.Add(new IdentifierExpression("\r\n")); |
astType.Children.Add(new IdentifierExpression("\r\n")); |
||||||
} |
} |
||||||
|
|
||||||
// Add methods
|
// Add methods
|
||||||
foreach(MethodDefinition methodDef in typeDef.Methods) { |
foreach(MethodDefinition methodDef in typeDef.Methods) { |
||||||
if (methodDef.IsSpecialName) continue; |
if (methodDef.IsSpecialName) continue; |
||||||
|
|
||||||
Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration(); |
Ast.MethodDeclaration astMethod = new Ast.MethodDeclaration(); |
||||||
astMethod.Name = methodDef.Name; |
astMethod.Name = methodDef.Name; |
||||||
astMethod.TypeReference = new Ast.TypeReference(methodDef.ReturnType.FullName); |
astMethod.TypeReference = new Ast.TypeReference(methodDef.ReturnType.FullName); |
||||||
astMethod.Modifier = ConvertModifiers(methodDef); |
astMethod.Modifier = ConvertModifiers(methodDef); |
||||||
|
|
||||||
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); |
astMethod.Parameters.AddRange(MakeParameters(methodDef.Parameters)); |
||||||
|
|
||||||
astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); |
astMethod.Body = AstMetodBodyBuilder.CreateMetodBody(methodDef); |
||||||
|
|
||||||
astType.Children.Add(astMethod); |
astType.Children.Add(astMethod); |
||||||
|
|
||||||
astType.Children.Add(new IdentifierExpression("\r\n")); |
astType.Children.Add(new IdentifierExpression("\r\n")); |
||||||
} |
} |
||||||
|
|
||||||
if (astType.Children.LastOrDefault() is IdentifierExpression) { |
if (astType.Children.LastOrDefault() is IdentifierExpression) { |
||||||
astType.Children.Last.Remove(); |
astType.Children.Last.Remove(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
IEnumerable<Ast.ParameterDeclarationExpression> MakeParameters(IEnumerable<ParameterDefinition> paramCol) |
IEnumerable<Ast.ParameterDeclarationExpression> MakeParameters(IEnumerable<ParameterDefinition> paramCol) |
||||||
{ |
{ |
||||||
foreach(ParameterDefinition paramDef in paramCol) { |
foreach(ParameterDefinition paramDef in paramCol) { |
||||||
Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression( |
Ast.ParameterDeclarationExpression astParam = new Ast.ParameterDeclarationExpression( |
||||||
new Ast.TypeReference(paramDef.ParameterType.FullName), |
new Ast.TypeReference(paramDef.ParameterType.FullName), |
||||||
paramDef.Name |
paramDef.Name |
||||||
); |
); |
||||||
|
|
||||||
if (paramDef.IsIn && !paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.In; |
if (paramDef.IsIn && !paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.In; |
||||||
if (!paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Out; |
if (!paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Out; |
||||||
if (paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Ref; |
if (paramDef.IsIn && paramDef.IsOut) astParam.ParamModifier = ParameterModifiers.Ref; |
||||||
|
|
||||||
yield return astParam; |
yield return astParam; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
File diff suppressed because it is too large
Load Diff
@ -1,76 +1,76 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using Ast = ICSharpCode.NRefactory.Ast; |
using Ast = ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Visitors; |
using ICSharpCode.NRefactory.Visitors; |
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
namespace Decompiler.Transforms.Ast |
||||||
{ |
{ |
||||||
public class Idioms: AbstractAstTransformer |
public class Idioms: AbstractAstTransformer |
||||||
{ |
{ |
||||||
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) |
public override object VisitInvocationExpression(InvocationExpression invocationExpression, object data) |
||||||
{ |
{ |
||||||
base.VisitInvocationExpression(invocationExpression, data); |
base.VisitInvocationExpression(invocationExpression, data); |
||||||
|
|
||||||
// Reduce "String.Concat(a, b)" to "a + b"
|
// Reduce "String.Concat(a, b)" to "a + b"
|
||||||
MemberReferenceExpression target = invocationExpression.TargetObject as MemberReferenceExpression; |
MemberReferenceExpression target = invocationExpression.TargetObject as MemberReferenceExpression; |
||||||
if (target != null && |
if (target != null && |
||||||
target.MemberName == "Concat" && |
target.MemberName == "Concat" && |
||||||
invocationExpression.Arguments.Count == 2 && |
invocationExpression.Arguments.Count == 2 && |
||||||
target.TargetObject is IdentifierExpression && |
target.TargetObject is IdentifierExpression && |
||||||
(target.TargetObject as IdentifierExpression).Identifier == "String") |
(target.TargetObject as IdentifierExpression).Identifier == "String") |
||||||
{ |
{ |
||||||
ReplaceCurrentNode( |
ReplaceCurrentNode( |
||||||
new BinaryOperatorExpression( |
new BinaryOperatorExpression( |
||||||
invocationExpression.Arguments[0], |
invocationExpression.Arguments[0], |
||||||
BinaryOperatorType.Add, |
BinaryOperatorType.Add, |
||||||
invocationExpression.Arguments[1] |
invocationExpression.Arguments[1] |
||||||
) |
) |
||||||
); |
); |
||||||
} |
} |
||||||
|
|
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitAssignmentExpression(AssignmentExpression assignment, object data) |
public override object VisitAssignmentExpression(AssignmentExpression assignment, object data) |
||||||
{ |
{ |
||||||
IdentifierExpression ident = assignment.Left as IdentifierExpression; |
IdentifierExpression ident = assignment.Left as IdentifierExpression; |
||||||
BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression; |
BinaryOperatorExpression binary = assignment.Right as BinaryOperatorExpression; |
||||||
if (ident != null && binary != null) { |
if (ident != null && binary != null) { |
||||||
IdentifierExpression binaryLeft = binary.Left as IdentifierExpression; |
IdentifierExpression binaryLeft = binary.Left as IdentifierExpression; |
||||||
if (binaryLeft != null && |
if (binaryLeft != null && |
||||||
binaryLeft.Identifier == ident.Identifier) { |
binaryLeft.Identifier == ident.Identifier) { |
||||||
if (binary.Right is PrimitiveExpression && |
if (binary.Right is PrimitiveExpression && |
||||||
1.Equals((binary.Right as PrimitiveExpression).Value)) { |
1.Equals((binary.Right as PrimitiveExpression).Value)) { |
||||||
if (binary.Op == BinaryOperatorType.Add) { |
if (binary.Op == BinaryOperatorType.Add) { |
||||||
ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostIncrement)); |
ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostIncrement)); |
||||||
} |
} |
||||||
if (binary.Op == BinaryOperatorType.Subtract) { |
if (binary.Op == BinaryOperatorType.Subtract) { |
||||||
ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostDecrement)); |
ReplaceCurrentNode(new UnaryOperatorExpression(ident, UnaryOperatorType.PostDecrement)); |
||||||
} |
} |
||||||
} else { |
} else { |
||||||
if (binary.Op == BinaryOperatorType.Add) { |
if (binary.Op == BinaryOperatorType.Add) { |
||||||
ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Add, binary.Right)); |
ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Add, binary.Right)); |
||||||
} |
} |
||||||
if (binary.Op == BinaryOperatorType.Subtract) { |
if (binary.Op == BinaryOperatorType.Subtract) { |
||||||
ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Subtract, binary.Right)); |
ReplaceCurrentNode(new AssignmentExpression(ident, AssignmentOperatorType.Subtract, binary.Right)); |
||||||
} |
} |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitCastExpression(CastExpression castExpression, object data) |
public override object VisitCastExpression(CastExpression castExpression, object data) |
||||||
{ |
{ |
||||||
if (castExpression.CastTo.Type == "int" && |
if (castExpression.CastTo.Type == "int" && |
||||||
castExpression.Expression is MemberReferenceExpression && |
castExpression.Expression is MemberReferenceExpression && |
||||||
(castExpression.Expression as MemberReferenceExpression).MemberName == "Length") { |
(castExpression.Expression as MemberReferenceExpression).MemberName == "Length") { |
||||||
ReplaceCurrentNode(castExpression.Expression); |
ReplaceCurrentNode(castExpression.Expression); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
return base.VisitCastExpression(castExpression, data); |
return base.VisitCastExpression(castExpression, data); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,87 +1,87 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
|
|
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Visitors; |
using ICSharpCode.NRefactory.Visitors; |
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
namespace Decompiler.Transforms.Ast |
||||||
{ |
{ |
||||||
public class PushNegation: AbstractAstTransformer |
public class PushNegation: AbstractAstTransformer |
||||||
{ |
{ |
||||||
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) |
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) |
||||||
{ |
{ |
||||||
// Remove double negation
|
// Remove double negation
|
||||||
// !!a
|
// !!a
|
||||||
if (unary.Op == UnaryOperatorType.Not && |
if (unary.Op == UnaryOperatorType.Not && |
||||||
unary.Expression is UnaryOperatorExpression && |
unary.Expression is UnaryOperatorExpression && |
||||||
(unary.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { |
(unary.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { |
||||||
Expression newParenth = new ParenthesizedExpression((unary.Expression as UnaryOperatorExpression).Expression); |
Expression newParenth = new ParenthesizedExpression((unary.Expression as UnaryOperatorExpression).Expression); |
||||||
ReplaceCurrentNode(newParenth); |
ReplaceCurrentNode(newParenth); |
||||||
return newParenth.AcceptVisitor(this, data); |
return newParenth.AcceptVisitor(this, data); |
||||||
} |
} |
||||||
|
|
||||||
// Basic assumtion is that we have something in form !(a)
|
// Basic assumtion is that we have something in form !(a)
|
||||||
if (unary.Op == UnaryOperatorType.Not && |
if (unary.Op == UnaryOperatorType.Not && |
||||||
unary.Expression is ParenthesizedExpression) { |
unary.Expression is ParenthesizedExpression) { |
||||||
ParenthesizedExpression parenth = ((ParenthesizedExpression)unary.Expression); |
ParenthesizedExpression parenth = ((ParenthesizedExpression)unary.Expression); |
||||||
|
|
||||||
// Push through two parenthesis
|
// Push through two parenthesis
|
||||||
// !((a))
|
// !((a))
|
||||||
if (parenth.Expression is ParenthesizedExpression) { |
if (parenth.Expression is ParenthesizedExpression) { |
||||||
parenth.Expression = new UnaryOperatorExpression(parenth.Expression, UnaryOperatorType.Not); |
parenth.Expression = new UnaryOperatorExpression(parenth.Expression, UnaryOperatorType.Not); |
||||||
ReplaceCurrentNode(parenth); |
ReplaceCurrentNode(parenth); |
||||||
return parenth.AcceptVisitor(this, data); |
return parenth.AcceptVisitor(this, data); |
||||||
} |
} |
||||||
|
|
||||||
// Remove double negation
|
// Remove double negation
|
||||||
// !(!a)
|
// !(!a)
|
||||||
if (parenth.Expression is UnaryOperatorExpression && |
if (parenth.Expression is UnaryOperatorExpression && |
||||||
(parenth.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { |
(parenth.Expression as UnaryOperatorExpression).Op == UnaryOperatorType.Not) { |
||||||
parenth.Expression = (parenth.Expression as UnaryOperatorExpression).Expression; |
parenth.Expression = (parenth.Expression as UnaryOperatorExpression).Expression; |
||||||
ReplaceCurrentNode(parenth); |
ReplaceCurrentNode(parenth); |
||||||
return parenth.AcceptVisitor(this, data); |
return parenth.AcceptVisitor(this, data); |
||||||
} |
} |
||||||
|
|
||||||
// Push through binary operation
|
// Push through binary operation
|
||||||
// !((a) op (b))
|
// !((a) op (b))
|
||||||
BinaryOperatorExpression binaryOp = parenth.Expression as BinaryOperatorExpression; |
BinaryOperatorExpression binaryOp = parenth.Expression as BinaryOperatorExpression; |
||||||
if (binaryOp != null && |
if (binaryOp != null && |
||||||
binaryOp.Left is ParenthesizedExpression && |
binaryOp.Left is ParenthesizedExpression && |
||||||
binaryOp.Right is ParenthesizedExpression) { |
binaryOp.Right is ParenthesizedExpression) { |
||||||
|
|
||||||
bool sucessful = true; |
bool sucessful = true; |
||||||
switch(binaryOp.Op) { |
switch(binaryOp.Op) { |
||||||
case BinaryOperatorType.Equality: binaryOp.Op = BinaryOperatorType.InEquality; break; |
case BinaryOperatorType.Equality: binaryOp.Op = BinaryOperatorType.InEquality; break; |
||||||
case BinaryOperatorType.InEquality: binaryOp.Op = BinaryOperatorType.Equality; break; |
case BinaryOperatorType.InEquality: binaryOp.Op = BinaryOperatorType.Equality; break; |
||||||
case BinaryOperatorType.GreaterThan: binaryOp.Op = BinaryOperatorType.LessThanOrEqual; break; |
case BinaryOperatorType.GreaterThan: binaryOp.Op = BinaryOperatorType.LessThanOrEqual; break; |
||||||
case BinaryOperatorType.GreaterThanOrEqual: binaryOp.Op = BinaryOperatorType.LessThan; break; |
case BinaryOperatorType.GreaterThanOrEqual: binaryOp.Op = BinaryOperatorType.LessThan; break; |
||||||
case BinaryOperatorType.LessThanOrEqual: binaryOp.Op = BinaryOperatorType.GreaterThan; break; |
case BinaryOperatorType.LessThanOrEqual: binaryOp.Op = BinaryOperatorType.GreaterThan; break; |
||||||
case BinaryOperatorType.LessThan: binaryOp.Op = BinaryOperatorType.GreaterThanOrEqual; break; |
case BinaryOperatorType.LessThan: binaryOp.Op = BinaryOperatorType.GreaterThanOrEqual; break; |
||||||
default: sucessful = false; break; |
default: sucessful = false; break; |
||||||
} |
} |
||||||
if (sucessful) { |
if (sucessful) { |
||||||
ReplaceCurrentNode(parenth); |
ReplaceCurrentNode(parenth); |
||||||
return parenth.AcceptVisitor(this, data); |
return parenth.AcceptVisitor(this, data); |
||||||
} |
} |
||||||
|
|
||||||
sucessful = true; |
sucessful = true; |
||||||
switch(binaryOp.Op) { |
switch(binaryOp.Op) { |
||||||
case BinaryOperatorType.BitwiseAnd: binaryOp.Op = BinaryOperatorType.BitwiseOr; break; |
case BinaryOperatorType.BitwiseAnd: binaryOp.Op = BinaryOperatorType.BitwiseOr; break; |
||||||
case BinaryOperatorType.BitwiseOr: binaryOp.Op = BinaryOperatorType.BitwiseAnd; break; |
case BinaryOperatorType.BitwiseOr: binaryOp.Op = BinaryOperatorType.BitwiseAnd; break; |
||||||
case BinaryOperatorType.LogicalAnd: binaryOp.Op = BinaryOperatorType.LogicalOr; break; |
case BinaryOperatorType.LogicalAnd: binaryOp.Op = BinaryOperatorType.LogicalOr; break; |
||||||
case BinaryOperatorType.LogicalOr: binaryOp.Op = BinaryOperatorType.LogicalAnd; break; |
case BinaryOperatorType.LogicalOr: binaryOp.Op = BinaryOperatorType.LogicalAnd; break; |
||||||
default: sucessful = false; break; |
default: sucessful = false; break; |
||||||
} |
} |
||||||
if (sucessful) { |
if (sucessful) { |
||||||
binaryOp.Left = new UnaryOperatorExpression(binaryOp.Left, UnaryOperatorType.Not); |
binaryOp.Left = new UnaryOperatorExpression(binaryOp.Left, UnaryOperatorType.Not); |
||||||
binaryOp.Right = new UnaryOperatorExpression(binaryOp.Right, UnaryOperatorType.Not); |
binaryOp.Right = new UnaryOperatorExpression(binaryOp.Right, UnaryOperatorType.Not); |
||||||
ReplaceCurrentNode(parenth); |
ReplaceCurrentNode(parenth); |
||||||
return parenth.AcceptVisitor(this, data); |
return parenth.AcceptVisitor(this, data); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return base.VisitUnaryOperatorExpression(unary, data); |
return base.VisitUnaryOperatorExpression(unary, data); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,50 +1,50 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using Ast = ICSharpCode.NRefactory.Ast; |
using Ast = ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Visitors; |
using ICSharpCode.NRefactory.Visitors; |
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
namespace Decompiler.Transforms.Ast |
||||||
{ |
{ |
||||||
public class RemoveDeadLabels: AbstractAstTransformer |
public class RemoveDeadLabels: AbstractAstTransformer |
||||||
{ |
{ |
||||||
List<string> usedLabels = new List<string>(); |
List<string> usedLabels = new List<string>(); |
||||||
bool collectingUsedLabels; |
bool collectingUsedLabels; |
||||||
|
|
||||||
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) |
public override object VisitConstructorDeclaration(ConstructorDeclaration constructorDeclaration, object data) |
||||||
{ |
{ |
||||||
collectingUsedLabels = true; |
collectingUsedLabels = true; |
||||||
base.VisitConstructorDeclaration(constructorDeclaration, data); |
base.VisitConstructorDeclaration(constructorDeclaration, data); |
||||||
collectingUsedLabels = false; |
collectingUsedLabels = false; |
||||||
base.VisitConstructorDeclaration(constructorDeclaration, data); |
base.VisitConstructorDeclaration(constructorDeclaration, data); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) |
public override object VisitMethodDeclaration(MethodDeclaration methodDeclaration, object data) |
||||||
{ |
{ |
||||||
collectingUsedLabels = true; |
collectingUsedLabels = true; |
||||||
base.VisitMethodDeclaration(methodDeclaration, data); |
base.VisitMethodDeclaration(methodDeclaration, data); |
||||||
collectingUsedLabels = false; |
collectingUsedLabels = false; |
||||||
base.VisitMethodDeclaration(methodDeclaration, data); |
base.VisitMethodDeclaration(methodDeclaration, data); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) |
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) |
||||||
{ |
{ |
||||||
if (collectingUsedLabels) { |
if (collectingUsedLabels) { |
||||||
usedLabels.Add(gotoStatement.Label); |
usedLabels.Add(gotoStatement.Label); |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitLabelStatement(LabelStatement labelStatement, object data) |
public override object VisitLabelStatement(LabelStatement labelStatement, object data) |
||||||
{ |
{ |
||||||
if (!collectingUsedLabels) { |
if (!collectingUsedLabels) { |
||||||
if (!usedLabels.Contains(labelStatement.Label)) { |
if (!usedLabels.Contains(labelStatement.Label)) { |
||||||
RemoveCurrentNode(); |
RemoveCurrentNode(); |
||||||
} |
} |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,36 +1,36 @@ |
|||||||
using System; |
using System; |
||||||
|
|
||||||
using Ast = ICSharpCode.NRefactory.Ast; |
using Ast = ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Visitors; |
using ICSharpCode.NRefactory.Visitors; |
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
namespace Decompiler.Transforms.Ast |
||||||
{ |
{ |
||||||
public class RemoveEmptyElseBody: AbstractAstTransformer |
public class RemoveEmptyElseBody: AbstractAstTransformer |
||||||
{ |
{ |
||||||
public override object VisitBlockStatement(BlockStatement blockStatement, object data) |
public override object VisitBlockStatement(BlockStatement blockStatement, object data) |
||||||
{ |
{ |
||||||
for(int i = 0; i < blockStatement.Children.Count; i++) { |
for(int i = 0; i < blockStatement.Children.Count; i++) { |
||||||
if (blockStatement.Children[i] is Statement && |
if (blockStatement.Children[i] is Statement && |
||||||
((Statement)blockStatement.Children[i]).IsNull) |
((Statement)blockStatement.Children[i]).IsNull) |
||||||
{ |
{ |
||||||
blockStatement.Children.RemoveAt(i); |
blockStatement.Children.RemoveAt(i); |
||||||
i--; |
i--; |
||||||
} |
} |
||||||
} |
} |
||||||
return base.VisitBlockStatement(blockStatement, data); |
return base.VisitBlockStatement(blockStatement, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) |
public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) |
||||||
{ |
{ |
||||||
base.VisitIfElseStatement(ifElseStatement, data); |
base.VisitIfElseStatement(ifElseStatement, data); |
||||||
if (ifElseStatement.FalseStatement.Count == 1 && |
if (ifElseStatement.FalseStatement.Count == 1 && |
||||||
ifElseStatement.FalseStatement[0] is BlockStatement && |
ifElseStatement.FalseStatement[0] is BlockStatement && |
||||||
ifElseStatement.FalseStatement[0].Children.Count == 0) |
ifElseStatement.FalseStatement[0].Children.Count == 0) |
||||||
{ |
{ |
||||||
ifElseStatement.FalseStatement.Clear(); |
ifElseStatement.FalseStatement.Clear(); |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,186 +1,186 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
|
|
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Visitors; |
using ICSharpCode.NRefactory.Visitors; |
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
namespace Decompiler.Transforms.Ast |
||||||
{ |
{ |
||||||
public class RemoveGotos: AbstractAstTransformer |
public class RemoveGotos: AbstractAstTransformer |
||||||
{ |
{ |
||||||
Stack<StatementWithEmbeddedStatement> enteredLoops = new Stack<StatementWithEmbeddedStatement>(); |
Stack<StatementWithEmbeddedStatement> enteredLoops = new Stack<StatementWithEmbeddedStatement>(); |
||||||
|
|
||||||
StatementWithEmbeddedStatement CurrentLoop { |
StatementWithEmbeddedStatement CurrentLoop { |
||||||
get { |
get { |
||||||
if (enteredLoops.Count > 0) { |
if (enteredLoops.Count > 0) { |
||||||
return enteredLoops.Peek(); |
return enteredLoops.Peek(); |
||||||
} else { |
} else { |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitForStatement(ForStatement forStatement, object data) |
public override object VisitForStatement(ForStatement forStatement, object data) |
||||||
{ |
{ |
||||||
enteredLoops.Push(forStatement); |
enteredLoops.Push(forStatement); |
||||||
base.VisitForStatement(forStatement, data); |
base.VisitForStatement(forStatement, data); |
||||||
enteredLoops.Pop(); |
enteredLoops.Pop(); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data) |
public override object VisitDoLoopStatement(DoLoopStatement doLoopStatement, object data) |
||||||
{ |
{ |
||||||
enteredLoops.Push(doLoopStatement); |
enteredLoops.Push(doLoopStatement); |
||||||
base.VisitDoLoopStatement(doLoopStatement, data); |
base.VisitDoLoopStatement(doLoopStatement, data); |
||||||
enteredLoops.Pop(); |
enteredLoops.Pop(); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitBlockStatement(BlockStatement blockStatement, object data) |
public override object VisitBlockStatement(BlockStatement blockStatement, object data) |
||||||
{ |
{ |
||||||
base.VisitBlockStatement(blockStatement, data); |
base.VisitBlockStatement(blockStatement, data); |
||||||
|
|
||||||
// Remove redundant jump at the end of block
|
// Remove redundant jump at the end of block
|
||||||
INode lastStmt = blockStatement.Children.Last; |
INode lastStmt = blockStatement.Children.Last; |
||||||
// End of while loop
|
// End of while loop
|
||||||
if (lastStmt is ContinueStatement && |
if (lastStmt is ContinueStatement && |
||||||
blockStatement.Parent is DoLoopStatement) |
blockStatement.Parent is DoLoopStatement) |
||||||
{ |
{ |
||||||
lastStmt.Remove(); |
lastStmt.Remove(); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
// End of for loop
|
// End of for loop
|
||||||
if (lastStmt is ContinueStatement && |
if (lastStmt is ContinueStatement && |
||||||
blockStatement.Parent is ForStatement) |
blockStatement.Parent is ForStatement) |
||||||
{ |
{ |
||||||
lastStmt.Remove(); |
lastStmt.Remove(); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
// End of method
|
// End of method
|
||||||
if (lastStmt is ReturnStatement && |
if (lastStmt is ReturnStatement && |
||||||
(blockStatement.Parent is MethodDeclaration || blockStatement.Parent is ConstructorDeclaration) && |
(blockStatement.Parent is MethodDeclaration || blockStatement.Parent is ConstructorDeclaration) && |
||||||
((ReturnStatement)lastStmt).Expression.IsNull) |
((ReturnStatement)lastStmt).Expression.IsNull) |
||||||
{ |
{ |
||||||
lastStmt.Remove(); |
lastStmt.Remove(); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
// Get the next statement that will be executed after this one
|
// Get the next statement that will be executed after this one
|
||||||
// May return null
|
// May return null
|
||||||
public static INode GetNextStatement(Statement statement) |
public static INode GetNextStatement(Statement statement) |
||||||
{ |
{ |
||||||
if (statement == null) throw new ArgumentNullException(); |
if (statement == null) throw new ArgumentNullException(); |
||||||
|
|
||||||
Statement next = (Statement)statement.Next(); |
Statement next = (Statement)statement.Next(); |
||||||
|
|
||||||
if (next != null) { |
if (next != null) { |
||||||
return EnterBlockStatement(next); |
return EnterBlockStatement(next); |
||||||
} else { |
} else { |
||||||
if (statement.Parent is BlockStatement && |
if (statement.Parent is BlockStatement && |
||||||
statement.Parent.Parent is Statement) { |
statement.Parent.Parent is Statement) { |
||||||
return ExitBlockStatement((Statement)statement.Parent.Parent); |
return ExitBlockStatement((Statement)statement.Parent.Parent); |
||||||
} else { |
} else { |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
// Get the statement that will be executed once the given block exits by the end brace
|
// Get the statement that will be executed once the given block exits by the end brace
|
||||||
// May return null
|
// May return null
|
||||||
public static INode ExitBlockStatement(Statement statement) |
public static INode ExitBlockStatement(Statement statement) |
||||||
{ |
{ |
||||||
if (statement == null) throw new ArgumentNullException(); |
if (statement == null) throw new ArgumentNullException(); |
||||||
|
|
||||||
// When an 'if' body is finished the execution continues with the
|
// When an 'if' body is finished the execution continues with the
|
||||||
// next statement after the 'if' statement
|
// next statement after the 'if' statement
|
||||||
if (statement is IfElseStatement) { |
if (statement is IfElseStatement) { |
||||||
return GetNextStatement((IfElseStatement)statement); |
return GetNextStatement((IfElseStatement)statement); |
||||||
} |
} |
||||||
|
|
||||||
// When a 'for' body is finished the execution continues by:
|
// When a 'for' body is finished the execution continues by:
|
||||||
// Iterator; Condition; Body
|
// Iterator; Condition; Body
|
||||||
if (statement is ForStatement) { |
if (statement is ForStatement) { |
||||||
ForStatement forLoop = statement as ForStatement; |
ForStatement forLoop = statement as ForStatement; |
||||||
if (forLoop.Iterator.Count > 0) { |
if (forLoop.Iterator.Count > 0) { |
||||||
return forLoop.Iterator[0]; |
return forLoop.Iterator[0]; |
||||||
} else if (!forLoop.Condition.IsNull) { |
} else if (!forLoop.Condition.IsNull) { |
||||||
return forLoop.Condition; |
return forLoop.Condition; |
||||||
} else { |
} else { |
||||||
return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.Children.First); |
return EnterBlockStatement((Statement)forLoop.EmbeddedStatement.Children.First); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
// Get the first statement that will be executed in the given block
|
// Get the first statement that will be executed in the given block
|
||||||
public static INode EnterBlockStatement(Statement statement) |
public static INode EnterBlockStatement(Statement statement) |
||||||
{ |
{ |
||||||
if (statement == null) throw new ArgumentNullException(); |
if (statement == null) throw new ArgumentNullException(); |
||||||
|
|
||||||
// For loop starts as follows: Initializers; Condition; Body
|
// For loop starts as follows: Initializers; Condition; Body
|
||||||
if (statement is ForStatement) { |
if (statement is ForStatement) { |
||||||
ForStatement forLoop = statement as ForStatement; |
ForStatement forLoop = statement as ForStatement; |
||||||
if (forLoop.Initializers.Count > 0) { |
if (forLoop.Initializers.Count > 0) { |
||||||
return forLoop.Initializers[0]; |
return forLoop.Initializers[0]; |
||||||
} else if (!forLoop.Condition.IsNull) { |
} else if (!forLoop.Condition.IsNull) { |
||||||
return forLoop.Condition; |
return forLoop.Condition; |
||||||
} else if (forLoop.EmbeddedStatement is BlockStatement && |
} else if (forLoop.EmbeddedStatement is BlockStatement && |
||||||
forLoop.EmbeddedStatement.Children.Count > 0) { |
forLoop.EmbeddedStatement.Children.Count > 0) { |
||||||
statement = (Statement)forLoop.EmbeddedStatement.Children.First; |
statement = (Statement)forLoop.EmbeddedStatement.Children.First; |
||||||
return EnterBlockStatement(statement); // Simplify again
|
return EnterBlockStatement(statement); // Simplify again
|
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return statement; // Can not simplify
|
return statement; // Can not simplify
|
||||||
} |
} |
||||||
|
|
||||||
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) |
public override object VisitGotoStatement(GotoStatement gotoStatement, object data) |
||||||
{ |
{ |
||||||
// Remove redundant goto which goes to a label that imideately follows
|
// Remove redundant goto which goes to a label that imideately follows
|
||||||
INode fallthoughTarget = GetNextStatement(gotoStatement); |
INode fallthoughTarget = GetNextStatement(gotoStatement); |
||||||
if ((fallthoughTarget is LabelStatement) && |
if ((fallthoughTarget is LabelStatement) && |
||||||
(fallthoughTarget as LabelStatement).Label == gotoStatement.Label) { |
(fallthoughTarget as LabelStatement).Label == gotoStatement.Label) { |
||||||
RemoveCurrentNode(); |
RemoveCurrentNode(); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
// Replace goto with 'break'
|
// Replace goto with 'break'
|
||||||
// Break statement moves right outside the looop
|
// Break statement moves right outside the looop
|
||||||
if (CurrentLoop != null) { |
if (CurrentLoop != null) { |
||||||
INode breakTarget = GetNextStatement(CurrentLoop); |
INode breakTarget = GetNextStatement(CurrentLoop); |
||||||
if ((breakTarget is LabelStatement) && |
if ((breakTarget is LabelStatement) && |
||||||
(breakTarget as LabelStatement).Label == gotoStatement.Label) { |
(breakTarget as LabelStatement).Label == gotoStatement.Label) { |
||||||
ReplaceCurrentNode(new BreakStatement()); |
ReplaceCurrentNode(new BreakStatement()); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
// Replace goto with 'continue'
|
// Replace goto with 'continue'
|
||||||
// Continue statement which moves at the very end of loop
|
// Continue statement which moves at the very end of loop
|
||||||
if (CurrentLoop != null && |
if (CurrentLoop != null && |
||||||
(CurrentLoop.EmbeddedStatement is BlockStatement) && |
(CurrentLoop.EmbeddedStatement is BlockStatement) && |
||||||
((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement) != null && |
((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement) != null && |
||||||
((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement).Label == gotoStatement.Label) { |
((CurrentLoop.EmbeddedStatement as BlockStatement).Children.Last as LabelStatement).Label == gotoStatement.Label) { |
||||||
ReplaceCurrentNode(new ContinueStatement()); |
ReplaceCurrentNode(new ContinueStatement()); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
// Replace goto with 'continue'
|
// Replace goto with 'continue'
|
||||||
// Continue statement which moves at the very start of for loop
|
// Continue statement which moves at the very start of for loop
|
||||||
if (CurrentLoop != null) { |
if (CurrentLoop != null) { |
||||||
INode continueTarget = ExitBlockStatement(CurrentLoop); // The start of the loop
|
INode continueTarget = ExitBlockStatement(CurrentLoop); // The start of the loop
|
||||||
if ((continueTarget is LabelStatement) && |
if ((continueTarget is LabelStatement) && |
||||||
(continueTarget as LabelStatement).Label == gotoStatement.Label) { |
(continueTarget as LabelStatement).Label == gotoStatement.Label) { |
||||||
ReplaceCurrentNode(new ContinueStatement()); |
ReplaceCurrentNode(new ContinueStatement()); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,245 +1,245 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
|
|
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Visitors; |
using ICSharpCode.NRefactory.Visitors; |
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
namespace Decompiler.Transforms.Ast |
||||||
{ |
{ |
||||||
public class RemoveParenthesis: AbstractAstTransformer |
public class RemoveParenthesis: AbstractAstTransformer |
||||||
{ |
{ |
||||||
public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) |
public override object VisitParenthesizedExpression(ParenthesizedExpression parenthesizedExpression, object data) |
||||||
{ |
{ |
||||||
// The following do not need to be parenthesized
|
// The following do not need to be parenthesized
|
||||||
if (parenthesizedExpression.Expression is IdentifierExpression || |
if (parenthesizedExpression.Expression is IdentifierExpression || |
||||||
parenthesizedExpression.Expression is PrimitiveExpression || |
parenthesizedExpression.Expression is PrimitiveExpression || |
||||||
parenthesizedExpression.Expression is ThisReferenceExpression || |
parenthesizedExpression.Expression is ThisReferenceExpression || |
||||||
parenthesizedExpression.Expression is ParenthesizedExpression) { |
parenthesizedExpression.Expression is ParenthesizedExpression) { |
||||||
ReplaceCurrentNode(parenthesizedExpression.Expression); |
ReplaceCurrentNode(parenthesizedExpression.Expression); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
return base.VisitParenthesizedExpression(parenthesizedExpression, data); |
return base.VisitParenthesizedExpression(parenthesizedExpression, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data) |
public override object VisitAssignmentExpression(AssignmentExpression assignmentExpression, object data) |
||||||
{ |
{ |
||||||
assignmentExpression.Left = Deparenthesize(assignmentExpression.Left); |
assignmentExpression.Left = Deparenthesize(assignmentExpression.Left); |
||||||
assignmentExpression.Right = Deparenthesize(assignmentExpression.Right); |
assignmentExpression.Right = Deparenthesize(assignmentExpression.Right); |
||||||
return base.VisitAssignmentExpression(assignmentExpression, data); |
return base.VisitAssignmentExpression(assignmentExpression, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitArrayCreateExpression(ArrayCreateExpression array, object data) |
public override object VisitArrayCreateExpression(ArrayCreateExpression array, object data) |
||||||
{ |
{ |
||||||
for(int i = 0; i < array.Arguments.Count; i++) { |
for(int i = 0; i < array.Arguments.Count; i++) { |
||||||
array.Arguments[i] = Deparenthesize(array.Arguments[i]); |
array.Arguments[i] = Deparenthesize(array.Arguments[i]); |
||||||
} |
} |
||||||
return base.VisitArrayCreateExpression(array, data); |
return base.VisitArrayCreateExpression(array, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitReturnStatement(ReturnStatement returnStatement, object data) |
public override object VisitReturnStatement(ReturnStatement returnStatement, object data) |
||||||
{ |
{ |
||||||
returnStatement.Expression = Deparenthesize(returnStatement.Expression); |
returnStatement.Expression = Deparenthesize(returnStatement.Expression); |
||||||
return base.VisitReturnStatement(returnStatement, data); |
return base.VisitReturnStatement(returnStatement, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitCastExpression(CastExpression castExpression, object data) |
public override object VisitCastExpression(CastExpression castExpression, object data) |
||||||
{ |
{ |
||||||
if (GetPrecedence(castExpression.Expression) > GetPrecedence(castExpression)) { |
if (GetPrecedence(castExpression.Expression) > GetPrecedence(castExpression)) { |
||||||
castExpression.Expression = Deparenthesize(castExpression.Expression); |
castExpression.Expression = Deparenthesize(castExpression.Expression); |
||||||
} |
} |
||||||
return base.VisitCastExpression(castExpression, data); |
return base.VisitCastExpression(castExpression, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitIndexerExpression(IndexerExpression indexer, object data) |
public override object VisitIndexerExpression(IndexerExpression indexer, object data) |
||||||
{ |
{ |
||||||
if (GetPrecedence(indexer.TargetObject) >= GetPrecedence(indexer)) { |
if (GetPrecedence(indexer.TargetObject) >= GetPrecedence(indexer)) { |
||||||
indexer.TargetObject = Deparenthesize(indexer.TargetObject); |
indexer.TargetObject = Deparenthesize(indexer.TargetObject); |
||||||
} |
} |
||||||
return base.VisitIndexerExpression(indexer, data); |
return base.VisitIndexerExpression(indexer, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) |
public override object VisitIfElseStatement(IfElseStatement ifElseStatement, object data) |
||||||
{ |
{ |
||||||
ifElseStatement.Condition = Deparenthesize(ifElseStatement.Condition); |
ifElseStatement.Condition = Deparenthesize(ifElseStatement.Condition); |
||||||
return base.VisitIfElseStatement(ifElseStatement, data); |
return base.VisitIfElseStatement(ifElseStatement, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data) |
public override object VisitVariableDeclaration(VariableDeclaration variableDeclaration, object data) |
||||||
{ |
{ |
||||||
variableDeclaration.Initializer = Deparenthesize(variableDeclaration.Initializer); |
variableDeclaration.Initializer = Deparenthesize(variableDeclaration.Initializer); |
||||||
return base.VisitVariableDeclaration(variableDeclaration, data); |
return base.VisitVariableDeclaration(variableDeclaration, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) |
public override object VisitUnaryOperatorExpression(UnaryOperatorExpression unary, object data) |
||||||
{ |
{ |
||||||
if (GetPrecedence(unary.Expression) > GetPrecedence(unary)) { |
if (GetPrecedence(unary.Expression) > GetPrecedence(unary)) { |
||||||
unary.Expression = Deparenthesize(unary.Expression); |
unary.Expression = Deparenthesize(unary.Expression); |
||||||
} |
} |
||||||
return base.VisitUnaryOperatorExpression(unary, data); |
return base.VisitUnaryOperatorExpression(unary, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitMemberReferenceExpression(MemberReferenceExpression memberRef, object data) |
public override object VisitMemberReferenceExpression(MemberReferenceExpression memberRef, object data) |
||||||
{ |
{ |
||||||
if (GetPrecedence(memberRef.TargetObject) >= GetPrecedence(memberRef)) { |
if (GetPrecedence(memberRef.TargetObject) >= GetPrecedence(memberRef)) { |
||||||
memberRef.TargetObject = Deparenthesize(memberRef.TargetObject); |
memberRef.TargetObject = Deparenthesize(memberRef.TargetObject); |
||||||
} |
} |
||||||
return base.VisitMemberReferenceExpression(memberRef, data); |
return base.VisitMemberReferenceExpression(memberRef, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitInvocationExpression(InvocationExpression invocation, object data) |
public override object VisitInvocationExpression(InvocationExpression invocation, object data) |
||||||
{ |
{ |
||||||
if (GetPrecedence(invocation.TargetObject) >= GetPrecedence(invocation)) { |
if (GetPrecedence(invocation.TargetObject) >= GetPrecedence(invocation)) { |
||||||
invocation.TargetObject = Deparenthesize(invocation.TargetObject); |
invocation.TargetObject = Deparenthesize(invocation.TargetObject); |
||||||
} |
} |
||||||
for(int i = 0; i < invocation.Arguments.Count; i++) { |
for(int i = 0; i < invocation.Arguments.Count; i++) { |
||||||
invocation.Arguments[i] = Deparenthesize(invocation.Arguments[i]); |
invocation.Arguments[i] = Deparenthesize(invocation.Arguments[i]); |
||||||
} |
} |
||||||
return base.VisitInvocationExpression(invocation, data); |
return base.VisitInvocationExpression(invocation, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binary, object data) |
public override object VisitBinaryOperatorExpression(BinaryOperatorExpression binary, object data) |
||||||
{ |
{ |
||||||
int? myPrecedence = GetPrecedence(binary); |
int? myPrecedence = GetPrecedence(binary); |
||||||
if (GetPrecedence(binary.Left) > myPrecedence) { |
if (GetPrecedence(binary.Left) > myPrecedence) { |
||||||
binary.Left = Deparenthesize(binary.Left); |
binary.Left = Deparenthesize(binary.Left); |
||||||
} |
} |
||||||
if (GetPrecedence(binary.Right) > myPrecedence) { |
if (GetPrecedence(binary.Right) > myPrecedence) { |
||||||
binary.Right = Deparenthesize(binary.Right); |
binary.Right = Deparenthesize(binary.Right); |
||||||
} |
} |
||||||
// Associativity
|
// Associativity
|
||||||
if (GetPrecedence(binary.Left) == myPrecedence && myPrecedence.HasValue) { |
if (GetPrecedence(binary.Left) == myPrecedence && myPrecedence.HasValue) { |
||||||
binary.Left = Deparenthesize(binary.Left); |
binary.Left = Deparenthesize(binary.Left); |
||||||
} |
} |
||||||
return base.VisitBinaryOperatorExpression(binary, data); |
return base.VisitBinaryOperatorExpression(binary, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) |
public override object VisitExpressionStatement(ExpressionStatement expressionStatement, object data) |
||||||
{ |
{ |
||||||
expressionStatement.Expression = Deparenthesize(expressionStatement.Expression); |
expressionStatement.Expression = Deparenthesize(expressionStatement.Expression); |
||||||
return base.VisitExpressionStatement(expressionStatement, data); |
return base.VisitExpressionStatement(expressionStatement, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitForStatement(ForStatement forStatement, object data) |
public override object VisitForStatement(ForStatement forStatement, object data) |
||||||
{ |
{ |
||||||
forStatement.Condition = Deparenthesize(forStatement.Condition); |
forStatement.Condition = Deparenthesize(forStatement.Condition); |
||||||
return base.VisitForStatement(forStatement, data); |
return base.VisitForStatement(forStatement, data); |
||||||
} |
} |
||||||
|
|
||||||
Expression Deparenthesize(Expression expr) |
Expression Deparenthesize(Expression expr) |
||||||
{ |
{ |
||||||
if (expr is ParenthesizedExpression) { |
if (expr is ParenthesizedExpression) { |
||||||
return Deparenthesize(((ParenthesizedExpression)expr).Expression); |
return Deparenthesize(((ParenthesizedExpression)expr).Expression); |
||||||
} else { |
} else { |
||||||
return expr; |
return expr; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
int? GetPrecedence(Expression expr) |
int? GetPrecedence(Expression expr) |
||||||
{ |
{ |
||||||
if (expr is ParenthesizedExpression) { |
if (expr is ParenthesizedExpression) { |
||||||
return GetPrecedence(((ParenthesizedExpression)expr).Expression); |
return GetPrecedence(((ParenthesizedExpression)expr).Expression); |
||||||
} |
} |
||||||
|
|
||||||
UnaryOperatorExpression unary = expr as UnaryOperatorExpression; |
UnaryOperatorExpression unary = expr as UnaryOperatorExpression; |
||||||
BinaryOperatorExpression binary = expr as BinaryOperatorExpression; |
BinaryOperatorExpression binary = expr as BinaryOperatorExpression; |
||||||
|
|
||||||
// see http://msdn2.microsoft.com/en-us/library/ms173145.aspx
|
// see http://msdn2.microsoft.com/en-us/library/ms173145.aspx
|
||||||
|
|
||||||
// Primary
|
// Primary
|
||||||
// x.y
|
// x.y
|
||||||
if (expr is MemberReferenceExpression) return 15; |
if (expr is MemberReferenceExpression) return 15; |
||||||
// f(x)
|
// f(x)
|
||||||
if (expr is InvocationExpression) return 15; |
if (expr is InvocationExpression) return 15; |
||||||
// a[x]
|
// a[x]
|
||||||
if (expr is IndexerExpression) return 15; |
if (expr is IndexerExpression) return 15; |
||||||
// x++
|
// x++
|
||||||
if (unary != null && unary.Op == UnaryOperatorType.PostIncrement) return 15; |
if (unary != null && unary.Op == UnaryOperatorType.PostIncrement) return 15; |
||||||
// x--
|
// x--
|
||||||
if (unary != null && unary.Op == UnaryOperatorType.PostDecrement) return 15; |
if (unary != null && unary.Op == UnaryOperatorType.PostDecrement) return 15; |
||||||
// new T(...)
|
// new T(...)
|
||||||
if (expr is ObjectCreateExpression) return 15; |
if (expr is ObjectCreateExpression) return 15; |
||||||
// new T(...){...}
|
// new T(...){...}
|
||||||
// new {...}
|
// new {...}
|
||||||
// new T[...]
|
// new T[...]
|
||||||
if (expr is ArrayCreateExpression) return 15; |
if (expr is ArrayCreateExpression) return 15; |
||||||
// typeof(T)
|
// typeof(T)
|
||||||
if (expr is TypeOfExpression) return 15; |
if (expr is TypeOfExpression) return 15; |
||||||
// checked(x)
|
// checked(x)
|
||||||
// unchecked(x)
|
// unchecked(x)
|
||||||
// default (T)
|
// default (T)
|
||||||
// delegate {}
|
// delegate {}
|
||||||
// Unary
|
// Unary
|
||||||
// +x
|
// +x
|
||||||
if (unary != null && unary.Op == UnaryOperatorType.Plus) return 14; |
if (unary != null && unary.Op == UnaryOperatorType.Plus) return 14; |
||||||
// -x
|
// -x
|
||||||
if (unary != null && unary.Op == UnaryOperatorType.Minus) return 14; |
if (unary != null && unary.Op == UnaryOperatorType.Minus) return 14; |
||||||
// !x
|
// !x
|
||||||
if (unary != null && unary.Op == UnaryOperatorType.Not) return 14; |
if (unary != null && unary.Op == UnaryOperatorType.Not) return 14; |
||||||
// ~x
|
// ~x
|
||||||
if (unary != null && unary.Op == UnaryOperatorType.BitNot) return 14; |
if (unary != null && unary.Op == UnaryOperatorType.BitNot) return 14; |
||||||
// ++x
|
// ++x
|
||||||
if (unary != null && unary.Op == UnaryOperatorType.Increment) return 14; |
if (unary != null && unary.Op == UnaryOperatorType.Increment) return 14; |
||||||
// --x
|
// --x
|
||||||
if (unary != null && unary.Op == UnaryOperatorType.Decrement) return 14; |
if (unary != null && unary.Op == UnaryOperatorType.Decrement) return 14; |
||||||
// (T)x
|
// (T)x
|
||||||
if (expr is CastExpression) return 14; |
if (expr is CastExpression) return 14; |
||||||
// Multiplicative
|
// Multiplicative
|
||||||
// *, ,
|
// *, ,
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.Multiply) return 13; |
if (binary != null && binary.Op == BinaryOperatorType.Multiply) return 13; |
||||||
// /
|
// /
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.Divide) return 13; |
if (binary != null && binary.Op == BinaryOperatorType.Divide) return 13; |
||||||
// %
|
// %
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.Modulus) return 13; |
if (binary != null && binary.Op == BinaryOperatorType.Modulus) return 13; |
||||||
// Additive
|
// Additive
|
||||||
// x + y
|
// x + y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.Add) return 12; |
if (binary != null && binary.Op == BinaryOperatorType.Add) return 12; |
||||||
// x - y
|
// x - y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.Subtract) return 12; |
if (binary != null && binary.Op == BinaryOperatorType.Subtract) return 12; |
||||||
// Shift
|
// Shift
|
||||||
// x << y
|
// x << y
|
||||||
// x >> y
|
// x >> y
|
||||||
// Relational and Type Testing
|
// Relational and Type Testing
|
||||||
// x < y
|
// x < y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.LessThan) return 10; |
if (binary != null && binary.Op == BinaryOperatorType.LessThan) return 10; |
||||||
// x > y
|
// x > y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.GreaterThan) return 10; |
if (binary != null && binary.Op == BinaryOperatorType.GreaterThan) return 10; |
||||||
// x <= y
|
// x <= y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.LessThanOrEqual) return 10; |
if (binary != null && binary.Op == BinaryOperatorType.LessThanOrEqual) return 10; |
||||||
// x >= y
|
// x >= y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.GreaterThanOrEqual) return 10; |
if (binary != null && binary.Op == BinaryOperatorType.GreaterThanOrEqual) return 10; |
||||||
// x is T
|
// x is T
|
||||||
// x as T
|
// x as T
|
||||||
// Equality
|
// Equality
|
||||||
// x == y
|
// x == y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.Equality) return 9; |
if (binary != null && binary.Op == BinaryOperatorType.Equality) return 9; |
||||||
// x != y
|
// x != y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.InEquality) return 9; |
if (binary != null && binary.Op == BinaryOperatorType.InEquality) return 9; |
||||||
// Logical AND
|
// Logical AND
|
||||||
// x & y
|
// x & y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.BitwiseAnd) return 8; |
if (binary != null && binary.Op == BinaryOperatorType.BitwiseAnd) return 8; |
||||||
// Logical XOR
|
// Logical XOR
|
||||||
// x ^ y
|
// x ^ y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.ExclusiveOr) return 7; |
if (binary != null && binary.Op == BinaryOperatorType.ExclusiveOr) return 7; |
||||||
// Logical OR
|
// Logical OR
|
||||||
// x | y
|
// x | y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.BitwiseOr) return 6; |
if (binary != null && binary.Op == BinaryOperatorType.BitwiseOr) return 6; |
||||||
// Conditional AND
|
// Conditional AND
|
||||||
// x && y
|
// x && y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.LogicalAnd) return 5; |
if (binary != null && binary.Op == BinaryOperatorType.LogicalAnd) return 5; |
||||||
// Conditional OR
|
// Conditional OR
|
||||||
// x || y
|
// x || y
|
||||||
if (binary != null && binary.Op == BinaryOperatorType.LogicalOr) return 4; |
if (binary != null && binary.Op == BinaryOperatorType.LogicalOr) return 4; |
||||||
// Null coalescing
|
// Null coalescing
|
||||||
// X ?? y
|
// X ?? y
|
||||||
// Conditional
|
// Conditional
|
||||||
// x ?: y : z
|
// x ?: y : z
|
||||||
// Assignment or anonymous function
|
// Assignment or anonymous function
|
||||||
// =, , =>
|
// =, , =>
|
||||||
if (expr is AssignmentExpression) return 1; |
if (expr is AssignmentExpression) return 1; |
||||||
// x op= y
|
// x op= y
|
||||||
// (T x) => y
|
// (T x) => y
|
||||||
|
|
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,75 +1,75 @@ |
|||||||
using System; |
using System; |
||||||
|
|
||||||
using Ast = ICSharpCode.NRefactory.Ast; |
using Ast = ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Visitors; |
using ICSharpCode.NRefactory.Visitors; |
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
namespace Decompiler.Transforms.Ast |
||||||
{ |
{ |
||||||
public class RestoreLoop: AbstractAstTransformer |
public class RestoreLoop: AbstractAstTransformer |
||||||
{ |
{ |
||||||
public override object VisitForStatement(ForStatement forStatement, object data) |
public override object VisitForStatement(ForStatement forStatement, object data) |
||||||
{ |
{ |
||||||
base.VisitForStatement(forStatement, data); |
base.VisitForStatement(forStatement, data); |
||||||
|
|
||||||
// Restore loop initializer
|
// Restore loop initializer
|
||||||
if (forStatement.Initializers.Count == 0) { |
if (forStatement.Initializers.Count == 0) { |
||||||
LocalVariableDeclaration varDeclr = forStatement.Previous() as LocalVariableDeclaration; |
LocalVariableDeclaration varDeclr = forStatement.Previous() as LocalVariableDeclaration; |
||||||
if (varDeclr != null) { |
if (varDeclr != null) { |
||||||
varDeclr.ReplaceWith(Statement.Null); |
varDeclr.ReplaceWith(Statement.Null); |
||||||
forStatement.Initializers.Add(varDeclr); |
forStatement.Initializers.Add(varDeclr); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
// Restore loop condition
|
// Restore loop condition
|
||||||
if (forStatement.Condition.IsNull && |
if (forStatement.Condition.IsNull && |
||||||
forStatement.EmbeddedStatement.Children.Count >= 3) |
forStatement.EmbeddedStatement.Children.Count >= 3) |
||||||
{ |
{ |
||||||
IfElseStatement condition = forStatement.EmbeddedStatement.Children[0] as IfElseStatement; |
IfElseStatement condition = forStatement.EmbeddedStatement.Children[0] as IfElseStatement; |
||||||
BreakStatement breakStmt = forStatement.EmbeddedStatement.Children[1] as BreakStatement; |
BreakStatement breakStmt = forStatement.EmbeddedStatement.Children[1] as BreakStatement; |
||||||
LabelStatement label = forStatement.EmbeddedStatement.Children[2] as LabelStatement; |
LabelStatement label = forStatement.EmbeddedStatement.Children[2] as LabelStatement; |
||||||
if (condition != null && breakStmt != null && label != null && |
if (condition != null && breakStmt != null && label != null && |
||||||
condition.TrueStatement.Count == 1) |
condition.TrueStatement.Count == 1) |
||||||
{ |
{ |
||||||
GotoStatement gotoStmt = condition.TrueStatement[0] as GotoStatement; |
GotoStatement gotoStmt = condition.TrueStatement[0] as GotoStatement; |
||||||
if (gotoStmt != null && gotoStmt.Label == label.Label) { |
if (gotoStmt != null && gotoStmt.Label == label.Label) { |
||||||
condition.Remove(); |
condition.Remove(); |
||||||
breakStmt.Remove(); |
breakStmt.Remove(); |
||||||
forStatement.Condition = condition.Condition; |
forStatement.Condition = condition.Condition; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
// Restore loop condition (version 2)
|
// Restore loop condition (version 2)
|
||||||
if (forStatement.Condition.IsNull) { |
if (forStatement.Condition.IsNull) { |
||||||
IfElseStatement condition = forStatement.EmbeddedStatement.Children.First as IfElseStatement; |
IfElseStatement condition = forStatement.EmbeddedStatement.Children.First as IfElseStatement; |
||||||
if (condition != null && |
if (condition != null && |
||||||
condition.TrueStatement.Count == 1 && |
condition.TrueStatement.Count == 1 && |
||||||
condition.TrueStatement[0] is BlockStatement && |
condition.TrueStatement[0] is BlockStatement && |
||||||
condition.TrueStatement[0].Children.Count == 1 && |
condition.TrueStatement[0].Children.Count == 1 && |
||||||
condition.TrueStatement[0].Children.First is BreakStatement && |
condition.TrueStatement[0].Children.First is BreakStatement && |
||||||
condition.FalseStatement.Count == 1 && |
condition.FalseStatement.Count == 1 && |
||||||
condition.FalseStatement[0] is BlockStatement && |
condition.FalseStatement[0] is BlockStatement && |
||||||
condition.FalseStatement[0].Children.Count == 0) |
condition.FalseStatement[0].Children.Count == 0) |
||||||
{ |
{ |
||||||
condition.Remove(); |
condition.Remove(); |
||||||
forStatement.Condition = new UnaryOperatorExpression(condition.Condition, UnaryOperatorType.Not); |
forStatement.Condition = new UnaryOperatorExpression(condition.Condition, UnaryOperatorType.Not); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
// Restore loop iterator
|
// Restore loop iterator
|
||||||
if (forStatement.EmbeddedStatement.Children.Count > 0 && |
if (forStatement.EmbeddedStatement.Children.Count > 0 && |
||||||
forStatement.Iterator.Count == 0) |
forStatement.Iterator.Count == 0) |
||||||
{ |
{ |
||||||
ExpressionStatement lastStmt = forStatement.EmbeddedStatement.Children.Last as ExpressionStatement; |
ExpressionStatement lastStmt = forStatement.EmbeddedStatement.Children.Last as ExpressionStatement; |
||||||
if (lastStmt != null && |
if (lastStmt != null && |
||||||
(lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) { |
(lastStmt.Expression is AssignmentExpression || lastStmt.Expression is UnaryOperatorExpression)) { |
||||||
lastStmt.Remove(); |
lastStmt.Remove(); |
||||||
forStatement.Iterator.Add(lastStmt); |
forStatement.Iterator.Add(lastStmt); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,91 +1,91 @@ |
|||||||
using System; |
using System; |
||||||
|
|
||||||
using Ast = ICSharpCode.NRefactory.Ast; |
using Ast = ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Ast; |
using ICSharpCode.NRefactory.Ast; |
||||||
using ICSharpCode.NRefactory.Visitors; |
using ICSharpCode.NRefactory.Visitors; |
||||||
|
|
||||||
namespace Decompiler.Transforms.Ast |
namespace Decompiler.Transforms.Ast |
||||||
{ |
{ |
||||||
public class SimplifyTypeReferences: AbstractAstTransformer |
public class SimplifyTypeReferences: AbstractAstTransformer |
||||||
{ |
{ |
||||||
string currentNamepace = string.Empty; |
string currentNamepace = string.Empty; |
||||||
string currentClass = null; |
string currentClass = null; |
||||||
|
|
||||||
public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) |
public override object VisitNamespaceDeclaration(NamespaceDeclaration namespaceDeclaration, object data) |
||||||
{ |
{ |
||||||
currentNamepace = namespaceDeclaration.Name; |
currentNamepace = namespaceDeclaration.Name; |
||||||
base.VisitNamespaceDeclaration(namespaceDeclaration, data); |
base.VisitNamespaceDeclaration(namespaceDeclaration, data); |
||||||
currentNamepace = string.Empty; |
currentNamepace = string.Empty; |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) |
public override object VisitTypeDeclaration(TypeDeclaration typeDeclaration, object data) |
||||||
{ |
{ |
||||||
currentClass = currentNamepace + "." + typeDeclaration.Name; |
currentClass = currentNamepace + "." + typeDeclaration.Name; |
||||||
base.VisitTypeDeclaration(typeDeclaration, data); |
base.VisitTypeDeclaration(typeDeclaration, data); |
||||||
currentClass = null; |
currentClass = null; |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) |
public override object VisitMemberReferenceExpression(MemberReferenceExpression memberReferenceExpression, object data) |
||||||
{ |
{ |
||||||
IdentifierExpression id = memberReferenceExpression.TargetObject as IdentifierExpression; |
IdentifierExpression id = memberReferenceExpression.TargetObject as IdentifierExpression; |
||||||
if (id != null) { |
if (id != null) { |
||||||
if (id.Identifier == "System" || id.Identifier == currentClass) { |
if (id.Identifier == "System" || id.Identifier == currentClass) { |
||||||
ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName)); |
ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName)); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
if (id.Identifier.StartsWith("System.")) { |
if (id.Identifier.StartsWith("System.")) { |
||||||
id.Identifier = id.Identifier.Replace("System.", ""); |
id.Identifier = id.Identifier.Replace("System.", ""); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
if (memberReferenceExpression.TargetObject is ThisReferenceExpression) { |
if (memberReferenceExpression.TargetObject is ThisReferenceExpression) { |
||||||
ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName)); |
ReplaceCurrentNode(new IdentifierExpression(memberReferenceExpression.MemberName)); |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
return base.VisitMemberReferenceExpression(memberReferenceExpression, data); |
return base.VisitMemberReferenceExpression(memberReferenceExpression, data); |
||||||
} |
} |
||||||
|
|
||||||
public override object VisitTypeReference(TypeReference typeReference, object data) |
public override object VisitTypeReference(TypeReference typeReference, object data) |
||||||
{ |
{ |
||||||
string fullName = typeReference.Type; |
string fullName = typeReference.Type; |
||||||
string shortName = GetShortName(fullName); |
string shortName = GetShortName(fullName); |
||||||
if (shortName != null) { |
if (shortName != null) { |
||||||
typeReference.Type = shortName; |
typeReference.Type = shortName; |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
if (fullName.EndsWith("[]")) { |
if (fullName.EndsWith("[]")) { |
||||||
shortName = GetShortName(fullName.Replace("[]","")); |
shortName = GetShortName(fullName.Replace("[]","")); |
||||||
if (shortName != null) { |
if (shortName != null) { |
||||||
typeReference.Type = shortName + "[]"; |
typeReference.Type = shortName + "[]"; |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
|
|
||||||
public string GetShortName(string fullName) |
public string GetShortName(string fullName) |
||||||
{ |
{ |
||||||
switch(fullName) { |
switch(fullName) { |
||||||
case "System.Boolean": return "bool"; |
case "System.Boolean": return "bool"; |
||||||
case "System.Byte": return "byte"; |
case "System.Byte": return "byte"; |
||||||
case "System.Char": return "char"; |
case "System.Char": return "char"; |
||||||
case "System.Decimal": return "decimal"; |
case "System.Decimal": return "decimal"; |
||||||
case "System.Double": return "double"; |
case "System.Double": return "double"; |
||||||
case "System.Single": return "float"; |
case "System.Single": return "float"; |
||||||
case "System.Int32": return "int"; |
case "System.Int32": return "int"; |
||||||
case "System.Int64": return "long"; |
case "System.Int64": return "long"; |
||||||
case "System.Object": return "object"; |
case "System.Object": return "object"; |
||||||
case "System.SByte": return "sbyte"; |
case "System.SByte": return "sbyte"; |
||||||
case "System.Int16": return "short"; |
case "System.Int16": return "short"; |
||||||
case "System.String": return "string"; |
case "System.String": return "string"; |
||||||
case "System.UInt32": return "uint"; |
case "System.UInt32": return "uint"; |
||||||
case "System.UInt64": return "ulong"; |
case "System.UInt64": return "ulong"; |
||||||
case "System.UInt16": return "ushort"; |
case "System.UInt16": return "ushort"; |
||||||
case "System.Void": return "void"; |
case "System.Void": return "void"; |
||||||
} |
} |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,192 +1,192 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections; |
using System.Collections; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using System.Diagnostics; |
using System.Diagnostics; |
||||||
|
|
||||||
namespace Decompiler.ControlFlow |
namespace Decompiler.ControlFlow |
||||||
{ |
{ |
||||||
public abstract partial class Node |
public abstract partial class Node |
||||||
{ |
{ |
||||||
public void Optimize() |
public void Optimize() |
||||||
{ |
{ |
||||||
if (Options.ReduceLoops) { |
if (Options.ReduceLoops) { |
||||||
OptimizeLoops(); |
OptimizeLoops(); |
||||||
} |
} |
||||||
if (Options.ReduceConditonals) { |
if (Options.ReduceConditonals) { |
||||||
OptimizeShortCircuits(); |
OptimizeShortCircuits(); |
||||||
OptimizeConditions(); |
OptimizeConditions(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public void OptimizeLoops() |
public void OptimizeLoops() |
||||||
{ |
{ |
||||||
Reset: |
Reset: |
||||||
foreach(Node child in this.Childs) { |
foreach(Node child in this.Childs) { |
||||||
if (child.Predecessors.Count == 1) { |
if (child.Predecessors.Count == 1) { |
||||||
Node predecessor = child.Predecessors[0]; |
Node predecessor = child.Predecessors[0]; |
||||||
Node mergedNode; |
Node mergedNode; |
||||||
if (child.Successors.Contains(predecessor)) { |
if (child.Successors.Contains(predecessor)) { |
||||||
mergedNode = MergeChilds<Loop>(predecessor, child); |
mergedNode = MergeChilds<Loop>(predecessor, child); |
||||||
} else { |
} else { |
||||||
mergedNode = MergeChilds<AcyclicGraph>(predecessor, child); |
mergedNode = MergeChilds<AcyclicGraph>(predecessor, child); |
||||||
} |
} |
||||||
mergedNode.FalttenAcyclicChilds(); |
mergedNode.FalttenAcyclicChilds(); |
||||||
goto Reset; |
goto Reset; |
||||||
} |
} |
||||||
} |
} |
||||||
// If the result is single acyclic node, eliminate it
|
// If the result is single acyclic node, eliminate it
|
||||||
if (this.Childs.Count == 1 && this.HeadChild is AcyclicGraph) { |
if (this.Childs.Count == 1 && this.HeadChild is AcyclicGraph) { |
||||||
Node headChild = this.HeadChild; |
Node headChild = this.HeadChild; |
||||||
this.Childs.Remove(this.HeadChild); |
this.Childs.Remove(this.HeadChild); |
||||||
headChild.Childs.MoveTo(this); |
headChild.Childs.MoveTo(this); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
NodeCollection GetReachableNodes() |
NodeCollection GetReachableNodes() |
||||||
{ |
{ |
||||||
NodeCollection reachableNodes = new NodeCollection(); |
NodeCollection reachableNodes = new NodeCollection(); |
||||||
reachableNodes.Add(this); |
reachableNodes.Add(this); |
||||||
for(int i = 0; i < reachableNodes.Count; i++) { |
for(int i = 0; i < reachableNodes.Count; i++) { |
||||||
foreach(Node alsoReachable in reachableNodes[i].Successors) { |
foreach(Node alsoReachable in reachableNodes[i].Successors) { |
||||||
// Do not go though the head child
|
// Do not go though the head child
|
||||||
if (alsoReachable != this.Parent.HeadChild) { |
if (alsoReachable != this.Parent.HeadChild) { |
||||||
reachableNodes.Add(alsoReachable); |
reachableNodes.Add(alsoReachable); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
return reachableNodes; |
return reachableNodes; |
||||||
} |
} |
||||||
|
|
||||||
public void OptimizeShortCircuits() |
public void OptimizeShortCircuits() |
||||||
{ |
{ |
||||||
foreach(Node child in this.Childs) { |
foreach(Node child in this.Childs) { |
||||||
if (child is Loop) { |
if (child is Loop) { |
||||||
child.OptimizeShortCircuits(); |
child.OptimizeShortCircuits(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
Reset: |
Reset: |
||||||
foreach(Node child in this.Childs) { |
foreach(Node child in this.Childs) { |
||||||
if (TryOptimizeShortCircuit(child)) { |
if (TryOptimizeShortCircuit(child)) { |
||||||
goto Reset; |
goto Reset; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public static bool TryOptimizeShortCircuit(Node head) |
public static bool TryOptimizeShortCircuit(Node head) |
||||||
{ |
{ |
||||||
if ((head is BasicBlock) && |
if ((head is BasicBlock) && |
||||||
(head as BasicBlock).BranchBasicBlock != null && |
(head as BasicBlock).BranchBasicBlock != null && |
||||||
(head as BasicBlock).FallThroughBasicBlock != null) { |
(head as BasicBlock).FallThroughBasicBlock != null) { |
||||||
head.Parent.MergeChilds<SimpleBranch>(head); |
head.Parent.MergeChilds<SimpleBranch>(head); |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
|
|
||||||
Branch top = head as Branch; |
Branch top = head as Branch; |
||||||
if (top == null) return false; |
if (top == null) return false; |
||||||
|
|
||||||
Branch left = head.FloatUpToNeighbours(top.TrueSuccessor) as Branch; |
Branch left = head.FloatUpToNeighbours(top.TrueSuccessor) as Branch; |
||||||
Branch right = head.FloatUpToNeighbours(top.FalseSuccessor) as Branch; |
Branch right = head.FloatUpToNeighbours(top.FalseSuccessor) as Branch; |
||||||
|
|
||||||
// A & B
|
// A & B
|
||||||
if (left != null && |
if (left != null && |
||||||
left.Predecessors.Count == 1 && |
left.Predecessors.Count == 1 && |
||||||
left.FalseSuccessor == top.FalseSuccessor) { |
left.FalseSuccessor == top.FalseSuccessor) { |
||||||
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left); |
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left); |
||||||
scBranch.Operator = ShortCircuitOperator.LeftAndRight; |
scBranch.Operator = ShortCircuitOperator.LeftAndRight; |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
|
|
||||||
// ~A | B
|
// ~A | B
|
||||||
if (left != null && |
if (left != null && |
||||||
left.Predecessors.Count == 1 && |
left.Predecessors.Count == 1 && |
||||||
left.TrueSuccessor == top.FalseSuccessor) { |
left.TrueSuccessor == top.FalseSuccessor) { |
||||||
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left); |
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, left); |
||||||
scBranch.Operator = ShortCircuitOperator.NotLeftOrRight; |
scBranch.Operator = ShortCircuitOperator.NotLeftOrRight; |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
|
|
||||||
// A | B
|
// A | B
|
||||||
if (right != null && |
if (right != null && |
||||||
right.Predecessors.Count == 1 && |
right.Predecessors.Count == 1 && |
||||||
right.TrueSuccessor == top.TrueSuccessor) { |
right.TrueSuccessor == top.TrueSuccessor) { |
||||||
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right); |
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right); |
||||||
scBranch.Operator = ShortCircuitOperator.LeftOrRight; |
scBranch.Operator = ShortCircuitOperator.LeftOrRight; |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
|
|
||||||
// ~A & B
|
// ~A & B
|
||||||
if (right != null && |
if (right != null && |
||||||
right.Predecessors.Count == 1 && |
right.Predecessors.Count == 1 && |
||||||
right.FalseSuccessor == top.TrueSuccessor) { |
right.FalseSuccessor == top.TrueSuccessor) { |
||||||
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right); |
ShortCircuitBranch scBranch = top.Parent.MergeChilds<ShortCircuitBranch>(top, right); |
||||||
scBranch.Operator = ShortCircuitOperator.NotLeftAndRight; |
scBranch.Operator = ShortCircuitOperator.NotLeftAndRight; |
||||||
return true; |
return true; |
||||||
} |
} |
||||||
|
|
||||||
return false; |
return false; |
||||||
} |
} |
||||||
|
|
||||||
public void OptimizeConditions() |
public void OptimizeConditions() |
||||||
{ |
{ |
||||||
foreach(Node child in this.Childs) { |
foreach(Node child in this.Childs) { |
||||||
if (child is Loop) { |
if (child is Loop) { |
||||||
child.OptimizeConditions(); |
child.OptimizeConditions(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
Node conditionNode = this.HeadChild; |
Node conditionNode = this.HeadChild; |
||||||
while(conditionNode != null) { |
while(conditionNode != null) { |
||||||
// Keep looking for some conditional block
|
// Keep looking for some conditional block
|
||||||
if (conditionNode is Branch) { |
if (conditionNode is Branch) { |
||||||
// Found start of conditional
|
// Found start of conditional
|
||||||
OptimizeIf((Branch)conditionNode); |
OptimizeIf((Branch)conditionNode); |
||||||
// Restart
|
// Restart
|
||||||
conditionNode = this.HeadChild; |
conditionNode = this.HeadChild; |
||||||
continue; |
continue; |
||||||
} else if (conditionNode.Successors.Count > 0) { |
} else if (conditionNode.Successors.Count > 0) { |
||||||
// Keep looking down
|
// Keep looking down
|
||||||
conditionNode = conditionNode.Successors[0]; |
conditionNode = conditionNode.Successors[0]; |
||||||
if (conditionNode == this.HeadChild) { |
if (conditionNode == this.HeadChild) { |
||||||
return; |
return; |
||||||
} |
} |
||||||
continue; // Next
|
continue; // Next
|
||||||
} else { |
} else { |
||||||
return; // End of block
|
return; // End of block
|
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public static void OptimizeIf(Branch condition) |
public static void OptimizeIf(Branch condition) |
||||||
{ |
{ |
||||||
Node trueStart = condition.FloatUpToNeighbours(condition.TrueSuccessor); |
Node trueStart = condition.FloatUpToNeighbours(condition.TrueSuccessor); |
||||||
Node falseStart = condition.FloatUpToNeighbours(condition.FalseSuccessor); |
Node falseStart = condition.FloatUpToNeighbours(condition.FalseSuccessor); |
||||||
|
|
||||||
NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty; |
NodeCollection trueReachable = trueStart != null ? trueStart.GetReachableNodes() : NodeCollection.Empty; |
||||||
NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty; |
NodeCollection falseReachable = falseStart != null ? falseStart.GetReachableNodes() : NodeCollection.Empty; |
||||||
NodeCollection commonReachable = NodeCollection.Intersect(trueReachable, falseReachable); |
NodeCollection commonReachable = NodeCollection.Intersect(trueReachable, falseReachable); |
||||||
|
|
||||||
NodeCollection trueNodes = trueReachable.Clone(); |
NodeCollection trueNodes = trueReachable.Clone(); |
||||||
trueNodes.RemoveRange(commonReachable); |
trueNodes.RemoveRange(commonReachable); |
||||||
NodeCollection falseNodes = falseReachable.Clone(); |
NodeCollection falseNodes = falseReachable.Clone(); |
||||||
falseNodes.RemoveRange(commonReachable); |
falseNodes.RemoveRange(commonReachable); |
||||||
|
|
||||||
// Replace the basic block with condition node
|
// Replace the basic block with condition node
|
||||||
Node conditionParent = condition.Parent; |
Node conditionParent = condition.Parent; |
||||||
int conditionIndex = condition.Index; |
int conditionIndex = condition.Index; |
||||||
ConditionalNode conditionalNode = new ConditionalNode(condition); |
ConditionalNode conditionalNode = new ConditionalNode(condition); |
||||||
conditionalNode.MoveTo(conditionParent, conditionIndex); |
conditionalNode.MoveTo(conditionParent, conditionIndex); |
||||||
|
|
||||||
// If there are no common nodes, let the 'true' block be the default
|
// If there are no common nodes, let the 'true' block be the default
|
||||||
if (commonReachable.Count > 0) { |
if (commonReachable.Count > 0) { |
||||||
trueNodes.MoveTo(conditionalNode.TrueBody); |
trueNodes.MoveTo(conditionalNode.TrueBody); |
||||||
} |
} |
||||||
|
|
||||||
falseNodes.MoveTo(conditionalNode.FalseBody); |
falseNodes.MoveTo(conditionalNode.FalseBody); |
||||||
|
|
||||||
// Optimize the created subtrees
|
// Optimize the created subtrees
|
||||||
conditionalNode.TrueBody.OptimizeConditions(); |
conditionalNode.TrueBody.OptimizeConditions(); |
||||||
conditionalNode.FalseBody.OptimizeConditions(); |
conditionalNode.FalseBody.OptimizeConditions(); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,233 +1,233 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections; |
using System.Collections; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
|
|
||||||
namespace Decompiler.ControlFlow |
namespace Decompiler.ControlFlow |
||||||
{ |
{ |
||||||
public abstract partial class Node |
public abstract partial class Node |
||||||
{ |
{ |
||||||
public static int NextNodeID = 1; |
public static int NextNodeID = 1; |
||||||
|
|
||||||
int id; |
int id; |
||||||
string label; |
string label; |
||||||
Node parent; |
Node parent; |
||||||
NodeCollection childs = new NodeCollection(); |
NodeCollection childs = new NodeCollection(); |
||||||
|
|
||||||
// Structural and linking cache
|
// Structural and linking cache
|
||||||
NodeCollection basicBlocks_cache = null; |
NodeCollection basicBlocks_cache = null; |
||||||
NodeCollection predecessors_cache = null; |
NodeCollection predecessors_cache = null; |
||||||
NodeCollection successors_cache = null; |
NodeCollection successors_cache = null; |
||||||
|
|
||||||
public int ID { |
public int ID { |
||||||
get { return id; } |
get { return id; } |
||||||
} |
} |
||||||
|
|
||||||
public string Label { |
public string Label { |
||||||
get { return label; } |
get { return label; } |
||||||
} |
} |
||||||
|
|
||||||
public Node Parent { |
public Node Parent { |
||||||
get { return parent; } |
get { return parent; } |
||||||
} |
} |
||||||
|
|
||||||
public Node HeadChild { |
public Node HeadChild { |
||||||
get { |
get { |
||||||
if (this.Childs.Count > 0) { |
if (this.Childs.Count > 0) { |
||||||
return this.Childs[0]; |
return this.Childs[0]; |
||||||
} else { |
} else { |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public NodeCollection Childs { |
public NodeCollection Childs { |
||||||
get { |
get { |
||||||
return childs; |
return childs; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
/// <summary> All basic blocks within the scope of this node (inclusive) </summary>
|
/// <summary> All basic blocks within the scope of this node (inclusive) </summary>
|
||||||
public NodeCollection BasicBlocks { |
public NodeCollection BasicBlocks { |
||||||
get { |
get { |
||||||
if (basicBlocks_cache == null) { |
if (basicBlocks_cache == null) { |
||||||
NodeCollection basicBlocks = new NodeCollection(); |
NodeCollection basicBlocks = new NodeCollection(); |
||||||
|
|
||||||
if (this is BasicBlock) { |
if (this is BasicBlock) { |
||||||
basicBlocks.Add(this); |
basicBlocks.Add(this); |
||||||
} |
} |
||||||
foreach(Node child in this.Childs) { |
foreach(Node child in this.Childs) { |
||||||
basicBlocks.AddRange(child.BasicBlocks); |
basicBlocks.AddRange(child.BasicBlocks); |
||||||
} |
} |
||||||
|
|
||||||
basicBlocks_cache = basicBlocks; |
basicBlocks_cache = basicBlocks; |
||||||
} |
} |
||||||
return basicBlocks_cache; |
return basicBlocks_cache; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
NodeCollection FloatUpToNeighbours(IEnumerable<BasicBlock> basicBlocks) |
NodeCollection FloatUpToNeighbours(IEnumerable<BasicBlock> basicBlocks) |
||||||
{ |
{ |
||||||
NodeCollection neighbours = new NodeCollection(); |
NodeCollection neighbours = new NodeCollection(); |
||||||
if (this.Parent != null) { |
if (this.Parent != null) { |
||||||
foreach(BasicBlock basicBlock in basicBlocks) { |
foreach(BasicBlock basicBlock in basicBlocks) { |
||||||
Node targetNode = FloatUpToNeighbours(basicBlock); |
Node targetNode = FloatUpToNeighbours(basicBlock); |
||||||
// The target is outside the scope of the parent node
|
// The target is outside the scope of the parent node
|
||||||
if (targetNode == null) continue; |
if (targetNode == null) continue; |
||||||
// This child is a loop
|
// This child is a loop
|
||||||
if (targetNode == this) continue; |
if (targetNode == this) continue; |
||||||
// We found a target in our scope
|
// We found a target in our scope
|
||||||
neighbours.Add(targetNode); |
neighbours.Add(targetNode); |
||||||
} |
} |
||||||
} |
} |
||||||
return neighbours; |
return neighbours; |
||||||
} |
} |
||||||
|
|
||||||
Node FloatUpToNeighbours(BasicBlock basicBlock) |
Node FloatUpToNeighbours(BasicBlock basicBlock) |
||||||
{ |
{ |
||||||
// Find neighbour coresponding to the basickBlock
|
// Find neighbour coresponding to the basickBlock
|
||||||
Node targetNode = basicBlock; |
Node targetNode = basicBlock; |
||||||
while(targetNode != null && targetNode.Parent != this.Parent) { |
while(targetNode != null && targetNode.Parent != this.Parent) { |
||||||
targetNode = targetNode.Parent; |
targetNode = targetNode.Parent; |
||||||
} |
} |
||||||
return targetNode; |
return targetNode; |
||||||
} |
} |
||||||
|
|
||||||
public NodeCollection Predecessors { |
public NodeCollection Predecessors { |
||||||
get { |
get { |
||||||
if (predecessors_cache == null) { |
if (predecessors_cache == null) { |
||||||
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
||||||
foreach(BasicBlock basicBlock in this.BasicBlocks) { |
foreach(BasicBlock basicBlock in this.BasicBlocks) { |
||||||
foreach(BasicBlock basicBlockPredecessor in basicBlock.BasicBlockPredecessors) { |
foreach(BasicBlock basicBlockPredecessor in basicBlock.BasicBlockPredecessors) { |
||||||
basicBlockPredecessors.Add(basicBlockPredecessor); |
basicBlockPredecessors.Add(basicBlockPredecessor); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
predecessors_cache = FloatUpToNeighbours(basicBlockPredecessors); |
predecessors_cache = FloatUpToNeighbours(basicBlockPredecessors); |
||||||
} |
} |
||||||
return predecessors_cache; |
return predecessors_cache; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public NodeCollection Successors { |
public NodeCollection Successors { |
||||||
get { |
get { |
||||||
if (successors_cache == null) { |
if (successors_cache == null) { |
||||||
List<BasicBlock> basicBlockSuccessors = new List<BasicBlock>(); |
List<BasicBlock> basicBlockSuccessors = new List<BasicBlock>(); |
||||||
foreach(BasicBlock basicBlock in this.BasicBlocks) { |
foreach(BasicBlock basicBlock in this.BasicBlocks) { |
||||||
foreach(BasicBlock basicBlockSuccessor in basicBlock.BasicBlockSuccessors) { |
foreach(BasicBlock basicBlockSuccessor in basicBlock.BasicBlockSuccessors) { |
||||||
basicBlockSuccessors.Add(basicBlockSuccessor); |
basicBlockSuccessors.Add(basicBlockSuccessor); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
successors_cache = FloatUpToNeighbours(basicBlockSuccessors); |
successors_cache = FloatUpToNeighbours(basicBlockSuccessors); |
||||||
} |
} |
||||||
return successors_cache; |
return successors_cache; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
int Index { |
int Index { |
||||||
get { |
get { |
||||||
if (this.Parent == null) throw new Exception("Does not have a parent"); |
if (this.Parent == null) throw new Exception("Does not have a parent"); |
||||||
return this.Parent.Childs.IndexOf(this); |
return this.Parent.Childs.IndexOf(this); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public Node NextNode { |
public Node NextNode { |
||||||
get { |
get { |
||||||
int index = this.Index + 1; |
int index = this.Index + 1; |
||||||
if (0 <= index && index < this.Parent.Childs.Count) { |
if (0 <= index && index < this.Parent.Childs.Count) { |
||||||
return this.Parent.Childs[index]; |
return this.Parent.Childs[index]; |
||||||
} else { |
} else { |
||||||
return null; |
return null; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public string Description { |
public string Description { |
||||||
get { |
get { |
||||||
return ToString(); |
return ToString(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
protected Node() |
protected Node() |
||||||
{ |
{ |
||||||
this.id = NextNodeID++; |
this.id = NextNodeID++; |
||||||
this.label = this.GetType().Name + "_" + ID; |
this.label = this.GetType().Name + "_" + ID; |
||||||
this.Childs.Added += delegate(object sender, NodeEventArgs e) { |
this.Childs.Added += delegate(object sender, NodeEventArgs e) { |
||||||
if (e.Node.Parent != null) { |
if (e.Node.Parent != null) { |
||||||
throw new Exception("Node is already assigned to other parent"); |
throw new Exception("Node is already assigned to other parent"); |
||||||
} |
} |
||||||
e.Node.parent = this; |
e.Node.parent = this; |
||||||
NotifyChildsChanged(); |
NotifyChildsChanged(); |
||||||
}; |
}; |
||||||
this.Childs.Removed += delegate(object sender, NodeEventArgs e) { |
this.Childs.Removed += delegate(object sender, NodeEventArgs e) { |
||||||
e.Node.parent = null; |
e.Node.parent = null; |
||||||
NotifyChildsChanged(); |
NotifyChildsChanged(); |
||||||
}; |
}; |
||||||
} |
} |
||||||
|
|
||||||
void NotifyChildsChanged() |
void NotifyChildsChanged() |
||||||
{ |
{ |
||||||
this.basicBlocks_cache = null; |
this.basicBlocks_cache = null; |
||||||
foreach(Node child in this.Childs) { |
foreach(Node child in this.Childs) { |
||||||
child.predecessors_cache = null; |
child.predecessors_cache = null; |
||||||
child.successors_cache = null; |
child.successors_cache = null; |
||||||
} |
} |
||||||
if (this.Parent != null) { |
if (this.Parent != null) { |
||||||
this.Parent.NotifyChildsChanged(); |
this.Parent.NotifyChildsChanged(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public override string ToString() |
public override string ToString() |
||||||
{ |
{ |
||||||
System.Text.StringBuilder sb = new System.Text.StringBuilder(); |
System.Text.StringBuilder sb = new System.Text.StringBuilder(); |
||||||
sb.Append(this.GetType().Name); |
sb.Append(this.GetType().Name); |
||||||
sb.Append(" "); |
sb.Append(" "); |
||||||
sb.Append(ID); |
sb.Append(ID); |
||||||
sb.Append(" "); |
sb.Append(" "); |
||||||
|
|
||||||
sb.Append("("); |
sb.Append("("); |
||||||
|
|
||||||
if (this.Predecessors.Count > 0) { |
if (this.Predecessors.Count > 0) { |
||||||
sb.Append("Predecessors:"); |
sb.Append("Predecessors:"); |
||||||
bool isFirst = true; |
bool isFirst = true; |
||||||
foreach(Node predecessor in this.Predecessors) { |
foreach(Node predecessor in this.Predecessors) { |
||||||
if (isFirst) { |
if (isFirst) { |
||||||
isFirst = false; |
isFirst = false; |
||||||
} else { |
} else { |
||||||
sb.Append(","); |
sb.Append(","); |
||||||
} |
} |
||||||
sb.Append(predecessor.ID); |
sb.Append(predecessor.ID); |
||||||
} |
} |
||||||
sb.Append(" "); |
sb.Append(" "); |
||||||
} |
} |
||||||
|
|
||||||
if (this.Successors.Count > 0) { |
if (this.Successors.Count > 0) { |
||||||
sb.Append("Successors:"); |
sb.Append("Successors:"); |
||||||
bool isFirst = true; |
bool isFirst = true; |
||||||
foreach(Node successor in this.Successors) { |
foreach(Node successor in this.Successors) { |
||||||
if (isFirst) { |
if (isFirst) { |
||||||
isFirst = false; |
isFirst = false; |
||||||
} else { |
} else { |
||||||
sb.Append(","); |
sb.Append(","); |
||||||
} |
} |
||||||
sb.Append(successor.ID); |
sb.Append(successor.ID); |
||||||
} |
} |
||||||
sb.Append(" "); |
sb.Append(" "); |
||||||
} |
} |
||||||
|
|
||||||
if (this.Parent != null) { |
if (this.Parent != null) { |
||||||
sb.Append("Parent:"); |
sb.Append("Parent:"); |
||||||
sb.Append(this.Parent.ID); |
sb.Append(this.Parent.ID); |
||||||
sb.Append(" "); |
sb.Append(" "); |
||||||
} |
} |
||||||
|
|
||||||
if (sb[sb.Length - 1] == '(') { |
if (sb[sb.Length - 1] == '(') { |
||||||
sb.Length -= 1; |
sb.Length -= 1; |
||||||
} else if (sb[sb.Length - 1] == ' ') { |
} else if (sb[sb.Length - 1] == ' ') { |
||||||
sb.Length -= 1; |
sb.Length -= 1; |
||||||
sb.Append(")"); |
sb.Append(")"); |
||||||
} |
} |
||||||
return sb.ToString(); |
return sb.ToString(); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,60 +1,60 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections; |
using System.Collections; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
|
|
||||||
namespace Decompiler.ControlFlow |
namespace Decompiler.ControlFlow |
||||||
{ |
{ |
||||||
public abstract partial class Node |
public abstract partial class Node |
||||||
{ |
{ |
||||||
public void Remove() |
public void Remove() |
||||||
{ |
{ |
||||||
if (this.Parent != null) { |
if (this.Parent != null) { |
||||||
this.Parent.Childs.Remove(this); |
this.Parent.Childs.Remove(this); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public void MoveTo(Node newNode) |
public void MoveTo(Node newNode) |
||||||
{ |
{ |
||||||
MoveTo(newNode, newNode.Childs.Count); |
MoveTo(newNode, newNode.Childs.Count); |
||||||
} |
} |
||||||
|
|
||||||
public void MoveTo(Node newNode, int index) |
public void MoveTo(Node newNode, int index) |
||||||
{ |
{ |
||||||
this.Remove(); |
this.Remove(); |
||||||
newNode.Childs.Insert(index, this); |
newNode.Childs.Insert(index, this); |
||||||
} |
} |
||||||
|
|
||||||
T MergeChilds<T>(params Node[] nodes) where T: Node, new() |
T MergeChilds<T>(params Node[] nodes) where T: Node, new() |
||||||
{ |
{ |
||||||
foreach(Node node in nodes) { |
foreach(Node node in nodes) { |
||||||
if (node == null) throw new ArgumentNullException("nodes"); |
if (node == null) throw new ArgumentNullException("nodes"); |
||||||
if (node.Parent != this) throw new ArgumentException("The node is not my child"); |
if (node.Parent != this) throw new ArgumentException("The node is not my child"); |
||||||
} |
} |
||||||
if (nodes.Length == 0) throw new ArgumentException("At least one node must be specified"); |
if (nodes.Length == 0) throw new ArgumentException("At least one node must be specified"); |
||||||
|
|
||||||
T mergedNode = new T(); |
T mergedNode = new T(); |
||||||
|
|
||||||
// Add the merged node
|
// Add the merged node
|
||||||
int headIndex = this.Childs.IndexOf(nodes[0]); |
int headIndex = this.Childs.IndexOf(nodes[0]); |
||||||
this.Childs.Insert(headIndex, mergedNode); |
this.Childs.Insert(headIndex, mergedNode); |
||||||
|
|
||||||
foreach(Node node in nodes) { |
foreach(Node node in nodes) { |
||||||
node.MoveTo(mergedNode); |
node.MoveTo(mergedNode); |
||||||
} |
} |
||||||
|
|
||||||
return mergedNode; |
return mergedNode; |
||||||
} |
} |
||||||
|
|
||||||
public void FalttenAcyclicChilds() |
public void FalttenAcyclicChilds() |
||||||
{ |
{ |
||||||
Reset: |
Reset: |
||||||
foreach(Node child in this.Childs) { |
foreach(Node child in this.Childs) { |
||||||
if (child is AcyclicGraph) { |
if (child is AcyclicGraph) { |
||||||
child.Childs.MoveTo(this, child.Index); |
child.Childs.MoveTo(this, child.Index); |
||||||
child.Remove(); |
child.Remove(); |
||||||
goto Reset; |
goto Reset; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,130 +1,130 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
|
|
||||||
namespace Decompiler.ControlFlow |
namespace Decompiler.ControlFlow |
||||||
{ |
{ |
||||||
public class NodeEventArgs: EventArgs |
public class NodeEventArgs: EventArgs |
||||||
{ |
{ |
||||||
Node node; |
Node node; |
||||||
|
|
||||||
public Node Node { |
public Node Node { |
||||||
get { return node; } |
get { return node; } |
||||||
} |
} |
||||||
|
|
||||||
public NodeEventArgs(Node node) |
public NodeEventArgs(Node node) |
||||||
{ |
{ |
||||||
this.node = node; |
this.node = node; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public class NodeCollection: System.Collections.ObjectModel.Collection<Node> |
public class NodeCollection: System.Collections.ObjectModel.Collection<Node> |
||||||
{ |
{ |
||||||
public static NodeCollection Empty = new NodeCollection(); |
public static NodeCollection Empty = new NodeCollection(); |
||||||
|
|
||||||
public event EventHandler<NodeEventArgs> Added; |
public event EventHandler<NodeEventArgs> Added; |
||||||
public event EventHandler<NodeEventArgs> Removed; |
public event EventHandler<NodeEventArgs> Removed; |
||||||
|
|
||||||
protected virtual void OnAdded(Node node) |
protected virtual void OnAdded(Node node) |
||||||
{ |
{ |
||||||
if (Added != null) { |
if (Added != null) { |
||||||
Added(this, new NodeEventArgs(node)); |
Added(this, new NodeEventArgs(node)); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
protected virtual void OnRemoved(Node node) |
protected virtual void OnRemoved(Node node) |
||||||
{ |
{ |
||||||
if (Removed != null) { |
if (Removed != null) { |
||||||
Removed(this, new NodeEventArgs(node)); |
Removed(this, new NodeEventArgs(node)); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
protected override void ClearItems() |
protected override void ClearItems() |
||||||
{ |
{ |
||||||
while(this.Count > 0) { |
while(this.Count > 0) { |
||||||
this.RemoveAt(this.Count - 1); |
this.RemoveAt(this.Count - 1); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
protected override void InsertItem(int index, Node item) |
protected override void InsertItem(int index, Node item) |
||||||
{ |
{ |
||||||
if (!this.Contains(item)) { |
if (!this.Contains(item)) { |
||||||
base.InsertItem(index, item); |
base.InsertItem(index, item); |
||||||
} |
} |
||||||
OnAdded(item); |
OnAdded(item); |
||||||
} |
} |
||||||
|
|
||||||
protected override void RemoveItem(int index) |
protected override void RemoveItem(int index) |
||||||
{ |
{ |
||||||
Node node = this[index]; |
Node node = this[index]; |
||||||
base.RemoveItem(index); |
base.RemoveItem(index); |
||||||
OnRemoved(node); |
OnRemoved(node); |
||||||
} |
} |
||||||
|
|
||||||
protected override void SetItem(int index, Node item) |
protected override void SetItem(int index, Node item) |
||||||
{ |
{ |
||||||
this.RemoveAt(index); |
this.RemoveAt(index); |
||||||
this.Insert(index, item); |
this.Insert(index, item); |
||||||
} |
} |
||||||
|
|
||||||
|
|
||||||
public void AddRange(IEnumerable<Node> items) |
public void AddRange(IEnumerable<Node> items) |
||||||
{ |
{ |
||||||
foreach(Node item in items) { |
foreach(Node item in items) { |
||||||
this.Add(item); |
this.Add(item); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public void RemoveRange(IEnumerable<Node> items) |
public void RemoveRange(IEnumerable<Node> items) |
||||||
{ |
{ |
||||||
foreach(Node item in items) { |
foreach(Node item in items) { |
||||||
this.Remove(item); |
this.Remove(item); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public void MoveTo(Node newNode) |
public void MoveTo(Node newNode) |
||||||
{ |
{ |
||||||
foreach(Node child in this.Clone()) { |
foreach(Node child in this.Clone()) { |
||||||
child.MoveTo(newNode); |
child.MoveTo(newNode); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public void MoveTo(Node newNode, int index) |
public void MoveTo(Node newNode, int index) |
||||||
{ |
{ |
||||||
foreach(Node child in this.Clone()) { |
foreach(Node child in this.Clone()) { |
||||||
child.MoveTo(newNode, index); |
child.MoveTo(newNode, index); |
||||||
index++; |
index++; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public NodeCollection() |
public NodeCollection() |
||||||
{ |
{ |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
public NodeCollection(IEnumerable<Node> items) |
public NodeCollection(IEnumerable<Node> items) |
||||||
{ |
{ |
||||||
this.AddRange(items); |
this.AddRange(items); |
||||||
} |
} |
||||||
|
|
||||||
public NodeCollection Clone() |
public NodeCollection Clone() |
||||||
{ |
{ |
||||||
return new NodeCollection(this); |
return new NodeCollection(this); |
||||||
} |
} |
||||||
|
|
||||||
public static NodeCollection Intersect(NodeCollection collectionA, NodeCollection collectionB) |
public static NodeCollection Intersect(NodeCollection collectionA, NodeCollection collectionB) |
||||||
{ |
{ |
||||||
NodeCollection result = new NodeCollection(); |
NodeCollection result = new NodeCollection(); |
||||||
foreach(Node a in collectionA) { |
foreach(Node a in collectionA) { |
||||||
if (collectionB.Contains(a)) { |
if (collectionB.Contains(a)) { |
||||||
result.Add(a); |
result.Add(a); |
||||||
} |
} |
||||||
} |
} |
||||||
return result; |
return result; |
||||||
} |
} |
||||||
|
|
||||||
public override string ToString() |
public override string ToString() |
||||||
{ |
{ |
||||||
return string.Format("{0} Count = {1}", typeof(NodeCollection).Name, this.Count); |
return string.Format("{0} Count = {1}", typeof(NodeCollection).Name, this.Count); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,255 +1,255 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using System.Linq; |
using System.Linq; |
||||||
using Decompiler.Mono.Cecil.Rocks; |
using Decompiler.Mono.Cecil.Rocks; |
||||||
using Mono.Cecil; |
using Mono.Cecil; |
||||||
using Mono.Cecil.Cil; |
using Mono.Cecil.Cil; |
||||||
|
|
||||||
namespace Decompiler.ControlFlow |
namespace Decompiler.ControlFlow |
||||||
{ |
{ |
||||||
public class BasicBlock: Node |
public class BasicBlock: Node |
||||||
{ |
{ |
||||||
List<ILNode> body = new List<ILNode>(); |
List<ILNode> body = new List<ILNode>(); |
||||||
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>(); |
||||||
BasicBlock fallThroughBasicBlock; |
BasicBlock fallThroughBasicBlock; |
||||||
BasicBlock branchBasicBlock; |
BasicBlock branchBasicBlock; |
||||||
|
|
||||||
public List<ILNode> Body { |
public List<ILNode> Body { |
||||||
get { return body; } |
get { return body; } |
||||||
} |
} |
||||||
|
|
||||||
public List<BasicBlock> BasicBlockPredecessors { |
public List<BasicBlock> BasicBlockPredecessors { |
||||||
get { return basicBlockPredecessors; } |
get { return basicBlockPredecessors; } |
||||||
} |
} |
||||||
|
|
||||||
public BasicBlock FallThroughBasicBlock { |
public BasicBlock FallThroughBasicBlock { |
||||||
get { return fallThroughBasicBlock; } |
get { return fallThroughBasicBlock; } |
||||||
set { fallThroughBasicBlock = value; } |
set { fallThroughBasicBlock = value; } |
||||||
} |
} |
||||||
|
|
||||||
public BasicBlock BranchBasicBlock { |
public BasicBlock BranchBasicBlock { |
||||||
get { return branchBasicBlock; } |
get { return branchBasicBlock; } |
||||||
set { branchBasicBlock = value; } |
set { branchBasicBlock = value; } |
||||||
} |
} |
||||||
|
|
||||||
public IEnumerable<BasicBlock> BasicBlockSuccessors { |
public IEnumerable<BasicBlock> BasicBlockSuccessors { |
||||||
get { |
get { |
||||||
if (this.FallThroughBasicBlock != null) { |
if (this.FallThroughBasicBlock != null) { |
||||||
yield return this.FallThroughBasicBlock; |
yield return this.FallThroughBasicBlock; |
||||||
} |
} |
||||||
if (this.BranchBasicBlock != null) { |
if (this.BranchBasicBlock != null) { |
||||||
yield return this.BranchBasicBlock; |
yield return this.BranchBasicBlock; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public enum ShortCircuitOperator { |
public enum ShortCircuitOperator { |
||||||
LeftAndRight, |
LeftAndRight, |
||||||
LeftOrRight, |
LeftOrRight, |
||||||
NotLeftAndRight, |
NotLeftAndRight, |
||||||
NotLeftOrRight, |
NotLeftOrRight, |
||||||
} |
} |
||||||
|
|
||||||
public abstract class Branch: Node |
public abstract class Branch: Node |
||||||
{ |
{ |
||||||
public abstract BasicBlock FirstBasicBlock { get; } |
public abstract BasicBlock FirstBasicBlock { get; } |
||||||
public abstract BasicBlock TrueSuccessor { get; } |
public abstract BasicBlock TrueSuccessor { get; } |
||||||
public abstract BasicBlock FalseSuccessor { get; } |
public abstract BasicBlock FalseSuccessor { get; } |
||||||
} |
} |
||||||
|
|
||||||
public class SimpleBranch: Branch |
public class SimpleBranch: Branch |
||||||
{ |
{ |
||||||
public override BasicBlock FirstBasicBlock { |
public override BasicBlock FirstBasicBlock { |
||||||
get { |
get { |
||||||
return this.BasicBlock; |
return this.BasicBlock; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public BasicBlock BasicBlock { |
public BasicBlock BasicBlock { |
||||||
get { return (BasicBlock)this.Childs[0]; } |
get { return (BasicBlock)this.Childs[0]; } |
||||||
} |
} |
||||||
|
|
||||||
public override BasicBlock TrueSuccessor { |
public override BasicBlock TrueSuccessor { |
||||||
get { return this.BasicBlock.BranchBasicBlock; } |
get { return this.BasicBlock.BranchBasicBlock; } |
||||||
} |
} |
||||||
|
|
||||||
public override BasicBlock FalseSuccessor { |
public override BasicBlock FalseSuccessor { |
||||||
get { return this.BasicBlock.FallThroughBasicBlock; } |
get { return this.BasicBlock.FallThroughBasicBlock; } |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public class ShortCircuitBranch: Branch |
public class ShortCircuitBranch: Branch |
||||||
{ |
{ |
||||||
ShortCircuitOperator @operator; |
ShortCircuitOperator @operator; |
||||||
|
|
||||||
public override BasicBlock FirstBasicBlock { |
public override BasicBlock FirstBasicBlock { |
||||||
get { |
get { |
||||||
return this.Left.FirstBasicBlock; |
return this.Left.FirstBasicBlock; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public Branch Left { |
public Branch Left { |
||||||
get { return (Branch)this.Childs[0];; } |
get { return (Branch)this.Childs[0];; } |
||||||
} |
} |
||||||
|
|
||||||
public Branch Right { |
public Branch Right { |
||||||
get { return (Branch)this.Childs[1]; } |
get { return (Branch)this.Childs[1]; } |
||||||
} |
} |
||||||
|
|
||||||
public ShortCircuitOperator Operator { |
public ShortCircuitOperator Operator { |
||||||
get { return @operator; } |
get { return @operator; } |
||||||
set { @operator = value; } |
set { @operator = value; } |
||||||
} |
} |
||||||
|
|
||||||
public override BasicBlock TrueSuccessor { |
public override BasicBlock TrueSuccessor { |
||||||
get { return this.Right.TrueSuccessor; } |
get { return this.Right.TrueSuccessor; } |
||||||
} |
} |
||||||
|
|
||||||
public override BasicBlock FalseSuccessor { |
public override BasicBlock FalseSuccessor { |
||||||
get { return this.Right.FalseSuccessor; } |
get { return this.Right.FalseSuccessor; } |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public class MethodBodyGraph: Node |
public class MethodBodyGraph: Node |
||||||
{ |
{ |
||||||
BasicBlock methodEntry; |
BasicBlock methodEntry; |
||||||
|
|
||||||
public BasicBlock MethodEntry { |
public BasicBlock MethodEntry { |
||||||
get { return methodEntry; } |
get { return methodEntry; } |
||||||
} |
} |
||||||
|
|
||||||
Dictionary<ILLabel, BasicBlock> labelToBasicBlock = new Dictionary<ILLabel, BasicBlock>(); |
Dictionary<ILLabel, BasicBlock> labelToBasicBlock = new Dictionary<ILLabel, BasicBlock>(); |
||||||
|
|
||||||
public MethodBodyGraph(List<ILNode> ast) |
public MethodBodyGraph(List<ILNode> ast) |
||||||
{ |
{ |
||||||
if (ast.Count == 0) throw new ArgumentException("Count == 0", "ast"); |
if (ast.Count == 0) throw new ArgumentException("Count == 0", "ast"); |
||||||
this.methodEntry = new BasicBlock(); |
this.methodEntry = new BasicBlock(); |
||||||
this.Childs.Add(this.methodEntry); |
this.Childs.Add(this.methodEntry); |
||||||
this.Childs.AddRange(SplitToBasicBlocks(ast)); |
this.Childs.AddRange(SplitToBasicBlocks(ast)); |
||||||
|
|
||||||
// Add branch links to BasicBlocks
|
// Add branch links to BasicBlocks
|
||||||
foreach(BasicBlock basicBlock in this.BasicBlocks) { |
foreach(BasicBlock basicBlock in this.BasicBlocks) { |
||||||
foreach(ILNode node in basicBlock.Body) { |
foreach(ILNode node in basicBlock.Body) { |
||||||
if (node is ILExpression) { |
if (node is ILExpression) { |
||||||
ILExpression expr = (ILExpression)node; |
ILExpression expr = (ILExpression)node; |
||||||
if (expr.Operand is ILLabel) { |
if (expr.Operand is ILLabel) { |
||||||
BasicBlock target = labelToBasicBlock[(ILLabel)expr.Operand]; |
BasicBlock target = labelToBasicBlock[(ILLabel)expr.Operand]; |
||||||
basicBlock.BranchBasicBlock = target; |
basicBlock.BranchBasicBlock = target; |
||||||
target.BasicBlockPredecessors.Add(basicBlock); |
target.BasicBlockPredecessors.Add(basicBlock); |
||||||
} |
} |
||||||
// TODO: Switch
|
// TODO: Switch
|
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public List<Node> SplitToBasicBlocks(List<ILNode> ast) |
public List<Node> SplitToBasicBlocks(List<ILNode> ast) |
||||||
{ |
{ |
||||||
if (ast.Count == 0) return new List<Node>(); |
if (ast.Count == 0) return new List<Node>(); |
||||||
|
|
||||||
List<Node> nodes = new List<Node>(); |
List<Node> nodes = new List<Node>(); |
||||||
|
|
||||||
BasicBlock basicBlock = null; |
BasicBlock basicBlock = null; |
||||||
|
|
||||||
for(int i = 0; i < ast.Count; i++) { |
for(int i = 0; i < ast.Count; i++) { |
||||||
if (i == 0 || |
if (i == 0 || |
||||||
ast[i] is ILLabel || |
ast[i] is ILLabel || |
||||||
ast[i - 1] is ILTryCatchBlock || |
ast[i - 1] is ILTryCatchBlock || |
||||||
ast[i] is ILTryCatchBlock || |
ast[i] is ILTryCatchBlock || |
||||||
(ast[i - 1] is ILExpression) && ((ILExpression)ast[i - 1]).OpCode.IsBranch() || |
(ast[i - 1] is ILExpression) && ((ILExpression)ast[i - 1]).OpCode.IsBranch() || |
||||||
(ast[i] is ILExpression) && ((ILExpression)ast[i]).OpCode.IsBranch()) |
(ast[i] is ILExpression) && ((ILExpression)ast[i]).OpCode.IsBranch()) |
||||||
{ |
{ |
||||||
BasicBlock oldBB = basicBlock; |
BasicBlock oldBB = basicBlock; |
||||||
basicBlock = new BasicBlock(); |
basicBlock = new BasicBlock(); |
||||||
nodes.Add(basicBlock); |
nodes.Add(basicBlock); |
||||||
// Links
|
// Links
|
||||||
if (oldBB != null && ast[i - 1] is ILExpression && ((ILExpression)ast[i - 1]).OpCode.CanFallThough()) { |
if (oldBB != null && ast[i - 1] is ILExpression && ((ILExpression)ast[i - 1]).OpCode.CanFallThough()) { |
||||||
oldBB.FallThroughBasicBlock = basicBlock; |
oldBB.FallThroughBasicBlock = basicBlock; |
||||||
basicBlock.BasicBlockPredecessors.Add(oldBB); |
basicBlock.BasicBlockPredecessors.Add(oldBB); |
||||||
} |
} |
||||||
} |
} |
||||||
if (ast[i] is ILTryCatchBlock) { |
if (ast[i] is ILTryCatchBlock) { |
||||||
nodes.Add(ConvertTryCatch((ILTryCatchBlock)ast[i])); |
nodes.Add(ConvertTryCatch((ILTryCatchBlock)ast[i])); |
||||||
} else { |
} else { |
||||||
basicBlock.Body.Add(ast[i]); |
basicBlock.Body.Add(ast[i]); |
||||||
} |
} |
||||||
if (ast[i] is ILLabel) { |
if (ast[i] is ILLabel) { |
||||||
labelToBasicBlock[(ILLabel)ast[i]] = basicBlock; |
labelToBasicBlock[(ILLabel)ast[i]] = basicBlock; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return nodes; |
return nodes; |
||||||
} |
} |
||||||
|
|
||||||
public TryCatchNode ConvertTryCatch(ILTryCatchBlock ilTryCatch) |
public TryCatchNode ConvertTryCatch(ILTryCatchBlock ilTryCatch) |
||||||
{ |
{ |
||||||
TryCatchNode tryCatch = new TryCatchNode(); |
TryCatchNode tryCatch = new TryCatchNode(); |
||||||
|
|
||||||
Block tryBlock = new Block(); |
Block tryBlock = new Block(); |
||||||
tryBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.TryBlock)); |
tryBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.TryBlock)); |
||||||
tryBlock.MoveTo(tryCatch); |
tryBlock.MoveTo(tryCatch); |
||||||
|
|
||||||
Block finallyBlock = new Block(); |
Block finallyBlock = new Block(); |
||||||
if (ilTryCatch.FinallyBlock != null) { |
if (ilTryCatch.FinallyBlock != null) { |
||||||
finallyBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.FinallyBlock)); |
finallyBlock.Childs.AddRange(SplitToBasicBlocks(ilTryCatch.FinallyBlock)); |
||||||
} |
} |
||||||
finallyBlock.MoveTo(tryCatch); |
finallyBlock.MoveTo(tryCatch); |
||||||
|
|
||||||
foreach(ILTryCatchBlock.CatchBlock cb in ilTryCatch.CatchBlocks) { |
foreach(ILTryCatchBlock.CatchBlock cb in ilTryCatch.CatchBlocks) { |
||||||
tryCatch.Types.Add(cb.ExceptionType); |
tryCatch.Types.Add(cb.ExceptionType); |
||||||
Block catchBlock = new Block(); |
Block catchBlock = new Block(); |
||||||
catchBlock.Childs.AddRange(SplitToBasicBlocks(cb.Body)); |
catchBlock.Childs.AddRange(SplitToBasicBlocks(cb.Body)); |
||||||
catchBlock.MoveTo(tryCatch); |
catchBlock.MoveTo(tryCatch); |
||||||
} |
} |
||||||
|
|
||||||
return tryCatch; |
return tryCatch; |
||||||
} |
} |
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
public class TryCatchNode: Node |
public class TryCatchNode: Node |
||||||
{ |
{ |
||||||
public List<TypeReference> Types = new List<TypeReference>(); |
public List<TypeReference> Types = new List<TypeReference>(); |
||||||
} |
} |
||||||
|
|
||||||
public class AcyclicGraph: Node |
public class AcyclicGraph: Node |
||||||
{ |
{ |
||||||
} |
} |
||||||
|
|
||||||
public class Loop: Node |
public class Loop: Node |
||||||
{ |
{ |
||||||
} |
} |
||||||
|
|
||||||
public class Block: Node |
public class Block: Node |
||||||
{ |
{ |
||||||
} |
} |
||||||
|
|
||||||
public class ConditionalNode: Node |
public class ConditionalNode: Node |
||||||
{ |
{ |
||||||
Branch condition; |
Branch condition; |
||||||
Block trueBody = new Block(); |
Block trueBody = new Block(); |
||||||
Block falseBody = new Block(); |
Block falseBody = new Block(); |
||||||
|
|
||||||
public Branch Condition { |
public Branch Condition { |
||||||
get { return condition; } |
get { return condition; } |
||||||
} |
} |
||||||
|
|
||||||
public Block TrueBody { |
public Block TrueBody { |
||||||
get { return trueBody; } |
get { return trueBody; } |
||||||
} |
} |
||||||
|
|
||||||
public Block FalseBody { |
public Block FalseBody { |
||||||
get { return falseBody; } |
get { return falseBody; } |
||||||
} |
} |
||||||
|
|
||||||
public ConditionalNode(Branch condition) |
public ConditionalNode(Branch condition) |
||||||
{ |
{ |
||||||
this.condition = condition; |
this.condition = condition; |
||||||
|
|
||||||
condition.MoveTo(this); |
condition.MoveTo(this); |
||||||
trueBody.MoveTo(this); |
trueBody.MoveTo(this); |
||||||
falseBody.MoveTo(this); |
falseBody.MoveTo(this); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,298 +1,298 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using System.Linq; |
using System.Linq; |
||||||
using System.Text; |
using System.Text; |
||||||
using Decompiler.Mono.Cecil.Rocks; |
using Decompiler.Mono.Cecil.Rocks; |
||||||
using Mono.Cecil; |
using Mono.Cecil; |
||||||
using Mono.Cecil.Cil; |
using Mono.Cecil.Cil; |
||||||
using Cecil = Mono.Cecil; |
using Cecil = Mono.Cecil; |
||||||
|
|
||||||
namespace Decompiler |
namespace Decompiler |
||||||
{ |
{ |
||||||
public class ILAstBuilder |
public class ILAstBuilder |
||||||
{ |
{ |
||||||
class ILStack |
class ILStack |
||||||
{ |
{ |
||||||
public class Slot |
public class Slot |
||||||
{ |
{ |
||||||
public Instruction PushedBy; |
public Instruction PushedBy; |
||||||
public TypeReference Type; |
public TypeReference Type; |
||||||
|
|
||||||
public Slot(Instruction inst, TypeReference type) |
public Slot(Instruction inst, TypeReference type) |
||||||
{ |
{ |
||||||
this.PushedBy = inst; |
this.PushedBy = inst; |
||||||
this.Type = type; |
this.Type = type; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public List<Slot> Items = new List<Slot>(); |
public List<Slot> Items = new List<Slot>(); |
||||||
|
|
||||||
public ILStack Clone() |
public ILStack Clone() |
||||||
{ |
{ |
||||||
ILStack clone = new ILStack(); |
ILStack clone = new ILStack(); |
||||||
foreach(Slot s in this.Items) { |
foreach(Slot s in this.Items) { |
||||||
clone.Items.Add(new Slot(s.PushedBy, s.Type)); |
clone.Items.Add(new Slot(s.PushedBy, s.Type)); |
||||||
} |
} |
||||||
return clone; |
return clone; |
||||||
} |
} |
||||||
|
|
||||||
public override string ToString() |
public override string ToString() |
||||||
{ |
{ |
||||||
StringBuilder sb = new StringBuilder(); |
StringBuilder sb = new StringBuilder(); |
||||||
bool first = true; |
bool first = true; |
||||||
foreach (Slot s in this.Items) { |
foreach (Slot s in this.Items) { |
||||||
if (!first) sb.Append(", "); |
if (!first) sb.Append(", "); |
||||||
sb.Append(s.PushedBy.Offset.ToString("X")); |
sb.Append(s.PushedBy.Offset.ToString("X")); |
||||||
first = false; |
first = false; |
||||||
} |
} |
||||||
return sb.ToString(); |
return sb.ToString(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
Dictionary<Instruction, ILStack> stackBefore = new Dictionary<Instruction, ILAstBuilder.ILStack>(); |
Dictionary<Instruction, ILStack> stackBefore = new Dictionary<Instruction, ILAstBuilder.ILStack>(); |
||||||
Dictionary<Instruction, ILLabel> labels = new Dictionary<Instruction, ILLabel>(); |
Dictionary<Instruction, ILLabel> labels = new Dictionary<Instruction, ILLabel>(); |
||||||
|
|
||||||
public List<ILNode> Build(MethodDefinition methodDef) |
public List<ILNode> Build(MethodDefinition methodDef) |
||||||
{ |
{ |
||||||
List<Instruction> body = new List<Instruction>(methodDef.Body.Instructions); |
List<Instruction> body = new List<Instruction>(methodDef.Body.Instructions); |
||||||
|
|
||||||
if (body.Count == 0) return new List<ILNode>(); |
if (body.Count == 0) return new List<ILNode>(); |
||||||
|
|
||||||
StackAnalysis(body, methodDef); |
StackAnalysis(body, methodDef); |
||||||
|
|
||||||
// Create branch labels for instructins; use the labels as branch operands
|
// Create branch labels for instructins; use the labels as branch operands
|
||||||
foreach (Instruction inst in body) { |
foreach (Instruction inst in body) { |
||||||
if (inst.Operand is Instruction[]) { |
if (inst.Operand is Instruction[]) { |
||||||
List<ILLabel> newOperand = new List<ILLabel>(); |
List<ILLabel> newOperand = new List<ILLabel>(); |
||||||
foreach(Instruction target in (Instruction[])inst.Operand) { |
foreach(Instruction target in (Instruction[])inst.Operand) { |
||||||
if (!labels.ContainsKey(target)) { |
if (!labels.ContainsKey(target)) { |
||||||
labels[target] = new ILLabel() { Name = "IL_" + target.Offset.ToString("X2") }; |
labels[target] = new ILLabel() { Name = "IL_" + target.Offset.ToString("X2") }; |
||||||
} |
} |
||||||
newOperand.Add(labels[target]); |
newOperand.Add(labels[target]); |
||||||
} |
} |
||||||
inst.Operand = newOperand.ToArray(); |
inst.Operand = newOperand.ToArray(); |
||||||
} else if (inst.Operand is Instruction) { |
} else if (inst.Operand is Instruction) { |
||||||
Instruction target = (Instruction)inst.Operand; |
Instruction target = (Instruction)inst.Operand; |
||||||
if (!labels.ContainsKey(target)) { |
if (!labels.ContainsKey(target)) { |
||||||
labels[target] = new ILLabel() { Name = "IL_" + target.Offset.ToString("X2") }; |
labels[target] = new ILLabel() { Name = "IL_" + target.Offset.ToString("X2") }; |
||||||
} |
} |
||||||
inst.Operand = labels[target]; |
inst.Operand = labels[target]; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
List<ILNode> ast = ConvertToAst(body, methodDef.Body.ExceptionHandlers); |
List<ILNode> ast = ConvertToAst(body, methodDef.Body.ExceptionHandlers); |
||||||
|
|
||||||
return ast; |
return ast; |
||||||
} |
} |
||||||
|
|
||||||
public void StackAnalysis(List<Instruction> body, MethodDefinition methodDef) |
public void StackAnalysis(List<Instruction> body, MethodDefinition methodDef) |
||||||
{ |
{ |
||||||
Queue<Instruction> agenda = new Queue<Instruction>(); |
Queue<Instruction> agenda = new Queue<Instruction>(); |
||||||
|
|
||||||
// Add known states
|
// Add known states
|
||||||
stackBefore[body[0]] = new ILStack(); |
stackBefore[body[0]] = new ILStack(); |
||||||
agenda.Enqueue(body[0]); |
agenda.Enqueue(body[0]); |
||||||
|
|
||||||
if(methodDef.Body.HasExceptionHandlers) { |
if(methodDef.Body.HasExceptionHandlers) { |
||||||
foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { |
foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) { |
||||||
stackBefore[ex.TryStart] = new ILStack(); |
stackBefore[ex.TryStart] = new ILStack(); |
||||||
agenda.Enqueue(ex.TryStart); |
agenda.Enqueue(ex.TryStart); |
||||||
|
|
||||||
ILStack stack = new ILStack(); |
ILStack stack = new ILStack(); |
||||||
stack.Items.Add(new ILStack.Slot(null, MyRocks.TypeException)); |
stack.Items.Add(new ILStack.Slot(null, MyRocks.TypeException)); |
||||||
stackBefore[ex.HandlerStart] = stack; |
stackBefore[ex.HandlerStart] = stack; |
||||||
agenda.Enqueue(ex.HandlerStart); |
agenda.Enqueue(ex.HandlerStart); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
// Process agenda
|
// Process agenda
|
||||||
while(agenda.Count > 0) { |
while(agenda.Count > 0) { |
||||||
Instruction inst = agenda.Dequeue(); |
Instruction inst = agenda.Dequeue(); |
||||||
|
|
||||||
// What is the effect of the instruction on the stack?
|
// What is the effect of the instruction on the stack?
|
||||||
ILStack newStack = stackBefore[inst].Clone(); |
ILStack newStack = stackBefore[inst].Clone(); |
||||||
int popCount = inst.GetPopCount(); |
int popCount = inst.GetPopCount(); |
||||||
if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all
|
if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all
|
||||||
List<TypeReference> typeArgs = new List<TypeReference>(); |
List<TypeReference> typeArgs = new List<TypeReference>(); |
||||||
for (int i = newStack.Items.Count - popCount; i < newStack.Items.Count; i++) { |
for (int i = newStack.Items.Count - popCount; i < newStack.Items.Count; i++) { |
||||||
typeArgs.Add(newStack.Items[i].Type); |
typeArgs.Add(newStack.Items[i].Type); |
||||||
} |
} |
||||||
TypeReference type; |
TypeReference type; |
||||||
try { |
try { |
||||||
type = inst.GetTypeInternal(methodDef, typeArgs); |
type = inst.GetTypeInternal(methodDef, typeArgs); |
||||||
} catch { |
} catch { |
||||||
type = MyRocks.TypeObject; |
type = MyRocks.TypeObject; |
||||||
} |
} |
||||||
if (popCount > 0) { |
if (popCount > 0) { |
||||||
newStack.Items.RemoveRange(newStack.Items.Count - popCount, popCount); |
newStack.Items.RemoveRange(newStack.Items.Count - popCount, popCount); |
||||||
} |
} |
||||||
int pushCount = inst.GetPushCount(); |
int pushCount = inst.GetPushCount(); |
||||||
for (int i = 0; i < pushCount; i++) { |
for (int i = 0; i < pushCount; i++) { |
||||||
newStack.Items.Add(new ILStack.Slot(inst, type)); |
newStack.Items.Add(new ILStack.Slot(inst, type)); |
||||||
} |
} |
||||||
|
|
||||||
// Apply the state to any successors
|
// Apply the state to any successors
|
||||||
List<Instruction> branchTargets = new List<Instruction>(); |
List<Instruction> branchTargets = new List<Instruction>(); |
||||||
if (inst.OpCode.CanFallThough()) { |
if (inst.OpCode.CanFallThough()) { |
||||||
branchTargets.Add(inst.Next); |
branchTargets.Add(inst.Next); |
||||||
} |
} |
||||||
if (inst.OpCode.IsBranch()) { |
if (inst.OpCode.IsBranch()) { |
||||||
if (inst.Operand is Instruction[]) { |
if (inst.Operand is Instruction[]) { |
||||||
branchTargets.AddRange((Instruction[])inst.Operand); |
branchTargets.AddRange((Instruction[])inst.Operand); |
||||||
} else { |
} else { |
||||||
branchTargets.Add((Instruction)inst.Operand); |
branchTargets.Add((Instruction)inst.Operand); |
||||||
} |
} |
||||||
} |
} |
||||||
foreach (Instruction branchTarget in branchTargets) { |
foreach (Instruction branchTarget in branchTargets) { |
||||||
ILStack nextStack; |
ILStack nextStack; |
||||||
if (stackBefore.TryGetValue(branchTarget, out nextStack)) { |
if (stackBefore.TryGetValue(branchTarget, out nextStack)) { |
||||||
// TODO: Compare stacks
|
// TODO: Compare stacks
|
||||||
} else { |
} else { |
||||||
stackBefore[branchTarget] = newStack; |
stackBefore[branchTarget] = newStack; |
||||||
agenda.Enqueue(branchTarget); |
agenda.Enqueue(branchTarget); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public List<ILNode> ConvertToAst(List<Instruction> body, IEnumerable<ExceptionHandler> ehs) |
public List<ILNode> ConvertToAst(List<Instruction> body, IEnumerable<ExceptionHandler> ehs) |
||||||
{ |
{ |
||||||
List<ILNode> ast = new List<ILNode>(); |
List<ILNode> ast = new List<ILNode>(); |
||||||
|
|
||||||
while (ehs.Any()) { |
while (ehs.Any()) { |
||||||
ILTryCatchBlock tryCatchBlock = new ILTryCatchBlock(); |
ILTryCatchBlock tryCatchBlock = new ILTryCatchBlock(); |
||||||
|
|
||||||
// Find the first and widest scope
|
// Find the first and widest scope
|
||||||
int tryStart = ehs.Min(eh => eh.TryStart.Offset); |
int tryStart = ehs.Min(eh => eh.TryStart.Offset); |
||||||
int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset); |
int tryEnd = ehs.Where(eh => eh.TryStart.Offset == tryStart).Max(eh => eh.TryEnd.Offset); |
||||||
var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).ToList(); |
var handlers = ehs.Where(eh => eh.TryStart.Offset == tryStart && eh.TryEnd.Offset == tryEnd).ToList(); |
||||||
|
|
||||||
// Cut all instructions up to the try block
|
// Cut all instructions up to the try block
|
||||||
{ |
{ |
||||||
int tryStartIdx; |
int tryStartIdx; |
||||||
for (tryStartIdx = 0; body[tryStartIdx].Offset != tryStart; tryStartIdx++); |
for (tryStartIdx = 0; body[tryStartIdx].Offset != tryStart; tryStartIdx++); |
||||||
ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx))); |
ast.AddRange(ConvertToAst(body.CutRange(0, tryStartIdx))); |
||||||
} |
} |
||||||
|
|
||||||
// Cut the try block
|
// Cut the try block
|
||||||
{ |
{ |
||||||
List<ExceptionHandler> nestedEHs = ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)).ToList(); |
List<ExceptionHandler> nestedEHs = ehs.Where(eh => (tryStart <= eh.TryStart.Offset && eh.TryEnd.Offset < tryEnd) || (tryStart < eh.TryStart.Offset && eh.TryEnd.Offset <= tryEnd)).ToList(); |
||||||
int tryEndIdx; |
int tryEndIdx; |
||||||
for (tryEndIdx = 0; tryEndIdx < body.Count && body[tryEndIdx].Offset != tryEnd; tryEndIdx++); |
for (tryEndIdx = 0; tryEndIdx < body.Count && body[tryEndIdx].Offset != tryEnd; tryEndIdx++); |
||||||
tryCatchBlock.TryBlock = ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs); |
tryCatchBlock.TryBlock = ConvertToAst(body.CutRange(0, tryEndIdx), nestedEHs); |
||||||
} |
} |
||||||
|
|
||||||
// Cut all handlers
|
// Cut all handlers
|
||||||
tryCatchBlock.CatchBlocks = new List<ILTryCatchBlock.CatchBlock>(); |
tryCatchBlock.CatchBlocks = new List<ILTryCatchBlock.CatchBlock>(); |
||||||
foreach(ExceptionHandler eh in handlers) { |
foreach(ExceptionHandler eh in handlers) { |
||||||
int start; |
int start; |
||||||
for (start = 0; body[start] != eh.HandlerStart; start++); |
for (start = 0; body[start] != eh.HandlerStart; start++); |
||||||
int end; |
int end; |
||||||
for (end = 0; body[end] != eh.HandlerEnd; end++); |
for (end = 0; body[end] != eh.HandlerEnd; end++); |
||||||
int count = end - start; |
int count = end - start; |
||||||
List<ExceptionHandler> nestedEHs = ehs.Where(e => (start <= e.TryStart.Offset && e.TryEnd.Offset < end) || (start < e.TryStart.Offset && e.TryEnd.Offset <= end)).ToList(); |
List<ExceptionHandler> nestedEHs = ehs.Where(e => (start <= e.TryStart.Offset && e.TryEnd.Offset < end) || (start < e.TryStart.Offset && e.TryEnd.Offset <= end)).ToList(); |
||||||
List<ILNode> handlerAst = ConvertToAst(body.CutRange(start, count), nestedEHs); |
List<ILNode> handlerAst = ConvertToAst(body.CutRange(start, count), nestedEHs); |
||||||
if (eh.HandlerType == ExceptionHandlerType.Catch) { |
if (eh.HandlerType == ExceptionHandlerType.Catch) { |
||||||
tryCatchBlock.CatchBlocks.Add(new ILTryCatchBlock.CatchBlock() { |
tryCatchBlock.CatchBlocks.Add(new ILTryCatchBlock.CatchBlock() { |
||||||
ExceptionType = eh.CatchType, |
ExceptionType = eh.CatchType, |
||||||
Body = handlerAst |
Body = handlerAst |
||||||
}); |
}); |
||||||
} else if (eh.HandlerType == ExceptionHandlerType.Finally) { |
} else if (eh.HandlerType == ExceptionHandlerType.Finally) { |
||||||
tryCatchBlock.FinallyBlock = handlerAst; |
tryCatchBlock.FinallyBlock = handlerAst; |
||||||
} else { |
} else { |
||||||
// TODO
|
// TODO
|
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
ehs = ehs.Where(eh => eh.TryStart.Offset > tryEnd).ToList(); |
ehs = ehs.Where(eh => eh.TryStart.Offset > tryEnd).ToList(); |
||||||
|
|
||||||
ast.Add(tryCatchBlock); |
ast.Add(tryCatchBlock); |
||||||
} |
} |
||||||
|
|
||||||
// Add whatever is left
|
// Add whatever is left
|
||||||
ast.AddRange(ConvertToAst(body)); |
ast.AddRange(ConvertToAst(body)); |
||||||
|
|
||||||
return ast; |
return ast; |
||||||
} |
} |
||||||
|
|
||||||
public List<ILNode> ConvertToAst(List<Instruction> body) |
public List<ILNode> ConvertToAst(List<Instruction> body) |
||||||
{ |
{ |
||||||
List<ILNode> ast = new List<ILNode>(); |
List<ILNode> ast = new List<ILNode>(); |
||||||
|
|
||||||
// Convert stack-based IL code to ILAst tree
|
// Convert stack-based IL code to ILAst tree
|
||||||
foreach(Instruction inst in body) { |
foreach(Instruction inst in body) { |
||||||
ILExpression expr = new ILExpression(inst.OpCode, inst.Operand); |
ILExpression expr = new ILExpression(inst.OpCode, inst.Operand); |
||||||
|
|
||||||
// Label for this instruction
|
// Label for this instruction
|
||||||
ILLabel label; |
ILLabel label; |
||||||
if (labels.TryGetValue(inst, out label)) { |
if (labels.TryGetValue(inst, out label)) { |
||||||
ast.Add(label); |
ast.Add(label); |
||||||
} |
} |
||||||
|
|
||||||
// Reference arguments using temporary variables
|
// Reference arguments using temporary variables
|
||||||
ILStack stack = stackBefore[inst]; |
ILStack stack = stackBefore[inst]; |
||||||
int popCount = inst.GetPopCount(); |
int popCount = inst.GetPopCount(); |
||||||
if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all
|
if (popCount == int.MaxValue) popCount = stackBefore[inst].Items.Count; // Pop all
|
||||||
for (int i = stack.Items.Count - popCount; i < stack.Items.Count; i++) { |
for (int i = stack.Items.Count - popCount; i < stack.Items.Count; i++) { |
||||||
Instruction pushedBy = stack.Items[i].PushedBy; |
Instruction pushedBy = stack.Items[i].PushedBy; |
||||||
if (pushedBy != null) { |
if (pushedBy != null) { |
||||||
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "expr" + pushedBy.Offset.ToString("X2") }); |
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "expr" + pushedBy.Offset.ToString("X2") }); |
||||||
expr.Arguments.Add(ldExpr); |
expr.Arguments.Add(ldExpr); |
||||||
} else { |
} else { |
||||||
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "exception" }); |
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new ILStackVariable() { Name = "exception" }); |
||||||
expr.Arguments.Add(ldExpr); |
expr.Arguments.Add(ldExpr); |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
// If the bytecode pushes anything store the result in temporary variable
|
// If the bytecode pushes anything store the result in temporary variable
|
||||||
int pushCount = inst.GetPushCount(); |
int pushCount = inst.GetPushCount(); |
||||||
if (pushCount > 0) { |
if (pushCount > 0) { |
||||||
ILExpression stExpr = new ILExpression(OpCodes.Stloc, new ILStackVariable() { Name = "expr" + inst.Offset.ToString("X2"), RefCount = pushCount }); |
ILExpression stExpr = new ILExpression(OpCodes.Stloc, new ILStackVariable() { Name = "expr" + inst.Offset.ToString("X2"), RefCount = pushCount }); |
||||||
stExpr.Arguments.Add(expr); |
stExpr.Arguments.Add(expr); |
||||||
expr = stExpr; |
expr = stExpr; |
||||||
} |
} |
||||||
|
|
||||||
ast.Add(expr); |
ast.Add(expr); |
||||||
} |
} |
||||||
|
|
||||||
// Try to in-line stloc / ldloc pairs
|
// Try to in-line stloc / ldloc pairs
|
||||||
for(int i = 0; i < ast.Count - 1; i++) { |
for(int i = 0; i < ast.Count - 1; i++) { |
||||||
ILExpression expr = ast[i] as ILExpression; |
ILExpression expr = ast[i] as ILExpression; |
||||||
ILExpression nextExpr = ast[i + 1] as ILExpression; |
ILExpression nextExpr = ast[i + 1] as ILExpression; |
||||||
|
|
||||||
if (expr != null && nextExpr != null && expr.OpCode.Code == Code.Stloc && expr.Operand is ILStackVariable) { |
if (expr != null && nextExpr != null && expr.OpCode.Code == Code.Stloc && expr.Operand is ILStackVariable) { |
||||||
|
|
||||||
// If the next expression is stloc, look inside
|
// If the next expression is stloc, look inside
|
||||||
if (nextExpr.OpCode.Code == Code.Stloc && nextExpr.Operand is ILStackVariable) { |
if (nextExpr.OpCode.Code == Code.Stloc && nextExpr.Operand is ILStackVariable) { |
||||||
nextExpr = nextExpr.Arguments[0]; |
nextExpr = nextExpr.Arguments[0]; |
||||||
} |
} |
||||||
|
|
||||||
// Find the use of the 'expr'
|
// Find the use of the 'expr'
|
||||||
for(int j = 0; j < nextExpr.Arguments.Count; j++) { |
for(int j = 0; j < nextExpr.Arguments.Count; j++) { |
||||||
ILExpression arg = nextExpr.Arguments[j]; |
ILExpression arg = nextExpr.Arguments[j]; |
||||||
|
|
||||||
// TODO: Check if duplicating the dup opcode has side-effects
|
// TODO: Check if duplicating the dup opcode has side-effects
|
||||||
|
|
||||||
if (arg.OpCode.Code == Code.Ldloc && arg.Operand is ILStackVariable) { |
if (arg.OpCode.Code == Code.Ldloc && arg.Operand is ILStackVariable) { |
||||||
ILStackVariable stVar = (ILStackVariable)expr.Operand; |
ILStackVariable stVar = (ILStackVariable)expr.Operand; |
||||||
ILStackVariable ldVar = (ILStackVariable)arg.Operand; |
ILStackVariable ldVar = (ILStackVariable)arg.Operand; |
||||||
if (stVar.Name == ldVar.Name) { |
if (stVar.Name == ldVar.Name) { |
||||||
stVar.RefCount--; |
stVar.RefCount--; |
||||||
if (stVar.RefCount <= 0) { |
if (stVar.RefCount <= 0) { |
||||||
ast.RemoveAt(i); |
ast.RemoveAt(i); |
||||||
} |
} |
||||||
nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body
|
nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body
|
||||||
i = Math.Max(0, i - 2); // Try the same index again
|
i = Math.Max(0, i - 2); // Try the same index again
|
||||||
break; // Found
|
break; // Found
|
||||||
} |
} |
||||||
} else { |
} else { |
||||||
break; // This argument might have side effects so we can not move the 'expr' after it.
|
break; // This argument might have side effects so we can not move the 'expr' after it.
|
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
return ast; |
return ast; |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,87 +1,87 @@ |
|||||||
using System; |
using System; |
||||||
using System.Collections.Generic; |
using System.Collections.Generic; |
||||||
using System.Text; |
using System.Text; |
||||||
|
|
||||||
using Decompiler.ControlFlow; |
using Decompiler.ControlFlow; |
||||||
using Mono.Cecil; |
using Mono.Cecil; |
||||||
using Mono.Cecil.Cil; |
using Mono.Cecil.Cil; |
||||||
using Cecil = Mono.Cecil; |
using Cecil = Mono.Cecil; |
||||||
|
|
||||||
namespace Decompiler |
namespace Decompiler |
||||||
{ |
{ |
||||||
public class ILNode |
public class ILNode |
||||||
{ |
{ |
||||||
} |
} |
||||||
|
|
||||||
public class ILLabel: ILNode |
public class ILLabel: ILNode |
||||||
{ |
{ |
||||||
public string Name; |
public string Name; |
||||||
|
|
||||||
public override string ToString() |
public override string ToString() |
||||||
{ |
{ |
||||||
return Name + ":"; |
return Name + ":"; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public class ILTryCatchBlock: ILNode |
public class ILTryCatchBlock: ILNode |
||||||
{ |
{ |
||||||
public class CatchBlock |
public class CatchBlock |
||||||
{ |
{ |
||||||
public TypeReference ExceptionType; |
public TypeReference ExceptionType; |
||||||
public List<ILNode> Body; |
public List<ILNode> Body; |
||||||
} |
} |
||||||
|
|
||||||
public List<ILNode> TryBlock; |
public List<ILNode> TryBlock; |
||||||
public List<CatchBlock> CatchBlocks; |
public List<CatchBlock> CatchBlocks; |
||||||
public List<ILNode> FinallyBlock; |
public List<ILNode> FinallyBlock; |
||||||
|
|
||||||
public override string ToString() |
public override string ToString() |
||||||
{ |
{ |
||||||
return "Try-Catch{}"; |
return "Try-Catch{}"; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public class ILStackVariable |
public class ILStackVariable |
||||||
{ |
{ |
||||||
public string Name; |
public string Name; |
||||||
public int RefCount; |
public int RefCount; |
||||||
|
|
||||||
public override string ToString() |
public override string ToString() |
||||||
{ |
{ |
||||||
return Name; |
return Name; |
||||||
} |
} |
||||||
} |
} |
||||||
|
|
||||||
public class ILExpression: ILNode |
public class ILExpression: ILNode |
||||||
{ |
{ |
||||||
public OpCode OpCode { get; set; } |
public OpCode OpCode { get; set; } |
||||||
public object Operand { get; set; } |
public object Operand { get; set; } |
||||||
public List<ILExpression> Arguments { get; set; } |
public List<ILExpression> Arguments { get; set; } |
||||||
|
|
||||||
public ILExpression(OpCode opCode, object operand, params ILExpression[] args) |
public ILExpression(OpCode opCode, object operand, params ILExpression[] args) |
||||||
{ |
{ |
||||||
this.OpCode = opCode; |
this.OpCode = opCode; |
||||||
this.Operand = operand; |
this.Operand = operand; |
||||||
this.Arguments = new List<ILExpression>(args); |
this.Arguments = new List<ILExpression>(args); |
||||||
} |
} |
||||||
|
|
||||||
public override string ToString() |
public override string ToString() |
||||||
{ |
{ |
||||||
StringBuilder sb = new StringBuilder(); |
StringBuilder sb = new StringBuilder(); |
||||||
sb.Append(OpCode.Name); |
sb.Append(OpCode.Name); |
||||||
sb.Append('('); |
sb.Append('('); |
||||||
bool first = true; |
bool first = true; |
||||||
if (Operand != null) { |
if (Operand != null) { |
||||||
sb.Append(Operand.ToString()); |
sb.Append(Operand.ToString()); |
||||||
first = false; |
first = false; |
||||||
} |
} |
||||||
foreach (ILExpression arg in this.Arguments) { |
foreach (ILExpression arg in this.Arguments) { |
||||||
if (!first) sb.Append(","); |
if (!first) sb.Append(","); |
||||||
sb.Append(arg.ToString()); |
sb.Append(arg.ToString()); |
||||||
first = false; |
first = false; |
||||||
} |
} |
||||||
sb.Append(')'); |
sb.Append(')'); |
||||||
return sb.ToString(); |
return sb.ToString(); |
||||||
} |
} |
||||||
} |
} |
||||||
} |
} |
||||||
@ -1,22 +1,22 @@ |
|||||||
using System; |
using System; |
||||||
|
|
||||||
namespace Decompiler |
namespace Decompiler |
||||||
{ |
{ |
||||||
public static class Options |
public static class Options |
||||||
{ |
{ |
||||||
public static string TypeFilter = null; |
public static string TypeFilter = null; |
||||||
public static int CollapseExpression = 1000; |
public static int CollapseExpression = 1000; |
||||||
public static int ReduceGraph = 1000; |
public static int ReduceGraph = 1000; |
||||||
public static bool NodeComments = false; |
public static bool NodeComments = false; |
||||||
public static bool ReduceLoops = true; |
public static bool ReduceLoops = true; |
||||||
public static bool ReduceConditonals = true; |
public static bool ReduceConditonals = true; |
||||||
public static bool ReduceAstJumps = true; |
public static bool ReduceAstJumps = true; |
||||||
public static bool ReduceAstLoops = true; |
public static bool ReduceAstLoops = true; |
||||||
public static bool ReduceAstOther = true; |
public static bool ReduceAstOther = true; |
||||||
} |
} |
||||||
|
|
||||||
class StopOptimizations: Exception |
class StopOptimizations: Exception |
||||||
{ |
{ |
||||||
|
|
||||||
} |
} |
||||||
} |
} |
||||||
Loading…
Reference in new issue