Browse Source

Refactoring the data model

pull/1/head^2
David Srbecký 15 years ago
parent
commit
eed0f0af6c
  1. 59
      Decompiler.csproj
  2. 2
      Decompiler.sln
  3. 2
      src/Ast/AstBuilder.cs
  4. 108
      src/Ast/AstMetodBodyBuilder.cs
  5. 0
      src/Ast/Transforms/Idioms.cs
  6. 0
      src/Ast/Transforms/PushNegation.cs
  7. 0
      src/Ast/Transforms/RemoveDeadLabels.cs
  8. 0
      src/Ast/Transforms/RemoveEmptyElseBody.cs
  9. 0
      src/Ast/Transforms/RemoveGotos.cs
  10. 0
      src/Ast/Transforms/RemoveParenthesis.cs
  11. 0
      src/Ast/Transforms/RestoreLoop.cs
  12. 0
      src/Ast/Transforms/SimplifyTypeReferences.cs
  13. 83
      src/ByteCode.StackAnalysis.cs
  14. 100
      src/ByteCode.StackBehaviour.cs
  15. 116
      src/ByteCode.cs
  16. 100
      src/ByteCodeCollection.cs
  17. 137
      src/ByteCodeExpression.cs
  18. 108
      src/ByteCodeExpressionCollection.cs
  19. 144
      src/CilStack.cs
  20. 4
      src/ILAst/ControlFlow/Node-Optimize.cs
  21. 0
      src/ILAst/ControlFlow/Node-Structure.cs
  22. 3
      src/ILAst/ControlFlow/Node-Transforms.cs
  23. 0
      src/ILAst/ControlFlow/NodeCollection.cs
  24. 38
      src/ILAst/ControlFlow/Nodes.cs
  25. 246
      src/ILAst/ILAstBuilder.cs
  26. 60
      src/ILAst/ILAstTypes.cs
  27. 0
      src/Mono.Cecil.Rocks/Constants.cs
  28. 628
      src/Mono.Cecil.Rocks/MyRocks.cs
  29. 14
      src/Options.cs
  30. 16
      src/Util.cs
  31. BIN
      tests/QuickSort/bin/Release/QuickSort.exe

59
Decompiler.csproj

@ -55,52 +55,39 @@ @@ -55,52 +55,39 @@
</ItemGroup>
<ItemGroup>
<Folder Include="src" />
<Folder Include="src\ControlFlow" />
<Folder Include="src\ILAst\ControlFlow" />
<Folder Include="src\Mono.Cecil.Rocks" />
<Folder Include="src\Transforms" />
<Folder Include="src\Transforms\Ast" />
<Folder Include="src\ILAst" />
<Folder Include="src\Ast" />
<Folder Include="src\Ast\Transforms" />
<Compile Include="src\AssemblyInfo.cs" />
<Compile Include="src\AstBuilder.cs" />
<Compile Include="src\AstMetodBodyBuilder.cs" />
<Compile Include="src\ByteCode.cs" />
<Compile Include="src\ByteCode.StackBehaviour.cs" />
<Compile Include="src\ByteCode.Type.cs" />
<Compile Include="src\ByteCodeCollection.cs" />
<Compile Include="src\CilStack.cs" />
<Compile Include="src\Constants.cs" />
<Compile Include="src\ControlFlow\Node-Optimize.cs" />
<Compile Include="src\ControlFlow\Node-Transforms.cs" />
<Compile Include="src\ControlFlow\NodeCollection.cs" />
<Compile Include="src\ControlFlow\Nodes.cs" />
<Compile Include="src\ControlFlow\Node-Structure.cs" />
<Compile Include="src\Ast\AstBuilder.cs" />
<Compile Include="src\Ast\AstMetodBodyBuilder.cs" />
<Compile Include="src\Ast\Transforms\Idioms.cs" />
<Compile Include="src\Ast\Transforms\PushNegation.cs" />
<Compile Include="src\Ast\Transforms\RemoveDeadLabels.cs" />
<Compile Include="src\Ast\Transforms\RemoveEmptyElseBody.cs" />
<Compile Include="src\Ast\Transforms\RemoveGotos.cs" />
<Compile Include="src\Ast\Transforms\RemoveParenthesis.cs" />
<Compile Include="src\Ast\Transforms\RestoreLoop.cs" />
<Compile Include="src\Ast\Transforms\SimplifyTypeReferences.cs" />
<Compile Include="src\ILAst\ControlFlow\Node-Optimize.cs" />
<Compile Include="src\ILAst\ControlFlow\Node-Transforms.cs" />
<Compile Include="src\ILAst\ControlFlow\NodeCollection.cs" />
<Compile Include="src\ILAst\ControlFlow\Nodes.cs" />
<Compile Include="src\ILAst\ControlFlow\Node-Structure.cs" />
<Compile Include="src\ILAst\ILAstBuilder.cs" />
<Compile Include="src\ILAst\ILAstTypes.cs" />
<Compile Include="src\MainForm.cs" />
<Compile Include="src\MainForm.Designer.cs" />
<Compile Include="src\Mono.Cecil.Rocks\Constants.cs" />
<Compile Include="src\Mono.Cecil.Rocks\MethodBodyRocks.cs" />
<Compile Include="src\Mono.Cecil.Rocks\MyRocks.cs" />
<Compile Include="src\Options.cs" />
<Compile Include="src\Program.cs" />
<Compile Include="src\ByteCode.StackAnalysis.cs" />
<Compile Include="src\ByteCodeExpression.cs" />
<Compile Include="src\ByteCodeExpressionCollection.cs" />
<Compile Include="src\Transforms\Ast\PushNegation.cs" />
<Compile Include="src\Transforms\Ast\Idioms.cs" />
<Compile Include="src\Transforms\Ast\RemoveDeadLabels.cs" />
<Compile Include="src\Transforms\Ast\RemoveEmptyElseBody.cs" />
<Compile Include="src\Transforms\Ast\RemoveGotos.cs" />
<Compile Include="src\Transforms\Ast\RemoveParenthesis.cs" />
<Compile Include="src\Transforms\Ast\RestoreLoop.cs" />
<Compile Include="src\Transforms\Ast\SimplifyTypeReferences.cs" />
<Compile Include="src\Util.cs" />
<EmbeddedResource Include="src\MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<None Include="tests\QuickSort\bin\Release\QuickSort.exe">
<Link>QuickSort.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="tests\Reversi\bin\Release\Reversi.exe">
<Link>Reversi.exe</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<ProjectReference Include="lib\Mono.Cecil\Mono.Cecil.csproj">
<Project>{D68133BD-1E63-496E-9EDE-4FBDBF77B486}</Project>
<Name>Mono.Cecil</Name>

2
Decompiler.sln

@ -1,7 +1,7 @@ @@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
# SharpDevelop 4.0.0.6486
# SharpDevelop 4.1.0.7279-alpha
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Decompiler", "Decompiler.csproj", "{EE3A3C1A-F9C3-4C75-853D-A9476E518C3A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NRefactory", "lib\NRefactory\Project\NRefactory.csproj", "{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}"

2
src/AstBuilder.cs → src/Ast/AstBuilder.cs

@ -73,7 +73,7 @@ namespace Decompiler @@ -73,7 +73,7 @@ namespace Decompiler
int startIndex = code.LastIndexOf("\r\n", endIndex, endIndex);
if (startIndex != -1) {
code = code.Remove(endIndex, "[Tab]".Length);
code = code.Insert(endIndex, new string(' ', 40 - endIndex + startIndex));
code = code.Insert(endIndex, new string(' ', Math.Max(0, 40 - endIndex + startIndex)));
continue;
}
}

108
src/AstMetodBodyBuilder.cs → src/Ast/AstMetodBodyBuilder.cs

@ -23,7 +23,11 @@ namespace Decompiler @@ -23,7 +23,11 @@ namespace Decompiler
{
AstMetodBodyBuilder builder = new AstMetodBodyBuilder();
builder.methodDef = methodDef;
return builder.CreateMetodBody();
try {
return builder.CreateMetodBody();
} catch {
return new BlockStatement();
}
}
public BlockStatement CreateMetodBody()
@ -34,19 +38,10 @@ namespace Decompiler @@ -34,19 +38,10 @@ namespace Decompiler
methodDef.Body.SimplifyMacros();
ByteCodeCollection body = new ByteCodeCollection(methodDef);
ByteCodeExpressionCollection exprCollection = new ByteCodeExpressionCollection(body);
try {
exprCollection.Optimize();
} catch (StopOptimizations) {
}
List<ILExpression> body = ILAstBuilder.Build(methodDef);
MethodBodyGraph bodyGraph = new MethodBodyGraph(exprCollection);
try {
bodyGraph.Optimize();
} catch (StopOptimizations) {
}
MethodBodyGraph bodyGraph = new MethodBodyGraph(body);
bodyGraph.Optimize();
List<string> intNames = new List<string>(new string[] {"i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t"});
Dictionary<string, int> typeNames = new Dictionary<string, int>();
@ -113,8 +108,11 @@ namespace Decompiler @@ -113,8 +108,11 @@ namespace Decompiler
yield return new Ast.LabelStatement(node.Label);
if (node is BasicBlock) {
foreach(ByteCodeExpression expr in ((BasicBlock)node).Body) {
yield return TransformExpressionToStatement(expr);
foreach(ILExpression expr in ((BasicBlock)node).Body) {
Statement stmt = TransformExpressionToStatement(expr);
if (stmt != null) {
yield return stmt;
}
}
Node fallThroughNode = ((BasicBlock)node).FallThroughBasicBlock;
// If there is default branch and it is not the following node
@ -196,26 +194,28 @@ namespace Decompiler @@ -196,26 +194,28 @@ namespace Decompiler
}
}
List<Ast.Expression> TransformExpressionArguments(ByteCodeExpression expr)
List<Ast.Expression> TransformExpressionArguments(ILExpression expr)
{
List<Ast.Expression> args = new List<Ast.Expression>();
// Args generated by nested expressions (which must be closed)
foreach(ByteCodeExpression arg in expr.Arguments) {
foreach(ILExpression arg in expr.Arguments) {
args.Add((Ast.Expression)TransformExpression(arg));
}
return args;
}
object TransformExpression(ByteCodeExpression expr)
object TransformExpression(ILExpression expr)
{
List<Ast.Expression> args = TransformExpressionArguments(expr);
return TransformByteCode(methodDef, expr, args);
}
Ast.Statement TransformExpressionToStatement(ByteCodeExpression expr)
Ast.Statement TransformExpressionToStatement(ILExpression expr)
{
object codeExpr = TransformExpression(expr);
if (codeExpr is Ast.Expression) {
if (codeExpr == null) {
return null;
} else if (codeExpr is Ast.Expression) {
return new Ast.ExpressionStatement((Ast.Expression)codeExpr);
} else if (codeExpr is Ast.Statement) {
return (Ast.Statement)codeExpr;
@ -292,39 +292,64 @@ namespace Decompiler @@ -292,39 +292,64 @@ namespace Decompiler
}
}
static object TransformByteCode(MethodDefinition methodDef, ByteCodeExpression byteCode, List<Ast.Expression> args)
static object TransformByteCode(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
{
try {
Ast.INode ret = TransformByteCode_Internal(methodDef, byteCode, args);
if (ret is Ast.Expression) {
ret = new ParenthesizedExpression((Ast.Expression)ret);
}
ret.UserData["Type"] = byteCode.Type;
// ret.UserData["Type"] = byteCode.Type;
return ret;
} catch (NotImplementedException) {
// Output the operand of the unknown IL code as well
if (byteCode.Operand != null) {
args.Insert(0, new IdentifierExpression(ByteCode.FormatByteCodeOperand(byteCode.Operand)));
args.Insert(0, new IdentifierExpression(FormatByteCodeOperand(byteCode.Operand)));
}
return new Ast.InvocationExpression(new IdentifierExpression("IL__" + byteCode.OpCode.Name), args);
return new Ast.InvocationExpression(new IdentifierExpression("__" + byteCode.OpCode.Name), args);
}
}
static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ByteCodeExpression byteCode, List<Ast.Expression> args)
static string FormatByteCodeOperand(object operand)
{
if (operand == null) {
return string.Empty;
//} else if (operand is ILExpression) {
// return string.Format("IL_{0:X2}", ((ILExpression)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 FieldReference) {
return ((FieldReference)operand).Name;
} else if (operand is string) {
return "\"" + operand + "\"";
} else if (operand is int) {
return operand.ToString();
} else {
return operand.ToString();
}
}
static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ILExpression byteCode, List<Ast.Expression> args)
{
// throw new NotImplementedException();
OpCode opCode = byteCode.OpCode;
object operand = byteCode.Operand;
Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null;
ByteCode operandAsByteCode = operand as ByteCode;
ILExpression operandAsByteCode = operand as ILExpression;
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
Ast.Statement branchCommand = null;
if (byteCode.BranchTarget != null) {
branchCommand = new Ast.GotoStatement(byteCode.BranchTarget.BasicBlock.Label);
if (byteCode.Operand is ILExpression) {
branchCommand = new Ast.GotoStatement(((ILExpression)byteCode.Operand).BasicBlock.Label);
}
switch(opCode.Code) {
@ -609,7 +634,7 @@ namespace Decompiler @@ -609,7 +634,7 @@ namespace Decompiler
new List<Expression>(args)
);
case Code.No: throw new NotImplementedException();
case Code.Nop: return new Ast.PrimitiveExpression("/* No-op */", "/* No-op */");
case Code.Nop: return null;
case Code.Or: throw new NotImplementedException();
case Code.Pop: throw new NotImplementedException();
case Code.Readonly: throw new NotImplementedException();
@ -666,23 +691,24 @@ namespace Decompiler @@ -666,23 +691,24 @@ namespace Decompiler
static Ast.Expression Convert(Ast.Expression expr, string reqType)
{
if (expr.UserData.ContainsKey("Type")) {
Cecil.TypeReference exprType = (Cecil.TypeReference)expr.UserData["Type"];
if (exprType == ByteCode.TypeZero &&
reqType == ByteCode.TypeBool.FullName) {
return new PrimitiveExpression(false, "false");
}
if (exprType == ByteCode.TypeOne &&
reqType == ByteCode.TypeBool.FullName) {
return new PrimitiveExpression(true, "true");
}
}
// if (expr.UserData.ContainsKey("Type")) {
// Cecil.TypeReference exprType = (Cecil.TypeReference)expr.UserData["Type"];
// if (exprType == ByteCode.TypeZero &&
// reqType == ByteCode.TypeBool.FullName) {
// return new PrimitiveExpression(false, "false");
// }
// if (exprType == ByteCode.TypeOne &&
// reqType == ByteCode.TypeBool.FullName) {
// return new PrimitiveExpression(true, "true");
// }
// }
return expr;
}
static Ast.Expression ConvertIntToBool(Ast.Expression astInt)
{
return new Ast.ParenthesizedExpression(new Ast.BinaryOperatorExpression(astInt, BinaryOperatorType.InEquality, new Ast.PrimitiveExpression(0, "0")));
return astInt;
// return new Ast.ParenthesizedExpression(new Ast.BinaryOperatorExpression(astInt, BinaryOperatorType.InEquality, new Ast.PrimitiveExpression(0, "0")));
}
}
}

0
src/Transforms/Ast/Idioms.cs → src/Ast/Transforms/Idioms.cs

0
src/Transforms/Ast/PushNegation.cs → src/Ast/Transforms/PushNegation.cs

0
src/Transforms/Ast/RemoveDeadLabels.cs → src/Ast/Transforms/RemoveDeadLabels.cs

0
src/Transforms/Ast/RemoveEmptyElseBody.cs → src/Ast/Transforms/RemoveEmptyElseBody.cs

0
src/Transforms/Ast/RemoveGotos.cs → src/Ast/Transforms/RemoveGotos.cs

0
src/Transforms/Ast/RemoveParenthesis.cs → src/Ast/Transforms/RemoveParenthesis.cs

0
src/Transforms/Ast/RestoreLoop.cs → src/Ast/Transforms/RestoreLoop.cs

0
src/Transforms/Ast/SimplifyTypeReferences.cs → src/Ast/Transforms/SimplifyTypeReferences.cs

83
src/ByteCode.StackAnalysis.cs

@ -1,83 +0,0 @@ @@ -1,83 +0,0 @@
using System;
using System.Collections.Generic;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public partial class ByteCode
{
CilStack stackBefore;
CilStack stackAfter;
List<ByteCode> branchesHere = new List<ByteCode>();
public CilStack StackBefore {
get { return stackBefore; }
}
public CilStack StackAfter {
get { return stackAfter; }
}
public List<ByteCode> BranchesHere {
get { return branchesHere; }
}
public void MergeStackBeforeWith(CilStack stack)
{
CilStack mergedStack;
if (CilStack.Merge(this.stackBefore, stack, out mergedStack)) {
// Stacks are identical
return;
}
this.stackBefore = mergedStack;
stackAfter = SimulateEffectOnStack(this.StackBefore);
if (this.OpCode.Code == Code.Endfinally) {
return; // TODO
}
if (this.OpCode.Code == Code.Switch) {
this.Next.MergeStackBeforeWith(this.StackAfter);
foreach(ByteCode target in (ByteCode[])this.Operand) {
target.MergeStackBeforeWith(this.StackAfter);
}
return;
}
switch(this.OpCode.FlowControl) {
case FlowControl.Branch:
this.BranchTarget.MergeStackBeforeWith(this.StackAfter);
break;
case FlowControl.Cond_Branch:
this.Next.MergeStackBeforeWith(this.StackAfter);
this.BranchTarget.MergeStackBeforeWith(this.StackAfter);
break;
case FlowControl.Next:
case FlowControl.Call:
this.Next.MergeStackBeforeWith(this.StackAfter);
break;
case FlowControl.Return:
if (this.StackAfter.Count > 0) throw new Exception("Non-empty stack at return instruction");
break;
default: throw new NotImplementedException();
}
}
public CilStack SimulateEffectOnStack(CilStack oldStack)
{
CilStack newStack = oldStack.Clone();
List<Cecil.TypeReference> typeArgs = new List<Cecil.TypeReference>();
foreach(CilStackSlot slot in newStack.PopCount(this.PopCount)) {
typeArgs.Add(slot.Type);
}
for (int i = 0; i < this.PushCount; i++) {
newStack.Push(new CilStackSlot(this, this.GetType(typeArgs.ToArray())));
}
return newStack;
}
}
}

100
src/ByteCode.StackBehaviour.cs

@ -1,100 +0,0 @@ @@ -1,100 +0,0 @@
using System;
using System.Collections.Generic;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public partial class ByteCode
{
public int PopCount {
get {
return GetPopCount();
}
}
public int PushCount {
get {
return GetPushCount();
}
}
int GetPopCount()
{
switch(this.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1;
case StackBehaviour.Popref: return 1;
case StackBehaviour.Pop1_pop1: return 2;
case StackBehaviour.Popi_pop1: return 2;
case StackBehaviour.Popi_popi: return 2;
case StackBehaviour.Popi_popi8: return 2;
case StackBehaviour.Popi_popr4: return 2;
case StackBehaviour.Popi_popr8: return 2;
case StackBehaviour.Popref_pop1: return 2;
case StackBehaviour.Popref_popi: return 2;
case StackBehaviour.Popi_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi8: return 3;
case StackBehaviour.Popref_popi_popr4: return 3;
case StackBehaviour.Popref_popi_popr8: return 3;
case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: return this.StackBefore.Count;
case StackBehaviour.Varpop:
switch(this.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand);
if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */;
} else {
return cecilMethod.Parameters.Count;
}
case Code.Calli: throw new NotImplementedException();
case Code.Ret:
if (methodDef.ReturnType.FullName == Constants.Void) {
return 0;
} else {
return 1;
}
case Code.Newobj:
Cecil.MethodReference ctorMethod = ((MethodReference)this.Operand);
return ctorMethod.Parameters.Count;
default: throw new Exception("Unknown Varpop opcode");
}
default: throw new Exception("Unknown pop behaviour: " + this.OpCode.StackBehaviourPop);
}
}
int GetPushCount()
{
switch(this.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2;
case StackBehaviour.Pushi: return 1;
case StackBehaviour.Pushi8: return 1;
case StackBehaviour.Pushr4: return 1;
case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls
switch(this.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
Cecil.MethodReference cecilMethod = ((MethodReference)this.Operand);
if (cecilMethod.ReturnType.FullName == Constants.Void) {
return 0;
} else {
return 1;
}
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
default: throw new Exception("Unknown push behaviour: " + this.OpCode.StackBehaviourPush);
}
}
}
}

116
src/ByteCode.cs

@ -1,116 +0,0 @@ @@ -1,116 +0,0 @@
using System;
using System.Collections.Generic;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public partial class ByteCode
{
ByteCode previous;
ByteCode next;
MethodDefinition methodDef;
int offset;
OpCode opCode;
object operand;
public ByteCode Previous {
get { return previous; }
set { previous = value; }
}
public ByteCode Next {
get { return next; }
set { next = value; }
}
public int Offset {
get { return offset; }
set { offset = value; }
}
public OpCode OpCode {
get { return opCode; }
set { opCode = value; }
}
public object Operand {
get { return operand; }
set { operand = value; }
}
public ByteCode BranchTarget {
get {
return operand as ByteCode;
}
}
public bool CanBranch {
get {
return OpCode.FlowControl == FlowControl.Branch ||
OpCode.FlowControl == FlowControl.Cond_Branch;
}
}
public ByteCode(MethodDefinition methodDef, Instruction inst)
{
this.methodDef = methodDef;
this.offset = inst.Offset;
this.opCode = inst.OpCode;
this.operand = inst.Operand;
}
public override string ToString()
{
return this.OpCode + " " + FormatByteCodeOperand(this.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
);
}
}
public string FormatedOperand {
get {
return FormatByteCodeOperand(this.Operand);
}
}
public static string 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 FieldReference) {
return ((FieldReference)operand).Name;
} else if (operand is string) {
return "\"" + operand + "\"";
} else if (operand is int) {
return operand.ToString();
} else {
return operand.ToString();
}
}
}
}

100
src/ByteCodeCollection.cs

@ -1,100 +0,0 @@ @@ -1,100 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public class ByteCodeCollection: IEnumerable<ByteCode>
{
List<ByteCode> list = new List<ByteCode>();
public IEnumerator<ByteCode> GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
public int Count {
get {
return list.Count;
}
}
public ByteCode this[int index] {
get {
return list[index];
}
}
public ByteCode GetByOffset(int offset)
{
foreach(ByteCode byteCode in this) {
if (byteCode.Offset == offset) {
return byteCode;
}
}
throw new Exception("Not found");
}
public int IndexOf(ByteCode byteCode)
{
return list.IndexOf(byteCode);
}
public ByteCodeCollection(MethodDefinition methodDef)
{
foreach(Instruction inst in methodDef.Body.Instructions) {
list.Add(new ByteCode(methodDef, inst));
}
foreach(ByteCode byteCode in this) {
if (byteCode.CanBranch) {
if (byteCode.Operand is Instruction[]) {
List<ByteCode> operands = new List<ByteCode>();
foreach(Instruction inst in (Instruction[])byteCode.Operand) {
ByteCode target = GetByOffset(inst.Offset);
operands.Add(target);
target.BranchesHere.Add(byteCode);
}
byteCode.Operand = operands.ToArray();
} else {
ByteCode target = GetByOffset(((Instruction)byteCode.Operand).Offset);
byteCode.Operand = target;
target.BranchesHere.Add(byteCode);
}
}
}
UpdateNextPrevious();
UpdateStackAnalysis(methodDef);
}
void UpdateNextPrevious()
{
for(int i = 0; i < list.Count - 1; i++) {
this[i].Next = this[i + 1];
this[i + 1].Previous = this[i];
}
}
void UpdateStackAnalysis(MethodDefinition methodDef)
{
if (this.Count > 0) {
this[0].MergeStackBeforeWith(CilStack.Empty);
}
foreach(ExceptionHandler handler in methodDef.Body.ExceptionHandlers) {
ByteCode byteCode = this.GetByOffset(handler.HandlerStart.Offset);
CilStack expetionStack = new CilStack();
// TODO: Allocated by what?
expetionStack.Add(new CilStackSlot(byteCode, ByteCode.TypeException));
byteCode.MergeStackBeforeWith(expetionStack);
}
}
}
}

137
src/ByteCodeExpression.cs

@ -1,137 +0,0 @@ @@ -1,137 +0,0 @@
using System;
using System.Collections.Generic;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public class ByteCodeExpression
{
ControlFlow.BasicBlock basicBlock;
OpCode opCode;
object operand;
List<ByteCodeExpression> arguments = new List<ByteCodeExpression>();
bool returnsValue;
Cecil.TypeReference type;
ByteCodeExpression branchTarget;
List<ByteCodeExpression> branchesHere = new List<ByteCodeExpression>();
bool isSSASR = false;
public Decompiler.ControlFlow.BasicBlock BasicBlock {
get { return basicBlock; }
set {
basicBlock = value;
foreach (ByteCodeExpression argument in arguments) {
argument.BasicBlock = value;
}
}
}
public OpCode OpCode {
get { return opCode; }
set { opCode = value; }
}
public object Operand {
get { return operand; }
set { operand = value; }
}
public List<ByteCodeExpression> Arguments {
get { return arguments; }
}
public bool ReturnsValue {
get { return returnsValue; }
set { returnsValue = value; }
}
public TypeReference Type {
get { return type; }
set { type = value; }
}
/// <summary> Single static assignment; single read </summary>
public bool IsSSASR {
get { return isSSASR; }
set { isSSASR = value; }
}
public ByteCodeExpression BranchTarget {
get { return branchTarget; }
set { branchTarget = value; }
}
public List<ByteCodeExpression> BranchesHere {
get { return branchesHere; }
}
public bool IsBranchTarget {
get { return BranchesHere.Count > 0; }
}
public static ByteCodeExpression Ldloc(string name)
{
return new ByteCodeExpression(OpCodes.Ldloc, new VariableDefinition(name, null), true);
}
public static ByteCodeExpression Stloc(string name)
{
return new ByteCodeExpression(OpCodes.Stloc, new VariableDefinition(name, null), false);
}
public ByteCodeExpression(OpCode opCode, object operand, bool returnsValue)
{
this.opCode = opCode;
this.operand = operand;
this.returnsValue = returnsValue;
}
public ByteCodeExpression(ByteCode byteCode)
{
this.OpCode = byteCode.OpCode;
this.Operand = byteCode.Operand;
foreach(CilStackSlot arg in byteCode.StackBefore.PeekCount(byteCode.PopCount)) {
string name = string.Format("expr{0:X2}", arg.AllocadedBy.Offset);
this.Arguments.Add(Ldloc(name));
}
this.ReturnsValue = byteCode.PushCount > 0;
this.Type = byteCode.Type;
}
public override string ToString()
{
return string.Format("[ByteCodeExpression OpCode={0}]", this.opCode);
}
public ByteCodeExpression Clone()
{
ByteCodeExpression clone = (ByteCodeExpression)this.MemberwiseClone();
clone.branchTarget = null;
clone.branchesHere = new List<ByteCodeExpression>();
return clone;
}
public bool IsConstant()
{
if (!IsOpCodeConstant()) return false;
foreach(ByteCodeExpression arg in this.Arguments) {
if (!arg.IsConstant()) return false;
}
return true;
}
bool IsOpCodeConstant()
{
switch(this.OpCode.Code) {
case Code.Ldarg: return true;
default: return false;
}
}
}
}

108
src/ByteCodeExpressionCollection.cs

@ -1,108 +0,0 @@ @@ -1,108 +0,0 @@
using System;
using System.Collections.Generic;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public class ByteCodeExpressionCollection: List<ByteCodeExpression>
{
public ByteCodeExpressionCollection(ByteCodeCollection byteCodeCol)
{
Dictionary<ByteCode, ByteCodeExpression> exprForByteCode = new Dictionary<ByteCode, ByteCodeExpression>();
foreach(ByteCode byteCode in byteCodeCol) {
ByteCodeExpression newExpr = new ByteCodeExpression(byteCode);
// If the bytecode pushes anything encapsulate it with stloc
if (byteCode.PushCount > 0) {
string name = string.Format("expr{0:X2}", byteCode.Offset);
ByteCodeExpression stExpr = ByteCodeExpression.Stloc(name);
stExpr.Arguments.Add(newExpr);
stExpr.IsSSASR = byteCode.PushCount == 1;
newExpr = stExpr;
}
exprForByteCode[byteCode] = newExpr;
this.Add(newExpr);
}
// Branching links
foreach(ByteCodeExpression expr in this) {
if (expr.Operand is ByteCode) {
expr.BranchTarget = exprForByteCode[(ByteCode)expr.Operand];
expr.BranchTarget.BranchesHere.Add(expr);
}
}
}
Dictionary<ByteCodeExpression, object> alreadyDuplicated = new Dictionary<ByteCodeExpression, object>();
public void Optimize()
{
for(int i = 0; i < this.Count - 1; i++) {
if (i < 0) continue;
ByteCodeExpression expr = this[i];
ByteCodeExpression nextExpr = this[i + 1];
// Duplicate 'dup' expressions
if (expr.OpCode.Code == Code.Stloc &&
expr.Arguments[0].OpCode.Code == Code.Dup &&
expr.Arguments[0].Arguments[0].IsConstant() &&
!alreadyDuplicated.ContainsKey(expr))
{
Options.NotifyCollapsingExpression();
this.Insert(i + 1, expr.Clone());
this[i].IsSSASR = true;
this[i + 1].IsSSASR = true;
alreadyDuplicated.Add(this[i], null);
alreadyDuplicated.Add(this[i + 1], null);
continue;
}
// Try to in-line stloc into following expression
if (expr.OpCode.Code == Code.Stloc &&
expr.IsSSASR &&
!nextExpr.IsBranchTarget) {
// If the next expression is stloc, look inside
if (nextExpr.OpCode.Code == Code.Stloc &&
nextExpr.Arguments[0].OpCode.Code != Code.Ldloc) {
nextExpr = nextExpr.Arguments[0];
}
// Find the use of the 'expr'
for(int j = 0; j < nextExpr.Arguments.Count; j++) {
ByteCodeExpression arg = nextExpr.Arguments[j];
if (arg.OpCode.Code == Code.Ldloc &&
((VariableDefinition)arg.Operand).Name == ((VariableDefinition)expr.Operand).Name) {
// Found
Options.NotifyCollapsingExpression();
this.RemoveAt(i); i--; // Remove the stloc
nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body
// Move branch links
foreach(ByteCodeExpression predExpr in expr.BranchesHere) {
predExpr.BranchTarget = this[i + 1];
predExpr.BranchTarget.BranchesHere.Add(predExpr);
}
i--; // Try the same index again
break;
}
if (arg.OpCode.Code != Code.Ldloc) {
// This argument might have side effects so we can not
// move the 'expr' after it. Terminate
break;
}
}
}
}
}
}
}

144
src/CilStack.cs

@ -1,144 +0,0 @@ @@ -1,144 +0,0 @@
using System;
using System.Collections.Generic;
using Ast = ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Ast;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
// Imutable
public struct CilStackSlot {
ByteCode allocadedBy;
Cecil.TypeReference type;
public ByteCode AllocadedBy {
get { return allocadedBy; }
}
public Cecil.TypeReference Type {
get { return type; }
}
public CilStackSlot(ByteCode allocadedBy, Cecil.TypeReference type)
{
if (allocadedBy == null) throw new ArgumentNullException();
if (type == null) throw new ArgumentNullException();
this.allocadedBy = allocadedBy;
this.type = type;
}
public override int GetHashCode()
{
int hashCode = 0;
if (allocadedBy != null) hashCode ^= allocadedBy.GetHashCode();
if (type != null) hashCode ^= type.GetHashCode();
return hashCode;
}
public override bool Equals(object obj)
{
if (!(obj is CilStackSlot)) return false;
CilStackSlot myCilStackSlot = (CilStackSlot)obj;
return object.Equals(this.allocadedBy, myCilStackSlot.allocadedBy) && object.Equals(this.type, myCilStackSlot.type);
}
public override string ToString()
{
if (allocadedBy == null) {
return "<??>";
} else {
return string.Format("expr{0:X2}", this.allocadedBy.Offset);
}
}
}
/// <remarks> The tail of the list is the top of the stack </remarks>
public class CilStack: List<CilStackSlot> {
public static CilStack Empty = new CilStack();
public CilStack Clone()
{
return new CilStack(this);
}
public CilStackSlot[] PopCount(int count)
{
CilStackSlot[] poped = this.GetRange(this.Count - count, count).ToArray();
this.RemoveRange(this.Count - count, count);
return poped;
}
public void Push(CilStackSlot slot)
{
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];
}
public CilStack(): base()
{
}
public CilStack(IEnumerable<CilStackSlot> slotEnum): base(slotEnum)
{
}
// Return true if stacks are same
public static bool Merge(CilStack stack1, CilStack stack2, out CilStack merged)
{
// Both null
if (stack1 == null && stack2 == null) {
throw new Exception("Both stacks are null");
}
// One of stacks null, one is not
if (stack1 == null || stack2 == null) {
merged = stack1 ?? stack2;
return false;
}
// Both are non-null
if (stack1.Count != stack2.Count) {
throw new Exception("Stack merge error: different sizes");
}
bool same = true;
int count = stack1.Count;
merged = stack1.Clone();
for (int i = 0; i < count; i++) {
if (!stack1[i].Equals(stack2[i])) {
// TODO: Do the merge
// merged[i] = new CilStackSlot(null, null); // Merge slots
same = false;
}
}
return same;
}
public override string ToString()
{
string ret = "Stack: {";
bool first = true;
foreach(CilStackSlot slot in this) {
if (!first) ret += ", ";
ret += slot.ToString();
first = false;
}
ret += "}";
return ret;
}
}
}

4
src/ControlFlow/Node-Optimize.cs → src/ILAst/ControlFlow/Node-Optimize.cs

@ -36,7 +36,6 @@ namespace Decompiler.ControlFlow @@ -36,7 +36,6 @@ namespace Decompiler.ControlFlow
}
// If the result is single acyclic node, eliminate it
if (this.Childs.Count == 1 && this.HeadChild is AcyclicGraph) {
Options.NotifyReducingGraph();
Node headChild = this.HeadChild;
this.Childs.Remove(this.HeadChild);
headChild.Childs.MoveTo(this);
@ -173,7 +172,6 @@ namespace Decompiler.ControlFlow @@ -173,7 +172,6 @@ namespace Decompiler.ControlFlow
falseNodes.RemoveRange(commonReachable);
// Replace the basic block with condition node
Options.NotifyReducingGraph();
Node conditionParent = condition.Parent;
int conditionIndex = condition.Index;
ConditionalNode conditionalNode = new ConditionalNode(condition);
@ -181,11 +179,9 @@ namespace Decompiler.ControlFlow @@ -181,11 +179,9 @@ namespace Decompiler.ControlFlow
// If there are no common nodes, let the 'true' block be the default
if (commonReachable.Count > 0) {
Options.NotifyReducingGraph();
trueNodes.MoveTo(conditionalNode.TrueBody);
}
Options.NotifyReducingGraph();
falseNodes.MoveTo(conditionalNode.FalseBody);
// Optimize the created subtrees

0
src/ControlFlow/Node-Structure.cs → src/ILAst/ControlFlow/Node-Structure.cs

3
src/ControlFlow/Node-Transforms.cs → src/ILAst/ControlFlow/Node-Transforms.cs

@ -35,12 +35,10 @@ namespace Decompiler.ControlFlow @@ -35,12 +35,10 @@ namespace Decompiler.ControlFlow
T mergedNode = new T();
// Add the merged node
Options.NotifyReducingGraph();
int headIndex = this.Childs.IndexOf(nodes[0]);
this.Childs.Insert(headIndex, mergedNode);
foreach(Node node in nodes) {
//Options.NotifyReducingGraph();
node.MoveTo(mergedNode);
}
@ -52,7 +50,6 @@ namespace Decompiler.ControlFlow @@ -52,7 +50,6 @@ namespace Decompiler.ControlFlow
Reset:
foreach(Node child in this.Childs) {
if (child is AcyclicGraph) {
Options.NotifyReducingGraph();
child.Childs.MoveTo(this, child.Index);
child.Remove();
goto Reset;

0
src/ControlFlow/NodeCollection.cs → src/ILAst/ControlFlow/NodeCollection.cs

38
src/ControlFlow/Nodes.cs → src/ILAst/ControlFlow/Nodes.cs

@ -1,18 +1,18 @@ @@ -1,18 +1,18 @@
using System;
using System.Collections.Generic;
using Decompiler.Mono.Cecil.Rocks;
using Mono.Cecil.Cil;
namespace Decompiler.ControlFlow
{
public class BasicBlock: Node
{
List<ByteCodeExpression> body = new List<ByteCodeExpression>();
List<ILExpression> body = new List<ILExpression>();
List<BasicBlock> basicBlockPredecessors = new List<BasicBlock>();
BasicBlock fallThroughBasicBlock;
BasicBlock branchBasicBlock;
public List<ByteCodeExpression> Body {
public List<ILExpression> Body {
get { return body; }
}
@ -117,27 +117,22 @@ namespace Decompiler.ControlFlow @@ -117,27 +117,22 @@ namespace Decompiler.ControlFlow
get { return methodEntry; }
}
public MethodBodyGraph(ByteCodeExpressionCollection exprs)
public MethodBodyGraph(List<ILExpression> exprs)
{
if (exprs.Count == 0) throw new ArgumentException("Count == 0", "exprs");
BasicBlock basicBlock = null;
for(int i = 0; i < exprs.Count; i++) {
// Start new basic block if
// - this is first expression
// - last expression was branch
// - this expression is branch target
// - this expression is a branch
if (i == 0 ||
exprs[i - 1].BranchTarget != null ||
exprs[i].BranchesHere.Count > 0 ||
exprs[i].BranchTarget != null)
exprs[i - 1].OpCode.IsBranch() ||
exprs[i].IsBranchTarget ||
exprs[i].OpCode.IsBranch())
{
basicBlock = new BasicBlock();
this.Childs.Add(basicBlock);
}
basicBlock.Body.Add(exprs[i]);
exprs[i].BasicBlock = basicBlock;
exprs[i].SetBasicBlock(basicBlock);
}
// Add fall-through links to BasicBlocks
@ -145,22 +140,17 @@ namespace Decompiler.ControlFlow @@ -145,22 +140,17 @@ namespace Decompiler.ControlFlow
BasicBlock node = exprs[i].BasicBlock;
BasicBlock target = exprs[i + 1].BasicBlock;
// Still same basic block - ignore
if (node == target) continue;
// Non-conditional branch does not fall-through
if (exprs[i].OpCode.Code == Code.Br ||
exprs[i].OpCode.Code == Code.Leave) continue;
node.FallThroughBasicBlock = target;
target.BasicBlockPredecessors.Add(node);
if (target != node && exprs[i].OpCode.CanFallThough()) {
node.FallThroughBasicBlock = target;
target.BasicBlockPredecessors.Add(node);
}
}
// Add branch links to BasicBlocks
for(int i = 0; i < exprs.Count; i++) {
if (exprs[i].BranchTarget != null) {
if (exprs[i].OpCode.IsBranch()) {
BasicBlock node = exprs[i].BasicBlock;
BasicBlock target = exprs[i].BranchTarget.BasicBlock;
BasicBlock target = ((ILExpression)exprs[i].Operand).BasicBlock;
node.BranchBasicBlock = target;
target.BasicBlockPredecessors.Add(node);

246
src/ILAst/ILAstBuilder.cs

@ -0,0 +1,246 @@ @@ -0,0 +1,246 @@
using System;
using System.Collections.Generic;
using System.Text;
using Decompiler.Mono.Cecil.Rocks;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Cecil = Mono.Cecil;
namespace Decompiler
{
public class ILAstBuilder
{
class ByteCode
{
public Instruction Instruction;
public ILStack StackBefore;
public string TmpVarName { get { return "expr" + this.Instruction.Offset; } }
public override string ToString()
{
return string.Format("[{0}, [{1}]]", Instruction, StackBefore);
}
}
class ILStack
{
public class Slot
{
public ByteCode PushedBy;
public TypeReference Type;
public Slot(ByteCode byteCode, TypeReference type)
{
this.PushedBy = byteCode;
this.Type = type;
}
}
public List<Slot> Items = new List<Slot>();
public ILStack Clone()
{
ILStack clone = new ILStack();
foreach(Slot s in this.Items) {
clone.Items.Add(new Slot(s.PushedBy, s.Type));
}
return clone;
}
public void MergeInto(ref ILStack other, out bool changed)
{
if (other == null) {
other = this;
changed = true;
} else {
changed = false;
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
bool first = true;
foreach (Slot s in this.Items) {
if (!first) sb.Append(", ");
sb.Append(s.PushedBy.Instruction.Offset.ToString("X"));
first = false;
}
return sb.ToString();
}
}
public static List<ILExpression> Build(MethodDefinition methodDef)
{
List<ByteCode> body = new List<ByteCode>();
Dictionary<Instruction, ByteCode> instToByteCode = new Dictionary<Instruction, ByteCode>();
// Create the IL body for analisys
foreach(Instruction inst in methodDef.Body.Instructions) {
ByteCode byteCode = new ByteCode();
byteCode.Instruction = inst;
body.Add(byteCode);
instToByteCode.Add(inst, byteCode);
}
// Stack analisys
if (body.Count > 0) {
Queue<ByteCode> agenda = new Queue<ByteCode>();
// Add known states
body[0].StackBefore = new ILStack();
agenda.Enqueue(body[0]);
if(methodDef.Body.HasExceptionHandlers) {
foreach(ExceptionHandler ex in methodDef.Body.ExceptionHandlers) {
ByteCode tryStart = instToByteCode[ex.TryStart];
tryStart.StackBefore = new ILStack();
agenda.Enqueue(tryStart);
ByteCode handlerStart = instToByteCode[ex.HandlerStart];
handlerStart.StackBefore = new ILStack();
handlerStart.StackBefore.Items.Add(new ILStack.Slot(null, MyRocks.TypeException));
agenda.Enqueue(handlerStart);
}
}
// Process agenda
while(agenda.Count > 0) {
ByteCode byteCode = agenda.Dequeue();
// What is the effect of the instruction on the stack?
ILStack newStack = byteCode.StackBefore.Clone();
int popCount = byteCode.Instruction.GetPopCount(methodDef, byteCode.StackBefore.Items.Count);
List<TypeReference> typeArgs = new List<TypeReference>();
for (int i = newStack.Items.Count - popCount; i < newStack.Items.Count; i++) {
typeArgs.Add(newStack.Items[i].Type);
}
TypeReference type;
try {
type = byteCode.Instruction.GetTypeInternal(methodDef, typeArgs);
} catch {
type = MyRocks.TypeObject;
}
if (popCount > 0) {
newStack.Items.RemoveRange(newStack.Items.Count - popCount, popCount);
}
int pushCount = byteCode.Instruction.GetPushCount();
for (int i = 0; i < pushCount; i++) {
newStack.Items.Add(new ILStack.Slot(byteCode, type));
}
// Apply the state to any successors
if (byteCode.Instruction.OpCode.CanFallThough()) {
ByteCode next = instToByteCode[byteCode.Instruction.Next];
bool changed;
newStack.MergeInto(ref next.StackBefore, out changed);
if (changed) agenda.Enqueue(next);
}
if (byteCode.Instruction.OpCode.IsBranch()) {
object operand = byteCode.Instruction.Operand;
if (operand is Instruction) {
ByteCode next = instToByteCode[(Instruction)operand];
bool changed;
newStack.MergeInto(ref next.StackBefore, out changed);
if (changed) agenda.Enqueue(next);
} else {
foreach(Instruction inst in (Instruction[])operand) {
ByteCode next = instToByteCode[inst];
bool changed;
newStack.MergeInto(ref next.StackBefore, out changed);
if (changed) agenda.Enqueue(next);
}
}
}
}
}
List<ILExpression> ast = new List<ILExpression>();
Dictionary<ByteCode, ILExpression> byteCodeToExpr = new Dictionary<ByteCode, ILExpression>();
// Convert stack-based IL code to ILAst tree
foreach(ByteCode byteCode in body) {
ILExpression expr = new ILExpression(byteCode.Instruction.OpCode, byteCode.Instruction.Operand);
byteCodeToExpr[byteCode] = expr;
// Reference arguments using temporary variables
ILStack stack = byteCode.StackBefore;
for (int i = stack.Items.Count - byteCode.Instruction.GetPopCount(methodDef, byteCode.StackBefore.Items.Count); i < stack.Items.Count; i++) {
ILExpression ldExpr = new ILExpression(OpCodes.Ldloc, new VariableDefinition(stack.Items[i].PushedBy.TmpVarName, null));
ldExpr.IsTempLdloc = true;
expr.Arguments.Add(ldExpr);
}
// If the bytecode pushes anything store the result in temporary variable
int pushCount = byteCode.Instruction.GetPushCount();
if (pushCount > 0) {
ILExpression stExpr = new ILExpression(OpCodes.Stloc, new VariableDefinition(byteCode.TmpVarName, null));
stExpr.Arguments.Add(expr);
stExpr.IsTempStloc = true;
stExpr.RefCount = pushCount;
expr.Partent = stExpr;
expr = stExpr;
}
ast.Add(expr);
}
// Convert branch operands
foreach(ILExpression expr in ast) {
if (expr.Operand is Instruction) {
ILExpression brTarget = byteCodeToExpr[instToByteCode[(Instruction)expr.Operand]];
expr.Operand = brTarget;
brTarget.IsBranchTarget = true;
if (brTarget.Partent != null) {
brTarget.Partent.IsBranchTarget = true;
}
}
}
// Try to in-line stloc / ldloc pairs
for(int i = 0; i < ast.Count - 1; i++) {
ILExpression expr = ast[i];
ILExpression nextExpr = ast[i + 1];
if (expr.IsTempStloc && !nextExpr.IsBranchTarget) {
// If the next expression is stloc, look inside
if (nextExpr.IsTempStloc) {
nextExpr = nextExpr.Arguments[0];
}
// Find the use of the 'expr'
for(int j = 0; j < nextExpr.Arguments.Count; j++) {
ILExpression arg = nextExpr.Arguments[j];
if (!arg.IsTempLdloc) {
break; // This argument might have side effects so we can not move the 'expr' after it.
} else {
if (((VariableDefinition)arg.Operand).Name == ((VariableDefinition)expr.Operand).Name) {
expr.RefCount--;
if (expr.RefCount <= 0) {
ast.RemoveAt(i);
}
nextExpr.Arguments[j] = expr.Arguments[0]; // Inline the stloc body
if (expr.IsBranchTarget) {
nextExpr.IsBranchTarget = true;
if (nextExpr.Partent != null) {
nextExpr.Partent.IsBranchTarget = true;
}
}
i = Math.Max(0, i - 2); // Try the same index again
break; // Found
}
}
}
}
}
return ast;
}
}
}

60
src/ILAst/ILAstTypes.cs

@ -0,0 +1,60 @@ @@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Text;
using Decompiler.ControlFlow;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Cecil = Mono.Cecil;
namespace Decompiler
{
public class ILExpression
{
public OpCode OpCode { get; set; }
public object Operand { get; set; }
public List<ILExpression> Arguments { get; set; }
public bool IsTempStloc { get; set; }
public bool IsTempLdloc { get; set; }
public int RefCount { get; set; }
public bool IsBranchTarget { get; set; }
public BasicBlock BasicBlock { get; set; }
// HACK: Do preoperly
public ILExpression Partent { get; set; }
public ILExpression(OpCode opCode, object operand, params ILExpression[] args)
{
this.OpCode = opCode;
this.Operand = operand;
this.Arguments = new List<ILExpression>(args);
}
public void SetBasicBlock(BasicBlock bb)
{
this.BasicBlock = bb;
foreach(ILExpression arg in Arguments) {
arg.SetBasicBlock(bb);
}
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(OpCode.Name);
sb.Append('(');
bool first = true;
if (Operand != null) {
sb.Append(Operand.ToString());
first = false;
}
foreach (ILExpression arg in this.Arguments) {
if (!first) sb.Append(",");
sb.Append(arg.ToString());
first = false;
}
sb.Append(')');
return sb.ToString();
}
}
}

0
src/Constants.cs → src/Mono.Cecil.Rocks/Constants.cs

628
src/ByteCode.Type.cs → src/Mono.Cecil.Rocks/MyRocks.cs

@ -1,275 +1,353 @@ @@ -1,275 +1,353 @@
using System;
using System.Collections.Generic;
using Ast = ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Ast;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public partial class ByteCode
{
static public Cecil.TypeReference TypeVoid = GetCecilType(typeof(void));
static public Cecil.TypeReference TypeObject = GetCecilType(typeof(Object));
static public Cecil.TypeReference TypeException = GetCecilType(typeof(Exception));
static public Cecil.TypeReference TypeBool = GetCecilType(typeof(bool));
static public Cecil.TypeReference TypeInt32 = GetCecilType(typeof(Int32));
static public Cecil.TypeReference TypeString = GetCecilType(typeof(string));
static public Cecil.TypeReference TypeZero = GetCecilType(typeof(Int32));
static public Cecil.TypeReference TypeOne = GetCecilType(typeof(Int32));
static public Cecil.TypeReference GetCecilType(Type type)
{
return new Cecil.TypeReference(type.Name, type.Namespace, null, type.IsValueType);
}
public Cecil.TypeReference Type {
get {
if (this.PushCount == 0) {
return TypeVoid;
} else {
return this.StackAfter.Peek(1).Type;
}
}
}
public Cecil.TypeReference GetType(params Cecil.TypeReference[] args)
{
try {
return(GetTypeInternal(args));
} catch (NotImplementedException) {
return TypeObject;
}
}
public Cecil.TypeReference GetTypeInternal(params Cecil.TypeReference[] args)
{
OpCode opCode = this.OpCode;
object operand = this.Operand;
Cecil.TypeReference operandAsTypeRef = operand as Cecil.TypeReference;
ByteCode operandAsByteCode = operand as ByteCode;
string operandAsByteCodeLabel = operand is ByteCode ? String.Format("IL_{0:X2}", ((ByteCode)operand).Offset) : null;
Cecil.TypeReference arg1 = args.Length >= 1 ? args[0] : null;
Cecil.TypeReference arg2 = args.Length >= 2 ? args[1] : null;
Cecil.TypeReference arg3 = args.Length >= 3 ? args[2] : null;
switch(opCode.Code) {
#region Arithmetic
case Code.Add:
case Code.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.Div:
case Code.Div_Un:
case Code.Mul:
case Code.Mul_Ovf:
case Code.Mul_Ovf_Un:
case Code.Rem:
case Code.Rem_Un:
case Code.Sub:
case Code.Sub_Ovf:
case Code.Sub_Ovf_Un:
case Code.And:
case Code.Xor:
case Code.Shl:
case Code.Shr:
case Code.Shr_Un: return TypeInt32;
case Code.Neg: return TypeInt32;
case Code.Not: return TypeInt32;
#endregion
#region Arrays
case Code.Newarr:
return new Cecil.ArrayType(operandAsTypeRef);
case Code.Ldlen: return TypeInt32;
case Code.Ldelem_I:
case Code.Ldelem_I1:
case Code.Ldelem_I2:
case Code.Ldelem_I4:
case Code.Ldelem_I8: return TypeInt32;
case Code.Ldelem_U1:
case Code.Ldelem_U2:
case Code.Ldelem_U4:
case Code.Ldelem_R4:
case Code.Ldelem_R8: throw new NotImplementedException();
case Code.Ldelem_Ref:
if (arg1 is ArrayType) {
return ((ArrayType)arg1).ElementType;
} else {
throw new NotImplementedException();
}
case Code.Ldelem_Any:
case Code.Ldelema: throw new NotImplementedException();
case Code.Stelem_I:
case Code.Stelem_I1:
case Code.Stelem_I2:
case Code.Stelem_I4:
case Code.Stelem_I8:
case Code.Stelem_R4:
case Code.Stelem_R8:
case Code.Stelem_Ref:
case Code.Stelem_Any: return TypeVoid;
#endregion
#region Branching
case Code.Br:
case Code.Brfalse:
case Code.Brtrue:
case Code.Beq:
case Code.Bge:
case Code.Bge_Un:
case Code.Bgt:
case Code.Bgt_Un:
case Code.Ble:
case Code.Ble_Un:
case Code.Blt:
case Code.Blt_Un:
case Code.Bne_Un: return TypeVoid;
#endregion
#region Comparison
case Code.Ceq:
case Code.Cgt:
case Code.Cgt_Un:
case Code.Clt:
case Code.Clt_Un: return TypeBool;
#endregion
#region Conversions
case Code.Conv_I:
case Code.Conv_I1:
case Code.Conv_I2:
case Code.Conv_I4:
case Code.Conv_I8:
case Code.Conv_U:
case Code.Conv_U1:
case Code.Conv_U2:
case Code.Conv_U4:
case Code.Conv_U8:
case Code.Conv_R4:
case Code.Conv_R8:
case Code.Conv_R_Un:
case Code.Conv_Ovf_I:
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_U:
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_I_Un:
case Code.Conv_Ovf_I1_Un:
case Code.Conv_Ovf_I2_Un:
case Code.Conv_Ovf_I4_Un:
case Code.Conv_Ovf_I8_Un:
case Code.Conv_Ovf_U_Un:
case Code.Conv_Ovf_U1_Un:
case Code.Conv_Ovf_U2_Un:
case Code.Conv_Ovf_U4_Un:
case Code.Conv_Ovf_U8_Un: return TypeInt32;
#endregion
#region Indirect
case Code.Ldind_I: throw new NotImplementedException();
case Code.Ldind_I1: throw new NotImplementedException();
case Code.Ldind_I2: throw new NotImplementedException();
case Code.Ldind_I4: throw new NotImplementedException();
case Code.Ldind_I8: throw new NotImplementedException();
case Code.Ldind_U1: throw new NotImplementedException();
case Code.Ldind_U2: throw new NotImplementedException();
case Code.Ldind_U4: throw new NotImplementedException();
case Code.Ldind_R4: throw new NotImplementedException();
case Code.Ldind_R8: throw new NotImplementedException();
case Code.Ldind_Ref: throw new NotImplementedException();
case Code.Stind_I: throw new NotImplementedException();
case Code.Stind_I1: throw new NotImplementedException();
case Code.Stind_I2: throw new NotImplementedException();
case Code.Stind_I4: throw new NotImplementedException();
case Code.Stind_I8: throw new NotImplementedException();
case Code.Stind_R4: throw new NotImplementedException();
case Code.Stind_R8: throw new NotImplementedException();
case Code.Stind_Ref: throw new NotImplementedException();
#endregion
case Code.Arglist: throw new NotImplementedException();
case Code.Box: throw new NotImplementedException();
case Code.Break: throw new NotImplementedException();
case Code.Call: return ((MethodReference)operand).ReturnType;
case Code.Calli: throw new NotImplementedException();
case Code.Callvirt: return ((MethodReference)operand).ReturnType;
case Code.Castclass: throw new NotImplementedException();
case Code.Ckfinite: throw new NotImplementedException();
case Code.Constrained: throw new NotImplementedException();
case Code.Cpblk: throw new NotImplementedException();
case Code.Cpobj: throw new NotImplementedException();
case Code.Dup: throw new NotImplementedException();
case Code.Endfilter: throw new NotImplementedException();
case Code.Endfinally: throw new NotImplementedException();
case Code.Initblk: throw new NotImplementedException();
case Code.Initobj: throw new NotImplementedException();
case Code.Isinst: throw new NotImplementedException();
case Code.Jmp: throw new NotImplementedException();
case Code.Ldarg:
Cecil.TypeReference typeRef = ((ParameterDefinition)operand).ParameterType;
// 'this' returns null; TODO: Return proper type of this
return typeRef ?? TypeObject;
case Code.Ldarga: throw new NotImplementedException();
case Code.Ldc_I4:
if ((int)operand == 0) {
return TypeZero;
} else if ((int)operand == 1) {
return TypeOne;
} else {
return TypeInt32;
}
case Code.Ldc_I8: throw new NotImplementedException();
case Code.Ldc_R4: throw new NotImplementedException();
case Code.Ldc_R8: throw new NotImplementedException();
case Code.Ldfld: return ((FieldDefinition)operand).FieldType;
case Code.Ldflda: throw new NotImplementedException();
case Code.Ldftn: throw new NotImplementedException();
case Code.Ldloc: return ((VariableDefinition)operand).VariableType;
case Code.Ldloca: throw new NotImplementedException();
case Code.Ldnull: throw new NotImplementedException();
case Code.Ldobj: throw new NotImplementedException();
case Code.Ldsfld: throw new NotImplementedException();
case Code.Ldsflda: throw new NotImplementedException();
case Code.Ldstr: return TypeString;
case Code.Ldtoken: throw new NotImplementedException();
case Code.Ldvirtftn: throw new NotImplementedException();
case Code.Leave: throw new NotImplementedException();
case Code.Localloc: throw new NotImplementedException();
case Code.Mkrefany: throw new NotImplementedException();
case Code.Newobj: throw new NotImplementedException();
case Code.No: throw new NotImplementedException();
case Code.Nop: return TypeVoid;
case Code.Or: throw new NotImplementedException();
case Code.Pop: throw new NotImplementedException();
case Code.Readonly: throw new NotImplementedException();
case Code.Refanytype: throw new NotImplementedException();
case Code.Refanyval: throw new NotImplementedException();
case Code.Ret: return TypeVoid;
case Code.Rethrow: throw new NotImplementedException();
case Code.Sizeof: throw new NotImplementedException();
case Code.Starg: throw new NotImplementedException();
case Code.Stfld: throw new NotImplementedException();
case Code.Stloc: return TypeVoid;
case Code.Stobj: throw new NotImplementedException();
case Code.Stsfld: throw new NotImplementedException();
case Code.Switch: throw new NotImplementedException();
case Code.Tail: throw new NotImplementedException();
case Code.Throw: throw new NotImplementedException();
case Code.Unaligned: throw new NotImplementedException();
case Code.Unbox: throw new NotImplementedException();
case Code.Unbox_Any: throw new NotImplementedException();
case Code.Volatile: throw new NotImplementedException();
default: throw new Exception("Unknown OpCode: " + opCode);
}
}
}
}
/*
* Created by SharpDevelop.
* User: User
* Date: 05/02/2011
* Time: 10:10
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Collections.Generic;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler.Mono.Cecil.Rocks
{
static class MyRocks
{
static public TypeReference TypeVoid = GetCecilType(typeof(void));
static public TypeReference TypeObject = GetCecilType(typeof(Object));
static public TypeReference TypeException = GetCecilType(typeof(Exception));
static public TypeReference TypeBool = GetCecilType(typeof(bool));
static public TypeReference TypeInt32 = GetCecilType(typeof(Int32));
static public TypeReference TypeString = GetCecilType(typeof(string));
static public TypeReference TypeZero = GetCecilType(typeof(Int32));
static public TypeReference TypeOne = GetCecilType(typeof(Int32));
public static bool CanFallThough(this OpCode opCode)
{
switch(opCode.FlowControl) {
case FlowControl.Branch: return false;
case FlowControl.Cond_Branch: return true;
case FlowControl.Next: return true;
case FlowControl.Call: return true;
case FlowControl.Return: return false;
case FlowControl.Throw: return false;
default: throw new NotImplementedException();
}
}
public static bool IsBranch(this OpCode opCode)
{
return opCode.FlowControl == FlowControl.Branch || opCode.FlowControl == FlowControl.Cond_Branch;
}
public static int GetPopCount(this Instruction inst, MethodDefinition methodDef, int stackLength)
{
switch(inst.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1;
case StackBehaviour.Popref: return 1;
case StackBehaviour.Pop1_pop1: return 2;
case StackBehaviour.Popi_pop1: return 2;
case StackBehaviour.Popi_popi: return 2;
case StackBehaviour.Popi_popi8: return 2;
case StackBehaviour.Popi_popr4: return 2;
case StackBehaviour.Popi_popr8: return 2;
case StackBehaviour.Popref_pop1: return 2;
case StackBehaviour.Popref_popi: return 2;
case StackBehaviour.Popi_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi: return 3;
case StackBehaviour.Popref_popi_popi8: return 3;
case StackBehaviour.Popref_popi_popr4: return 3;
case StackBehaviour.Popref_popi_popr8: return 3;
case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: return stackLength;
case StackBehaviour.Varpop:
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */;
} else {
return cecilMethod.Parameters.Count;
}
case Code.Calli: throw new NotImplementedException();
case Code.Ret:
if (methodDef.ReturnType.FullName == Constants.Void) {
return 0;
} else {
return 1;
}
case Code.Newobj:
MethodReference ctorMethod = ((MethodReference)inst.Operand);
return ctorMethod.Parameters.Count;
default: throw new Exception("Unknown Varpop opcode");
}
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop);
}
}
public static int GetPushCount(this Instruction inst)
{
switch(inst.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2;
case StackBehaviour.Pushi: return 1;
case StackBehaviour.Pushi8: return 1;
case StackBehaviour.Pushr4: return 1;
case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls
switch(inst.OpCode.Code) {
case Code.Call:
case Code.Callvirt:
MethodReference cecilMethod = ((MethodReference)inst.Operand);
if (cecilMethod.ReturnType.FullName == Constants.Void) {
return 0;
} else {
return 1;
}
case Code.Calli: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode");
}
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush);
}
}
static public TypeReference GetCecilType(Type type)
{
return new TypeReference(type.Name, type.Namespace, null, type.IsValueType);
}
static public TypeReference GetTypeInternal(this Instruction inst, MethodDefinition methodDef, List<TypeReference> args)
{
OpCode opCode = inst.OpCode;
object operand = inst.Operand;
TypeReference operandAsTypeRef = operand as TypeReference;
//ByteCode operandAsByteCode = operand as ByteCode;
//string operandAsByteCodeLabel = operand is ByteCode ? String.Format("IL_{0:X2}", ((ByteCode)operand).Offset) : null;
TypeReference arg1 = args.Count >= 1 ? args[0] : null;
TypeReference arg2 = args.Count >= 2 ? args[1] : null;
TypeReference arg3 = args.Count >= 3 ? args[2] : null;
switch(opCode.Code) {
#region Arithmetic
case Code.Add:
case Code.Add_Ovf:
case Code.Add_Ovf_Un:
case Code.Div:
case Code.Div_Un:
case Code.Mul:
case Code.Mul_Ovf:
case Code.Mul_Ovf_Un:
case Code.Rem:
case Code.Rem_Un:
case Code.Sub:
case Code.Sub_Ovf:
case Code.Sub_Ovf_Un:
case Code.And:
case Code.Xor:
case Code.Shl:
case Code.Shr:
case Code.Shr_Un: return TypeInt32;
case Code.Neg: return TypeInt32;
case Code.Not: return TypeInt32;
#endregion
#region Arrays
case Code.Newarr:
return new ArrayType(operandAsTypeRef);
case Code.Ldlen: return TypeInt32;
case Code.Ldelem_I:
case Code.Ldelem_I1:
case Code.Ldelem_I2:
case Code.Ldelem_I4:
case Code.Ldelem_I8: return TypeInt32;
case Code.Ldelem_U1:
case Code.Ldelem_U2:
case Code.Ldelem_U4:
case Code.Ldelem_R4:
case Code.Ldelem_R8: throw new NotImplementedException();
case Code.Ldelem_Ref:
if (arg1 is ArrayType) {
return ((ArrayType)arg1).ElementType;
} else {
throw new NotImplementedException();
}
case Code.Ldelem_Any:
case Code.Ldelema: throw new NotImplementedException();
case Code.Stelem_I:
case Code.Stelem_I1:
case Code.Stelem_I2:
case Code.Stelem_I4:
case Code.Stelem_I8:
case Code.Stelem_R4:
case Code.Stelem_R8:
case Code.Stelem_Ref:
case Code.Stelem_Any: return TypeVoid;
#endregion
#region Branching
case Code.Br:
case Code.Brfalse:
case Code.Brtrue:
case Code.Beq:
case Code.Bge:
case Code.Bge_Un:
case Code.Bgt:
case Code.Bgt_Un:
case Code.Ble:
case Code.Ble_Un:
case Code.Blt:
case Code.Blt_Un:
case Code.Bne_Un: return TypeVoid;
#endregion
#region Comparison
case Code.Ceq:
case Code.Cgt:
case Code.Cgt_Un:
case Code.Clt:
case Code.Clt_Un: return TypeBool;
#endregion
#region Conversions
case Code.Conv_I:
case Code.Conv_I1:
case Code.Conv_I2:
case Code.Conv_I4:
case Code.Conv_I8:
case Code.Conv_U:
case Code.Conv_U1:
case Code.Conv_U2:
case Code.Conv_U4:
case Code.Conv_U8:
case Code.Conv_R4:
case Code.Conv_R8:
case Code.Conv_R_Un:
case Code.Conv_Ovf_I:
case Code.Conv_Ovf_I1:
case Code.Conv_Ovf_I2:
case Code.Conv_Ovf_I4:
case Code.Conv_Ovf_I8:
case Code.Conv_Ovf_U:
case Code.Conv_Ovf_U1:
case Code.Conv_Ovf_U2:
case Code.Conv_Ovf_U4:
case Code.Conv_Ovf_U8:
case Code.Conv_Ovf_I_Un:
case Code.Conv_Ovf_I1_Un:
case Code.Conv_Ovf_I2_Un:
case Code.Conv_Ovf_I4_Un:
case Code.Conv_Ovf_I8_Un:
case Code.Conv_Ovf_U_Un:
case Code.Conv_Ovf_U1_Un:
case Code.Conv_Ovf_U2_Un:
case Code.Conv_Ovf_U4_Un:
case Code.Conv_Ovf_U8_Un: return TypeInt32;
#endregion
#region Indirect
case Code.Ldind_I: throw new NotImplementedException();
case Code.Ldind_I1: throw new NotImplementedException();
case Code.Ldind_I2: throw new NotImplementedException();
case Code.Ldind_I4: throw new NotImplementedException();
case Code.Ldind_I8: throw new NotImplementedException();
case Code.Ldind_U1: throw new NotImplementedException();
case Code.Ldind_U2: throw new NotImplementedException();
case Code.Ldind_U4: throw new NotImplementedException();
case Code.Ldind_R4: throw new NotImplementedException();
case Code.Ldind_R8: throw new NotImplementedException();
case Code.Ldind_Ref: throw new NotImplementedException();
case Code.Stind_I: throw new NotImplementedException();
case Code.Stind_I1: throw new NotImplementedException();
case Code.Stind_I2: throw new NotImplementedException();
case Code.Stind_I4: throw new NotImplementedException();
case Code.Stind_I8: throw new NotImplementedException();
case Code.Stind_R4: throw new NotImplementedException();
case Code.Stind_R8: throw new NotImplementedException();
case Code.Stind_Ref: throw new NotImplementedException();
#endregion
case Code.Arglist: throw new NotImplementedException();
case Code.Box: throw new NotImplementedException();
case Code.Break: throw new NotImplementedException();
case Code.Call: return ((MethodReference)operand).ReturnType;
case Code.Calli: throw new NotImplementedException();
case Code.Callvirt: return ((MethodReference)operand).ReturnType;
case Code.Castclass: throw new NotImplementedException();
case Code.Ckfinite: throw new NotImplementedException();
case Code.Constrained: throw new NotImplementedException();
case Code.Cpblk: throw new NotImplementedException();
case Code.Cpobj: throw new NotImplementedException();
case Code.Dup: throw new NotImplementedException();
case Code.Endfilter: throw new NotImplementedException();
case Code.Endfinally: throw new NotImplementedException();
case Code.Initblk: throw new NotImplementedException();
case Code.Initobj: throw new NotImplementedException();
case Code.Isinst: throw new NotImplementedException();
case Code.Jmp: throw new NotImplementedException();
case Code.Ldarg:
TypeReference typeRef = ((ParameterDefinition)operand).ParameterType;
// 'this' returns null; TODO: Return proper type of this
return typeRef ?? TypeObject;
case Code.Ldarga: throw new NotImplementedException();
case Code.Ldc_I4:
if ((int)operand == 0) {
return TypeZero;
} else if ((int)operand == 1) {
return TypeOne;
} else {
return TypeInt32;
}
case Code.Ldc_I8: throw new NotImplementedException();
case Code.Ldc_R4: throw new NotImplementedException();
case Code.Ldc_R8: throw new NotImplementedException();
case Code.Ldfld: return ((FieldDefinition)operand).FieldType;
case Code.Ldflda: throw new NotImplementedException();
case Code.Ldftn: throw new NotImplementedException();
case Code.Ldloc: return ((VariableDefinition)operand).VariableType;
case Code.Ldloca: throw new NotImplementedException();
case Code.Ldnull: throw new NotImplementedException();
case Code.Ldobj: throw new NotImplementedException();
case Code.Ldsfld: throw new NotImplementedException();
case Code.Ldsflda: throw new NotImplementedException();
case Code.Ldstr: return TypeString;
case Code.Ldtoken: throw new NotImplementedException();
case Code.Ldvirtftn: throw new NotImplementedException();
case Code.Leave: throw new NotImplementedException();
case Code.Localloc: throw new NotImplementedException();
case Code.Mkrefany: throw new NotImplementedException();
case Code.Newobj: throw new NotImplementedException();
case Code.No: throw new NotImplementedException();
case Code.Nop: return TypeVoid;
case Code.Or: throw new NotImplementedException();
case Code.Pop: throw new NotImplementedException();
case Code.Readonly: throw new NotImplementedException();
case Code.Refanytype: throw new NotImplementedException();
case Code.Refanyval: throw new NotImplementedException();
case Code.Ret: return TypeVoid;
case Code.Rethrow: throw new NotImplementedException();
case Code.Sizeof: throw new NotImplementedException();
case Code.Starg: throw new NotImplementedException();
case Code.Stfld: throw new NotImplementedException();
case Code.Stloc: return TypeVoid;
case Code.Stobj: throw new NotImplementedException();
case Code.Stsfld: throw new NotImplementedException();
case Code.Switch: throw new NotImplementedException();
case Code.Tail: throw new NotImplementedException();
case Code.Throw: throw new NotImplementedException();
case Code.Unaligned: throw new NotImplementedException();
case Code.Unbox: throw new NotImplementedException();
case Code.Unbox_Any: throw new NotImplementedException();
case Code.Volatile: throw new NotImplementedException();
default: throw new Exception("Unknown OpCode: " + opCode);
}
}
}
}

14
src/Options.cs

@ -13,20 +13,6 @@ namespace Decompiler @@ -13,20 +13,6 @@ namespace Decompiler
public static bool ReduceAstJumps = true;
public static bool ReduceAstLoops = true;
public static bool ReduceAstOther = true;
public static void NotifyCollapsingExpression()
{
if (CollapseExpression-- <= 0) {
throw new StopOptimizations();
}
}
public static void NotifyReducingGraph()
{
if (ReduceGraph-- <= 0) {
throw new StopOptimizations();
}
}
}
class StopOptimizations: Exception

16
src/Util.cs

@ -1,16 +0,0 @@ @@ -1,16 +0,0 @@
using System;
using Ast = ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Ast;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public static class Util
{
}
}

BIN
tests/QuickSort/bin/Release/QuickSort.exe

Binary file not shown.
Loading…
Cancel
Save