|
|
|
@ -65,8 +65,13 @@ namespace ICSharpCode.Decompiler.IL
@@ -65,8 +65,13 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
foreach (var block in container.Blocks) |
|
|
|
|
for (int i = 0; i < container.Blocks.Count; i++) { |
|
|
|
|
var block = container.Blocks[i]; |
|
|
|
|
// Note: it's possible for additional blocks to be appended to the container
|
|
|
|
|
// by the Visit() call; but there should be no other changes to the Blocks collection.
|
|
|
|
|
Visit(block, continueTarget); |
|
|
|
|
Debug.Assert(container.Blocks[i] == block); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
@ -94,10 +99,10 @@ namespace ICSharpCode.Decompiler.IL
@@ -94,10 +99,10 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
|
|
|
|
|
// reduce nesting in switch blocks
|
|
|
|
|
if (container.Kind == ContainerKind.Switch && |
|
|
|
|
CanDuplicateExit(NextInsn(), continueTarget) && |
|
|
|
|
ReduceNesting(block, container, NextInsn())) |
|
|
|
|
CanDuplicateExit(NextInsn(), continueTarget) && |
|
|
|
|
ReduceSwitchNesting(block, container, NextInsn())) { |
|
|
|
|
RemoveRedundantExit(block, nextInstruction); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case IfInstruction ifInst: |
|
|
|
|
ImproveILOrdering(block, ifInst); |
|
|
|
@ -200,7 +205,7 @@ namespace ICSharpCode.Decompiler.IL
@@ -200,7 +205,7 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
/// Reduce Nesting in switch statements by replacing break; in cases with the block exit, and extracting the default case
|
|
|
|
|
/// Does not affect IL order
|
|
|
|
|
/// </summary>
|
|
|
|
|
private bool ReduceNesting(Block parentBlock, BlockContainer switchContainer, ILInstruction exitInst) |
|
|
|
|
private bool ReduceSwitchNesting(Block parentBlock, BlockContainer switchContainer, ILInstruction exitInst) |
|
|
|
|
{ |
|
|
|
|
// break; from outer container cannot be brought inside the switch as the meaning would change
|
|
|
|
|
if (exitInst is Leave leave && !leave.IsLeavingFunction) |
|
|
|
@ -229,7 +234,10 @@ namespace ICSharpCode.Decompiler.IL
@@ -229,7 +234,10 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
var defaultTree = TreeTraversal.PreOrder(defaultNode, n => n.DominatorTreeChildren).ToList(); |
|
|
|
|
if (defaultTree.SelectMany(n => n.Successors).Any(n => !defaultNode.Dominates(n))) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (defaultTree.Count > 1 && !(parentBlock.Parent is BlockContainer)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
EnsureEndPointUnreachable(parentBlock, exitInst); |
|
|
|
|
context.Step("Extract default case of switch", switchContainer); |
|
|
|
|
|
|
|
|
@ -247,14 +255,18 @@ namespace ICSharpCode.Decompiler.IL
@@ -247,14 +255,18 @@ namespace ICSharpCode.Decompiler.IL
|
|
|
|
|
switchContainer.Blocks.Remove(block); |
|
|
|
|
|
|
|
|
|
// replace the parent block exit with the default case instructions
|
|
|
|
|
Debug.Assert(parentBlock.Instructions.Last() == exitInst); |
|
|
|
|
parentBlock.Instructions.RemoveLast(); |
|
|
|
|
parentBlock.Instructions.AddRange(defaultBlock.Instructions); |
|
|
|
|
|
|
|
|
|
// add any additional blocks from the default case to the parent container
|
|
|
|
|
var parentContainer = (BlockContainer)parentBlock.Ancestors.First(p => p is BlockContainer); |
|
|
|
|
int insertAt = parentContainer.Blocks.IndexOf(parentBlock) + 1; |
|
|
|
|
foreach (var block in defaultBlocks.Skip(1)) |
|
|
|
|
parentContainer.Blocks.Insert(insertAt++, block); |
|
|
|
|
Debug.Assert(defaultBlocks[0] == defaultBlock); |
|
|
|
|
if (defaultBlocks.Count > 1) { |
|
|
|
|
var parentContainer = (BlockContainer)parentBlock.Parent; |
|
|
|
|
int insertAt = parentContainer.Blocks.IndexOf(parentBlock) + 1; |
|
|
|
|
foreach (var block in defaultBlocks.Skip(1)) |
|
|
|
|
parentContainer.Blocks.Insert(insertAt++, block); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|