Browse Source

Fix #447: second part ReturnFromDoWhileInTryFinally

pull/987/head
Siegfried Pammer 8 years ago
parent
commit
37474ae5e9
  1. 17
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs
  2. 60
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il
  3. 43
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il
  4. 39
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il
  5. 53
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il
  6. 50
      ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs

17
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.cs

@ -637,5 +637,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -637,5 +637,22 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
Console.WriteLine("End of method");
}
public void ReturnFromDoWhileInTryFinally()
{
try {
do {
if (this.Condition("return")) {
return;
}
} while (this.Condition("repeat"));
Environment.GetCommandLineArgs();
} finally {
Environment.GetCommandLineArgs();
}
Environment.GetCommandLineArgs();
}
}
}

60
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly dky1g03y
.assembly fawxdzyv
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module dky1g03y.dll
// MVID: {4ADF70C5-8EC0-41AF-A9B1-6DF95B943C1A}
.module fawxdzyv.dll
// MVID: {8B0E086E-9CF4-420F-8491-C1950C43B6C0}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x03580000
// Image base: 0x03590000
// =============== CLASS MEMBERS DECLARATION ===================
@ -2215,6 +2215,58 @@ @@ -2215,6 +2215,58 @@
IL_00a0: ret
} // end of method Loops::ForLoop
.method public hidebysig instance void
ReturnFromDoWhileInTryFinally() cil managed
{
// Code size 67 (0x43)
.maxstack 2
.locals init (bool V_0)
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: nop
IL_0003: ldarg.0
IL_0004: ldstr "return"
IL_0009: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_000e: ldc.i4.0
IL_000f: ceq
IL_0011: stloc.0
IL_0012: ldloc.0
IL_0013: brtrue.s IL_0018
IL_0015: nop
IL_0016: leave.s IL_0041
IL_0018: nop
IL_0019: ldarg.0
IL_001a: ldstr "repeat"
IL_001f: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0024: stloc.0
IL_0025: ldloc.0
IL_0026: brtrue.s IL_0002
IL_0028: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_002d: pop
IL_002e: nop
IL_002f: leave.s IL_003a
} // end .try
finally
{
IL_0031: nop
IL_0032: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0037: pop
IL_0038: nop
IL_0039: endfinally
} // end handler
IL_003a: nop
IL_003b: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0040: pop
IL_0041: nop
IL_0042: ret
} // end of method Loops::ReturnFromDoWhileInTryFinally
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

43
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.il

@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0
}
.assembly trg3dx5v
.assembly w2cet5qb
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
.custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78 // ....T..WrapNonEx
@ -20,15 +20,15 @@ @@ -20,15 +20,15 @@
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module trg3dx5v.dll
// MVID: {39502A20-4431-466D-88D2-F47B21FB8C58}
.module w2cet5qb.dll
// MVID: {F3696C2D-E180-4496-B78F-ACC7FD27833A}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00B30000
// Image base: 0x04C90000
// =============== CLASS MEMBERS DECLARATION ===================
@ -1719,6 +1719,41 @@ @@ -1719,6 +1719,41 @@
IL_007b: ret
} // end of method Loops::ForLoop
.method public hidebysig instance void
ReturnFromDoWhileInTryFinally() cil managed
{
// Code size 50 (0x32)
.maxstack 2
.try
{
IL_0000: ldarg.0
IL_0001: ldstr "return"
IL_0006: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_000b: brfalse.s IL_000f
IL_000d: leave.s IL_0031
IL_000f: ldarg.0
IL_0010: ldstr "repeat"
IL_0015: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_001a: brtrue.s IL_0000
IL_001c: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0021: pop
IL_0022: leave.s IL_002b
} // end .try
finally
{
IL_0024: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0029: pop
IL_002a: endfinally
} // end handler
IL_002b: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0030: pop
IL_0031: ret
} // end of method Loops::ReturnFromDoWhileInTryFinally
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

39
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.opt.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module Loops.dll
// MVID: {F193AB7E-127F-4EFE-9BF9-ADF41756C267}
// MVID: {54789F7A-02C9-433E-A0D4-8F5763DBAB55}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x03460000
// Image base: 0x034F0000
// =============== CLASS MEMBERS DECLARATION ===================
@ -1672,6 +1672,41 @@ @@ -1672,6 +1672,41 @@
IL_007b: ret
} // end of method Loops::ForLoop
.method public hidebysig instance void
ReturnFromDoWhileInTryFinally() cil managed
{
// Code size 50 (0x32)
.maxstack 2
.try
{
IL_0000: ldarg.0
IL_0001: ldstr "return"
IL_0006: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_000b: brfalse.s IL_000f
IL_000d: leave.s IL_0031
IL_000f: ldarg.0
IL_0010: ldstr "repeat"
IL_0015: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_001a: brtrue.s IL_0000
IL_001c: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0021: pop
IL_0022: leave.s IL_002b
} // end .try
finally
{
IL_0024: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0029: pop
IL_002a: endfinally
} // end handler
IL_002b: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0030: pop
IL_0031: ret
} // end of method Loops::ReturnFromDoWhileInTryFinally
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

53
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Loops.roslyn.il

@ -25,14 +25,14 @@ @@ -25,14 +25,14 @@
.ver 0:0:0:0
}
.module Loops.dll
// MVID: {8F6E41CD-7AE5-437C-BACB-4A672A0014D0}
// MVID: {AF6A735F-62A4-480B-8A6B-50E8BB64AD30}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY
// Image base: 0x00C80000
// Image base: 0x05400000
// =============== CLASS MEMBERS DECLARATION ===================
@ -2083,6 +2083,55 @@ @@ -2083,6 +2083,55 @@
IL_009e: ret
} // end of method Loops::ForLoop
.method public hidebysig instance void
ReturnFromDoWhileInTryFinally() cil managed
{
// Code size 62 (0x3e)
.maxstack 2
.locals init (bool V_0,
bool V_1)
IL_0000: nop
.try
{
IL_0001: nop
IL_0002: nop
IL_0003: ldarg.0
IL_0004: ldstr "return"
IL_0009: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_000e: stloc.0
IL_000f: ldloc.0
IL_0010: brfalse.s IL_0015
IL_0012: nop
IL_0013: leave.s IL_003d
IL_0015: nop
IL_0016: ldarg.0
IL_0017: ldstr "repeat"
IL_001c: call instance bool ICSharpCode.Decompiler.Tests.TestCases.Pretty.Loops::Condition(string)
IL_0021: stloc.1
IL_0022: ldloc.1
IL_0023: brtrue.s IL_0002
IL_0025: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_002a: pop
IL_002b: nop
IL_002c: leave.s IL_0037
} // end .try
finally
{
IL_002e: nop
IL_002f: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_0034: pop
IL_0035: nop
IL_0036: endfinally
} // end handler
IL_0037: call string[] [mscorlib]System.Environment::GetCommandLineArgs()
IL_003c: pop
IL_003d: ret
} // end of method Loops::ReturnFromDoWhileInTryFinally
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{

50
ICSharpCode.Decompiler/IL/Transforms/HighLevelLoopTransform.cs

@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using ICSharpCode.Decompiler.Util;
@ -109,7 +110,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -109,7 +110,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary>
bool MatchDoWhileLoop(BlockContainer loop)
{
(List<IfInstruction> conditions, ILInstruction exit, bool swap, bool split) = AnalyzeDoWhileConditions(loop);
(List<IfInstruction> conditions, ILInstruction exit, bool swap, bool split, bool unwrap) = AnalyzeDoWhileConditions(loop);
// not a do-while loop, exit.
if (conditions == null || conditions.Count == 0)
return false;
@ -117,6 +118,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -117,6 +118,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
Block conditionBlock;
// first we remove all extracted instructions from the original block.
var originalBlock = (Block)exit.Parent;
if (unwrap) {
// we found a condition block nested in a condition that is followed by a return statement:
// we flip the condition and swap the blocks
Debug.Assert(originalBlock.Parent is IfInstruction);
var returnCondition = (IfInstruction)originalBlock.Parent;
var topLevelBlock = (Block)returnCondition.Parent;
Debug.Assert(topLevelBlock.Parent == loop);
var leaveFunction = topLevelBlock.Instructions[returnCondition.ChildIndex + 1];
Debug.Assert(leaveFunction.MatchReturn(out _));
returnCondition.Condition = Comp.LogicNot(returnCondition.Condition);
returnCondition.TrueInst = leaveFunction;
// simplify the condition:
new ExpressionTransforms().Run(topLevelBlock, returnCondition.ChildIndex, new StatementTransformContext(new BlockTransformContext(context)));
topLevelBlock.Instructions.RemoveAt(returnCondition.ChildIndex + 1);
topLevelBlock.Instructions.AddRange(originalBlock.Instructions);
originalBlock = topLevelBlock;
split = true;
}
originalBlock.Instructions.RemoveRange(originalBlock.Instructions.Count - conditions.Count - 1, conditions.Count + 1);
// we need to split the block:
if (split) {
@ -161,22 +180,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -161,22 +180,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true;
}
static (List<IfInstruction> conditions, ILInstruction exit, bool swap, bool split) AnalyzeDoWhileConditions(BlockContainer loop)
static (List<IfInstruction> conditions, ILInstruction exit, bool swap, bool split, bool unwrap) AnalyzeDoWhileConditions(BlockContainer loop)
{
bool swap;
// we iterate over all blocks from the bottom, because the entry-point
// should only be considered as condition block, if there are no other blocks.
foreach (var block in loop.Blocks.Reverse()) {
// first we match the end of the block:
if (MatchDoWhileConditionBlock(loop, block, out swap)) {
if (MatchDoWhileConditionBlock(loop, block, out bool swap, out bool unwrapCondtionBlock, out Block conditionBlock)) {
// now collect all instructions that are usable as loop conditions
var conditions = CollectConditions(loop, block, swap);
var conditions = CollectConditions(loop, conditionBlock, swap);
// split only if the block is either the entry-point or contains other instructions as well.
var split = block == loop.EntryPoint || block.Instructions.Count > conditions.Count + 1; // + 1 is the final leave/branch.
return (conditions, block.Instructions.Last(), swap, split);
var split = conditionBlock == loop.EntryPoint || conditionBlock.Instructions.Count > conditions.Count + 1; // + 1 is the final leave/branch.
return (conditions, conditionBlock.Instructions.Last(), swap, split, unwrapCondtionBlock);
}
}
return (null, null, false, false);
return (null, null, false, false, false);
}
/// <summary>
@ -216,7 +234,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -216,7 +234,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
static bool MatchDoWhileConditionBlock(BlockContainer loop, Block block, out bool swapBranches)
static bool MatchDoWhileConditionBlock(BlockContainer loop, Block block, out bool swapBranches, out bool unwrapCondtionBlock, out Block conditionBlock)
{
// match the end of the block:
// if (condition) branch entry-point else nop
@ -225,6 +243,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -225,6 +243,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// if (condition) leave loop else nop
// branch entry-point
swapBranches = false;
unwrapCondtionBlock = false;
conditionBlock = block;
// empty block?
if (block.Instructions.Count < 2)
return false;
@ -233,6 +253,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -233,6 +253,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// no IfInstruction or already transformed?
if (ifInstruction == null || !ifInstruction.FalseInst.MatchNop())
return false;
// the block ends in a return statement preceeded by an IfInstruction
// take a look at the nested block and check if that might be a condition block
if (last.MatchReturn(out _) && ifInstruction.TrueInst is Block nestedConditionBlock) {
if (nestedConditionBlock.Instructions.Count < 2)
return false;
last = nestedConditionBlock.Instructions.Last();
ifInstruction = nestedConditionBlock.Instructions.SecondToLastOrDefault() as IfInstruction;
if (ifInstruction == null || !ifInstruction.FalseInst.MatchNop())
return false;
unwrapCondtionBlock = true;
conditionBlock = nestedConditionBlock;
}
// if the last instruction is a branch
// we assume the branch instructions need to be swapped.
if (last.MatchBranch(loop.EntryPoint))

Loading…
Cancel
Save