diff --git a/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs b/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs index 623aa9189..15f0f10b6 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs @@ -20,6 +20,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.Util; namespace ICSharpCode.Decompiler.IL @@ -239,6 +240,19 @@ namespace ICSharpCode.Decompiler.IL } } + internal override bool CanInlineIntoSlot(int childIndex, ILInstruction expressionBeingMoved) + { + // Inlining into the entry-point is allowed as long as we're not moving code into a loop. + // This is used to inline into the switch expression. + return childIndex == 0 && this.EntryPoint.IncomingEdgeCount == 1; + } + + internal override bool PrepareExtract(int childIndex, ExtractionContext ctx) + { + // Un-inlining from the entry-point is allowed as long as we're not moving code out of a loop + return childIndex == 0 && this.EntryPoint.IncomingEdgeCount == 1; + } + /// /// Topologically sort the blocks. /// The new order is returned without modifying the BlockContainer. diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs index b7a96a8df..1bc534954 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs @@ -802,6 +802,15 @@ namespace ICSharpCode.Decompiler.IL } return true; } + + /// + /// Gets whether the specified instruction may be inlined into the specified slot. + /// Note: this does not check whether reordering with the previous slots is valid; only wheter the target slot supports inlining at all! + /// + internal virtual bool CanInlineIntoSlot(int childIndex, ILInstruction expressionBeingMoved) + { + return GetChildSlot(childIndex).CanInlineInto; + } } public interface IInstructionWithTypeOperand diff --git a/ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs b/ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs index bfe56d08f..8e2b2e430 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/NullableInstructions.cs @@ -63,7 +63,7 @@ namespace ICSharpCode.Decompiler.IL /// public bool RefOutput { get => ResultType == StackType.Ref; } - public NullableUnwrap(StackType unwrappedType, ILInstruction argument, bool refInput=false) + public NullableUnwrap(StackType unwrappedType, ILInstruction argument, bool refInput = false) : base(OpCode.NullableUnwrap, argument) { this.ResultType = unwrappedType; @@ -132,5 +132,13 @@ namespace ICSharpCode.Decompiler.IL return base.PrepareExtract(childIndex, ctx) && (ctx.FlagsBeingMoved & InstructionFlags.MayUnwrapNull) == 0; } + + internal override bool CanInlineIntoSlot(int childIndex, ILInstruction expressionBeingMoved) + { + // Inlining into nullable.rewrap is OK unless the expression being inlined + // contains a nullable.wrap that isn't being re-wrapped within the expression being inlined. + return base.CanInlineIntoSlot(childIndex, expressionBeingMoved) + && !expressionBeingMoved.HasFlag(InstructionFlags.MayUnwrapNull); + } } } diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index dfa9932d0..ab26ec7b5 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -589,6 +589,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } else if (expr is Block block) { // Inlining into inline-blocks? switch (block.Kind) { + case BlockKind.ControlFlow when block.Parent is BlockContainer: case BlockKind.ArrayInitializer: case BlockKind.CollectionInitializer: case BlockKind.ObjectInitializer: @@ -604,19 +605,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms default: return FindResult.Stop; } - } else if (expr is BlockContainer container && container.EntryPoint.IncomingEdgeCount == 1) { - // Possibly a switch-container, allow inlining into the switch instruction: - return NoContinue(FindLoadInNext(container.EntryPoint.Instructions[0], v, expressionBeingMoved, options)); - // If FindLoadInNext() returns null, we still can't continue searching - // because we can't inline over the remainder of the blockcontainer. - } else if (expr is NullableRewrap) { - // Inlining into nullable.rewrap is OK unless the expression being inlined - // contains a nullable.wrap that isn't being re-wrapped within the expression being inlined. - if (expressionBeingMoved.HasFlag(InstructionFlags.MayUnwrapNull)) - return FindResult.Stop; } foreach (var child in expr.Children) { - if (!child.SlotInfo.CanInlineInto) + if (!expr.CanInlineIntoSlot(child.ChildIndex, expressionBeingMoved)) return FindResult.Stop; // Recursively try to find the load instruction @@ -672,7 +663,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms { Debug.Assert(targetLoad.IsDescendantOf(stmt)); for (ILInstruction inst = targetLoad; inst != stmt; inst = inst.Parent) { - if (!inst.SlotInfo.CanInlineInto) + if (!inst.Parent.CanInlineIntoSlot(inst.ChildIndex, expressionBeingMoved)) return false; // Check whether re-ordering with predecessors is valid: int childIndex = inst.ChildIndex;