From eedcfebb0fd85707714e94ea69697e27a669a028 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Mon, 16 Mar 2015 22:28:30 +0100 Subject: [PATCH] Remove 'loop' instruction; just use a block container. --- .../CSharp/StatementBuilder.cs | 5 -- .../ICSharpCode.Decompiler.csproj | 1 - ICSharpCode.Decompiler/IL/Instructions.cs | 38 -------------- ICSharpCode.Decompiler/IL/Instructions.tt | 5 -- .../IL/Instructions/Loop.cs | 50 ------------------- .../IL/Transforms/LoopDetection.cs | 44 ++++------------ 6 files changed, 10 insertions(+), 133 deletions(-) delete mode 100644 ICSharpCode.Decompiler/IL/Instructions/Loop.cs diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index efe7b0a43..ad8c39546 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -74,11 +74,6 @@ namespace ICSharpCode.Decompiler.CSharp return new IfElseStatement(condition, trueStatement, falseStatement); } - protected internal override Statement VisitLoop(Loop inst) - { - return new WhileStatement(new PrimitiveExpression(true), Convert(inst.Body)); - } - protected internal override Statement VisitBranch(Branch inst) { return new GotoStatement(inst.TargetLabel); diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index b26e19ae1..e737ec011 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -95,7 +95,6 @@ - diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index be3599b03..23a765234 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -70,8 +70,6 @@ namespace ICSharpCode.Decompiler.IL EndFinally, /// If statement / conditional expression. if (condition) trueExpr else falseExpr IfInstruction, - /// Infinite loop - Loop, /// Try-catch statement. TryCatch, /// Catch handler within a try-catch statement. @@ -608,37 +606,6 @@ namespace ICSharpCode.Decompiler.IL } } - /// Infinite loop - public sealed partial class Loop : ILInstruction - { - public Loop(ILInstruction body) : base(OpCode.Loop) - { - this.Body = body; - } - ILInstruction body; - public ILInstruction Body { - get { return this.body; } - set { - ValidateChild(value); - SetChildInstruction(ref this.body, value); - } - } - public override IEnumerable Children { - get { - yield return this.body; - } - } - public override void TransformChildren(ILVisitor visitor) - { - this.Body = this.body.AcceptVisitor(visitor); - } - public override StackType ResultType { get { return StackType.Void; } } - public override T AcceptVisitor(ILVisitor visitor) - { - return visitor.VisitLoop(this); - } - } - /// Try-catch statement. public sealed partial class TryCatch : TryInstruction { @@ -2137,10 +2104,6 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst); } - protected internal virtual T VisitLoop(Loop inst) - { - return Default(inst); - } protected internal virtual T VisitTryCatch(TryCatch inst) { return Default(inst); @@ -2419,7 +2382,6 @@ namespace ICSharpCode.Decompiler.IL "br", "endfinally", "if", - "loop", "try.catch", "try.catch.handler", "try.finally", diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index fe7b41d26..f3e7b059f 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -71,11 +71,6 @@ new ChildInfo("trueInst"), new ChildInfo("falseInst"), }), CustomConstructor, CustomComputeFlags, CustomWriteTo), - new OpCode("loop", "Infinite loop", - CustomChildren(new []{ - new ChildInfo("body") - }), - CustomComputeFlags, CustomWriteTo, ResultType("Void")), new OpCode("try.catch", "Try-catch statement.", BaseClass("TryInstruction"), CustomConstructor, CustomComputeFlags, CustomWriteTo), new OpCode("try.catch.handler", "Catch handler within a try-catch statement.", diff --git a/ICSharpCode.Decompiler/IL/Instructions/Loop.cs b/ICSharpCode.Decompiler/IL/Instructions/Loop.cs deleted file mode 100644 index 4eb485aac..000000000 --- a/ICSharpCode.Decompiler/IL/Instructions/Loop.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) 2014 Daniel Grunwald -// -// 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.IL -{ - partial class Loop - { - public override void WriteTo(ITextOutput output) - { - output.Write("loop "); - body.WriteTo(output); - } - - protected override InstructionFlags ComputeFlags() - { - return Block.Phase1Boundary(body.Flags) - | InstructionFlags.EndPointUnreachable - | InstructionFlags.SideEffect; // an infinite loop is a side effect - } - - internal override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context) - { - return this; - } - - internal override void TransformStackIntoVariables(TransformStackIntoVariablesState state) - { - var initialVariables = state.Variables.Clone(); - Body = Body.Inline(InstructionFlags.None, state); - Body.TransformStackIntoVariables(state); - state.MergeVariables(initialVariables, state.Variables); - } - } -} diff --git a/ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs b/ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs index 9d4c37ead..af58967df 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs @@ -126,8 +126,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms } } if (loop != null) { - // loop now is the union of all natural loops with loop head h - Debug.Assert(loop[0] == h); + // loop now is the union of all natural loops with loop head h. + // Sort blocks in the loop in reverse post-order to make the output look a bit nicer. + // (if the loop doesn't contain nested loops, this is a topological sort) + loop.Sort((a, b) => b.PostOrderNumber.CompareTo(a.PostOrderNumber)); + Debug.Assert(loop[0] == h); // TODO: is this guaranteed after sorting? foreach (var node in loop) { node.Visited = false; // reset visited flag so that we can find nested loops Debug.Assert(h.Dominates(node), "The loop body must be dominated by the loop head"); @@ -148,15 +151,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms Block oldEntryPoint = (Block)loop[0].UserData; BlockContainer oldContainer = (BlockContainer)oldEntryPoint.Parent; - BlockContainer body = new BlockContainer(); + BlockContainer loopContainer = new BlockContainer(); Block newEntryPoint = new Block(); - body.Blocks.Add(newEntryPoint); + loopContainer.Blocks.Add(newEntryPoint); // Move contents of oldEntryPoint to newEntryPoint // (we can't move the block itself because it might be the target of branch instructions outside the loop) newEntryPoint.Instructions.ReplaceList(oldEntryPoint.Instructions); newEntryPoint.FinalInstruction = oldEntryPoint.FinalInstruction; newEntryPoint.ILRange = oldEntryPoint.ILRange; - oldEntryPoint.Instructions.ReplaceList(new[] { new Loop(body) }); + oldEntryPoint.Instructions.ReplaceList(new[] { loopContainer }); oldEntryPoint.FinalInstruction = new Nop(); // Move other blocks into the loop body: they're all dominated by the loop header, @@ -164,43 +167,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms for (int i = 1; i < loop.Count; i++) { Block block = (Block)loop[i].UserData; Debug.Assert(block.Parent == oldContainer); - body.Blocks.Add(block); + loopContainer.Blocks.Add(block); } // Remove all blocks that were moved into the body from the old container oldContainer.Blocks.RemoveAll(b => b.Parent != oldContainer); // Rewrite branches within the loop from oldEntryPoint to newEntryPoint: - foreach (var branch in body.Descendants.OfType()) { + foreach (var branch in loopContainer.Descendants.OfType()) { if (branch.TargetBlock == oldEntryPoint) branch.TargetBlock = newEntryPoint; } - - // Because we use extended basic blocks, not just basic blocks, it's possible - // that we moved too many instructions into the loop body. - // In cases where those additional instructions branch, that's not really a problem - // (and is more readable with the instructions being inside the loop, anyways) - // But in cases where those additional instructions fall through to the end of - // the block, they previously had the semantics of falling out of the oldContainer, - // thus leaving the loop. - // Now they just fall out of the body block container, and thus get executed repeatedly. - // To fix up this semantic difference, we'll patch up these blocks to branch to - // a new empty block in the old container. - Block fallthrough_helper_block = null; - foreach (var block in body.Blocks) { - if (!block.HasFlag(InstructionFlags.EndPointUnreachable)) { - if (block.FinalInstruction.OpCode != OpCode.Nop) { - // move final instruction into the block - block.Instructions.Add(new Void(block.FinalInstruction)); - block.FinalInstruction = new Nop(); - } - if (fallthrough_helper_block == null) { - fallthrough_helper_block = new Block(); - oldContainer.Blocks.Add(fallthrough_helper_block); - } - block.Instructions.Add(new Branch(fallthrough_helper_block)); - } - Debug.Assert(block.HasFlag(InstructionFlags.EndPointUnreachable)); - } } } }