Browse Source

Build inline blocks when there are IL statements (opcodes not pushing anything) in a block while the stack is non-empty.

pull/728/head
Daniel Grunwald 12 years ago
parent
commit
557f790127
  1. 1
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  2. 40
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  3. 4
      ICSharpCode.Decompiler/IL/ILReader.cs
  4. 16
      ICSharpCode.Decompiler/IL/Instructions/ArrayInstructions.cs
  5. 1
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  6. 4
      ICSharpCode.Decompiler/IL/Instructions/OpCode.cs

1
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -70,6 +70,7 @@ @@ -70,6 +70,7 @@
<Compile Include="Disassembler\ILStructure.cs" />
<Compile Include="Disassembler\MethodBodyDisassembler.cs" />
<Compile Include="Disassembler\ReflectionDisassembler.cs" />
<Compile Include="IL\Instructions\ArrayInstructions.cs" />
<Compile Include="IL\SemanticHelper.cs" />
<Compile Include="IL\BlockBuilder.cs" />
<Compile Include="IL\ILOpCodes.cs">

40
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -32,10 +32,35 @@ namespace ICSharpCode.Decompiler.IL @@ -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 @@ -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;
}
}
}

4
ICSharpCode.Decompiler/IL/ILReader.cs

@ -493,7 +493,9 @@ namespace ICSharpCode.Decompiler.IL @@ -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:

16
ICSharpCode.Decompiler/IL/Instructions/ArrayInstructions.cs

@ -0,0 +1,16 @@ @@ -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; }
}
}
}

1
ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

@ -11,7 +11,6 @@ namespace ICSharpCode.Decompiler.IL @@ -11,7 +11,6 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public abstract class ILInstruction(public readonly OpCode OpCode)
{
public static readonly ILInstruction Nop = new Nop();
public static readonly ILInstruction Pop = new Pop();
/// <summary>

4
ICSharpCode.Decompiler/IL/Instructions/OpCode.cs

@ -234,5 +234,9 @@ namespace ICSharpCode.Decompiler.IL @@ -234,5 +234,9 @@ namespace ICSharpCode.Decompiler.IL
/// A container of IL blocks. <see cref="IL.BlockContainer"/>
/// </summary>
BlockContainer,
/// <summary>
/// Returns the length of an array as 'native unsigned int'.
/// </summary>
LdLen,
}
}

Loading…
Cancel
Save