mirror of https://github.com/icsharpcode/ILSpy.git
22 changed files with 446 additions and 9 deletions
@ -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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -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++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -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…
Reference in new issue