Browse Source

Split method body to basic blocks

pull/1/head^2
David Srbecký 18 years ago
parent
commit
aba6b0950c
  1. 1
      Decompiler.csproj
  2. 82
      src/AstMetodBodyBuilder.cs
  3. 10
      src/ByteCode.cs
  4. 187
      src/ControlFlow.cs
  5. 47
      src/StackExpression.cs
  6. 2
      src/StackExpressionCollection.cs

1
Decompiler.csproj

@ -50,6 +50,7 @@
<Compile Include="src\ByteCode.StackAnalysis.cs" /> <Compile Include="src\ByteCode.StackAnalysis.cs" />
<Compile Include="src\StackExpression.cs" /> <Compile Include="src\StackExpression.cs" />
<Compile Include="src\StackExpressionCollection.cs" /> <Compile Include="src\StackExpressionCollection.cs" />
<Compile Include="src\ControlFlow.cs" />
<Compile Include="src\Util.cs" /> <Compile Include="src\Util.cs" />
<EmbeddedResource Include="src\MainForm.resx"> <EmbeddedResource Include="src\MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon> <DependentUpon>MainForm.cs</DependentUpon>

82
src/AstMetodBodyBuilder.cs

@ -22,8 +22,10 @@ namespace Decompiler
methodDef.Body.Simplify(); methodDef.Body.Simplify();
ByteCodeCollection body = new ByteCodeCollection(methodDef); ByteCodeCollection body = new ByteCodeCollection(methodDef);
StackExpressionCollection exprCol = new StackExpressionCollection(body); StackExpressionCollection exprCollection = new StackExpressionCollection(body);
exprCol.Optimize(); exprCollection.Optimize();
BasicBlockSet basicBlockSet = new BasicBlockSet(exprCollection);
foreach(VariableDefinition varDef in methodDef.Body.Variables) { foreach(VariableDefinition varDef in methodDef.Body.Variables) {
localVarTypes[varDef.Name] = varDef.VariableType; localVarTypes[varDef.Name] = varDef.VariableType;
@ -35,43 +37,47 @@ namespace Decompiler
// astBlock.Children.Add(astLocalVar); // astBlock.Children.Add(astLocalVar);
} }
for(int i = 0; i < exprCol.Count; i++) { for(int b = 0; b < basicBlockSet.Elements.Count; b++) {
StackExpression expr = exprCol[i]; BasicBlock basicBlock = (BasicBlock)basicBlockSet.Elements[b];
Ast.Statement astStatement = null; astBlock.Children.Add(MakeComment(basicBlock.ToString()));
try { for(int i = 0; i < basicBlock.Body.Count; i++) {
List<Ast.Expression> args = new List<Ast.Expression>(); StackExpression expr = basicBlock.Body[i];
foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) { Ast.Statement astStatement = null;
string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset); try {
args.Add(new Ast.IdentifierExpression(name)); List<Ast.Expression> args = new List<Ast.Expression>();
} foreach(CilStackSlot stackSlot in expr.StackBefore.PeekCount(expr.PopCount)) {
object codeExpr = MakeCodeDomExpression(methodDef, expr, args.ToArray()); string name = string.Format("expr{0:X2}", stackSlot.AllocadedBy.Offset);
if (codeExpr is Ast.Expression) { args.Add(new Ast.IdentifierExpression(name));
if (expr.PushCount == 1) { }
string type = expr.ExpressionByteCode.Type.FullName; object codeExpr = MakeCodeDomExpression(methodDef, expr, args.ToArray());
string name = string.Format("expr{0:X2}", expr.ExpressionByteCode.Offset); if (codeExpr is Ast.Expression) {
Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString())); if (expr.PushCount == 1) {
astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr)); string type = expr.LastByteCode.Type.FullName;
astStatement = astLocal; string name = string.Format("expr{0:X2}", expr.LastByteCode.Offset);
} else { Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString()));
astStatement = new ExpressionStatement((Ast.Expression)codeExpr); astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr));
astStatement = astLocal;
} else {
astStatement = new ExpressionStatement((Ast.Expression)codeExpr);
}
} else if (codeExpr is Ast.Statement) {
astStatement = (Ast.Statement)codeExpr;
} }
} else if (codeExpr is Ast.Statement) { } catch (NotImplementedException) {
astStatement = (Ast.Statement)codeExpr; astStatement = MakeComment(expr.LastByteCode.Description);
} }
} catch (NotImplementedException) { if (expr.IsBranchTarget) {
astStatement = MakeComment(expr.ExpressionByteCode.Description); astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", expr.FirstByteCode.Offset)));
} }
if (expr.IsBranchTarget) { // Skip last return statement
astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", expr.FirstByteCode.Offset))); // if (i == exprCol.Count - 1 &&
} // expr.LastByteCode.OpCode.Code == Code.Ret &&
// Skip last return statement // expr.LastByteCode.PopCount == 0 &&
if (i == exprCol.Count - 1 && // !expr.IsBranchTarget) {
expr.ExpressionByteCode.OpCode.Code == Code.Ret && // continue;
expr.ExpressionByteCode.PopCount == 0 && // }
!expr.IsBranchTarget) { astBlock.Children.Add(astStatement);
continue;
} }
astBlock.Children.Add(astStatement);
} }
return astBlock; return astBlock;
@ -79,7 +85,7 @@ namespace Decompiler
static Ast.ExpressionStatement MakeComment(string text) static Ast.ExpressionStatement MakeComment(string text)
{ {
text = "/*" + text + "*/"; text = "/* " + text + "*/";
return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); return new Ast.ExpressionStatement(new PrimitiveExpression(text, text));
} }
@ -97,7 +103,7 @@ namespace Decompiler
allArgs.Add(astExpr); allArgs.Add(astExpr);
} }
} }
return MakeCodeDomExpression(methodDef, expr.ExpressionByteCode, allArgs.ToArray()); return MakeCodeDomExpression(methodDef, expr.LastByteCode, allArgs.ToArray());
} }
static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args) static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args)

10
src/ByteCode.cs

@ -9,6 +9,7 @@ namespace Decompiler
{ {
public partial class ByteCode public partial class ByteCode
{ {
StackExpression owner;
ByteCode previous; ByteCode previous;
ByteCode next; ByteCode next;
@ -17,6 +18,11 @@ namespace Decompiler
OpCode opCode; OpCode opCode;
object operand; object operand;
public StackExpression Owner {
get { return owner; }
set { owner = value; }
}
public ByteCode Previous { public ByteCode Previous {
get { return previous; } get { return previous; }
set { previous = value; } set { previous = value; }
@ -44,7 +50,7 @@ namespace Decompiler
public ByteCode BranchTarget { public ByteCode BranchTarget {
get { get {
return (ByteCode)operand; return operand as ByteCode;
} }
} }
@ -66,7 +72,7 @@ namespace Decompiler
public string Description { public string Description {
get { get {
return string.Format( return string.Format(
" {1, -22} # {2}->{3} {4} {5}", "{1, -22} # {2}->{3} {4} {5}",
this.Offset, this.Offset,
this.OpCode + " " + FormatByteCodeOperand(this.Operand), this.OpCode + " " + FormatByteCodeOperand(this.Operand),
this.OpCode.StackBehaviourPop, this.OpCode.StackBehaviourPop,

187
src/ControlFlow.cs

@ -0,0 +1,187 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace Decompiler
{
public class Set<T>: List<T>
{
}
public class BasicBlock
{
int id;
BasicBlockSet owner;
Set<BasicBlock> predecessors;
public Set<BasicBlock> successors;
BasicBlock fallThroughSuccessor;
BasicBlock branchSuccessor;
List<StackExpression> body = new List<StackExpression>();
#region Peoperties
public int Id {
get { return id; }
set { id = value; }
}
public BasicBlockSet Owner {
get { return owner; }
set { owner = value; }
}
public Set<BasicBlock> Predecessors {
get { return predecessors; }
set { predecessors = value; }
}
public Set<BasicBlock> Successors {
get { return successors; }
set { successors = value; }
}
public BasicBlock FallThroughSuccessor {
get { return fallThroughSuccessor; }
set { fallThroughSuccessor = value; }
}
public BasicBlock BranchSuccessor {
get { return branchSuccessor; }
set { branchSuccessor = value; }
}
public List<StackExpression> Body {
get { return body; }
set { body = value; }
}
#endregion
public override string ToString()
{
//return string.Format("BackBlock {0} ({1} expressions)", id, body.Count);
return string.Format("BackBlock {0}", id, body.Count);
}
}
public enum BasicBlockSetType {
MethodBody,
Acyclic,
Loop,
}
public class BasicBlockSet
{
BasicBlockSet owner;
BasicBlockSetType type;
object head;
Set<object> elements = new Set<object>();
Set<BasicBlock> BasicBlockSuccessors;
BasicBlock headBasicBlock {
get {
return null;
}
}
public BasicBlockSet Owner {
get { return owner; }
}
public BasicBlockSetType Type {
get { return type; }
}
public object Head {
get { return head; }
}
public Set<object> Elements {
get { return elements; }
}
BasicBlockSet()
{
}
public BasicBlockSet(object head, object tail)
{
if (head == null) throw new ArgumentNullException("head");
if (tail == null) throw new ArgumentNullException("tail");
BasicBlockSet headAsSet = head as BasicBlockSet;
BasicBlockSet tailAsSet = tail as BasicBlockSet;
// Add head
if (head is BasicBlock) {
this.head = head;
this.elements.Add(head);
} else if (headAsSet != null && headAsSet.type == BasicBlockSetType.Acyclic) {
this.head = headAsSet.head;
this.elements.AddRange(headAsSet.elements);
} else if (headAsSet != null && headAsSet.type == BasicBlockSetType.Loop) {
this.head = headAsSet;
this.elements.Add(headAsSet);
} else {
throw new Exception("Invalid head");
}
// Add tail
if (tail is BasicBlock) {
this.elements.Add(tail);
} else if (tailAsSet != null && tailAsSet.type == BasicBlockSetType.Acyclic) {
this.elements.AddRange(tailAsSet.elements);
} else if (tailAsSet != null && tailAsSet.type == BasicBlockSetType.Loop) {
this.elements.Add(tailAsSet);
} else {
throw new Exception("Invalid tail");
}
// Get type
if (tail is BasicBlock) {
if (((BasicBlock)tail).successors.Contains(this.headBasicBlock)) {
this.type = BasicBlockSetType.Loop;
} else {
this.type = BasicBlockSetType.Acyclic;
}
} else if (tailAsSet != null) {
if (tailAsSet.BasicBlockSuccessors.Contains(this.headBasicBlock)) {
}
} else {
throw new Exception("Invalid tail");
}
}
public BasicBlockSet(StackExpressionCollection exprs)
{
if (exprs.Count == 0) throw new ArgumentException("Count == 0", "exprs");
this.owner = null;
this.type = BasicBlockSetType.MethodBody;
BasicBlock basicBlock = null;
int basicBlockId = 1;
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
if (i == 0 || exprs[i - 1].BranchTarget != null || exprs[i].BranchesHere.Count > 0){
basicBlock = new BasicBlock();
this.elements.Add(basicBlock);
basicBlock.Id = basicBlockId++;
}
basicBlock.Body.Add(exprs[i]);
}
this.head = this.elements[0];
}
}
}

47
src/StackExpression.cs

@ -9,11 +9,16 @@ namespace Decompiler
{ {
public class StackExpression public class StackExpression
{ {
ByteCode expressionByteCode; StackExpressionCollection owner;
ByteCode lastByteCode;
List<StackExpression> lastArguments = new List<StackExpression>(); List<StackExpression> lastArguments = new List<StackExpression>();
public ByteCode ExpressionByteCode { public StackExpressionCollection Owner {
get { return expressionByteCode; } get { return owner; }
}
public ByteCode LastByteCode {
get { return lastByteCode; }
} }
// A list of closed expression for last arguments // A list of closed expression for last arguments
@ -29,7 +34,7 @@ namespace Decompiler
public CilStack StackAfter { public CilStack StackAfter {
get { get {
return this.ExpressionByteCode.StackAfter; return this.LastByteCode.StackAfter;
} }
} }
@ -43,6 +48,26 @@ namespace Decompiler
} }
} }
public List<StackExpression> BranchesHere {
get {
List<StackExpression> branchesHere = new List<StackExpression>();
foreach(ByteCode byteCode in this.FirstByteCode.BranchesHere) {
branchesHere.Add(byteCode.Owner);
}
return branchesHere;
}
}
public StackExpression BranchTarget {
get {
if (this.lastByteCode.BranchTarget == null) {
return null;
} else {
return this.lastByteCode.BranchTarget.Owner;
}
}
}
public bool IsBranchTarget { public bool IsBranchTarget {
get { get {
return this.FirstByteCode.BranchesHere.Count > 0; return this.FirstByteCode.BranchesHere.Count > 0;
@ -77,9 +102,9 @@ namespace Decompiler
stackSize += expr.PushCount; stackSize += expr.PushCount;
} }
{ {
stackSize -= expressionByteCode.PopCount; stackSize -= lastByteCode.PopCount;
minStackSize = Math.Min(minStackSize, stackSize); minStackSize = Math.Min(minStackSize, stackSize);
stackSize += expressionByteCode.PushCount; stackSize += lastByteCode.PushCount;
} }
popCount = -minStackSize; popCount = -minStackSize;
pushCount = stackSize - minStackSize; pushCount = stackSize - minStackSize;
@ -90,19 +115,21 @@ namespace Decompiler
if (lastArguments.Count > 0) { if (lastArguments.Count > 0) {
return lastArguments[0].FirstByteCode; return lastArguments[0].FirstByteCode;
} else { } else {
return this.ExpressionByteCode; return this.LastByteCode;
} }
} }
} }
public StackExpression(ByteCode expressionByteCode) public StackExpression(StackExpressionCollection owner, ByteCode lastByteCode)
{ {
this.expressionByteCode = expressionByteCode; this.owner = owner;
this.lastByteCode = lastByteCode;
this.lastByteCode.Owner = this;
} }
public bool MustBeParenthesized { public bool MustBeParenthesized {
get { get {
switch(this.ExpressionByteCode.OpCode.Code) { switch(this.LastByteCode.OpCode.Code) {
#region Arithmetic #region Arithmetic
case Code.Neg: case Code.Neg:
case Code.Not: case Code.Not:

2
src/StackExpressionCollection.cs

@ -12,7 +12,7 @@ namespace Decompiler
public StackExpressionCollection(ByteCodeCollection byteCodeCol) public StackExpressionCollection(ByteCodeCollection byteCodeCol)
{ {
foreach(ByteCode bc in byteCodeCol) { foreach(ByteCode bc in byteCodeCol) {
this.Add(new StackExpression(bc)); this.Add(new StackExpression(this, bc));
} }
} }

Loading…
Cancel
Save