mirror of https://github.com/icsharpcode/ILSpy.git
3 changed files with 123 additions and 110 deletions
@ -0,0 +1,122 @@
@@ -0,0 +1,122 @@
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
|
||||
using Cecil = Mono.Cecil; |
||||
using Mono.Cecil; |
||||
using Mono.Cecil.Cil; |
||||
|
||||
namespace Decompiler |
||||
{ |
||||
public partial class ByteCode |
||||
{ |
||||
public int PopCount { |
||||
get { |
||||
int popCount; |
||||
int pushCount; |
||||
SimulateStackSize(out popCount, out pushCount); |
||||
return popCount; |
||||
} |
||||
} |
||||
|
||||
public int PushCount { |
||||
get { |
||||
int popCount; |
||||
int pushCount; |
||||
SimulateStackSize(out popCount, out pushCount); |
||||
return pushCount; |
||||
} |
||||
} |
||||
|
||||
void SimulateStackSize(out int popCount, out int pushCount) |
||||
{ |
||||
int stackSize = 0; |
||||
int minStackSize = 0; |
||||
foreach(ByteCode bc in nestedByteCodes) { |
||||
stackSize -= bc.PopCount; |
||||
minStackSize = Math.Min(minStackSize, stackSize); |
||||
stackSize += bc.PushCount; |
||||
} |
||||
{ |
||||
stackSize -= GetPopCount(methodDef, this); |
||||
minStackSize = Math.Min(minStackSize, stackSize); |
||||
stackSize += GetPushCount(methodDef, this); |
||||
} |
||||
popCount = -minStackSize; |
||||
pushCount = stackSize - minStackSize; |
||||
} |
||||
|
||||
static int GetPopCount(MethodDefinition methodDef, ByteCode byteCode) |
||||
{ |
||||
switch(byteCode.OpCode.StackBehaviourPop) { |
||||
case StackBehaviour.Pop0: return 0; |
||||
case StackBehaviour.Pop1: return 1; |
||||
case StackBehaviour.Popi: return 1; |
||||
case StackBehaviour.Popref: return 1; |
||||
case StackBehaviour.Pop1_pop1: return 2; |
||||
case StackBehaviour.Popi_pop1: return 2; |
||||
case StackBehaviour.Popi_popi: return 2; |
||||
case StackBehaviour.Popi_popi8: return 2; |
||||
case StackBehaviour.Popi_popr4: return 2; |
||||
case StackBehaviour.Popi_popr8: return 2; |
||||
case StackBehaviour.Popref_pop1: return 2; |
||||
case StackBehaviour.Popref_popi: return 2; |
||||
case StackBehaviour.Popi_popi_popi: return 3; |
||||
case StackBehaviour.Popref_popi_popi: return 3; |
||||
case StackBehaviour.Popref_popi_popi8: return 3; |
||||
case StackBehaviour.Popref_popi_popr4: return 3; |
||||
case StackBehaviour.Popref_popi_popr8: return 3; |
||||
case StackBehaviour.Popref_popi_popref: return 3; |
||||
case StackBehaviour.PopAll: throw new Exception("PopAll"); |
||||
case StackBehaviour.Varpop: |
||||
switch(byteCode.OpCode.Code) { |
||||
case Code.Call: |
||||
Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand); |
||||
if (cecilMethod.HasThis) { |
||||
return cecilMethod.Parameters.Count + 1 /* this */; |
||||
} else { |
||||
return cecilMethod.Parameters.Count; |
||||
} |
||||
case Code.Calli: throw new NotImplementedException(); |
||||
case Code.Callvirt: throw new NotImplementedException(); |
||||
case Code.Ret: |
||||
if (methodDef.ReturnType.ReturnType.FullName == Constants.Void) { |
||||
return 0; |
||||
} else { |
||||
return 1; |
||||
} |
||||
case Code.Newobj: throw new NotImplementedException(); |
||||
default: throw new Exception("Unknown Varpop opcode"); |
||||
} |
||||
default: throw new Exception("Unknown pop behaviour: " + byteCode.OpCode.StackBehaviourPop); |
||||
} |
||||
} |
||||
|
||||
static int GetPushCount(MethodDefinition methodDef, ByteCode byteCode) |
||||
{ |
||||
switch(byteCode.OpCode.StackBehaviourPush) { |
||||
case StackBehaviour.Push0: return 0; |
||||
case StackBehaviour.Push1: return 1; |
||||
case StackBehaviour.Push1_push1: return 2; |
||||
case StackBehaviour.Pushi: return 1; |
||||
case StackBehaviour.Pushi8: return 1; |
||||
case StackBehaviour.Pushr4: return 1; |
||||
case StackBehaviour.Pushr8: return 1; |
||||
case StackBehaviour.Pushref: return 1; |
||||
case StackBehaviour.Varpush: // Happens only for calls
|
||||
switch(byteCode.OpCode.Code) { |
||||
case Code.Call: |
||||
Cecil.MethodReference cecilMethod = ((MethodReference)byteCode.Operand); |
||||
if (cecilMethod.ReturnType.ReturnType.FullName == Constants.Void) { |
||||
return 0; |
||||
} else { |
||||
return 1; |
||||
} |
||||
case Code.Calli: throw new NotImplementedException(); |
||||
case Code.Callvirt: throw new NotImplementedException(); |
||||
default: throw new Exception("Unknown Varpush opcode"); |
||||
} |
||||
default: throw new Exception("Unknown push behaviour: " + byteCode.OpCode.StackBehaviourPush); |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue