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 @@
<Compile Include="Disassembler\ILStructure.cs" /> <Compile Include="Disassembler\ILStructure.cs" />
<Compile Include="Disassembler\MethodBodyDisassembler.cs" /> <Compile Include="Disassembler\MethodBodyDisassembler.cs" />
<Compile Include="Disassembler\ReflectionDisassembler.cs" /> <Compile Include="Disassembler\ReflectionDisassembler.cs" />
<Compile Include="IL\Instructions\ArrayInstructions.cs" />
<Compile Include="IL\SemanticHelper.cs" /> <Compile Include="IL\SemanticHelper.cs" />
<Compile Include="IL\BlockBuilder.cs" /> <Compile Include="IL\BlockBuilder.cs" />
<Compile Include="IL\ILOpCodes.cs"> <Compile Include="IL\ILOpCodes.cs">

40
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -32,10 +32,35 @@ namespace ICSharpCode.Decompiler.IL
} }
if (currentBlock != null) { if (currentBlock != null) {
if (instructionStack == null) { if (instructionStack == null) {
// inlining disabled
currentBlock.Instructions.Add(inst); currentBlock.Instructions.Add(inst);
} else { } else {
var inlinedInst = inst.Inline(InstructionFlags.None, instructionStack, out bool finished); 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) if (!inst.IsEndReachable)
FinalizeCurrentBlock(inst.ILRange.End, fallthrough: false); FinalizeCurrentBlock(inst.ILRange.End, fallthrough: false);
@ -49,15 +74,20 @@ namespace ICSharpCode.Decompiler.IL
{ {
if (currentBlock == null) if (currentBlock == null)
return; 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) { if (instructionStack != null && instructionStack.Count > 0) {
// Flush instruction stack // Flush instruction stack
currentBlock.Instructions.AddRange(instructionStack.Reverse()); currentBlock.Instructions.AddRange(instructionStack.Reverse());
instructionStack.Clear(); 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
stack.PopOrDefault(); stack.PopOrDefault();
return new StoreInstanceField((FieldReference)ReadAndDecodeMetadataToken()); return new StoreInstanceField((FieldReference)ReadAndDecodeMetadataToken());
case ILOpCode.Ldlen: case ILOpCode.Ldlen:
throw new NotImplementedException(); stack.PopOrDefault();
stack.Push(StackType.I);
return new LdLen();
case ILOpCode.Ldobj: case ILOpCode.Ldobj:
throw new NotImplementedException(); throw new NotImplementedException();
case ILOpCode.Ldsfld: case ILOpCode.Ldsfld:

16
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; }
}
}
}

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

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

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

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

Loading…
Cancel
Save