From 4dec7abb638fb6c556e7ae8593c3a0fa2349e296 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 22 Mar 2015 18:20:18 +0100 Subject: [PATCH] Replace 'endfinally' with 'leave' --- ICSharpCode.Decompiler/IL/BlockBuilder.cs | 6 ++++ ICSharpCode.Decompiler/IL/ILReader.cs | 2 +- ICSharpCode.Decompiler/IL/InstructionFlags.cs | 4 +++ ICSharpCode.Decompiler/IL/Instructions.cs | 32 ------------------- ICSharpCode.Decompiler/IL/Instructions.tt | 3 -- .../IL/Instructions/Leave.cs | 14 ++++---- .../IL/Transforms/LoopDetection.cs | 2 +- 7 files changed, 20 insertions(+), 43 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/BlockBuilder.cs b/ICSharpCode.Decompiler/IL/BlockBuilder.cs index fbd3785b5..ba4a06c1f 100644 --- a/ICSharpCode.Decompiler/IL/BlockBuilder.cs +++ b/ICSharpCode.Decompiler/IL/BlockBuilder.cs @@ -175,8 +175,14 @@ namespace ICSharpCode.Decompiler.IL switch (inst.OpCode) { case OpCode.Branch: var branch = (Branch)inst; + Debug.Assert(branch.TargetBlock == null); branch.TargetBlock = FindBranchTarget(branch.TargetILOffset); break; + case OpCode.Leave: + var leave = (Leave)inst; + Debug.Assert(leave.TargetContainer == null); + leave.TargetContainer = containerStack.Peek(); + break; case OpCode.BlockContainer: var container = (BlockContainer)inst; containerStack.Push(container); diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index 8ce77b8c2..099e1137c 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -431,7 +431,7 @@ namespace ICSharpCode.Decompiler.IL return new Peek(stack.Count > 0 ? stack.Peek() : StackType.Unknown); case ILOpCode.Endfilter: case ILOpCode.Endfinally: - return new EndFinally(); + return new Leave(null); case ILOpCode.Initblk: throw new NotImplementedException(); case ILOpCode.Jmp: diff --git a/ICSharpCode.Decompiler/IL/InstructionFlags.cs b/ICSharpCode.Decompiler/IL/InstructionFlags.cs index 331b303ef..e725e3728 100644 --- a/ICSharpCode.Decompiler/IL/InstructionFlags.cs +++ b/ICSharpCode.Decompiler/IL/InstructionFlags.cs @@ -81,6 +81,10 @@ namespace ICSharpCode.Decompiler.IL /// /// The instruction performs unconditional control flow, so that its endpoint is unreachable. /// + /// + /// If EndPointUnreachable is set, either MayThrow or MayBranch should also be set + /// (unless the instruction represents an infinite loop). + /// EndPointUnreachable = 0x400, } } diff --git a/ICSharpCode.Decompiler/IL/Instructions.cs b/ICSharpCode.Decompiler/IL/Instructions.cs index bae80dc2e..a7af4fb7a 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions.cs @@ -68,8 +68,6 @@ namespace ICSharpCode.Decompiler.IL Branch, /// Unconditional branch to end of block container. goto container_end;, often break; Leave, - /// Marks the end of an finally, fault or exception filter block. - EndFinally, /// If statement / conditional expression. if (condition) trueExpr else falseExpr IfInstruction, /// Try-catch statement. @@ -701,27 +699,6 @@ namespace ICSharpCode.Decompiler.IL } } - /// Marks the end of an finally, fault or exception filter block. - public sealed partial class EndFinally : SimpleInstruction - { - public EndFinally() : base(OpCode.EndFinally) - { - } - public override StackType ResultType { get { return StackType.Void; } } - protected override InstructionFlags ComputeFlags() - { - return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch; - } - public override void AcceptVisitor(ILVisitor visitor) - { - visitor.VisitEndFinally(this); - } - public override T AcceptVisitor(ILVisitor visitor) - { - return visitor.VisitEndFinally(this); - } - } - /// If statement / conditional expression. if (condition) trueExpr else falseExpr public sealed partial class IfInstruction : ILInstruction { @@ -2737,10 +2714,6 @@ namespace ICSharpCode.Decompiler.IL { Default(inst); } - protected internal virtual void VisitEndFinally(EndFinally inst) - { - Default(inst); - } protected internal virtual void VisitIfInstruction(IfInstruction inst) { Default(inst); @@ -3039,10 +3012,6 @@ namespace ICSharpCode.Decompiler.IL { return Default(inst); } - protected internal virtual T VisitEndFinally(EndFinally inst) - { - return Default(inst); - } protected internal virtual T VisitIfInstruction(IfInstruction inst) { return Default(inst); @@ -3328,7 +3297,6 @@ namespace ICSharpCode.Decompiler.IL "arglist", "br", "leave", - "endfinally", "if", "try.catch", "try.catch.handler", diff --git a/ICSharpCode.Decompiler/IL/Instructions.tt b/ICSharpCode.Decompiler/IL/Instructions.tt index 5063172b7..b589ca286 100644 --- a/ICSharpCode.Decompiler/IL/Instructions.tt +++ b/ICSharpCode.Decompiler/IL/Instructions.tt @@ -63,9 +63,6 @@ CustomClassName("Branch"), NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags), new OpCode("leave", "Unconditional branch to end of block container. goto container_end;, often break;", NoArguments, CustomConstructor, UnconditionalBranch, MayBranch, CustomComputeFlags), - // TODO: get rid of endfinally, we can represent those with 'leave blockcontainer' instead - new OpCode("endfinally", "Marks the end of an finally, fault or exception filter block.", - CustomClassName("EndFinally"), NoArguments, UnconditionalBranch, MayBranch), new OpCode("if", "If statement / conditional expression. if (condition) trueExpr else falseExpr", CustomClassName("IfInstruction"), CustomChildren(new []{ diff --git a/ICSharpCode.Decompiler/IL/Instructions/Leave.cs b/ICSharpCode.Decompiler/IL/Instructions/Leave.cs index 7f7b55cff..385ae108d 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Leave.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Leave.cs @@ -47,8 +47,8 @@ namespace ICSharpCode.Decompiler.IL public Leave(BlockContainer targetContainer) : base(OpCode.Leave) { - if (targetContainer == null) - throw new ArgumentNullException("targetContainer"); + // Note: ILReader will create Leave instructions with targetContainer==null to represent 'endfinally', + // the targetContainer will then be filled in by BlockBuilder this.targetContainer = targetContainer; } @@ -88,20 +88,22 @@ namespace ICSharpCode.Decompiler.IL } public string TargetLabel { - get { return targetContainer.EntryPoint.Label; } + get { return targetContainer != null ? targetContainer.EntryPoint.Label : string.Empty; } } internal override void CheckInvariant() { base.CheckInvariant(); - Debug.Assert(this.IsDescendantOf(targetContainer)); + Debug.Assert(targetContainer == null || this.IsDescendantOf(targetContainer)); } public override void WriteTo(ITextOutput output) { output.Write(OpCode); - output.Write(' '); - output.WriteReference(TargetLabel, targetContainer, isLocal: true); + if (targetContainer != null) { + output.Write(' '); + output.WriteReference(TargetLabel, targetContainer, isLocal: true); + } if (PopCount != 0) { output.Write(" (pops "); output.Write(PopCount.ToString()); diff --git a/ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs b/ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs index 6826af895..b60bdf235 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs @@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms /// * LoopDetection should run before other control flow structures are detected. /// * Blocks should be basic blocks (not extended basic blocks) so that the natural loops /// don't include more instructions than strictly necessary. - /// * (depending on future loop detection improvements:) Loop detection should run after the 'return block' is duplicated. + /// * (depending on future loop detection improvements:) Loop detection should run after the 'return block' is duplicated (OptimizingTransform). /// public class LoopDetection : IILTransform {