Browse Source

Handle 'leave' instruction in StatementBuilder

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
3db0e01eee
  1. 2
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  2. 23
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  3. 5
      ICSharpCode.Decompiler/IL/Instructions/Block.cs

2
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -172,7 +172,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -172,7 +172,7 @@ namespace ICSharpCode.Decompiler.CSharp
{
return new TypeOfExpression(ConvertType(inst.Type))
.WithILInstruction(inst)
.WithRR(new TypeOfResolveResult(compilation.FindType(KnownTypeCode.Type), inst.Type);
.WithRR(new TypeOfResolveResult(compilation.FindType(KnownTypeCode.Type), inst.Type));
}
protected internal override TranslatedExpression VisitLogicNot(LogicNot inst)

23
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -88,6 +88,22 @@ namespace ICSharpCode.Decompiler.CSharp @@ -88,6 +88,22 @@ namespace ICSharpCode.Decompiler.CSharp
return new GotoStatement(inst.TargetLabel);
}
/// <summary>Target container that a 'break;' statement would break out of</summary>
BlockContainer breakTarget;
/// <summary>Dictionary from BlockContainer to label name for 'goto of_container';</summary>
readonly Dictionary<BlockContainer, string> endContainerLabels = new Dictionary<BlockContainer, string>();
protected internal override Statement VisitLeave(Leave inst)
{
if (inst.TargetContainer == breakTarget)
return new BreakStatement();
string label;
if (!endContainerLabels.TryGetValue(inst.TargetContainer, out label)) {
endContainerLabels.Add(inst.TargetContainer, "end_" + inst.TargetLabel);
}
return new GotoStatement(label);
}
protected internal override Statement VisitThrow(Throw inst)
{
return new ThrowStatement(exprBuilder.Translate(inst.Argument));
@ -163,8 +179,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -163,8 +179,10 @@ namespace ICSharpCode.Decompiler.CSharp
if (container.EntryPoint.IncomingEdgeCount > 1) {
var oldContinueTarget = continueTarget;
var oldContinueCount = continueCount;
var oldBreakTarget = breakTarget;
continueTarget = container.EntryPoint;
continueCount = 0;
breakTarget = container;
var blockStatement = ConvertBlockContainer(container);
Debug.Assert(continueCount < container.EntryPoint.IncomingEdgeCount);
Debug.Assert(blockStatement.Statements.First() is LabelStatement);
@ -174,6 +192,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -174,6 +192,7 @@ namespace ICSharpCode.Decompiler.CSharp
}
continueTarget = oldContinueTarget;
continueCount = oldContinueCount;
breakTarget = oldBreakTarget;
return new WhileStatement(new PrimitiveExpression(true), blockStatement);
} else {
return ConvertBlockContainer(container);
@ -195,6 +214,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -195,6 +214,10 @@ namespace ICSharpCode.Decompiler.CSharp
blockStatement.Add(Convert(block.FinalInstruction));
}
}
string label;
if (endContainerLabels.TryGetValue(container, out label)) {
blockStatement.Add(new LabelStatement { Label = label });
}
return blockStatement;
}
}

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

@ -51,8 +51,9 @@ namespace ICSharpCode.Decompiler.IL @@ -51,8 +51,9 @@ namespace ICSharpCode.Decompiler.IL
/// </para>
/// </summary>
/// <remarks>
/// Fun fact: the empty block acts like a phase-2 pop instruction,
/// which is a slightly different behavior than the normal phase-1 <see cref="Pop"/> instruction!
/// Fun fact: wrapping a pop instruction in a block
/// (<c>new Block { FinalInstruction = popInst }</c>) turns it
/// from a phase-1 pop instruction to a phase-2 pop instruction.
/// However, this is just of theoretical interest; we currently don't plan to use inline blocks that
/// pop elements that they didn't push themselves.
/// </remarks>

Loading…
Cancel
Save