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

82
src/AstMetodBodyBuilder.cs

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

10
src/ByteCode.cs

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

187
src/ControlFlow.cs

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

2
src/StackExpressionCollection.cs

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

Loading…
Cancel
Save