Browse Source

Eliminate goto in conditional return in try block.

pull/728/merge
Daniel Grunwald 9 years ago
parent
commit
dd485b971d
  1. 16
      ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs
  2. 1
      ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs
  3. 3
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  4. 1
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  5. 6
      ICSharpCode.Decompiler/Tests/PrettyTestRunner.cs
  6. 40
      ICSharpCode.Decompiler/Tests/TestCases/Pretty/ExceptionHandling.cs
  7. 2
      NRefactory

16
ICSharpCode.Decompiler/IL/ControlFlow/ConditionDetection.cs

@ -190,7 +190,8 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
if (ifInst.FalseInst.OpCode != OpCode.Nop && ifInst.FalseInst.ILRange.Start < ifInst.TrueInst.ILRange.Start if (ifInst.FalseInst.OpCode != OpCode.Nop && ifInst.FalseInst.ILRange.Start < ifInst.TrueInst.ILRange.Start
|| ifInst.TrueInst.OpCode == OpCode.Nop) { || ifInst.TrueInst.OpCode == OpCode.Nop) {
// swap true and false branches of if, to bring them in the same order as the IL code // swap true and false branches of if/else construct,
// to bring them in the same order as the IL code
var oldTrue = ifInst.TrueInst; var oldTrue = ifInst.TrueInst;
ifInst.TrueInst = ifInst.FalseInst; ifInst.TrueInst = ifInst.FalseInst;
ifInst.FalseInst = oldTrue; ifInst.FalseInst = oldTrue;
@ -210,10 +211,21 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
bool IsBranchToLaterTarget(ILInstruction inst1, ILInstruction inst2) bool IsBranchToLaterTarget(ILInstruction inst1, ILInstruction inst2)
{ {
Block block1, block2; Block block1 = null, block2 = null;
if (inst1.MatchBranch(out block1) && inst2.MatchBranch(out block2)) { if (inst1.MatchBranch(out block1) && inst2.MatchBranch(out block2)) {
return block1.ILRange.Start > block2.ILRange.Start; return block1.ILRange.Start > block2.ILRange.Start;
} }
BlockContainer container1, container2;
if (inst1.MatchLeave(out container1) && container1.Parent is TryInstruction) {
// 'leave tryBlock' is considered to have a later target than
// any branch within the container, and also a later target
// than a return instruction.
// This is necessary to avoid "goto" statements in the
// ExceptionHandling.ConditionalReturnInThrow test.
if (!inst2.MatchLeave(out container2))
container2 = block2?.Parent as BlockContainer;
return container2 == null || container2.IsDescendantOf(container1);
}
return false; return false;
} }

1
ICSharpCode.Decompiler/IL/ControlFlow/ControlFlowSimplification.cs

@ -90,6 +90,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
} }
var nextBranch = (Branch)targetBlock.Instructions[0]; var nextBranch = (Branch)targetBlock.Instructions[0];
branch.TargetBlock = nextBranch.TargetBlock; branch.TargetBlock = nextBranch.TargetBlock;
branch.AddILRange(nextBranch.ILRange);
if (targetBlock.IncomingEdgeCount == 0) if (targetBlock.IncomingEdgeCount == 0)
targetBlock.Instructions.Clear(); // mark the block for deletion targetBlock.Instructions.Clear(); // mark the block for deletion
targetBlock = branch.TargetBlock; targetBlock = branch.TargetBlock;

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

@ -181,6 +181,9 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public void SortBlocks(bool deleteUnreachableBlocks = false) public void SortBlocks(bool deleteUnreachableBlocks = false)
{ {
if (Blocks.Count < 2)
return;
// Visit blocks in post-order // Visit blocks in post-order
BitSet visited = new BitSet(Blocks.Count); BitSet visited = new BitSet(Blocks.Count);
List<Block> postOrder = new List<Block>(); List<Block> postOrder = new List<Block>();

1
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -151,6 +151,7 @@
<Compile Include="TestCases\Correctness\ValueTypeCall.cs" /> <Compile Include="TestCases\Correctness\ValueTypeCall.cs" />
<Compile Include="CorrectnessTestRunner.cs" /> <Compile Include="CorrectnessTestRunner.cs" />
<Compile Include="TestCases\Pretty\CompoundAssignmentTest.cs" /> <Compile Include="TestCases\Pretty\CompoundAssignmentTest.cs" />
<Compile Include="TestCases\Pretty\ExceptionHandling.cs" />
<Compile Include="TestCases\Pretty\HelloWorld.cs" /> <Compile Include="TestCases\Pretty\HelloWorld.cs" />
<Compile Include="TestCases\Pretty\InlineAssignmentTest.cs" /> <Compile Include="TestCases\Pretty\InlineAssignmentTest.cs" />
<Compile Include="TestCases\Pretty\ShortCircuit.cs" /> <Compile Include="TestCases\Pretty\ShortCircuit.cs" />

6
ICSharpCode.Decompiler/Tests/PrettyTestRunner.cs

@ -88,6 +88,12 @@ namespace ICSharpCode.Decompiler.Tests
Run(cscOptions: cscOptions); Run(cscOptions: cscOptions);
} }
[Test]
public void ExceptionHandling([Values(CompilerOptions.None, CompilerOptions.Optimize)] CompilerOptions cscOptions)
{
Run(cscOptions: cscOptions);
}
void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None) void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None)
{ {
var ilFile = Path.Combine(TestCasePath, testName); var ilFile = Path.Combine(TestCasePath, testName);

40
ICSharpCode.Decompiler/Tests/TestCases/Pretty/ExceptionHandling.cs

@ -0,0 +1,40 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public abstract class ExceptionHandling
{
public abstract bool B(int i);
public abstract void M(int i);
public bool ConditionalReturnInThrow()
{
try {
if (this.B(0)) {
return this.B(1);
}
} catch {
}
return false;
}
}
}

2
NRefactory

@ -1 +1 @@
Subproject commit 85cf91fe5138252a44b8e1d14a10366f90a5a10d Subproject commit 2b10193ea20a26ae9c8db21a79c60f3be8d8cca8
Loading…
Cancel
Save