Browse Source

Add void-visitor and make Descendants use post-order.

pull/728/head
Daniel Grunwald 10 years ago
parent
commit
f37655a573
  1. 586
      ICSharpCode.Decompiler/IL/Instructions.cs
  2. 20
      ICSharpCode.Decompiler/IL/Instructions.tt
  3. 86
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  4. 7
      ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs
  5. 2
      ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs
  6. 23
      ICSharpCode.Decompiler/IL/Transforms/TransformStackIntoVariables.cs
  7. 8
      ICSharpCode.Decompiler/IL/Transforms/TransformingVisitor.cs

586
ICSharpCode.Decompiler/IL/Instructions.cs

File diff suppressed because it is too large Load Diff

20
ICSharpCode.Decompiler/IL/Instructions.tt

@ -227,6 +227,10 @@ namespace ICSharpCode.Decompiler.IL @@ -227,6 +227,10 @@ namespace ICSharpCode.Decompiler.IL
{<#=Body(opCode.WriteToBody)#>}
<# } #>
<# if (opCode.GenerateAcceptVisitor) { #>
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.Visit<#=opCode.Name#>(this);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.Visit<#=opCode.Name#>(this);
@ -236,6 +240,22 @@ namespace ICSharpCode.Decompiler.IL @@ -236,6 +240,22 @@ namespace ICSharpCode.Decompiler.IL
<# } #>
/// <summary>
/// Base class for visitor pattern.
/// </summary>
public abstract class ILVisitor
{
/// <summary>Called by Visit*() methods that were not overridden</summary>
protected abstract void Default(ILInstruction inst);
<# foreach (OpCode opCode in opCodes) { #>
protected internal virtual void Visit<#=opCode.Name#>(<#=opCode.Name#> <#=opCode.VariableName#>)
{
Default(<#=opCode.VariableName#>);
}
<# } #>
}
/// <summary>
/// Base class for visitor pattern.
/// </summary>

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

@ -139,6 +139,11 @@ namespace ICSharpCode.Decompiler.IL @@ -139,6 +139,11 @@ namespace ICSharpCode.Decompiler.IL
return output.ToString();
}
/// <summary>
/// Calls the Visit*-method on the visitor corresponding to the concrete type of this instruction.
/// </summary>
public abstract void AcceptVisitor(ILVisitor visitor);
/// <summary>
/// Calls the Visit*-method on the visitor corresponding to the concrete type of this instruction.
/// </summary>
@ -192,6 +197,35 @@ namespace ICSharpCode.Decompiler.IL @@ -192,6 +197,35 @@ namespace ICSharpCode.Decompiler.IL
}
}
#if DEBUG
int activeEnumerators;
#endif
[Conditional("DEBUG")]
internal void AssertNoEnumerators()
{
#if DEBUG
Debug.Assert(activeEnumerators == 0);
#endif
}
[Conditional("DEBUG")]
internal void StartEnumerator()
{
#if DEBUG
activeEnumerators++;
#endif
}
[Conditional("DEBUG")]
internal void StopEnumerator()
{
#if DEBUG
Debug.Assert(activeEnumerators > 0);
activeEnumerators--;
#endif
}
public struct ChildrenEnumerator : IEnumerator<ILInstruction>
{
readonly ILInstruction inst;
@ -204,6 +238,7 @@ namespace ICSharpCode.Decompiler.IL @@ -204,6 +238,7 @@ namespace ICSharpCode.Decompiler.IL
this.inst = inst;
this.pos = -1;
this.end = inst.GetChildCount();
inst.StartEnumerator();
}
public ILInstruction Current {
@ -219,6 +254,7 @@ namespace ICSharpCode.Decompiler.IL @@ -219,6 +254,7 @@ namespace ICSharpCode.Decompiler.IL
public void Dispose()
{
inst.StopEnumerator();
}
object System.Collections.IEnumerator.Current {
@ -232,32 +268,54 @@ namespace ICSharpCode.Decompiler.IL @@ -232,32 +268,54 @@ namespace ICSharpCode.Decompiler.IL
}
#endregion
/// <summary>
/// Transforms the children of this instruction by applying the specified visitor.
/// </summary>
[Obsolete]
public void TransformChildren(ILVisitor<ILInstruction> visitor)
{
int count = GetChildCount();
for (int i = 0; i < count; i++) {
SetChild(i, GetChild(i).AcceptVisitor(visitor));
}
}
/// <summary>
/// Replaces this ILInstruction with the given replacement instruction.
/// </summary>
public void ReplaceWith(ILInstruction replacement)
{
Debug.Assert(parent.GetChild(ChildIndex) == this);
if (replacement == this)
return;
parent.SetChild(ChildIndex, replacement);
}
/// <summary>
/// Returns all descendants of the ILInstruction.
/// Returns all descendants of the ILInstruction in post-order.
/// </summary>
/// <remarks>
/// Within a loop 'foreach (var node in inst.Descendants)', it is illegal to
/// add or remove from the child collections of node's ancestors, as those are
/// currently being enumerated.
/// Note that it is valid to modify node's children as those were already previously visited.
/// As a special case, it is also allowed to replace node itself with another node.
/// </remarks>
public IEnumerable<ILInstruction> Descendants {
get {
return TreeTraversal.PreOrder(Children, inst => inst.Children);
// Copy of TreeTraversal.PostOrder() specialized for ChildrenEnumerator
Stack<ChildrenEnumerator> stack = new Stack<ChildrenEnumerator>();
ChildrenEnumerator enumerator = new ChildrenEnumerator(this);
try {
while (true) {
while (enumerator.MoveNext()) {
var element = enumerator.Current;
stack.Push(enumerator);
enumerator = new ChildrenEnumerator(element);
}
enumerator.Dispose();
if (stack.Count > 0) {
yield return stack.Peek().Current;
// Pop enumerator only after yielding, so that it gets
// disposed if the enumeration is aborted.
enumerator = stack.Pop();
} else {
break;
}
}
} finally {
while (stack.Count > 0) {
stack.Pop().Dispose();
}
}
}
}

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

@ -113,6 +113,7 @@ namespace ICSharpCode.Decompiler.IL @@ -113,6 +113,7 @@ namespace ICSharpCode.Decompiler.IL
public void Add(T value)
{
parentInstruction.AssertNoEnumerators();
value.ChildIndex = list.Count + firstChildIndex;
list.Add(value);
parentInstruction.InstructionCollectionAdded(value);
@ -121,6 +122,7 @@ namespace ICSharpCode.Decompiler.IL @@ -121,6 +122,7 @@ namespace ICSharpCode.Decompiler.IL
public void AddRange(IEnumerable<T> values)
{
parentInstruction.AssertNoEnumerators();
foreach (T value in values) {
value.ChildIndex = list.Count + firstChildIndex;
list.Add(value);
@ -137,6 +139,7 @@ namespace ICSharpCode.Decompiler.IL @@ -137,6 +139,7 @@ namespace ICSharpCode.Decompiler.IL
/// </remarks>
public void ReplaceList(IEnumerable<T> newList)
{
parentInstruction.AssertNoEnumerators();
int index = 0;
foreach (T value in newList) {
value.ChildIndex = index + firstChildIndex;
@ -160,6 +163,7 @@ namespace ICSharpCode.Decompiler.IL @@ -160,6 +163,7 @@ namespace ICSharpCode.Decompiler.IL
public void Insert(int index, T item)
{
parentInstruction.AssertNoEnumerators();
list.Insert(index, item);
item.ChildIndex = index;
parentInstruction.InstructionCollectionAdded(item);
@ -175,6 +179,7 @@ namespace ICSharpCode.Decompiler.IL @@ -175,6 +179,7 @@ namespace ICSharpCode.Decompiler.IL
public void RemoveAt(int index)
{
parentInstruction.AssertNoEnumerators();
parentInstruction.InstructionCollectionRemoved(list[index]);
list.RemoveAt(index);
for (int i = index; i < list.Count; i++) {
@ -187,6 +192,7 @@ namespace ICSharpCode.Decompiler.IL @@ -187,6 +192,7 @@ namespace ICSharpCode.Decompiler.IL
public void Clear()
{
parentInstruction.AssertNoEnumerators();
foreach (var entry in list) {
parentInstruction.InstructionCollectionRemoved(entry);
}
@ -213,6 +219,7 @@ namespace ICSharpCode.Decompiler.IL @@ -213,6 +219,7 @@ namespace ICSharpCode.Decompiler.IL
/// </remarks>
public int RemoveAll(Predicate<T> predicate)
{
parentInstruction.AssertNoEnumerators();
int j = 0;
for (int i = 0; i < list.Count; i++) {
T item = list[i];

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

@ -80,7 +80,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -80,7 +80,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
public void Run(ILFunction function, ILTransformContext context)
{
foreach (var blockContainer in function.Descendants.OfType<BlockContainer>().ToArray()) {
foreach (var blockContainer in function.Descendants.OfType<BlockContainer>()) {
Run(blockContainer, context);
}
}

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

@ -42,11 +42,11 @@ namespace ICSharpCode.Decompiler.IL @@ -42,11 +42,11 @@ namespace ICSharpCode.Decompiler.IL
state.TypeSystem = context.TypeSystem;
function.TransformStackIntoVariables(state);
HashSet<ILVariable> variables = new HashSet<ILVariable>();
function.TransformChildren(new CollectStackVariablesVisitor(state, variables));
function.AcceptVisitor(new CollectStackVariablesVisitor(state, variables));
function.Variables.AddRange(variables);
}
class CollectStackVariablesVisitor : ILVisitor<ILInstruction>
class CollectStackVariablesVisitor : ILVisitor
{
readonly TransformStackIntoVariablesState state;
@ -58,32 +58,33 @@ namespace ICSharpCode.Decompiler.IL @@ -58,32 +58,33 @@ namespace ICSharpCode.Decompiler.IL
this.variables = variables;
}
protected override ILInstruction Default(ILInstruction inst)
protected override void Default(ILInstruction inst)
{
inst.TransformChildren(this);
return inst;
foreach (var child in inst.Children) {
child.AcceptVisitor(this);
}
}
protected internal override ILInstruction VisitLdLoc(LdLoc inst)
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 = new LdLoc(variable);
inst.ReplaceWith(new LdLoc(variable));
}
return base.VisitLdLoc(inst);
}
protected internal override ILInstruction VisitStLoc(StLoc inst)
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 = new StLoc(inst.Value, variable);
inst.ReplaceWith(new StLoc(inst.Value, variable));
}
return base.VisitStLoc(inst);
}
}
}

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

@ -42,7 +42,9 @@ namespace ICSharpCode.Decompiler.IL @@ -42,7 +42,9 @@ namespace ICSharpCode.Decompiler.IL
protected override ILInstruction Default(ILInstruction inst)
{
inst.TransformChildren(this);
foreach (var child in inst.Children) {
child.ReplaceWith(child.AcceptVisitor(this));
}
return inst;
}
@ -197,7 +199,9 @@ namespace ICSharpCode.Decompiler.IL @@ -197,7 +199,9 @@ namespace ICSharpCode.Decompiler.IL
protected internal override ILInstruction VisitBlockContainer(BlockContainer container)
{
container.TransformChildren(this);
foreach (var block in container.Blocks) {
block.ReplaceWith(block.AcceptVisitor(this));
}
// VisitBranch() 'steals' blocks from containers. Remove all blocks that were stolen from the block list:
Debug.Assert(container.EntryPoint.IncomingEdgeCount > 0);

Loading…
Cancel
Save