Browse Source

ILInstruction.Clone()

pull/728/head
Daniel Grunwald 10 years ago
parent
commit
0cae30cce2
  1. 10
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  2. 5
      ICSharpCode.Decompiler/CSharp/Transforms/TransformContext.cs
  3. 4
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  4. 47
      ICSharpCode.Decompiler/IL/BlockBuilder.cs
  5. 91
      ICSharpCode.Decompiler/IL/Instructions.cs
  6. 40
      ICSharpCode.Decompiler/IL/Instructions.tt
  7. 9
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  8. 17
      ICSharpCode.Decompiler/IL/Instructions/BlockContainer.cs
  9. 38
      ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs
  10. 24
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs
  11. 10
      ICSharpCode.Decompiler/IL/Instructions/Return.cs
  12. 11
      ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs
  13. 23
      ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs
  14. 11
      ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs
  15. 53
      ICSharpCode.Decompiler/IL/Transforms/OptimizingTransform.cs
  16. 4
      ICSharpCode.Decompiler/Output/PlainTextOutput.cs
  17. 2
      ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj
  18. 0
      ICSharpCode.Decompiler/Tests/Util/LongSetTests.cs
  19. 15
      ICSharpCode.Decompiler/Util/Argument.cs
  20. 5
      ICSharpCode.Decompiler/Util/UnionFind.cs
  21. 17
      ILSpy/Languages/CSharpLanguage.cs
  22. 2
      ILSpy/Languages/Languages.cs
  23. 3
      ILSpy/MainWindow.xaml.cs
  24. 2
      ILSpy/TreeNodes/ILSpyTreeNode.cs

10
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -41,6 +41,7 @@ namespace ICSharpCode.Decompiler.CSharp
readonly DecompilerTypeSystem typeSystem;
List<IILTransform> ilTransforms = new List<IILTransform> {
new OptimizingTransform(),
new LoopDetection(),
new TransformingVisitor(),
new TransformStackIntoVariables()
@ -101,9 +102,11 @@ namespace ICSharpCode.Decompiler.CSharp @@ -101,9 +102,11 @@ namespace ICSharpCode.Decompiler.CSharp
void RunTransforms(AstNode rootNode, ITypeResolveContext decompilationContext)
{
var context = new TransformContext(typeSystem, decompilationContext);
foreach (var transform in astTransforms)
var context = new TransformContext(typeSystem, decompilationContext, CancellationToken);
foreach (var transform in astTransforms) {
CancellationToken.ThrowIfCancellationRequested();
transform.Run(rootNode, context);
}
rootNode.AcceptVisitor(new InsertParenthesesVisitor { InsertParenthesesForReadability = true });
}
@ -226,8 +229,9 @@ namespace ICSharpCode.Decompiler.CSharp @@ -226,8 +229,9 @@ namespace ICSharpCode.Decompiler.CSharp
var ilReader = new ILReader(specializingTypeSystem);
var function = ilReader.ReadIL(methodDefinition.Body, CancellationToken);
function.CheckInvariant();
var context = new ILTransformContext { TypeSystem = specializingTypeSystem };
var context = new ILTransformContext { TypeSystem = specializingTypeSystem, CancellationToken = CancellationToken };
foreach (var transform in ilTransforms) {
CancellationToken.ThrowIfCancellationRequested();
transform.Run(function, context);
function.CheckInvariant();
}

5
ICSharpCode.Decompiler/CSharp/Transforms/TransformContext.cs

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Threading;
using ICSharpCode.NRefactory.CSharp.Resolver;
using ICSharpCode.NRefactory.TypeSystem;
@ -28,6 +29,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -28,6 +29,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
public class TransformContext
{
public readonly DecompilerTypeSystem TypeSystem;
public readonly CancellationToken CancellationToken;
readonly ITypeResolveContext decompilationContext;
/// <summary>
@ -44,10 +46,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms @@ -44,10 +46,11 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
get { return decompilationContext.CurrentTypeDefinition; }
}
internal TransformContext(DecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext)
internal TransformContext(DecompilerTypeSystem typeSystem, ITypeResolveContext decompilationContext, CancellationToken cancellationToken)
{
this.TypeSystem = typeSystem;
this.decompilationContext = decompilationContext;
this.CancellationToken = cancellationToken;
}
}
}

4
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -105,10 +105,10 @@ @@ -105,10 +105,10 @@
<Compile Include="IL\IInlineContext.cs" />
<Compile Include="IL\NRTypeExtensions.cs" />
<Compile Include="IL\Transforms\LoopDetection.cs" />
<Compile Include="IL\Transforms\OptimizingTransform.cs" />
<Compile Include="IL\Transforms\TransformingVisitor.cs" />
<Compile Include="IL\Transforms\TransformStackIntoVariables.cs" />
<Compile Include="IL\Transforms\TransformStackIntoVariablesState.cs" />
<Compile Include="IL\UnionFind.cs" />
<Compile Include="CecilExtensions.cs" />
<Compile Include="Disassembler\DisassemblerHelpers.cs" />
<Compile Include="Disassembler\ILStructure.cs" />
@ -137,9 +137,9 @@ @@ -137,9 +137,9 @@
<Compile Include="TypeSystem\IDecompilerTypeSystem.cs" />
<Compile Include="TypeSystem\ReferenceResolvingException.cs" />
<Compile Include="TypeSystem\TypesHierarchyHelpers.cs" />
<Compile Include="Util\Argument.cs" />
<Compile Include="Util\CollectionExtensions.cs" />
<Compile Include="Util\Interval.cs" />
<Compile Include="Util\UnionFind.cs" />
<None Include="IL\ILOpCodes.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>ILOpCodes.cs</LastGenOutput>

47
ICSharpCode.Decompiler/IL/BlockBuilder.cs

@ -32,6 +32,12 @@ namespace ICSharpCode.Decompiler.IL @@ -32,6 +32,12 @@ namespace ICSharpCode.Decompiler.IL
readonly Mono.Cecil.Cil.MethodBody body;
readonly IDecompilerTypeSystem typeSystem;
/// <summary>
/// Gets/Sets whether to create extended basic blocks instead of basic blocks.
/// The default is <c>false</c>.
/// </summary>
public bool CreateExtendedBlocks;
public BlockBuilder(Mono.Cecil.Cil.MethodBody body, IDecompilerTypeSystem typeSystem)
{
Debug.Assert(body != null);
@ -145,6 +151,8 @@ namespace ICSharpCode.Decompiler.IL @@ -145,6 +151,8 @@ namespace ICSharpCode.Decompiler.IL
currentBlock.Instructions.Add(inst);
if (inst.HasFlag(InstructionFlags.EndPointUnreachable))
FinalizeCurrentBlock(inst.ILRange.End, fallthrough: false);
else if (!CreateExtendedBlocks && inst.HasFlag(InstructionFlags.MayBranch))
FinalizeCurrentBlock(inst.ILRange.End, fallthrough: true);
}
FinalizeCurrentBlock(body.CodeSize, fallthrough: false);
containerStack.Clear();
@ -195,42 +203,3 @@ namespace ICSharpCode.Decompiler.IL @@ -195,42 +203,3 @@ namespace ICSharpCode.Decompiler.IL
}
}
}
/* Inlining logic: } else {
bool finished;
var inlinedInst = inst.Inline(InstructionFlags.None, instructionStack, out finished);
if (inlinedInst.HasFlag(InstructionFlags.MayBranch)) {
// Values currently on the stack might be used on both sides of the branch,
// so we can't inline them.
FlushInstructionStack();
}
if (inlinedInst.ResultType == StackType.Void) {
// 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);
}
}
private void FlushInstructionStack()
{
if (instructionStack != null && instructionStack.Count > 0) {
// Flush instruction stack
currentBlock.Instructions.AddRange(instructionStack.Reverse());
instructionStack.Clear();
}
}*/

91
ICSharpCode.Decompiler/IL/Instructions.cs

@ -214,6 +214,12 @@ namespace ICSharpCode.Decompiler.IL @@ -214,6 +214,12 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (UnaryInstruction)ShallowClone();
clone.Argument = this.argument.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Argument = this.argument.Inline(flagsBefore, context);
@ -288,6 +294,13 @@ namespace ICSharpCode.Decompiler.IL @@ -288,6 +294,13 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (BinaryInstruction)ShallowClone();
clone.Left = this.left.Clone();
clone.Right = this.right.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Right = this.right.Inline(flagsBefore | ((this.left.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), context);
@ -420,6 +433,12 @@ namespace ICSharpCode.Decompiler.IL @@ -420,6 +433,12 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (ILFunction)ShallowClone();
clone.Body = this.body.Clone();
return clone;
}
public override StackType ResultType { get { return StackType.O; } }
public override void AcceptVisitor(ILVisitor visitor)
{
@ -763,6 +782,14 @@ namespace ICSharpCode.Decompiler.IL @@ -763,6 +782,14 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (IfInstruction)ShallowClone();
clone.Condition = this.condition.Clone();
clone.TrueInst = this.trueInst.Clone();
clone.FalseInst = this.falseInst.Clone();
return clone;
}
public override void AcceptVisitor(ILVisitor visitor)
{
visitor.VisitIfInstruction(this);
@ -841,6 +868,13 @@ namespace ICSharpCode.Decompiler.IL @@ -841,6 +868,13 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (TryCatchHandler)ShallowClone();
clone.Filter = this.filter.Clone();
clone.Body = this.body.Clone();
return clone;
}
readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } }
@ -1153,6 +1187,12 @@ namespace ICSharpCode.Decompiler.IL @@ -1153,6 +1187,12 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (StLoc)ShallowClone();
clone.Value = this.value.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Value = this.value.Inline(flagsBefore, context);
@ -1529,6 +1569,12 @@ namespace ICSharpCode.Decompiler.IL @@ -1529,6 +1569,12 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdFld)ShallowClone();
clone.Target = this.target.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
@ -1612,6 +1658,12 @@ namespace ICSharpCode.Decompiler.IL @@ -1612,6 +1658,12 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdFlda)ShallowClone();
clone.Target = this.target.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
@ -1701,6 +1753,13 @@ namespace ICSharpCode.Decompiler.IL @@ -1701,6 +1753,13 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (StFld)ShallowClone();
clone.Target = this.target.Clone();
clone.Value = this.value.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Value = this.value.Inline(flagsBefore | ((this.target.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), context);
@ -1854,6 +1913,12 @@ namespace ICSharpCode.Decompiler.IL @@ -1854,6 +1913,12 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (StsFld)ShallowClone();
clone.Value = this.value.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Value = this.value.Inline(flagsBefore, context);
@ -2001,6 +2066,12 @@ namespace ICSharpCode.Decompiler.IL @@ -2001,6 +2066,12 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdObj)ShallowClone();
clone.Target = this.target.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
@ -2098,6 +2169,13 @@ namespace ICSharpCode.Decompiler.IL @@ -2098,6 +2169,13 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (StObj)ShallowClone();
clone.Target = this.target.Clone();
clone.Value = this.value.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Value = this.value.Inline(flagsBefore | ((this.target.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), context);
@ -2429,6 +2507,12 @@ namespace ICSharpCode.Decompiler.IL @@ -2429,6 +2507,12 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdLen)ShallowClone();
clone.Target = this.target.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Target = this.target.Inline(flagsBefore, context);
@ -2513,6 +2597,13 @@ namespace ICSharpCode.Decompiler.IL @@ -2513,6 +2597,13 @@ namespace ICSharpCode.Decompiler.IL
throw new IndexOutOfRangeException();
}
}
public sealed override ILInstruction Clone()
{
var clone = (LdElema)ShallowClone();
clone.Array = this.array.Clone();
clone.Index = this.index.Clone();
return clone;
}
internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)
{
this.Index = this.index.Inline(flagsBefore | ((this.array.Flags) & ~(InstructionFlags.MayPeek | InstructionFlags.MayPop)), context);

40
ICSharpCode.Decompiler/IL/Instructions.tt

@ -528,7 +528,6 @@ namespace ICSharpCode.Decompiler.IL @@ -528,7 +528,6 @@ namespace ICSharpCode.Decompiler.IL
public readonly string PropertyName;
public readonly string Name;
public bool IsArgument;
public bool IsOptional;
public ChildInfo(string name)
{
@ -551,15 +550,11 @@ namespace ICSharpCode.Decompiler.IL @@ -551,15 +550,11 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorBody.Add("this." + argProp + " = " + arg + ";");
if (i > 0)
opCode.WriteArguments.Add("output.Write(\", \");");
if (children[i].IsOptional)
opCode.WriteArguments.Add("if (this." + arg + " != null) this." + arg + ".WriteTo(output);");
else
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output);");
opCode.WriteArguments.Add("this." + arg + ".WriteTo(output);");
opCode.Members.Add("ILInstruction " + arg + ";");
opCode.Members.Add("public ILInstruction " + argProp + " {" + Environment.NewLine
+ "\tget { return this." + arg + "; }" + Environment.NewLine
+ "\tset {" + Environment.NewLine
+ (children[i].IsOptional ? "\t\tif (value != null)" + Environment.NewLine + "\t" : "")
+ "\t\t" + (children[i].IsArgument ? "ValidateArgument" : "ValidateChild") + "(value);" + Environment.NewLine
+ "\t\tSetChildInstruction(ref this." + arg + ", value, " + i + ");" + Environment.NewLine
+ "\t}" + Environment.NewLine
@ -603,44 +598,23 @@ namespace ICSharpCode.Decompiler.IL @@ -603,44 +598,23 @@ namespace ICSharpCode.Decompiler.IL
b.Append("}");
opCode.Members.Add(b.ToString());
/*
b = new StringBuilder();
b.AppendLine("public override IEnumerable<ILInstruction> Children {");
b.AppendLine("\tget {");
foreach (var child in children) {
if (child.IsOptional) {
b.AppendLine("\t\tif (this." + child.Name + " != null)");
b.Append('\t');
}
b.AppendLine("\t\tyield return this." + child.Name + ";");
}
b.AppendLine("\t}");
b.Append("}");
opCode.Members.Add(b.ToString());
b = new StringBuilder();
b.AppendLine("public override void TransformChildren(ILVisitor<ILInstruction> visitor)");
b.AppendLine("public sealed override ILInstruction Clone()");
b.AppendLine("{");
foreach (var child in children) {
if (child.IsOptional) {
b.AppendLine("\tif (this." + child.Name + " != null)");
b.Append('\t');
}
b.AppendLine("\tthis." + child.PropertyName + " = this." + child.Name + ".AcceptVisitor(visitor);");
b.AppendLine("\tvar clone = (" + opCode.Name + ")ShallowClone();");
for (int i = 0; i < children.Length; i++) {
b.AppendLine("\tclone." + children[i].PropertyName + " = this." + children[i].Name + ".Clone();");
}
b.AppendLine("\treturn clone;");
b.Append("}");
opCode.Members.Add(b.ToString());
*/
if (generateInline) {
b = new StringBuilder();
b.AppendLine("internal sealed override ILInstruction Inline(InstructionFlags flagsBefore, IInlineContext context)");
b.AppendLine("{");
for (int i = children.Length - 1; i >= 0; i--) {
string arg = children[i].Name;
if (children[i].IsOptional) {
b.AppendLine("\tif (this." + arg + " != null)");
b.Append("\t");
}
b.Append("\tthis." + MakeName(arg) + " = this." + arg + ".Inline(flagsBefore");
if (i > 0) {
b.Append(" | ((");

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

@ -95,6 +95,15 @@ namespace ICSharpCode.Decompiler.IL @@ -95,6 +95,15 @@ namespace ICSharpCode.Decompiler.IL
this.FinalInstruction = new Nop();
}
public override ILInstruction Clone()
{
Block clone = new Block();
clone.ILRange = this.ILRange;
clone.Instructions.AddRange(this.Instructions.Select(inst => inst.Clone()));
clone.FinalInstruction = this.FinalInstruction.Clone();
return clone;
}
public override StackType ResultType {
get {
return finalInstruction.ResultType;

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

@ -66,6 +66,23 @@ namespace ICSharpCode.Decompiler.IL @@ -66,6 +66,23 @@ namespace ICSharpCode.Decompiler.IL
this.Blocks = new InstructionCollection<Block>(this, 0);
}
public override ILInstruction Clone()
{
BlockContainer clone = new BlockContainer();
clone.ILRange = this.ILRange;
clone.Blocks.AddRange(this.Blocks.Select(block => (Block)block.Clone()));
// Adjust branch instructions to point to the new container
foreach (var branch in clone.Descendants.OfType<Branch>()) {
if (branch.TargetBlock != null && branch.TargetBlock.Parent == this)
branch.TargetBlock = clone.Blocks[branch.TargetBlock.ChildIndex];
}
foreach (var leave in clone.Descendants.OfType<Leave>()) {
if (leave.TargetContainer == this)
leave.TargetContainer = clone;
}
return clone;
}
protected internal override void InstructionCollectionUpdateComplete()
{
base.InstructionCollectionUpdateComplete();

38
ICSharpCode.Decompiler/IL/Instructions/CallInstruction.cs

@ -46,6 +46,17 @@ namespace ICSharpCode.Decompiler.IL @@ -46,6 +46,17 @@ namespace ICSharpCode.Decompiler.IL
public readonly InstructionCollection<ILInstruction> Arguments;
public readonly IMethod Method;
/// <summary>
/// Gets/Sets whether the call has the 'tail.' prefix.
/// </summary>
public bool IsTail;
/// <summary>
/// Gets/Sets the type specified in the 'constrained.' prefix.
/// Returns null if no 'constrained.' prefix exists for this call.
/// </summary>
public IType ConstrainedTo;
protected CallInstruction(OpCode opCode, IMethod method) : base(opCode)
{
Debug.Assert(method != null);
@ -53,6 +64,16 @@ namespace ICSharpCode.Decompiler.IL @@ -53,6 +64,16 @@ namespace ICSharpCode.Decompiler.IL
this.Arguments = new InstructionCollection<ILInstruction>(this, 0);
}
public sealed override ILInstruction Clone()
{
var clone = Create(this.OpCode, this.Method);
clone.Arguments.AddRange(this.Arguments.Select(arg => arg.Clone()));
clone.ILRange = this.ILRange;
clone.IsTail = this.IsTail;
clone.ConstrainedTo = this.ConstrainedTo;
return clone;
}
public override StackType ResultType {
get {
if (OpCode == OpCode.NewObj)
@ -62,17 +83,17 @@ namespace ICSharpCode.Decompiler.IL @@ -62,17 +83,17 @@ namespace ICSharpCode.Decompiler.IL
}
}
protected override int GetChildCount()
protected sealed override int GetChildCount()
{
return Arguments.Count;
}
protected override ILInstruction GetChild(int index)
protected sealed override ILInstruction GetChild(int index)
{
return Arguments[index];
}
protected override void SetChild(int index, ILInstruction value)
protected sealed override void SetChild(int index, ILInstruction value)
{
Arguments[index] = value;
}
@ -85,17 +106,6 @@ namespace ICSharpCode.Decompiler.IL @@ -85,17 +106,6 @@ namespace ICSharpCode.Decompiler.IL
return flags;
}
/// <summary>
/// Gets/Sets whether the call has the 'tail.' prefix.
/// </summary>
public bool IsTail;
/// <summary>
/// Gets/Sets the type specified in the 'constrained.' prefix.
/// Returns null if no 'constrained.' prefix exists for this call.
/// </summary>
public IType ConstrainedTo;
public override void WriteTo(ITextOutput output)
{
if (ConstrainedTo != null) {

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

@ -465,5 +465,29 @@ namespace ICSharpCode.Decompiler.IL @@ -465,5 +465,29 @@ namespace ICSharpCode.Decompiler.IL
{
InvalidateFlags();
}
/// <summary>
/// Creates a deep clone of the ILInstruction.
/// </summary>
public abstract ILInstruction Clone();
/// <summary>
/// Creates a shallow clone of the ILInstruction.
/// </summary>
/// <remarks>
/// Like MemberwiseClone(), except that the new instruction starts as disconnected.
/// </remarks>
protected ILInstruction ShallowClone()
{
ILInstruction inst = (ILInstruction)MemberwiseClone();
// reset refCount and parent so that the cloned instruction starts as disconnected
inst.refCount = 0;
inst.parent = null;
inst.flags = invalidFlags;
#if DEBUG
inst.activeEnumerators = 0;
#endif
return inst;
}
}
}

10
ICSharpCode.Decompiler/IL/Instructions/Return.cs

@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.IL @@ -31,7 +31,7 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public ILInstruction ReturnValue {
get { return returnValue; }
set {
set {
if (value != null)
ValidateArgument(value);
SetChildInstruction(ref returnValue, value, 0);
@ -47,6 +47,14 @@ namespace ICSharpCode.Decompiler.IL @@ -47,6 +47,14 @@ namespace ICSharpCode.Decompiler.IL
this.ReturnValue = argument;
}
public override ILInstruction Clone()
{
Return clone = (Return)ShallowClone();
if (returnValue != null)
clone.ReturnValue = returnValue.Clone();
return clone;
}
protected override InstructionFlags ComputeFlags()
{
InstructionFlags flags = InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;

11
ICSharpCode.Decompiler/IL/Instructions/SimpleInstruction.cs

@ -39,21 +39,26 @@ namespace ICSharpCode.Decompiler.IL @@ -39,21 +39,26 @@ namespace ICSharpCode.Decompiler.IL
output.Write(OpCode);
}
protected override int GetChildCount()
protected sealed override int GetChildCount()
{
return 0;
}
protected override ILInstruction GetChild(int index)
protected sealed override ILInstruction GetChild(int index)
{
throw new IndexOutOfRangeException();
}
protected override void SetChild(int index, ILInstruction value)
protected sealed override void SetChild(int index, ILInstruction value)
{
throw new IndexOutOfRangeException();
}
public sealed override ILInstruction Clone()
{
return ShallowClone();
}
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.None;

23
ICSharpCode.Decompiler/IL/Instructions/TryInstruction.cs

@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ICSharpCode.Decompiler.IL
{
@ -64,6 +65,14 @@ namespace ICSharpCode.Decompiler.IL @@ -64,6 +65,14 @@ namespace ICSharpCode.Decompiler.IL
this.Handlers = new InstructionCollection<TryCatchHandler>(this, 1);
}
public override ILInstruction Clone()
{
var clone = new TryCatch(TryBlock.Clone());
clone.ILRange = this.ILRange;
clone.Handlers.AddRange(this.Handlers.Select(h => (TryCatchHandler)h.Clone()));
return clone;
}
public override void WriteTo(ITextOutput output)
{
output.Write(".try ");
@ -197,6 +206,13 @@ namespace ICSharpCode.Decompiler.IL @@ -197,6 +206,13 @@ namespace ICSharpCode.Decompiler.IL
}
}
public override ILInstruction Clone()
{
return new TryFinally(TryBlock.Clone(), finallyBlock.Clone()) {
ILRange = this.ILRange
};
}
public override void WriteTo(ITextOutput output)
{
output.Write(".try ");
@ -270,6 +286,13 @@ namespace ICSharpCode.Decompiler.IL @@ -270,6 +286,13 @@ namespace ICSharpCode.Decompiler.IL
}
}
public override ILInstruction Clone()
{
return new TryFault(TryBlock.Clone(), faultBlock.Clone()) {
ILRange = this.ILRange
};
}
public override void WriteTo(ITextOutput output)
{
output.Write(".try ");

11
ICSharpCode.Decompiler/IL/Transforms/LoopDetection.cs

@ -26,12 +26,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -26,12 +26,15 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// <summary>
/// Detect loops in IL AST.
/// </summary>
/// <remarks>
/// Transform ordering:
/// * LoopDetection should run before other control flow structures are detected.
/// * Blocks should be basic blocks (not extended basic blocks) so that the natural loops
/// don't include more instructions than strictly necessary.
/// * (depending on future loop detection improvements:) Loop detection should run after the 'return block' is duplicated.
/// </remarks>
public class LoopDetection : IILTransform
{
// Transform ordering:
// LoopDetection should run before other control flow structures are detected.
// It should run after the 'return block' is duplicated.
#region Construct Control Flow Graph
/// <summary>
/// Constructs a control flow graph for the blocks in the given block container.

53
ICSharpCode.Decompiler/IL/Transforms/OptimizingTransform.cs

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
// 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.Linq;
namespace ICSharpCode.Decompiler.IL.Transforms
{
/// <summary>
/// This transform 'optimizes' the IL code: it replaces constructs that
/// are generated by the C# compiler in debug mode with shorter constructs
/// that are more straightforward to analyze.
/// </summary>
/// <remarks>
/// The optimizations performed are:
/// * 'nop' instructions are removed
/// * TODO branches that lead to a 'return block' are replaced with a return instruction
/// </remarks>
public class OptimizingTransform : IILTransform
{
public void Run(ILFunction function, ILTransformContext context)
{
foreach (var block in function.Descendants.OfType<Block>()) {
// Remove 'nop' instructions
block.Instructions.RemoveAll(inst => inst.OpCode == OpCode.Nop);
/* TODO we might need this for the 'return block' optimization
// Ensure return blocks are inlined:
if (block.Instructions.Count == 2 && block.Instructions[1].OpCode == OpCode.Return) {
Return ret = (Return)block.Instructions[1];
if (ret.ReturnValue != null && ret.ReturnValue.OpCode == OpCode.Pop && block.Instructions[0].ResultType != StackType.Void) {
ret.ReturnValue = block.Instructions[0];
block.Instructions.RemoveAt(0);
}
}
*/
}
}
}
}

4
ICSharpCode.Decompiler/Output/PlainTextOutput.cs

@ -97,12 +97,12 @@ namespace ICSharpCode.Decompiler @@ -97,12 +97,12 @@ namespace ICSharpCode.Decompiler
column = 1;
}
public void WriteDefinition(string text, object definition, bool isLocal)
public void WriteDefinition(string text, object definition, bool isLocal = true)
{
Write(text);
}
public void WriteReference(string text, object reference, bool isLocal)
public void WriteReference(string text, object reference, bool isLocal = false)
{
Write(text);
}

2
ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj

@ -102,13 +102,13 @@ @@ -102,13 +102,13 @@
<Compile Include="Helpers\TypeSystemHelper.cs" />
<Compile Include="ILTransforms\InliningTests.cs" />
<Compile Include="Loops.cs" />
<Compile Include="LongSetTests.cs" />
<Compile Include="StackToVariablesTests.cs" />
<Compile Include="TestCases\CompoundAssignment.cs" />
<Compile Include="TestCases\ControlFlow.cs" />
<Compile Include="TestCases\HelloWorld.cs" />
<Compile Include="TestCases\PropertiesAndEvents.cs" />
<Compile Include="TestRunner.cs" />
<Compile Include="Util\LongSetTests.cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />

0
ICSharpCode.Decompiler/Tests/LongSetTests.cs → ICSharpCode.Decompiler/Tests/Util/LongSetTests.cs

15
ICSharpCode.Decompiler/Util/Argument.cs

@ -1,15 +0,0 @@ @@ -1,15 +0,0 @@
using System;
using ICSharpCode.Decompiler.IL;
namespace ICSharpCode.Decompiler
{
static class Argument
{
public static T NotNull<T>(T value, string paramName)
{
if (value == null)
throw new ArgumentNullException(paramName);
return value;
}
}
}

5
ICSharpCode.Decompiler/IL/UnionFind.cs → ICSharpCode.Decompiler/Util/UnionFind.cs

@ -20,8 +20,11 @@ using System; @@ -20,8 +20,11 @@ using System;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.Decompiler.IL
namespace ICSharpCode.Decompiler
{
/// <summary>
/// Union-Find data structure.
/// </summary>
public class UnionFind<T>
{
Dictionary<T, Node> mapping;

17
ILSpy/Languages/CSharpLanguage.cs

@ -44,33 +44,34 @@ namespace ICSharpCode.ILSpy @@ -44,33 +44,34 @@ namespace ICSharpCode.ILSpy
{
string name = "C#";
bool showAllMembers = false;
//Predicate<IAstTransform> transformAbortCondition = null;
int transformCount = int.MaxValue;
public CSharpLanguage()
{
}
#if DEBUG
/*
internal static IEnumerable<CSharpLanguage> GetDebugLanguages()
{
DecompilerContext context = new DecompilerContext(ModuleDefinition.CreateModule("dummy", ModuleKind.Dll));
//DecompilerContext context = new DecompilerContext(ModuleDefinition.CreateModule("dummy", ModuleKind.Dll));
var decompiler = new CSharpDecompiler(ModuleDefinition.CreateModule("Dummy", ModuleKind.Dll));
string lastTransformName = "no transforms";
foreach (Type _transformType in TransformationPipeline.CreatePipeline(context).Select(v => v.GetType()).Distinct()) {
Type transformType = _transformType; // copy for lambda
int transformCount = 0;
foreach (var transform in decompiler.AstTransforms) {
Type transformType = transform.GetType(); // copy for lambda
yield return new CSharpLanguage {
transformAbortCondition = v => transformType.IsInstanceOfType(v),
transformCount = transformCount,
name = "C# - " + lastTransformName,
showAllMembers = true
};
lastTransformName = "after " + transformType.Name;
transformCount++;
}
yield return new CSharpLanguage {
name = "C# - " + lastTransformName,
showAllMembers = true
};
}
*/
#endif
public override string Name
@ -92,6 +93,8 @@ namespace ICSharpCode.ILSpy @@ -92,6 +93,8 @@ namespace ICSharpCode.ILSpy
{
WriteCommentLine(output, TypeToString(method.DeclaringType, includeNamespace: true));
CSharpDecompiler decompiler = new CSharpDecompiler(method.Module);
while (decompiler.AstTransforms.Count > transformCount)
decompiler.AstTransforms.RemoveAt(decompiler.AstTransforms.Count - 1);
output.WriteLine(decompiler.Decompile(method).ToString());
/*
AstBuilder codeDomBuilder = CreateAstBuilder(options, currentType: method.DeclaringType, isSingleMember: true);

2
ILSpy/Languages/Languages.cs

@ -42,7 +42,7 @@ namespace ICSharpCode.ILSpy @@ -42,7 +42,7 @@ namespace ICSharpCode.ILSpy
languages.AddRange(composition.GetExportedValues<Language>());
#if DEBUG
languages.AddRange(ILAstLanguage.GetDebugLanguages());
//languages.AddRange(CSharpLanguage.GetDebugLanguages());
languages.AddRange(CSharpLanguage.GetDebugLanguages());
#endif
allLanguages = languages.AsReadOnly();
}

3
ILSpy/MainWindow.xaml.cs

@ -541,6 +541,9 @@ namespace ICSharpCode.ILSpy @@ -541,6 +541,9 @@ namespace ICSharpCode.ILSpy
break;
bestMatch = node;
node.EnsureLazyChildren();
var ilSpyTreeNode = node as ILSpyTreeNode;
if (ilSpyTreeNode != null)
ilSpyTreeNode.EnsureChildrenFiltered();
node = node.Children.FirstOrDefault(c => c.ToString() == element);
}
if (returnBestMatch)

2
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -157,7 +157,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -157,7 +157,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
EnsureChildrenFiltered();
}
void EnsureChildrenFiltered()
internal void EnsureChildrenFiltered()
{
EnsureLazyChildren();
if (childrenNeedFiltering) {

Loading…
Cancel
Save