Browse Source

implement TransformStackIntoVariables step to eliminate peek and pop instructions

pull/728/head
Siegfried Pammer 10 years ago
parent
commit
f45c2fa401
  1. 15
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 3
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 3
      ICSharpCode.Decompiler/IL/ILVariable.cs
  4. 48
      ICSharpCode.Decompiler/IL/Instructions.cs
  5. 9
      ICSharpCode.Decompiler/IL/Instructions.tt
  6. 19
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  7. 6
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  8. 13
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  9. 7
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  10. 8
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  11. 5
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  12. 5
      ICSharpCode.Decompiler/IL/Instructions/IfInstruction.cs
  13. 6
      ICSharpCode.Decompiler/IL/Instructions/Return.cs
  14. 4
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  15. 19
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  16. 90
      ICSharpCode.Decompiler/IL/TransformStackIntoVariables.cs
  17. 7
      ICSharpCode.Decompiler/IL/TransformingVisitor.cs
  18. 85
      ICSharpCode.Decompiler/IL/UnionFind.cs
  19. 7
      ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs
  20. 4
      ICSharpCode.Decompiler/Tests/Helpers/TypeSystemHelper.cs
  21. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  22. 91
      ICSharpCode.Decompiler/Tests/StackToVariablesTests.cs

15
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -37,6 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -37,6 +37,7 @@ namespace ICSharpCode.Decompiler.CSharp
public class CSharpDecompiler
{
readonly DecompilerTypeSystem typeSystem;
List<IAstTransform> astTransforms = new List<IAstTransform> {
//new PushNegation(),
//new DelegateConstruction(context),
@ -54,6 +55,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -54,6 +55,11 @@ namespace ICSharpCode.Decompiler.CSharp
//new FlattenSwitchBlocks(),
};
List<IILTransform> ilTransforms = new List<IILTransform> {
new TransformingVisitor(),
new TransformStackIntoVariables()
};
public CancellationToken CancellationToken { get; set; }
/// <summary>
@ -192,15 +198,18 @@ namespace ICSharpCode.Decompiler.CSharp @@ -192,15 +198,18 @@ namespace ICSharpCode.Decompiler.CSharp
var ilReader = new ILReader(typeSystem);
var function = ilReader.ReadIL(methodDefinition.Body, CancellationToken);
function.CheckInvariant();
function.Body = function.Body.AcceptVisitor(new TransformingVisitor());
function.CheckInvariant();
var context = new ILTransformContext { TypeSystem = typeSystem };
foreach (var transform in ilTransforms) {
transform.Run(function, context);
function.CheckInvariant();
}
var statementBuilder = new StatementBuilder(decompilationContext, method);
var body = statementBuilder.ConvertAsBlock(function.Body);
// insert variables at start of body
Statement prevVarDecl = null;
foreach (var v in function.Variables) {
if (v.Kind == VariableKind.Local) {
if (v.Kind == VariableKind.Local || v.Kind == VariableKind.StackSlot) {
var type = typeSystemAstBuilder.ConvertType(v.Type);
var varDecl = new VariableDeclarationStatement(type, v.Name);
body.Statements.InsertAfter(prevVarDecl, varDecl);

3
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -98,11 +98,14 @@ @@ -98,11 +98,14 @@
<Compile Include="IL\Instructions\PatternMatching.cs" />
<Compile Include="IL\Instructions\Return.cs" />
<Compile Include="IL\Instructions\SimpleInstruction.cs" />
<Compile Include="IL\Instructions\TransformStackIntoVariablesState.cs" />
<Compile Include="IL\Instructions\TryInstruction.cs" />
<Compile Include="IL\Instructions\UnaryInstruction.cs" />
<Compile Include="IL\IInlineContext.cs" />
<Compile Include="IL\NRTypeExtensions.cs" />
<Compile Include="IL\TransformingVisitor.cs" />
<Compile Include="IL\TransformStackIntoVariables.cs" />
<Compile Include="IL\UnionFind.cs" />
<Compile Include="TypesHierarchyHelpers.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />

3
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -45,7 +45,8 @@ namespace ICSharpCode.Decompiler.IL @@ -45,7 +45,8 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>
/// Variable created for exception handler
/// </summary>
Exception
Exception,
StackSlot
}
public class ILVariable

48
ICSharpCode.Decompiler/IL/Instructions.cs

@ -201,6 +201,10 @@ namespace ICSharpCode.Decompiler.IL @@ -201,6 +201,10 @@ namespace ICSharpCode.Decompiler.IL
this.Argument = this.argument.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Argument.TransformStackIntoVariables(state);
}
protected override InstructionFlags ComputeFlags()
{
return argument.Flags;
@ -255,6 +259,11 @@ namespace ICSharpCode.Decompiler.IL @@ -255,6 +259,11 @@ namespace ICSharpCode.Decompiler.IL
this.Left = this.left.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Left.TransformStackIntoVariables(state);
Right.TransformStackIntoVariables(state);
}
protected override InstructionFlags ComputeFlags()
{
return left.Flags | right.Flags;
@ -887,6 +896,10 @@ namespace ICSharpCode.Decompiler.IL @@ -887,6 +896,10 @@ namespace ICSharpCode.Decompiler.IL
this.Value = this.value.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Value.TransformStackIntoVariables(state);
}
readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } }
@ -1166,6 +1179,10 @@ namespace ICSharpCode.Decompiler.IL @@ -1166,6 +1179,10 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal 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>
@ -1227,6 +1244,10 @@ namespace ICSharpCode.Decompiler.IL @@ -1227,6 +1244,10 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
readonly IField field;
/// <summary>Returns the field operand.</summary>
public IField Field { get { return field; } }
@ -1292,6 +1313,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1292,6 +1313,11 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal 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>
@ -1413,6 +1439,10 @@ namespace ICSharpCode.Decompiler.IL @@ -1413,6 +1439,10 @@ namespace ICSharpCode.Decompiler.IL
this.Value = this.value.Inline(flagsBefore, context);
return this;
}
internal 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>
@ -1530,6 +1560,10 @@ namespace ICSharpCode.Decompiler.IL @@ -1530,6 +1560,10 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
readonly IType type;
/// <summary>Returns the type operand.</summary>
public IType Type { get { return type; } }
@ -1603,6 +1637,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1603,6 +1637,11 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal 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; } }
@ -1874,6 +1913,10 @@ namespace ICSharpCode.Decompiler.IL @@ -1874,6 +1913,10 @@ namespace ICSharpCode.Decompiler.IL
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
public override StackType ResultType { get { return StackType.I; } }
protected override InstructionFlags ComputeFlags()
{
@ -1934,6 +1977,11 @@ namespace ICSharpCode.Decompiler.IL @@ -1934,6 +1977,11 @@ namespace ICSharpCode.Decompiler.IL
this.Array = this.array.Inline(flagsBefore, context);
return this;
}
internal 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; } }

9
ICSharpCode.Decompiler/IL/Instructions.tt

@ -606,6 +606,15 @@ namespace ICSharpCode.Decompiler.IL @@ -606,6 +606,15 @@ namespace ICSharpCode.Decompiler.IL
b.AppendLine("\treturn this;");
b.Append("}");
opCode.Members.Add(b.ToString());
b.Clear();
b.AppendLine("internal 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());
}
};
}

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

@ -22,6 +22,8 @@ using System.Diagnostics; @@ -22,6 +22,8 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
namespace ICSharpCode.Decompiler.IL
{
@ -163,5 +165,22 @@ namespace ICSharpCode.Decompiler.IL @@ -163,5 +165,22 @@ 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(inst, variable));
}
Instructions[i] = inst;
}
FinalInstruction = FinalInstruction.Inline(InstructionFlags.None, state);
FinalInstruction.TransformStackIntoVariables(state);
}
}
}

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

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
@ -102,6 +103,11 @@ namespace ICSharpCode.Decompiler.IL @@ -102,6 +103,11 @@ namespace ICSharpCode.Decompiler.IL
// Blocks are phase-1 boundaries
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
EntryPoint.TransformStackIntoVariables(state);
}
}
}

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

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Text;
@ -111,5 +112,17 @@ namespace ICSharpCode.Decompiler.IL @@ -111,5 +112,17 @@ namespace ICSharpCode.Decompiler.IL
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());
}
}
}
}

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

@ -124,5 +124,12 @@ namespace ICSharpCode.Decompiler.IL @@ -124,5 +124,12 @@ 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,5 +68,13 @@ namespace ICSharpCode.Decompiler.IL @@ -68,5 +68,13 @@ 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

@ -168,6 +168,11 @@ namespace ICSharpCode.Decompiler.IL @@ -168,6 +168,11 @@ namespace ICSharpCode.Decompiler.IL
/// is equivalent to phase-1 execution of the instruction.
/// </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.

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

@ -58,6 +58,11 @@ namespace ICSharpCode.Decompiler.IL @@ -58,6 +58,11 @@ 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)
{
throw new NotImplementedException();
}
protected override InstructionFlags ComputeFlags()
{

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

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

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

@ -59,6 +59,10 @@ namespace ICSharpCode.Decompiler.IL @@ -59,6 +59,10 @@ namespace ICSharpCode.Decompiler.IL
// Nothing to do, since we don't have arguments.
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
}
}
partial class Pop

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

@ -102,6 +102,11 @@ namespace ICSharpCode.Decompiler.IL @@ -102,6 +102,11 @@ namespace ICSharpCode.Decompiler.IL
throw new InvalidOperationException("Cannot transform a TryCatchHandler");
}
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
throw new NotImplementedException();
}
}
/// <summary>
@ -139,6 +144,10 @@ namespace ICSharpCode.Decompiler.IL @@ -139,6 +144,10 @@ namespace ICSharpCode.Decompiler.IL
{
return Block.Phase1Boundary(filter.Flags) | Block.Phase1Boundary(body.Flags);
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
}
public override void WriteTo(ITextOutput output)
{
@ -216,6 +225,11 @@ namespace ICSharpCode.Decompiler.IL @@ -216,6 +225,11 @@ namespace ICSharpCode.Decompiler.IL
this.TryBlock = TryBlock.AcceptVisitor(visitor);
this.FinallyBlock = finallyBlock.AcceptVisitor(visitor);
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
throw new NotImplementedException();
}
}
partial class TryFault
@ -264,5 +278,10 @@ namespace ICSharpCode.Decompiler.IL @@ -264,5 +278,10 @@ namespace ICSharpCode.Decompiler.IL
this.TryBlock = TryBlock.AcceptVisitor(visitor);
this.FaultBlock = faultBlock.AcceptVisitor(visitor);
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
throw new NotImplementedException();
}
}
}

90
ICSharpCode.Decompiler/IL/TransformStackIntoVariables.cs

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
// 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;
namespace ICSharpCode.Decompiler.IL
{
public class ILTransformContext
{
public DecompilerTypeSystem TypeSystem { get; set; }
}
public interface IILTransform
{
void Run(ILFunction function, ILTransformContext context);
}
public class TransformStackIntoVariables : IILTransform
{
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.TransformChildren(new CollectStackVariablesVisitor(state, variables));
function.Variables.AddRange(variables);
}
class CollectStackVariablesVisitor : ILVisitor<ILInstruction>
{
readonly TransformStackIntoVariablesState state;
readonly HashSet<ILVariable> variables;
public CollectStackVariablesVisitor(TransformStackIntoVariablesState state, HashSet<ILVariable> variables)
{
this.state = state;
this.variables = variables;
}
protected override ILInstruction Default(ILInstruction inst)
{
inst.TransformChildren(this);
return inst;
}
protected internal override ILInstruction VisitLdLoc(LdLoc 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 = new LdLoc(variable);
}
return base.VisitLdLoc(inst);
}
protected internal override ILInstruction VisitStLoc(StLoc 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 = new StLoc(inst.Value, variable);
}
return base.VisitStLoc(inst);
}
}
}
}

7
ICSharpCode.Decompiler/IL/TransformingVisitor.cs

@ -33,8 +33,13 @@ namespace ICSharpCode.Decompiler.IL @@ -33,8 +33,13 @@ namespace ICSharpCode.Decompiler.IL
/// - cleanup after branch inlining
/// - removal of unnecessary blocks and block containers
/// </remarks>
public class TransformingVisitor : ILVisitor<ILInstruction>
public class TransformingVisitor : ILVisitor<ILInstruction>, IILTransform
{
public void Run(ILFunction function, ILTransformContext context)
{
function.AcceptVisitor(this);
}
protected override ILInstruction Default(ILInstruction inst)
{
inst.TransformChildren(this);

85
ICSharpCode.Decompiler/IL/UnionFind.cs

@ -0,0 +1,85 @@ @@ -0,0 +1,85 @@
// 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;
namespace ICSharpCode.Decompiler.IL
{
public class UnionFind<T>
{
Dictionary<T, Node> mapping;
class Node
{
public int rank;
public Node parent;
public T value;
}
public UnionFind()
{
mapping = new Dictionary<T, Node>();
}
Node GetNode(T element)
{
Node node;
if (!mapping.TryGetValue(element, out node)) {
node = new Node {
value = element,
rank = 0
};
node.parent = node;
mapping.Add(element, node);
}
return node;
}
public T Find(T element)
{
return FindRoot(GetNode(element)).value;
}
Node FindRoot(Node node)
{
if (node.parent != node)
node.parent = FindRoot(node.parent);
return node.parent;
}
public void Merge(T a, T b)
{
var rootA = FindRoot(GetNode(a));
var rootB = FindRoot(GetNode(b));
if (rootA == rootB)
return;
if (rootA.rank < rootB.rank)
rootA.parent = rootB;
else if (rootA.rank > rootB.rank)
rootB.parent = rootA;
else {
rootB.parent = rootA;
rootA.rank++;
}
}
}
}

7
ICSharpCode.Decompiler/Tests/Helpers/RemoveCompilerAttribute.cs

@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -35,7 +35,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
}
}
class EscapeGeneratedIdentifiers : DepthFirstAstVisitor<object, object>
class EscapeGeneratedIdentifiers : DepthFirstAstVisitor
{
bool IsValid(char ch)
{
@ -51,15 +51,14 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -51,15 +51,14 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
return string.Concat(s.Select(ch => IsValid(ch) ? ch.ToString() : string.Format("_{0:0000X}", (int)ch)));
}
public override object VisitIdentifier(Identifier identifier, object data)
public override void VisitIdentifier(Identifier identifier)
{
identifier.Name = ReplaceInvalid(identifier.Name);
return null;
}
public void Run(AstNode node)
{
node.AcceptVisitor(this, null);
node.AcceptVisitor(this);
}
}
}

4
ICSharpCode.Decompiler/Tests/Helpers/TypeSystemHelper.cs

@ -38,6 +38,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -38,6 +38,10 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
return new DecompilerTypeSystem(module);
});
public static DecompilerTypeSystem Instance {
get { return decompilerTypeSystem.Value; }
}
public static IAssembly FromReflection(Assembly assembly)
{
return decompilerTypeSystem.Value.Compilation.Assemblies.Single(asm => asm.AssemblyName == assembly.GetName().Name);

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -101,6 +101,7 @@ @@ -101,6 +101,7 @@
<Compile Include="Helpers\Tester.cs" />
<Compile Include="Helpers\TypeSystemHelper.cs" />
<Compile Include="ILTransforms\Inlining.cs" />
<Compile Include="StackToVariablesTests.cs" />
<Compile Include="TestCases\CompoundAssignment.cs" />
<Compile Include="TestCases\ControlFlow.cs" />
<Compile Include="TestCases\HelloWorld.cs" />

91
ICSharpCode.Decompiler/Tests/StackToVariablesTests.cs

@ -0,0 +1,91 @@ @@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation;
using NUnit.Framework;
using ICSharpCode.Decompiler.Tests.Helpers;
namespace ICSharpCode.Decompiler.Tests
{
[TestFixture]
public class StackToVariablesTests
{
ILVariable StackSlot<T>(int index)
{
return new ILVariable(VariableKind.StackSlot, TypeSystem.FromReflection(typeof(T)), index) {
Name = "S_" + index
};
}
[Test]
public void Test1()
{
Block input = new Block {
Instructions = {
new LdcI4(1),
new LdcI4(2),
new LdcI4(3),
new LdcI4(4),
new Call(TypeSystem.Action<int, int, int, int>()) {
Arguments = {
new Pop(StackType.I4),
new Block { FinalInstruction = new Pop(StackType.I4) },
new Block { FinalInstruction = new Pop(StackType.I4) },
new Pop(StackType.I4)
}
}
}
};
// F(3, 2, 1, 4)
Block expected = new Block {
Instructions = {
new Void(new StLoc(new LdcI4(1), StackSlot<int>(0))),
new Void(new StLoc(new LdcI4(2), StackSlot<int>(1))),
new Void(new StLoc(new LdcI4(3), StackSlot<int>(2))),
new Void(new StLoc(new LdcI4(4), StackSlot<int>(3))),
new Call(TypeSystem.Action<int, int, int, int>()) {
Arguments = {
new LdLoc(StackSlot<int>(2)),
new Block { FinalInstruction = new LdLoc(StackSlot<int>(1)) },
new Block { FinalInstruction = new LdLoc(StackSlot<int>(0)) },
new LdLoc(StackSlot<int>(3))
}
}
}
};
TestStackIntoVariablesTransform(input, expected);
}
[Test]
public void Test2()
{
Block input = new Block {
Instructions = {
new LdcI4(1),
new LdcI4(2),
new Add(new Pop(StackType.I4), new Pop(StackType.I4), false, Sign.Signed)
}
};
Block expected = new Block {
Instructions = {
new Void(new StLoc(new LdcI4(1), StackSlot<int>(0))),
new Void(new StLoc(new LdcI4(2), StackSlot<int>(1))),
new Void(new StLoc(new Add(new LdLoc(StackSlot<int>(0)), new LdLoc(StackSlot<int>(1)), false, Sign.Signed), StackSlot<int>(2)))
}
};
TestStackIntoVariablesTransform(input, expected);
}
void TestStackIntoVariablesTransform(Block input, Block expected)
{
input.AddRef();
ILFunction function = new ILFunction(null, input);
var context = new ILTransformContext { TypeSystem = TypeSystem.Instance };
new TransformStackIntoVariables().Run(function, context);
Assert.AreEqual(expected.ToString(), input.ToString());
}
}
}
Loading…
Cancel
Save