Browse Source

Include operands in ILAst output

pull/728/head
Daniel Grunwald 11 years ago
parent
commit
3a3220ccc2
  1. 23
      ICSharpCode.Decompiler/IL/ILReader.cs
  2. 202
      ICSharpCode.Decompiler/IL/Instructions.cs
  3. 60
      ICSharpCode.Decompiler/IL/Instructions.tt
  4. 10
      ICSharpCode.Decompiler/IL/Instructions/BinaryComparisonInstruction.cs
  5. 43
      ICSharpCode.Decompiler/IL/Instructions/ILInstruction.cs

23
ICSharpCode.Decompiler/IL/ILReader.cs

@ -24,6 +24,7 @@ using System.Threading.Tasks;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using Mono.Cecil; using Mono.Cecil;
using Cil = Mono.Cecil.Cil;
using System.Collections; using System.Collections;
using System.Threading; using System.Threading;
@ -45,7 +46,7 @@ namespace ICSharpCode.Decompiler.IL
return new MetadataToken(reader.ReadUInt32()); return new MetadataToken(reader.ReadUInt32());
} }
readonly Mono.Cecil.Cil.MethodBody body; readonly Cil.MethodBody body;
readonly CancellationToken cancellationToken; readonly CancellationToken cancellationToken;
readonly TypeSystem typeSystem; readonly TypeSystem typeSystem;
@ -56,7 +57,7 @@ namespace ICSharpCode.Decompiler.IL
BitArray isBranchTarget; BitArray isBranchTarget;
List<ILInstruction> instructionBuilder; List<ILInstruction> instructionBuilder;
public ILReader(Mono.Cecil.Cil.MethodBody body, CancellationToken cancellationToken) public ILReader(Cil.MethodBody body, CancellationToken cancellationToken)
{ {
if (body == null) if (body == null)
throw new ArgumentNullException("body"); throw new ArgumentNullException("body");
@ -101,7 +102,23 @@ namespace ICSharpCode.Decompiler.IL
isBranchTarget = new BitArray(body.CodeSize); isBranchTarget = new BitArray(body.CodeSize);
stack.Clear(); stack.Clear();
branchStackDict.Clear(); branchStackDict.Clear();
// Fill isBranchTarget and branchStackDict based on exception handlers
foreach (var eh in body.ExceptionHandlers) {
isBranchTarget[eh.TryStart.Offset] = true;
if (eh.FilterStart != null) {
isBranchTarget[eh.FilterStart.Offset] = true;
branchStackDict[eh.FilterStart.Offset] = ImmutableArray.Create(StackType.O);
}
if (eh.HandlerStart != null) {
isBranchTarget[eh.HandlerStart.Offset] = true;
if (eh.HandlerType == Cil.ExceptionHandlerType.Catch || eh.HandlerType == Cil.ExceptionHandlerType.Filter)
branchStackDict[eh.HandlerStart.Offset] = ImmutableArray.Create(StackType.O);
else
branchStackDict[eh.HandlerStart.Offset] = ImmutableArray<StackType>.Empty;
}
}
while (reader.Position < reader.Length) { while (reader.Position < reader.Length) {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
int start = reader.Position; int start = reader.Position;

202
ICSharpCode.Decompiler/IL/Instructions.cs

@ -167,12 +167,12 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.resultType = resultType; this.resultType = resultType;
} }
StackType resultType;
public override StackType ResultType { get { return resultType; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return InstructionFlags.MayPeek; return InstructionFlags.MayPeek;
} }
StackType resultType;
public override StackType ResultType { get { return resultType; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitPeek(this); return visitor.VisitPeek(this);
@ -270,11 +270,11 @@ namespace ICSharpCode.Decompiler.IL
public Div(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Div, left, right, overflowMode) public Div(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Div, left, right, overflowMode)
{ {
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow;
} }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitDiv(this); return visitor.VisitDiv(this);
@ -287,11 +287,11 @@ namespace ICSharpCode.Decompiler.IL
public Rem(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Rem, left, right, overflowMode) public Rem(ILInstruction left, ILInstruction right, OverflowMode overflowMode) : base(OpCode.Rem, left, right, overflowMode)
{ {
} }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow;
} }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitRem(this); return visitor.VisitRem(this);
@ -366,11 +366,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Unconditional branch. <c>goto target;</c></summary> /// <summary>Unconditional branch. <c>goto target;</c></summary>
public sealed partial class Branch : SimpleInstruction public sealed partial class Branch : SimpleInstruction
{ {
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch; return InstructionFlags.EndPointUnreachable | InstructionFlags.MayBranch;
} }
public override StackType ResultType { get { return StackType.Void; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitBranch(this); return visitor.VisitBranch(this);
@ -393,11 +393,11 @@ namespace ICSharpCode.Decompiler.IL
public DebugBreak() : base(OpCode.DebugBreak) public DebugBreak() : base(OpCode.DebugBreak)
{ {
} }
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return InstructionFlags.SideEffect; return InstructionFlags.SideEffect;
} }
public override StackType ResultType { get { return StackType.Void; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitDebugBreak(this); return visitor.VisitDebugBreak(this);
@ -501,11 +501,11 @@ namespace ICSharpCode.Decompiler.IL
public Ckfinite() : base(OpCode.Ckfinite) public Ckfinite() : base(OpCode.Ckfinite)
{ {
} }
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return InstructionFlags.MayPeek | InstructionFlags.MayThrow; return InstructionFlags.MayPeek | InstructionFlags.MayThrow;
} }
public override StackType ResultType { get { return StackType.Void; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitCkfinite(this); return visitor.VisitCkfinite(this);
@ -533,6 +533,12 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns the variable operand.</summary> /// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } } public ILVariable Variable { get { return variable; } }
public override StackType ResultType { get { return variable.Type.GetStackType(); } } public override StackType ResultType { get { return variable.Type.GetStackType(); } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdLoc(this); return visitor.VisitLdLoc(this);
@ -550,6 +556,12 @@ namespace ICSharpCode.Decompiler.IL
readonly ILVariable variable; readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary> /// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } } public ILVariable Variable { get { return variable; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdLoca(this); return visitor.VisitLdLoca(this);
@ -567,6 +579,15 @@ namespace ICSharpCode.Decompiler.IL
readonly ILVariable variable; readonly ILVariable variable;
/// <summary>Returns the variable operand.</summary> /// <summary>Returns the variable operand.</summary>
public ILVariable Variable { get { return variable; } } public ILVariable Variable { get { return variable; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
variable.WriteTo(output);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitStLoc(this); return visitor.VisitStLoc(this);
@ -581,13 +602,13 @@ namespace ICSharpCode.Decompiler.IL
this.Value = value; this.Value = value;
} }
public readonly string Value; public readonly string Value;
public override StackType ResultType { get { return StackType.O; } }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
} }
public override StackType ResultType { get { return StackType.O; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdStr(this); return visitor.VisitLdStr(this);
@ -602,13 +623,13 @@ namespace ICSharpCode.Decompiler.IL
this.Value = value; this.Value = value;
} }
public readonly int Value; public readonly int Value;
public override StackType ResultType { get { return StackType.I4; } }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
} }
public override StackType ResultType { get { return StackType.I4; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdcI4(this); return visitor.VisitLdcI4(this);
@ -623,13 +644,13 @@ namespace ICSharpCode.Decompiler.IL
this.Value = value; this.Value = value;
} }
public readonly long Value; public readonly long Value;
public override StackType ResultType { get { return StackType.I8; } }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
} }
public override StackType ResultType { get { return StackType.I8; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdcI8(this); return visitor.VisitLdcI8(this);
@ -644,13 +665,13 @@ namespace ICSharpCode.Decompiler.IL
this.Value = value; this.Value = value;
} }
public readonly double Value; public readonly double Value;
public override StackType ResultType { get { return StackType.F; } }
public override void WriteTo(ITextOutput output) public override void WriteTo(ITextOutput output)
{ {
output.Write(OpCode); output.Write(OpCode);
output.Write(' '); output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, Value); Disassembler.DisassemblerHelpers.WriteOperand(output, Value);
} }
public override StackType ResultType { get { return StackType.F; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdcF(this); return visitor.VisitLdcF(this);
@ -673,11 +694,11 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns from the current method or lambda.</summary> /// <summary>Returns from the current method or lambda.</summary>
public sealed partial class Return : ILInstruction public sealed partial class Return : ILInstruction
{ {
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable; return InstructionFlags.MayBranch | InstructionFlags.EndPointUnreachable;
} }
public override StackType ResultType { get { return StackType.Void; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitReturn(this); return visitor.VisitReturn(this);
@ -717,10 +738,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.field = field; this.field = field;
} }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary> /// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; } public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary> /// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -729,6 +746,23 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns the field operand.</summary> /// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } } public FieldReference Field { get { return field; } }
public override StackType ResultType { get { return field.FieldType.GetStackType(); } } public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdFld(this); return visitor.VisitLdFld(this);
@ -742,14 +776,23 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.field = field; this.field = field;
} }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
readonly FieldReference field; readonly FieldReference field;
/// <summary>Returns the field operand.</summary> /// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } } public FieldReference Field { get { return field; } }
public override StackType ResultType { get { return StackType.Ref; } } public override StackType ResultType { get { return StackType.Ref; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.MayThrow;
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdFlda(this); return visitor.VisitLdFlda(this);
@ -763,10 +806,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.field = field; this.field = field;
} }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary> /// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; } public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary> /// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -775,6 +814,25 @@ namespace ICSharpCode.Decompiler.IL
readonly FieldReference field; readonly FieldReference field;
/// <summary>Returns the field operand.</summary> /// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } } public FieldReference Field { get { return field; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
Left.WriteTo(output);
output.Write(", ");
Right.WriteTo(output);
output.Write(')');
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitStFld(this); return visitor.VisitStFld(this);
@ -788,10 +846,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.field = field; this.field = field;
} }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.SideEffect;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary> /// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; } public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary> /// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -800,6 +854,20 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns the field operand.</summary> /// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } } public FieldReference Field { get { return field; } }
public override StackType ResultType { get { return field.FieldType.GetStackType(); } } public override StackType ResultType { get { return field.FieldType.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return InstructionFlags.SideEffect;
}
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdsFld(this); return visitor.VisitLdsFld(this);
@ -817,6 +885,12 @@ namespace ICSharpCode.Decompiler.IL
readonly FieldReference field; readonly FieldReference field;
/// <summary>Returns the field operand.</summary> /// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } } public FieldReference Field { get { return field; } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdsFlda(this); return visitor.VisitLdsFlda(this);
@ -830,10 +904,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.field = field; this.field = field;
} }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect;
}
/// <summary>Gets/Sets whether the memory access is volatile.</summary> /// <summary>Gets/Sets whether the memory access is volatile.</summary>
public bool IsVolatile { get; set; } public bool IsVolatile { get; set; }
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary> /// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
@ -842,6 +912,23 @@ namespace ICSharpCode.Decompiler.IL
readonly FieldReference field; readonly FieldReference field;
/// <summary>Returns the field operand.</summary> /// <summary>Returns the field operand.</summary>
public FieldReference Field { get { return field; } } public FieldReference Field { get { return field; } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect;
}
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, field);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitStsFld(this); return visitor.VisitStsFld(this);
@ -859,6 +946,15 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns the type operand.</summary> /// <summary>Returns the type operand.</summary>
public TypeReference Type { get { return type; } } public TypeReference Type { get { return type; } }
public override StackType ResultType { get { return type.GetStackType(); } } public override StackType ResultType { get { return type.GetStackType(); } }
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitIsInst(this); return visitor.VisitIsInst(this);
@ -872,10 +968,6 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.type = type; this.type = type;
} }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
readonly TypeReference type; readonly TypeReference type;
/// <summary>Returns the type operand.</summary> /// <summary>Returns the type operand.</summary>
public TypeReference Type { get { return type; } } public TypeReference Type { get { return type; } }
@ -884,6 +976,23 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary> /// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>
public byte UnalignedPrefix { get; set; } public byte UnalignedPrefix { get; set; }
public override StackType ResultType { get { return type.GetStackType(); } } public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public override void WriteTo(ITextOutput output)
{
if (IsVolatile)
output.Write("volatile.");
if (UnalignedPrefix > 0)
output.Write("unaligned(" + UnalignedPrefix + ").");
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdObj(this); return visitor.VisitLdObj(this);
@ -897,14 +1006,23 @@ namespace ICSharpCode.Decompiler.IL
{ {
this.type = type; this.type = type;
} }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
readonly TypeReference type; readonly TypeReference type;
/// <summary>Returns the type operand.</summary> /// <summary>Returns the type operand.</summary>
public TypeReference Type { get { return type; } } public TypeReference Type { get { return type; } }
public override StackType ResultType { get { return type.GetStackType(); } } public override StackType ResultType { get { return type.GetStackType(); } }
protected override InstructionFlags ComputeFlags()
{
return base.ComputeFlags() | InstructionFlags.SideEffect | InstructionFlags.MayThrow;
}
public override void WriteTo(ITextOutput output)
{
output.Write(OpCode);
output.Write(' ');
Disassembler.DisassemblerHelpers.WriteOperand(output, type);
output.Write('(');
Argument.WriteTo(output);
output.Write(')');
}
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitUnboxAny(this); return visitor.VisitUnboxAny(this);
@ -930,11 +1048,11 @@ namespace ICSharpCode.Decompiler.IL
public Throw(ILInstruction argument) : base(OpCode.Throw, argument) public Throw(ILInstruction argument) : base(OpCode.Throw, argument)
{ {
} }
public override StackType ResultType { get { return StackType.Void; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable; return base.ComputeFlags() | InstructionFlags.MayThrow | InstructionFlags.EndPointUnreachable;
} }
public override StackType ResultType { get { return StackType.Void; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitThrow(this); return visitor.VisitThrow(this);
@ -947,11 +1065,11 @@ namespace ICSharpCode.Decompiler.IL
public LdLen(ILInstruction argument) : base(OpCode.LdLen, argument) public LdLen(ILInstruction argument) : base(OpCode.LdLen, argument)
{ {
} }
public override StackType ResultType { get { return StackType.I; } }
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return base.ComputeFlags() | InstructionFlags.MayThrow; return base.ComputeFlags() | InstructionFlags.MayThrow;
} }
public override StackType ResultType { get { return StackType.I; } }
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.VisitLdLen(this); return visitor.VisitLdLen(this);

60
ICSharpCode.Decompiler/IL/Instructions.tt

@ -147,13 +147,17 @@ namespace ICSharpCode.Decompiler.IL
public <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : base(<#=string.Join(", ", opCode.BaseConstructorArguments)#>) public <#=opCode.Name#>(<#=string.Join(", ", opCode.ConstructorParameters)#>) : base(<#=string.Join(", ", opCode.BaseConstructorArguments)#>)
{<#=Body(opCode.ConstructorBody)#>} {<#=Body(opCode.ConstructorBody)#>}
<# } #> <# } #>
<#=string.Join(Environment.NewLine, opCode.Members.Select(m => "\t\t" + m.Replace("\n", "\n\t\t")))#>
<# if (opCode.GenerateComputeFlags && opCode.Flags.Any(f => f != "base.ComputeFlags()")) { #> <# if (opCode.GenerateComputeFlags && opCode.Flags.Any(f => f != "base.ComputeFlags()")) { #>
protected override InstructionFlags ComputeFlags() protected override InstructionFlags ComputeFlags()
{ {
return <#=string.Join(" | ", opCode.Flags)#>; return <#=string.Join(" | ", opCode.Flags)#>;
} }
<# } #> <# } #>
<#=string.Join(Environment.NewLine, opCode.Members.Select(m => "\t\t" + m.Replace("\n", "\n\t\t")))#> <# if (opCode.GenerateWriteTo) { #>
public override void WriteTo(ITextOutput output)
{<#=Body(opCode.WriteToBody)#>}
<# } #>
public override T AcceptVisitor<T>(ILVisitor<T> visitor) public override T AcceptVisitor<T>(ILVisitor<T> visitor)
{ {
return visitor.Visit<#=opCode.Name#>(this); return visitor.Visit<#=opCode.Name#>(this);
@ -219,7 +223,7 @@ namespace ICSharpCode.Decompiler.IL
} }
<#+ <#+
static string Body(List<string> statements) static string Body(IEnumerable<string> statements)
{ {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
foreach (var st in statements) { foreach (var st in statements) {
@ -269,6 +273,22 @@ namespace ICSharpCode.Decompiler.IL
public List<string> Flags = new List<string>(); public List<string> Flags = new List<string>();
public bool GenerateComputeFlags = true; public bool GenerateComputeFlags = true;
public bool GenerateWriteTo = false;
public List<string> WriteOpCodePrefix = new List<string>();
public List<string> WriteOpCodeSuffix = new List<string>();
public List<string> WriteOperand = new List<string>();
public List<string> WriteArguments = new List<string>();
public IEnumerable<string> WriteToBody {
get {
foreach (string line in WriteOpCodePrefix)
yield return line;
yield return "output.Write(OpCode);";
foreach (string line in WriteOpCodeSuffix.Concat(WriteOperand).Concat(WriteArguments))
yield return line;
}
}
} }
static Action<OpCode> CustomClassName(string name) static Action<OpCode> CustomClassName(string name)
@ -323,9 +343,6 @@ namespace ICSharpCode.Decompiler.IL
// MayBranch trait: the instruction may cause control flow to branch (e.g. branch, conditionalbranch, return) // MayBranch trait: the instruction may cause control flow to branch (e.g. branch, conditionalbranch, return)
static Action<OpCode> MayBranch = HasFlag("InstructionFlags.MayBranch"); static Action<OpCode> MayBranch = HasFlag("InstructionFlags.MayBranch");
// HasBranchTarget trait: the instruction has an explicit branch target offset
static Action<OpCode> HasBranchTarget = opCode => {};
// UnconditionalBranch trait: the instruction does not produce a result normally; it always branches or throws an exception. Implies VoidResult. // UnconditionalBranch trait: the instruction does not produce a result normally; it always branches or throws an exception. Implies VoidResult.
static Action<OpCode> UnconditionalBranch = VoidResult + HasFlag("InstructionFlags.EndPointUnreachable"); static Action<OpCode> UnconditionalBranch = VoidResult + HasFlag("InstructionFlags.EndPointUnreachable");
@ -348,6 +365,9 @@ namespace ICSharpCode.Decompiler.IL
opCode.Flags.Add("base.ComputeFlags()"); opCode.Flags.Add("base.ComputeFlags()");
opCode.ConstructorParameters.Add("ILInstruction argument"); opCode.ConstructorParameters.Add("ILInstruction argument");
opCode.BaseConstructorArguments.Add("argument"); opCode.BaseConstructorArguments.Add("argument");
opCode.WriteArguments.Add("output.Write('(');");
opCode.WriteArguments.Add("Argument.WriteTo(output);");
opCode.WriteArguments.Add("output.Write(')');");
}; };
// Binary trait: the instruction has two arguments named 'Left' and 'Right' // Binary trait: the instruction has two arguments named 'Left' and 'Right'
@ -358,6 +378,11 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorParameters.Add("ILInstruction right"); opCode.ConstructorParameters.Add("ILInstruction right");
opCode.BaseConstructorArguments.Add("left"); opCode.BaseConstructorArguments.Add("left");
opCode.BaseConstructorArguments.Add("right"); opCode.BaseConstructorArguments.Add("right");
opCode.WriteArguments.Add("output.Write('(');");
opCode.WriteArguments.Add("Left.WriteTo(output);");
opCode.WriteArguments.Add("output.Write(\", \");");
opCode.WriteArguments.Add("Right.WriteTo(output);");
opCode.WriteArguments.Add("output.Write(')');");
}; };
// BinaryNumeric trait: the instruction is derived from BinaryNumericInstruction. Implies Binary; and implies MayThrow if the overflow mode is checked. // BinaryNumeric trait: the instruction is derived from BinaryNumericInstruction. Implies Binary; and implies MayThrow if the overflow mode is checked.
@ -366,12 +391,15 @@ namespace ICSharpCode.Decompiler.IL
opCode.BaseClass = "BinaryNumericInstruction"; opCode.BaseClass = "BinaryNumericInstruction";
opCode.ConstructorParameters.Add("OverflowMode overflowMode"); opCode.ConstructorParameters.Add("OverflowMode overflowMode");
opCode.BaseConstructorArguments.Add("overflowMode"); opCode.BaseConstructorArguments.Add("overflowMode");
opCode.WriteOpCodeSuffix.Add("output.WriteSuffix(overflowMode);");
}; };
// BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result. // BinaryNumeric trait: the instruction is derived from BinaryComparisonInstruction. Implies Binary and I4Result.
static Action<OpCode> BinaryComparison = opCode => { static Action<OpCode> BinaryComparison = opCode => {
Binary(opCode); Binary(opCode);
opCode.BaseClass = "BinaryComparisonInstruction"; opCode.BaseClass = "BinaryComparisonInstruction";
opCode.WriteOpCodeSuffix.Add("output.Write('.');");
opCode.WriteOpCodeSuffix.Add("output.Write(OpType);");
}; };
// SideEffect trait: the instruction has a non-local side effect // SideEffect trait: the instruction has a non-local side effect
@ -392,6 +420,9 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorBody.Add("this.variable = variable;"); opCode.ConstructorBody.Add("this.variable = variable;");
opCode.Members.Add("/// <summary>Returns the variable operand.</summary>" + Environment.NewLine opCode.Members.Add("/// <summary>Returns the variable operand.</summary>" + Environment.NewLine
+ "public ILVariable Variable { get { return variable; } }"); + "public ILVariable Variable { get { return variable; } }");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("variable.WriteTo(output);");
}; };
static Action<OpCode> HasFieldOperand = opCode => { static Action<OpCode> HasFieldOperand = opCode => {
@ -400,6 +431,9 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorBody.Add("this.field = field;"); opCode.ConstructorBody.Add("this.field = field;");
opCode.Members.Add("/// <summary>Returns the field operand.</summary>" + Environment.NewLine opCode.Members.Add("/// <summary>Returns the field operand.</summary>" + Environment.NewLine
+ "public FieldReference Field { get { return field; } }"); + "public FieldReference Field { get { return field; } }");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("Disassembler.DisassemblerHelpers.WriteOperand(output, field);");
}; };
static Action<OpCode> HasTypeOperand = opCode => { static Action<OpCode> HasTypeOperand = opCode => {
@ -408,6 +442,9 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorBody.Add("this.type = type;"); opCode.ConstructorBody.Add("this.type = type;");
opCode.Members.Add("/// <summary>Returns the type operand.</summary>" + Environment.NewLine opCode.Members.Add("/// <summary>Returns the type operand.</summary>" + Environment.NewLine
+ "public TypeReference Type { get { return type; } }"); + "public TypeReference Type { get { return type; } }");
opCode.GenerateWriteTo = true;
opCode.WriteOperand.Add("output.Write(' ');");
opCode.WriteOperand.Add("Disassembler.DisassemblerHelpers.WriteOperand(output, type);");
}; };
// LoadConstant trait: the instruction loads a compile-time constant. Implies NoArguments. // LoadConstant trait: the instruction loads a compile-time constant. Implies NoArguments.
@ -418,12 +455,9 @@ namespace ICSharpCode.Decompiler.IL
opCode.ConstructorParameters.Add(operandType + " value"); opCode.ConstructorParameters.Add(operandType + " value");
opCode.Members.Add("public readonly " + operandType + " Value;"); opCode.Members.Add("public readonly " + operandType + " Value;");
opCode.ConstructorBody.Add("this.Value = value;"); opCode.ConstructorBody.Add("this.Value = value;");
opCode.Members.Add("public override void WriteTo(ITextOutput output)" + Environment.NewLine opCode.GenerateWriteTo = true;
+ "{" + Environment.NewLine opCode.WriteOperand.Add("output.Write(' ');");
+ "\toutput.Write(OpCode);" + Environment.NewLine opCode.WriteOperand.Add("Disassembler.DisassemblerHelpers.WriteOperand(output, Value);");
+ "\toutput.Write(' ');" + Environment.NewLine
+ "\tDisassembler.DisassemblerHelpers.WriteOperand(output, Value);" + Environment.NewLine
+ "}");
}; };
} }
@ -431,11 +465,15 @@ namespace ICSharpCode.Decompiler.IL
opCode.Interfaces.Add("ISupportsVolatilePrefix"); opCode.Interfaces.Add("ISupportsVolatilePrefix");
opCode.Members.Add("/// <summary>Gets/Sets whether the memory access is volatile.</summary>" + Environment.NewLine opCode.Members.Add("/// <summary>Gets/Sets whether the memory access is volatile.</summary>" + Environment.NewLine
+ "public bool IsVolatile { get; set; }"); + "public bool IsVolatile { get; set; }");
opCode.GenerateWriteTo = true;
opCode.WriteOpCodePrefix.Add("if (IsVolatile)" + Environment.NewLine + "\toutput.Write(\"volatile.\");");
}; };
static Action<OpCode> SupportsUnalignedPrefix = opCode => { static Action<OpCode> SupportsUnalignedPrefix = opCode => {
opCode.Interfaces.Add("ISupportsUnalignedPrefix"); opCode.Interfaces.Add("ISupportsUnalignedPrefix");
opCode.Members.Add("/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>" + Environment.NewLine opCode.Members.Add("/// <summary>Returns the alignment specified by the 'unaligned' prefix; or 0 if there was no 'unaligned' prefix.</summary>" + Environment.NewLine
+ "public byte UnalignedPrefix { get; set; }"); + "public byte UnalignedPrefix { get; set; }");
opCode.GenerateWriteTo = true;
opCode.WriteOpCodePrefix.Add("if (UnalignedPrefix > 0)" + Environment.NewLine + "\toutput.Write(\"unaligned(\" + UnalignedPrefix + \").\");");
}; };
#> #>

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

@ -30,9 +30,17 @@ namespace ICSharpCode.Decompiler.IL
protected BinaryComparisonInstruction(OpCode opCode, ILInstruction left, ILInstruction right) : base(opCode, left, right) protected BinaryComparisonInstruction(OpCode opCode, ILInstruction left, ILInstruction right) : base(opCode, left, right)
{ {
// TODO this.OpType = opType; this.OpType = ComputeOpType(left.ResultType, right.ResultType);
} }
static StackType ComputeOpType(StackType left, StackType right)
{
if (left == StackType.I || right == StackType.I)
return StackType.I;
Debug.Assert(left == right);
return left;
}
public sealed override StackType ResultType { public sealed override StackType ResultType {
get { get {
return StackType.I4; return StackType.I4;

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

@ -98,6 +98,9 @@ namespace ICSharpCode.Decompiler.IL
/// </summary> /// </summary>
public Interval ILRange; public Interval ILRange;
/// <summary>
/// Writes the ILAst to the text output.
/// </summary>
public abstract void WriteTo(ITextOutput output); public abstract void WriteTo(ITextOutput output);
public override string ToString() public override string ToString()
@ -107,6 +110,9 @@ namespace ICSharpCode.Decompiler.IL
return output.ToString(); return output.ToString();
} }
/// <summary>
/// Calls the Visit*-method on the visitor corresponding to the concrete type of this instruction.
/// </summary>
public abstract T AcceptVisitor<T>(ILVisitor<T> visitor); public abstract T AcceptVisitor<T>(ILVisitor<T> visitor);
/// <summary> /// <summary>
@ -131,42 +137,5 @@ namespace ICSharpCode.Decompiler.IL
/// <param name="instructionStack">The instruction stack.</param> /// <param name="instructionStack">The instruction stack.</param>
/// <param name="finished">Receives 'true' if all open 'pop' or 'peek' placeholders were inlined into; false otherwise.</param> /// <param name="finished">Receives 'true' if all open 'pop' or 'peek' placeholders were inlined into; false otherwise.</param>
internal abstract ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished); internal abstract ILInstruction Inline(InstructionFlags flagsBefore, Stack<ILInstruction> instructionStack, out bool finished);
/*
/// <summary>
/// Gets whether this instruction peeks at the top value of the stack.
/// If this instruction also pops elements from the stack, this property refers to the top value
/// left after the pop operations.
/// </summary>
public abstract bool IsPeeking { get; }
/// <summary>
/// Gets whether the instruction produces no result.
/// Instructions without result may not be used as arguments to other instructions;
/// and do not result in a stack push when used as a top-level instruction within a block.
/// </summary>
public virtual bool NoResult
{
get { return false; }
}
/// <summary>
/// Gets whether the end point of this instruction is reachable from the start point.
/// Returns false if the instruction performs an unconditional branch, or always throws an exception.
/// </summary>
public virtual bool IsEndReachable
{
get { return true; }
}
public abstract InstructionFlags Flags { get; }
public virtual void WriteTo(ITextOutput output)
{
output.Write(OpCode);
}
public abstract void TransformChildren(Func<ILInstruction, ILInstruction> transformFunc);
*/
} }
} }

Loading…
Cancel
Save