Browse Source

Remove the evaluation stack from ILAst; the ILReader now directly introduces stack variables.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
06356512fa
  1. 3
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 5
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  3. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 4
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  5. 459
      ICSharpCode.Decompiler/IL/ILReader.cs
  6. 24
      ICSharpCode.Decompiler/IL/ILVariable.cs
  7. 170
      ICSharpCode.Decompiler/IL/Instructions.cs
  8. 19
      ICSharpCode.Decompiler/IL/Instructions.tt
  9. 27
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  10. 10
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  11. 32
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  12. 7
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  13. 8
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  14. 5
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  15. 21
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  16. 28
      ICSharpCode.Decompiler/IL/Instructions/Leave.cs
  17. 24
      ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs
  18. 7
      ICSharpCode.Decompiler/IL/Instructions/Return.cs
  19. 30
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  20. 20
      ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs
  21. 57
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  22. 6
      ICSharpCode.Decompiler/IL/Transforms/ControlFlowSimplification.cs
  23. 34
      ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs
  24. 9
      ICSharpCode.Decompiler/IL/Transforms/OptimizingTransform.cs
  25. 96
      ICSharpCode.Decompiler/IL/Transforms/TransformStackIntoVariables.cs
  26. 82
      ICSharpCode.Decompiler/IL/Transforms/TransformStackIntoVariablesState.cs
  27. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformingVisitor.cs
  28. 2
      ICSharpCode.Decompiler/Tests/ILTransforms/InliningTests.cs

3
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -44,8 +44,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -44,8 +44,7 @@ namespace ICSharpCode.Decompiler.CSharp
new OptimizingTransform(),
new LoopDetection(),
new ControlFlowSimplification(),
new TransformingVisitor(),
new TransformStackIntoVariables()
new TransformingVisitor()
};
List<IAstTransform> astTransforms = new List<IAstTransform> {

5
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -61,11 +61,6 @@ namespace ICSharpCode.Decompiler.CSharp @@ -61,11 +61,6 @@ namespace ICSharpCode.Decompiler.CSharp
return new EmptyStatement();
}
protected internal override Statement VisitVoid(ICSharpCode.Decompiler.IL.Void inst)
{
return new ExpressionStatement(exprBuilder.Translate(inst.Argument));
}
protected internal override Statement VisitIfInstruction(IfInstruction inst)
{
var condition = exprBuilder.TranslateCondition(inst.Condition);

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -106,11 +106,10 @@ @@ -106,11 +106,10 @@
<Compile Include="IL\IInlineContext.cs" />
<Compile Include="IL\NRTypeExtensions.cs" />
<Compile Include="IL\Transforms\ControlFlowSimplification.cs" />
<Compile Include="IL\Transforms\IILTransform.cs" />
<Compile Include="IL\Transforms\LoopDetection.cs" />
<Compile Include="IL\Transforms\OptimizingTransform.cs" />
<Compile Include="IL\Transforms\TransformingVisitor.cs" />
<Compile Include="IL\Transforms\TransformStackIntoVariables.cs" />
<Compile Include="IL\Transforms\TransformStackIntoVariablesState.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />
<Compile Include="Disassembler\ILStructure.cs" />

4
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -78,7 +78,9 @@ namespace ICSharpCode.Decompiler.IL @@ -78,7 +78,9 @@ namespace ICSharpCode.Decompiler.IL
tryInstructionList.Add(tryCatch);
}
var variable = new ILVariable(VariableKind.Exception, typeSystem.Resolve(eh.CatchType), handlerBlock.ILRange.Start);
ILVariable variable = null;
throw new NotImplementedException();
//var variable = new ILVariable(VariableKind.Exception, typeSystem.Resolve(eh.CatchType), handlerBlock.ILRange.Start);
variable.Name = "ex";
handlerBlock.EntryPoint.Instructions.Add(new LdLoc(variable));

459
ICSharpCode.Decompiler/IL/ILReader.cs

@ -60,14 +60,16 @@ namespace ICSharpCode.Decompiler.IL @@ -60,14 +60,16 @@ namespace ICSharpCode.Decompiler.IL
Cil.MethodBody body;
BlobReader reader;
Stack<StackType> stack;
ImmutableStack<ILVariable> currentStack;
ILVariable[] parameterVariables;
ILVariable[] localVariables;
BitArray isBranchTarget;
List<ILInstruction> instructionBuilder;
// Dictionary that stores stacks for forward jumps
Dictionary<int, ImmutableArray<StackType>> branchStackDict;
// Dictionary that stores stacks for each IL instruction
Dictionary<int, ImmutableStack<ILVariable>> stackByOffset;
UnionFind<ILVariable> unionFind;
IEnumerable<ILVariable> stackVariables;
void Init(Cil.MethodBody body)
{
@ -75,12 +77,13 @@ namespace ICSharpCode.Decompiler.IL @@ -75,12 +77,13 @@ namespace ICSharpCode.Decompiler.IL
throw new ArgumentNullException("body");
this.body = body;
this.reader = body.GetILReader();
this.stack = new Stack<StackType>(body.MaxStackSize);
this.currentStack = ImmutableStack<ILVariable>.Empty;
this.unionFind = new UnionFind<ILVariable>();
InitParameterVariables();
this.localVariables = body.Variables.SelectArray(CreateILVariable);
this.instructionBuilder = new List<ILInstruction>();
this.isBranchTarget = new BitArray(body.CodeSize);
this.branchStackDict = new Dictionary<int, ImmutableArray<StackType>>();
this.stackByOffset = new Dictionary<int, ImmutableStack<ILVariable>>();
}
IMetadataTokenProvider ReadAndDecodeMetadataToken()
@ -154,46 +157,69 @@ namespace ICSharpCode.Decompiler.IL @@ -154,46 +157,69 @@ namespace ICSharpCode.Decompiler.IL
Debug.Fail(message);
}
void ReadInstructions(Dictionary<int, ImmutableArray<StackType>> outputStacks, CancellationToken cancellationToken)
void MergeStacks(ImmutableStack<ILVariable> a, ImmutableStack<ILVariable> b)
{
var enum1 = a.GetEnumerator();
var enum2 = b.GetEnumerator();
while (enum1.MoveNext() && enum2.MoveNext()) {
unionFind.Merge(enum1.Current, enum2.Current);
}
}
void StoreStackForOffset(int offset, ImmutableStack<ILVariable> stack)
{
ImmutableStack<ILVariable> existing;
if (stackByOffset.TryGetValue(offset, out existing)) {
MergeStacks(existing, stack);
} else {
stackByOffset.Add(offset, stack);
}
}
void ReadInstructions(CancellationToken cancellationToken)
{
// Fill isBranchTarget and branchStackDict based on exception handlers
foreach (var eh in body.ExceptionHandlers) {
ImmutableStack<ILVariable> ehStack = null;
if (eh.HandlerType == Cil.ExceptionHandlerType.Catch || eh.HandlerType == Cil.ExceptionHandlerType.Filter) {
ehStack = ImmutableStack.Create(
new ILVariable(VariableKind.Exception, typeSystem.Resolve(eh.CatchType), eh.HandlerStart.Offset)
);
} else {
ehStack = ImmutableStack<ILVariable>.Empty;
}
if (eh.FilterStart != null) {
isBranchTarget[eh.FilterStart.Offset] = true;
branchStackDict[eh.FilterStart.Offset] = ImmutableArray.Create(eh.CatchType.GetStackType());
StoreStackForOffset(eh.FilterStart.Offset, ehStack);
}
if (eh.HandlerStart != null) {
isBranchTarget[eh.HandlerStart.Offset] = true;
if (eh.HandlerType == Cil.ExceptionHandlerType.Catch || eh.HandlerType == Cil.ExceptionHandlerType.Filter)
branchStackDict[eh.HandlerStart.Offset] = ImmutableArray.Create(eh.CatchType.GetStackType());
else
branchStackDict[eh.HandlerStart.Offset] = ImmutableArray<StackType>.Empty;
StoreStackForOffset(eh.HandlerStart.Offset, ehStack);
}
}
while (reader.Position < reader.Length) {
cancellationToken.ThrowIfCancellationRequested();
int start = reader.Position;
if (outputStacks != null)
outputStacks.Add(start, stack.ToImmutableArray());
StoreStackForOffset(start, currentStack);
ILInstruction decodedInstruction = DecodeInstruction();
if (decodedInstruction.ResultType == StackType.Unknown)
Warn("Unknown result type (might be due to invalid IL)");
decodedInstruction.CheckInvariant();
if (decodedInstruction.ResultType != StackType.Void)
stack.Push(decodedInstruction.ResultType);
decodedInstruction.ILRange = new Interval(start, reader.Position);
instructionBuilder.Add(decodedInstruction);
if (decodedInstruction.HasFlag(InstructionFlags.EndPointUnreachable)) {
stack.Clear();
ImmutableArray<StackType> stackFromBranch;
if (branchStackDict.TryGetValue(reader.Position, out stackFromBranch)) {
for (int i = stackFromBranch.Length - 1; i >= 0; i--) {
stack.Push(stackFromBranch[i]);
}
if (!stackByOffset.TryGetValue(reader.Position, out currentStack)) {
currentStack = ImmutableStack<ILVariable>.Empty;
}
}
}
var visitor = new CollectStackVariablesVisitor(unionFind);
for (int i = 0; i < instructionBuilder.Count; i++) {
instructionBuilder[i] = instructionBuilder[i].AcceptVisitor(visitor);
}
stackVariables = visitor.variables;
}
/// <summary>
@ -202,17 +228,16 @@ namespace ICSharpCode.Decompiler.IL @@ -202,17 +228,16 @@ namespace ICSharpCode.Decompiler.IL
public void WriteTypedIL(Cil.MethodBody body, ITextOutput output, CancellationToken cancellationToken = default(CancellationToken))
{
Init(body);
var outputStacks = new Dictionary<int, ImmutableArray<StackType>>();
ReadInstructions(outputStacks, cancellationToken);
ReadInstructions(cancellationToken);
foreach (var inst in instructionBuilder) {
output.Write(" [");
bool isFirstElement = true;
foreach (var element in outputStacks[inst.ILRange.Start]) {
foreach (var element in stackByOffset[inst.ILRange.Start]) {
if (isFirstElement)
isFirstElement = false;
else
output.Write(", ");
output.Write(element);
output.Write(element.StackType);
}
output.Write(']');
output.WriteLine();
@ -234,25 +259,26 @@ namespace ICSharpCode.Decompiler.IL @@ -234,25 +259,26 @@ namespace ICSharpCode.Decompiler.IL
public ILFunction ReadIL(Cil.MethodBody body, CancellationToken cancellationToken = default(CancellationToken))
{
Init(body);
ReadInstructions(null, cancellationToken);
ReadInstructions(cancellationToken);
var container = new BlockBuilder(body, typeSystem).CreateBlocks(instructionBuilder, isBranchTarget);
var function = new ILFunction(body.Method, container);
function.Variables.AddRange(parameterVariables);
function.Variables.AddRange(localVariables);
function.Variables.AddRange(stackVariables);
function.AddRef(); // mark the root node
return function;
}
ILInstruction Neg()
{
switch (stack.PeekOrDefault()) {
switch (PeekStackType()) {
case StackType.I4:
case StackType.I:
return new Sub(new LdcI4(0), Pop(), checkForOverflow: false, sign: Sign.None);
return Push(new Sub(new LdcI4(0), Pop(), checkForOverflow: false, sign: Sign.None));
case StackType.I8:
return new Sub(new LdcI8(0), Pop(), checkForOverflow: false, sign: Sign.None);
return Push(new Sub(new LdcI8(0), Pop(), checkForOverflow: false, sign: Sign.None));
case StackType.F:
return new Sub(new LdcF(0), Pop(), checkForOverflow: false, sign: Sign.None);
return Push(new Sub(new LdcF(0), Pop(), checkForOverflow: false, sign: Sign.None));
default:
Warn("Unsupported input type for neg: ");
goto case StackType.I4;
@ -282,7 +308,7 @@ namespace ICSharpCode.Decompiler.IL @@ -282,7 +308,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.And:
return BinaryNumeric(OpCode.BitAnd);
case ILOpCode.Arglist:
return new Arglist();
return Push(new Arglist());
case ILOpCode.Beq:
return DecodeComparisonBranch(false, OpCode.Ceq, OpCode.Ceq, false);
case ILOpCode.Beq_S:
@ -344,83 +370,83 @@ namespace ICSharpCode.Decompiler.IL @@ -344,83 +370,83 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Calli:
throw new NotImplementedException();
case ILOpCode.Ceq:
return Comparison(OpCode.Ceq, OpCode.Ceq);
return Push(Comparison(OpCode.Ceq, OpCode.Ceq));
case ILOpCode.Cgt:
return Comparison(OpCode.Cgt, OpCode.Cgt);
return Push(Comparison(OpCode.Cgt, OpCode.Cgt));
case ILOpCode.Cgt_Un:
return Comparison(OpCode.Cgt_Un, OpCode.Cgt_Un);
return Push(Comparison(OpCode.Cgt_Un, OpCode.Cgt_Un));
case ILOpCode.Clt:
return Comparison(OpCode.Clt, OpCode.Clt);
return Push(Comparison(OpCode.Clt, OpCode.Clt));
case ILOpCode.Clt_Un:
return Comparison(OpCode.Clt_Un, OpCode.Clt_Un);
return Push(Comparison(OpCode.Clt_Un, OpCode.Clt_Un));
case ILOpCode.Ckfinite:
return new Ckfinite(new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown));
return new Ckfinite(Peek());
case ILOpCode.Conv_I1:
return new Conv(Pop(), PrimitiveType.I1, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.I1, false, Sign.None));
case ILOpCode.Conv_I2:
return new Conv(Pop(), PrimitiveType.I2, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.I2, false, Sign.None));
case ILOpCode.Conv_I4:
return new Conv(Pop(), PrimitiveType.I4, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.I4, false, Sign.None));
case ILOpCode.Conv_I8:
return new Conv(Pop(), PrimitiveType.I8, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.I8, false, Sign.None));
case ILOpCode.Conv_R4:
return new Conv(Pop(), PrimitiveType.R4, false, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.R4, false, Sign.Signed));
case ILOpCode.Conv_R8:
return new Conv(Pop(), PrimitiveType.R8, false, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.R8, false, Sign.Signed));
case ILOpCode.Conv_U1:
return new Conv(Pop(), PrimitiveType.U1, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.U1, false, Sign.None));
case ILOpCode.Conv_U2:
return new Conv(Pop(), PrimitiveType.U2, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.U2, false, Sign.None));
case ILOpCode.Conv_U4:
return new Conv(Pop(), PrimitiveType.U4, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.U4, false, Sign.None));
case ILOpCode.Conv_U8:
return new Conv(Pop(), PrimitiveType.U8, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.U8, false, Sign.None));
case ILOpCode.Conv_I:
return new Conv(Pop(), PrimitiveType.I, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.I, false, Sign.None));
case ILOpCode.Conv_U:
return new Conv(Pop(), PrimitiveType.U, false, Sign.None);
return Push(new Conv(Pop(), PrimitiveType.U, false, Sign.None));
case ILOpCode.Conv_R_Un:
return new Conv(Pop(), PrimitiveType.R8, false, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.R8, false, Sign.Unsigned));
case ILOpCode.Conv_Ovf_I1:
return new Conv(Pop(), PrimitiveType.I1, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.I1, true, Sign.Signed));
case ILOpCode.Conv_Ovf_I2:
return new Conv(Pop(), PrimitiveType.I2, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.I2, true, Sign.Signed));
case ILOpCode.Conv_Ovf_I4:
return new Conv(Pop(), PrimitiveType.I4, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.I4, true, Sign.Signed));
case ILOpCode.Conv_Ovf_I8:
return new Conv(Pop(), PrimitiveType.I8, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.I8, true, Sign.Signed));
case ILOpCode.Conv_Ovf_U1:
return new Conv(Pop(), PrimitiveType.U1, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.U1, true, Sign.Signed));
case ILOpCode.Conv_Ovf_U2:
return new Conv(Pop(), PrimitiveType.U2, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.U2, true, Sign.Signed));
case ILOpCode.Conv_Ovf_U4:
return new Conv(Pop(), PrimitiveType.U4, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.U4, true, Sign.Signed));
case ILOpCode.Conv_Ovf_U8:
return new Conv(Pop(), PrimitiveType.U8, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.U8, true, Sign.Signed));
case ILOpCode.Conv_Ovf_I:
return new Conv(Pop(), PrimitiveType.I, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.I, true, Sign.Signed));
case ILOpCode.Conv_Ovf_U:
return new Conv(Pop(), PrimitiveType.U, true, Sign.Signed);
return Push(new Conv(Pop(), PrimitiveType.U, true, Sign.Signed));
case ILOpCode.Conv_Ovf_I1_Un:
return new Conv(Pop(), PrimitiveType.I1, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.I1, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_I2_Un:
return new Conv(Pop(), PrimitiveType.I2, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.I2, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_I4_Un:
return new Conv(Pop(), PrimitiveType.I4, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.I4, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_I8_Un:
return new Conv(Pop(), PrimitiveType.I8, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.I8, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_U1_Un:
return new Conv(Pop(), PrimitiveType.U1, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.U1, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_U2_Un:
return new Conv(Pop(), PrimitiveType.U2, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.U2, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_U4_Un:
return new Conv(Pop(), PrimitiveType.U4, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.U4, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_U8_Un:
return new Conv(Pop(), PrimitiveType.U8, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.U8, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_I_Un:
return new Conv(Pop(), PrimitiveType.I, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.I, true, Sign.Unsigned));
case ILOpCode.Conv_Ovf_U_Un:
return new Conv(Pop(), PrimitiveType.U, true, Sign.Unsigned);
return Push(new Conv(Pop(), PrimitiveType.U, true, Sign.Unsigned));
case ILOpCode.Cpblk:
throw new NotImplementedException();
case ILOpCode.Div:
@ -428,7 +454,7 @@ namespace ICSharpCode.Decompiler.IL @@ -428,7 +454,7 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Div_Un:
return BinaryNumeric(OpCode.Div, false, Sign.Unsigned);
case ILOpCode.Dup:
return new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown);
return Push(Peek());
case ILOpCode.Endfilter:
case ILOpCode.Endfinally:
return new Leave(null);
@ -437,26 +463,26 @@ namespace ICSharpCode.Decompiler.IL @@ -437,26 +463,26 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Jmp:
throw new NotImplementedException();
case ILOpCode.Ldarg:
return Ldarg(reader.ReadUInt16());
return Push(Ldarg(reader.ReadUInt16()));
case ILOpCode.Ldarg_S:
return Ldarg(reader.ReadByte());
return Push(Ldarg(reader.ReadByte()));
case ILOpCode.Ldarg_0:
case ILOpCode.Ldarg_1:
case ILOpCode.Ldarg_2:
case ILOpCode.Ldarg_3:
return Ldarg(ilOpCode - ILOpCode.Ldarg_0);
return Push(Ldarg(ilOpCode - ILOpCode.Ldarg_0));
case ILOpCode.Ldarga:
return Ldarga(reader.ReadUInt16());
return Push(Ldarga(reader.ReadUInt16()));
case ILOpCode.Ldarga_S:
return Ldarga(reader.ReadByte());
return Push(Ldarga(reader.ReadByte()));
case ILOpCode.Ldc_I4:
return new LdcI4(reader.ReadInt32());
return Push(new LdcI4(reader.ReadInt32()));
case ILOpCode.Ldc_I8:
return new LdcI8(reader.ReadInt64());
return Push(new LdcI8(reader.ReadInt64()));
case ILOpCode.Ldc_R4:
return new LdcF(reader.ReadSingle());
return Push(new LdcF(reader.ReadSingle()));
case ILOpCode.Ldc_R8:
return new LdcF(reader.ReadDouble());
return Push(new LdcF(reader.ReadDouble()));
case ILOpCode.Ldc_I4_M1:
case ILOpCode.Ldc_I4_0:
case ILOpCode.Ldc_I4_1:
@ -467,56 +493,56 @@ namespace ICSharpCode.Decompiler.IL @@ -467,56 +493,56 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Ldc_I4_6:
case ILOpCode.Ldc_I4_7:
case ILOpCode.Ldc_I4_8:
return new LdcI4((int)ilOpCode - (int)ILOpCode.Ldc_I4_0);
return Push(new LdcI4((int)ilOpCode - (int)ILOpCode.Ldc_I4_0));
case ILOpCode.Ldc_I4_S:
return new LdcI4(reader.ReadSByte());
return Push(new LdcI4(reader.ReadSByte()));
case ILOpCode.Ldnull:
return new LdNull();
return Push(new LdNull());
case ILOpCode.Ldstr:
return DecodeLdstr();
return Push(DecodeLdstr());
case ILOpCode.Ldftn:
return new LdFtn(ReadAndDecodeMethodReference());
return Push(new LdFtn(ReadAndDecodeMethodReference()));
case ILOpCode.Ldind_I1:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.SByte));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.SByte)));
case ILOpCode.Ldind_I2:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.Int16));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.Int16)));
case ILOpCode.Ldind_I4:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.Int32));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.Int32)));
case ILOpCode.Ldind_I8:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.Int64));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.Int64)));
case ILOpCode.Ldind_U1:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.Byte));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.Byte)));
case ILOpCode.Ldind_U2:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.UInt16));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.UInt16)));
case ILOpCode.Ldind_U4:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.UInt32));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.UInt32)));
case ILOpCode.Ldind_R4:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.Single));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.Single)));
case ILOpCode.Ldind_R8:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.Double));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.Double)));
case ILOpCode.Ldind_I:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.IntPtr));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.IntPtr)));
case ILOpCode.Ldind_Ref:
return new LdObj(Pop(), compilation.FindType(KnownTypeCode.Object));
return Push(new LdObj(Pop(), compilation.FindType(KnownTypeCode.Object)));
case ILOpCode.Ldloc:
return Ldloc(reader.ReadUInt16());
return Push(Ldloc(reader.ReadUInt16()));
case ILOpCode.Ldloc_S:
return Ldloc(reader.ReadByte());
return Push(Ldloc(reader.ReadByte()));
case ILOpCode.Ldloc_0:
case ILOpCode.Ldloc_1:
case ILOpCode.Ldloc_2:
case ILOpCode.Ldloc_3:
return Ldloc(ilOpCode - ILOpCode.Ldloc_0);
return Push(Ldloc(ilOpCode - ILOpCode.Ldloc_0));
case ILOpCode.Ldloca:
return Ldloca(reader.ReadUInt16());
return Push(Ldloca(reader.ReadUInt16()));
case ILOpCode.Ldloca_S:
return Ldloca(reader.ReadByte());
return Push(Ldloca(reader.ReadByte()));
case ILOpCode.Leave:
return DecodeUnconditionalBranch(false, isLeave: true);
case ILOpCode.Leave_S:
return DecodeUnconditionalBranch(true, isLeave: true);
case ILOpCode.Localloc:
return new LocAlloc(Pop());
return Push(new LocAlloc(Pop()));
case ILOpCode.Mul:
return BinaryNumeric(OpCode.Mul, false, Sign.None);
case ILOpCode.Mul_Ovf:
@ -530,11 +556,11 @@ namespace ICSharpCode.Decompiler.IL @@ -530,11 +556,11 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Nop:
return new Nop();
case ILOpCode.Not:
return new BitNot(Pop());
return Push(new BitNot(Pop()));
case ILOpCode.Or:
return BinaryNumeric(OpCode.BitOr);
case ILOpCode.Pop:
return new Void(Pop());
return new Nop();
case ILOpCode.Rem:
return BinaryNumeric(OpCode.Rem, false, Sign.Signed);
case ILOpCode.Rem_Un:
@ -552,21 +578,21 @@ namespace ICSharpCode.Decompiler.IL @@ -552,21 +578,21 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Starg_S:
return Starg(reader.ReadByte());
case ILOpCode.Stind_I1:
return new Void(new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.SByte)));
return new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.SByte));
case ILOpCode.Stind_I2:
return new Void(new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Int16)));
return new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Int16));
case ILOpCode.Stind_I4:
return new Void(new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Int32)));
return new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Int32));
case ILOpCode.Stind_I8:
return new Void(new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Int64)));
return new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Int64));
case ILOpCode.Stind_R4:
return new Void(new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Single)));
return new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Single));
case ILOpCode.Stind_R8:
return new Void(new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Double)));
return new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Double));
case ILOpCode.Stind_I:
return new Void(new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.IntPtr)));
return new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.IntPtr));
case ILOpCode.Stind_Ref:
return new Void(new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Object)));
return new StObj(value: Pop(), target: Pop(), type: compilation.FindType(KnownTypeCode.Object));
case ILOpCode.Stloc:
return Stloc(reader.ReadUInt16());
case ILOpCode.Stloc_S:
@ -587,61 +613,61 @@ namespace ICSharpCode.Decompiler.IL @@ -587,61 +613,61 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Xor:
return BinaryNumeric(OpCode.BitXor);
case ILOpCode.Box:
return new Box(Pop(), ReadAndDecodeTypeReference());
return Push(new Box(Pop(), ReadAndDecodeTypeReference()));
case ILOpCode.Castclass:
return new CastClass(Pop(), ReadAndDecodeTypeReference());
return Push(new CastClass(Pop(), ReadAndDecodeTypeReference()));
case ILOpCode.Cpobj:
{
var type = ReadAndDecodeTypeReference();
var ld = new LdObj(Pop(), type);
return new Void(new StObj(Pop(), ld, type));
return new StObj(Pop(), ld, type);
}
case ILOpCode.Initobj:
return InitObj(Pop(), ReadAndDecodeTypeReference());
return Push(InitObj(Pop(), ReadAndDecodeTypeReference()));
case ILOpCode.Isinst:
return new IsInst(Pop(), ReadAndDecodeTypeReference());
return Push(new IsInst(Pop(), ReadAndDecodeTypeReference()));
case ILOpCode.Ldelem:
return LdElem(index: Pop(), array: Pop(), type: ReadAndDecodeTypeReference());
return LdElem(ReadAndDecodeTypeReference());
case ILOpCode.Ldelem_I1:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.SByte));
return LdElem(compilation.FindType(KnownTypeCode.SByte));
case ILOpCode.Ldelem_I2:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int16));
return LdElem(compilation.FindType(KnownTypeCode.Int16));
case ILOpCode.Ldelem_I4:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int32));
return LdElem(compilation.FindType(KnownTypeCode.Int32));
case ILOpCode.Ldelem_I8:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int64));
return LdElem(compilation.FindType(KnownTypeCode.Int64));
case ILOpCode.Ldelem_U1:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Byte));
return LdElem(compilation.FindType(KnownTypeCode.Byte));
case ILOpCode.Ldelem_U2:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.UInt16));
return LdElem(compilation.FindType(KnownTypeCode.UInt16));
case ILOpCode.Ldelem_U4:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.UInt32));
return LdElem(compilation.FindType(KnownTypeCode.UInt32));
case ILOpCode.Ldelem_R4:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Single));
return LdElem(compilation.FindType(KnownTypeCode.Single));
case ILOpCode.Ldelem_R8:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Double));
return LdElem(compilation.FindType(KnownTypeCode.Double));
case ILOpCode.Ldelem_I:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.IntPtr));
return LdElem(compilation.FindType(KnownTypeCode.IntPtr));
case ILOpCode.Ldelem_Ref:
return LdElem(index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Object));
return LdElem(compilation.FindType(KnownTypeCode.Object));
case ILOpCode.Ldelema:
return new LdElema(index: Pop(), array: Pop(), type: ReadAndDecodeTypeReference());
return Push(new LdElema(index: Pop(), array: Pop(), type: ReadAndDecodeTypeReference()));
case ILOpCode.Ldfld:
return new LdFld(Pop(), ReadAndDecodeFieldReference());
return Push(new LdFld(Pop(), ReadAndDecodeFieldReference()));
case ILOpCode.Ldflda:
return new LdFlda(Pop(), ReadAndDecodeFieldReference());
return Push(new LdFlda(Pop(), ReadAndDecodeFieldReference()));
case ILOpCode.Stfld:
return new Void(new StFld(value: Pop(), target: Pop(), field: ReadAndDecodeFieldReference()));
return new StFld(value: Pop(), target: Pop(), field: ReadAndDecodeFieldReference());
case ILOpCode.Ldlen:
return new LdLen(Pop());
return Push(new LdLen(Pop()));
case ILOpCode.Ldobj:
return new LdObj(Pop(), ReadAndDecodeTypeReference());
return Push(new LdObj(Pop(), ReadAndDecodeTypeReference()));
case ILOpCode.Ldsfld:
return new LdsFld(ReadAndDecodeFieldReference());
return Push(new LdsFld(ReadAndDecodeFieldReference()));
case ILOpCode.Ldsflda:
return new LdsFlda(ReadAndDecodeFieldReference());
return Push(new LdsFlda(ReadAndDecodeFieldReference()));
case ILOpCode.Stsfld:
return new Void(new StsFld(Pop(), ReadAndDecodeFieldReference()));
return new StsFld(Pop(), ReadAndDecodeFieldReference());
case ILOpCode.Ldtoken:
var memberReference = ReadAndDecodeMetadataToken() as MemberReference;
if (memberReference is TypeReference)
@ -652,11 +678,11 @@ namespace ICSharpCode.Decompiler.IL @@ -652,11 +678,11 @@ namespace ICSharpCode.Decompiler.IL
return new LdMemberToken(typeSystem.Resolve((MethodReference)memberReference));
throw new NotImplementedException();
case ILOpCode.Ldvirtftn:
return new LdVirtFtn(Pop(), ReadAndDecodeMethodReference());
return Push(new LdVirtFtn(Pop(), ReadAndDecodeMethodReference()));
case ILOpCode.Mkrefany:
throw new NotImplementedException();
case ILOpCode.Newarr:
return new NewArr(ReadAndDecodeTypeReference(), Pop());
return Push(new NewArr(ReadAndDecodeTypeReference(), Pop()));
case ILOpCode.Refanytype:
throw new NotImplementedException();
case ILOpCode.Refanyval:
@ -666,46 +692,113 @@ namespace ICSharpCode.Decompiler.IL @@ -666,46 +692,113 @@ namespace ICSharpCode.Decompiler.IL
case ILOpCode.Sizeof:
return new SizeOf(ReadAndDecodeTypeReference());
case ILOpCode.Stelem:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: ReadAndDecodeTypeReference());
return StElem(ReadAndDecodeTypeReference());
case ILOpCode.Stelem_I1:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.SByte));
return StElem(compilation.FindType(KnownTypeCode.SByte));
case ILOpCode.Stelem_I2:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int16));
return StElem(compilation.FindType(KnownTypeCode.Int16));
case ILOpCode.Stelem_I4:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int32));
return StElem(compilation.FindType(KnownTypeCode.Int32));
case ILOpCode.Stelem_I8:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Int64));
return StElem(compilation.FindType(KnownTypeCode.Int64));
case ILOpCode.Stelem_R4:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Single));
return StElem(compilation.FindType(KnownTypeCode.Single));
case ILOpCode.Stelem_R8:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Double));
return StElem(compilation.FindType(KnownTypeCode.Double));
case ILOpCode.Stelem_I:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.IntPtr));
return StElem(compilation.FindType(KnownTypeCode.IntPtr));
case ILOpCode.Stelem_Ref:
return StElem(value: Pop(), index: Pop(), array: Pop(), type: compilation.FindType(KnownTypeCode.Object));
return StElem(compilation.FindType(KnownTypeCode.Object));
case ILOpCode.Stobj:
return new Void(new StObj(value: Pop(), target: Pop(), type: ReadAndDecodeTypeReference()));
return new StObj(value: Pop(), target: Pop(), type: ReadAndDecodeTypeReference());
case ILOpCode.Throw:
return new Throw(Pop());
case ILOpCode.Unbox:
return new Unbox(Pop(), ReadAndDecodeTypeReference());
return Push(new Unbox(Pop(), ReadAndDecodeTypeReference()));
case ILOpCode.Unbox_Any:
return new UnboxAny(Pop(), ReadAndDecodeTypeReference());
return Push(new UnboxAny(Pop(), ReadAndDecodeTypeReference()));
default:
throw new NotImplementedException(ilOpCode.ToString());
}
}
private IL.Pop Pop()
StackType PeekStackType()
{
if (stack.Count > 0) {
return new IL.Pop(stack.Pop());
} else {
Warn("Stack underflow");
return new IL.Pop(StackType.Unknown);
}
if (currentStack.IsEmpty)
return StackType.Unknown;
else
return currentStack.Peek().StackType;
}
class CollectStackVariablesVisitor : ILVisitor<ILInstruction>
{
readonly UnionFind<ILVariable> unionFind;
internal readonly HashSet<ILVariable> variables = new HashSet<ILVariable>();
public CollectStackVariablesVisitor(UnionFind<ILVariable> unionFind)
{
Debug.Assert(unionFind != null);
this.unionFind = unionFind;
}
protected override ILInstruction Default(ILInstruction inst)
{
foreach (var child in inst.Children) {
var newChild = child.AcceptVisitor(this);
if (newChild != child)
child.ReplaceWith(newChild);
}
return inst;
}
protected internal override ILInstruction VisitLdLoc(LdLoc inst)
{
base.VisitLdLoc(inst);
if (inst.Variable.Kind == VariableKind.StackSlot) {
var variable = unionFind.Find(inst.Variable);
if (variables.Add(variable))
variable.Name = "S_" + (variables.Count - 1);
return new LdLoc(variable) { ILRange = inst.ILRange };
}
return inst;
}
protected internal override ILInstruction VisitStLoc(StLoc inst)
{
base.VisitStLoc(inst);
if (inst.Variable.Kind == VariableKind.StackSlot) {
var variable = unionFind.Find(inst.Variable);
if (variables.Add(variable))
variable.Name = "S_" + (variables.Count - 1);
return new StLoc(variable, inst.Value) { ILRange = inst.ILRange };
}
return inst;
}
}
ILInstruction Push(ILInstruction inst)
{
Debug.Assert(inst.ResultType != StackType.Void);
var v = new ILVariable(VariableKind.StackSlot, inst.ResultType, inst.ILRange.Start);
v.Name = "S_" + inst.ILRange.Start.ToString("x4");
currentStack = currentStack.Push(v);
return new StLoc(v, inst);
}
IL.LdLoc Peek()
{
// TODO: handle stack underflow?
return new LdLoc(currentStack.Peek());
}
IL.LdLoc Pop()
{
// TODO: handle stack underflow?
ILVariable v;
currentStack = currentStack.Pop(out v);
return new LdLoc(v);
}
private ILInstruction Return()
{
@ -733,7 +826,7 @@ namespace ICSharpCode.Decompiler.IL @@ -733,7 +826,7 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction Starg(ushort v)
{
return new Void(new StLoc(parameterVariables[v], Pop()));
return new StLoc(parameterVariables[v], Pop());
}
private ILInstruction Ldloc(ushort v)
@ -748,17 +841,20 @@ namespace ICSharpCode.Decompiler.IL @@ -748,17 +841,20 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction Stloc(ushort v)
{
return new Void(new StLoc(localVariables[v], Pop()));
return new StLoc(localVariables[v], Pop());
}
private ILInstruction LdElem(ILInstruction array, ILInstruction index, IType type)
private ILInstruction LdElem(IType type)
{
return new LdObj(new LdElema(array, index, type), type);
return Push(new LdObj(new LdElema(index: Pop(), array: Pop(), type: type), type));
}
private ILInstruction StElem(ILInstruction array, ILInstruction index, ILInstruction value, IType type)
private ILInstruction StElem(IType type)
{
return new Void(new StObj(new LdElema(array, index, type), value, type));
var value = Pop();
var index = Pop();
var array = Pop();
return new StObj(new LdElema(array, index, type), value, type);
}
ILInstruction InitObj(ILInstruction target, IType type)
@ -789,7 +885,7 @@ namespace ICSharpCode.Decompiler.IL @@ -789,7 +885,7 @@ namespace ICSharpCode.Decompiler.IL
{
byte alignment = reader.ReadByte();
var inst = DecodeInstruction();
var sup = UnpackVoid(inst) as ISupportsUnalignedPrefix;
var sup = inst as ISupportsUnalignedPrefix;
if (sup != null)
sup.UnalignedPrefix = alignment;
else
@ -800,7 +896,7 @@ namespace ICSharpCode.Decompiler.IL @@ -800,7 +896,7 @@ namespace ICSharpCode.Decompiler.IL
private ILInstruction DecodeVolatile()
{
var inst = DecodeInstruction();
var svp = UnpackVoid(inst) as ISupportsVolatilePrefix;
var svp = inst as ISupportsVolatilePrefix;
if (svp != null)
svp.IsVolatile = true;
else
@ -808,12 +904,6 @@ namespace ICSharpCode.Decompiler.IL @@ -808,12 +904,6 @@ namespace ICSharpCode.Decompiler.IL
return inst;
}
ILInstruction UnpackVoid(ILInstruction inst)
{
Void v = inst as Void;
return v != null ? v.Argument : inst;
}
private ILInstruction DecodeReadonly()
{
var inst = DecodeInstruction();
@ -834,7 +924,10 @@ namespace ICSharpCode.Decompiler.IL @@ -834,7 +924,10 @@ namespace ICSharpCode.Decompiler.IL
}
var call = CallInstruction.Create(opCode, method);
call.Arguments.AddRange(arguments);
return call;
if (call.ResultType != StackType.Void)
return Push(call);
else
return call;
}
static int GetPopCount(OpCode callCode, MethodReference methodReference)
@ -858,10 +951,12 @@ namespace ICSharpCode.Decompiler.IL @@ -858,10 +951,12 @@ namespace ICSharpCode.Decompiler.IL
var right = Pop();
var left = Pop();
// Based on Table 4: Binary Comparison or Branch Operation
OpCode opCode;
if (left.ResultType == StackType.F && right.ResultType == StackType.F)
return BinaryComparisonInstruction.Create(opCode_F, left, right);
opCode = opCode_F;
else
return BinaryComparisonInstruction.Create(opCode_I, left, right);
opCode = opCode_I;
return BinaryComparisonInstruction.Create(opCode, left, right);
}
ILInstruction DecodeComparisonBranch(bool shortForm, OpCode comparisonOpCodeForInts, OpCode comparisonOpCodeForFloats, bool negate)
@ -911,21 +1006,17 @@ namespace ICSharpCode.Decompiler.IL @@ -911,21 +1006,17 @@ namespace ICSharpCode.Decompiler.IL
{
int target = shortForm ? reader.ReadSByte() : reader.ReadInt32();
target += reader.Position;
int popCount = 0;
if (isLeave) {
popCount = stack.Count;
stack.Clear();
currentStack = currentStack.Clear();
}
MarkBranchTarget(target);
return new Branch(target) { PopCount = popCount };
return new Branch(target);
}
void MarkBranchTarget(int targetILOffset)
{
isBranchTarget[targetILOffset] = true;
if (targetILOffset >= reader.Position) {
branchStackDict[targetILOffset] = stack.ToImmutableArray();
}
StoreStackForOffset(targetILOffset, currentStack);
}
ILInstruction DecodeSwitch()
@ -950,7 +1041,7 @@ namespace ICSharpCode.Decompiler.IL @@ -950,7 +1041,7 @@ namespace ICSharpCode.Decompiler.IL
{
var right = Pop();
var left = Pop();
return BinaryNumericInstruction.Create(opCode, left, right, checkForOverflow, sign);
return Push(BinaryNumericInstruction.Create(opCode, left, right, checkForOverflow, sign));
}
}
}

24
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -17,14 +17,8 @@ @@ -17,14 +17,8 @@
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.NRefactory.TypeSystem;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.Disassembler;
namespace ICSharpCode.Decompiler.IL
{
@ -53,6 +47,7 @@ namespace ICSharpCode.Decompiler.IL @@ -53,6 +47,7 @@ namespace ICSharpCode.Decompiler.IL
{
public readonly VariableKind Kind;
public readonly IType Type;
public readonly StackType StackType;
/// <summary>
/// The index of the local variable or parameter (depending on Kind)
@ -84,6 +79,12 @@ namespace ICSharpCode.Decompiler.IL @@ -84,6 +79,12 @@ namespace ICSharpCode.Decompiler.IL
/// This variable is automatically updated when adding/removing ldloca instructions from the ILAst.
/// </remarks>
public int AddressCount;
public bool IsSingleUse {
get {
return LoadCount == 1 && StoreCount == 1 && AddressCount == 0;
}
}
public ILVariable(VariableKind kind, IType type, int index)
{
@ -91,6 +92,17 @@ namespace ICSharpCode.Decompiler.IL @@ -91,6 +92,17 @@ namespace ICSharpCode.Decompiler.IL
throw new ArgumentNullException("type");
this.Kind = kind;
this.Type = type;
this.StackType = type.GetStackType();
this.Index = index;
}
public ILVariable(VariableKind kind, StackType type, int index)
{
if (type == null)
throw new ArgumentNullException("type");
this.Kind = kind;
this.Type = SpecialType.UnknownType;
this.StackType = type;
this.Index = index;
}

170
ICSharpCode.Decompiler/IL/Instructions.cs

@ -30,12 +30,6 @@ namespace ICSharpCode.Decompiler.IL @@ -30,12 +30,6 @@ namespace ICSharpCode.Decompiler.IL
{
/// <summary>No operation. Takes 0 arguments and returns void.</summary>
Nop,
/// <summary>Pops the top of the evaluation stack and returns the value.</summary>
Pop,
/// <summary>Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.</summary>
Peek,
/// <summary>Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.</summary>
Void,
/// <summary>A container of IL blocks.</summary>
ILFunction,
/// <summary>A container of IL blocks.</summary>
@ -227,10 +221,6 @@ namespace ICSharpCode.Decompiler.IL @@ -227,10 +221,6 @@ namespace ICSharpCode.Decompiler.IL
this.Argument = this.argument.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Argument.TransformStackIntoVariables(state);
}
protected override InstructionFlags ComputeFlags()
{
return argument.Flags;
@ -309,11 +299,6 @@ namespace ICSharpCode.Decompiler.IL @@ -309,11 +299,6 @@ namespace ICSharpCode.Decompiler.IL
this.Left = this.left.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Left.TransformStackIntoVariables(state);
Right.TransformStackIntoVariables(state);
}
protected override InstructionFlags ComputeFlags()
{
return left.Flags | right.Flags;
@ -346,61 +331,6 @@ namespace ICSharpCode.Decompiler.IL @@ -346,61 +331,6 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>Pops the top of the evaluation stack and returns the value.</summary>
public sealed partial class Pop : SimpleInstruction
{
public Pop(StackType resultType) : base(OpCode.Pop)
{
this.resultType = resultType;
}
StackType resultType;
public override StackType ResultType { get { return resultType; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitPop(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitPop(this);
}
}
/// <summary>Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.</summary>
public sealed partial class Peek : SimpleInstruction
{
public Peek(StackType resultType) : base(OpCode.Peek)
{
this.resultType = resultType;
}
StackType resultType;
public override StackType ResultType { get { return resultType; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitPeek(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitPeek(this);
}
}
/// <summary>Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.</summary>
public sealed partial class Void : UnaryInstruction
{
public Void(ILInstruction argument) : base(OpCode.Void, argument)
{
}
public override StackType ResultType { get { return StackType.Void; } }
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitVoid(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitVoid(this);
}
}
/// <summary>A container of IL blocks.</summary>
public sealed partial class ILFunction : ILInstruction
{
@ -1148,7 +1078,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1148,7 +1078,7 @@ namespace ICSharpCode.Decompiler.IL
readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } }
public override StackType ResultType { get { return variable.Type.GetStackType(); } }
public override StackType ResultType { get { return variable.StackType; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
@ -1247,11 +1177,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1247,11 +1177,7 @@ namespace ICSharpCode.Decompiler.IL
this.Value = this.value.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Value.TransformStackIntoVariables(state);
}
public override StackType ResultType { get { return variable.Type.GetStackType(); } }
public override StackType ResultType { get { return variable.StackType; } }
protected override InstructionFlags ComputeFlags()
{
return value.Flags;
@ -1626,10 +1552,6 @@ namespace ICSharpCode.Decompiler.IL @@ -1626,10 +1552,6 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -1715,10 +1637,6 @@ namespace ICSharpCode.Decompiler.IL @@ -1715,10 +1637,6 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
readonly IField field;
/// <summary>Returns the field operand.</summary>
public IField Field { get { return field; } }
@ -1812,11 +1730,6 @@ namespace ICSharpCode.Decompiler.IL @@ -1812,11 +1730,6 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
Value.TransformStackIntoVariables(state);
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -1970,10 +1883,6 @@ namespace ICSharpCode.Decompiler.IL @@ -1970,10 +1883,6 @@ namespace ICSharpCode.Decompiler.IL
this.Value = this.value.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Value.TransformStackIntoVariables(state);
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -2123,10 +2032,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2123,10 +2032,6 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
readonly IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
@ -2228,11 +2133,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2228,11 +2133,6 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
Value.TransformStackIntoVariables(state);
}
readonly IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
@ -2442,10 +2342,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2442,10 +2342,6 @@ namespace ICSharpCode.Decompiler.IL
this.Size = this.size.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Size.TransformStackIntoVariables(state);
}
public override StackType ResultType { get { return StackType.O; } }
protected override InstructionFlags ComputeFlags()
{
@ -2615,10 +2511,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2615,10 +2511,6 @@ namespace ICSharpCode.Decompiler.IL
this.Array = this.array.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Array.TransformStackIntoVariables(state);
}
public override StackType ResultType { get { return StackType.I; } }
protected override InstructionFlags ComputeFlags()
{
@ -2707,11 +2599,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2707,11 +2599,6 @@ namespace ICSharpCode.Decompiler.IL
this.Array = this.array.Inline(flagsBefore, context);
return this;
}
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Array.TransformStackIntoVariables(state);
Index.TransformStackIntoVariables(state);
}
readonly IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
@ -2758,18 +2645,6 @@ namespace ICSharpCode.Decompiler.IL @@ -2758,18 +2645,6 @@ namespace ICSharpCode.Decompiler.IL
{
Default(inst);
}
protected internal virtual void VisitPop(Pop inst)
{
Default(inst);
}
protected internal virtual void VisitPeek(Peek inst)
{
Default(inst);
}
protected internal virtual void VisitVoid(Void inst)
{
Default(inst);
}
protected internal virtual void VisitILFunction(ILFunction function)
{
Default(function);
@ -3064,18 +2939,6 @@ namespace ICSharpCode.Decompiler.IL @@ -3064,18 +2939,6 @@ namespace ICSharpCode.Decompiler.IL
{
return Default(inst);
}
protected internal virtual T VisitPop(Pop inst)
{
return Default(inst);
}
protected internal virtual T VisitPeek(Peek inst)
{
return Default(inst);
}
protected internal virtual T VisitVoid(Void inst)
{
return Default(inst);
}
protected internal virtual T VisitILFunction(ILFunction function)
{
return Default(function);
@ -3414,9 +3277,6 @@ namespace ICSharpCode.Decompiler.IL @@ -3414,9 +3277,6 @@ namespace ICSharpCode.Decompiler.IL
{
static readonly string[] originalOpCodeNames = {
"nop",
"pop",
"peek",
"void",
"ILFunction",
"BlockContainer",
"Block",
@ -3500,32 +3360,6 @@ namespace ICSharpCode.Decompiler.IL @@ -3500,32 +3360,6 @@ namespace ICSharpCode.Decompiler.IL
}
return false;
}
public bool MatchPop()
{
var inst = this as Pop;
if (inst != null) {
return true;
}
return false;
}
public bool MatchPeek()
{
var inst = this as Peek;
if (inst != null) {
return true;
}
return false;
}
public bool MatchVoid(out ILInstruction argument)
{
var inst = this as Void;
if (inst != null) {
argument = inst.Argument;
return true;
}
argument = default(ILInstruction);
return false;
}
public bool MatchLogicNot(out ILInstruction argument)
{
var inst = this as LogicNot;

19
ICSharpCode.Decompiler/IL/Instructions.tt

@ -33,12 +33,6 @@ @@ -33,12 +33,6 @@
OpCode[] opCodes = {
new OpCode("nop", "No operation. Takes 0 arguments and returns void.",
VoidResult, NoArguments),
new OpCode("pop", "Pops the top of the evaluation stack and returns the value.",
NoArguments, ResultTypeParam),
new OpCode("peek", "Peeks at the top of the evaluation stack and returns the value. Corresponds to IL 'dup'.",
NoArguments, ResultTypeParam),
new OpCode("void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.",
VoidResult, Unary),
new OpCode("ILFunction", "A container of IL blocks.",
CustomChildren(new [] {
new ChildInfo("body")
@ -106,12 +100,12 @@ @@ -106,12 +100,12 @@
new OpCode("conv", "Numeric cast.",
Unary, CustomConstructor),
new OpCode("ldloc", "Loads the value of a local variable. (ldarg/ldloc)",
CustomClassName("LdLoc"), NoArguments, HasVariableOperand, ResultType("variable.Type.GetStackType()")),
CustomClassName("LdLoc"), NoArguments, HasVariableOperand, ResultType("variable.StackType")),
new OpCode("ldloca", "Loads the address of a local variable. (ldarga/ldloca)",
CustomClassName("LdLoca"), NoArguments, ResultType("Ref"), HasVariableOperand),
new OpCode("stloc", "Stores a value into a local variable. (starg/stloc)",
CustomClassName("StLoc"), HasVariableOperand, CustomArguments("value"),
ResultType("variable.Type.GetStackType()")),
ResultType("variable.StackType")),
new OpCode("ldstr", "Loads a constant string.",
CustomClassName("LdStr"), LoadConstant("string"), ResultType("O")),
new OpCode("ldc.i4", "Loads a constant 32-bit integer.",
@ -670,15 +664,6 @@ namespace ICSharpCode.Decompiler.IL @@ -670,15 +664,6 @@ namespace ICSharpCode.Decompiler.IL
b.AppendLine("\treturn this;");
b.Append("}");
opCode.Members.Add(b.ToString());
b.Clear();
b.AppendLine("internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)");
b.AppendLine("{");
for (int i = 0; i < children.Length; i++) {
string arg = children[i].Name;
b.AppendLine("\t" + MakeName(arg) + ".TransformStackIntoVariables(state);");
}
b.Append("}");
opCode.Members.Add(b.ToString());
}
};
}

27
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -187,15 +187,9 @@ namespace ICSharpCode.Decompiler.IL @@ -187,15 +187,9 @@ namespace ICSharpCode.Decompiler.IL
/// The MayPop and MayPeek flags are removed and converted into
/// MayReadEvaluationStack and/or MayWriteEvaluationStack flags.
/// </summary>
[Obsolete("there's not phase-1 evaluation anymore")]
internal static InstructionFlags Phase1Boundary(InstructionFlags flags)
{
// Convert phase-1 flags to phase-2 flags
if ((flags & InstructionFlags.MayPop) != 0)
flags |= InstructionFlags.MayWriteEvaluationStack;
if ((flags & (InstructionFlags.MayPeek | InstructionFlags.MayPop)) != 0)
flags |= InstructionFlags.MayReadEvaluationStack;
// an inline block has no phase-1 effects
flags &= ~(InstructionFlags.MayPeek | InstructionFlags.MayPop);
return flags;
}
@ -204,24 +198,5 @@ namespace ICSharpCode.Decompiler.IL @@ -204,24 +198,5 @@ namespace ICSharpCode.Decompiler.IL
// an inline block has no phase-1 effects, so we're immediately done with inlining
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
for (int i = 0; i < Instructions.Count; i++) {
var inst = Instructions[i].Inline(InstructionFlags.None, state);
inst.TransformStackIntoVariables(state);
if (inst.ResultType != StackType.Void) {
var type = state.TypeSystem.Compilation.FindType(inst.ResultType.ToKnownTypeCode());
ILVariable variable = new ILVariable(VariableKind.StackSlot, type, state.Variables.Count);
state.Variables.Push(variable);
inst = new Void(new StLoc(variable, inst));
}
Instructions[i] = inst;
if (inst.HasFlag(InstructionFlags.EndPointUnreachable))
return;
}
FinalInstruction = FinalInstruction.Inline(InstructionFlags.None, state);
FinalInstruction.TransformStackIntoVariables(state);
}
}
}

10
ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs

@ -160,16 +160,6 @@ namespace ICSharpCode.Decompiler.IL @@ -160,16 +160,6 @@ namespace ICSharpCode.Decompiler.IL
// Blocks are phase-1 boundaries
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
EntryPoint.TransformStackIntoVariables(state);
ImmutableArray<ILVariable> variables;
if (state.FinalVariables.TryGetValue(this, out variables))
state.Variables = variables.ToStack();
else
state.Variables.Clear();
}
}
}

32
ICSharpCode.Decompiler/IL/Instructions/Branch.cs

@ -41,11 +41,6 @@ namespace ICSharpCode.Decompiler.IL @@ -41,11 +41,6 @@ namespace ICSharpCode.Decompiler.IL
readonly int targetILOffset;
Block targetBlock;
/// <summary>
/// Pops the specified number of arguments from the evaluation stack during the branching operation.
/// </summary>
public int PopCount;
public Branch(int targetILOffset) : base(OpCode.Branch)
{
this.targetILOffset = targetILOffset;
@ -61,12 +56,7 @@ namespace ICSharpCode.Decompiler.IL @@ -61,12 +56,7 @@ namespace ICSharpCode.Decompiler.IL
protected override InstructionFlags ComputeFlags()
{
var flags = InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
if (PopCount > 0) {
// the branch pop happens during phase-2, so don't use MayPop
flags |= InstructionFlags.MayWriteEvaluationStack;
}
return flags;
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
public int TargetILOffset {
@ -116,26 +106,6 @@ namespace ICSharpCode.Decompiler.IL @@ -116,26 +106,6 @@ namespace ICSharpCode.Decompiler.IL
output.Write(OpCode);
output.Write(' ');
output.WriteReference(TargetLabel, (object)targetBlock ?? TargetILOffset, isLocal: true);
if (PopCount != 0) {
output.Write(" (pops ");
output.Write(PopCount.ToString());
output.Write(" element)");
}
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
ImmutableArray<ILVariable> initialVariables;
if (!state.InitialVariables.TryGetValue(targetBlock, out initialVariables)) {
initialVariables = state.Variables.ToImmutableArray();
state.InitialVariables.Add(targetBlock, initialVariables);
targetBlock.TransformStackIntoVariables(state);
} else {
state.MergeVariables(state.Variables, initialVariables.ToStack());
}
// No one is supposed to use the variable stack after an unconditional branch,
// but let's clear it just to be safe.
state.Variables.Clear();
}
}
}

7
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -138,12 +138,5 @@ namespace ICSharpCode.Decompiler.IL @@ -138,12 +138,5 @@ namespace ICSharpCode.Decompiler.IL
}
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
for (int i = 0; i < Arguments.Count; i++) {
Arguments[i].TransformStackIntoVariables(state);
}
}
}
}

8
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -68,13 +68,5 @@ namespace ICSharpCode.Decompiler.IL @@ -68,13 +68,5 @@ namespace ICSharpCode.Decompiler.IL
// To the outside, lambda creation looks like a constant
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
var oldStack = state.Variables;
state.Variables = new Stack<ILVariable>();
Body.TransformStackIntoVariables(state);
state.Variables = oldStack;
}
}
}

5
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -344,11 +344,6 @@ namespace ICSharpCode.Decompiler.IL @@ -344,11 +344,6 @@ namespace ICSharpCode.Decompiler.IL
/// </remarks>
internal abstract ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context);
/// <summary>
/// Transforms the evaluation stack 'pop' and 'peek' instructions into local copy.
/// </summary>
internal abstract void TransformStackIntoVariables(TransformStackIntoVariablesState state);
/// <summary>
/// Number of parents that refer to this instruction and are connected to the root.
/// Usually is 0 for unconnected nodes and 1 for connected nodes, but may temporarily increase to 2

21
ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs

@ -58,27 +58,6 @@ namespace ICSharpCode.Decompiler.IL @@ -58,27 +58,6 @@ namespace ICSharpCode.Decompiler.IL
// note: we skip TrueInst and FalseInst because there's a phase-1-boundary around them
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Condition.TransformStackIntoVariables(state);
var stackAfterCondition = state.Variables.Clone();
TrueInst = TrueInst.Inline(InstructionFlags.None, state);
TrueInst.TransformStackIntoVariables(state);
var afterTrue = state.Variables.Clone();
state.Variables = stackAfterCondition;
FalseInst = FalseInst.Inline(InstructionFlags.None, state);
FalseInst.TransformStackIntoVariables(state);
if (!TrueInst.HasFlag(InstructionFlags.EndPointUnreachable) && !FalseInst.HasFlag(InstructionFlags.EndPointUnreachable)) {
// If end-points of both instructions are reachable, merge their states
state.MergeVariables(state.Variables, afterTrue);
}
if (FalseInst.HasFlag(InstructionFlags.EndPointUnreachable)) {
// If the end-point of FalseInst is unreachable, continue with the end-state of TrueInst instead
// (if both are unreachable, it doesn't matter what we continue with)
state.Variables = afterTrue;
}
}
protected override InstructionFlags ComputeFlags()
{

28
ICSharpCode.Decompiler/IL/Instructions/Leave.cs

@ -40,11 +40,6 @@ namespace ICSharpCode.Decompiler.IL @@ -40,11 +40,6 @@ namespace ICSharpCode.Decompiler.IL
{
BlockContainer targetContainer;
/// <summary>
/// Pops the specified number of arguments from the evaluation stack during the branching operation.
/// </summary>
public int PopCount;
public Leave(BlockContainer targetContainer) : base(OpCode.Leave)
{
// Note: ILReader will create Leave instructions with targetContainer==null to represent 'endfinally',
@ -54,12 +49,7 @@ namespace ICSharpCode.Decompiler.IL @@ -54,12 +49,7 @@ namespace ICSharpCode.Decompiler.IL
protected override InstructionFlags ComputeFlags()
{
var flags = InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
if (PopCount > 0) {
// the branch pop happens during phase-2, so don't use MayPop
flags |= InstructionFlags.MayWriteEvaluationStack;
}
return flags;
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
}
public BlockContainer TargetContainer {
@ -104,22 +94,6 @@ namespace ICSharpCode.Decompiler.IL @@ -104,22 +94,6 @@ namespace ICSharpCode.Decompiler.IL
output.Write(' ');
output.WriteReference(TargetLabel, targetContainer, isLocal: true);
}
if (PopCount != 0) {
output.Write(" (pops ");
output.Write(PopCount.ToString());
output.Write(" element)");
}
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
ImmutableArray<ILVariable> variables;
if (state.FinalVariables.TryGetValue(targetContainer, out variables)) {
state.MergeVariables(state.Variables, variables.ToStack());
} else {
state.FinalVariables.Add(targetContainer, state.Variables.ToImmutableArray());
}
state.Variables.Clear();
}
}
}

24
ICSharpCode.Decompiler/IL/Instructions/PatternMatching.cs

@ -38,5 +38,29 @@ namespace ICSharpCode.Decompiler.IL @@ -38,5 +38,29 @@ namespace ICSharpCode.Decompiler.IL
var inst = this as LdLoc;
return inst != null && inst.Variable.Kind == VariableKind.This;
}
public bool MatchStLoc(ILVariable variable, out ILInstruction value)
{
var inst = this as StLoc;
if (inst != null && inst.Variable == variable) {
value = inst.Value;
return true;
}
value = null;
return false;
}
public bool MatchStLoc(out ILVariable variable, out ILInstruction value)
{
var inst = this as StLoc;
if (inst != null) {
variable = inst.Variable;
value = inst.Value;
return true;
}
variable = null;
value = null;
return false;
}
}
}

7
ICSharpCode.Decompiler/IL/Instructions/Return.cs

@ -101,12 +101,5 @@ namespace ICSharpCode.Decompiler.IL @@ -101,12 +101,5 @@ namespace ICSharpCode.Decompiler.IL
this.ReturnValue = returnValue.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
if (returnValue != null)
ReturnValue.TransformStackIntoVariables(state);
state.Variables.Clear();
}
}
}

30
ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs

@ -69,35 +69,5 @@ namespace ICSharpCode.Decompiler.IL @@ -69,35 +69,5 @@ namespace ICSharpCode.Decompiler.IL
// Nothing to do, since we don't have arguments.
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
}
}
partial class Pop
{
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayPop;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
return context.Pop(flagsBefore) ?? this;
}
}
partial class Peek
{
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.MayPeek;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
return context.Peek(flagsBefore) ?? this;
}
}
}

20
ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs

@ -93,21 +93,6 @@ namespace ICSharpCode.Decompiler.IL @@ -93,21 +93,6 @@ namespace ICSharpCode.Decompiler.IL
Sections[index - 1] = (SwitchSection)value;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Value.TransformStackIntoVariables(state);
var stateAfterExpression = state.Variables.Clone();
for (int i = 0; i < Sections.Count; i++) {
state.Variables = stateAfterExpression.Clone();
Sections[i] = (SwitchSection)Sections[i].Inline(InstructionFlags.None, state);
Sections[i].TransformStackIntoVariables(state);
if (!Sections[i].HasFlag(InstructionFlags.EndPointUnreachable)) {
state.MergeVariables(state.Variables, stateAfterExpression);
}
}
state.Variables = stateAfterExpression;
}
public override ILInstruction Clone()
{
var clone = new SwitchInstruction(value.Clone());
@ -149,10 +134,5 @@ namespace ICSharpCode.Decompiler.IL @@ -149,10 +134,5 @@ namespace ICSharpCode.Decompiler.IL
body.WriteTo(output);
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
body.TransformStackIntoVariables(state);
}
}
}

57
ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs

@ -115,23 +115,6 @@ namespace ICSharpCode.Decompiler.IL @@ -115,23 +115,6 @@ namespace ICSharpCode.Decompiler.IL
else
Handlers[index - 1] = (TryCatchHandler)value;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
TryBlock = TryBlock.Inline(InstructionFlags.None, state);
TryBlock.TransformStackIntoVariables(state);
Stack<ILVariable> variablesAfter = TryBlock.HasFlag(InstructionFlags.EndPointUnreachable) ? null : state.Variables.Clone();
for (int i = 0; i < Handlers.Count; i++) {
Handlers[i].TransformStackIntoVariables(state);
if (!Handlers[i].HasFlag(InstructionFlags.EndPointUnreachable)) {
if (variablesAfter == null)
variablesAfter = state.Variables.Clone();
else
state.MergeVariables(variablesAfter, state.Variables);
}
}
state.Variables = variablesAfter ?? new Stack<ILVariable>();
}
}
/// <summary>
@ -170,16 +153,6 @@ namespace ICSharpCode.Decompiler.IL @@ -170,16 +153,6 @@ namespace ICSharpCode.Decompiler.IL
return Block.Phase1Boundary(filter.Flags) | Block.Phase1Boundary(body.Flags);
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
state.Variables.Clear();
Filter = Filter.Inline(InstructionFlags.None, state);
Filter.TransformStackIntoVariables(state);
state.Variables.Clear();
Body = Body.Inline(InstructionFlags.None, state);
Body.TransformStackIntoVariables(state);
}
public override void WriteTo(ITextOutput output)
{
output.Write("catch ");
@ -281,17 +254,6 @@ namespace ICSharpCode.Decompiler.IL @@ -281,17 +254,6 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
TryBlock = TryBlock.Inline(InstructionFlags.None, state);
TryBlock.TransformStackIntoVariables(state);
var variablesAfterTry = state.Variables;
state.Variables = new Stack<ILVariable>();
FinallyBlock = FinallyBlock.Inline(InstructionFlags.None, state);
FinallyBlock.TransformStackIntoVariables(state);
state.Variables = variablesAfterTry;
}
}
partial class TryFault
@ -366,24 +328,5 @@ namespace ICSharpCode.Decompiler.IL @@ -366,24 +328,5 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
TryBlock = TryBlock.Inline(InstructionFlags.None, state);
TryBlock.TransformStackIntoVariables(state);
var variablesAfterTry = state.Variables;
state.Variables = new Stack<ILVariable>();
FaultBlock = FaultBlock.Inline(InstructionFlags.None, state);
FaultBlock.TransformStackIntoVariables(state);
if (!TryBlock.HasFlag(InstructionFlags.EndPointUnreachable) && !FaultBlock.HasFlag(InstructionFlags.EndPointUnreachable)) {
// If end-points of both instructions are reachable, merge their states
state.MergeVariables(state.Variables, variablesAfterTry);
}
if (FaultBlock.HasFlag(InstructionFlags.EndPointUnreachable)) {
// If the end-point of FaultBlock is unreachable, continue with the end-state of TryBlock instead
// (if both are unreachable, it doesn't matter what we continue with)
state.Variables = variablesAfterTry;
}
}
}
}

6
ICSharpCode.Decompiler/IL/Transforms/ControlFlowSimplification.cs

@ -152,7 +152,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -152,7 +152,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
bool IsUsableBranchToChild(ControlFlowNode cfgNode, ILInstruction potentialBranchInstruction)
{
Branch br = potentialBranchInstruction as Branch;
if (br == null || br.PopCount != 0)
if (br == null)
return false;
var targetBlock = br.TargetBlock;
return targetBlock.Parent == currentContainer && cfgNode.Dominates(controlFlowGraph[targetBlock.ChildIndex])
@ -167,11 +167,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -167,11 +167,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case OpCode.Branch:
Branch br1 = (Branch)exit1;
Branch br2 = (Branch)exit2;
return br1.TargetBlock == br2.TargetBlock && br1.PopCount == br2.PopCount;
return br1.TargetBlock == br2.TargetBlock;
case OpCode.Leave:
Leave leave1 = (Leave)exit1;
Leave leave2 = (Leave)exit2;
return leave1.TargetContainer == leave2.TargetContainer && leave1.PopCount == leave2.PopCount;
return leave1.TargetContainer == leave2.TargetContainer;
case OpCode.Return:
Return ret1 = (Return)exit1;
Return ret2 = (Return)exit2;

34
ICSharpCode.Decompiler/IL/Transforms/IILTransform.cs

@ -0,0 +1,34 @@ @@ -0,0 +1,34 @@
// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Threading;
namespace ICSharpCode.Decompiler.IL
{
public class ILTransformContext
{
public IDecompilerTypeSystem TypeSystem { get; set; }
public CancellationToken CancellationToken { get; set; }
}
public interface IILTransform
{
void Run(ILFunction function, ILTransformContext context);
}
}

9
ICSharpCode.Decompiler/IL/Transforms/OptimizingTransform.cs

@ -44,7 +44,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -44,7 +44,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// Ensure return blocks are inlined:
if (block.Instructions.Count == 2 && block.Instructions[1].OpCode == OpCode.Return) {
Return ret = (Return)block.Instructions[1];
if (ret.ReturnValue != null && ret.ReturnValue.OpCode == OpCode.Pop && block.Instructions[0].ResultType != StackType.Void) {
ILVariable v;
ILInstruction inst;
if (ret.ReturnValue != null && ret.ReturnValue.MatchLdLoc(out v)
&& v.IsSingleUse && block.Instructions[0].MatchStLoc(v, out inst))
{
ret.ReturnValue = block.Instructions[0];
block.Instructions.RemoveAt(0);
}
@ -62,7 +66,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -62,7 +66,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
var nextBranch = (Branch)targetBlock.Instructions[0];
branch.TargetBlock = nextBranch.TargetBlock;
branch.PopCount += nextBranch.PopCount;
if (targetBlock.IncomingEdgeCount == 0)
targetBlock.Instructions.Clear(); // mark the block for deletion
targetBlock = branch.TargetBlock;
@ -73,7 +76,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -73,7 +76,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
} else if (branch.TargetBlock.Instructions.Count == 1 && branch.TargetBlock.Instructions[0].OpCode == OpCode.Leave) {
// Replace branches to 'leave' instruction with the leave instruction
Leave leave = (Leave)branch.TargetBlock.Instructions[0];
branch.ReplaceWith(new Leave(leave.TargetContainer) { PopCount = branch.PopCount + leave.PopCount, ILRange = branch.ILRange });
branch.ReplaceWith(new Leave(leave.TargetContainer) { ILRange = branch.ILRange });
}
if (targetBlock.IncomingEdgeCount == 0)
targetBlock.Instructions.Clear(); // mark the block for deletion

96
ICSharpCode.Decompiler/IL/Transforms/TransformStackIntoVariables.cs

@ -1,96 +0,0 @@ @@ -1,96 +0,0 @@
// Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace ICSharpCode.Decompiler.IL
{
public class ILTransformContext
{
public IDecompilerTypeSystem TypeSystem { get; set; }
public CancellationToken CancellationToken { get; set; }
}
public interface IILTransform
{
void Run(ILFunction function, ILTransformContext context);
}
public class TransformStackIntoVariables : IILTransform
{
// Transform ordering:
// TransformStackIntoVariables should run after all inlining transforms, so that no unnecessary variables are created.
public void Run(ILFunction function, ILTransformContext context)
{
var state = new TransformStackIntoVariablesState();
state.TypeSystem = context.TypeSystem;
function.TransformStackIntoVariables(state);
HashSet<ILVariable> variables = new HashSet<ILVariable>();
function.AcceptVisitor(new CollectStackVariablesVisitor(state, variables));
function.Variables.AddRange(variables);
}
class CollectStackVariablesVisitor : ILVisitor
{
readonly TransformStackIntoVariablesState state;
readonly HashSet<ILVariable> variables;
public CollectStackVariablesVisitor(TransformStackIntoVariablesState state, HashSet<ILVariable> variables)
{
this.state = state;
this.variables = variables;
}
protected override void Default(ILInstruction inst)
{
foreach (var child in inst.Children) {
child.AcceptVisitor(this);
}
}
protected internal override void VisitLdLoc(LdLoc inst)
{
base.VisitLdLoc(inst);
if (inst.Variable.Kind == VariableKind.StackSlot) {
var variable = state.UnionFind.Find(inst.Variable);
if (variables.Add(variable))
variable.Name = "S_" + (variables.Count - 1);
inst.ReplaceWith(new LdLoc(variable));
}
}
protected internal override void VisitStLoc(StLoc inst)
{
base.VisitStLoc(inst);
if (inst.Variable.Kind == VariableKind.StackSlot) {
var variable = state.UnionFind.Find(inst.Variable);
if (variables.Add(variable))
variable.Name = "S_" + (variables.Count - 1);
inst.ReplaceWith(new StLoc(variable, inst.Value));
}
}
}
}
}

82
ICSharpCode.Decompiler/IL/Transforms/TransformStackIntoVariablesState.cs

@ -1,82 +0,0 @@ @@ -1,82 +0,0 @@
// Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
namespace ICSharpCode.Decompiler.IL
{
public class TransformStackIntoVariablesState : IInlineContext
{
public Stack<ILVariable> Variables { get; set; }
public UnionFind<ILVariable> UnionFind { get; set; }
public Dictionary<Block, ImmutableArray<ILVariable>> InitialVariables { get; set; }
public Dictionary<BlockContainer, ImmutableArray<ILVariable>> FinalVariables { get; set; }
public IDecompilerTypeSystem TypeSystem { get; set; }
public TransformStackIntoVariablesState()
{
Variables = new Stack<ILVariable>();
UnionFind = new UnionFind<ILVariable>();
InitialVariables = new Dictionary<Block, ImmutableArray<ILVariable>>();
FinalVariables = new Dictionary<BlockContainer, ImmutableArray<ILVariable>>();
}
public void MergeVariables(Stack<ILVariable> a, Stack<ILVariable> b)
{
Debug.Assert(a.Count == b.Count);
var enum1 = a.GetEnumerator();
var enum2 = b.GetEnumerator();
while (enum1.MoveNext() && enum2.MoveNext())
UnionFind.Merge(enum1.Current, enum2.Current);
}
ILInstruction IInlineContext.Peek(InstructionFlags flagsBefore)
{
return new LdLoc(Variables.Peek());
}
ILInstruction IInlineContext.Pop(InstructionFlags flagsBefore)
{
return new LdLoc(Variables.Pop());
}
}
public static class Extensions
{
public static Stack<T> Clone<T>(this Stack<T> inst)
{
if (inst == null)
throw new ArgumentNullException("inst");
return inst.ToImmutableArray().ToStack();
}
public static Stack<T> ToStack<T>(this ImmutableArray<T> inst)
{
var copy = new Stack<T>();
for (int i = inst.Length - 1; i >= 0; i--)
copy.Push(inst[i]);
return copy;
}
}
}

2
ICSharpCode.Decompiler/IL/Transforms/TransformingVisitor.cs

@ -61,6 +61,7 @@ namespace ICSharpCode.Decompiler.IL @@ -61,6 +61,7 @@ namespace ICSharpCode.Decompiler.IL
protected bool removeNops = true;
/*
sealed class InliningStack : Stack<ILInstruction>, IInlineContext
{
/// <summary>
@ -196,6 +197,7 @@ namespace ICSharpCode.Decompiler.IL @@ -196,6 +197,7 @@ namespace ICSharpCode.Decompiler.IL
output.Add(inst);
}
}
*/
protected internal override ILInstruction VisitBlockContainer(BlockContainer container)
{

2
ICSharpCode.Decompiler/Tests/ILTransforms/InliningTests.cs

@ -23,6 +23,7 @@ using ICSharpCode.Decompiler.Tests.Helpers; @@ -23,6 +23,7 @@ using ICSharpCode.Decompiler.Tests.Helpers;
namespace ICSharpCode.Decompiler.Tests.ILTransforms
{
/*
/// <summary>
/// IL Inlining unit tests.
/// </summary>
@ -126,4 +127,5 @@ namespace ICSharpCode.Decompiler.Tests.ILTransforms @@ -126,4 +127,5 @@ namespace ICSharpCode.Decompiler.Tests.ILTransforms
);
}
}
*/
}

Loading…
Cancel
Save