diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index a36cb05f5..603c9d38c 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -70,6 +70,7 @@ + diff --git a/ICSharpCode.Decompiler/IL/BlockBuilder.cs b/ICSharpCode.Decompiler/IL/BlockBuilder.cs index 90fcecd0e..b1e13c7b4 100644 --- a/ICSharpCode.Decompiler/IL/BlockBuilder.cs +++ b/ICSharpCode.Decompiler/IL/BlockBuilder.cs @@ -32,10 +32,35 @@ namespace ICSharpCode.Decompiler.IL } if (currentBlock != null) { if (instructionStack == null) { + // inlining disabled currentBlock.Instructions.Add(inst); } else { var inlinedInst = inst.Inline(InstructionFlags.None, instructionStack, out bool finished); - instructionStack.Push(inlinedInst); + if (inlinedInst is Branch) { + // Values currently on the stack might be used on both sides of the branch, + // so we can't inline them. + FlushInstructionStack(); + } + if (inlinedInst.NoResult) { + // We cannot directly push instructions onto the stack if they don't produce + // a result. + if (finished && instructionStack.Count > 0) { + // Wrap the instruction on top of the stack into an inline block, + // and append our void-typed instruction to the end of that block. + var headInst = instructionStack.Pop(); + var block = headInst as Block ?? new Block { Instructions = { headInst } }; + block.Instructions.Add(inlinedInst); + instructionStack.Push(block); + } else { + // We can't move incomplete instructions into a nested block + // or the instruction stack was empty + FlushInstructionStack(); + currentBlock.Instructions.Add(inst); + } + } else { + // Instruction has a result, so we can push it on the stack normally + instructionStack.Push(inlinedInst); + } } if (!inst.IsEndReachable) FinalizeCurrentBlock(inst.ILRange.End, fallthrough: false); @@ -49,15 +74,20 @@ namespace ICSharpCode.Decompiler.IL { if (currentBlock == null) return; + FlushInstructionStack(); + currentBlock.ILRange = new Interval(currentBlock.ILRange.Start, currentILOffset); + if (fallthrough) + currentBlock.Instructions.Add(new Branch(OpCode.Branch, currentILOffset)); + currentBlock = null; + } + + private void FlushInstructionStack() + { if (instructionStack != null && instructionStack.Count > 0) { // Flush instruction stack currentBlock.Instructions.AddRange(instructionStack.Reverse()); instructionStack.Clear(); } - currentBlock.ILRange = new Interval(currentBlock.ILRange.Start, currentILOffset); - if (fallthrough) - currentBlock.Instructions.Add(new Branch(OpCode.Branch, currentILOffset)); - currentBlock = null; } } } diff --git a/ICSharpCode.Decompiler/IL/ILReader.cs b/ICSharpCode.Decompiler/IL/ILReader.cs index f152b0bb9..192c4affa 100644 --- a/ICSharpCode.Decompiler/IL/ILReader.cs +++ b/ICSharpCode.Decompiler/IL/ILReader.cs @@ -493,7 +493,9 @@ namespace ICSharpCode.Decompiler.IL stack.PopOrDefault(); return new StoreInstanceField((FieldReference)ReadAndDecodeMetadataToken()); case ILOpCode.Ldlen: - throw new NotImplementedException(); + stack.PopOrDefault(); + stack.Push(StackType.I); + return new LdLen(); case ILOpCode.Ldobj: throw new NotImplementedException(); case ILOpCode.Ldsfld: diff --git a/ICSharpCode.Decompiler/IL/Instructions/ArrayInstructions.cs b/ICSharpCode.Decompiler/IL/Instructions/ArrayInstructions.cs new file mode 100644 index 000000000..53f00f7b8 --- /dev/null +++ b/ICSharpCode.Decompiler/IL/Instructions/ArrayInstructions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ICSharpCode.Decompiler.IL +{ + class LdLen() : UnaryInstruction(OpCode.LdLen) + { + public override InstructionFlags Flags + { + get { return InstructionFlags.MayThrow | Operand.Flags; } + } + } +} diff --git a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs index b79b1694d..12be67b87 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs @@ -11,7 +11,6 @@ namespace ICSharpCode.Decompiler.IL /// public abstract class ILInstruction(public readonly OpCode OpCode) { - public static readonly ILInstruction Nop = new Nop(); public static readonly ILInstruction Pop = new Pop(); /// diff --git a/ICSharpCode.Decompiler/IL/Instructions/OpCode.cs b/ICSharpCode.Decompiler/IL/Instructions/OpCode.cs index 68dfe717a..3a815f397 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/OpCode.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/OpCode.cs @@ -234,5 +234,9 @@ namespace ICSharpCode.Decompiler.IL /// A container of IL blocks. /// BlockContainer, + /// + /// Returns the length of an array as 'native unsigned int'. + /// + LdLen, } }