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
} }
Console.WriteLine("End of method"); 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 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0 .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.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 .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 @@
.hash algorithm 0x00008004 .hash algorithm 0x00008004
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module dky1g03y.dll .module fawxdzyv.dll
// MVID: {4ADF70C5-8EC0-41AF-A9B1-6DF95B943C1A} // MVID: {8B0E086E-9CF4-420F-8491-C1950C43B6C0}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x03580000 // Image base: 0x03590000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -2215,6 +2215,58 @@
IL_00a0: ret IL_00a0: ret
} // end of method Loops::ForLoop } // 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 .method public hidebysig specialname rtspecialname
instance void .ctor() cil managed instance void .ctor() cil managed
{ {

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

@ -10,7 +10,7 @@
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 4:0:0:0 .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.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 .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 @@
.hash algorithm 0x00008004 .hash algorithm 0x00008004
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module trg3dx5v.dll .module w2cet5qb.dll
// MVID: {39502A20-4431-466D-88D2-F47B21FB8C58} // MVID: {F3696C2D-E180-4496-B78F-ACC7FD27833A}
.custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x00B30000 // Image base: 0x04C90000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -1719,6 +1719,41 @@
IL_007b: ret IL_007b: ret
} // end of method Loops::ForLoop } // 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 .method public hidebysig specialname rtspecialname
instance void .ctor() cil managed instance void .ctor() cil managed
{ {

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

@ -25,14 +25,14 @@
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module Loops.dll .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 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x03460000 // Image base: 0x034F0000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -1672,6 +1672,41 @@
IL_007b: ret IL_007b: ret
} // end of method Loops::ForLoop } // 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 .method public hidebysig specialname rtspecialname
instance void .ctor() cil managed instance void .ctor() cil managed
{ {

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

@ -25,14 +25,14 @@
.ver 0:0:0:0 .ver 0:0:0:0
} }
.module Loops.dll .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 ) .custom instance void [mscorlib]System.Security.UnverifiableCodeAttribute::.ctor() = ( 01 00 00 00 )
.imagebase 0x10000000 .imagebase 0x10000000
.file alignment 0x00000200 .file alignment 0x00000200
.stackreserve 0x00100000 .stackreserve 0x00100000
.subsystem 0x0003 // WINDOWS_CUI .subsystem 0x0003 // WINDOWS_CUI
.corflags 0x00000001 // ILONLY .corflags 0x00000001 // ILONLY
// Image base: 0x00C80000 // Image base: 0x05400000
// =============== CLASS MEMBERS DECLARATION =================== // =============== CLASS MEMBERS DECLARATION ===================
@ -2083,6 +2083,55 @@
IL_009e: ret IL_009e: ret
} // end of method Loops::ForLoop } // 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 .method public hidebysig specialname rtspecialname
instance void .ctor() cil managed instance void .ctor() cil managed
{ {

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

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Util;
@ -109,7 +110,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// </summary> /// </summary>
bool MatchDoWhileLoop(BlockContainer loop) 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. // not a do-while loop, exit.
if (conditions == null || conditions.Count == 0) if (conditions == null || conditions.Count == 0)
return false; return false;
@ -117,6 +118,24 @@ namespace ICSharpCode.Decompiler.IL.Transforms
Block conditionBlock; Block conditionBlock;
// first we remove all extracted instructions from the original block. // first we remove all extracted instructions from the original block.
var originalBlock = (Block)exit.Parent; 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); originalBlock.Instructions.RemoveRange(originalBlock.Instructions.Count - conditions.Count - 1, conditions.Count + 1);
// we need to split the block: // we need to split the block:
if (split) { if (split) {
@ -161,22 +180,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return true; 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 // 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. // should only be considered as condition block, if there are no other blocks.
foreach (var block in loop.Blocks.Reverse()) { foreach (var block in loop.Blocks.Reverse()) {
// first we match the end of the block: // 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 // 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. // 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. var split = conditionBlock == loop.EntryPoint || conditionBlock.Instructions.Count > conditions.Count + 1; // + 1 is the final leave/branch.
return (conditions, block.Instructions.Last(), swap, split); return (conditions, conditionBlock.Instructions.Last(), swap, split, unwrapCondtionBlock);
} }
} }
return (null, null, false, false); return (null, null, false, false, false);
} }
/// <summary> /// <summary>
@ -216,7 +234,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false; 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: // match the end of the block:
// if (condition) branch entry-point else nop // if (condition) branch entry-point else nop
@ -225,6 +243,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// if (condition) leave loop else nop // if (condition) leave loop else nop
// branch entry-point // branch entry-point
swapBranches = false; swapBranches = false;
unwrapCondtionBlock = false;
conditionBlock = block;
// empty block? // empty block?
if (block.Instructions.Count < 2) if (block.Instructions.Count < 2)
return false; return false;
@ -233,6 +253,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// no IfInstruction or already transformed? // no IfInstruction or already transformed?
if (ifInstruction == null || !ifInstruction.FalseInst.MatchNop()) if (ifInstruction == null || !ifInstruction.FalseInst.MatchNop())
return false; 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 // if the last instruction is a branch
// we assume the branch instructions need to be swapped. // we assume the branch instructions need to be swapped.
if (last.MatchBranch(loop.EntryPoint)) if (last.MatchBranch(loop.EntryPoint))

Loading…
Cancel
Save