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