diff --git a/Decompiler.csproj b/Decompiler.csproj
index b3be72fb4..9a315da95 100644
--- a/Decompiler.csproj
+++ b/Decompiler.csproj
@@ -48,6 +48,8 @@
+
+
MainForm.cs
diff --git a/src/AstMetodBodyBuilder.cs b/src/AstMetodBodyBuilder.cs
index 9202147a8..7bda9a6e3 100644
--- a/src/AstMetodBodyBuilder.cs
+++ b/src/AstMetodBodyBuilder.cs
@@ -19,6 +19,7 @@ namespace Decompiler
methodDef.Body.Simplify();
ByteCodeCollection body = new ByteCodeCollection(methodDef);
+ StackExpressionCollection exprCol = new StackExpressionCollection(body);
foreach(VariableDefinition varDef in methodDef.Body.Variables) {
Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name);
@@ -27,34 +28,19 @@ namespace Decompiler
astBlock.Children.Add(astLocalVar);
}
- foreach(ByteCode byteCode in body) {
- OpCode opCode = byteCode.OpCode;
- string description =
- string.Format(" {1, -22} # {2}->{3} {4} {5}",
- byteCode.Offset,
- opCode + " " + FormatByteCodeOperand(byteCode.Operand),
- opCode.StackBehaviourPop,
- opCode.StackBehaviourPush,
- opCode.FlowControl == FlowControl.Next ? string.Empty : "Flow=" + opCode.FlowControl,
- opCode.OpCodeType == OpCodeType.Macro ? "(macro)" : string.Empty);
-
+ foreach(StackExpression expr in exprCol) {
Ast.Statement astStatement = null;
try {
- int argCount = byteCode.PopCount;
- Ast.Expression[] args = new Ast.Expression[argCount];
- for(int i = 0; i < argCount; i++) {
- ByteCode allocBy = byteCode.StackBefore.Peek(argCount - i).AllocadedBy;
- string name = string.Format("expr{0:X2}", allocBy.Offset);
- args[i] = new Ast.IdentifierExpression(name);
+ List args = new List();
+ foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) {
+ string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset);
+ args.Add(new Ast.IdentifierExpression(name));
}
- object codeExpr = MakeCodeDomExpression(
- methodDef,
- byteCode,
- args);
+ object codeExpr = MakeCodeDomExpression(methodDef, expr, args.ToArray());
if (codeExpr is Ast.Expression) {
- if (byteCode.PushCount == 1) {
- string type = byteCode.Type.FullName;
- string name = string.Format("expr{0:X2}", byteCode.Offset);
+ if (expr.PushCount == 1) {
+ string type = expr.ExpressionByteCode.Type.FullName;
+ string name = string.Format("expr{0:X2}", expr.ExpressionByteCode.Offset);
Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString()));
astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr));
astStatement = astLocal;
@@ -65,14 +51,12 @@ namespace Decompiler
astStatement = (Ast.Statement)codeExpr;
}
} catch (NotImplementedException) {
- astStatement = MakeComment(description);
+ astStatement = MakeComment(expr.ExpressionByteCode.Description);
}
- //astBlock.Children.Add(MakeComment(description));
- if (byteCode.BranchesHere.Count > 0) {
- astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", byteCode.Offset)));
+ if (expr.FirstByteCode.BranchesHere.Count > 0) {
+ astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", expr.FirstByteCode.Offset)));
}
astBlock.Children.Add(astStatement);
- //astBlock.Children.Add(MakeComment(" " + stackAnalysis.StackAfter[instr].ToString()));
}
return astBlock;
@@ -84,27 +68,16 @@ namespace Decompiler
return new Ast.ExpressionStatement(new PrimitiveExpression(text, text));
}
- static object FormatByteCodeOperand(object operand)
+ static object MakeCodeDomExpression(MethodDefinition methodDef, StackExpression expr, params Ast.Expression[] args)
{
- if (operand == null) {
- return string.Empty;
- } else if (operand is ByteCode) {
- return string.Format("IL_{0:X2}", ((ByteCode)operand).Offset);
- } else if (operand is MethodReference) {
- return ((MethodReference)operand).Name + "()";
- } else if (operand is Cecil.TypeReference) {
- return ((Cecil.TypeReference)operand).FullName;
- } else if (operand is VariableDefinition) {
- return ((VariableDefinition)operand).Name;
- } else if (operand is ParameterDefinition) {
- return ((ParameterDefinition)operand).Name;
- } else if (operand is string) {
- return "\"" + operand + "\"";
- } else if (operand is int) {
- return operand.ToString();
- } else {
- return "(" + operand.GetType() + ")";
+ List allArgs = new List();
+ // Add args from stack
+ allArgs.AddRange(args);
+ // Args generated by nested expressions
+ foreach(StackExpression nestedExpr in expr.LastArguments) {
+ allArgs.Add(new Ast.ParenthesizedExpression((Ast.Expression)MakeCodeDomExpression(methodDef, nestedExpr)));
}
+ return MakeCodeDomExpression(methodDef, expr.ExpressionByteCode, args);
}
static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args)
diff --git a/src/ByteCode.StackBehaviour.cs b/src/ByteCode.StackBehaviour.cs
index 2a910ac9a..f4d462c94 100644
--- a/src/ByteCode.StackBehaviour.cs
+++ b/src/ByteCode.StackBehaviour.cs
@@ -11,43 +11,19 @@ namespace Decompiler
{
public int PopCount {
get {
- int popCount;
- int pushCount;
- SimulateStackSize(out popCount, out pushCount);
- return popCount;
+ return GetPopCount();
}
}
public int PushCount {
get {
- int popCount;
- int pushCount;
- SimulateStackSize(out popCount, out pushCount);
- return pushCount;
+ return GetPushCount();
}
}
- void SimulateStackSize(out int popCount, out int pushCount)
+ int GetPopCount()
{
- int stackSize = 0;
- int minStackSize = 0;
- foreach(ByteCode bc in nestedByteCodes) {
- stackSize -= bc.PopCount;
- minStackSize = Math.Min(minStackSize, stackSize);
- stackSize += bc.PushCount;
- }
- {
- stackSize -= GetPopCount(methodDef, this);
- minStackSize = Math.Min(minStackSize, stackSize);
- stackSize += GetPushCount(methodDef, this);
- }
- popCount = -minStackSize;
- pushCount = stackSize - minStackSize;
- }
-
- static int GetPopCount(MethodDefinition methodDef, ByteCode byteCode)
- {
- switch(byteCode.OpCode.StackBehaviourPop) {
+ switch(this.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1;
@@ -68,9 +44,9 @@ namespace Decompiler
case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: throw new Exception("PopAll");
case StackBehaviour.Varpop:
- switch(byteCode.OpCode.Code) {
+ switch(this.OpCode.Code) {
case Code.Call:
- Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand);
+ Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand);
if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */;
} else {
@@ -87,13 +63,13 @@ namespace Decompiler
case Code.Newobj: throw new NotImplementedException();
default: throw new Exception("Unknown Varpop opcode");
}
- default: throw new Exception("Unknown pop behaviour: " + byteCode.OpCode.StackBehaviourPop);
+ default: throw new Exception("Unknown pop behaviour: " + this.OpCode.StackBehaviourPop);
}
}
- static int GetPushCount(MethodDefinition methodDef, ByteCode byteCode)
+ int GetPushCount()
{
- switch(byteCode.OpCode.StackBehaviourPush) {
+ switch(this.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2;
@@ -103,9 +79,9 @@ namespace Decompiler
case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls
- switch(byteCode.OpCode.Code) {
+ switch(this.OpCode.Code) {
case Code.Call:
- Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand);
+ Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand);
if (cecilMethod.ReturnType.ReturnType.FullName == Constants.Void) {
return 0;
} else {
@@ -115,7 +91,7 @@ namespace Decompiler
case Code.Callvirt: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
- default: throw new Exception("Unknown push behaviour: " + byteCode.OpCode.StackBehaviourPush);
+ default: throw new Exception("Unknown push behaviour: " + this.OpCode.StackBehaviourPush);
}
}
}
diff --git a/src/ByteCode.cs b/src/ByteCode.cs
index a4b8206e3..470305ffe 100644
--- a/src/ByteCode.cs
+++ b/src/ByteCode.cs
@@ -12,8 +12,6 @@ namespace Decompiler
ByteCode previous;
ByteCode next;
- List nestedByteCodes = new List();
-
MethodDefinition methodDef;
int offset;
OpCode opCode;
@@ -29,10 +27,6 @@ namespace Decompiler
set { next = value; }
}
- public List NestedByteCodes {
- get { return nestedByteCodes; }
- }
-
public int Offset {
get { return offset; }
set { offset = value; }
@@ -68,5 +62,42 @@ namespace Decompiler
this.opCode = inst.OpCode;
this.operand = inst.Operand;
}
+
+ public string Description {
+ get {
+ return string.Format(
+ " {1, -22} # {2}->{3} {4} {5}",
+ this.Offset,
+ this.OpCode + " " + FormatByteCodeOperand(this.Operand),
+ this.OpCode.StackBehaviourPop,
+ this.OpCode.StackBehaviourPush,
+ this.OpCode.FlowControl == FlowControl.Next ? string.Empty : "Flow=" + opCode.FlowControl,
+ this.OpCode.OpCodeType == OpCodeType.Macro ? "(macro)" : string.Empty
+ );
+ }
+ }
+
+ static object FormatByteCodeOperand(object operand)
+ {
+ if (operand == null) {
+ return string.Empty;
+ } else if (operand is ByteCode) {
+ return string.Format("IL_{0:X2}", ((ByteCode)operand).Offset);
+ } else if (operand is MethodReference) {
+ return ((MethodReference)operand).Name + "()";
+ } else if (operand is Cecil.TypeReference) {
+ return ((Cecil.TypeReference)operand).FullName;
+ } else if (operand is VariableDefinition) {
+ return ((VariableDefinition)operand).Name;
+ } else if (operand is ParameterDefinition) {
+ return ((ParameterDefinition)operand).Name;
+ } else if (operand is string) {
+ return "\"" + operand + "\"";
+ } else if (operand is int) {
+ return operand.ToString();
+ } else {
+ return "(" + operand.GetType() + ")";
+ }
+ }
}
}
diff --git a/src/CilStack.cs b/src/CilStack.cs
index 56ae91286..f4d066e97 100644
--- a/src/CilStack.cs
+++ b/src/CilStack.cs
@@ -75,6 +75,11 @@ namespace Decompiler
this.Add(slot);
}
+ public CilStackSlot[] PeekCount(int count)
+ {
+ return this.GetRange(this.Count - count, count).ToArray();
+ }
+
public CilStackSlot Peek(int depth)
{
return this[this.Count - depth];
diff --git a/src/StackExpression.cs b/src/StackExpression.cs
new file mode 100644
index 000000000..59714bfdf
--- /dev/null
+++ b/src/StackExpression.cs
@@ -0,0 +1,86 @@
+using System;
+using System.Collections.Generic;
+
+using Cecil = Mono.Cecil;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Decompiler
+{
+ public class StackExpression
+ {
+ ByteCode expressionByteCode;
+ List lastArguments = new List();
+
+ public ByteCode ExpressionByteCode {
+ get { return expressionByteCode; }
+ }
+
+ public List LastArguments {
+ get { return lastArguments; }
+ }
+
+ public CilStack StackBefore {
+ get {
+ return this.FirstByteCode.StackBefore;
+ }
+ }
+
+ public CilStack StackAfter {
+ get {
+ return this.ExpressionByteCode.StackAfter;
+ }
+ }
+
+ public int PopCount {
+ get {
+ int popCount;
+ int pushCount;
+ SimulateStackSize(out popCount, out pushCount);
+ return popCount;
+ }
+ }
+
+ public int PushCount {
+ get {
+ int popCount;
+ int pushCount;
+ SimulateStackSize(out popCount, out pushCount);
+ return pushCount;
+ }
+ }
+
+ void SimulateStackSize(out int popCount, out int pushCount)
+ {
+ int stackSize = 0;
+ int minStackSize = 0;
+ foreach(StackExpression expr in lastArguments) {
+ stackSize -= expr.PopCount;
+ minStackSize = Math.Min(minStackSize, stackSize);
+ stackSize += expr.PushCount;
+ }
+ {
+ stackSize -= expressionByteCode.PopCount;
+ minStackSize = Math.Min(minStackSize, stackSize);
+ stackSize += expressionByteCode.PushCount;
+ }
+ popCount = -minStackSize;
+ pushCount = stackSize - minStackSize;
+ }
+
+ public ByteCode FirstByteCode {
+ get {
+ if (lastArguments.Count > 0) {
+ return lastArguments[0].FirstByteCode;
+ } else {
+ return this.ExpressionByteCode;
+ }
+ }
+ }
+
+ public StackExpression(ByteCode expressionByteCode)
+ {
+ this.expressionByteCode = expressionByteCode;
+ }
+ }
+}
diff --git a/src/StackExpressionCollection.cs b/src/StackExpressionCollection.cs
new file mode 100644
index 000000000..81beb2a81
--- /dev/null
+++ b/src/StackExpressionCollection.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+
+using Cecil = Mono.Cecil;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Decompiler
+{
+ public class StackExpressionCollection: List
+ {
+ public StackExpressionCollection(ByteCodeCollection byteCodeCol)
+ {
+ foreach(ByteCode bc in byteCodeCol) {
+ this.Add(new StackExpression(bc));
+ }
+ }
+
+ public void Optimize()
+ {
+
+ }
+ }
+}