diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index e3e43be69..51d24fc07 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -42,13 +42,13 @@ - - + + - - + + diff --git a/ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs b/ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs index 222d82daa..32310150c 100644 --- a/ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs +++ b/ICSharpCode.Decompiler/IL/ILInstructionExtensions.cs @@ -18,5 +18,14 @@ namespace ICSharpCode.Decompiler.IL target.AddILRange(range); return target; } + + public static ILInstruction GetNextSibling(this ILInstruction instruction) + { + if (instruction?.Parent == null) + return null; + if (instruction.ChildIndex + 1 >= instruction.Parent.Children.Count) + return null; + return instruction.Parent.Children[instruction.ChildIndex + 1]; + } } } diff --git a/ICSharpCode.Decompiler/IL/Instructions/Block.cs b/ICSharpCode.Decompiler/IL/Instructions/Block.cs index ab04f550e..dcaa0b580 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/Block.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/Block.cs @@ -43,11 +43,11 @@ namespace ICSharpCode.Decompiler.IL { public static readonly SlotInfo InstructionSlot = new SlotInfo("Instruction", isCollection: true); public static readonly SlotInfo FinalInstructionSlot = new SlotInfo("FinalInstruction"); - + public readonly BlockKind Kind; public readonly InstructionCollection Instructions; ILInstruction finalInstruction; - + /// /// For blocks in a block container, this field holds /// the number of incoming control flow edges to this block. @@ -77,21 +77,21 @@ namespace ICSharpCode.Decompiler.IL SetChildInstruction(ref finalInstruction, value, Instructions.Count); } } - + protected internal override void InstructionCollectionUpdateComplete() { base.InstructionCollectionUpdateComplete(); if (finalInstruction.Parent == this) finalInstruction.ChildIndex = Instructions.Count; } - + public Block(BlockKind kind = BlockKind.ControlFlow) : base(OpCode.Block) { this.Kind = kind; this.Instructions = new InstructionCollection(this, 0); this.FinalInstruction = new Nop(); } - + public override ILInstruction Clone() { Block clone = new Block(Kind); @@ -100,7 +100,7 @@ namespace ICSharpCode.Decompiler.IL clone.FinalInstruction = this.FinalInstruction.Clone(); return clone; } - + internal override void CheckInvariant(ILPhase phase) { base.CheckInvariant(phase); @@ -133,18 +133,17 @@ namespace ICSharpCode.Decompiler.IL break; } } - + public override StackType ResultType { get { return finalInstruction.ResultType; } } - + /// /// Gets the name of this block. /// - public string Label - { + public string Label { get { return Disassembler.DisassemblerHelpers.OffsetToString(this.StartILOffset); } } @@ -179,19 +178,19 @@ namespace ICSharpCode.Decompiler.IL output.Write("}"); output.MarkFoldEnd(); } - + protected override int GetChildCount() { return Instructions.Count + 1; } - + protected override ILInstruction GetChild(int index) { if (index == Instructions.Count) return finalInstruction; return Instructions[index]; } - + protected override void SetChild(int index, ILInstruction value) { if (index == Instructions.Count) @@ -199,7 +198,7 @@ namespace ICSharpCode.Decompiler.IL else Instructions[index] = value; } - + protected override SlotInfo GetChildSlot(int index) { if (index == Instructions.Count) @@ -207,7 +206,7 @@ namespace ICSharpCode.Decompiler.IL else return InstructionSlot; } - + protected override InstructionFlags ComputeFlags() { var flags = InstructionFlags.None; @@ -217,7 +216,7 @@ namespace ICSharpCode.Decompiler.IL flags |= FinalInstruction.Flags; return flags; } - + public override InstructionFlags DirectFlags { get { return InstructionFlags.None; @@ -280,6 +279,21 @@ namespace ICSharpCode.Decompiler.IL return inst; } + /// + /// Gets the closest parent Block. + /// Returns null, if the instruction is not a descendant of a Block. + /// + public static Block FindClosestBlock(ILInstruction inst) + { + var curr = inst; + while (curr != null) { + if (curr is Block) + return (Block)curr; + curr = curr.Parent; + } + return null; + } + public bool MatchInlineAssignBlock(out CallInstruction call, out ILInstruction value) { call = null; diff --git a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs index 05f7d2f5f..0a19dd86a 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs @@ -271,6 +271,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms } Block block; if (TransformSpanTCtorContainingStackAlloc(inst, out ILInstruction locallocSpan)) { + context.Step("new Span(stackalloc) -> stackalloc Span", inst); inst.ReplaceWith(locallocSpan); block = null; ILInstruction stmt = locallocSpan; @@ -281,7 +282,9 @@ namespace ICSharpCode.Decompiler.IL.Transforms } stmt = stmt.Parent; } - //ILInlining.InlineIfPossible(block, stmt.ChildIndex - 1, context); + // Special case to eliminate extra store + if (stmt.GetNextSibling() is StLoc) + ILInlining.InlineIfPossible(block, stmt.ChildIndex, context); return; } if (TransformArrayInitializers.TransformSpanTArrayInitialization(inst, context, out block)) { diff --git a/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj b/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj index 0f4829272..1958ed447 100644 --- a/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj +++ b/ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj @@ -31,7 +31,7 @@ - + diff --git a/ILSpy.BamlDecompiler.Tests/app.config b/ILSpy.BamlDecompiler.Tests/app.config index 5095b0e47..8eaf7eb82 100644 --- a/ILSpy.BamlDecompiler.Tests/app.config +++ b/ILSpy.BamlDecompiler.Tests/app.config @@ -7,8 +7,14 @@ + + + + + + - +