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,
}
}