From f39b6f7672f27aa1371e40f5252102f2f48db2c3 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 22 Mar 2015 18:39:39 +0100 Subject: [PATCH] TransformStackIntoVariables for TryCatch --- .../CSharp/StatementBuilder.cs | 16 ++++++- .../IL/Instructions/TryInstruction.cs | 44 +++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index dde2acc1d..13a3c3d31 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -99,7 +99,8 @@ namespace ICSharpCode.Decompiler.CSharp return new BreakStatement(); string label; if (!endContainerLabels.TryGetValue(inst.TargetContainer, out label)) { - endContainerLabels.Add(inst.TargetContainer, "end_" + inst.TargetLabel); + label = "end_" + inst.TargetLabel; + endContainerLabels.Add(inst.TargetContainer, label); } return new GotoStatement(label); } @@ -208,6 +209,10 @@ namespace ICSharpCode.Decompiler.CSharp blockStatement.Add(new LabelStatement { Label = block.Label }); } foreach (var inst in block.Instructions) { + if (inst.OpCode == OpCode.Leave && IsFinalLeave((Leave)inst)) { + // skip the final 'leave' instruction and just fall out of the BlockStatement + continue; + } blockStatement.Add(Convert(inst)); } if (block.FinalInstruction.OpCode != OpCode.Nop) { @@ -220,5 +225,14 @@ namespace ICSharpCode.Decompiler.CSharp } return blockStatement; } + + static bool IsFinalLeave(Leave leave) + { + Block block = (Block)leave.Parent; + if (leave.ChildIndex != block.Instructions.Count - 1 || block.FinalInstruction.OpCode != OpCode.Nop) + return false; + BlockContainer container = (BlockContainer)block.Parent; + return block.ChildIndex == container.Blocks.Count - 1; + } } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs index 2e77753b4..53e38b19d 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs @@ -118,7 +118,19 @@ namespace ICSharpCode.Decompiler.IL internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state) { - throw new NotImplementedException(); + TryBlock = TryBlock.Inline(InstructionFlags.None, state); + TryBlock.TransformStackIntoVariables(state); + Stack variablesAfter = TryBlock.HasFlag(InstructionFlags.EndPointUnreachable) ? null : state.Variables.Clone(); + for (int i = 0; i < Handlers.Count; i++) { + Handlers[i].TransformStackIntoVariables(state); + if (!Handlers[i].HasFlag(InstructionFlags.EndPointUnreachable)) { + if (variablesAfter == null) + variablesAfter = state.Variables.Clone(); + else + state.MergeVariables(variablesAfter, state.Variables); + } + } + state.Variables = variablesAfter ?? new Stack(); } } @@ -160,6 +172,12 @@ namespace ICSharpCode.Decompiler.IL internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state) { + state.Variables.Clear(); + Filter = Filter.Inline(InstructionFlags.None, state); + Filter.TransformStackIntoVariables(state); + state.Variables.Clear(); + Body = Body.Inline(InstructionFlags.None, state); + Body.TransformStackIntoVariables(state); } public override void WriteTo(ITextOutput output) @@ -266,7 +284,13 @@ namespace ICSharpCode.Decompiler.IL internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state) { - throw new NotImplementedException(); + TryBlock = TryBlock.Inline(InstructionFlags.None, state); + TryBlock.TransformStackIntoVariables(state); + var variablesAfterTry = state.Variables; + state.Variables = new Stack(); + FinallyBlock = FinallyBlock.Inline(InstructionFlags.None, state); + FinallyBlock.TransformStackIntoVariables(state); + state.Variables = variablesAfterTry; } } @@ -344,7 +368,21 @@ namespace ICSharpCode.Decompiler.IL internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state) { - throw new NotImplementedException(); + TryBlock = TryBlock.Inline(InstructionFlags.None, state); + TryBlock.TransformStackIntoVariables(state); + var variablesAfterTry = state.Variables; + state.Variables = new Stack(); + FaultBlock = FaultBlock.Inline(InstructionFlags.None, state); + FaultBlock.TransformStackIntoVariables(state); + if (!TryBlock.HasFlag(InstructionFlags.EndPointUnreachable) && !FaultBlock.HasFlag(InstructionFlags.EndPointUnreachable)) { + // If end-points of both instructions are reachable, merge their states + state.MergeVariables(state.Variables, variablesAfterTry); + } + if (FaultBlock.HasFlag(InstructionFlags.EndPointUnreachable)) { + // If the end-point of FaultBlock is unreachable, continue with the end-state of TryBlock instead + // (if both are unreachable, it doesn't matter what we continue with) + state.Variables = variablesAfterTry; + } } } }