Browse Source

Add more enumerator debugging.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
769990ef04
  1. 43
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  2. 66
      ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs

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

@ -199,36 +199,37 @@ namespace ICSharpCode.Decompiler.IL
#if DEBUG #if DEBUG
int activeEnumerators; int activeEnumerators;
#endif
[Conditional("DEBUG")]
internal void AssertNoEnumerators()
{
#if DEBUG
Debug.Assert(activeEnumerators == 0);
#endif
}
[Conditional("DEBUG")] [Conditional("DEBUG")]
internal void StartEnumerator() internal void StartEnumerator()
{ {
#if DEBUG
activeEnumerators++; activeEnumerators++;
#endif
} }
[Conditional("DEBUG")] [Conditional("DEBUG")]
internal void StopEnumerator() internal void StopEnumerator()
{ {
#if DEBUG
Debug.Assert(activeEnumerators > 0); Debug.Assert(activeEnumerators > 0);
activeEnumerators--; activeEnumerators--;
}
#endif
[Conditional("DEBUG")]
internal void AssertNoEnumerators()
{
#if DEBUG
Debug.Assert(activeEnumerators == 0);
#endif #endif
} }
/// <summary>
/// Enumerator over the children of an ILInstruction.
/// Warning: even though this is a struct, it is invalid to copy:
/// the number of constructor calls must match the number of dispose calls.
/// </summary>
public struct ChildrenEnumerator : IEnumerator<ILInstruction> public struct ChildrenEnumerator : IEnumerator<ILInstruction>
{ {
readonly ILInstruction inst; ILInstruction inst;
readonly int end; readonly int end;
int pos; int pos;
@ -238,7 +239,9 @@ namespace ICSharpCode.Decompiler.IL
this.inst = inst; this.inst = inst;
this.pos = -1; this.pos = -1;
this.end = inst.GetChildCount(); this.end = inst.GetChildCount();
#if DEBUG
inst.StartEnumerator(); inst.StartEnumerator();
#endif
} }
public ILInstruction Current { public ILInstruction Current {
@ -254,7 +257,12 @@ namespace ICSharpCode.Decompiler.IL
public void Dispose() public void Dispose()
{ {
inst.StopEnumerator(); #if DEBUG
if (inst != null) {
inst.StopEnumerator();
inst = null;
}
#endif
} }
object System.Collections.IEnumerator.Current { object System.Collections.IEnumerator.Current {
@ -263,7 +271,7 @@ namespace ICSharpCode.Decompiler.IL
void System.Collections.IEnumerator.Reset() void System.Collections.IEnumerator.Reset()
{ {
throw new NotSupportedException(); pos = -1;
} }
} }
#endregion #endregion
@ -303,15 +311,14 @@ namespace ICSharpCode.Decompiler.IL
} }
enumerator.Dispose(); enumerator.Dispose();
if (stack.Count > 0) { 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(); enumerator = stack.Pop();
yield return enumerator.Current;
} else { } else {
break; break;
} }
} }
} finally { } finally {
enumerator.Dispose();
while (stack.Count > 0) { while (stack.Count > 0) {
stack.Pop().Dispose(); stack.Pop().Dispose();
} }

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

@ -56,20 +56,78 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
public List<T>.Enumerator GetEnumerator() #region GetEnumerator
public Enumerator GetEnumerator()
{ {
return list.GetEnumerator(); return new Enumerator(this);
}
/// <summary>
/// Custom enumerator for InstructionCollection.
/// Unlike List{T}.Enumerator, this enumerator allows replacing an item during the enumeration.
/// Adding/removing items from the collection still is invalid (however, such
/// invalid actions are only detected in debug builds).
///
/// Warning: even though this is a struct, it is invalid to copy:
/// the number of constructor calls must match the number of dispose calls.
/// </summary>
public struct Enumerator : IEnumerator<T>
{
#if DEBUG
ILInstruction parentInstruction;
#endif
readonly List<T> list;
int pos;
public Enumerator(InstructionCollection<T> col)
{
this.list = col.list;
this.pos = -1;
#if DEBUG
this.parentInstruction = col.parentInstruction;
col.parentInstruction.StartEnumerator();
#endif
}
public bool MoveNext()
{
return ++pos < list.Count;
}
public T Current {
get { return list[pos]; }
}
public void Dispose()
{
#if DEBUG
if (parentInstruction != null) {
parentInstruction.StopEnumerator();
parentInstruction = null;
}
#endif
}
void System.Collections.IEnumerator.Reset()
{
pos = -1;
}
object System.Collections.IEnumerator.Current {
get { return this.Current; }
}
} }
IEnumerator<T> IEnumerable<T>.GetEnumerator() IEnumerator<T> IEnumerable<T>.GetEnumerator()
{ {
return list.GetEnumerator(); return GetEnumerator();
} }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{ {
return list.GetEnumerator(); return GetEnumerator();
} }
#endregion
/// <summary> /// <summary>
/// Gets the index of the instruction in this collection. /// Gets the index of the instruction in this collection.

Loading…
Cancel
Save