Browse Source

Add ILInstruction.ReplaceWith() method and make ILInstruction.Children an IReadOnlyList.

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
bcfe1b0813
  1. 31
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  2. 471
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 48
      ICSharpCode.Decompiler/IL/Instructions.tt
  4. 56
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  5. 19
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  6. 16
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  7. 147
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  8. 213
      ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs
  9. 24
      ICSharpCode.Decompiler/IL/Instructions/Return.cs
  10. 13
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  11. 98
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  12. 2
      ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs
  13. 39
      ICSharpCode.Decompiler/Tests/Loops.cs

31
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -74,8 +74,17 @@ namespace ICSharpCode.Decompiler.CSharp @@ -74,8 +74,17 @@ namespace ICSharpCode.Decompiler.CSharp
return new IfElseStatement(condition, trueStatement, falseStatement);
}
/// <summary>Target block that a 'continue;' statement would jump to</summary>
Block continueTarget;
/// <summary>Number of ContinueStatements that were created for the current continueTarget</summary>
int continueCount;
protected internal override Statement VisitBranch(Branch inst)
{
if (inst.TargetBlock == continueTarget) {
continueCount++;
return new ContinueStatement();
}
return new GotoStatement(inst.TargetLabel);
}
@ -150,6 +159,28 @@ namespace ICSharpCode.Decompiler.CSharp @@ -150,6 +159,28 @@ namespace ICSharpCode.Decompiler.CSharp
}
protected internal override Statement VisitBlockContainer(BlockContainer container)
{
if (container.EntryPoint.IncomingEdgeCount > 1) {
var oldContinueTarget = continueTarget;
var oldContinueCount = continueCount;
continueTarget = container.EntryPoint;
continueCount = 0;
var blockStatement = ConvertBlockContainer(container);
Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount);
Debug.Assert(blockStatement.Statements.First() is LabelStatement);
if (container.EntryPoint.IncomingEdgeCount == continueCount + 1) {
// Remove the entrypoint label if all jumps to the label were replaced with 'continue;' statements
blockStatement.Statements.First().Remove();
}
continueTarget = oldContinueTarget;
continueCount = oldContinueCount;
return new WhileStatement(new PrimitiveExpression(true), blockStatement);
} else {
return ConvertBlockContainer(container);
}
}
BlockStatement ConvertBlockContainer(BlockContainer container)
{
BlockStatement blockStatement = new BlockStatement();
foreach (var block in container.Blocks) {

471
ICSharpCode.Decompiler/IL/Instructions.cs

@ -186,24 +186,38 @@ namespace ICSharpCode.Decompiler.IL @@ -186,24 +186,38 @@ namespace ICSharpCode.Decompiler.IL
get { return this.argument; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.argument, value);
SetChildInstruction(ref this.argument, value, 0);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.argument;
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.argument;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Argument = this.argument.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Argument = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Argument = this.argument.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Argument.TransformStackIntoVariables(state);
}
@ -233,7 +247,7 @@ namespace ICSharpCode.Decompiler.IL @@ -233,7 +247,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.left; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.left, value);
SetChildInstruction(ref this.left, value, 0);
}
}
ILInstruction right;
@ -241,27 +255,44 @@ namespace ICSharpCode.Decompiler.IL @@ -241,27 +255,44 @@ namespace ICSharpCode.Decompiler.IL
get { return this.right; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.right, value);
SetChildInstruction(ref this.right, value, 1);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.left;
yield return this.right;
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.left;
case 1:
return this.right;
default:
throw new IndexOutOfRangeException();
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
}
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Left = this.left.AcceptVisitor(visitor);
this.Right = this.right.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Left = value;
break;
case 1:
this.Right = value;
break;
default:
throw new IndexOutOfRangeException();
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Right = this.right.Inline(flagsBefore | ((this.left.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), context);
this.Left = this.left.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Left.TransformStackIntoVariables(state);
Right.TransformStackIntoVariables(state);
@ -345,17 +376,31 @@ namespace ICSharpCode.Decompiler.IL @@ -345,17 +376,31 @@ namespace ICSharpCode.Decompiler.IL
get { return this.body; }
set {
ValidateChild(value);
SetChildInstruction(ref this.body, value);
SetChildInstruction(ref this.body, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.body;
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.body;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Body = this.body.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Body = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
public override StackType ResultType { get { return StackType.O; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
@ -570,7 +615,7 @@ namespace ICSharpCode.Decompiler.IL @@ -570,7 +615,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.condition; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.condition, value);
SetChildInstruction(ref this.condition, value, 0);
}
}
ILInstruction trueInst;
@ -578,7 +623,7 @@ namespace ICSharpCode.Decompiler.IL @@ -578,7 +623,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.trueInst; }
set {
ValidateChild(value);
SetChildInstruction(ref this.trueInst, value);
SetChildInstruction(ref this.trueInst, value, 1);
}
}
ILInstruction falseInst;
@ -586,21 +631,41 @@ namespace ICSharpCode.Decompiler.IL @@ -586,21 +631,41 @@ namespace ICSharpCode.Decompiler.IL
get { return this.falseInst; }
set {
ValidateChild(value);
SetChildInstruction(ref this.falseInst, value);
SetChildInstruction(ref this.falseInst, value, 2);
}
}
protected sealed override int GetChildCount()
{
return 3;
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.condition;
yield return this.trueInst;
yield return this.falseInst;
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.condition;
case 1:
return this.trueInst;
case 2:
return this.falseInst;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Condition = this.condition.AcceptVisitor(visitor);
this.TrueInst = this.trueInst.AcceptVisitor(visitor);
this.FalseInst = this.falseInst.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Condition = value;
break;
case 1:
this.TrueInst = value;
break;
case 2:
this.FalseInst = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
@ -633,7 +698,7 @@ namespace ICSharpCode.Decompiler.IL @@ -633,7 +698,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.filter; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.filter, value);
SetChildInstruction(ref this.filter, value, 0);
}
}
ILInstruction body;
@ -641,19 +706,36 @@ namespace ICSharpCode.Decompiler.IL @@ -641,19 +706,36 @@ namespace ICSharpCode.Decompiler.IL
get { return this.body; }
set {
ValidateChild(value);
SetChildInstruction(ref this.body, value);
SetChildInstruction(ref this.body, value, 1);
}
}
protected sealed override int GetChildCount()
{
return 2;
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.filter;
yield return this.body;
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.filter;
case 1:
return this.body;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Filter = this.filter.AcceptVisitor(visitor);
this.Body = this.body.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Filter = value;
break;
case 1:
this.Body = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary>
@ -881,24 +963,38 @@ namespace ICSharpCode.Decompiler.IL @@ -881,24 +963,38 @@ namespace ICSharpCode.Decompiler.IL
get { return this.value; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.value, value);
SetChildInstruction(ref this.value, value, 0);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.value;
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Value = this.value.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Value = this.value.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Value.TransformStackIntoVariables(state);
}
@ -1187,24 +1283,38 @@ namespace ICSharpCode.Decompiler.IL @@ -1187,24 +1283,38 @@ namespace ICSharpCode.Decompiler.IL
get { return this.target; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.target, value);
SetChildInstruction(ref this.target, value, 0);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.target;
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Target = this.target.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Target = value;
break;
default:
throw new IndexOutOfRangeException();
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
@ -1252,24 +1362,38 @@ namespace ICSharpCode.Decompiler.IL @@ -1252,24 +1362,38 @@ namespace ICSharpCode.Decompiler.IL
get { return this.target; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.target, value);
SetChildInstruction(ref this.target, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.target;
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Target = this.target.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Target = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
@ -1310,7 +1434,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1310,7 +1434,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.target; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.target, value);
SetChildInstruction(ref this.target, value, 0);
}
}
ILInstruction value;
@ -1318,27 +1442,44 @@ namespace ICSharpCode.Decompiler.IL @@ -1318,27 +1442,44 @@ namespace ICSharpCode.Decompiler.IL
get { return this.value; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.value, value);
SetChildInstruction(ref this.value, value, 1);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.target;
yield return this.value;
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
case 1:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Target = this.target.AcceptVisitor(visitor);
this.Value = this.value.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Target = value;
break;
case 1:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Value = this.value.Inline(flagsBefore | ((this.target.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), context);
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
Value.TransformStackIntoVariables(state);
@ -1447,24 +1588,38 @@ namespace ICSharpCode.Decompiler.IL @@ -1447,24 +1588,38 @@ namespace ICSharpCode.Decompiler.IL
get { return this.value; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.value, value);
SetChildInstruction(ref this.value, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.value;
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.value;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Value = this.value.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Value = this.value.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Value.TransformStackIntoVariables(state);
}
@ -1568,24 +1723,38 @@ namespace ICSharpCode.Decompiler.IL @@ -1568,24 +1723,38 @@ namespace ICSharpCode.Decompiler.IL
get { return this.target; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.target, value);
SetChildInstruction(ref this.target, value, 0);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.target;
protected sealed override int GetChildCount()
{
return 1;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Target = this.target.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Target = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
@ -1634,7 +1803,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1634,7 +1803,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.target; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.target, value);
SetChildInstruction(ref this.target, value, 0);
}
}
ILInstruction value;
@ -1642,27 +1811,44 @@ namespace ICSharpCode.Decompiler.IL @@ -1642,27 +1811,44 @@ namespace ICSharpCode.Decompiler.IL
get { return this.value; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.value, value);
SetChildInstruction(ref this.value, value, 1);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.target;
yield return this.value;
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
case 1:
return this.value;
default:
throw new IndexOutOfRangeException();
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
}
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Target = this.target.AcceptVisitor(visitor);
this.Value = this.value.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Target = value;
break;
case 1:
this.Value = value;
break;
default:
throw new IndexOutOfRangeException();
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Value = this.value.Inline(flagsBefore | ((this.target.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), context);
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
Value.TransformStackIntoVariables(state);
@ -1921,24 +2107,38 @@ namespace ICSharpCode.Decompiler.IL @@ -1921,24 +2107,38 @@ namespace ICSharpCode.Decompiler.IL
get { return this.target; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.target, value);
SetChildInstruction(ref this.target, value, 0);
}
}
protected sealed override int GetChildCount()
{
return 1;
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.target;
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.target;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Target = this.target.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Target = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Target.TransformStackIntoVariables(state);
}
@ -1974,7 +2174,7 @@ namespace ICSharpCode.Decompiler.IL @@ -1974,7 +2174,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.array; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.array, value);
SetChildInstruction(ref this.array, value, 0);
}
}
ILInstruction index;
@ -1982,27 +2182,44 @@ namespace ICSharpCode.Decompiler.IL @@ -1982,27 +2182,44 @@ namespace ICSharpCode.Decompiler.IL
get { return this.index; }
set {
ValidateArgument(value);
SetChildInstruction(ref this.index, value);
SetChildInstruction(ref this.index, value, 1);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.array;
yield return this.index;
protected sealed override int GetChildCount()
{
return 2;
}
protected sealed override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return this.array;
case 1:
return this.index;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected sealed override void SetChild(int index, ILInstruction value)
{
this.Array = this.array.AcceptVisitor(visitor);
this.Index = this.index.AcceptVisitor(visitor);
switch (index) {
case 0:
this.Array = value;
break;
case 1:
this.Index = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Index = this.index.Inline(flagsBefore | ((this.array.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), context);
this.Array = this.array.Inline(flagsBefore, context);
return this;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
{
Array.TransformStackIntoVariables(state);
Index.TransformStackIntoVariables(state);

48
ICSharpCode.Decompiler/IL/Instructions.tt

@ -539,28 +539,49 @@ namespace ICSharpCode.Decompiler.IL @@ -539,28 +539,49 @@ namespace ICSharpCode.Decompiler.IL
+ "\tset {" + Environment.NewLine
+ (children[i].IsOptional ? "\t\tif (value != null)" + Environment.NewLine + "\t" : "")
+ "\t\t" + (children[i].IsArgument ? "ValidateArgument" : "ValidateChild") + "(value);" + Environment.NewLine
+ "\t\tSetChildInstruction(ref this." + arg + ", value);" + Environment.NewLine
+ "\t\tSetChildInstruction(ref this." + arg + ", value, " + i + ");" + Environment.NewLine
+ "\t}" + Environment.NewLine
+ "}");
}
opCode.WriteArguments.Add("output.Write(')');");
StringBuilder b;
/*
b = new StringBuilder();
b.AppendLine("public override TAccumulate AggregateChildren<TSource, TAccumulate>(TAccumulate initial, ILVisitor<TSource> visitor, Func<TAccumulate, TSource, TAccumulate> func)");
b.AppendLine("protected sealed override int GetChildCount()");
b.AppendLine("{");
b.AppendLine("\tTAccumulate value = initial;");
foreach (var child in children) {
if (child.IsOptional) {
b.AppendLine("\tif (this." + child.Name + " != null)");
b.Append('\t');
b.AppendLine("\treturn " + children.Length + ";");
b.Append("}");
opCode.Members.Add(b.ToString());
b = new StringBuilder();
b.AppendLine("protected sealed override ILInstruction GetChild(int index)");
b.AppendLine("{");
b.AppendLine("\tswitch (index) {");
for (int i = 0; i < children.Length; i++) {
b.AppendLine("\t\tcase " + i + ":");
b.AppendLine("\t\t\treturn this." + children[i].Name + ";");
}
b.AppendLine("\tvalue = func(value, this." + child.Name + ".AcceptVisitor(visitor));");
b.AppendLine("\t\tdefault:");
b.AppendLine("\t\t\tthrow new IndexOutOfRangeException();");
b.AppendLine("\t}");
b.Append("}");
opCode.Members.Add(b.ToString());
b = new StringBuilder();
b.AppendLine("protected sealed override void SetChild(int index, ILInstruction value)");
b.AppendLine("{");
b.AppendLine("\tswitch (index) {");
for (int i = 0; i < children.Length; i++) {
b.AppendLine("\t\tcase " + i + ":");
b.AppendLine("\t\t\tthis." + children[i].PropertyName + " = value;");
b.AppendLine("\t\t\tbreak;");
}
b.AppendLine("\treturn value;");
b.AppendLine("\t\tdefault:");
b.AppendLine("\t\t\tthrow new IndexOutOfRangeException();");
b.AppendLine("\t}");
b.Append("}");
opCode.Members.Add(b.ToString());*/
opCode.Members.Add(b.ToString());
/*
b = new StringBuilder();
b.AppendLine("public override IEnumerable<ILInstruction> Children {");
b.AppendLine("\tget {");
@ -587,9 +608,10 @@ namespace ICSharpCode.Decompiler.IL @@ -587,9 +608,10 @@ namespace ICSharpCode.Decompiler.IL
}
b.Append("}");
opCode.Members.Add(b.ToString());
*/
if (generateInline) {
b = new StringBuilder();
b.AppendLine("internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)");
b.AppendLine("internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)");
b.AppendLine("{");
for (int i = children.Length - 1; i >= 0; i--) {
string arg = children[i].Name;
@ -609,7 +631,7 @@ namespace ICSharpCode.Decompiler.IL @@ -609,7 +631,7 @@ namespace ICSharpCode.Decompiler.IL
b.Append("}");
opCode.Members.Add(b.ToString());
b.Clear();
b.AppendLine("internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)");
b.AppendLine("internal sealed override void TransformStackIntoVariables(TransformStackIntoVariablesState state)");
b.AppendLine("{");
for (int i = 0; i < children.Length; i++) {
string arg = children[i].Name;

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

@ -69,27 +69,7 @@ namespace ICSharpCode.Decompiler.IL @@ -69,27 +69,7 @@ namespace ICSharpCode.Decompiler.IL
/// This variable is automatically updated when adding/removing branch instructions from the ILAst,
/// or when adding the block as an entry point to a BlockContainer.
/// </remarks>
public int IncomingEdgeCount;
/// <summary>
/// Returns the index of the block in the parent BlockContainer's block list.
/// Returns 0 if the block is not in a BlockContainer.
/// </summary>
public int Index {
get {
// TODO: we can offer this in O(1) by making the
// parent BlockContainer store this in the blocks,
// but I'm not sure if it's worth the complexity.
// We'll have to see if the Index is useful in more than a few places.
// (otherwise those few places could use a Dictionary<Block, int>)
var bc = Parent as BlockContainer;
if (bc != null) {
return bc.Blocks.IndexOf(this);
} else {
return 0;
}
}
}
public int IncomingEdgeCount { get; internal set; }
public ILInstruction FinalInstruction {
get {
@ -97,14 +77,20 @@ namespace ICSharpCode.Decompiler.IL @@ -97,14 +77,20 @@ namespace ICSharpCode.Decompiler.IL
}
set {
ValidateChild(value);
SetChildInstruction(ref finalInstruction, value);
SetChildInstruction(ref finalInstruction, value, Instructions.Count);
}
}
protected internal override void InstructionCollectionUpdateComplete()
{
base.InstructionCollectionUpdateComplete();
if (finalInstruction.Parent == this)
finalInstruction.ChildIndex = Instructions.Count;
}
public Block() : base(OpCode.Block)
{
this.Instructions = new InstructionCollection<ILInstruction>(this);
this.Instructions = new InstructionCollection<ILInstruction>(this, 0);
this.FinalInstruction = new Nop();
}
@ -143,20 +129,24 @@ namespace ICSharpCode.Decompiler.IL @@ -143,20 +129,24 @@ namespace ICSharpCode.Decompiler.IL
output.Write("}");
}
public override IEnumerable<ILInstruction> Children {
get {
foreach (var inst in Instructions)
yield return inst;
yield return finalInstruction;
}
protected override int GetChildCount()
{
return Instructions.Count + 1;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected override ILInstruction GetChild(int index)
{
for (int i = 0; i < Instructions.Count; i++) {
Instructions[i] = Instructions[i].AcceptVisitor(visitor);
if (index == Instructions.Count)
return finalInstruction;
return Instructions[index];
}
FinalInstruction = FinalInstruction.AcceptVisitor(visitor);
protected override void SetChild(int index, ILInstruction value)
{
if (index == Instructions.Count)
FinalInstruction = value;
else
Instructions[index] = value;
}
protected override InstructionFlags ComputeFlags()

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

@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.IL @@ -55,7 +55,7 @@ namespace ICSharpCode.Decompiler.IL
public BlockContainer() : base(OpCode.BlockContainer)
{
this.Blocks = new InstructionCollection<Block>(this);
this.Blocks = new InstructionCollection<Block>(this, 0);
}
protected internal override void InstructionCollectionUpdateComplete()
@ -91,17 +91,20 @@ namespace ICSharpCode.Decompiler.IL @@ -91,17 +91,20 @@ namespace ICSharpCode.Decompiler.IL
output.Write("}");
}
public override IEnumerable<ILInstruction> Children {
get { return Blocks; }
protected override int GetChildCount()
{
return Blocks.Count;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected override ILInstruction GetChild(int index)
{
foreach (var block in Blocks) {
// Recurse into the blocks, but don't allow replacing the block
if (block.AcceptVisitor(visitor) != block)
throw new InvalidOperationException("Cannot replace blocks in BlockContainer");
return Blocks[index];
}
protected override void SetChild(int index, ILInstruction value)
{
if (Blocks[index] != value)
throw new InvalidOperationException("Cannot replace blocks in BlockContainer");
}
internal override void CheckInvariant()

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

@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler.IL @@ -50,7 +50,7 @@ namespace ICSharpCode.Decompiler.IL
{
Debug.Assert(method != null);
this.Method = method;
this.Arguments = new InstructionCollection<ILInstruction>(this);
this.Arguments = new InstructionCollection<ILInstruction>(this, 0);
}
public override StackType ResultType {
@ -62,15 +62,19 @@ namespace ICSharpCode.Decompiler.IL @@ -62,15 +62,19 @@ namespace ICSharpCode.Decompiler.IL
}
}
public override IEnumerable<ILInstruction> Children {
get { return Arguments; }
protected override int GetChildCount()
{
return Arguments.Count;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected override ILInstruction GetChild(int index)
{
for (int i = 0; i < Arguments.Count; i++) {
Arguments[i] = Arguments[i].AcceptVisitor(visitor);
return Arguments[index];
}
protected override void SetChild(int index, ILInstruction value)
{
Arguments[index] = value;
}
protected override InstructionFlags ComputeFlags()

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

@ -59,6 +59,7 @@ namespace ICSharpCode.Decompiler.IL @@ -59,6 +59,7 @@ namespace ICSharpCode.Decompiler.IL
{
foreach (var child in Children) {
Debug.Assert(child.Parent == this);
Debug.Assert(this.GetChild(child.ChildIndex) == child);
// if child flags are invalid, parent flags must be too
Debug.Assert(child.flags != invalidFlags || this.flags == invalidFlags);
Debug.Assert(child.IsConnected == this.IsConnected);
@ -146,12 +147,110 @@ namespace ICSharpCode.Decompiler.IL @@ -146,12 +147,110 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>
/// Gets the child nodes of this instruction.
/// </summary>
public abstract IEnumerable<ILInstruction> Children { get; }
public ChildrenCollection Children {
get {
return new ChildrenCollection(this);
}
}
protected abstract int GetChildCount();
protected abstract ILInstruction GetChild(int index);
protected abstract void SetChild(int index, ILInstruction value);
#region ChildrenCollection + ChildrenEnumerator
public struct ChildrenCollection : IReadOnlyList<ILInstruction>
{
readonly ILInstruction inst;
internal ChildrenCollection(ILInstruction inst)
{
Debug.Assert(inst != null);
this.inst = inst;
}
public int Count {
get { return inst.GetChildCount(); }
}
public ILInstruction this[int index] {
get { return inst.GetChild(index); }
}
public ChildrenEnumerator GetEnumerator()
{
return new ChildrenEnumerator(inst);
}
IEnumerator<ILInstruction> IEnumerable<ILInstruction>.GetEnumerator()
{
return GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public struct ChildrenEnumerator : IEnumerator<ILInstruction>
{
readonly ILInstruction inst;
readonly int end;
int pos;
public ChildrenEnumerator(ILInstruction inst)
{
Debug.Assert(inst != null);
this.inst = inst;
this.pos = -1;
this.end = inst.GetChildCount();
}
public ILInstruction Current {
get {
return inst.GetChild(pos);
}
}
public bool MoveNext()
{
return ++pos < end;
}
public void Dispose()
{
}
object System.Collections.IEnumerator.Current {
get { return this.Current; }
}
void System.Collections.IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
#endregion
/// <summary>
/// Transforms the children of this instruction by applying the specified visitor.
/// </summary>
public abstract void TransformChildren(ILVisitor<ILInstruction> visitor);
[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)
{
parent.SetChild(ChildIndex, replacement);
}
/// <summary>
/// Returns all descendants of the ILInstruction.
@ -206,16 +305,25 @@ namespace ICSharpCode.Decompiler.IL @@ -206,16 +305,25 @@ namespace ICSharpCode.Decompiler.IL
}
}
/// <summary>
/// Gets whether this ILInstruction is connected to the root node of the ILAst.
/// </summary>
protected bool IsConnected {
get { return refCount > 0; }
}
/// <summary>
/// Called after the ILInstruction was connected to the root node of the ILAst.
/// </summary>
protected virtual void Connected()
{
foreach (var child in Children)
child.AddRef();
}
/// <summary>
/// Called after the ILInstruction was disconnected from the root node of the ILAst.
/// </summary>
protected virtual void Disconnected()
{
foreach (var child in Children)
@ -231,19 +339,37 @@ namespace ICSharpCode.Decompiler.IL @@ -231,19 +339,37 @@ namespace ICSharpCode.Decompiler.IL
get { return parent; }
}
protected void SetChildInstruction(ref ILInstruction childPointer, ILInstruction newValue)
/// <summary>
/// Gets the index of this node in the Parent.Children collection.
/// </summary>
public int ChildIndex { get; internal set; }
/// <summary>
/// Replaces a child of this ILInstruction.
/// </summary>
/// <param name="childPointer">Reference to the field holding the child</param>
/// <param name="newValue">New child</param>
/// <param name="index">Index of the field in the Children collection</param>
protected internal void SetChildInstruction(ref ILInstruction childPointer, ILInstruction newValue, int index)
{
if (childPointer == newValue)
ILInstruction oldValue = childPointer;
Debug.Assert(this is Return || oldValue == GetChild(index));
if (oldValue == newValue)
return;
childPointer = newValue;
if (newValue != null) {
newValue.parent = this;
newValue.ChildIndex = index;
}
if (refCount > 0) {
// The new value may be a subtree of the old value.
// We first call AddRef(), then ReleaseRef() to prevent the subtree
// that stays connected from receiving a Disconnected() notification followed by a Connected() notification.
if (newValue != null)
newValue.AddRef();
childPointer.ReleaseRef();
if (oldValue != null)
oldValue.ReleaseRef();
}
childPointer = newValue;
newValue.parent = this;
InvalidateFlags();
}
@ -252,18 +378,19 @@ namespace ICSharpCode.Decompiler.IL @@ -252,18 +378,19 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
protected internal void InstructionCollectionAdded(ILInstruction newChild)
{
Debug.Assert(GetChild(newChild.ChildIndex) == newChild);
newChild.parent = this;
if (refCount > 0)
newChild.AddRef();
newChild.parent = this;
}
/// <summary>
/// Called when a child is removed from a InstructionCollection.
/// </summary>
protected internal void InstructionCollectionRemoved(ILInstruction newChild)
protected internal void InstructionCollectionRemoved(ILInstruction oldChild)
{
if (refCount > 0)
newChild.ReleaseRef();
oldChild.ReleaseRef();
}
/// <summary>

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

@ -19,74 +19,219 @@ @@ -19,74 +19,219 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
namespace ICSharpCode.Decompiler.IL
{
public sealed class InstructionCollection<T> : Collection<T> where T : ILInstruction
public sealed class InstructionCollection<T> : IList<T> where T : ILInstruction
{
readonly ILInstruction parentInstruction;
readonly int firstChildIndex;
readonly List<T> list = new List<T>();
public InstructionCollection(ILInstruction parentInstruction)
public InstructionCollection(ILInstruction parentInstruction, int firstChildIndex)
{
if (parentInstruction == null)
throw new ArgumentNullException("parentInstruction");
this.parentInstruction = parentInstruction;
this.firstChildIndex = firstChildIndex;
}
protected override void ClearItems()
public int Count {
get { return list.Count; }
}
public T this[int index] {
get { return list[index]; }
set {
T oldValue = list[index];
if (oldValue != value) {
list[index] = value;
value.ChildIndex = index + firstChildIndex;
parentInstruction.InstructionCollectionAdded(value);
parentInstruction.InstructionCollectionRemoved(oldValue);
parentInstruction.InstructionCollectionUpdateComplete();
}
}
}
public List<T>.Enumerator GetEnumerator()
{
return list.GetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return list.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return list.GetEnumerator();
}
/// <summary>
/// Gets the index of the instruction in this collection.
/// Returns -1 if the instruction does not exist in the collection.
/// </summary>
/// <remarks>
/// Runs in O(1) is the item can be found using the Parent/ChildIndex properties.
/// Otherwise, runs in O(N).
/// </remarks>
public int IndexOf(T item)
{
// If this collection is the item's primary location, we can use ChildIndex:
int index = item.ChildIndex - firstChildIndex;
if (index >= 0 && index <= list.Count && list[index] == item)
return index;
// But we still need to fall back on a full search, because the ILAst might be
// in a state where item is in multiple locations.
return list.IndexOf(item);
}
/// <summary>
/// Gets whether the item is in this collection.
/// </summary>
/// <remarks>
/// This method searches the list.
/// Usually it's more efficient to test item.Parent instead!
/// </remarks>
public bool Contains(T item)
{
return IndexOf(item) >= 0;
}
void ICollection<T>.CopyTo(T[] array, int arrayIndex)
{
foreach (var child in this)
parentInstruction.InstructionCollectionRemoved(child);
base.ClearItems();
list.CopyTo(array, arrayIndex);
}
bool ICollection<T>.IsReadOnly {
get { return false; }
}
public void Add(T value)
{
value.ChildIndex = list.Count + firstChildIndex;
list.Add(value);
parentInstruction.InstructionCollectionAdded(value);
parentInstruction.InstructionCollectionUpdateComplete();
}
protected override void InsertItem(int index, T item)
public void AddRange(IEnumerable<T> values)
{
if (item == null)
throw new ArgumentNullException("item");
parentInstruction.InstructionCollectionAdded(item);
base.InsertItem(index, item);
foreach (T value in values) {
value.ChildIndex = list.Count + firstChildIndex;
list.Add(value);
parentInstruction.InstructionCollectionAdded(value);
}
parentInstruction.InstructionCollectionUpdateComplete();
}
protected override void RemoveItem(int index)
/// <summary>
/// Replaces all entries in the InstructionCollection with the newList.
/// </summary>
/// <remarks>
/// Equivalent to Clear() followed by AddRange(newList), but slightly more efficient.
/// </remarks>
public void ReplaceList(IEnumerable<T> newList)
{
parentInstruction.InstructionCollectionRemoved(this[index]);
base.RemoveItem(index);
int index = 0;
foreach (T value in newList) {
value.ChildIndex = index + firstChildIndex;
if (index < list.Count) {
T oldValue = list[index];
list[index] = value;
parentInstruction.InstructionCollectionAdded(value);
parentInstruction.InstructionCollectionRemoved(oldValue);
} else {
list.Add(value);
parentInstruction.InstructionCollectionAdded(value);
}
index++;
}
for (int i = index; i < list.Count; i++) {
parentInstruction.InstructionCollectionRemoved(list[i]);
}
list.RemoveRange(index, list.Count - index);
parentInstruction.InstructionCollectionUpdateComplete();
}
protected override void SetItem(int index, T item)
public void Insert(int index, T item)
{
if (item == null)
throw new ArgumentNullException("item");
if (this[index] == item)
return;
parentInstruction.InstructionCollectionRemoved(this[index]);
list.Insert(index, item);
item.ChildIndex = index;
parentInstruction.InstructionCollectionAdded(item);
base.SetItem(index, item);
for (int i = index + 1; i < list.Count; i++) {
T other_item = list[i];
// Update ChildIndex of items after the inserted one, but only if
// that's their 'primary position' (in case of multiple parents)
if (other_item.Parent == parentInstruction && other_item.ChildIndex == i + firstChildIndex - 1)
other_item.ChildIndex = i + firstChildIndex;
}
parentInstruction.InstructionCollectionUpdateComplete();
}
public int RemoveAll(Predicate<T> predicate)
public void RemoveAt(int index)
{
// TODO: optimize
int removed = 0;
for (int i = 0; i < this.Count;) {
if (predicate(this[i])) {
RemoveAt(i);
removed++;
} else {
i++;
parentInstruction.InstructionCollectionRemoved(list[index]);
list.RemoveAt(index);
for (int i = index; i < list.Count; i++) {
var other_item = list[i];
if (other_item.Parent == parentInstruction && other_item.ChildIndex == i + firstChildIndex + 1)
other_item.ChildIndex = i + firstChildIndex;
}
parentInstruction.InstructionCollectionUpdateComplete();
}
return removed;
public void Clear()
{
foreach (var entry in list) {
parentInstruction.InstructionCollectionRemoved(entry);
}
list.Clear();
parentInstruction.InstructionCollectionUpdateComplete();
}
public void ReplaceList(IEnumerable<T> newList)
public bool Remove(T item)
{
int index = IndexOf(item);
if (index >= 0) {
RemoveAt(index);
return true;
}
return false;
}
/// <summary>
/// Removes all elements for which the predicate returns true.
/// </summary>
/// <remarks>
/// This method runs in O(N), which is more efficient than calling RemoveAt() in a loop.
/// The collection may be in an invalid state during the invocation of the predicate.
/// </remarks>
public int RemoveAll(Predicate<T> predicate)
{
Clear();
this.AddRange(newList);
int j = 0;
for (int i = 0; i < list.Count; i++) {
T item = list[i];
if (predicate(item)) {
parentInstruction.InstructionCollectionRemoved(item);
} else {
// keep the item
if (item.Parent == parentInstruction && item.ChildIndex == i + firstChildIndex)
item.ChildIndex = j + firstChildIndex;
list[j] = item;
j++;
}
}
int removed = list.Count - j;
if (removed > 0) {
list.RemoveRange(j, removed);
parentInstruction.InstructionCollectionUpdateComplete();
}
return removed;
}
}
}

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

@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL @@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL
set {
if (value != null)
ValidateArgument(value);
SetChildInstruction(ref returnValue, value);
SetChildInstruction(ref returnValue, value, 0);
}
}
@ -66,17 +66,25 @@ namespace ICSharpCode.Decompiler.IL @@ -66,17 +66,25 @@ namespace ICSharpCode.Decompiler.IL
}
}
public override IEnumerable<ILInstruction> Children {
get {
if (returnValue != null)
yield return returnValue;
protected override int GetChildCount()
{
return returnValue != null ? 1 : 0;
}
protected override ILInstruction GetChild(int index)
{
if (index == 0 && returnValue != null)
return returnValue;
else
throw new IndexOutOfRangeException();
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected override void SetChild(int index, ILInstruction value)
{
if (returnValue != null)
this.ReturnValue = returnValue.AcceptVisitor(visitor);
if (index == 0 && returnValue != null)
ReturnValue = value;
else
throw new IndexOutOfRangeException();
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)

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

@ -39,14 +39,19 @@ namespace ICSharpCode.Decompiler.IL @@ -39,14 +39,19 @@ namespace ICSharpCode.Decompiler.IL
output.Write(OpCode);
}
public sealed override IEnumerable<ILInstruction> Children {
get {
return EmptyList<ILInstruction>.Instance;
protected override int GetChildCount()
{
return 0;
}
protected override ILInstruction GetChild(int index)
{
throw new IndexOutOfRangeException();
}
public sealed override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected override void SetChild(int index, ILInstruction value)
{
throw new IndexOutOfRangeException();
}
protected override InstructionFlags ComputeFlags()

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

@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL @@ -34,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.tryBlock; }
set {
ValidateChild(value);
SetChildInstruction(ref this.tryBlock, value);
SetChildInstruction(ref this.tryBlock, value, 0);
}
}
@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.IL @@ -61,7 +61,7 @@ namespace ICSharpCode.Decompiler.IL
public TryCatch(ILInstruction tryBlock) : base(OpCode.TryCatch, tryBlock)
{
this.Handlers = new InstructionCollection<TryCatchHandler>(this);
this.Handlers = new InstructionCollection<TryCatchHandler>(this, 1);
}
public override void WriteTo(ITextOutput output)
@ -86,21 +86,25 @@ namespace ICSharpCode.Decompiler.IL @@ -86,21 +86,25 @@ namespace ICSharpCode.Decompiler.IL
return flags;
}
public override IEnumerable<ILInstruction> Children {
get {
yield return TryBlock;
foreach (var handler in Handlers)
yield return handler;
}
protected override int GetChildCount()
{
return 1 + Handlers.Count;
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected override ILInstruction GetChild(int index)
{
this.TryBlock = TryBlock.AcceptVisitor(visitor);
for (int i = 0; i < Handlers.Count; i++) {
if (Handlers[i].AcceptVisitor(visitor) != Handlers[i])
throw new InvalidOperationException("Cannot transform a TryCatchHandler");
if (index == 0)
return TryBlock;
else
return Handlers[index - 1];
}
protected override void SetChild(int index, ILInstruction value)
{
if (index == 0)
TryBlock = value;
else
Handlers[index - 1] = (TryCatchHandler)value;
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
@ -189,7 +193,7 @@ namespace ICSharpCode.Decompiler.IL @@ -189,7 +193,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.finallyBlock; }
set {
ValidateChild(value);
SetChildInstruction(ref this.finallyBlock, value);
SetChildInstruction(ref this.finallyBlock, value, 1);
}
}
@ -213,17 +217,35 @@ namespace ICSharpCode.Decompiler.IL @@ -213,17 +217,35 @@ namespace ICSharpCode.Decompiler.IL
return Block.Phase1Boundary(TryBlock.Flags) | Block.Phase1Boundary(finallyBlock.Flags);
}
public override IEnumerable<ILInstruction> Children {
get {
yield return TryBlock;
yield return finallyBlock;
protected override int GetChildCount()
{
return 2;
}
protected override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return TryBlock;
case 1:
return finallyBlock;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected override void SetChild(int index, ILInstruction value)
{
this.TryBlock = TryBlock.AcceptVisitor(visitor);
this.FinallyBlock = finallyBlock.AcceptVisitor(visitor);
switch (index) {
case 0:
TryBlock = value;
break;
case 1:
FinallyBlock = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)
@ -244,7 +266,7 @@ namespace ICSharpCode.Decompiler.IL @@ -244,7 +266,7 @@ namespace ICSharpCode.Decompiler.IL
get { return this.faultBlock; }
set {
ValidateChild(value);
SetChildInstruction(ref this.faultBlock, value);
SetChildInstruction(ref this.faultBlock, value, 1);
}
}
@ -266,17 +288,35 @@ namespace ICSharpCode.Decompiler.IL @@ -266,17 +288,35 @@ namespace ICSharpCode.Decompiler.IL
return IfInstruction.CombineFlags(Block.Phase1Boundary(TryBlock.Flags), Block.Phase1Boundary(faultBlock.Flags));
}
public override IEnumerable<ILInstruction> Children {
get {
yield return TryBlock;
yield return faultBlock;
protected override int GetChildCount()
{
return 2;
}
protected override ILInstruction GetChild(int index)
{
switch (index) {
case 0:
return TryBlock;
case 1:
return faultBlock;
default:
throw new IndexOutOfRangeException();
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
protected override void SetChild(int index, ILInstruction value)
{
this.TryBlock = TryBlock.AcceptVisitor(visitor);
this.FaultBlock = faultBlock.AcceptVisitor(visitor);
switch (index) {
case 0:
TryBlock = value;
break;
case 1:
FaultBlock = value;
break;
default:
throw new IndexOutOfRangeException();
}
}
internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state)

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

@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
var sourceNode = nodes[i];
foreach (var branch in block.Descendants.OfType<Branch>()) {
if (branch.TargetBlock.Parent == bc) {
sourceNode.AddEdgeTo(nodes[branch.TargetBlock.Index]);
sourceNode.AddEdgeTo(nodes[bc.Blocks.IndexOf(branch.TargetBlock)]);
} else {
// Note: edges into different block containers are ignored:
// Either they point to a nested block container in the source block,

39
ICSharpCode.Decompiler/Tests/Loops.cs

@ -83,5 +83,44 @@ public class Loops @@ -83,5 +83,44 @@ public class Loops
}
}
}
public int MultipleExits()
{
int i = 0;
while (true) {
if (i % 4 == 0) { return 4; }
if (i % 7 == 0) { break; }
if (i % 9 == 0) { return 5; }
if (i % 11 == 0) { break; }
i++;
}
i = int.MinValue;
return i;
}
public int InterestingLoop()
{
int i = 0;
if (i % 11 == 0) {
while (true) {
if (i % 4 == 0) {
if (i % 7 == 0) {
if (i % 11 == 0) {
continue; // use a continue here to prevent moving the if (i%7) outside the loop
}
Console.WriteLine("7");
} else {
// this block is not part of the natural loop
Console.WriteLine("!7");
}
break;
}
i++;
}
// This instruction is still dominated by the loop header
i = int.MinValue;
}
return i;
}
}

Loading…
Cancel
Save