Browse Source

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.
pull/1/head^2
David Srbecký 18 years ago
parent
commit
4beea5c6a1
  1. 35
      bin/Debug/output.cs
  2. 50
      src/AstMetodBodyBuilder.cs
  3. 8
      src/ByteCode.cs
  4. 148
      src/ByteCodeExpression.cs
  5. 78
      src/ByteCodeExpressionCollection.cs
  6. 2
      src/ControlFlow/Nodes.cs

35
bin/Debug/output.cs

@ -162,48 +162,27 @@ namespace Reversi @@ -162,48 +162,27 @@ namespace Reversi
}
}
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:
}

50
src/AstMetodBodyBuilder.cs

@ -180,13 +180,9 @@ namespace Decompiler @@ -180,13 +180,9 @@ namespace Decompiler
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;
}
@ -194,22 +190,14 @@ namespace Decompiler @@ -194,22 +190,14 @@ namespace Decompiler
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 @@ namespace Decompiler @@ -234,7 +222,7 @@ namespace Decompiler
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 @@ namespace Decompiler @@ -284,7 +272,7 @@ namespace Decompiler
}
}
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 @@ namespace Decompiler @@ -296,14 +284,16 @@ namespace Decompiler
} 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 @@ namespace Decompiler @@ -313,8 +303,8 @@ namespace Decompiler
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 @@ namespace Decompiler @@ -603,13 +593,17 @@ namespace Decompiler
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();

8
src/ByteCode.cs

@ -9,7 +9,6 @@ namespace Decompiler @@ -9,7 +9,6 @@ namespace Decompiler
{
public partial class ByteCode
{
ByteCodeExpression expression;
ByteCode previous;
ByteCode next;
@ -18,11 +17,6 @@ namespace Decompiler @@ -18,11 +17,6 @@ namespace Decompiler
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 @@ namespace Decompiler @@ -94,7 +88,7 @@ namespace Decompiler
}
}
static string FormatByteCodeOperand(object operand)
public static string FormatByteCodeOperand(object operand)
{
if (operand == null) {
return string.Empty;

148
src/ByteCodeExpression.cs

@ -10,137 +10,103 @@ namespace Decompiler @@ -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);
}
}
}

78
src/ByteCodeExpressionCollection.cs

@ -11,26 +11,78 @@ namespace Decompiler @@ -11,26 +11,78 @@ namespace Decompiler
{
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;
}
}
}
}
}

2
src/ControlFlow/Nodes.cs

@ -149,7 +149,7 @@ namespace Decompiler.ControlFlow @@ -149,7 +149,7 @@ namespace Decompiler.ControlFlow
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);

Loading…
Cancel
Save