Permalink
Browse files

Completely rewritten ByteCodeExpressions.

It is now new representation of the code - that is, an extra stage in the decompilation process.
It is independent of the previous representation and thus it can be much more easily transformed.
  • Loading branch information...
1 parent 9f4dc86 commit 4beea5c6a1c5a7d817d9a25bb3dfe85e6e06b5f9 @dsrbecky dsrbecky committed Mar 28, 2008
Showing with 153 additions and 168 deletions.
  1. +7 −28 bin/Debug/output.cs
  2. +22 −28 src/AstMetodBodyBuilder.cs
  3. +1 −7 src/ByteCode.cs
  4. +57 −91 src/ByteCodeExpression.cs
  5. +65 −13 src/ByteCodeExpressionCollection.cs
  6. +1 −1 src/ControlFlow/Nodes.cs
View
35 bin/Debug/output.cs
@@ -162,48 +162,27 @@ private void UpdateCounts()
}
}
if (squares[i, j] == Black) {
- object expr122 = this;
- int expr123 = expr122.blackCount;
- int expr129 = expr123 + 1;
- expr122.blackCount = expr129;
+ expr122.blackCount = blackCount + 1;
if (flag2) {
- object expr134 = this;
- int expr135 = expr134.blackFrontierCount;
- int expr13B = expr135 + 1;
- expr134.blackFrontierCount = expr13B;
+ expr134.blackFrontierCount = blackFrontierCount + 1;
}
if (safeDiscs[i, j]) {
- object expr151 = this;
- int expr152 = expr151.blackSafeCount;
- int expr158 = expr152 + 1;
- expr151.blackSafeCount = expr158;
+ expr151.blackSafeCount = blackSafeCount + 1;
}
} else {
if (squares[i, j] == White) {
- object expr175 = this;
- int expr176 = expr175.whiteCount;
- int expr17C = expr176 + 1;
- expr175.whiteCount = expr17C;
+ expr175.whiteCount = whiteCount + 1;
if (flag2) {
- object expr187 = this;
- int expr188 = expr187.whiteFrontierCount;
- int expr18E = expr188 + 1;
- expr187.whiteFrontierCount = expr18E;
+ expr187.whiteFrontierCount = whiteFrontierCount + 1;
}
if (safeDiscs[i, j]) {
- object expr1A4 = this;
- int expr1A5 = expr1A4.whiteSafeCount;
- int expr1AB = expr1A5 + 1;
- expr1A4.whiteSafeCount = expr1AB;
+ expr1A4.whiteSafeCount = whiteSafeCount + 1;
goto BasicBlock_327;
} else {
goto BasicBlock_327;
}
}
- object expr1B4 = this;
- int expr1B5 = expr1B4.emptyCount;
- int expr1BB = expr1B5 + 1;
- expr1B4.emptyCount = expr1BB;
+ expr1B4.emptyCount = emptyCount + 1;
}
BasicBlock_327:
}
View
50 src/AstMetodBodyBuilder.cs
@@ -180,36 +180,24 @@ IEnumerable<Ast.INode> TransformNode(Node node)
List<Ast.Expression> TransformExpressionArguments(ByteCodeExpression expr)
{
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));
- }
// Args generated by nested expressions (which must be closed)
- foreach(ByteCodeExpression nestedExpr in expr.LastArguments) {
- args.Add((Ast.Expression)TransformExpression(nestedExpr));
+ foreach(ByteCodeExpression arg in expr.Arguments) {
+ args.Add((Ast.Expression)TransformExpression(arg));
}
return args;
}
object TransformExpression(ByteCodeExpression expr)
{
List<Ast.Expression> args = TransformExpressionArguments(expr);
- return TransformByteCode(methodDef, expr.LastByteCode, args);
+ return TransformByteCode(methodDef, expr, args);
}
Ast.Statement TransformExpressionToStatement(ByteCodeExpression expr)
{
object codeExpr = TransformExpression(expr);
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));
- return astLocal;
- } else {
- return new Ast.ExpressionStatement((Ast.Expression)codeExpr);
- }
+ return new Ast.ExpressionStatement((Ast.Expression)codeExpr);
} else if (codeExpr is Ast.Statement) {
return (Ast.Statement)codeExpr;
} else {
@@ -234,7 +222,7 @@ Ast.Expression MakeBranchCondition_Internal(Branch branch)
List<Ast.Expression> args = TransformExpressionArguments(((SimpleBranch)branch).BasicBlock.Body[0]);
Ast.Expression arg1 = args.Count >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Count >= 2 ? args[1] : null;
- switch(((SimpleBranch)branch).BasicBlock.Body[0].LastByteCode.OpCode.Code) {
+ switch(((SimpleBranch)branch).BasicBlock.Body[0].OpCode.Code) {
case Code.Brfalse: return new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not);
case Code.Brtrue: return arg1;
case Code.Beq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2);
@@ -284,7 +272,7 @@ Ast.Expression MakeBranchCondition_Internal(Branch branch)
}
}
- static object TransformByteCode(MethodDefinition methodDef, ByteCode byteCode, List<Ast.Expression> args)
+ static object TransformByteCode(MethodDefinition methodDef, ByteCodeExpression byteCode, List<Ast.Expression> args)
{
try {
Ast.INode ret = TransformByteCode_Internal(methodDef, byteCode, args);
@@ -296,14 +284,16 @@ static object TransformByteCode(MethodDefinition methodDef, ByteCode byteCode, L
} catch (NotImplementedException) {
// Output the operand of the unknown IL code as well
if (byteCode.Operand != null) {
- args.Insert(0, new IdentifierExpression(byteCode.FormatedOperand));
+ args.Insert(0, new IdentifierExpression(ByteCode.FormatByteCodeOperand(byteCode.Operand)));
}
return new Ast.InvocationExpression(new IdentifierExpression("IL__" + byteCode.OpCode.Name), args);
}
}
- static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ByteCode byteCode, List<Ast.Expression> args)
+ static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ByteCodeExpression 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;
@@ -313,8 +303,8 @@ static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ByteCode
Ast.Expression arg3 = args.Count >= 3 ? args[2] : null;
Ast.Statement branchCommand = null;
- if (operand is ByteCode) {
- branchCommand = new Ast.GotoStatement(((ByteCode)operand).Expression.BasicBlock.Label);
+ if (byteCode.BranchTarget != null) {
+ branchCommand = new Ast.GotoStatement(byteCode.BranchTarget.BasicBlock.Label);
}
switch(opCode.Code) {
@@ -603,13 +593,17 @@ static Ast.INode TransformByteCode_Internal(MethodDefinition methodDef, ByteCode
VariableDefinition locVar = (VariableDefinition)operand;
string name = locVar.Name;
arg1 = Convert(arg1, locVar.VariableType);
- if (localVarDefined[name]) {
- return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1);
+ if (localVarDefined.ContainsKey(name)) {
+ if (localVarDefined[name]) {
+ return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1);
+ } else {
+ Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(name, arg1));
+ astLocalVar.TypeReference = new Ast.TypeReference(localVarTypes[name].FullName);
+ localVarDefined[name] = true;
+ return astLocalVar;
+ }
} else {
- Ast.LocalVariableDeclaration astLocalVar = new Ast.LocalVariableDeclaration(new Ast.VariableDeclaration(name, arg1));
- astLocalVar.TypeReference = new Ast.TypeReference(localVarTypes[name].FullName);
- localVarDefined[name] = true;
- return astLocalVar;
+ return new Ast.AssignmentExpression(new Ast.IdentifierExpression(name), AssignmentOperatorType.Assign, arg1);
}
}
case Code.Stobj: throw new NotImplementedException();
View
8 src/ByteCode.cs
@@ -9,7 +9,6 @@ namespace Decompiler
{
public partial class ByteCode
{
- ByteCodeExpression expression;
ByteCode previous;
ByteCode next;
@@ -18,11 +17,6 @@ public partial class ByteCode
OpCode opCode;
object operand;
- public ByteCodeExpression Expression {
- get { return expression; }
- set { expression = value; }
- }
-
public ByteCode Previous {
get { return previous; }
set { previous = value; }
@@ -94,7 +88,7 @@ public override string ToString()
}
}
- static string FormatByteCodeOperand(object operand)
+ public static string FormatByteCodeOperand(object operand)
{
if (operand == null) {
return string.Empty;
View
148 src/ByteCodeExpression.cs
@@ -10,137 +10,103 @@ namespace Decompiler
public class ByteCodeExpression
{
ControlFlow.BasicBlock basicBlock;
- ByteCodeExpressionCollection owner;
- ByteCode lastByteCode;
- List<ByteCodeExpression> lastArguments = new List<ByteCodeExpression>();
+
+ 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 lastArgument in lastArguments) {
- lastArgument.BasicBlock = value;
+ foreach (ByteCodeExpression argument in arguments) {
+ argument.BasicBlock = value;
}
}
}
- public ByteCodeExpressionCollection Owner {
- get { return owner; }
+ public OpCode OpCode {
+ get { return opCode; }
+ set { opCode = value; }
}
- public ByteCode LastByteCode {
- get { return lastByteCode; }
+ public object Operand {
+ get { return operand; }
+ set { operand = value; }
}
- // A list of closed expression for last arguments
- public List<ByteCodeExpression> LastArguments {
- get { return lastArguments; }
+ public List<ByteCodeExpression> Arguments {
+ get { return arguments; }
}
- public CilStack StackBefore {
- get {
- return this.FirstByteCode.StackBefore;
- }
+ public bool ReturnsValue {
+ get { return returnsValue; }
+ set { returnsValue = value; }
}
- public CilStack StackAfter {
- get {
- return this.LastByteCode.StackAfter;
- }
+ public TypeReference Type {
+ get { return type; }
+ set { type = value; }
}
- /// <summary>
- /// Expression is closed if it has no inputs and has exactly one output
- /// </summary>
- public bool IsClosed {
- get {
- return this.PopCount == 0 &&
- this.PushCount == 1;
- }
- }
-
- public List<ByteCodeExpression> BranchesHere {
- get {
- List<ByteCodeExpression> branchesHere = new List<ByteCodeExpression>();
- foreach(ByteCode byteCode in this.FirstByteCode.BranchesHere) {
- branchesHere.Add(byteCode.Expression);
- }
- return branchesHere;
- }
+ /// <summary> Single static assignment; single read </summary>
+ public bool IsSSASR {
+ get { return isSSASR; }
+ set { isSSASR = value; }
}
public ByteCodeExpression BranchTarget {
- get {
- if (this.lastByteCode.BranchTarget == null) {
- return null;
- } else {
- return this.lastByteCode.BranchTarget.Expression;
- }
- }
+ get { return branchTarget; }
+ set { branchTarget = value; }
}
- public bool IsBranchTarget {
- get {
- return this.FirstByteCode.BranchesHere.Count > 0;
- }
+ public List<ByteCodeExpression> BranchesHere {
+ get { return branchesHere; }
}
- public int PopCount {
- get {
- int popCount;
- int pushCount;
- SimulateStackSize(out popCount, out pushCount);
- return popCount;
- }
+ public bool IsBranchTarget {
+ get { return BranchesHere.Count > 0; }
}
- public int PushCount {
- get {
- int popCount;
- int pushCount;
- SimulateStackSize(out popCount, out pushCount);
- return pushCount;
- }
+ public static ByteCodeExpression Ldloc(string name)
+ {
+ return new ByteCodeExpression(OpCodes.Ldloc, new VariableDefinition(name, 0, null, null), true);
}
- void SimulateStackSize(out int popCount, out int pushCount)
+ public static ByteCodeExpression Stloc(string name)
{
- int stackSize = 0;
- int minStackSize = 0;
- foreach(ByteCodeExpression expr in lastArguments) {
- stackSize -= expr.PopCount;
- minStackSize = Math.Min(minStackSize, stackSize);
- stackSize += expr.PushCount;
- }
- {
- stackSize -= lastByteCode.PopCount;
- minStackSize = Math.Min(minStackSize, stackSize);
- stackSize += lastByteCode.PushCount;
- }
- popCount = -minStackSize;
- pushCount = stackSize - minStackSize;
+ return new ByteCodeExpression(OpCodes.Stloc, new VariableDefinition(name, 0, null, null), false);
}
- public ByteCode FirstByteCode {
- get {
- if (lastArguments.Count > 0) {
- return lastArguments[0].FirstByteCode;
- } else {
- return this.LastByteCode;
- }
- }
+ public ByteCodeExpression(OpCode opCode, object operand, bool returnsValue)
+ {
+ this.opCode = opCode;
+ this.operand = operand;
+ this.returnsValue = returnsValue;
}
- public ByteCodeExpression(ByteCodeExpressionCollection owner, ByteCode lastByteCode)
+ public ByteCodeExpression(ByteCode byteCode)
{
- this.owner = owner;
- this.lastByteCode = lastByteCode;
- this.lastByteCode.Expression = this;
+ 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 this.LastByteCode.ToString();
+ return string.Format("[ByteCodeExpression OpCode={0}]", this.opCode);
}
}
}
View
78 src/ByteCodeExpressionCollection.cs
@@ -11,26 +11,78 @@ public class ByteCodeExpressionCollection: List<ByteCodeExpression>
{
public ByteCodeExpressionCollection(ByteCodeCollection byteCodeCol)
{
- foreach(ByteCode bc in byteCodeCol) {
- this.Add(new ByteCodeExpression(this, bc));
+ 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 = true;
+ 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);
+ }
}
}
public void Optimize()
{
- for(int i = 1; i < this.Count; i++) {
- if (i == 0) continue;
- ByteCodeExpression prevExpr = this[i - 1];
+ // Try to in-line stloc into following expression
+
+ for(int i = 0; i < this.Count - 1; i++) {
+ if (i < 0) continue;
+
ByteCodeExpression expr = this[i];
+ ByteCodeExpression nextExpr = this[i + 1];
- if (expr.PopCount > 0 && // This expr needs some more arguments
- !expr.IsBranchTarget &&
- prevExpr.IsClosed)
- {
- Options.NotifyCollapsingExpression();
- this.RemoveAt(i - 1); i--;
- expr.LastArguments.Insert(0, prevExpr);
- i--;
+ 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;
+ }
+ }
}
}
}
View
2 src/ControlFlow/Nodes.cs
@@ -149,7 +149,7 @@ public MethodBodyGraph(ByteCodeExpressionCollection exprs)
if (node == target) continue;
// Non-conditional branch does not fall-through
- if (exprs[i].LastByteCode.OpCode.Code == Code.Br) continue;
+ if (exprs[i].OpCode.Code == Code.Br) continue;
node.FallThroughBasicBlock = target;
target.BasicBlockPredecessors.Add(node);

0 comments on commit 4beea5c

Please sign in to comment.