Browse Source

Create ILFunction top-level node

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
63b32fef35
  1. 4
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 37
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  4. 14
      ICSharpCode.Decompiler/IL/ILReader.cs
  5. 10
      ICSharpCode.Decompiler/IL/ILVariable.cs
  6. 34
      ICSharpCode.Decompiler/IL/Instructions.cs
  7. 4
      ICSharpCode.Decompiler/IL/Instructions.tt
  8. 27
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  9. 36
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  10. 59
      ICSharpCode.Decompiler/IL/Instructions/Branch.cs
  11. 69
      ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs
  12. 15
      ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs
  13. 20
      ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs
  14. 64
      ICSharpCode.Decompiler/IL/TransformingVisitor.cs
  15. 8
      ILSpy/Languages/ILAstLanguage.cs

4
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -102,8 +102,8 @@ namespace ICSharpCode.Decompiler.CSharp
var entityDecl = typeSystemAstBuilder.ConvertEntity(method); var entityDecl = typeSystemAstBuilder.ConvertEntity(method);
if (methodDefinition.HasBody) { if (methodDefinition.HasBody) {
var ilReader = new ILReader(methodDefinition.Body, CancellationToken); var ilReader = new ILReader(methodDefinition.Body, CancellationToken);
var inst = ilReader.CreateBlocks(true); var function = ilReader.CreateFunction(true);
var body = statementBuilder.ConvertAsBlock(inst); var body = statementBuilder.ConvertAsBlock(function.Body);
body.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true }); body.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
entityDecl.AddChild(body, Roles.Body); entityDecl.AddChild(body, Roles.Body);
} }

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -79,6 +79,7 @@
<Compile Include="IL\Instructions\CallInstruction.cs" /> <Compile Include="IL\Instructions\CallInstruction.cs" />
<Compile Include="IL\Instructions\Conv.cs" /> <Compile Include="IL\Instructions\Conv.cs" />
<Compile Include="IL\Instructions\IfInstruction.cs" /> <Compile Include="IL\Instructions\IfInstruction.cs" />
<Compile Include="IL\Instructions\ILFunction.cs" />
<Compile Include="IL\Instructions\ILInstruction.cs" /> <Compile Include="IL\Instructions\ILInstruction.cs" />
<Compile Include="IL\Instructions\InstructionCollection.cs" /> <Compile Include="IL\Instructions\InstructionCollection.cs" />
<Compile Include="IL\Instructions\MemoryInstructions.cs" /> <Compile Include="IL\Instructions\MemoryInstructions.cs" />
@ -87,6 +88,7 @@
<Compile Include="IL\Instructions\TryCatch.cs" /> <Compile Include="IL\Instructions\TryCatch.cs" />
<Compile Include="IL\Instructions\TryFinally.cs" /> <Compile Include="IL\Instructions\TryFinally.cs" />
<Compile Include="IL\Instructions\UnaryInstruction.cs" /> <Compile Include="IL\Instructions\UnaryInstruction.cs" />
<Compile Include="IL\TransformingVisitor.cs" />
<Compile Include="TypesHierarchyHelpers.cs" /> <Compile Include="TypesHierarchyHelpers.cs" />
<Compile Include="CecilExtensions.cs" /> <Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" /> <Compile Include="Disassembler\DisassemblerHelpers.cs" />

37
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -43,7 +43,6 @@ namespace ICSharpCode.Decompiler.IL
public BlockContainer CreateBlocks(List<ILInstruction> instructions, BitArray incomingBranches) public BlockContainer CreateBlocks(List<ILInstruction> instructions, BitArray incomingBranches)
{ {
currentContainer = new BlockContainer(); currentContainer = new BlockContainer();
currentContainer.AddRef(); // mark the root node
incomingBranches[0] = true; // see entrypoint as incoming branch incomingBranches[0] = true; // see entrypoint as incoming branch
@ -95,6 +94,7 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
FinalizeCurrentBlock(body.CodeSize, fallthrough: false); FinalizeCurrentBlock(body.CodeSize, fallthrough: false);
ConnectBranches(currentContainer);
return currentContainer; return currentContainer;
} }
@ -117,5 +117,40 @@ namespace ICSharpCode.Decompiler.IL
instructionStack.Clear(); instructionStack.Clear();
} }
} }
Stack<BlockContainer> containerStack = new Stack<BlockContainer>();
void ConnectBranches(ILInstruction inst)
{
switch (inst.OpCode) {
case OpCode.Branch:
var branch = (Branch)inst;
branch.TargetBlock = FindBranchTarget(branch.TargetILOffset);
break;
case OpCode.BlockContainer:
var container = (BlockContainer)inst;
containerStack.Push(container);
container.EntryPoint.IncomingEdgeCount++; // count the entry edge
foreach (var block in container.Blocks)
ConnectBranches(block);
containerStack.Pop();
break;
default:
foreach (var child in inst.Children)
ConnectBranches(child);
break;
}
}
Block FindBranchTarget(int targetILOffset)
{
foreach (var container in containerStack) {
foreach (var block in container.Blocks) {
if (block.ILRange.Start == targetILOffset)
return block;
}
}
throw new InvalidOperationException("Could not find block for branch target");
}
} }
} }

14
ICSharpCode.Decompiler/IL/ILReader.cs

@ -169,16 +169,16 @@ namespace ICSharpCode.Decompiler.IL
new Disassembler.MethodBodyDisassembler(output, false, cancellationToken).WriteExceptionHandlers(body); new Disassembler.MethodBodyDisassembler(output, false, cancellationToken).WriteExceptionHandlers(body);
} }
public void WriteBlocks(ITextOutput output, bool instructionInlining) public ILFunction CreateFunction(bool instructionInlining)
{
CreateBlocks(instructionInlining).WriteTo(output);
}
internal BlockContainer CreateBlocks(bool instructionInlining)
{ {
if (instructionBuilder == null) if (instructionBuilder == null)
ReadInstructions(null); ReadInstructions(null);
return new BlockBuilder(body, instructionInlining).CreateBlocks(instructionBuilder, isBranchTarget); var container = new BlockBuilder(body, instructionInlining).CreateBlocks(instructionBuilder, isBranchTarget);
var function = new ILFunction(body.Method, container);
function.Variables.AddRange(parameterVariables);
function.Variables.AddRange(localVariables);
function.AddRef(); // mark the root node
return function;
} }
ILInstruction Neg() ILInstruction Neg()

10
ICSharpCode.Decompiler/IL/ILVariable.cs

@ -23,6 +23,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Decompiler.Disassembler;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
@ -79,9 +80,16 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
internal void WriteDefinitionTo(ITextOutput output)
{
output.WriteDefinition(this.Name, CecilObject ?? this, isLocal: true);
output.Write(" : ");
Type.WriteTo(output);
}
internal void WriteTo(ITextOutput output) internal void WriteTo(ITextOutput output)
{ {
output.WriteReference(this.ToString(), CecilObject ?? this, isLocal: true); output.WriteReference(this.Name, CecilObject ?? this, isLocal: true);
} }
} }
} }

34
ICSharpCode.Decompiler/IL/Instructions.cs

@ -36,6 +36,8 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.</summary> /// <summary>Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.</summary>
Void, Void,
/// <summary>A container of IL blocks.</summary> /// <summary>A container of IL blocks.</summary>
ILFunction,
/// <summary>A container of IL blocks.</summary>
BlockContainer, BlockContainer,
/// <summary>A block of IL instructions.</summary> /// <summary>A block of IL instructions.</summary>
Block, Block,
@ -328,6 +330,33 @@ namespace ICSharpCode.Decompiler.IL
} }
} }
/// <summary>A container of IL blocks.</summary>
public sealed partial class ILFunction : ILInstruction
{
ILInstruction body;
public ILInstruction Body {
get { return this.body; }
set {
ValidateChild(value);
SetChildInstruction(ref this.body, value);
}
}
public override IEnumerable<ILInstruction> Children {
get {
yield return this.body;
}
}
public override void TransformChildren(ILVisitor<ILInstruction> visitor)
{
this.Body = this.body.AcceptVisitor(visitor);
}
public override StackType ResultType { get { return StackType.O; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{
return visitor.VisitILFunction(this);
}
}
/// <summary>A container of IL blocks.</summary> /// <summary>A container of IL blocks.</summary>
public sealed partial class BlockContainer : ILInstruction public sealed partial class BlockContainer : ILInstruction
{ {
@ -2037,6 +2066,10 @@ namespace ICSharpCode.Decompiler.IL
{ {
return Default(inst); return Default(inst);
} }
protected internal virtual T VisitILFunction(ILFunction function)
{
return Default(function);
}
protected internal virtual T VisitBlockContainer(BlockContainer container) protected internal virtual T VisitBlockContainer(BlockContainer container)
{ {
return Default(container); return Default(container);
@ -2362,6 +2395,7 @@ namespace ICSharpCode.Decompiler.IL
"pop", "pop",
"peek", "peek",
"void", "void",
"ILFunction",
"BlockContainer", "BlockContainer",
"Block", "Block",
"logic.not", "logic.not",

4
ICSharpCode.Decompiler/IL/Instructions.tt

@ -39,6 +39,10 @@
Peeking, NoArguments, ResultTypeParam), Peeking, NoArguments, ResultTypeParam),
new OpCode("void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.", new OpCode("void", "Ignore the arguments and produce void. Used to prevent the end result of an instruction from being pushed to the evaluation stack.",
VoidResult, Unary), VoidResult, Unary),
new OpCode("ILFunction", "A container of IL blocks.",
CustomChildren(new [] {
new ChildInfo("body")
}), CustomConstructor, CustomWriteTo, CustomComputeFlags, CustomVariableName("function"), ResultType("O")),
new OpCode("BlockContainer", "A container of IL blocks.", new OpCode("BlockContainer", "A container of IL blocks.",
VoidResult, CustomConstructor, CustomVariableName("container")), VoidResult, CustomConstructor, CustomVariableName("container")),
new OpCode("Block", "A block of IL instructions.", new OpCode("Block", "A block of IL instructions.",

27
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -1,4 +1,22 @@
using System; // Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -11,6 +29,8 @@ namespace ICSharpCode.Decompiler.IL
{ {
public readonly InstructionCollection<ILInstruction> Instructions; public readonly InstructionCollection<ILInstruction> Instructions;
public int IncomingEdgeCount;
public Block() : base(OpCode.Block) public Block() : base(OpCode.Block)
{ {
this.Instructions = new InstructionCollection<ILInstruction>(this); this.Instructions = new InstructionCollection<ILInstruction>(this);
@ -32,7 +52,10 @@ namespace ICSharpCode.Decompiler.IL
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.WriteDefinition("Block " + Label, this); output.Write("Block ");
output.WriteDefinition(Label, this);
if (Parent is BlockContainer)
output.Write(" (incoming: {0})", IncomingEdgeCount);
output.WriteLine(" {"); output.WriteLine(" {");
output.Indent(); output.Indent();
foreach (var inst in Instructions) { foreach (var inst in Instructions) {

36
ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs

@ -1,4 +1,22 @@
using System; // Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -16,7 +34,7 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
partial class BlockContainer : ILInstruction partial class BlockContainer : ILInstruction
{ {
public readonly IList<Block> Blocks; public readonly InstructionCollection<Block> Blocks;
public Block EntryPoint { public Block EntryPoint {
get { get {
@ -29,19 +47,7 @@ namespace ICSharpCode.Decompiler.IL
this.Blocks = new InstructionCollection<Block>(this); this.Blocks = new InstructionCollection<Block>(this);
} }
/* public override void WriteTo(ITextOutput output)
public override bool IsPeeking { get { return EntryPoint.IsPeeking; } }
public override bool NoResult { get { return true; } }
public override void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc)
{
for (int i = 0; i < Blocks.Count; i++) {
if (transformFunc(Blocks[i]) != Blocks[i])
throw new InvalidOperationException("Cannot replace blocks");
}
}
*/public override void WriteTo(ITextOutput output)
{ {
output.WriteLine("BlockContainer {"); output.WriteLine("BlockContainer {");
output.Indent(); output.Indent();

59
ICSharpCode.Decompiler/IL/Instructions/Branch.cs

@ -1,4 +1,22 @@
using System; // Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
@ -9,7 +27,8 @@ namespace ICSharpCode.Decompiler.IL
{ {
partial class Branch : SimpleInstruction partial class Branch : SimpleInstruction
{ {
public readonly int TargetILOffset; readonly int targetILOffset;
Block targetBlock;
/// <summary> /// <summary>
/// Pops the specified number of arguments from the evaluation stack during the branching operation. /// Pops the specified number of arguments from the evaluation stack during the branching operation.
@ -20,18 +39,48 @@ namespace ICSharpCode.Decompiler.IL
public Branch(int targetILOffset) : base(OpCode.Branch) public Branch(int targetILOffset) : base(OpCode.Branch)
{ {
this.TargetILOffset = targetILOffset; this.targetILOffset = targetILOffset;
}
public int TargetILOffset {
get { return targetBlock != null ? targetBlock.ILRange.Start : targetILOffset; }
}
public Block TargetBlock {
get { return targetBlock; }
set {
if (targetBlock != null && IsConnected)
targetBlock.IncomingEdgeCount--;
targetBlock = value;
if (targetBlock != null && IsConnected)
targetBlock.IncomingEdgeCount++;
}
}
protected override void Connected()
{
base.Connected();
if (targetBlock != null)
targetBlock.IncomingEdgeCount++;
}
protected override void Disconnected()
{
base.Disconnected();
if (targetBlock != null)
targetBlock.IncomingEdgeCount--;
} }
public string TargetLabel { public string TargetLabel {
get { return CecilExtensions.OffsetToString(TargetILOffset); } get { return targetBlock != null ? targetBlock.Label : CecilExtensions.OffsetToString(TargetILOffset); }
} }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
output.WriteReference(TargetLabel, TargetILOffset, isLocal: true); output.WriteReference(TargetLabel, (object)targetBlock ?? TargetILOffset, isLocal: true);
if (PopCount != 0) { if (PopCount != 0) {
output.Write(" (pop "); output.Write(" (pop ");
output.Write(PopCount.ToString()); output.Write(PopCount.ToString());

69
ICSharpCode.Decompiler/IL/Instructions/ILFunction.cs

@ -0,0 +1,69 @@
// Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using Mono.Cecil;
using ICSharpCode.Decompiler.Disassembler;
namespace ICSharpCode.Decompiler.IL
{
partial class ILFunction
{
public readonly MethodDefinition Method;
public readonly IList<ILVariable> Variables = new List<ILVariable>();
public ILFunction(MethodDefinition method, ILInstruction body) : base(OpCode.ILFunction)
{
this.Body = body;
this.Method = method;
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Method.WriteTo(output);
output.WriteLine(" {");
output.Indent();
foreach (var variable in Variables) {
variable.WriteDefinitionTo(output);
output.WriteLine();
}
output.WriteLine();
body.WriteTo(output);
output.Unindent();
output.WriteLine("}");
}
protected override InstructionFlags ComputeFlags()
{
// Creating a lambda may throw OutOfMemoryException
return InstructionFlags.MayThrow;
}
internal override ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished)
{
// To the outside, lambda creation looks like a constant
finished = true;
return this;
}
}
}

15
ICSharpCode.Decompiler/IL/Instructions/InstructionCollection.cs

@ -18,6 +18,7 @@
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq;
namespace ICSharpCode.Decompiler.IL namespace ICSharpCode.Decompiler.IL
{ {
@ -61,5 +62,19 @@ namespace ICSharpCode.Decompiler.IL
parentInstruction.AddChildInstruction(item); parentInstruction.AddChildInstruction(item);
base.SetItem(index, item); base.SetItem(index, item);
} }
public int RemoveAll(Predicate<T> predicate)
{
int removed = 0;
for (int i = 0; i < this.Count;) {
if (predicate(this[i])) {
RemoveAt(i);
removed++;
} else {
i++;
}
}
return removed;
}
} }
} }

20
ICSharpCode.Decompiler/IL/Instructions/MemoryInstructions.cs

@ -1,4 +1,22 @@
using ICSharpCode.Decompiler.Disassembler; // Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using ICSharpCode.Decompiler.Disassembler;
using Mono.Cecil; using Mono.Cecil;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;

64
ICSharpCode.Decompiler/IL/TransformingVisitor.cs

@ -0,0 +1,64 @@
// Copyright (c) 2014 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Diagnostics;
using Mono.Cecil;
namespace ICSharpCode.Decompiler.IL
{
/// <summary>
/// Visitor that applies a list of transformations to the IL Ast.
/// </summary>
public class TransformingVisitor : ILVisitor<ILInstruction>
{
protected override ILInstruction Default(ILInstruction inst)
{
inst.TransformChildren(this);
return inst;
}
protected internal override ILInstruction VisitBranch(Branch inst)
{
// If this branch is the only edge to the target block, we can inline the target block here:
if (inst.TargetBlock.IncomingEdgeCount == 1 && inst.PopCount == 0) {
return inst.TargetBlock;
}
return base.VisitBranch(inst);
}
protected internal override ILInstruction VisitBlockContainer(BlockContainer container)
{
container.TransformChildren(this);
// VisitBranch() 'steals' blocks from containers. Remove all blocks that were stolen from the block list:
Debug.Assert(container.EntryPoint.IncomingEdgeCount > 0);
container.Blocks.RemoveAll(b => b.IncomingEdgeCount == 0);
// If the container only contains a single block, and the block contents do not jump back to the block start,
// we can remove the container.
if (container.Blocks.Count == 1 && container.EntryPoint.IncomingEdgeCount == 1) {
// If the block has only one instruction, we can remove the block too
if (container.EntryPoint.Instructions.Count == 1)
return container.EntryPoint.Instructions[0];
return container.EntryPoint;
}
return container;
}
}
}

8
ILSpy/Languages/ILAstLanguage.cs

@ -99,10 +99,8 @@ namespace ICSharpCode.ILSpy
//} //}
} }
public override string FileExtension public override string FileExtension {
{ get {
get
{
return ".il"; return ".il";
} }
} }
@ -151,7 +149,7 @@ namespace ICSharpCode.ILSpy
if (!method.HasBody) if (!method.HasBody)
return; return;
ILReader reader = new ILReader(method.Body, options.CancellationToken); ILReader reader = new ILReader(method.Body, options.CancellationToken);
reader.WriteBlocks(output, instructionInlining); reader.CreateFunction(instructionInlining).WriteTo(output);
} }
} }
} }

Loading…
Cancel
Save