From 3db0e01eee2ea3b2c0847676ff4e55e470f7446c Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 21 Mar 2015 21:15:16 +0100 Subject: [PATCH] Handle 'leave' instruction in StatementBuilder --- .../CSharp/ExpressionBuilder.cs | 2 +- .../CSharp/StatementBuilder.cs | 23 +++++++++++++++++++ .../IL/Instructions/Block.cs | 5 ++-- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 0adc49150..f04ba50a8 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -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) diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index d5a9692ea..dde2acc1d 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -88,6 +88,22 @@ namespace ICSharpCode.Decompiler.CSharp return new GotoStatement(inst.TargetLabel); } + /// Target container that a 'break;' statement would break out of + BlockContainer breakTarget; + /// Dictionary from BlockContainer to label name for 'goto of_container'; + readonly Dictionary endContainerLabels = new Dictionary(); + + 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 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 } 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 blockStatement.Add(Convert(block.FinalInstruction)); } } + string label; + if (endContainerLabels.TryGetValue(container, out label)) { + blockStatement.Add(new LabelStatement { Label = label }); + } return blockStatement; } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/Block.cs b/ICSharpCode.Decompiler/IL/Instructions/Block.cs index 03edd5863..626c62c58 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Block.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Block.cs @@ -51,8 +51,9 @@ namespace ICSharpCode.Decompiler.IL /// /// /// - /// Fun fact: the empty block acts like a phase-2 pop instruction, - /// which is a slightly different behavior than the normal phase-1 instruction! + /// Fun fact: wrapping a pop instruction in a block + /// (new Block { FinalInstruction = popInst }) 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. ///