Browse Source

Use custom data structure to store bytecode sequence

pull/1/head^2
David Srbecký 18 years ago
parent
commit
0fe95f6b0b
  1. 2
      Decompiler.csproj
  2. 69
      src/AstMetodBodyBuilder.cs
  3. 65
      src/ByteCode.cs
  4. 62
      src/ByteCodeCollection.cs
  5. 14
      src/StackAnalysis.Types.cs
  6. 80
      src/StackAnalysis.cs
  7. 20
      src/Util.cs

2
Decompiler.csproj

@ -39,6 +39,8 @@
<Compile Include="src\AssemblyInfo.cs" /> <Compile Include="src\AssemblyInfo.cs" />
<Compile Include="src\AstBuilder.cs" /> <Compile Include="src\AstBuilder.cs" />
<Compile Include="src\AstMetodBodyBuilder.cs" /> <Compile Include="src\AstMetodBodyBuilder.cs" />
<Compile Include="src\ByteCode.cs" />
<Compile Include="src\ByteCodeCollection.cs" />
<Compile Include="src\MainForm.cs" /> <Compile Include="src\MainForm.cs" />
<Compile Include="src\MainForm.Designer.cs" /> <Compile Include="src\MainForm.Designer.cs" />
<Compile Include="src\Program.cs" /> <Compile Include="src\Program.cs" />

69
src/AstMetodBodyBuilder.cs

@ -18,7 +18,8 @@ namespace Decompiler
methodDef.Body.Simplify(); methodDef.Body.Simplify();
StackAnalysis stackAnalysis = new StackAnalysis(methodDef); ByteCodeCollection body = new ByteCodeCollection(methodDef.Body.Instructions);
StackAnalysis stackAnalysis = new StackAnalysis(methodDef, body);
foreach(VariableDefinition varDef in methodDef.Body.Variables) { foreach(VariableDefinition varDef in methodDef.Body.Variables) {
Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name); Ast.VariableDeclaration astVar = new Ast.VariableDeclaration(varDef.Name);
@ -27,12 +28,12 @@ namespace Decompiler
astBlock.Children.Add(astLocalVar); astBlock.Children.Add(astLocalVar);
} }
foreach(Instruction instr in methodDef.Body.Instructions) { foreach(ByteCode byteCode in body) {
OpCode opCode = instr.OpCode; OpCode opCode = byteCode.OpCode;
string description = string description =
string.Format(" {1, -22} # {2}->{3} {4} {5}", string.Format(" {1, -22} # {2}->{3} {4} {5}",
instr.Offset, byteCode.Offset,
opCode + " " + FormatInstructionOperand(instr.Operand), opCode + " " + FormatByteCodeOperand(byteCode.Operand),
opCode.StackBehaviourPop, opCode.StackBehaviourPop,
opCode.StackBehaviourPush, opCode.StackBehaviourPush,
opCode.FlowControl == FlowControl.Next ? string.Empty : "Flow=" + opCode.FlowControl, opCode.FlowControl == FlowControl.Next ? string.Empty : "Flow=" + opCode.FlowControl,
@ -40,21 +41,21 @@ namespace Decompiler
Ast.Statement astStatement = null; Ast.Statement astStatement = null;
try { try {
int argCount = Util.GetNumberOfInputs(methodDef, instr); int argCount = Util.GetNumberOfInputs(methodDef, byteCode);
Ast.Expression[] args = new Ast.Expression[argCount]; Ast.Expression[] args = new Ast.Expression[argCount];
for(int i = 0; i < argCount; i++) { for(int i = 0; i < argCount; i++) {
Instruction allocBy = stackAnalysis.StackBefore[instr].Peek(argCount - i).AllocadedBy; ByteCode allocBy = stackAnalysis.StackBefore[byteCode].Peek(argCount - i).AllocadedBy;
string name = string.Format("expr{0:X2}", allocBy.Offset); string name = string.Format("expr{0:X2}", allocBy.Offset);
args[i] = new Ast.IdentifierExpression(name); args[i] = new Ast.IdentifierExpression(name);
} }
object codeExpr = MakeCodeDomExpression( object codeExpr = MakeCodeDomExpression(
methodDef, methodDef,
instr, byteCode,
args); args);
if (codeExpr is Ast.Expression) { if (codeExpr is Ast.Expression) {
if (Util.GetNumberOfOutputs(methodDef, instr) == 1) { if (Util.GetNumberOfOutputs(methodDef, byteCode) == 1) {
string type = stackAnalysis.GetTypeOf(instr).FullName; string type = stackAnalysis.GetTypeOf(byteCode).FullName;
string name = string.Format("expr{0:X2}", instr.Offset); string name = string.Format("expr{0:X2}", byteCode.Offset);
Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString())); Ast.LocalVariableDeclaration astLocal = new Ast.LocalVariableDeclaration(new Ast.TypeReference(type.ToString()));
astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr)); astLocal.Variables.Add(new Ast.VariableDeclaration(name, (Ast.Expression)codeExpr));
astStatement = astLocal; astStatement = astLocal;
@ -68,8 +69,8 @@ namespace Decompiler
astStatement = MakeComment(description); astStatement = MakeComment(description);
} }
//astBlock.Children.Add(MakeComment(description)); //astBlock.Children.Add(MakeComment(description));
if (stackAnalysis.BranchTargetOf[instr].Count > 0) { if (stackAnalysis.BranchTargetOf[byteCode].Count > 0) {
astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", instr.Offset))); astBlock.Children.Add(new Ast.LabelStatement(string.Format("IL_{0:X2}", byteCode.Offset)));
} }
astBlock.Children.Add(astStatement); astBlock.Children.Add(astStatement);
//astBlock.Children.Add(MakeComment(" " + stackAnalysis.StackAfter[instr].ToString())); //astBlock.Children.Add(MakeComment(" " + stackAnalysis.StackAfter[instr].ToString()));
@ -84,12 +85,12 @@ namespace Decompiler
return new Ast.ExpressionStatement(new PrimitiveExpression(text, text)); return new Ast.ExpressionStatement(new PrimitiveExpression(text, text));
} }
static object FormatInstructionOperand(object operand) static object FormatByteCodeOperand(object operand)
{ {
if (operand == null) { if (operand == null) {
return string.Empty; return string.Empty;
} else if (operand is Instruction) { } else if (operand is ByteCode) {
return string.Format("IL_{0:X2}", ((Instruction)operand).Offset); return string.Format("IL_{0:X2}", ((ByteCode)operand).Offset);
} else if (operand is MethodReference) { } else if (operand is MethodReference) {
return ((MethodReference)operand).Name + "()"; return ((MethodReference)operand).Name + "()";
} else if (operand is Cecil.TypeReference) { } else if (operand is Cecil.TypeReference) {
@ -107,13 +108,13 @@ namespace Decompiler
} }
} }
static object MakeCodeDomExpression(MethodDefinition methodDef, Instruction inst, params Ast.Expression[] args) static object MakeCodeDomExpression(MethodDefinition methodDef, ByteCode byteCode, params Ast.Expression[] args)
{ {
OpCode opCode = inst.OpCode; OpCode opCode = byteCode.OpCode;
object operand = inst.Operand; object operand = byteCode.Operand;
Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null; Ast.TypeReference operandAsTypeRef = operand is Cecil.TypeReference ? new Ast.TypeReference(((Cecil.TypeReference)operand).FullName) : null;
Instruction operandAsInstruction = operand is Instruction ? (Instruction)operand : null; ByteCode operandAsByteCode = operand as ByteCode;
string operandAsInstructionLabel = operand is Instruction ? String.Format("IL_{0:X2}", ((Instruction)operand).Offset) : null; string operandAsByteCodeLabel = operand is ByteCode ? String.Format("IL_{0:X2}", ((ByteCode)operand).Offset) : null;
Ast.Expression arg1 = args.Length >= 1 ? args[0] : null; Ast.Expression arg1 = args.Length >= 1 ? args[0] : null;
Ast.Expression arg2 = args.Length >= 2 ? args[1] : null; Ast.Expression arg2 = args.Length >= 2 ? args[1] : null;
Ast.Expression arg3 = args.Length >= 3 ? args[2] : null; Ast.Expression arg3 = args.Length >= 3 ? args[2] : null;
@ -174,19 +175,19 @@ namespace Decompiler
case Code.Stelem_Any: throw new NotImplementedException(); case Code.Stelem_Any: throw new NotImplementedException();
#endregion #endregion
#region Branching #region Branching
case Code.Br: return new Ast.GotoStatement(operandAsInstructionLabel); case Code.Br: return new Ast.GotoStatement(operandAsByteCodeLabel);
case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Brfalse: return new Ast.IfElseStatement(new Ast.UnaryOperatorExpression(arg1, UnaryOperatorType.Not), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Brtrue: return new Ast.IfElseStatement(arg1, new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Brtrue: return new Ast.IfElseStatement(arg1, new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Beq: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Bge: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Bge_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Bge_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThanOrEqual, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Bgt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Bgt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Bgt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Bgt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.GreaterThan, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Ble: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Ble: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Ble_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Ble_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThanOrEqual, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Blt: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Blt_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.LessThan, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), new Ast.GotoStatement(operandAsInstructionLabel)); case Code.Bne_Un: return new Ast.IfElseStatement(new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.InEquality, arg2), new Ast.GotoStatement(operandAsByteCodeLabel));
#endregion #endregion
#region Comparison #region Comparison
case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2)); case Code.Ceq: return new Ast.BinaryOperatorExpression(arg1, BinaryOperatorType.Equality, ConvertIntToBool(arg2));

65
src/ByteCode.cs

@ -0,0 +1,65 @@
using System;
using System.Collections.Generic;
using Cecil = Mono.Cecil;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace Decompiler
{
public class ByteCode
{
ByteCode next;
int offset;
OpCode opCode;
object operand;
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 (ByteCode)operand;
}
}
public bool CanBranch {
get {
return OpCode.FlowControl == FlowControl.Branch ||
OpCode.FlowControl == FlowControl.Cond_Branch;
}
}
public ByteCode(int offset, OpCode opCode, object operand)
{
this.offset = offset;
this.opCode = opCode;
this.operand = operand;
}
public ByteCode(Instruction inst)
{
this.offset = inst.Offset;
this.opCode = inst.OpCode;
this.operand = inst.Operand;
}
}
}

62
src/ByteCodeCollection.cs

@ -0,0 +1,62 @@
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> byteCodes = new List<ByteCode>();
public IEnumerator<ByteCode> GetEnumerator()
{
return byteCodes.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return byteCodes.GetEnumerator();
}
public int Count {
get {
return byteCodes.Count;
}
}
public ByteCode this[int index] {
get {
return byteCodes[index];
}
}
public ByteCode GetByOffset(int offset)
{
foreach(ByteCode byteCode in this) {
if (byteCode.Offset == offset) {
return byteCode;
}
}
throw new Exception("Not found");
}
public ByteCodeCollection(InstructionCollection instCol)
{
foreach(Instruction inst in instCol) {
byteCodes.Add(new ByteCode(inst));
}
foreach(ByteCode byteCode in this) {
if (byteCode.CanBranch) {
byteCode.Operand = GetByOffset(((Instruction)byteCode.Operand).Offset);
}
}
for(int i = 0; i < byteCodes.Count - 1; i++) {
this[i].Next = this[i + 1];
}
}
}
}

14
src/StackAnalysis.Types.cs

@ -23,22 +23,22 @@ namespace Decompiler
return new Cecil.TypeReference(type.Name, type.Namespace, null, type.IsValueType); return new Cecil.TypeReference(type.Name, type.Namespace, null, type.IsValueType);
} }
static Cecil.TypeReference GetType(MethodDefinition methodDef, Instruction inst, params Cecil.TypeReference[] args) static Cecil.TypeReference GetType(MethodDefinition methodDef, ByteCode byteCode, params Cecil.TypeReference[] args)
{ {
try { try {
return(GetTypeInternal(methodDef, inst, args)); return(GetTypeInternal(methodDef, byteCode, args));
} catch (NotImplementedException) { } catch (NotImplementedException) {
return TypeObject; return TypeObject;
} }
} }
static Cecil.TypeReference GetTypeInternal(MethodDefinition methodDef, Instruction inst, params Cecil.TypeReference[] args) static Cecil.TypeReference GetTypeInternal(MethodDefinition methodDef, ByteCode byteCode, params Cecil.TypeReference[] args)
{ {
OpCode opCode = inst.OpCode; OpCode opCode = byteCode.OpCode;
object operand = inst.Operand; object operand = byteCode.Operand;
Cecil.TypeReference operandAsTypeRef = operand as Cecil.TypeReference; Cecil.TypeReference operandAsTypeRef = operand as Cecil.TypeReference;
Instruction operandAsInstruction = operand is Instruction ? (Instruction)operand : null; ByteCode operandAsByteCode = operand as ByteCode;
string operandAsInstructionLabel = operand is Instruction ? String.Format("IL_{0:X2}", ((Instruction)operand).Offset) : null; 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 arg1 = args.Length >= 1 ? args[0] : null;
Cecil.TypeReference arg2 = args.Length >= 2 ? args[1] : null; Cecil.TypeReference arg2 = args.Length >= 2 ? args[1] : null;
Cecil.TypeReference arg3 = args.Length >= 3 ? args[2] : null; Cecil.TypeReference arg3 = args.Length >= 3 ? args[2] : null;

80
src/StackAnalysis.cs

@ -12,10 +12,10 @@ namespace Decompiler
{ {
// Imutable // Imutable
public struct CilStackSlot { public struct CilStackSlot {
Instruction allocadedBy; ByteCode allocadedBy;
Cecil.TypeReference type; Cecil.TypeReference type;
public Instruction AllocadedBy { public ByteCode AllocadedBy {
get { return allocadedBy; } get { return allocadedBy; }
} }
@ -23,7 +23,7 @@ namespace Decompiler
get { return type; } get { return type; }
} }
public CilStackSlot(Instruction allocadedBy, Cecil.TypeReference type) public CilStackSlot(ByteCode allocadedBy, Cecil.TypeReference type)
{ {
this.allocadedBy = allocadedBy; this.allocadedBy = allocadedBy;
this.type = type; this.type = type;
@ -106,98 +106,96 @@ namespace Decompiler
public partial class StackAnalysis { public partial class StackAnalysis {
MethodDefinition methodDef; MethodDefinition methodDef;
Dictionary<Instruction, CilStack> stackBefore = new Dictionary<Instruction, CilStack>(); Dictionary<ByteCode, CilStack> stackBefore = new Dictionary<ByteCode, CilStack>();
Dictionary<Instruction, CilStack> stackAfter = new Dictionary<Instruction, CilStack>(); Dictionary<ByteCode, CilStack> stackAfter = new Dictionary<ByteCode, CilStack>();
Dictionary<Instruction, List<Instruction>> branchTargetOf = new Dictionary<Instruction, List<Instruction>>(); Dictionary<ByteCode, List<ByteCode>> branchTargetOf = new Dictionary<ByteCode, List<ByteCode>>();
public Dictionary<Instruction, CilStack> StackBefore { public Dictionary<ByteCode, CilStack> StackBefore {
get { return stackBefore; } get { return stackBefore; }
} }
public Dictionary<Instruction, CilStack> StackAfter { public Dictionary<ByteCode, CilStack> StackAfter {
get { return stackAfter; } get { return stackAfter; }
} }
public Dictionary<Instruction, List<Instruction>> BranchTargetOf { public Dictionary<ByteCode, List<ByteCode>> BranchTargetOf {
get { return branchTargetOf; } get { return branchTargetOf; }
} }
public Cecil.TypeReference GetTypeOf(Instruction inst) public Cecil.TypeReference GetTypeOf(ByteCode byteCode)
{ {
if (Util.GetNumberOfOutputs(methodDef, inst) == 0) { if (Util.GetNumberOfOutputs(methodDef, byteCode) == 0) {
return TypeVoid; return TypeVoid;
} else { } else {
return StackAfter[inst].Peek(1).Type; return StackAfter[byteCode].Peek(1).Type;
} }
} }
public StackAnalysis(MethodDefinition methodDef) { public StackAnalysis(MethodDefinition methodDef, ByteCodeCollection byteCodeCol) {
this.methodDef = methodDef; this.methodDef = methodDef;
foreach(Instruction inst in methodDef.Body.Instructions) { foreach(ByteCode byteCode in byteCodeCol) {
stackBefore[inst] = null; stackBefore[byteCode] = null;
stackAfter[inst] = null; stackAfter[byteCode] = null;
branchTargetOf[inst] = new List<Instruction>(); branchTargetOf[byteCode] = new List<ByteCode>();
} }
foreach(Instruction inst in methodDef.Body.Instructions) { foreach(ByteCode byteCode in byteCodeCol) {
if (inst.OpCode.FlowControl == FlowControl.Branch || if (byteCode.CanBranch) {
inst.OpCode.FlowControl == FlowControl.Cond_Branch) branchTargetOf[byteCode.BranchTarget].Add(byteCode);
{
branchTargetOf[(Instruction)inst.Operand].Add(inst);
} }
} }
if (methodDef.Body.Instructions.Count > 0) { if (byteCodeCol.Count > 0) {
Instruction firstInst = methodDef.Body.Instructions[0]; ByteCode firstInst = byteCodeCol[0];
stackBefore[firstInst] = CilStack.Empty; stackBefore[firstInst] = CilStack.Empty;
ProcessInstructionRec(firstInst); ProcessByteCodeRec(firstInst);
} }
} }
void ProcessInstructionRec(Instruction inst) void ProcessByteCodeRec(ByteCode byteCode)
{ {
stackAfter[inst] = ChangeStack(stackBefore[inst], inst); stackAfter[byteCode] = ChangeStack(stackBefore[byteCode], byteCode);
switch(inst.OpCode.FlowControl) { switch(byteCode.OpCode.FlowControl) {
case FlowControl.Branch: case FlowControl.Branch:
CopyStack(inst, ((Instruction)inst.Operand)); CopyStack(byteCode, byteCode.BranchTarget);
break; break;
case FlowControl.Cond_Branch: case FlowControl.Cond_Branch:
CopyStack(inst, inst.Next); CopyStack(byteCode, byteCode.Next);
CopyStack(inst, ((Instruction)inst.Operand)); CopyStack(byteCode, byteCode.BranchTarget);
break; break;
case FlowControl.Next: case FlowControl.Next:
case FlowControl.Call: case FlowControl.Call:
CopyStack(inst, inst.Next); CopyStack(byteCode, byteCode.Next);
break; break;
case FlowControl.Return: case FlowControl.Return:
if (stackAfter[inst].Count > 0) throw new Exception("Non-empty stack at the end"); if (stackAfter[byteCode].Count > 0) throw new Exception("Non-empty stack at the end");
break; break;
default: throw new NotImplementedException(); default: throw new NotImplementedException();
} }
} }
CilStack ChangeStack(CilStack oldStack, Instruction inst) CilStack ChangeStack(CilStack oldStack, ByteCode byteCode)
{ {
CilStack newStack = oldStack.Clone(); CilStack newStack = oldStack.Clone();
CilStackSlot[] popedSlots = newStack.PopCount(Util.GetNumberOfInputs(methodDef, inst)); CilStackSlot[] popedSlots = newStack.PopCount(Util.GetNumberOfInputs(methodDef, byteCode));
List<Cecil.TypeReference> typeArgs = new List<Cecil.TypeReference>(); List<Cecil.TypeReference> typeArgs = new List<Cecil.TypeReference>();
foreach(CilStackSlot slot in popedSlots) { foreach(CilStackSlot slot in popedSlots) {
typeArgs.Add(slot.Type); typeArgs.Add(slot.Type);
} }
for (int i = 0; i < Util.GetNumberOfOutputs(methodDef, inst); i++) { for (int i = 0; i < Util.GetNumberOfOutputs(methodDef, byteCode); i++) {
newStack.Push(new CilStackSlot(inst, GetType(methodDef, inst, typeArgs.ToArray()))); newStack.Push(new CilStackSlot(byteCode, GetType(methodDef, byteCode, typeArgs.ToArray())));
} }
return newStack; return newStack;
} }
void CopyStack(Instruction instFrom, Instruction instTo) void CopyStack(ByteCode byteCodeFrom, ByteCode byteCodeTo)
{ {
CilStack mergedStack; CilStack mergedStack;
if (!Merge(stackAfter[instFrom], stackBefore[instTo], out mergedStack)) { if (!Merge(stackAfter[byteCodeFrom], stackBefore[byteCodeTo], out mergedStack)) {
stackBefore[instTo] = mergedStack; stackBefore[byteCodeTo] = mergedStack;
ProcessInstructionRec(instTo); ProcessByteCodeRec(byteCodeTo);
} }
} }

20
src/Util.cs

@ -11,9 +11,9 @@ namespace Decompiler
{ {
public static class Util public static class Util
{ {
public static int GetNumberOfInputs(MethodDefinition methodDef, Instruction inst) public static int GetNumberOfInputs(MethodDefinition methodDef, ByteCode byteCode)
{ {
switch(inst.OpCode.StackBehaviourPop) { switch(byteCode.OpCode.StackBehaviourPop) {
case StackBehaviour.Pop0: return 0; case StackBehaviour.Pop0: return 0;
case StackBehaviour.Pop1: return 1; case StackBehaviour.Pop1: return 1;
case StackBehaviour.Popi: return 1; case StackBehaviour.Popi: return 1;
@ -34,9 +34,9 @@ namespace Decompiler
case StackBehaviour.Popref_popi_popref: return 3; case StackBehaviour.Popref_popi_popref: return 3;
case StackBehaviour.PopAll: throw new Exception("PopAll"); case StackBehaviour.PopAll: throw new Exception("PopAll");
case StackBehaviour.Varpop: case StackBehaviour.Varpop:
switch(inst.OpCode.Code) { switch(byteCode.OpCode.Code) {
case Code.Call: case Code.Call:
Cecil.MethodReference cecilMethod = ((MethodReference)inst.Operand); Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand);
if (cecilMethod.HasThis) { if (cecilMethod.HasThis) {
return cecilMethod.Parameters.Count + 1 /* this */; return cecilMethod.Parameters.Count + 1 /* this */;
} else { } else {
@ -53,13 +53,13 @@ namespace Decompiler
case Code.Newobj: throw new NotImplementedException(); case Code.Newobj: throw new NotImplementedException();
default: throw new Exception("Unknown Varpop opcode"); default: throw new Exception("Unknown Varpop opcode");
} }
default: throw new Exception("Unknown pop behaviour: " + inst.OpCode.StackBehaviourPop); default: throw new Exception("Unknown pop behaviour: " + byteCode.OpCode.StackBehaviourPop);
} }
} }
public static int GetNumberOfOutputs(MethodDefinition methodDef, Instruction inst) public static int GetNumberOfOutputs(MethodDefinition methodDef, ByteCode byteCode)
{ {
switch(inst.OpCode.StackBehaviourPush) { switch(byteCode.OpCode.StackBehaviourPush) {
case StackBehaviour.Push0: return 0; case StackBehaviour.Push0: return 0;
case StackBehaviour.Push1: return 1; case StackBehaviour.Push1: return 1;
case StackBehaviour.Push1_push1: return 2; case StackBehaviour.Push1_push1: return 2;
@ -69,9 +69,9 @@ namespace Decompiler
case StackBehaviour.Pushr8: return 1; case StackBehaviour.Pushr8: return 1;
case StackBehaviour.Pushref: return 1; case StackBehaviour.Pushref: return 1;
case StackBehaviour.Varpush: // Happens only for calls case StackBehaviour.Varpush: // Happens only for calls
switch(inst.OpCode.Code) { switch(byteCode.OpCode.Code) {
case Code.Call: case Code.Call:
Cecil.MethodReference cecilMethod = ((MethodReference)inst.Operand); Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand);
if (cecilMethod.ReturnType.ReturnType.FullName == Constants.Void) { if (cecilMethod.ReturnType.ReturnType.FullName == Constants.Void) {
return 0; return 0;
} else { } else {
@ -81,7 +81,7 @@ namespace Decompiler
case Code.Callvirt: throw new NotImplementedException(); case Code.Callvirt: throw new NotImplementedException();
default: throw new Exception("Unknown Varpush opcode"); default: throw new Exception("Unknown Varpush opcode");
} }
default: throw new Exception("Unknown push behaviour: " + inst.OpCode.StackBehaviourPush); default: throw new Exception("Unknown push behaviour: " + byteCode.OpCode.StackBehaviourPush);
} }
} }
} }

Loading…
Cancel
Save